first steps of making 'opt' a first class type for Nim
This commit is contained in:
parent
e879da5791
commit
f7f3a25be8
20 changed files with 198 additions and 35 deletions
|
|
@ -354,7 +354,7 @@ type
|
||||||
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
|
||||||
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
tyFloat, tyFloat32, tyFloat64, tyFloat128,
|
||||||
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
|
||||||
tyUnused0, tyUnused1, tyUnused2,
|
tyOptAsRef, tyUnused1, tyUnused2,
|
||||||
tyVarargs,
|
tyVarargs,
|
||||||
tyUnused,
|
tyUnused,
|
||||||
tyProxy # used as errornous type (for idetools)
|
tyProxy # used as errornous type (for idetools)
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,8 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
|
||||||
var c: TTraversalClosure
|
var c: TTraversalClosure
|
||||||
var p = newProc(nil, m)
|
var p = newProc(nil, m)
|
||||||
result = "Marker_" & getTypeName(m, origTyp, sig)
|
result = "Marker_" & getTypeName(m, origTyp, sig)
|
||||||
let typ = origTyp.skipTypes(abstractInst)
|
var typ = origTyp.skipTypes(abstractInst)
|
||||||
|
if typ.kind == tyOpt: typ = optLowering(typ)
|
||||||
|
|
||||||
case reason
|
case reason
|
||||||
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
|
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ proc mapType(typ: PType): TCTypeKind =
|
||||||
of 8: result = ctInt64
|
of 8: result = ctInt64
|
||||||
else: internalError("mapType")
|
else: internalError("mapType")
|
||||||
of tyRange: result = mapType(typ.sons[0])
|
of tyRange: result = mapType(typ.sons[0])
|
||||||
of tyPtr, tyVar, tyRef:
|
of tyPtr, tyVar, tyRef, tyOptAsRef:
|
||||||
var base = skipTypes(typ.lastSon, typedescInst)
|
var base = skipTypes(typ.lastSon, typedescInst)
|
||||||
case base.kind
|
case base.kind
|
||||||
of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray
|
of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray
|
||||||
|
|
@ -194,6 +194,13 @@ proc mapType(typ: PType): TCTypeKind =
|
||||||
else: result = ctPtr
|
else: result = ctPtr
|
||||||
of tyPointer: result = ctPtr
|
of tyPointer: result = ctPtr
|
||||||
of tySequence: result = ctNimSeq
|
of tySequence: result = ctNimSeq
|
||||||
|
of tyOpt:
|
||||||
|
case optKind(typ)
|
||||||
|
of oBool: result = ctStruct
|
||||||
|
of oNil, oPtr: result = ctPtr
|
||||||
|
of oEnum:
|
||||||
|
# The 'nil' value is always negative, so we always use a signed integer
|
||||||
|
result = if getSize(typ.sons[0]) == 8: ctInt64 else: ctInt32
|
||||||
of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
|
of tyProc: result = if typ.callConv != ccClosure: ctProc else: ctStruct
|
||||||
of tyString: result = ctNimStr
|
of tyString: result = ctNimStr
|
||||||
of tyCString: result = ctCString
|
of tyCString: result = ctCString
|
||||||
|
|
@ -350,7 +357,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
result = getTypePre(m, typ, sig)
|
result = getTypePre(m, typ, sig)
|
||||||
if result != nil: return
|
if result != nil: return
|
||||||
let concrete = typ.skipTypes(abstractInst)
|
let concrete = typ.skipTypes(abstractInst + {tyOpt})
|
||||||
case concrete.kind
|
case concrete.kind
|
||||||
of tySequence, tyTuple, tyObject:
|
of tySequence, tyTuple, tyObject:
|
||||||
result = getTypeName(m, typ, sig)
|
result = getTypeName(m, typ, sig)
|
||||||
|
|
@ -376,6 +383,12 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
|
||||||
of tySequence:
|
of tySequence:
|
||||||
result = getTypeForward(m, t, hashType(t)) & "*"
|
result = getTypeForward(m, t, hashType(t)) & "*"
|
||||||
pushType(m, t)
|
pushType(m, t)
|
||||||
|
of tyOpt:
|
||||||
|
if optKind(etB) == oPtr:
|
||||||
|
result = getTypeForward(m, t, hashType(t)) & "*"
|
||||||
|
pushType(m, t)
|
||||||
|
else:
|
||||||
|
result = getTypeDescAux(m, t, check)
|
||||||
else:
|
else:
|
||||||
result = getTypeDescAux(m, t, check)
|
result = getTypeDescAux(m, t, check)
|
||||||
|
|
||||||
|
|
@ -506,7 +519,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
|
||||||
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
|
||||||
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
|
||||||
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
[getTypeDescAux(m, fieldType.elemType, check), sname])
|
||||||
elif fieldType.kind == tySequence:
|
elif fieldType.kind in {tySequence, tyOpt}:
|
||||||
# we need to use a weak dependency here for trecursive_table.
|
# we need to use a weak dependency here for trecursive_table.
|
||||||
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
|
||||||
elif field.bitsize != 0:
|
elif field.bitsize != 0:
|
||||||
|
|
@ -625,7 +638,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
excl(check, t.id)
|
excl(check, t.id)
|
||||||
return
|
return
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyRef, tyPtr, tyVar:
|
of tyRef, tyOptAsRef, tyPtr, tyVar:
|
||||||
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
|
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
|
||||||
compileToCpp(m): "&" else: "*"
|
compileToCpp(m): "&" else: "*"
|
||||||
var et = origTyp.skipTypes(abstractInst).lastSon
|
var et = origTyp.skipTypes(abstractInst).lastSon
|
||||||
|
|
@ -652,6 +665,21 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
result = name & "*" & star
|
result = name & "*" & star
|
||||||
m.typeCache[sig] = result
|
m.typeCache[sig] = result
|
||||||
pushType(m, et)
|
pushType(m, et)
|
||||||
|
of tyOpt:
|
||||||
|
if etB.sons[0].kind in {tyObject, tyTuple}:
|
||||||
|
let name = getTypeForward(m, et, hashType et)
|
||||||
|
result = name & "*" & star
|
||||||
|
m.typeCache[sig] = result
|
||||||
|
pushType(m, et)
|
||||||
|
elif optKind(etB) == oBool:
|
||||||
|
let name = getTypeForward(m, et, hashType et)
|
||||||
|
result = name & "*"
|
||||||
|
m.typeCache[sig] = result
|
||||||
|
pushType(m, et)
|
||||||
|
else:
|
||||||
|
# else we have a strong dependency :-(
|
||||||
|
result = getTypeDescAux(m, et, check) & star
|
||||||
|
m.typeCache[sig] = result
|
||||||
else:
|
else:
|
||||||
# else we have a strong dependency :-(
|
# else we have a strong dependency :-(
|
||||||
result = getTypeDescAux(m, et, check) & star
|
result = getTypeDescAux(m, et, check) & star
|
||||||
|
|
@ -727,6 +755,38 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
|
||||||
else:
|
else:
|
||||||
result = rope("TGenericSeq")
|
result = rope("TGenericSeq")
|
||||||
add(result, "*")
|
add(result, "*")
|
||||||
|
of tyOpt:
|
||||||
|
result = cacheGetType(m.typeCache, sig)
|
||||||
|
if result == nil:
|
||||||
|
case optKind(t)
|
||||||
|
of oBool:
|
||||||
|
result = cacheGetType(m.forwTypeCache, sig)
|
||||||
|
if result == nil:
|
||||||
|
result = getTypeName(m, origTyp, sig)
|
||||||
|
addf(m.s[cfsForwardTypes], getForwardStructFormat(m),
|
||||||
|
[structOrUnion(t), result])
|
||||||
|
m.forwTypeCache[sig] = result
|
||||||
|
appcg(m, m.s[cfsSeqTypes], "struct $2 {$n" &
|
||||||
|
" NIM_BOOL Field0;$n" &
|
||||||
|
" $1 Field1;$n" &
|
||||||
|
"};$n", [getTypeDescAux(m, t.sons[0], check), result])
|
||||||
|
of oPtr:
|
||||||
|
let et = t.sons[0]
|
||||||
|
if et.kind in {tyTuple, tyObject}:
|
||||||
|
let name = getTypeForward(m, et, hashType et)
|
||||||
|
result = name & "*"
|
||||||
|
pushType(m, et)
|
||||||
|
else:
|
||||||
|
result = getTypeDescAux(m, t.sons[0], check) & "*"
|
||||||
|
of oNil:
|
||||||
|
result = getTypeDescAux(m, t.sons[0], check)
|
||||||
|
of oEnum:
|
||||||
|
result = getTypeName(m, origTyp, sig)
|
||||||
|
if getSize(t.sons[0]) == 8:
|
||||||
|
addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
|
||||||
|
else:
|
||||||
|
addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
|
||||||
|
m.typeCache[sig] = result
|
||||||
of tyArray:
|
of tyArray:
|
||||||
var n: BiggestInt = lengthOrd(t)
|
var n: BiggestInt = lengthOrd(t)
|
||||||
if n <= 0: n = 1 # make an array of at least one element
|
if n <= 0: n = 1 # make an array of at least one element
|
||||||
|
|
@ -1114,6 +1174,8 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
|
||||||
proc genTypeInfo(m: BModule, t: PType): Rope =
|
proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||||
let origType = t
|
let origType = t
|
||||||
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
|
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
|
||||||
|
if t.kind == tyOpt:
|
||||||
|
return genTypeInfo(m, optLowering(t))
|
||||||
|
|
||||||
let sig = hashType(origType)
|
let sig = hashType(origType)
|
||||||
result = m.typeInfoMarker.getOrDefault(sig)
|
result = m.typeInfoMarker.getOrDefault(sig)
|
||||||
|
|
@ -1159,7 +1221,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
|
||||||
else:
|
else:
|
||||||
let x = fakeClosureType(t.owner)
|
let x = fakeClosureType(t.owner)
|
||||||
genTupleInfo(m, x, x, result)
|
genTupleInfo(m, x, x, result)
|
||||||
of tySequence, tyRef:
|
of tySequence, tyRef, tyOptAsRef:
|
||||||
genTypeInfoAux(m, t, t, result)
|
genTypeInfoAux(m, t, t, result)
|
||||||
if gSelectedGC >= gcMarkAndSweep:
|
if gSelectedGC >= gcMarkAndSweep:
|
||||||
let markerProc = genTraverseProc(m, origType, sig, tiNew)
|
let markerProc = genTraverseProc(m, origType, sig, tiNew)
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ proc getUniqueType*(key: PType): PType =
|
||||||
else:
|
else:
|
||||||
# ugh, we need the canon here:
|
# ugh, we need the canon here:
|
||||||
result = slowSearch(key, k)
|
result = slowSearch(key, k)
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("getUniqueType")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("getUniqueType")
|
||||||
|
|
||||||
proc makeSingleLineCString*(s: string): string =
|
proc makeSingleLineCString*(s: string): string =
|
||||||
result = "\""
|
result = "\""
|
||||||
|
|
|
||||||
|
|
@ -107,3 +107,4 @@ proc initDefines*() =
|
||||||
defineSymbol("nimDistros")
|
defineSymbol("nimDistros")
|
||||||
defineSymbol("nimHasCppDefine")
|
defineSymbol("nimHasCppDefine")
|
||||||
defineSymbol("nimGenericInOutFlags")
|
defineSymbol("nimGenericInOutFlags")
|
||||||
|
when false: defineSymbol("nimHasOpt")
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,7 @@ proc mapType(typ: PType): TJSTypeKind =
|
||||||
else: result = etyNone
|
else: result = etyNone
|
||||||
of tyProc: result = etyProc
|
of tyProc: result = etyProc
|
||||||
of tyCString: result = etyString
|
of tyCString: result = etyString
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("mapType")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("mapType")
|
||||||
|
|
||||||
proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
||||||
if p.target == targetPHP: result = etyObject
|
if p.target == targetPHP: result = etyObject
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
of tyOrdinal, tyRange, tyInferred,
|
of tyOrdinal, tyRange, tyInferred,
|
||||||
tyGenericInst, tyStatic, tyVar, tyAlias:
|
tyGenericInst, tyStatic, tyVar, tyAlias:
|
||||||
liftBodyAux(c, lastSon(t), body, x, y)
|
liftBodyAux(c, lastSon(t), body, x, y)
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("liftBodyAux")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("liftBodyAux")
|
||||||
|
|
||||||
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
||||||
result = newType(tyProc, owner)
|
result = newType(tyProc, owner)
|
||||||
|
|
|
||||||
|
|
@ -1393,6 +1393,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
|
||||||
of mSet: result = semSet(c, n, prev)
|
of mSet: result = semSet(c, n, prev)
|
||||||
of mOrdinal: result = semOrdinal(c, n, prev)
|
of mOrdinal: result = semOrdinal(c, n, prev)
|
||||||
of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
|
of mSeq: result = semContainer(c, n, tySequence, "seq", prev)
|
||||||
|
of mOpt: result = semContainer(c, n, tyOpt, "opt", prev)
|
||||||
of mVarargs: result = semVarargs(c, n, prev)
|
of mVarargs: result = semVarargs(c, n, prev)
|
||||||
of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
|
of mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
|
||||||
of mExpr:
|
of mExpr:
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,6 @@ type
|
||||||
|
|
||||||
proc equalParams*(a, b: PNode): TParamsEquality
|
proc equalParams*(a, b: PNode): TParamsEquality
|
||||||
# returns whether the parameter lists of the procs a, b are exactly the same
|
# returns whether the parameter lists of the procs a, b are exactly the same
|
||||||
proc isOrdinalType*(t: PType): bool
|
|
||||||
proc enumHasHoles*(t: PType): bool
|
|
||||||
|
|
||||||
const
|
const
|
||||||
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
|
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
|
||||||
|
|
@ -129,7 +127,7 @@ proc elemType*(t: PType): PType =
|
||||||
else: result = t.lastSon
|
else: result = t.lastSon
|
||||||
assert(result != nil)
|
assert(result != nil)
|
||||||
|
|
||||||
proc isOrdinalType(t: PType): bool =
|
proc isOrdinalType*(t: PType): bool =
|
||||||
assert(t != nil)
|
assert(t != nil)
|
||||||
const
|
const
|
||||||
# caution: uint, uint64 are no ordinal types!
|
# caution: uint, uint64 are no ordinal types!
|
||||||
|
|
@ -137,7 +135,7 @@ proc isOrdinalType(t: PType): bool =
|
||||||
parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tyDistinct}
|
parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tyDistinct}
|
||||||
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
|
t.kind in baseKinds or (t.kind in parentKinds and isOrdinalType(t.sons[0]))
|
||||||
|
|
||||||
proc enumHasHoles(t: PType): bool =
|
proc enumHasHoles*(t: PType): bool =
|
||||||
var b = t
|
var b = t
|
||||||
while b.kind in {tyRange, tyGenericInst, tyAlias}: b = b.sons[0]
|
while b.kind in {tyRange, tyGenericInst, tyAlias}: b = b.sons[0]
|
||||||
result = b.kind == tyEnum and tfEnumHasHoles in b.flags
|
result = b.kind == tyEnum and tfEnumHasHoles in b.flags
|
||||||
|
|
@ -995,7 +993,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
|
||||||
cycleCheck()
|
cycleCheck()
|
||||||
result = sameTypeAux(a.lastSon, b.lastSon, c)
|
result = sameTypeAux(a.lastSon, b.lastSon, c)
|
||||||
of tyNone: result = false
|
of tyNone: result = false
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("sameFlags")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("sameFlags")
|
||||||
|
|
||||||
proc sameBackendType*(x, y: PType): bool =
|
proc sameBackendType*(x, y: PType): bool =
|
||||||
var c = initSameTypeClosure()
|
var c = initSameTypeClosure()
|
||||||
|
|
@ -1176,7 +1174,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
|
||||||
# for now same as error node; we say it's a valid type as it should
|
# for now same as error node; we say it's a valid type as it should
|
||||||
# prevent cascading errors:
|
# prevent cascading errors:
|
||||||
result = nil
|
result = nil
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("typeAllowedAux")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("typeAllowedAux")
|
||||||
|
|
||||||
proc typeAllowed*(t: PType, kind: TSymKind): PType =
|
proc typeAllowed*(t: PType, kind: TSymKind): PType =
|
||||||
# returns 'nil' on success and otherwise the part of the type that is
|
# returns 'nil' on success and otherwise the part of the type that is
|
||||||
|
|
@ -1187,6 +1185,63 @@ proc typeAllowed*(t: PType, kind: TSymKind): PType =
|
||||||
proc align(address, alignment: BiggestInt): BiggestInt =
|
proc align(address, alignment: BiggestInt): BiggestInt =
|
||||||
result = (address + (alignment - 1)) and not (alignment - 1)
|
result = (address + (alignment - 1)) and not (alignment - 1)
|
||||||
|
|
||||||
|
type
|
||||||
|
OptKind* = enum ## What to map 'opt T' to internally.
|
||||||
|
oBool ## opt[T] requires an additional 'bool' field
|
||||||
|
oNil ## opt[T] has no overhead since 'nil'
|
||||||
|
## is available
|
||||||
|
oEnum ## We can use some enum value that is not yet
|
||||||
|
## used for opt[T]
|
||||||
|
oPtr ## opt[T] actually introduces a hidden pointer
|
||||||
|
## in order for the type recursion to work
|
||||||
|
|
||||||
|
proc optKind*(typ: PType): OptKind =
|
||||||
|
## return true iff 'opt[T]' can be mapped to 'T' internally
|
||||||
|
## because we have a 'nil' value available:
|
||||||
|
assert typ.kind == tyOpt
|
||||||
|
case typ.sons[0].skipTypes(abstractInst).kind
|
||||||
|
of tyRef, tyPtr, tyProc:
|
||||||
|
result = oNil
|
||||||
|
of tyArray, tyObject, tyTuple:
|
||||||
|
result = oPtr
|
||||||
|
of tyBool: result = oEnum
|
||||||
|
of tyEnum:
|
||||||
|
assert(typ.n.sons[0].kind == nkSym)
|
||||||
|
if typ.n.sons[0].sym.position != low(int):
|
||||||
|
result = oEnum
|
||||||
|
else:
|
||||||
|
result = oBool
|
||||||
|
else:
|
||||||
|
result = oBool
|
||||||
|
|
||||||
|
proc optLowering*(typ: PType): PType =
|
||||||
|
case optKind(typ)
|
||||||
|
of oNil: result = typ.sons[0]
|
||||||
|
of oPtr:
|
||||||
|
result = newType(tyOptAsRef, typ.owner)
|
||||||
|
result.rawAddSon typ.sons[0]
|
||||||
|
of oBool:
|
||||||
|
result = newType(tyTuple, typ.owner)
|
||||||
|
result.rawAddSon newType(tyBool, typ.owner)
|
||||||
|
result.rawAddSon typ.sons[0]
|
||||||
|
of oEnum:
|
||||||
|
if lastOrd(typ) + 1 < `shl`(BiggestInt(1), 32):
|
||||||
|
result = newType(tyInt32, typ.owner)
|
||||||
|
else:
|
||||||
|
result = newType(tyInt64, typ.owner)
|
||||||
|
|
||||||
|
proc optEnumValue*(typ: PType): BiggestInt =
|
||||||
|
assert typ.kind == tyOpt
|
||||||
|
assert optKind(typ) == oEnum
|
||||||
|
let elem = typ.sons[0].skipTypes(abstractInst).kind
|
||||||
|
if elem == tyBool:
|
||||||
|
result = 2
|
||||||
|
else:
|
||||||
|
assert elem == tyEnum
|
||||||
|
assert typ.n.sons[0].sym.position != low(int)
|
||||||
|
result = typ.n.sons[0].sym.position - 1
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
szNonConcreteType* = -3
|
szNonConcreteType* = -3
|
||||||
szIllegalRecursion* = -2
|
szIllegalRecursion* = -2
|
||||||
|
|
@ -1341,6 +1396,14 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
|
||||||
of tyStatic:
|
of tyStatic:
|
||||||
result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
|
result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
|
||||||
else: szUnknownSize
|
else: szUnknownSize
|
||||||
|
of tyOpt:
|
||||||
|
case optKind(typ)
|
||||||
|
of oBool: result = computeSizeAux(lastSon(typ), a) + 1
|
||||||
|
of oEnum:
|
||||||
|
if lastOrd(typ) + 1 < `shl`(BiggestInt(1), 32): result = 4
|
||||||
|
else: result = 8
|
||||||
|
of oNil: result = computeSizeAux(lastSon(typ), a)
|
||||||
|
of oPtr: result = ptrSize
|
||||||
else:
|
else:
|
||||||
#internalError("computeSizeAux()")
|
#internalError("computeSizeAux()")
|
||||||
result = szUnknownSize
|
result = szUnknownSize
|
||||||
|
|
|
||||||
|
|
@ -314,7 +314,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
|
||||||
result.add atomicType("static", mNone)
|
result.add atomicType("static", mNone)
|
||||||
if t.n != nil:
|
if t.n != nil:
|
||||||
result.add t.n.copyTree
|
result.add t.n.copyTree
|
||||||
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("mapTypeToAstX")
|
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("mapTypeToAstX")
|
||||||
|
|
||||||
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
|
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
|
||||||
result = mapTypeToAstX(t, info, false, true)
|
result = mapTypeToAstX(t, info, false, true)
|
||||||
|
|
|
||||||
|
|
@ -1537,6 +1537,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
|
||||||
addSon(result, getNullValue(t.sons[i], info))
|
addSon(result, getNullValue(t.sons[i], info))
|
||||||
of tySet:
|
of tySet:
|
||||||
result = newNodeIT(nkCurly, info, t)
|
result = newNodeIT(nkCurly, info, t)
|
||||||
|
of tyOpt:
|
||||||
|
result = newNodeIT(nkNilLit, info, t)
|
||||||
else:
|
else:
|
||||||
globalError(info, "cannot create null element for: " & $t.kind)
|
globalError(info, "cannot create null element for: " & $t.kind)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ type
|
||||||
akUInt16 = 42, ## any represents an unsigned in16
|
akUInt16 = 42, ## any represents an unsigned in16
|
||||||
akUInt32 = 43, ## any represents an unsigned int32
|
akUInt32 = 43, ## any represents an unsigned int32
|
||||||
akUInt64 = 44, ## any represents an unsigned int64
|
akUInt64 = 44, ## any represents an unsigned int64
|
||||||
|
akOpt = 44+18 ## the builtin 'opt' type.
|
||||||
|
|
||||||
Any* = object ## can represent any nim value; NOTE: the wrapped
|
Any* = object ## can represent any nim value; NOTE: the wrapped
|
||||||
## value can be modified with its wrapper! This means
|
## value can be modified with its wrapper! This means
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,9 @@ type
|
||||||
UncheckedArray* {.unchecked.}[T] = array[0, T]
|
UncheckedArray* {.unchecked.}[T] = array[0, T]
|
||||||
## Array with no bounds checking
|
## Array with no bounds checking
|
||||||
|
|
||||||
|
when defined(nimHasOpt):
|
||||||
|
type opt*{.magic: "Opt".}[T]
|
||||||
|
|
||||||
proc high*[T: Ordinal](x: T): T {.magic: "High", noSideEffect.}
|
proc high*[T: Ordinal](x: T): T {.magic: "High", noSideEffect.}
|
||||||
## returns the highest possible index of an array, a sequence, a string or
|
## returns the highest possible index of an array, a sequence, a string or
|
||||||
## the highest possible value of an ordinal value `x`. As a special
|
## the highest possible value of an ordinal value `x`. As a special
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,19 @@ proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
|
||||||
cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
|
cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
|
||||||
of tyRef:
|
of tyRef:
|
||||||
unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
|
unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
|
||||||
|
of tyOptAsRef:
|
||||||
|
let s2 = cast[PPointer](src)[]
|
||||||
|
let d = cast[PPointer](dest)
|
||||||
|
if s2 == nil:
|
||||||
|
unsureAsgnRef(d, s2)
|
||||||
|
else:
|
||||||
|
when declared(usrToCell):
|
||||||
|
let realType = usrToCell(s2).typ
|
||||||
|
else:
|
||||||
|
let realType = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[]
|
||||||
|
else: mt.base
|
||||||
|
var z = newObj(realType, realType.base.size)
|
||||||
|
genericAssignAux(d, addr z, mt.base, shallow)
|
||||||
else:
|
else:
|
||||||
copyMem(dest, src, mt.size) # copy raw bits
|
copyMem(dest, src, mt.size) # copy raw bits
|
||||||
|
|
||||||
|
|
@ -115,6 +128,7 @@ when false:
|
||||||
of tyPtr: k = "ptr"
|
of tyPtr: k = "ptr"
|
||||||
of tyRef: k = "ref"
|
of tyRef: k = "ref"
|
||||||
of tyVar: k = "var"
|
of tyVar: k = "var"
|
||||||
|
of tyOptAsRef: k = "optref"
|
||||||
of tySequence: k = "seq"
|
of tySequence: k = "seq"
|
||||||
of tyProc: k = "proc"
|
of tyProc: k = "proc"
|
||||||
of tyPointer: k = "range"
|
of tyPointer: k = "range"
|
||||||
|
|
@ -195,7 +209,7 @@ proc genericReset(dest: pointer, mt: PNimType) =
|
||||||
var d = cast[ByteAddress](dest)
|
var d = cast[ByteAddress](dest)
|
||||||
sysAssert(mt != nil, "genericReset 2")
|
sysAssert(mt != nil, "genericReset 2")
|
||||||
case mt.kind
|
case mt.kind
|
||||||
of tyString, tyRef, tySequence:
|
of tyString, tyRef, tyOptAsRef, tySequence:
|
||||||
unsureAsgnRef(cast[PPointer](dest), nil)
|
unsureAsgnRef(cast[PPointer](dest), nil)
|
||||||
of tyTuple:
|
of tyTuple:
|
||||||
genericResetAux(dest, mt.node)
|
genericResetAux(dest, mt.node)
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
|
||||||
for i in 0..(mt.size div mt.base.size)-1:
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
storeAux(cast[pointer](d +% i*% mt.base.size),
|
storeAux(cast[pointer](d +% i*% mt.base.size),
|
||||||
cast[pointer](s +% i*% mt.base.size), mt.base, t, mode)
|
cast[pointer](s +% i*% mt.base.size), mt.base, t, mode)
|
||||||
of tyRef:
|
of tyRef, tyOptAsRef:
|
||||||
var s = cast[PPointer](src)[]
|
var s = cast[PPointer](src)[]
|
||||||
var x = cast[PPointer](dest)
|
var x = cast[PPointer](dest)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
|
||||||
for i in 0..(mt.size div mt.base.size)-1:
|
for i in 0..(mt.size div mt.base.size)-1:
|
||||||
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
|
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
|
||||||
cast[pointer](s +% i*% mt.base.size), mt.base, tab)
|
cast[pointer](s +% i*% mt.base.size), mt.base, tab)
|
||||||
of tyRef:
|
of tyRef, tyOptAsRef:
|
||||||
let s2 = cast[PPointer](src)[]
|
let s2 = cast[PPointer](src)[]
|
||||||
if s2 == nil:
|
if s2 == nil:
|
||||||
unsureAsgnRef(cast[PPointer](dest), s2)
|
unsureAsgnRef(cast[PPointer](dest), s2)
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
|
||||||
for i in 0..n.len-1:
|
for i in 0..n.len-1:
|
||||||
# inlined for speed
|
# inlined for speed
|
||||||
if n.sons[i].kind == nkSlot:
|
if n.sons[i].kind == nkSlot:
|
||||||
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
|
if n.sons[i].typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}:
|
||||||
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
|
||||||
else:
|
else:
|
||||||
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
|
||||||
|
|
@ -366,7 +366,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
case mt.kind
|
case mt.kind
|
||||||
of tyRef, tyString, tySequence: # leaf:
|
of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
|
||||||
doOperation(cast[PPointer](d)[], op)
|
doOperation(cast[PPointer](d)[], op)
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
forAllSlotsAux(dest, mt.node, op)
|
forAllSlotsAux(dest, mt.node, op)
|
||||||
|
|
@ -379,13 +379,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
gcAssert(cell != nil, "forAllChildren: 1")
|
gcAssert(cell != nil, "forAllChildren: 1")
|
||||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
||||||
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
||||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
|
gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 4"
|
||||||
let marker = cell.typ.marker
|
let marker = cell.typ.marker
|
||||||
if marker != nil:
|
if marker != nil:
|
||||||
marker(cellToUsr(cell), op.int)
|
marker(cellToUsr(cell), op.int)
|
||||||
else:
|
else:
|
||||||
case cell.typ.kind
|
case cell.typ.kind
|
||||||
of tyRef: # common case
|
of tyRef, tyOptAsRef: # common case
|
||||||
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var d = cast[ByteAddress](cellToUsr(cell))
|
var d = cast[ByteAddress](cellToUsr(cell))
|
||||||
|
|
@ -461,7 +461,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
incTypeSize typ, size
|
incTypeSize typ, size
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
#gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small"
|
#gcAssert typ.kind in {tyString, tySequence} or size >= typ.base.size, "size too small"
|
||||||
|
|
@ -509,7 +509,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
incTypeSize typ, size
|
incTypeSize typ, size
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -358,7 +358,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
case mt.kind
|
case mt.kind
|
||||||
of tyRef, tyString, tySequence: # leaf:
|
of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
|
||||||
doOperation(cast[PPointer](d)[], op)
|
doOperation(cast[PPointer](d)[], op)
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
forAllSlotsAux(dest, mt.node, op)
|
forAllSlotsAux(dest, mt.node, op)
|
||||||
|
|
@ -371,13 +371,13 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
gcAssert(cell != nil, "forAllChildren: 1")
|
gcAssert(cell != nil, "forAllChildren: 1")
|
||||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
||||||
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
||||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
|
gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 4"
|
||||||
let marker = cell.typ.marker
|
let marker = cell.typ.marker
|
||||||
if marker != nil:
|
if marker != nil:
|
||||||
marker(cellToUsr(cell), op.int)
|
marker(cellToUsr(cell), op.int)
|
||||||
else:
|
else:
|
||||||
case cell.typ.kind
|
case cell.typ.kind
|
||||||
of tyRef: # common case
|
of tyRef, tyOptAsRef: # common case
|
||||||
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var d = cast[ByteAddress](cellToUsr(cell))
|
var d = cast[ByteAddress](cellToUsr(cell))
|
||||||
|
|
@ -442,7 +442,7 @@ proc gcInvariant*() =
|
||||||
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
@ -487,7 +487,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
# generates a new object and sets its reference counter to 1
|
# generates a new object and sets its reference counter to 1
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
sysAssert(allocInv(gch.region), "newObjRC1 after collectCT")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,7 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
if dest == nil: return # nothing to do
|
if dest == nil: return # nothing to do
|
||||||
if ntfNoRefs notin mt.flags:
|
if ntfNoRefs notin mt.flags:
|
||||||
case mt.kind
|
case mt.kind
|
||||||
of tyRef, tyString, tySequence: # leaf:
|
of tyRef, tyOptAsRef, tyString, tySequence: # leaf:
|
||||||
doOperation(cast[PPointer](d)[], op)
|
doOperation(cast[PPointer](d)[], op)
|
||||||
of tyObject, tyTuple:
|
of tyObject, tyTuple:
|
||||||
forAllSlotsAux(dest, mt.node, op)
|
forAllSlotsAux(dest, mt.node, op)
|
||||||
|
|
@ -264,13 +264,13 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
||||||
proc forAllChildren(cell: PCell, op: WalkOp) =
|
proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
gcAssert(cell != nil, "forAllChildren: 1")
|
gcAssert(cell != nil, "forAllChildren: 1")
|
||||||
gcAssert(cell.typ != nil, "forAllChildren: 2")
|
gcAssert(cell.typ != nil, "forAllChildren: 2")
|
||||||
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
|
gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 3"
|
||||||
let marker = cell.typ.marker
|
let marker = cell.typ.marker
|
||||||
if marker != nil:
|
if marker != nil:
|
||||||
marker(cellToUsr(cell), op.int)
|
marker(cellToUsr(cell), op.int)
|
||||||
else:
|
else:
|
||||||
case cell.typ.kind
|
case cell.typ.kind
|
||||||
of tyRef: # common case
|
of tyRef, tyOptAsRef: # common case
|
||||||
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
|
||||||
of tySequence:
|
of tySequence:
|
||||||
var d = cast[ByteAddress](cellToUsr(cell))
|
var d = cast[ByteAddress](cellToUsr(cell))
|
||||||
|
|
@ -285,7 +285,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
|
||||||
# generates a new object and sets its reference counter to 0
|
# generates a new object and sets its reference counter to 0
|
||||||
incTypeSize typ, size
|
incTypeSize typ, size
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyOptAsRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(Cell)))
|
||||||
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
gcAssert((cast[ByteAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,21 @@ type
|
||||||
tyUInt16,
|
tyUInt16,
|
||||||
tyUInt32,
|
tyUInt32,
|
||||||
tyUInt64,
|
tyUInt64,
|
||||||
|
tyOptAsRef, tyUnused1, tyUnused2,
|
||||||
|
tyVarargsHidden,
|
||||||
|
tyUnusedHidden,
|
||||||
|
tyProxyHidden,
|
||||||
|
tyBuiltInTypeClassHidden,
|
||||||
|
tyUserTypeClassHidden,
|
||||||
|
tyUserTypeClassInstHidden,
|
||||||
|
tyCompositeTypeClassHidden,
|
||||||
|
tyInferredHidden,
|
||||||
|
tyAndHidden, tyOrHidden, tyNotHidden,
|
||||||
|
tyAnythingHidden,
|
||||||
|
tyStaticHidden,
|
||||||
|
tyFromExprHidden,
|
||||||
|
tyOpt,
|
||||||
|
tyVoidHidden
|
||||||
|
|
||||||
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
TNimNodeKind = enum nkNone, nkSlot, nkList, nkCase
|
||||||
TNimNode {.codegenType.} = object
|
TNimNode {.codegenType.} = object
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue