Merge branch 'devel' into araq

This commit is contained in:
Andreas Rumpf 2017-10-02 08:31:38 +02:00
commit e9243a1616
152 changed files with 3012 additions and 3097 deletions

View file

@ -95,7 +95,7 @@ proc isPartOf*(a, b: PNode): TAnalysisResult =
if a.kind == b.kind:
case a.kind
of nkSym:
const varKinds = {skVar, skTemp, skProc}
const varKinds = {skVar, skTemp, skProc, skFunc}
# same symbol: aliasing:
if a.sym.id == b.sym.id: result = arYes
elif a.sym.kind in varKinds or b.sym.kind in varKinds:

View file

@ -221,6 +221,8 @@ type
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
nkBreakState, # special break statement for easier code generation
nkFuncDef # a func
TNodeKinds* = set[TNodeKind]
type
@ -352,7 +354,7 @@ type
tyInt, tyInt8, tyInt16, tyInt32, tyInt64, # signed integers
tyFloat, tyFloat32, tyFloat64, tyFloat128,
tyUInt, tyUInt8, tyUInt16, tyUInt32, tyUInt64,
tyUnused0, tyUnused1, tyUnused2,
tyOptAsRef, tyUnused1, tyUnused2,
tyVarargs,
tyUnused,
tyProxy # used as errornous type (for idetools)
@ -402,14 +404,8 @@ type
# instantiation and prior to this it has the potential to
# be any type.
tyFieldAccessor
# Expressions such as Type.field (valid in contexts such
# as the `is` operator and magics like `high` and `low`).
# Could be lifted to a single argument proc returning the
# field value.
# sons[0]: type of containing object or tuple
# sons[1]: field type
# .n: nkDotExpr storing the field name
tyOpt
# Builtin optional type
tyVoid
# now different from tyEmpty, hurray!
@ -534,6 +530,7 @@ type
skConst, # a constant
skResult, # special 'result' variable
skProc, # a proc
skFunc, # a func
skMethod, # a method
skIterator, # an iterator
skConverter, # a type converter
@ -552,7 +549,7 @@ type
TSymKinds* = set[TSymKind]
const
routineKinds* = {skProc, skMethod, skIterator,
routineKinds* = {skProc, skFunc, skMethod, skIterator,
skConverter, skMacro, skTemplate}
tfIncompleteStruct* = tfVarargs
tfUncheckedArray* = tfVarargs
@ -621,7 +618,7 @@ type
mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast,
mNewString, mNewStringOfCap, mParseBiggestFloat,
mReset,
mArray, mOpenArray, mRange, mSet, mSeq, mVarargs,
mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs,
mRef, mPtr, mVar, mDistinct, mVoid, mTuple,
mOrdinal,
mInt, mInt8, mInt16, mInt32, mInt64,
@ -631,7 +628,7 @@ type
mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
mIsMainModule, mCompileDate, mCompileTime, mProcCall,
mCpuEndian, mHostOS, mHostCPU, mAppType,
mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType,
mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
@ -754,9 +751,9 @@ type
TLocFlags* = set[TLocFlag]
TLoc* = object
k*: TLocKind # kind of location
s*: TStorageLoc
storage*: TStorageLoc
flags*: TLocFlags # location's flags
t*: PType # type of location
lode*: PNode # Node where the location came from; can be faked
r*: Rope # rope value of location (code generators)
dup*: Rope # duplicated location for precise stack scans
@ -934,7 +931,7 @@ type
# the poor naming choices in the standard library.
const
OverloadableSyms* = {skProc, skMethod, skIterator,
OverloadableSyms* = {skProc, skFunc, skMethod, skIterator,
skConverter, skModule, skTemplate, skMacro}
GenericTypes*: TTypeKinds = {tyGenericInvocation, tyGenericBody,
@ -957,7 +954,7 @@ const
tyTuple, tySequence}
NilableTypes*: TTypeKinds = {tyPointer, tyCString, tyRef, tyPtr, tySequence,
tyProc, tyString, tyError}
ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType,
ExportableSymKinds* = {skVar, skConst, skProc, skFunc, skMethod, skType,
skIterator,
skMacro, skTemplate, skConverter, skEnumField, skLet, skStub, skAlias}
PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
@ -981,14 +978,14 @@ const
nkLiterals* = {nkCharLit..nkTripleStrLit}
nkLambdaKinds* = {nkLambda, nkDo}
declarativeDefs* = {nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef}
declarativeDefs* = {nkProcDef, nkFuncDef, nkMethodDef, nkIteratorDef, nkConverterDef}
procDefs* = nkLambdaKinds + declarativeDefs
nkSymChoices* = {nkClosedSymChoice, nkOpenSymChoice}
nkStrKinds* = {nkStrLit..nkTripleStrLit}
skLocalVars* = {skVar, skLet, skForVar, skParam, skResult}
skProcKinds* = {skProc, skTemplate, skMacro, skIterator,
skProcKinds* = {skProc, skFunc, skTemplate, skMacro, skIterator,
skMethod, skConverter}
var ggDebug* {.deprecated.}: bool ## convenience switch for trying out things
@ -1264,11 +1261,10 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
proc mergeLoc(a: var TLoc, b: TLoc) =
if a.k == low(a.k): a.k = b.k
if a.s == low(a.s): a.s = b.s
if a.storage == low(a.storage): a.storage = b.storage
a.flags = a.flags + b.flags
if a.t == nil: a.t = b.t
if a.lode == nil: a.lode = b.lode
if a.r == nil: a.r = b.r
#if a.a == 0: a.a = b.a
proc newSons*(father: PNode, length: int) =
if isNil(father.sons):

View file

@ -130,7 +130,7 @@ proc hashType(c: var MD5Context, t: PType) =
c.hashSym body.sym
for i in countup(1, sonsLen(t) - 2):
c.hashType t.sons[i]
of tyFromExpr, tyFieldAccessor:
of tyFromExpr:
c.hashTree(t.n)
of tyArray:
c.hashTree(t.sons[0].n)

View file

@ -56,7 +56,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@ -241,7 +241,7 @@ proc genClosureCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
initLoc(list, locCall, d.lode, OnUnknown)
list.r = callPattern % [op.r, pl, pl.addComma, rawProc]
genAssignment(p, d, list, {}) # no need for deep copying
else:
@ -437,7 +437,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, d.t, OnUnknown)
initLoc(list, locCall, d.lode, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
@ -519,7 +519,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, nil, OnUnknown)
initLoc(list, locCall, ri, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:

View file

@ -157,10 +157,23 @@ proc getStorageLoc(n: PNode): TStorageLoc =
result = getStorageLoc(n.sons[0])
else: result = OnUnknown
proc canMove(n: PNode): bool =
# for now we're conservative here:
if n.kind == nkBracket:
# This needs to be kept consistent with 'const' seq code
# generation!
if not isDeepConstExpr(n) or n.len == 0:
if skipTypes(n.typ, abstractVarRange).kind == tySequence:
return true
result = n.kind in nkCallKinds
#if result:
# echo n.info, " optimized ", n
# result = false
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.s == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC():
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
elif dest.s == OnHeap:
elif dest.storage == OnHeap:
# location is on heap
# now the writer barrier is inlined for performance:
#
@ -202,13 +215,13 @@ proc asgnComplexity(n: PNode): int =
proc optAsgnLoc(a: TLoc, t: PType, field: Rope): TLoc =
assert field != nil
result.k = locField
result.s = a.s
result.t = t
result.storage = a.storage
result.lode = lodeTyp t
result.r = rdLoc(a) & "." & field
proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
let newflags =
if src.s == OnStatic:
if src.storage == OnStatic:
flags + {needToCopy}
elif tfShallow in dest.t.flags:
flags - {needToCopy}
@ -225,7 +238,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
t: PNode, typ: PType) =
if t == nil: return
let newflags =
if src.s == OnStatic:
if src.storage == OnStatic:
flags + {needToCopy}
elif tfShallow in dest.t.flags:
flags - {needToCopy}
@ -250,7 +263,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# (for objects, etc.):
if needToCopy notin flags or
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if dest.s == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC():
useStringh(p.module)
linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
@ -274,18 +287,18 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyRef:
genRefAssign(p, dest, src, flags)
of tySequence:
if needToCopy notin flags and src.s != OnStatic:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags)
else:
linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t))
of tyString:
if needToCopy notin flags and src.s != OnStatic:
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags)
else:
if dest.s == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC():
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
elif dest.s == OnHeap:
elif dest.storage == OnHeap:
# we use a temporary to care for the dreaded self assignment:
var tmp: TLoc
getTemp(p, ty, tmp)
@ -357,7 +370,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
else: internalError("genAssignment: " & $ty.kind)
if optMemTracker in p.options and dest.s in {OnHeap, OnUnknown}:
if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}:
#writeStackTrace()
#echo p.currLineInfo, " requesting"
linefmt(p, cpsStmts, "#memTrackerWrite((void*)$1, $2, $3, $4);$n",
@ -407,11 +420,11 @@ proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
else:
d = s # ``d`` is free, so fill it with ``s``
proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
proc putDataIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope) =
var a: TLoc
if d.k != locNone:
# need to generate an assignment here
initLoc(a, locData, t, OnStatic)
initLoc(a, locData, n, OnStatic)
a.r = r
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
else: genAssignment(p, d, a, {needToCopy})
@ -419,14 +432,14 @@ proc putDataIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope) =
# we cannot call initLoc() here as that would overwrite
# the flags field!
d.k = locData
d.t = t
d.lode = n
d.r = r
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope; s=OnUnknown) =
proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
var a: TLoc
if d.k != locNone:
# need to generate an assignment here
initLoc(a, locExpr, t, s)
initLoc(a, locExpr, n, s)
a.r = r
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
else: genAssignment(p, d, a, {needToCopy})
@ -434,7 +447,7 @@ proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: Rope; s=OnUnknown) =
# we cannot call initLoc() here as that would overwrite
# the flags field!
d.k = locExpr
d.t = t
d.lode = n
d.r = r
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
@ -456,7 +469,7 @@ proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
proc binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
@ -464,17 +477,17 @@ proc binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc]))
putIntoDest(p, d, e, ropecg(p.module, frmt, [a.rdCharLoc, b.rdCharLoc]))
proc unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a)]))
putIntoDest(p, d, e, ropecg(p.module, frmt, [rdLoc(a)]))
proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
putIntoDest(p, d, e, ropecg(p.module, frmt, [rdCharLoc(a)]))
proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
frmt: string): Rope =
@ -514,11 +527,11 @@ proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options:
let res = opr[m] % [getTypeDesc(p.module, e.typ), rdLoc(a), rdLoc(b)]
putIntoDest(p, d, e.typ, res)
putIntoDest(p, d, e, res)
else:
let res = binaryArithOverflowRaw(p, t, a, b,
if t.kind == tyInt64: prc64[m] else: prc[m])
putIntoDest(p, d, e.typ, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
putIntoDest(p, d, e, "($#)($#)" % [getTypeDesc(p.module, e.typ), res])
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
@ -535,7 +548,7 @@ proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if optOverflowCheck in p.options:
linefmt(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
rdLoc(a), intLiteral(firstOrd(t)))
putIntoDest(p, d, e.typ, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
putIntoDest(p, d, e, opr[m] % [rdLoc(a), rope(getSize(t) * 8)])
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
@ -593,7 +606,7 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
k = getSize(a.t) * 8
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
binArithTab[op] % [rdLoc(a), rdLoc(b), rope(s),
getSimpleTypeDesc(p.module, e.typ), rope(k)])
@ -604,10 +617,10 @@ proc genEqProc(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if a.t.skipTypes(abstractInst).callConv == ccClosure:
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
"($1.ClP_0 == $2.ClP_0 && $1.ClE_0 == $2.ClE_0)" % [rdLoc(a), rdLoc(b)])
else:
putIntoDest(p, d, e.typ, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
putIntoDest(p, d, e, "($1 == $2)" % [rdLoc(a), rdLoc(b)])
proc genIsNil(p: BProc, e: PNode, d: var TLoc) =
let t = skipTypes(e.sons[1].typ, abstractRange)
@ -644,7 +657,7 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
assert(e.sons[1].typ != nil)
initLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
unArithTab[op] % [rdLoc(a), rope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)])
@ -662,7 +675,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
# message(e.info, warnUser, "CAME HERE " & renderTree(e))
expr(p, e.sons[0], d)
if e.sons[0].typ.skipTypes(abstractInst).kind == tyRef:
d.s = OnHeap
d.storage = OnHeap
else:
var a: TLoc
var typ = skipTypes(e.sons[0].typ, abstractInst)
@ -675,25 +688,25 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
initLocExprSingleUse(p, e.sons[0], a)
if d.k == locNone:
# dest = *a; <-- We do not know that 'dest' is on the heap!
# It is completely wrong to set 'd.s' here, unless it's not yet
# It is completely wrong to set 'd.storage' here, unless it's not yet
# been assigned to.
case typ.kind
of tyRef:
d.s = OnHeap
d.storage = OnHeap
of tyVar:
d.s = OnUnknown
d.storage = OnUnknown
if tfVarIsPtr notin typ.flags and p.module.compileToCpp and
e.kind == nkHiddenDeref:
putIntoDest(p, d, e.typ, rdLoc(a), a.s)
putIntoDest(p, d, e, rdLoc(a), a.storage)
return
of tyPtr:
d.s = OnUnknown # BUGFIX!
d.storage = OnUnknown # BUGFIX!
else:
internalError(e.info, "genDeref " & $typ.kind)
elif p.module.compileToCpp:
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
e.kind == nkHiddenDeref:
putIntoDest(p, d, e.typ, rdLoc(a), a.s)
putIntoDest(p, d, e, rdLoc(a), a.storage)
return
if enforceDeref and mt == ctPtrToArray:
# we lie about the type for better C interop: 'ptr array[3,T]' is
@ -701,26 +714,26 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
# See tmissingderef. So we get rid of the deref instead. The codegen
# ends up using 'memcpy' for the array assignment,
# so the '&' and '*' cancel out:
putIntoDest(p, d, a.t.sons[0], rdLoc(a), a.s)
putIntoDest(p, d, lodeTyp(a.t.sons[0]), rdLoc(a), a.storage)
else:
putIntoDest(p, d, e.typ, "(*$1)" % [rdLoc(a)], a.s)
putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage)
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
# careful 'addr(myptrToArray)' needs to get the ampersand:
if e.sons[0].typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
var a: TLoc
initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, "&" & a.r, a.s)
putIntoDest(p, d, e, "&" & a.r, a.storage)
#Message(e.info, warnUser, "HERE NEW &")
elif mapType(e.sons[0].typ) == ctArray or isCppRef(p, e.sons[0].typ):
expr(p, e.sons[0], d)
else:
var a: TLoc
initLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, addrLoc(a), a.s)
putIntoDest(p, d, e, addrLoc(a), a.storage)
template inheritLocation(d: var TLoc, a: TLoc) =
if d.k == locNone: d.s = a.s
if d.k == locNone: d.storage = a.storage
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
initLocExpr(p, e.sons[0], a)
@ -742,7 +755,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
addf(r, ".Field$1", [rope(i)])
putIntoDest(p, d, tupType.sons[i], r, a.s)
putIntoDest(p, d, e, r, a.storage)
proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
resTyp: ptr PType = nil): PSym =
@ -769,15 +782,14 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
# we found a unique tuple type which lacks field information
# so we use Field$i
addf(r, ".Field$1", [rope(f.position)])
putIntoDest(p, d, f.typ, r, a.s)
putIntoDest(p, d, e, r, a.storage)
else:
var rtyp: PType
let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp)
if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty))
addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r, a.s)
#d.s = a.s
putIntoDest(p, d, e, r, a.storage)
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
@ -792,11 +804,11 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
if op.magic == mNot: it = it.sons[1]
let disc = it.sons[2].skipConv
assert(disc.kind == nkSym)
initLoc(test, locNone, it.typ, OnStack)
initLoc(test, locNone, it, OnStack)
initLocExpr(p, it.sons[1], u)
var o = obj
let d = lookupFieldAgain(p, origTy, disc.sym, o)
initLoc(v, locExpr, d.typ, OnUnknown)
initLoc(v, locExpr, disc, OnUnknown)
v.r = o
v.r.add(".")
v.r.add(d.loc.r)
@ -827,11 +839,11 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
internalError(e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field, ty)
add(r, rfmt(nil, ".$1", field.loc.r))
putIntoDest(p, d, field.typ, r, a.s)
putIntoDest(p, d, e.sons[0], r, a.storage)
else:
genRecordField(p, e.sons[0], d)
proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
@ -853,30 +865,30 @@ proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
if idx < firstOrd(ty) or idx > lastOrd(ty):
localError(x.info, errIndexOutOfBounds)
d.inheritLocation(a)
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.s)
putIntoDest(p, d, n,
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s)
inheritLocation(d, a)
putIntoDest(p, d, n,
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b) # emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.s)
inheritLocation(d, a)
putIntoDest(p, d, n,
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
@ -892,20 +904,20 @@ proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
linefmt(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
rdLoc(b), rdLoc(a), lenField(p))
if d.k == locNone: d.s = OnHeap
if d.k == locNone: d.storage = OnHeap
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
a.r = rfmt(nil, "(*$1)", a.r)
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.s)
putIntoDest(p, d, n,
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind
of tyArray: genArrayElem(p, n.sons[0], n.sons[1], d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
of tyArray: genArrayElem(p, n, n.sons[0], n.sons[1], d)
of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, n.sons[0], n.sons[1], d)
of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d)
of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d)
of tyTuple: genTupleElem(p, n, d)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
@ -1071,7 +1083,7 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
getTypeDesc(p.module, bt)])
#if bt != b.t:
# echo "YES ", e.info, " new: ", typeToString(bt), " old: ", typeToString(b.t)
initLoc(dest, locExpr, bt, OnHeap)
initLoc(dest, locExpr, e.sons[2], OnHeap)
getIntTemp(p, tmpL)
lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r)
@ -1088,7 +1100,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
var sizeExpr = sizeExpr
let typ = a.t
var b: TLoc
initLoc(b, locExpr, a.t, OnHeap)
initLoc(b, locExpr, a.lode, OnHeap)
let refType = typ.skipTypes(abstractInst)
assert refType.kind == tyRef
let bt = refType.lastSon
@ -1098,7 +1110,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
let args = [getTypeDesc(p.module, typ),
genTypeInfo(p.module, typ),
sizeExpr]
if a.s == OnHeap and usesNativeGC():
if a.storage == OnHeap and usesNativeGC():
# use newObjRC1 as an optimization
if canFormAcycle(a.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
@ -1128,8 +1140,8 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
let args = [getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), length]
var call: TLoc
initLoc(call, locExpr, dest.t, OnHeap)
if dest.s == OnHeap and usesNativeGC():
initLoc(call, locExpr, dest.lode, OnHeap)
if dest.storage == OnHeap and usesNativeGC():
if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
else:
@ -1151,7 +1163,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
let seqtype = skipTypes(e.typ, abstractVarRange)
var a: TLoc
initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module,
putIntoDest(p, d, e, ropecg(p.module,
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype), a.rdLoc]))
@ -1163,7 +1175,7 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
let t = n.typ
discard getTypeDesc(p.module, t) # so that any fields are initialized
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
fillLoc(d, locData, n, p.module.tmpBase & rope(id), OnStatic)
if id == p.module.labels:
# expression not found in the cache:
inc(p.module.labels)
@ -1205,8 +1217,8 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
add(tmp2.r, ".")
add(tmp2.r, field.loc.r)
tmp2.k = locTemp
tmp2.t = field.loc.t
tmp2.s = if isRef: OnHeap else: OnStack
tmp2.lode = it.sons[1]
tmp2.storage = if isRef: OnHeap else: OnStack
expr(p, it.sons[1], tmp2)
if d.k == locNone:
@ -1214,37 +1226,37 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
else:
genAssignment(p, d, tmp, {})
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
var arr: TLoc
if d.k == locNone:
getTemp(p, t.typ, d)
getTemp(p, n.typ, d)
# generate call to newSeq before adding the elements per hand:
genNewSeqAux(p, d, intLiteral(sonsLen(t)))
for i in countup(0, sonsLen(t) - 1):
initLoc(arr, locExpr, elemType(skipTypes(t.typ, typedescInst)), OnHeap)
genNewSeqAux(p, d, intLiteral(sonsLen(n)))
for i in countup(0, sonsLen(n) - 1):
initLoc(arr, locExpr, n[i], OnHeap)
arr.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
arr.s = OnHeap # we know that sequences are on the heap
expr(p, t.sons[i], arr)
gcUsage(t)
arr.storage = OnHeap # we know that sequences are on the heap
expr(p, n[i], arr)
gcUsage(n)
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
var elem, a, arr: TLoc
if t.sons[1].kind == nkBracket:
t.sons[1].typ = t.typ
genSeqConstr(p, t.sons[1], d)
if n.sons[1].kind == nkBracket:
n.sons[1].typ = n.typ
genSeqConstr(p, n.sons[1], d)
return
if d.k == locNone:
getTemp(p, t.typ, d)
getTemp(p, n.typ, d)
# generate call to newSeq before adding the elements per hand:
var L = int(lengthOrd(t.sons[1].typ))
var L = int(lengthOrd(n.sons[1].typ))
genNewSeqAux(p, d, intLiteral(L))
initLocExpr(p, t.sons[1], a)
initLocExpr(p, n.sons[1], a)
for i in countup(0, L - 1):
initLoc(elem, locExpr, elemType(skipTypes(t.typ, abstractInst)), OnHeap)
initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
elem.s = OnHeap # we know that sequences are on the heap
initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
elem.storage = OnHeap # we know that sequences are on the heap
initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
@ -1256,7 +1268,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
refType = skipTypes(e.sons[1].typ, abstractVarRange)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], f)
initLoc(b, locExpr, a.t, OnHeap)
initLoc(b, locExpr, a.lode, OnHeap)
ti = genTypeInfo(p.module, refType)
addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
@ -1308,7 +1320,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r))
else:
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r))
putIntoDest(p, d, getSysType(tyBool), r, a.s)
putIntoDest(p, d, x, r, a.storage)
proc genOf(p: BProc, n: PNode, d: var TLoc) =
genOf(p, n.sons[1], n.sons[2].typ, d)
@ -1319,52 +1331,53 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
var t = skipTypes(e.sons[1].typ, abstractVarRange)
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, e,
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]), a.storage)
of tyFloat..tyFloat128:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]), a.storage)
of tyBool:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]), a.storage)
of tyChar:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]), a.storage)
of tyEnum, tyOrdinal:
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
ropecg(p.module, "#reprEnum((NI)$1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
rdLoc(a), genTypeInfo(p.module, t)]), a.storage)
of tyString:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]), a.storage)
of tySet:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(a), genTypeInfo(p.module, t)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(a), genTypeInfo(p.module, t)]), a.storage)
of tyOpenArray, tyVarargs:
var b: TLoc
case a.t.kind
of tyOpenArray, tyVarargs:
putIntoDest(p, b, e.typ, "$1, $1Len_0" % [rdLoc(a)], a.s)
putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage)
of tyString, tySequence:
putIntoDest(p, b, e.typ,
"$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.s)
putIntoDest(p, b, e,
"$1->data, $1->$2" % [rdLoc(a), lenField(p)], a.storage)
of tyArray:
putIntoDest(p, b, e.typ,
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.s)
putIntoDest(p, b, e,
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
else: internalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t))]), a.s)
genTypeInfo(p.module, elemType(t))]), a.storage)
of tyCString, tyArray, tyRef, tyPtr, tyPointer, tyNil, tySequence:
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]), a.s)
rdLoc(a), genTypeInfo(p.module, t)]), a.storage)
of tyEmpty, tyVoid:
localError(e.info, "'repr' doesn't support 'void' type")
else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]), a.s)
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]),
a.storage)
gcUsage(e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
let t = e.sons[1].typ
putIntoDest(p, d, e.typ, genTypeInfo(p.module, t))
putIntoDest(p, d, e, genTypeInfo(p.module, t))
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
@ -1409,11 +1422,11 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else:
frmt = "$1 = ($2 ? $2->len : 0);$n"
lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
putIntoDest(p, d, e.typ, tmp.r)
putIntoDest(p, d, e, tmp.r)
of tyArray:
# YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e.typ, rope(lastOrd(typ)))
else: putIntoDest(p, d, e.typ, rope(lengthOrd(typ)))
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ)))
else: putIntoDest(p, d, e, rope(lengthOrd(typ)))
else: internalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
@ -1471,7 +1484,7 @@ proc fewCmps(s: PNode): bool =
result = sonsLen(s) <= 8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
putIntoDest(p, d, e.typ, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
putIntoDest(p, d, e, frmt % [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
@ -1500,7 +1513,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
else:
e.sons[2]
initLocExpr(p, ea, a)
initLoc(b, locExpr, e.typ, OnUnknown)
initLoc(b, locExpr, e, OnUnknown)
b.r = rope("(")
var length = sonsLen(e.sons[1])
for i in countup(0, length - 1):
@ -1514,7 +1527,7 @@ proc genInOp(p: BProc, e: PNode, d: var TLoc) =
addf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
if i < length - 1: add(b.r, " || ")
add(b.r, ")")
putIntoDest(p, d, e.typ, b.r)
putIntoDest(p, d, e, b.r)
else:
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
@ -1599,14 +1612,14 @@ proc genSomeCast(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[1], a)
let etyp = skipTypes(e.typ, abstractRange)
if etyp.kind in ValueTypes and lfIndirect notin a.flags:
putIntoDest(p, d, e.typ, "(*($1*) ($2))" %
[getTypeDesc(p.module, e.typ), addrLoc(a)], a.s)
putIntoDest(p, d, e, "(*($1*) ($2))" %
[getTypeDesc(p.module, e.typ), addrLoc(a)], a.storage)
elif etyp.kind == tyProc and etyp.callConv == ccClosure:
putIntoDest(p, d, e.typ, "(($1) ($2))" %
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.s)
putIntoDest(p, d, e, "(($1) ($2))" %
[getClosureType(p.module, etyp, clHalfWithEnv), rdCharLoc(a)], a.storage)
else:
putIntoDest(p, d, e.typ, "(($1) ($2))" %
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.s)
putIntoDest(p, d, e, "(($1) ($2))" %
[getTypeDesc(p.module, e.typ), rdCharLoc(a)], a.storage)
proc genCast(p: BProc, e: PNode, d: var TLoc) =
const ValueTypes = {tyFloat..tyFloat128, tyTuple, tyObject, tyArray}
@ -1622,11 +1635,11 @@ proc genCast(p: BProc, e: PNode, d: var TLoc) =
linefmt(p, cpsLocals, "union { $1 source; $2 dest; } LOC$3;$n",
getTypeDesc(p.module, e.sons[1].typ), getTypeDesc(p.module, e.typ), lbl)
tmp.k = locExpr
tmp.t = srct
tmp.s = OnStack
tmp.lode = lodeTyp srct
tmp.storage = OnStack
tmp.flags = {}
expr(p, e.sons[1], tmp)
putIntoDest(p, d, e.typ, "LOC$#.dest" % [lbl], tmp.s)
putIntoDest(p, d, e, "LOC$#.dest" % [lbl], tmp.storage)
else:
# I prefer the shorter cast version for pointer types -> generate less
# C code; plus it's the right thing to do for closures:
@ -1639,14 +1652,14 @@ proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
if optRangeCheck notin p.options or dest.skipTypes({tyRange}).kind in
{tyUInt..tyUInt64}:
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.s)
putIntoDest(p, d, n, "(($1) ($2))" %
[getTypeDesc(p.module, dest), rdCharLoc(a)], a.storage)
else:
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
putIntoDest(p, d, lodeTyp dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
rope(magic)]), a.s)
rope(magic)]), a.storage)
proc genConv(p: BProc, e: PNode, d: var TLoc) =
let destType = e.typ.skipTypes({tyVar, tyGenericInst, tyAlias})
@ -1658,13 +1671,15 @@ proc genConv(p: BProc, e: PNode, d: var TLoc) =
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar), "$1->data" % [rdLoc(a)], a.s)
putIntoDest(p, d, n, "$1->data" % [rdLoc(a)],
a.storage)
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar),
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]), a.s)
putIntoDest(p, d, n,
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
a.storage)
gcUsage(n)
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
@ -1675,11 +1690,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
binaryExpr(p, e, d, "($1 == $2)")
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e.typ,
putIntoDest(p, d, e,
rfmt(nil, "(($1) && ($1)->$2 == 0)", rdLoc(x), lenField(p)))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")
@ -1692,9 +1707,9 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, rfmt(nil, "(($4)($2) $1 ($4)($3))",
rope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ)))
putIntoDest(p, d, e, rfmt(nil, "(($4)($2) $1 ($4)($3))",
rope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ)))
if optNaNCheck in p.options:
linefmt(p, cpsStmts, "#nanCheck($1);$n", rdLoc(d))
if optInfCheck in p.options:
@ -1736,7 +1751,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyAlias, tyVar})
let res = binaryArithOverflowRaw(p, ranged, a, b,
if underlying.kind == tyInt64: fun64[op] else: fun[op])
putIntoDest(p, a, ranged, "($#)($#)" % [
putIntoDest(p, a, e.sons[1], "($#)($#)" % [
getTypeDesc(p.module, ranged), res])
of mConStrStr: genStrConcat(p, e, d)
@ -1762,7 +1777,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mNewSeqOfCap: genNewSeqOfCap(p, e, d)
of mSizeOf:
let t = e.sons[1].typ.skipTypes({tyTypeDesc})
putIntoDest(p, d, e.typ, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
putIntoDest(p, d, e, "((NI)sizeof($1))" % [getTypeDesc(p.module, t)])
of mChr: genSomeCast(p, e, d)
of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@ -1783,7 +1798,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else:
frmt = "$1 = $2->len;$n"
lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a))
putIntoDest(p, d, e.typ, tmp.r)
putIntoDest(p, d, e, tmp.r)
of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
of mSetLengthStr: genSetLengthStr(p, e, d)
@ -1825,7 +1840,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
var
a, b, idx: TLoc
if nfAllConst in e.flags:
putIntoDest(p, d, e.typ, genSetNode(p, e))
putIntoDest(p, d, e, genSetNode(p, e))
else:
if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8:
@ -1872,7 +1887,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr: it = it.sons[1]
initLoc(rec, locExpr, it.typ, d.s)
initLoc(rec, locExpr, it, d.storage)
rec.r = "$1.Field$2" % [rdLoc(d), rope(i)]
expr(p, it, rec)
@ -1888,7 +1903,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
var tmp = "CNSTCLOSURE" & rope(p.module.labels)
addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), tmp, genConstExpr(p, n)])
putIntoDest(p, d, n.typ, tmp, OnStatic)
putIntoDest(p, d, n, tmp, OnStatic)
else:
var tmp, a, b: TLoc
initLocExpr(p, n.sons[0], a)
@ -1911,7 +1926,7 @@ proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
if not handleConstExpr(p, n, d):
if d.k == locNone: getTemp(p, n.typ, d)
for i in countup(0, sonsLen(n) - 1):
initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), d.storage)
arr.r = "$1[$2]" % [rdLoc(d), intLiteral(i)]
expr(p, n.sons[i], arr)
@ -1949,11 +1964,11 @@ proc upConv(p: BProc, n: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
r, genTypeInfo(p.module, dest))
if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ,
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.s)
putIntoDest(p, d, n,
"(($1) ($2))" % [getTypeDesc(p.module, n.typ), rdLoc(a)], a.storage)
else:
putIntoDest(p, d, n.typ, "(*($1*) ($2))" %
[getTypeDesc(p.module, dest), addrLoc(a)], a.s)
putIntoDest(p, d, n, "(*($1*) ($2))" %
[getTypeDesc(p.module, dest), addrLoc(a)], a.storage)
proc downConv(p: BProc, n: PNode, d: var TLoc) =
if p.module.compileToCpp:
@ -1985,9 +2000,9 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
else:
r = "&" & r
putIntoDest(p, d, n.typ, r, a.s)
putIntoDest(p, d, n, r, a.storage)
else:
putIntoDest(p, d, n.typ, r, a.s)
putIntoDest(p, d, n, r, a.storage)
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
let t = n.typ
@ -2002,13 +2017,13 @@ proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
if d.k == locNone:
fillLoc(d, locData, t, tmp, OnStatic)
fillLoc(d, locData, n, tmp, OnStatic)
else:
putDataIntoDest(p, d, t, tmp)
putDataIntoDest(p, d, n, tmp)
# This fixes bug #4551, but we really need better dataflow
# analysis to make this 100% safe.
if t.kind notin {tySequence, tyString}:
d.s = OnStatic
d.storage = OnStatic
proc expr(p: BProc, n: PNode, d: var TLoc) =
p.currLineInfo = n.info
@ -2019,31 +2034,31 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of skMethod:
if {sfDispatcher, sfForward} * sym.flags != {}:
# we cannot produce code for the dispatcher yet:
fillProcLoc(p.module, sym)
fillProcLoc(p.module, n)
genProcPrototype(p.module, sym)
else:
genProc(p.module, sym)
putLocIntoDest(p, d, sym.loc)
of skProc, skConverter, skIterator:
of skProc, skConverter, skIterator, skFunc:
#if sym.kind == skIterator:
# echo renderTree(sym.getBody, {renderIds})
if sfCompileTime in sym.flags:
localError(n.info, "request to generate code for .compileTime proc: " &
sym.name.s)
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
if sym.loc.r == nil or sym.loc.lode == nil:
internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skConst:
if isSimpleConst(sym.typ):
putIntoDest(p, d, n.typ, genLiteral(p, sym.ast, sym.typ), OnStatic)
putIntoDest(p, d, n, genLiteral(p, sym.ast, sym.typ), OnStatic)
else:
genComplexConst(p, sym, d)
of skEnumField:
putIntoDest(p, d, n.typ, rope(sym.position))
putIntoDest(p, d, n, rope(sym.position))
of skVar, skForVar, skResult, skLet:
if {sfGlobal, sfThread} * sym.flags != {}:
genVarPrototype(p.module, sym)
genVarPrototype(p.module, n)
if sym.loc.r == nil or sym.loc.t == nil:
#echo "FAILED FOR PRCO ", p.prc.name.s
#echo renderTree(p.prc.ast, {renderIds})
@ -2051,7 +2066,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, "NimTV_->" & sym.loc.r)
putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r)
else:
putLocIntoDest(p, d, sym.loc)
else:
@ -2072,12 +2087,12 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
of nkNilLit:
if not isEmptyType(n.typ):
putIntoDest(p, d, n.typ, genLiteral(p, n))
putIntoDest(p, d, n, genLiteral(p, n))
of nkStrLit..nkTripleStrLit:
putDataIntoDest(p, d, n.typ, genLiteral(p, n))
putDataIntoDest(p, d, n, genLiteral(p, n))
of nkIntLit..nkUInt64Lit,
nkFloatLit..nkFloat128Lit, nkCharLit:
putIntoDest(p, d, n.typ, genLiteral(p, n))
putIntoDest(p, d, n, genLiteral(p, n))
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit:
genLineDir(p, n)
@ -2097,7 +2112,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
genCall(p, n, d)
of nkCurly:
if isDeepConstExpr(n) and n.len != 0:
putIntoDest(p, d, n.typ, genSetNode(p, n))
putIntoDest(p, d, n, genSetNode(p, n))
else:
genSetConstr(p, n, d)
of nkBracket:
@ -2138,7 +2153,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkLambdaKinds:
var sym = n.sons[namePos].sym
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
if sym.loc.r == nil or sym.loc.lode == nil:
internalError(n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of nkClosure: genClosure(p, n, d)
@ -2190,7 +2205,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
discard
of nkPragma: genPragma(p, n)
of nkPragmaBlock: expr(p, n.lastSon, d)
of nkProcDef, nkMethodDef, nkConverterDef:
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
if n.sons[genericParamsPos].kind == nkEmpty:
var prc = n.sons[namePos].sym
# due to a bug/limitation in the lambda lifting, unused inner procs

View file

@ -48,16 +48,17 @@ proc genVarTuple(p: BProc, n: PNode) =
initLocExpr(p, n.sons[L-1], tup)
var t = tup.t.skipTypes(abstractInst)
for i in countup(0, L-3):
var v = n.sons[i].sym
let vn = n.sons[i]
let v = vn.sym
if sfCompileTime in v.flags: continue
if sfGlobal in v.flags:
assignGlobalVar(p, v)
assignGlobalVar(p, vn)
genObjectInit(p, cpsInit, v.typ, v.loc, true)
registerGcRoot(p, v)
else:
assignLocalVar(p, v)
assignLocalVar(p, vn)
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(n[L-1]))
initLoc(field, locExpr, t.sons[i], tup.s)
initLoc(field, locExpr, vn, tup.storage)
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
@ -171,7 +172,7 @@ proc genBreakState(p: BProc, n: PNode) =
lineF(p, cpsStmts, "if ((((NI*) $1.ClE_0)[1]) < 0) break;$n", [rdLoc(a)])
# lineF(p, cpsStmts, "if (($1) < 0) break;$n", [rdLoc(a)])
proc genVarPrototypeAux(m: BModule, sym: PSym)
proc genVarPrototypeAux(m: BModule, n: PNode)
proc genGotoVar(p: BProc; value: PNode) =
if value.kind notin {nkCharLit..nkUInt64Lit}:
@ -180,7 +181,8 @@ proc genGotoVar(p: BProc; value: PNode) =
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
proc genSingleVar(p: BProc, a: PNode) =
let v = a.sons[0].sym
let vn = a.sons[0]
let v = vn.sym
if sfCompileTime in v.flags: return
if sfGoto in v.flags:
# translate 'var state {.goto.} = X' into 'goto LX':
@ -195,7 +197,7 @@ proc genSingleVar(p: BProc, a: PNode) =
if sfPure in v.flags:
# v.owner.kind != skModule:
targetProc = p.module.preInitProc
assignGlobalVar(targetProc, v)
assignGlobalVar(targetProc, vn)
# XXX: be careful here.
# Global variables should not be zeromem-ed within loops
# (see bug #20).
@ -206,7 +208,7 @@ proc genSingleVar(p: BProc, a: PNode) =
# Alternative construction using default constructor (which may zeromem):
# if sfImportc notin v.flags: constructLoc(p.module.preInitProc, v.loc)
if sfExportc in v.flags and p.module.g.generatedHeader != nil:
genVarPrototypeAux(p.module.g.generatedHeader, v)
genVarPrototypeAux(p.module.g.generatedHeader, vn)
registerGcRoot(p, v)
else:
let value = a.sons[2]
@ -217,7 +219,7 @@ proc genSingleVar(p: BProc, a: PNode) =
# parameterless constructor followed by an assignment operator. So we
# generate better code here:
genLineDir(p, a)
let decl = localVarDecl(p, v)
let decl = localVarDecl(p, vn)
var tmp: TLoc
if value.kind in nkCallKinds and value[0].kind == nkSym and
sfConstructor in value[0].sym.flags:
@ -233,7 +235,7 @@ proc genSingleVar(p: BProc, a: PNode) =
initLocExprSingleUse(p, value, tmp)
lineF(p, cpsStmts, "$# = $#;$n", [decl, tmp.rdLoc])
return
assignLocalVar(p, v)
assignLocalVar(p, vn)
initLocalVar(p, v, imm)
if a.sons[2].kind != nkEmpty:
@ -513,7 +515,7 @@ proc genParForStmt(p: BProc, t: PNode) =
preserveBreakIdx:
let forLoopVar = t.sons[0].sym
var rangeA, rangeB: TLoc
assignLocalVar(p, forLoopVar)
assignLocalVar(p, t.sons[0])
#initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack)
#discard mangleName(forLoopVar)
let call = t.sons[1]
@ -958,7 +960,7 @@ proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false): Rope =
res.add(t.sons[i].strVal)
of nkSym:
var sym = t.sons[i].sym
if sym.kind in {skProc, skIterator, skMethod}:
if sym.kind in {skProc, skFunc, skIterator, skMethod}:
var a: TLoc
initLocExpr(p, t.sons[i], a)
res.add($rdLoc(a))

View file

@ -121,7 +121,8 @@ proc genTraverseProc(m: BModule, origTyp: PType; sig: SigHash;
var c: TTraversalClosure
var p = newProc(nil, m)
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
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"

View file

@ -183,7 +183,7 @@ proc mapType(typ: PType): TCTypeKind =
of 8: result = ctInt64
else: internalError("mapType")
of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyRef:
of tyPtr, tyVar, tyRef, tyOptAsRef:
var base = skipTypes(typ.lastSon, typedescInst)
case base.kind
of tyOpenArray, tyArray, tyVarargs: result = ctPtrToArray
@ -194,6 +194,13 @@ proc mapType(typ: PType): TCTypeKind =
else: result = ctPtr
of tyPointer: result = ctPtr
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 tyString: result = ctNimStr
of tyCString: result = ctCString
@ -282,12 +289,13 @@ proc ccgIntroducedPtr(s: PSym): bool =
result = (getSize(pt) > platform.floatSize*2) or (optByRef in s.options)
else: result = false
proc fillResult(param: PSym) =
fillLoc(param.loc, locParam, param.typ, ~"Result",
proc fillResult(param: PNode) =
fillLoc(param.sym.loc, locParam, param, ~"Result",
OnStack)
if mapReturnType(param.typ) != ctArray and isInvalidReturnType(param.typ):
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
let t = param.sym.typ
if mapReturnType(t) != ctArray and isInvalidReturnType(t):
incl(param.sym.loc.flags, lfIndirect)
param.sym.loc.storage = OnUnknown
proc typeNameOrLiteral(m: BModule; t: PType, literal: string): Rope =
if t.sym != nil and sfImportc in t.sym.flags and t.sym.magic == mNone:
@ -349,7 +357,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
if result != nil: return
result = getTypePre(m, typ, sig)
if result != nil: return
let concrete = typ.skipTypes(abstractInst)
let concrete = typ.skipTypes(abstractInst + {tyOpt})
case concrete.kind
of tySequence, tyTuple, tyObject:
result = getTypeName(m, typ, sig)
@ -375,6 +383,12 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
of tySequence:
result = getTypeForward(m, t, hashType(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:
result = getTypeDescAux(m, t, check)
@ -398,13 +412,13 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
if params != nil: add(params, ~", ")
fillLoc(param.loc, locParam, param.typ, mangleParamName(m, param),
fillLoc(param.loc, locParam, t.n.sons[i], mangleParamName(m, param),
param.paramStorageLoc)
if ccgIntroducedPtr(param):
add(params, getTypeDescWeak(m, param.typ, check))
add(params, ~"*")
incl(param.loc.flags, lfIndirect)
param.loc.s = OnUnknown
param.loc.storage = OnUnknown
elif weakDep:
add(params, getTypeDescWeak(m, param.typ, check))
else:
@ -417,7 +431,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
var j = 0
while arr.kind in {tyOpenArray, tyVarargs}:
# this fixes the 'sort' bug:
if param.typ.kind == tyVar: param.loc.s = OnUnknown
if param.typ.kind == tyVar: param.loc.storage = OnUnknown
# need to pass hidden parameter:
addf(params, ", NI $1Len_$2", [param.loc.r, j.rope])
inc(j)
@ -496,16 +510,16 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
let sname = mangleRecFieldName(m, field, rectype)
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, sname]
else: sname
fillLoc(field.loc, locField, field.typ, ae, OnUnknown)
fillLoc(field.loc, locField, n, ae, OnUnknown)
# for importcpp'ed objects, we only need to set field.loc, but don't
# have to recurse via 'getTypeDescAux'. And not doing so prevents problems
# with heavily templatized C++ code:
if not isImportedCppType(rectype):
let fieldType = field.loc.t.skipTypes(abstractInst)
let fieldType = field.loc.lode.typ.skipTypes(abstractInst)
if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags:
addf(result, "$1 $2[SEQ_DECL_SIZE];$n",
[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.
addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname])
elif field.bitsize != 0:
@ -624,7 +638,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
excl(check, t.id)
return
case t.kind
of tyRef, tyPtr, tyVar:
of tyRef, tyOptAsRef, tyPtr, tyVar:
var star = if t.kind == tyVar and tfVarIsPtr notin origTyp.flags and
compileToCpp(m): "&" else: "*"
var et = origTyp.skipTypes(abstractInst).lastSon
@ -651,6 +665,21 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
result = name & "*" & star
m.typeCache[sig] = result
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 we have a strong dependency :-(
result = getTypeDescAux(m, et, check) & star
@ -726,6 +755,38 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
else:
result = rope("TGenericSeq")
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:
var n: BiggestInt = lengthOrd(t)
if n <= 0: n = 1 # make an array of at least one element
@ -861,7 +922,7 @@ proc genProcHeader(m: BModule, prc: PSym): Rope =
elif prc.typ.callConv == ccInline:
result.add "static "
var check = initIntSet()
fillLoc(prc.loc, locProc, prc.typ, mangleName(m, prc), OnUnknown)
fillLoc(prc.loc, locProc, prc.ast[namePos], mangleName(m, prc), OnUnknown)
genProcParams(m, prc.typ, rettype, params, check)
# careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph!
@ -1113,6 +1174,8 @@ proc genDeepCopyProc(m: BModule; s: PSym; result: Rope) =
proc genTypeInfo(m: BModule, t: PType): Rope =
let origType = t
var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
if t.kind == tyOpt:
return genTypeInfo(m, optLowering(t))
let sig = hashType(origType)
result = m.typeInfoMarker.getOrDefault(sig)
@ -1158,7 +1221,7 @@ proc genTypeInfo(m: BModule, t: PType): Rope =
else:
let x = fakeClosureType(t.owner)
genTupleInfo(m, x, x, result)
of tySequence, tyRef:
of tySequence, tyRef, tyOptAsRef:
genTypeInfoAux(m, t, t, result)
if gSelectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig, tiNew)

View file

@ -100,7 +100,7 @@ proc getUniqueType*(key: PType): PType =
if result == nil:
gCanonicalTypes[k] = key
result = key
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr, tyFieldAccessor:
of tyTypeDesc, tyTypeClasses, tyGenericParam, tyFromExpr:
if key.isResolvedUserTypeClass:
return getUniqueType(lastSon(key))
if key.sym != nil:
@ -126,7 +126,7 @@ proc getUniqueType*(key: PType): PType =
result = slowSearch(key, k)
of tyGenericInvocation, tyGenericBody,
tyOpenArray, tyArray, tySet, tyRange, tyTuple,
tySequence, tyForward, tyVarargs, tyProxy:
tySequence, tyForward, tyVarargs, tyProxy, tyOpt:
# we have to do a slow linear search because types may need
# to be compared by their structure:
result = slowSearch(key, k)
@ -157,7 +157,7 @@ proc getUniqueType*(key: PType): PType =
else:
# ugh, we need the canon here:
result = slowSearch(key, k)
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("getUniqueType")
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("getUniqueType")
proc makeSingleLineCString*(s: string): string =
result = "\""

View file

@ -47,21 +47,31 @@ proc findPendingModule(m: BModule, s: PSym): BModule =
var ms = getModule(s)
result = m.g.modules[ms.position]
proc initLoc(result: var TLoc, k: TLocKind, typ: PType, s: TStorageLoc) =
proc initLoc(result: var TLoc, k: TLocKind, lode: PNode, s: TStorageLoc) =
result.k = k
result.s = s
result.t = typ
result.storage = s
result.lode = lode
result.r = nil
result.flags = {}
proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: Rope, s: TStorageLoc) =
proc fillLoc(a: var TLoc, k: TLocKind, lode: PNode, r: Rope, s: TStorageLoc) =
# fills the loc if it is not already initialized
if a.k == locNone:
a.k = k
a.t = typ
a.s = s
a.lode = lode
a.storage = s
if a.r == nil: a.r = r
proc t(a: TLoc): PType {.inline.} =
if a.lode.kind == nkSym:
result = a.lode.sym.typ
else:
result = a.lode.typ
proc lodeTyp(t: PType): PNode =
result = newNode(nkEmpty)
result.typ = t
proc isSimpleConst(typ: PType): bool =
let t = skipTypes(typ, abstractVar)
result = t.kind notin
@ -286,7 +296,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
if not isComplexValueType(typ):
if containsGcRef:
var nilLoc: TLoc
initLoc(nilLoc, locTemp, loc.t, OnStack)
initLoc(nilLoc, locTemp, loc.lode, OnStack)
nilLoc.r = rope("NIM_NIL")
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
else:
@ -294,7 +304,7 @@ proc resetLoc(p: BProc, loc: var TLoc) =
else:
if optNilCheck in p.options:
linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc))
if loc.s != OnStack:
if loc.storage != OnStack:
linefmt(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
addrLoc(loc), genTypeInfo(p.module, loc.t))
# XXX: generated reset procs should not touch the m_type
@ -340,8 +350,8 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) =
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r)
result.k = locTemp
result.t = t
result.s = OnStack
result.lode = lodeTyp t
result.storage = OnStack
result.flags = {}
constructLoc(p, result, not needsInit)
@ -350,8 +360,8 @@ proc getIntTemp(p: BProc, result: var TLoc) =
result.r = "T" & rope(p.labels) & "_"
linefmt(p, cpsLocals, "NI $1;$n", result.r)
result.k = locTemp
result.s = OnStack
result.t = getSysType(tyInt)
result.storage = OnStack
result.lode = lodeTyp getSysType(tyInt)
result.flags = {}
proc initGCFrame(p: BProc): Rope =
@ -375,9 +385,10 @@ proc localDebugInfo(p: BProc, s: PSym) =
inc(p.maxFrameLen)
inc p.blocks[p.blocks.len-1].frameLen
proc localVarDecl(p: BProc; s: PSym): Rope =
proc localVarDecl(p: BProc; n: PNode): Rope =
let s = n.sym
if s.loc.k == locNone:
fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack)
fillLoc(s.loc, locLocalVar, n, mangleLocalName(p, s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
result = getTypeDesc(p.module, s.typ)
if s.constraint.isNil:
@ -390,23 +401,24 @@ proc localVarDecl(p: BProc; s: PSym): Rope =
else:
result = s.cgDeclFrmt % [result, s.loc.r]
proc assignLocalVar(p: BProc, s: PSym) =
proc assignLocalVar(p: BProc, n: PNode) =
#assert(s.loc.k == locNone) # not yet assigned
# this need not be fulfilled for inline procs; they are regenerated
# for each module that uses them!
let nl = if optLineDir in gOptions: "" else: tnl
let decl = localVarDecl(p, s) & ";" & nl
let decl = localVarDecl(p, n) & ";" & nl
line(p, cpsLocals, decl)
localDebugInfo(p, s)
localDebugInfo(p, n.sym)
include ccgthreadvars
proc varInDynamicLib(m: BModule, sym: PSym)
proc mangleDynLibProc(sym: PSym): Rope
proc assignGlobalVar(p: BProc, s: PSym) =
proc assignGlobalVar(p: BProc, n: PNode) =
let s = n.sym
if s.loc.k == locNone:
fillLoc(s.loc, locGlobalVar, s.typ, mangleName(p.module, s), OnHeap)
fillLoc(s.loc, locGlobalVar, n, mangleName(p.module, s), OnHeap)
if lfDynamicLib in s.loc.flags:
var q = findPendingModule(p.module, s)
@ -446,9 +458,10 @@ proc assignParam(p: BProc, s: PSym) =
scopeMangledParam(p, s)
localDebugInfo(p, s)
proc fillProcLoc(m: BModule; sym: PSym) =
proc fillProcLoc(m: BModule; n: PNode) =
let sym = n.sym
if sym.loc.k == locNone:
fillLoc(sym.loc, locProc, sym.typ, mangleName(m, sym), OnStack)
fillLoc(sym.loc, locProc, n, mangleName(m, sym), OnStack)
proc getLabel(p: BProc): TLabel =
inc(p.labels)
@ -457,7 +470,7 @@ proc getLabel(p: BProc): TLabel =
proc fixLabel(p: BProc, labl: TLabel) =
lineF(p, cpsStmts, "$1: ;$n", [labl])
proc genVarPrototype(m: BModule, sym: PSym)
proc genVarPrototype(m: BModule, n: PNode)
proc requestConstImpl(p: BProc, sym: PSym)
proc genStmts(p: BProc, t: PNode)
proc expr(p: BProc, n: PNode, d: var TLoc)
@ -469,11 +482,11 @@ proc genLiteral(p: BProc, n: PNode): Rope
proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown)
initLoc(result, locNone, e, OnUnknown)
expr(p, e, result)
proc initLocExprSingleUse(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, e.typ, OnUnknown)
initLoc(result, locNone, e, OnUnknown)
result.flags.incl lfSingleUse
expr(p, e, result)
@ -590,8 +603,8 @@ proc cgsym(m: BModule, name: string): Rope =
var sym = magicsys.getCompilerProc(name)
if sym != nil:
case sym.kind
of skProc, skMethod, skConverter, skIterator: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, sym)
of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
of skType: discard getTypeDesc(m, sym.typ)
else: internalError("cgsym: " & name & ": " & $sym.kind)
else:
@ -645,7 +658,7 @@ proc closureSetup(p: BProc, prc: PSym) =
internalError(prc.info, "closure generation failed")
var env = ls.sym
#echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, env)
assignLocalVar(p, ls)
# generate cast assignment:
linefmt(p, cpsStmts, "$1 = ($2) ClE_0;$n",
rdLoc(env.loc), getTypeDesc(p.module, env.typ))
@ -676,29 +689,30 @@ proc genProcAux(m: BModule, prc: PSym) =
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
internalError(prc.info, "proc has no result symbol")
var res = prc.ast.sons[resultPos].sym # get result symbol
let resNode = prc.ast.sons[resultPos]
let res = resNode.sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]):
if sfNoInit in prc.flags: incl(res.flags, sfNoInit)
if sfNoInit in prc.flags and p.module.compileToCpp and (let val = easyResultAsgn(prc.getBody); val != nil):
var decl = localVarDecl(p, res)
var decl = localVarDecl(p, resNode)
var a: TLoc
initLocExprSingleUse(p, val, a)
linefmt(p, cpsStmts, "$1 = $2;$n", decl, rdLoc(a))
else:
# declare the result symbol:
assignLocalVar(p, res)
assignLocalVar(p, resNode)
assert(res.loc.r != nil)
initLocalVar(p, res, immediateAsgn=false)
returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
else:
fillResult(res)
fillResult(resNode)
assignParam(p, res)
if skipTypes(res.typ, abstractInst).kind == tyArray:
#incl(res.loc.flags, lfIndirect)
res.loc.s = OnUnknown
res.loc.storage = OnUnknown
for i in countup(1, sonsLen(prc.typ.n) - 1):
var param = prc.typ.n.sons[i].sym
let param = prc.typ.n.sons[i].sym
if param.typ.isCompileTimeOnly: continue
assignParam(p, param)
closureSetup(p, prc)
@ -764,13 +778,13 @@ proc genProcPrototype(m: BModule, sym: PSym) =
proc genProcNoForward(m: BModule, prc: PSym) =
if lfImportCompilerProc in prc.loc.flags:
fillProcLoc(m, prc)
fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc)
# dependency to a compilerproc:
discard cgsym(m, prc.name.s)
return
if lfNoDecl in prc.loc.flags:
fillProcLoc(m, prc)
fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc)
genProcPrototype(m, prc)
elif prc.typ.callConv == ccInline:
@ -779,7 +793,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
# a check for ``m.declaredThings``.
if not containsOrIncl(m.declaredThings, prc.id):
#if prc.loc.k == locNone:
fillProcLoc(m, prc)
fillProcLoc(m, prc.ast[namePos])
#elif {sfExportc, sfImportc} * prc.flags == {}:
# # reset name to restore consistency in case of hashing collisions:
# echo "resetting ", prc.id, " by ", m.module.name.s
@ -790,7 +804,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
genProcAux(m, prc)
elif lfDynamicLib in prc.loc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc)
fillProcLoc(q, prc.ast[namePos])
useHeader(m, prc)
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
@ -799,13 +813,13 @@ proc genProcNoForward(m: BModule, prc: PSym) =
symInDynamicLibPartial(m, prc)
elif sfImportc notin prc.flags:
var q = findPendingModule(m, prc)
fillProcLoc(q, prc)
fillProcLoc(q, prc.ast[namePos])
useHeader(m, prc)
genProcPrototype(m, prc)
if q != nil and not containsOrIncl(q.declaredThings, prc.id):
genProcAux(q, prc)
else:
fillProcLoc(m, prc)
fillProcLoc(m, prc.ast[namePos])
useHeader(m, prc)
if sfInfixCall notin prc.flags: genProcPrototype(m, prc)
@ -813,7 +827,7 @@ proc requestConstImpl(p: BProc, sym: PSym) =
var m = p.module
useHeader(m, sym)
if sym.loc.k == locNone:
fillLoc(sym.loc, locData, sym.typ, mangleName(p.module, sym), OnStatic)
fillLoc(sym.loc, locData, sym.ast, mangleName(p.module, sym), OnStatic)
if lfNoDecl in sym.loc.flags: return
# declare implementation:
var q = findPendingModule(m, sym)
@ -836,7 +850,7 @@ proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags or not isActivated(prc): return
if sfForward in prc.flags:
addForwardedProc(m, prc)
fillProcLoc(m, prc)
fillProcLoc(m, prc.ast[namePos])
else:
genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
@ -846,10 +860,11 @@ proc genProc(m: BModule, prc: PSym) =
if not containsOrIncl(m.g.generatedHeader.declaredThings, prc.id):
genProcAux(m.g.generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
proc genVarPrototypeAux(m: BModule, n: PNode) =
#assert(sfGlobal in sym.flags)
let sym = n.sym
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(m, sym), OnHeap)
fillLoc(sym.loc, locGlobalVar, n, mangleName(m, sym), OnHeap)
if (lfNoDecl in sym.loc.flags) or containsOrIncl(m.declaredThings, sym.id):
return
if sym.owner.id != m.module.id:
@ -865,8 +880,8 @@ proc genVarPrototypeAux(m: BModule, sym: PSym) =
if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc genVarPrototype(m: BModule, sym: PSym) =
genVarPrototypeAux(m, sym)
proc genVarPrototype(m: BModule, n: PNode) =
genVarPrototypeAux(m, n)
proc addIntTypes(result: var Rope) {.inline.} =
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &

View file

@ -107,3 +107,4 @@ proc initDefines*() =
defineSymbol("nimDistros")
defineSymbol("nimHasCppDefine")
defineSymbol("nimGenericInOutFlags")
when false: defineSymbol("nimHasOpt")

View file

@ -325,7 +325,7 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string =
## section of ``doc/docgen.txt``.
result = baseName
case k:
of skProc: result.add(defaultParamSeparator)
of skProc, skFunc: result.add(defaultParamSeparator)
of skMacro: result.add(".m" & defaultParamSeparator)
of skMethod: result.add(".e" & defaultParamSeparator)
of skIterator: result.add(".i" & defaultParamSeparator)
@ -341,7 +341,7 @@ proc isCallable(n: PNode): bool =
## Returns true if `n` contains a callable node.
case n.kind
of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkTemplateDef,
nkConverterDef: result = true
nkConverterDef, nkFuncDef: result = true
else:
result = false
@ -533,6 +533,9 @@ proc generateDoc*(d: PDoc, n: PNode) =
of nkProcDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skProc)
of nkFuncDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skFunc)
of nkMethodDef:
when useEffectSystem: documentRaises(n)
genItem(d, n, n.sons[namePos], skMethod)
@ -574,6 +577,9 @@ proc generateJson*(d: PDoc, n: PNode) =
of nkProcDef:
when useEffectSystem: documentRaises(n)
d.add genJsonItem(d, n, n.sons[namePos], skProc)
of nkFuncDef:
when useEffectSystem: documentRaises(n)
d.add genJsonItem(d, n, n.sons[namePos], skFunc)
of nkMethodDef:
when useEffectSystem: documentRaises(n)
d.add genJsonItem(d, n, n.sons[namePos], skMethod)
@ -604,8 +610,8 @@ proc generateJson*(d: PDoc, n: PNode) =
proc genSection(d: PDoc, kind: TSymKind) =
const sectionNames: array[skModule..skTemplate, string] = [
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Methods",
"Iterators", "Converters", "Macros", "Templates"
"Imports", "Types", "Vars", "Lets", "Consts", "Vars", "Procs", "Funcs",
"Methods", "Iterators", "Converters", "Macros", "Templates"
]
if d.section[kind] == nil: return
var title = sectionNames[kind].rope

View file

@ -652,9 +652,10 @@ proc getLinkCmd(projectfile, objfiles: string): string =
else:
var linkerExe = getConfigVar(cCompiler, ".linkerexe")
if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(): result = quoteShell(linkerExe)
else: result = quoteShell(joinPath(ccompilerpath, linkerExe))
if noAbsolutePaths(): result = linkerExe
else: result = joinPath(ccompilerpath, linkerExe)
let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
else: ""
var exefile, builddll: string
@ -701,6 +702,40 @@ template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed
rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode)
raise
proc execLinkCmd(linkCmd: string) =
tryExceptOSErrorMessage("invocation of external linker program failed."):
execExternalProgram(linkCmd,
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) =
let runCb = proc (idx: int, p: Process) =
let exitCode = p.peekExitCode
if exitCode != 0:
rawMessage(errGenerated, "execution of an external compiler program '" &
cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
p.outputStream.readAll.strip)
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
if gNumberOfProcessors <= 1:
for i in countup(0, high(cmds)):
tryExceptOSErrorMessage("invocation of external compiler program failed."):
res = execWithEcho(cmds[i])
if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
else:
tryExceptOSErrorMessage("invocation of external compiler program failed."):
if optListCmd in gGlobalOptions or gVerbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, afterRunEvent=runCb)
elif gVerbosity == 1:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
else:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, afterRunEvent=runCb)
if res != 0:
if gNumberOfProcessors <= 1:
rawMessage(errExecutionOfProgramFailed, cmds.join())
proc callCCompiler*(projectfile: string) =
var
linkCmd: string
@ -713,35 +748,9 @@ proc callCCompiler*(projectfile: string) =
var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
let runCb = proc (idx: int, p: Process) =
let exitCode = p.peekExitCode
if exitCode != 0:
rawMessage(errGenerated, "execution of an external compiler program '" &
cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
p.outputStream.readAll.strip)
compileCFile(toCompile, script, cmds, prettyCmds)
if optCompileOnly notin gGlobalOptions:
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
var res = 0
if gNumberOfProcessors <= 1:
for i in countup(0, high(cmds)):
tryExceptOSErrorMessage("invocation of external compiler program failed."):
res = execWithEcho(cmds[i])
if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
else:
tryExceptOSErrorMessage("invocation of external compiler program failed."):
if optListCmd in gGlobalOptions or gVerbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, afterRunEvent=runCb)
elif gVerbosity == 1:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
else:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath, poParentStreams},
gNumberOfProcessors, afterRunEvent=runCb)
if res != 0:
if gNumberOfProcessors <= 1:
rawMessage(errExecutionOfProgramFailed, cmds.join())
execCmdsInParallel(cmds, prettyCb)
if optNoLinking notin gGlobalOptions:
# call the linker:
var objfiles = ""
@ -756,9 +765,7 @@ proc callCCompiler*(projectfile: string) =
linkCmd = getLinkCmd(projectfile, objfiles)
if optCompileOnly notin gGlobalOptions:
tryExceptOSErrorMessage("invocation of external linker program failed."):
execExternalProgram(linkCmd,
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
execLinkCmd(linkCmd)
else:
linkCmd = ""
if optGenScript in gGlobalOptions:
@ -766,7 +773,8 @@ proc callCCompiler*(projectfile: string) =
add(script, tnl)
generateScript(projectfile, script)
from json import escapeJson
#from json import escapeJson
import json
proc writeJsonBuildInstructions*(projectfile: string) =
template lit(x: untyped) = f.write x
@ -834,6 +842,34 @@ proc writeJsonBuildInstructions*(projectfile: string) =
lit "\L}\L"
close(f)
proc runJsonBuildInstructions*(projectfile: string) =
let file = projectfile.splitFile.name
let jsonFile = toGeneratedFile(file, "json")
try:
let data = json.parseFile(jsonFile)
let toCompile = data["compile"]
doAssert toCompile.kind == JArray
var cmds: TStringSeq = @[]
var prettyCmds: TStringSeq = @[]
for c in toCompile:
doAssert c.kind == JArray
doAssert c.len >= 2
add(cmds, c[1].getStr)
let (_, name, _) = splitFile(c[0].getStr)
add(prettyCmds, "CC: " & name)
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
execCmdsInParallel(cmds, prettyCb)
let linkCmd = data["linkcmd"]
doAssert linkCmd.kind == JString
execLinkCmd(linkCmd.getStr)
except:
echo getCurrentException().getStackTrace()
quit "error evaluating JSON file: " & jsonFile
proc genMappingFiles(list: CFileList): Rope =
for it in list:
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])

83
compiler/gorgeimpl.nim Normal file
View file

@ -0,0 +1,83 @@
#
#
# The Nim Compiler
# (c) Copyright 2017 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Module that implements ``gorge`` for the compiler as well as
## the scriptable import mechanism.
import msgs, securehash, os, osproc, streams, strutils, options
proc readOutput(p: Process): (string, int) =
result[0] = ""
var output = p.outputStream
while not output.atEnd:
result[0].add(output.readLine)
result[0].add("\n")
if result[0].len > 0:
result[0].setLen(result[0].len - "\n".len)
result[1] = p.waitForExit
proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) =
let workingDir = parentDir(info.toFullPath)
if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile("gorge_" & $h, "txt")
var f: File
if open(f, filename):
result = (f.readAll, 0)
f.close
return
var readSuccessful = false
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
readSuccessful = true
# only cache successful runs:
if result[1] == 0:
writeFile(filename, result[0])
except IOError, OSError:
if not readSuccessful: result = ("", -1)
else:
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
except IOError, OSError:
result = ("", -1)
proc scriptableImport*(pkg, subdir: string; info: TLineInfo): string =
var cmd = getConfigVar("resolver.exe")
if cmd.len == 0: cmd = "nimresolve"
else: cmd = quoteShell(cmd)
cmd.add " --source:"
cmd.add quoteShell(info.toFullPath())
cmd.add " --stdlib:"
cmd.add quoteShell(options.libpath)
cmd.add " --project:"
cmd.add quoteShell(gProjectFull)
if subdir.len != 0:
cmd.add " --subdir:"
cmd.add quoteShell(subdir)
if options.gNoNimblePath:
cmd.add " --nonimblepath"
cmd.add ' '
cmd.add quoteShell(pkg)
let (res, exitCode) = opGorge(cmd, "", cmd, info)
if exitCode == 0:
result = res.strip()
elif res.len > 0:
localError(info, res)
else:
localError(info, "cannot resolve: " & (pkg / subdir))

View file

@ -11,11 +11,22 @@
import
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
semdata, passes, renderer
semdata, passes, renderer, gorgeimpl
proc evalImport*(c: PContext, n: PNode): PNode
proc evalFrom*(c: PContext, n: PNode): PNode
proc lookupPackage(pkg, subdir: PNode): string =
let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: ""
case pkg.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
result = scriptableImport(pkg.strVal, sub, pkg.info)
of nkIdent:
result = scriptableImport(pkg.ident.s, sub, pkg.info)
else:
localError(pkg.info, "package name must be an identifier or string literal")
result = ""
proc getModuleName*(n: PNode): string =
# This returns a short relative module name without the nim extension
# e.g. like "system", "importer" or "somepath/module"
@ -31,16 +42,33 @@ proc getModuleName*(n: PNode): string =
result = n.ident.s
of nkSym:
result = n.sym.name.s
of nkInfix, nkPrefix:
if n.sons[0].kind == nkIdent and n.sons[0].ident.id == getIdent("as").id:
of nkInfix:
let n0 = n[0]
let n1 = n[1]
if n0.kind == nkIdent and n0.ident.id == getIdent("as").id:
# XXX hack ahead:
n.kind = nkImportAs
n.sons[0] = n.sons[1]
n.sons[1] = n.sons[2]
n.sons.setLen(2)
return getModuleName(n.sons[0])
# hacky way to implement 'x / y /../ z':
result = renderTree(n, {renderNoComments}).replace(" ")
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
if n0.kind == nkIdent and n0.ident.s == "/":
result = lookupPackage(n1[1], n[2])
else:
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
# hacky way to implement 'x / y /../ z':
result = getModuleName(n1)
result.add renderTree(n0, {renderNoComments})
result.add getModuleName(n[2])
of nkPrefix:
if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$":
result = lookupPackage(n[1], nil)
else:
# hacky way to implement 'x / y /../ z':
result = renderTree(n, {renderNoComments}).replace(" ")
of nkDotExpr:
result = renderTree(n, {renderNoComments}).replace(".", "/")
of nkImportAs:
@ -60,6 +88,11 @@ proc checkModuleName*(n: PNode; doLocalError=true): int32 =
else:
result = fullPath.fileInfoIdx
proc importPureEnumField*(c: PContext; s: PSym) =
var check = strTableGet(c.importTable.symbols, s.name)
if check == nil:
strTableAdd(c.pureEnumFields, s)
proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be
# pointless in practice. So importing stubs is fine here!
@ -75,7 +108,7 @@ proc rawImportSymbol(c: PContext, s: PSym) =
strTableAdd(c.importTable.symbols, s)
if s.kind == skType:
var etyp = s.typ
if etyp.kind in {tyBool, tyEnum} and sfPure notin s.flags:
if etyp.kind in {tyBool, tyEnum}:
for j in countup(0, sonsLen(etyp.n) - 1):
var e = etyp.n.sons[j].sym
if e.kind != skEnumField:
@ -91,7 +124,10 @@ proc rawImportSymbol(c: PContext, s: PSym) =
break
check = nextIdentIter(it, c.importTable.symbols)
if e != nil:
rawImportSymbol(c, e)
if sfPure notin s.flags:
rawImportSymbol(c, e)
else:
importPureEnumField(c, e)
else:
# rodgen assures that converters and patterns are no stubs
if s.kind == skConverter: addConverter(c, s)
@ -201,12 +237,14 @@ proc evalImport(c: PContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
let sep = renderTree(it.sons[0], {renderNoComments})
let dir = renderTree(it.sons[1], {renderNoComments})
let sep = it[0]
let dir = it[1]
let a = newNodeI(nkInfix, it.info)
a.add sep
a.add dir
a.add sep # dummy entry, replaced in the loop
for x in it[2]:
let f = renderTree(x, {renderNoComments})
let a = newStrNode(nkStrLit, (dir & sep & f).replace(" "))
a.info = it.info
a.sons[2] = x
impMod(c, a)
else:
impMod(c, it)

View file

@ -187,12 +187,12 @@ proc mapType(typ: PType): TJSTypeKind =
of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table
of tyString, tySequence: result = etySeq
of tyString, tySequence, tyOpt: result = etySeq
of tyObject, tyArray, tyTuple, tyOpenArray, tyVarargs:
result = etyObject
of tyNil: result = etyNull
of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvocation,
tyNone, tyFromExpr, tyForward, tyEmpty, tyFieldAccessor,
tyNone, tyFromExpr, tyForward, tyEmpty,
tyExpr, tyStmt, tyTypeDesc, tyTypeClasses, tyVoid, tyAlias:
result = etyNone
of tyInferred:
@ -202,7 +202,7 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone
of tyProc: result = etyProc
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 =
if p.target == targetPHP: result = etyObject
@ -292,7 +292,7 @@ proc useMagic(p: PProc, name: string) =
if name.len == 0: return
var s = magicsys.getCompilerProc(name)
if s != nil:
internalAssert s.kind in {skProc, skMethod, skConverter}
internalAssert s.kind in {skProc, skFunc, skMethod, skConverter}
if not p.g.generatedSyms.containsOrIncl(s.id):
let code = genProc(p, s)
add(p.g.constants, code)
@ -927,7 +927,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
# we don't care if it's an etyBaseIndex (global) of a string, it's
# still a string that needs to be copied properly:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyString}:
if x.typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}:
xtyp = etySeq
case xtyp
of etySeq:
@ -971,7 +971,7 @@ proc genFastAsgn(p: PProc, n: PNode) =
# See bug #5933. So we try to be more compatible with the C backend semantics
# here for 'shallowCopy'. This is an educated guess and might require further
# changes later:
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyString}
let noCopy = n[0].typ.skipTypes(abstractInst).kind in {tySequence, tyOpt, tyString}
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=noCopy)
proc genSwap(p: PProc, n: PNode) =
@ -1111,7 +1111,7 @@ template isIndirect(x: PSym): bool =
({sfAddrTaken, sfGlobal} * v.flags != {} and
#(mapType(v.typ) != etyObject) and
{sfImportc, sfVolatile, sfExportc} * v.flags == {} and
v.kind notin {skProc, skConverter, skMethod, skIterator,
v.kind notin {skProc, skFunc, skConverter, skMethod, skIterator,
skConst, skTemp, skLet} and p.target == targetJS)
proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
@ -1237,7 +1237,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else:
r.res = "$" & s.loc.r
p.declareGlobal(s.id, r.res)
of skProc, skConverter, skMethod:
of skProc, skFunc, skConverter, skMethod:
discard mangleName(s, p.target)
if p.target == targetPHP and r.kind != resCallee:
r.res = makeJsString($s.loc.r)
@ -1550,7 +1550,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = putToSeq("[null, 0]", indirect)
else:
result = putToSeq("null", indirect)
of tySequence, tyString, tyCString, tyPointer, tyProc:
of tySequence, tyOpt, tyString, tyCString, tyPointer, tyProc:
result = putToSeq("null", indirect)
of tyStatic:
if t.n != nil:
@ -2338,7 +2338,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef: discard
of nkPragma: genPragma(p, n)
of nkProcDef, nkMethodDef, nkConverterDef:
of nkProcDef, nkFuncDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
genSym(p, n.sons[namePos], r)

View file

@ -194,7 +194,7 @@ proc illegalCapture(s: PSym): bool {.inline.} =
s.kind == skResult
proc isInnerProc(s: PSym): bool =
if s.kind in {skProc, skMethod, skConverter, skIterator} and s.magic == mNone:
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and s.magic == mNone:
result = s.skipGenericOwner.kind in routineKinds
proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
@ -371,7 +371,8 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
case n.kind
of nkSym:
let s = n.sym
if s.kind in {skProc, skMethod, skConverter, skIterator} and s.typ != nil and s.typ.callConv == ccClosure:
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator} and
s.typ != nil and s.typ.callConv == ccClosure:
# this handles the case that the inner proc was declared as
# .closure but does not actually capture anything:
addClosureParam(c, s, n.info)
@ -443,7 +444,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
discard
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef:
discard
of nkLambdaKinds, nkIteratorDef:
of nkLambdaKinds, nkIteratorDef, nkFuncDef:
if n.typ != nil:
detectCapturedVars(n[namePos], owner, c)
else:
@ -730,7 +731,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# now we know better, so patch it:
n.sons[0] = x.sons[0]
n.sons[1] = x.sons[1]
of nkLambdaKinds, nkIteratorDef:
of nkLambdaKinds, nkIteratorDef, nkFuncDef:
if n.typ != nil and n[namePos].kind == nkSym:
let m = newSymNode(n[namePos].sym)
m.typ = n.typ

View file

@ -48,7 +48,7 @@ type
tkShl, tkShr, tkStatic,
tkTemplate,
tkTry, tkTuple, tkType, tkUsing,
tkVar, tkWhen, tkWhile, tkWith, tkWithout, tkXor,
tkVar, tkWhen, tkWhile, tkXor,
tkYield, # end of keywords
tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit,
tkUIntLit, tkUInt8Lit, tkUInt16Lit, tkUInt32Lit, tkUInt64Lit,
@ -89,7 +89,7 @@ const
"shl", "shr", "static",
"template",
"try", "tuple", "type", "using",
"var", "when", "while", "with", "without", "xor",
"var", "when", "while", "xor",
"yield",
"tkIntLit", "tkInt8Lit", "tkInt16Lit", "tkInt32Lit", "tkInt64Lit",
"tkUIntLit", "tkUInt8Lit", "tkUInt16Lit", "tkUInt32Lit", "tkUInt64Lit",

View file

@ -144,8 +144,10 @@ type
proc getSymRepr*(s: PSym): string =
case s.kind
of skProc, skMethod, skConverter, skIterator: result = getProcHeader(s)
else: result = s.name.s
of skProc, skFunc, skMethod, skConverter, skIterator:
result = getProcHeader(s)
else:
result = s.name.s
proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
# check if all symbols have been used and defined:
@ -286,7 +288,7 @@ proc lookUp*(c: PContext, n: PNode): PSym =
type
TLookupFlag* = enum
checkAmbiguity, checkUndeclared, checkModule
checkAmbiguity, checkUndeclared, checkModule, checkPureEnumFields
proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
@ -297,6 +299,8 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = searchInScopes(c, ident).skipAlias(n)
else:
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
if result == nil and checkPureEnumFields in flags:
result = strTableGet(c.pureEnumFields, ident)
if result == nil and checkUndeclared in flags:
fixSpelling(n, ident, searchInScopes)
errorUndeclaredIdentifier(c, n.info, ident.s)

View file

@ -633,7 +633,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
if fn.kind == nkClosure:
localError(n.info, "closure in spawn environment is not allowed")
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
skMethod, skConverter}):
skFunc, skMethod, skConverter}):
# for indirect calls we pass the function pointer in the scratchObj
var argType = n[0].typ.skipTypes(abstractInst)
var field = newSym(skField, getIdent"fn", owner, n.info)

View file

@ -78,6 +78,10 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
extccomp.callCCompiler(proj)
extccomp.writeJsonBuildInstructions(proj)
proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) =
let proj = changeFileExt(gProjectFull, "")
extccomp.runJsonBuildInstructions(proj)
proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
#incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS)
@ -266,6 +270,9 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
of "nop", "help":
# prevent the "success" message:
gCmd = cmdDump
of "jsonscript":
gCmd = cmdJsonScript
commandJsonScript(graph, cache)
else:
rawMessage(errInvalidCommandX, command)

View file

@ -119,4 +119,6 @@ condsyms.initDefines()
when not defined(selftest):
handleCmdLine(newIdentCache(), newConfigRef())
when declared(GC_setMaxPause):
echo GC_getStatistics()
msgQuit(int8(msgs.gErrorCounter > 0))

View file

@ -16,11 +16,11 @@ proc addPath*(path: string, info: TLineInfo) =
options.searchPaths.insert(path, 0)
type
Version = distinct string
Version* = distinct string
proc `$`(ver: Version): string {.borrow.}
proc `$`*(ver: Version): string {.borrow.}
proc newVersion(ver: string): Version =
proc newVersion*(ver: string): Version =
doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits,
"Wrong version: " & ver)
return Version(ver)
@ -28,7 +28,7 @@ proc newVersion(ver: string): Version =
proc isSpecial(ver: Version): bool =
return ($ver).len > 0 and ($ver)[0] == '#'
proc `<`(ver: Version, ver2: Version): bool =
proc `<`*(ver: Version, ver2: Version): bool =
## This is synced from Nimble's version module.
# Handling for special versions such as "#head" or "#branch".

View file

@ -91,7 +91,8 @@ type
cmdRst2html, # convert a reStructuredText file to HTML
cmdRst2tex, # convert a reStructuredText file to TeX
cmdInteractive, # start interactive session
cmdRun # run the project via TCC backend
cmdRun, # run the project via TCC backend
cmdJsonScript # compile a .json build file
TStringSeq* = seq[string]
TGCMode* = enum # the selected GC
gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc,

View file

@ -255,13 +255,6 @@ proc isUnary(p: TParser): bool =
p.tok.strongSpaceB == 0 and
p.tok.strongSpaceA > 0:
result = true
# versions prior to 0.13.0 used to do this:
when false:
if p.strongSpaces:
result = true
else:
parMessage(p, warnDeprecated,
"will be parsed as unary operator; inconsistent spacing")
proc checkBinary(p: TParser) {.inline.} =
## Check if the current parser token is a binary operator.
@ -700,12 +693,7 @@ proc primarySuffix(p: var TParser, r: PNode, baseIndent: int): PNode =
result = r
template somePar() =
if p.tok.strongSpaceA > 0:
if p.strongSpaces:
break
else:
parMessage(p, warnDeprecated,
"a [b] will be parsed as command syntax; spacing")
if p.tok.strongSpaceA > 0: break
# progress guaranteed
while p.tok.indent < 0 or
(p.tok.tokType == tkDot and p.tok.indent >= baseIndent):
@ -991,7 +979,7 @@ proc parseDoBlock(p: var TParser; info: TLineInfo): PNode =
if params.kind != nkEmpty:
result = newProcNode(nkDo, info, result, params = params, pragmas = pragmas)
proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
proc parseProcExpr(p: var TParser; isExpr: bool; kind: TNodeKind): PNode =
#| procExpr = 'proc' paramListColon pragmas? ('=' COMMENT? stmt)?
# either a proc type or a anonymous proc
let info = parLineInfo(p)
@ -1002,7 +990,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
if p.tok.tokType == tkEquals and isExpr:
getTok(p)
skipComment(p, result)
result = newProcNode(nkLambda, info, parseStmt(p),
result = newProcNode(kind, info, parseStmt(p),
params = params,
pragmas = pragmas)
else:
@ -1014,7 +1002,7 @@ proc parseProcExpr(p: var TParser, isExpr: bool): PNode =
proc isExprStart(p: TParser): bool =
case p.tok.tokType
of tkSymbol, tkAccent, tkOpr, tkNot, tkNil, tkCast, tkIf,
tkProc, tkIterator, tkBind, tkAddr,
tkProc, tkFunc, tkIterator, tkBind, tkAddr,
tkParLe, tkBracketLe, tkCurlyLe, tkIntLit..tkCharLit, tkVar, tkRef, tkPtr,
tkTuple, tkObject, tkType, tkWhen, tkCase, tkOut:
result = true
@ -1038,9 +1026,15 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
optInd(p, result)
if not isOperator(p.tok) and isExprStart(p):
addSon(result, primary(p, mode))
if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
let nodeKind = if p.tok.tokType == tkWith: nkWith
else: nkWithout
if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
# XXX document this feature!
var nodeKind: TNodeKind
if p.tok.ident.s == "with":
nodeKind = nkWith
elif p.tok.ident.s == "without":
nodeKind = nkWithout
else:
return result
getTok(p)
let list = newNodeP(nodeKind, p)
result.addSon list
@ -1088,21 +1082,12 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
case p.tok.tokType:
of tkTuple: result = parseTuple(p, mode == pmTypeDef)
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
of tkProc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
of tkFunc: result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkFuncDef)
of tkIterator:
when false:
if mode in {pmTypeDesc, pmTypeDef}:
result = parseProcExpr(p, false)
result.kind = nkIteratorTy
else:
# no anon iterators for now:
parMessage(p, errExprExpected, p.tok)
getTok(p) # we must consume a token here to prevend endless loops!
result = ast.emptyNode
else:
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef})
if result.kind == nkLambda: result.kind = nkIteratorDef
else: result.kind = nkIteratorTy
result = parseProcExpr(p, mode notin {pmTypeDesc, pmTypeDef}, nkLambda)
if result.kind == nkLambda: result.kind = nkIteratorDef
else: result.kind = nkIteratorTy
of tkEnum:
if mode == pmTypeDef:
result = parseEnum(p)
@ -2000,6 +1985,7 @@ proc complexOrSimpleStmt(p: var TParser): PNode =
of tkDefer: result = parseStaticOrDefer(p, nkDefer)
of tkAsm: result = parseAsm(p)
of tkProc: result = parseRoutine(p, nkProcDef)
of tkFunc: result = parseRoutine(p, nkFuncDef)
of tkMethod: result = parseRoutine(p, nkMethodDef)
of tkIterator: result = parseRoutine(p, nkIteratorDef)
of tkMacro: result = parseRoutine(p, nkMacroDef)
@ -2056,8 +2042,8 @@ proc parseStmt(p: var TParser): PNode =
else:
# the case statement is only needed for better error messages:
case p.tok.tokType
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkIterator,
tkMacro, tkType, tkConst, tkWhen, tkVar:
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
parMessage(p, errComplexStmtRequiresInd)
result = ast.emptyNode
else:

View file

@ -64,7 +64,7 @@ proc astNeeded*(s: PSym): bool =
# needs to be stored. The passes manager frees s.sons[codePos] when
# appropriate to free the procedure body's memory. This is important
# to keep memory usage down.
if (s.kind in {skMethod, skProc}) and
if (s.kind in {skMethod, skProc, skFunc}) and
({sfCompilerProc, sfCompileTime} * s.flags == {}) and
(s.typ.callConv != ccInline) and
(s.ast.sons[genericParamsPos].kind == nkEmpty):

View file

@ -906,9 +906,14 @@ proc parseTypeDescKAux(p: var TParser, kind: TNodeKind,
optInd(p, result)
if not isOperator(p.tok) and isExprStart(p):
addSon(result, primary(p, mode))
if kind == nkDistinctTy and p.tok.tokType in {tkWith, tkWithout}:
let nodeKind = if p.tok.tokType == tkWith: nkWith
else: nkWithout
if kind == nkDistinctTy and p.tok.tokType == tkSymbol:
var nodeKind: TNodeKind
if p.tok.ident.s == "with":
nodeKind = nkWith
elif p.tok.ident.s == "without":
nodeKind = nkWithout
else:
return result
getTok(p)
let list = newNodeP(nodeKind, p)
result.addSon list

View file

@ -1079,9 +1079,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gsub(g, n.sons[0])
if n.len > 1:
if n[1].kind == nkWith:
putWithSpace(g, tkWith, " with")
putWithSpace(g, tkSymbol, " with")
else:
putWithSpace(g, tkWithout, " without")
putWithSpace(g, tkSymbol, " without")
gcomma(g, n[1])
else:
put(g, tkDistinct, "distinct")
@ -1166,6 +1166,9 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
of nkProcDef:
if renderNoProcDefs notin g.flags: putWithSpace(g, tkProc, "proc")
gproc(g, n)
of nkFuncDef:
if renderNoProcDefs notin g.flags: putWithSpace(g, tkFunc, "func")
gproc(g, n)
of nkConverterDef:
if renderNoProcDefs notin g.flags: putWithSpace(g, tkConverter, "converter")
gproc(g, n)
@ -1324,7 +1327,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
if p.typ == nil or tfImplicitTypeParam notin p.typ.flags:
return true
return false
if n.hasExplicitParams:
put(g, tkBracketLe, "[")
gsemicolon(g, n)
@ -1363,7 +1366,13 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
proc renderTree(n: PNode, renderFlags: TRenderFlags = {}): string =
var g: TSrcGen
initSrcGen(g, renderFlags)
gsub(g, n)
# do not indent the initial statement list so that
# writeFile("file.nim", repr n)
# produces working Nim code:
if n.kind in {nkStmtList, nkStmtListExpr, nkStmtListType}:
gstmts(g, n, emptyContext, doIndent = false)
else:
gsub(g, n)
result = g.buf
proc renderModule(n: PNode, filename: string,

View file

@ -257,9 +257,9 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.k = low(loc.k)
if r.s[r.pos] == '*':
inc(r.pos)
loc.s = TStorageLoc(decodeVInt(r.s, r.pos))
loc.storage = TStorageLoc(decodeVInt(r.s, r.pos))
else:
loc.s = low(loc.s)
loc.storage = low(loc.storage)
if r.s[r.pos] == '$':
inc(r.pos)
loc.flags = cast[TLocFlags](int32(decodeVInt(r.s, r.pos)))
@ -267,9 +267,10 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
loc.flags = {}
if r.s[r.pos] == '^':
inc(r.pos)
loc.t = rrGetType(r, decodeVInt(r.s, r.pos), info)
loc.lode = decodeNode(r, info)
# rrGetType(r, decodeVInt(r.s, r.pos), info)
else:
loc.t = nil
loc.lode = nil
if r.s[r.pos] == '!':
inc(r.pos)
loc.r = rope(decodeStr(r.s, r.pos))
@ -588,7 +589,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
return false
of cmdNone, cmdDoc, cmdInterpret, cmdPretty, cmdGenDepend, cmdDump,
cmdCheck, cmdParse, cmdScan, cmdIdeTools, cmdDef,
cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun:
cmdRst2html, cmdRst2tex, cmdInteractive, cmdRun, cmdJsonScript:
discard
# else: trigger recompilation:
result = true

View file

@ -175,16 +175,17 @@ proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
var oldLen = result.len
result.add('<')
if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
if loc.s != low(loc.s):
if loc.storage != low(loc.storage):
add(result, '*')
encodeVInt(ord(loc.s), result)
encodeVInt(ord(loc.storage), result)
if loc.flags != {}:
add(result, '$')
encodeVInt(cast[int32](loc.flags), result)
if loc.t != nil:
if loc.lode != nil:
add(result, '^')
encodeVInt(cast[int32](loc.t.id), result)
pushType(w, loc.t)
encodeNode(w, unknownLineInfo(), loc.lode, result)
#encodeVInt(cast[int32](loc.t.id), result)
#pushType(w, loc.t)
if loc.r != nil:
add(result, '!')
encodeStr($loc.r, result)
@ -579,7 +580,7 @@ proc process(c: PPassContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
#var s = n.sons[namePos].sym
#addInterfaceSym(w, s)
of nkProcDef, nkIteratorDef, nkConverterDef,
of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
nkTemplateDef, nkMacroDef:
let s = n.sons[namePos].sym
if s == nil: internalError(n.info, "rodwrite.process")

View file

@ -449,7 +449,7 @@ include semtypes, semtempl, semgnrc, semstmts, semexprs
proc addCodeForGenerics(c: PContext, n: PNode) =
for i in countup(c.lastGenericIdx, c.generics.len - 1):
var prc = c.generics[i].inst.sym
if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone:
if prc.kind in {skProc, skFunc, skMethod, skConverter} and prc.magic == mNone:
if prc.ast == nil or prc.ast.sons[bodyPos] == nil:
internalError(prc.info, "no code for " & prc.name.s)
else:
@ -495,13 +495,15 @@ proc isImportSystemStmt(n: PNode): bool =
case n.kind
of nkImportStmt:
for x in n:
let f = checkModuleName(x, false)
if x.kind == nkIdent:
let f = checkModuleName(x, false)
if f == magicsys.systemModule.info.fileIndex:
return true
of nkImportExceptStmt, nkFromStmt:
if n[0].kind == nkIdent:
let f = checkModuleName(n[0], false)
if f == magicsys.systemModule.info.fileIndex:
return true
of nkImportExceptStmt, nkFromStmt:
let f = checkModuleName(n[0], false)
if f == magicsys.systemModule.info.fileIndex:
return true
else: discard
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =

View file

@ -185,7 +185,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
case t.kind
of tyNone, tyEmpty, tyVoid: discard
of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString,
tyPtr, tyString, tyRef:
tyPtr, tyString, tyRef, tyOpt:
defaultOp(c, t, body, x, y)
of tyArray, tySequence:
if tfHasAsgn in t.flags:
@ -227,9 +227,9 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
tyTypeDesc, tyGenericInvocation, tyForward:
internalError(c.info, "assignment requested for type: " & typeToString(t))
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyFieldAccessor, tyStatic, tyVar, tyAlias:
tyGenericInst, tyStatic, tyVar, tyAlias:
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 =
result = newType(tyProc, owner)

View file

@ -468,7 +468,7 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
for i in countup(0, len(a)-1):
var candidate = a.sons[i].sym
if candidate.kind in {skProc, skMethod, skConverter,
skIterator}:
skFunc, skIterator}:
# it suffices that the candidate has the proper number of generic
# type parameters:
if safeLen(candidate.ast.sons[genericParamsPos]) == n.len-1:

View file

@ -65,7 +65,7 @@ type
efWantStmt, efAllowStmt, efDetermineType, efExplain,
efAllowDestructor, efWantValue, efOperand, efNoSemCheck,
efNoProcvarCheck, efNoEvaluateGeneric, efInCall, efFromHlo,
TExprFlags* = set[TExprFlag]
TTypeAttachedOp* = enum
@ -112,6 +112,7 @@ type
semGenerateInstance*: proc (c: PContext, fn: PSym, pt: TIdTable,
info: TLineInfo): PSym
includedFiles*: IntSet # used to detect recursive include files
pureEnumFields*: TStrTable # pure enum fields that can be used unambiguously
userPragmas*: TStrTable
evalContext*: PEvalContext
unknownIdents*: IntSet # ids of all unknown identifiers to prevent
@ -210,6 +211,7 @@ proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext
result.converters = @[]
result.patterns = @[]
result.includedFiles = initIntSet()
initStrTable(result.pureEnumFields)
initStrTable(result.userPragmas)
result.generics = @[]
result.unknownIdents = initIntSet()
@ -371,7 +373,7 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
addSonSkipIntLit(result, intType) # basetype of range
proc markIndirect*(c: PContext, s: PSym) {.inline.} =
if s.kind in {skProc, skConverter, skMethod, skIterator}:
if s.kind in {skProc, skFunc, skConverter, skMethod, skIterator}:
incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis

View file

@ -246,8 +246,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
localError(n.info, errXExpectsTypeOrValue, opToStr[m])
else:
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
var typ = skipTypes(n.sons[1].typ, abstractVarRange +
{tyTypeDesc, tyFieldAccessor})
var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc})
case typ.kind
of tySequence, tyString, tyCString, tyOpenArray, tyVarargs:
n.typ = getSysType(tyInt)
@ -255,7 +254,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
n.typ = typ.sons[0] # indextype
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
# do not skip the range!
n.typ = n.sons[1].typ.skipTypes(abstractVar + {tyFieldAccessor})
n.typ = n.sons[1].typ.skipTypes(abstractVar)
of tyGenericParam:
# prepare this for resolving in semtypinst:
# we must use copyTree here in order to avoid creating a cycle
@ -279,7 +278,7 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode =
n[1].typ != nil and n[1].typ.kind == tyTypeDesc and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = n[1].typ.skipTypes({tyTypeDesc, tyFieldAccessor})
let t1 = n[1].typ.skipTypes({tyTypeDesc})
if n[2].kind in {nkStrLit..nkTripleStrLit}:
case n[2].strVal.normalize
@ -573,7 +572,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
optImplicitStatic notin gOptions: return
if callee.magic notin ctfeWhitelist: return
if callee.kind notin {skProc, skConverter} or callee.isGenericRoutine:
if callee.kind notin {skProc, skFunc, skConverter} or callee.isGenericRoutine:
return
if n.typ != nil and typeAllowed(n.typ, skConst) != nil: return
@ -615,10 +614,10 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
# for typeof support.
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
result = semOverloadedCall(c, n, nOrig,
{skProc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags)
{skProc, skFunc, skMethod, skConverter, skMacro, skTemplate, skIterator}, flags)
else:
result = semOverloadedCall(c, n, nOrig,
{skProc, skMethod, skConverter, skMacro, skTemplate}, flags)
{skProc, skFunc, skMethod, skConverter, skMacro, skTemplate}, flags)
if result != nil:
if result.sons[0].kind != nkSym:
@ -1086,9 +1085,6 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
if field != nil:
n.typ = makeTypeDesc(c, field.typ)
return n
#n.typ = newTypeWithSons(c, tyFieldAccessor, @[ty, field.typ])
#n.typ.n = copyTree(n)
#return n
else:
tryReadingGenericParam(ty)
return
@ -1229,7 +1225,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: nil
if s != nil:
case s.kind
of skProc, skMethod, skConverter, skIterator:
of skProc, skFunc, skMethod, skConverter, skIterator:
# type parameters: partial generic specialization
n.sons[0] = semSymGenericInstantiation(c, n.sons[0], s)
result = explicitGenericInstantiation(c, n, s)
@ -1397,7 +1393,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode =
proc semReturn(c: PContext, n: PNode): PNode =
result = n
checkSonsLen(n, 1)
if c.p.owner.kind in {skConverter, skMethod, skProc, skMacro} or (
if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or (
c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure):
if n.sons[0].kind != nkEmpty:
# transform ``return expr`` to ``result = expr; return``
@ -1620,9 +1616,10 @@ proc semExpandToAst(c: PContext, n: PNode): PNode =
# Preserve the magic symbol in order to be handled in evals.nim
internalAssert n.sons[0].sym.magic == mExpandToAst
#n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType
n.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
else: sysTypeFromName"PNimrodNode"
result = n
if n.kind == nkStmtList and n.len == 1: result = n[0]
else: result = n
result.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode"
else: sysTypeFromName"PNimrodNode"
proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym,
flags: TExprFlags = {}): PNode =
@ -2114,12 +2111,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if nfSem in n.flags: return
case n.kind
of nkIdent, nkAccQuoted:
let checks = if efNoEvaluateGeneric in flags: {checkUndeclared}
else: {checkUndeclared, checkModule, checkAmbiguity}
let checks = if efNoEvaluateGeneric in flags:
{checkUndeclared, checkPureEnumFields}
else:
{checkUndeclared, checkModule, checkAmbiguity, checkPureEnumFields}
var s = qualifiedLookUp(c, n, checks)
if c.matchedConcept == nil: semCaptureSym(s, c.p.owner)
result = semSym(c, n, s, flags)
if s.kind in {skProc, skMethod, skConverter, skIterator}:
if s.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
#performProcvarCheck(c, n, s)
result = symChoice(c, n, s, scClosed)
if result.kind == nkSym:
@ -2214,7 +2213,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
errorUseQualifier(c, n.info, s)
elif s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
of skProc, skMethod, skConverter, skIterator:
of skProc, skFunc, skMethod, skConverter, skIterator:
if s.magic == mNone: result = semDirectOp(c, n, flags)
else: result = semMagic(c, n, s, flags)
else:
@ -2328,6 +2327,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
of nkPragma: pragma(c, c.p.owner, n, stmtPragmas)
of nkIteratorDef: result = semIterator(c, n)
of nkProcDef: result = semProc(c, n)
of nkFuncDef: result = semFunc(c, n)
of nkMethodDef: result = semMethod(c, n)
of nkConverterDef: result = semConverterDef(c, n)
of nkMacroDef: result = semMacroDef(c, n)

View file

@ -486,6 +486,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n)
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n)
of mAppType: result = getAppType(n)
of mNaN: result = newFloatNodeT(NaN, n)
of mInf: result = newFloatNodeT(Inf, n)
@ -498,7 +500,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = newStrNodeT(lookupSymbol(s.name), n)
else:
result = copyTree(s.ast)
of {skProc, skMethod}:
of {skProc, skFunc, skMethod}:
result = n
of skType:
# XXX gensym'ed symbols can come here and cannot be resolved. This is
@ -522,7 +524,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkCallKinds:
if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym
if s.kind != skProc: return
if s.kind != skProc and s.kind != skFunc: return
try:
case s.magic
of mNone:

View file

@ -61,7 +61,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
of skUnknown:
# Introduced in this pass! Leave it as an identifier.
result = n
of skProc, skMethod, skIterator, skConverter, skModule:
of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
result = symChoice(c, n, s, scOpen)
of skTemplate:
if macroToExpandSym(s):
@ -105,6 +105,10 @@ proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
result = n
let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident).skipAlias(n)
if s == nil:
s = strTableGet(c.pureEnumFields, ident)
if s != nil and contains(c.ambiguousSymbols, s.id):
s = nil
if s == nil:
if ident.id notin ctx.toMixin and withinMixin notin flags:
errorUndeclaredIdentifier(c, n.info, ident.s)
@ -239,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
of skUnknown, skParam:
# Leave it as an identifier.
discard
of skProc, skMethod, skIterator, skConverter, skModule:
of skProc, skFunc, skMethod, skIterator, skConverter, skModule:
result.sons[0] = sc
# do not check of 's.magic==mRoof' here because it might be some
# other '^' but after overload resolution the proper one:
@ -433,7 +437,7 @@ proc semGenericStmt(c: PContext, n: PNode,
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkIteratorDef, nkLambdaKinds:
nkFuncDef, nkIteratorDef, nkLambdaKinds:
checkSonsLen(n, bodyPos + 1)
if n.sons[namePos].kind != nkEmpty:
addTempDecl(c, getIdentNode(n.sons[0]), skProc)

View file

@ -36,7 +36,7 @@ proc rawPushProcCon(c: PContext, owner: PSym) =
c.p = x
proc rawHandleSelf(c: PContext; owner: PSym) =
const callableSymbols = {skProc, skMethod, skConverter, skIterator, skMacro}
const callableSymbols = {skProc, skFunc, skMethod, skConverter, skIterator, skMacro}
if c.selfName != nil and owner.kind in callableSymbols and owner.typ != nil:
let params = owner.typ.n
if params.len > 1:

View file

@ -387,7 +387,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
addFactNeg(c.guards, canon(n.sons[0]))
dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma:
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
discard
else:
analyseSons(c, n)

View file

@ -835,7 +835,7 @@ proc track(tracked: PEffects, n: PNode) =
setLen(tracked.locked, oldLocked)
tracked.currLockLevel = oldLockLevel
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkLambda, nkDo:
nkMacroDef, nkTemplateDef, nkLambda, nkDo, nkFuncDef:
discard
of nkCast, nkHiddenStdConv, nkHiddenSubConv, nkConv:
if n.len == 2: track(tracked, n.sons[1])
@ -937,7 +937,7 @@ proc trackProc*(s: PSym, body: PNode) =
track(t, body)
if not isEmptyType(s.typ.sons[0]) and
{tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
s.kind in {skProc, skConverter, skMethod}:
s.kind in {skProc, skFunc, skConverter, skMethod}:
var res = s.ast.sons[resultPos].sym # get result symbol
if res.id notin t.init:
message(body.info, warnProveInit, "result")
@ -979,10 +979,10 @@ proc trackProc*(s: PSym, body: PNode) =
message(s.info, warnLockLevel,
"declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
when useWriteTracking: trackWrites(s, body)
if s.kind == skFunc: trackWrites(s, body)
proc trackTopLevelStmt*(module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef,
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
return
var effects = newNode(nkEffectList, n.info)

View file

@ -437,8 +437,6 @@ proc isDiscardUnderscore(v: PSym): bool =
proc semUsing(c: PContext; n: PNode): PNode =
result = ast.emptyNode
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using")
if not experimentalMode(c):
localError(n.info, "use the {.experimental.} pragma to enable 'using'")
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
if gCmd == cmdIdeTools: suggestStmt(c, a)
@ -493,6 +491,7 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) =
addSon(obj.n, newSymNode(field))
n.sons[0] = makeDeref x
n.sons[1] = newSymNode(field)
n.typ = field.typ
else:
localError(n.info, "implicit object field construction " &
"requires a .partial object, but got " & typeToString(obj))
@ -1233,7 +1232,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode =
s.typ = n.typ
for i in 1..<params.len:
if params[i].typ.kind in {tyTypeDesc, tyGenericParam,
tyFromExpr, tyFieldAccessor}+tyTypeClasses:
tyFromExpr}+tyTypeClasses:
localError(params[i].info, "cannot infer type of parameter: " &
params[i].sym.name.s)
#params[i].sym.owner = s
@ -1603,6 +1602,9 @@ proc semIterator(c: PContext, n: PNode): PNode =
proc semProc(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skProc, procPragmas)
proc semFunc(c: PContext, n: PNode): PNode =
result = semProcAux(c, n, skFunc, procPragmas)
proc semMethod(c: PContext, n: PNode): PNode =
if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method")
result = semProcAux(c, n, skMethod, methodPragmas)

View file

@ -449,6 +449,8 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
a.sons[2] = semTemplBody(c, a.sons[2])
of nkProcDef, nkLambdaKinds:
result = semRoutineInTemplBody(c, n, skProc)
of nkFuncDef:
result = semRoutineInTemplBody(c, n, skFunc)
of nkMethodDef:
result = semRoutineInTemplBody(c, n, skMethod)
of nkIteratorDef:

View file

@ -88,7 +88,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if not isPure: strTableAdd(c.module.tab, e)
addSon(result.n, newSymNode(e))
styleCheckDef(e)
if sfGenSym notin e.flags and not isPure: addDecl(c, e)
if sfGenSym notin e.flags:
if not isPure: addDecl(c, e)
else: importPureEnumField(c, e)
if isPure and strTableIncl(symbols, e):
wrongRedefinition(e.info, e.name.s)
inc(counter)
@ -1391,6 +1393,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of mSet: result = semSet(c, n, prev)
of mOrdinal: result = semOrdinal(c, n, 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 mTypeDesc: result = makeTypeDesc(c, semTypeNode(c, n[1], nil))
of mExpr:
@ -1590,6 +1593,8 @@ proc processMagicType(c: PContext, m: PSym) =
setMagicType(m, tySet, 0)
of mSeq:
setMagicType(m, tySequence, 0)
of mOpt:
setMagicType(m, tyOpt, 0)
of mOrdinal:
setMagicType(m, tyOrdinal, 0)
rawAddSon(m.typ, newTypeS(tyNone, c))

View file

@ -170,7 +170,7 @@ proc reResolveCallsWithTypedescParams(cl: var TReplTypeVars, n: PNode): PNode =
if isTypeParam(n[i]): needsFixing = true
if needsFixing:
n.sons[0] = newSymNode(n.sons[0].sym.owner)
return cl.c.semOverloadedCall(cl.c, n, n, {skProc}, {})
return cl.c.semOverloadedCall(cl.c, n, n, {skProc, skFunc}, {})
for i in 0 .. <n.safeLen:
n.sons[i] = reResolveCallsWithTypedescParams(cl, n[i])

View file

@ -201,7 +201,7 @@ proc hashType(c: var MD5Context, t: PType; flags: set[ConsiderFlag]) =
of tyRef, tyPtr, tyGenericBody, tyVar:
c.hashType t.lastSon, flags
if tfVarIsPtr in t.flags: c &= ".varisptr"
of tyFromExpr, tyFieldAccessor:
of tyFromExpr:
c.hashTree(t.n)
of tyTuple:
if t.n != nil and CoType notin flags:

View file

@ -936,7 +936,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
tfExplicit notin aOrig.flags
aOrig = if useTypeLoweringRuleInTypeClass:
aOrig.skipTypes({tyTypeDesc, tyFieldAccessor})
aOrig.skipTypes({tyTypeDesc})
else:
aOrig
@ -1373,7 +1373,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
# XXX: This is very hacky. It should be moved back into liftTypeParam
if x.kind in {tyGenericInst, tyArray} and
c.calleeSym != nil and
c.calleeSym.kind == skProc:
c.calleeSym.kind in {skProc, skFunc}:
let inst = prepareMetatypeForSigmatch(c.c, c.bindings, c.call.info, f)
return typeRel(c, inst, a)
@ -1832,7 +1832,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
bothMetaCounter < 100:
lastBindingsLength = m.bindings.counter
inc(bothMetaCounter)
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
@ -1865,7 +1865,7 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
else:
result = implicitConv(nkHiddenStdConv, f, arg, m, c)
of isInferred, isInferredConvertible:
if arg.kind in {nkProcDef, nkIteratorDef} + nkLambdaKinds:
if arg.kind in {nkProcDef, nkFuncDef, nkIteratorDef} + nkLambdaKinds:
result = c.semInferredLambda(c, m.bindings, arg)
elif arg.kind != nkSym:
return nil
@ -1952,7 +1952,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
z.calleeSym = m.calleeSym
var best = -1
for i in countup(0, sonsLen(arg) - 1):
if arg.sons[i].sym.kind in {skProc, skMethod, skConverter, skIterator}:
if arg.sons[i].sym.kind in {skProc, skFunc, skMethod, skConverter, skIterator}:
copyCandidate(z, m)
z.callee = arg.sons[i].typ
if tfUnresolved in z.callee.flags: continue

View file

@ -121,7 +121,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
if s.kind == skIterator:
if c.tooEarly: return n
else: return liftIterSym(n, getCurrOwner(c))
elif s.kind in {skProc, skConverter, skMethod} and not c.tooEarly:
elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
# top level .closure procs are still somewhat supported for 'Nake':
return makeClosure(s, nil, n.info)
#elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:

View file

@ -12,9 +12,6 @@
import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
proc firstOrd*(t: PType): BiggestInt
proc lastOrd*(t: PType): BiggestInt
proc lengthOrd*(t: PType): BiggestInt
type
TPreferedDesc* = enum
preferName, preferDesc, preferExported, preferModuleInfo, preferGenericArg
@ -48,8 +45,6 @@ type
proc equalParams*(a, b: PNode): TParamsEquality
# 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
# TODO: Remove tyTypeDesc from each abstractX and (where necessary)
@ -70,17 +65,6 @@ const
typedescPtrs* = abstractPtrs + {tyTypeDesc}
typedescInst* = abstractInst + {tyTypeDesc}
proc containsObject*(t: PType): bool
proc containsGarbageCollectedRef*(typ: PType): bool
proc containsHiddenPointer*(typ: PType): bool
proc canFormAcycle*(typ: PType): bool
proc isCompatibleToCString*(a: PType): bool
proc getOrdValue*(n: PNode): BiggestInt
proc computeSize*(typ: PType): BiggestInt
proc getSize*(typ: PType): BiggestInt
proc isPureObject*(typ: PType): bool
proc invalidGenericInst*(f: PType): bool
# for debugging
type
TTypeFieldResult* = enum
frNone, # type has no object type field
@ -92,16 +76,16 @@ proc analyseObjectWithTypeField*(t: PType): TTypeFieldResult
# made or intializing of the type field suffices or if there is no type field
# at all in this type.
proc invalidGenericInst(f: PType): bool =
proc invalidGenericInst*(f: PType): bool =
result = f.kind == tyGenericInst and lastSon(f) == nil
proc isPureObject(typ: PType): bool =
proc isPureObject*(typ: PType): bool =
var t = typ
while t.kind == tyObject and t.sons[0] != nil:
t = t.sons[0].skipTypes(skipPtrs)
result = t.sym != nil and sfPure in t.sym.flags
proc getOrdValue(n: PNode): BiggestInt =
proc getOrdValue*(n: PNode): BiggestInt =
case n.kind
of nkCharLit..nkUInt64Lit: result = n.intVal
of nkNilLit: result = 0
@ -116,14 +100,6 @@ proc isIntLit*(t: PType): bool {.inline.} =
proc isFloatLit*(t: PType): bool {.inline.} =
result = t.kind == tyFloat and t.n != nil and t.n.kind == nkFloatLit
proc isCompatibleToCString(a: PType): bool =
if a.kind == tyArray:
if (firstOrd(a.sons[0]) == 0) and
(skipTypes(a.sons[0], {tyRange, tyGenericInst, tyAlias}).kind in
{tyInt..tyInt64, tyUInt..tyUInt64}) and
(a.sons[1].kind == tyChar):
result = true
proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
result = sym.owner.name.s & '.' & sym.name.s & '('
var n = sym.typ.n
@ -151,7 +127,7 @@ proc elemType*(t: PType): PType =
else: result = t.lastSon
assert(result != nil)
proc isOrdinalType(t: PType): bool =
proc isOrdinalType*(t: PType): bool =
assert(t != nil)
const
# caution: uint, uint64 are no ordinal types!
@ -159,7 +135,7 @@ proc isOrdinalType(t: PType): bool =
parentKinds = {tyRange, tyOrdinal, tyGenericInst, tyAlias, tyDistinct}
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
while b.kind in {tyRange, tyGenericInst, tyAlias}: b = b.sons[0]
result = b.kind == tyEnum and tfEnumHasHoles in b.flags
@ -252,7 +228,7 @@ proc searchTypeFor(t: PType, predicate: TTypePredicate): bool =
proc isObjectPredicate(t: PType): bool =
result = t.kind == tyObject
proc containsObject(t: PType): bool =
proc containsObject*(t: PType): bool =
result = searchTypeFor(t, isObjectPredicate)
proc isObjectWithTypeFieldPredicate(t: PType): bool =
@ -297,7 +273,7 @@ proc isGCRef(t: PType): bool =
result = t.kind in GcTypeKinds or
(t.kind == tyProc and t.callConv == ccClosure)
proc containsGarbageCollectedRef(typ: PType): bool =
proc containsGarbageCollectedRef*(typ: PType): bool =
# returns true if typ contains a reference, sequence or string (all the
# things that are garbage-collected)
result = searchTypeFor(typ, isGCRef)
@ -312,7 +288,7 @@ proc containsTyRef*(typ: PType): bool =
proc isHiddenPointer(t: PType): bool =
result = t.kind in {tyString, tySequence}
proc containsHiddenPointer(typ: PType): bool =
proc containsHiddenPointer*(typ: PType): bool =
# returns true if typ contains a string, table or sequence (all the things
# that need to be copied deeply)
result = searchTypeFor(typ, isHiddenPointer)
@ -355,7 +331,7 @@ proc canFormAcycleAux(marker: var IntSet, typ: PType, startId: int): bool =
of tyProc: result = typ.callConv == ccClosure
else: discard
proc canFormAcycle(typ: PType): bool =
proc canFormAcycle*(typ: PType): bool =
var marker = initIntSet()
result = canFormAcycleAux(marker, typ, typ.id)
@ -521,7 +497,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyExpr:
internalAssert t.len == 0
result = "untyped"
of tyFromExpr, tyFieldAccessor:
of tyFromExpr:
result = renderTree(t.n)
of tyArray:
if t.sons[0].kind == tyRange:
@ -532,6 +508,8 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
typeToString(t.sons[1]) & ']'
of tySequence:
result = "seq[" & typeToString(t.sons[0]) & ']'
of tyOpt:
result = "opt[" & typeToString(t.sons[0]) & ']'
of tyOrdinal:
result = "ordinal[" & typeToString(t.sons[0]) & ']'
of tySet:
@ -605,7 +583,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = typeToStr[t.kind]
result.addTypeFlags(t)
proc firstOrd(t: PType): BiggestInt =
proc firstOrd*(t: PType): BiggestInt =
case t.kind
of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
result = 0
@ -630,7 +608,7 @@ proc firstOrd(t: PType): BiggestInt =
else:
assert(t.n.sons[0].kind == nkSym)
result = t.n.sons[0].sym.position
of tyGenericInst, tyDistinct, tyTypeDesc, tyFieldAccessor, tyAlias:
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
result = firstOrd(lastSon(t))
of tyOrdinal:
if t.len > 0: result = firstOrd(lastSon(t))
@ -639,7 +617,7 @@ proc firstOrd(t: PType): BiggestInt =
internalError("invalid kind for first(" & $t.kind & ')')
result = 0
proc lastOrd(t: PType): BiggestInt =
proc lastOrd*(t: PType): BiggestInt =
case t.kind
of tyBool: result = 1
of tyChar: result = 255
@ -666,7 +644,7 @@ proc lastOrd(t: PType): BiggestInt =
of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
result = t.n.sons[sonsLen(t.n) - 1].sym.position
of tyGenericInst, tyDistinct, tyTypeDesc, tyFieldAccessor, tyAlias:
of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias:
result = lastOrd(lastSon(t))
of tyProxy: result = 0
of tyOrdinal:
@ -676,7 +654,7 @@ proc lastOrd(t: PType): BiggestInt =
internalError("invalid kind for last(" & $t.kind & ')')
result = 0
proc lengthOrd(t: PType): BiggestInt =
proc lengthOrd*(t: PType): BiggestInt =
case t.kind
of tyInt64, tyInt32, tyInt: result = lastOrd(t)
of tyDistinct: result = lengthOrd(t.sons[0])
@ -689,6 +667,14 @@ proc lengthOrd(t: PType): BiggestInt =
else:
result = lastOrd(t) - firstOrd(t) + 1
proc isCompatibleToCString*(a: PType): bool =
if a.kind == tyArray:
if (firstOrd(a.sons[0]) == 0) and
(skipTypes(a.sons[0], {tyRange, tyGenericInst, tyAlias}).kind in
{tyInt..tyInt64, tyUInt..tyUInt64}) and
(a.sons[1].kind == tyChar):
result = true
# -------------- type equality -----------------------------------------------
type
@ -989,7 +975,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
result = a.sym.position == b.sym.position
of tyGenericInvocation, tyGenericBody, tySequence,
tyOpenArray, tySet, tyRef, tyPtr, tyVar,
tyArray, tyProc, tyVarargs, tyOrdinal, tyTypeClasses, tyFieldAccessor:
tyArray, tyProc, tyVarargs, tyOrdinal, tyTypeClasses, tyOpt:
cycleCheck()
if a.kind == tyUserTypeClass and a.n != nil: return a.n == b.n
result = sameChildrenAux(a, b, c) and sameFlags(a, b)
@ -1007,7 +993,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck()
result = sameTypeAux(a.lastSon, b.lastSon, c)
of tyNone: result = false
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("sameFlags")
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("sameFlags")
proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure()
@ -1089,7 +1075,7 @@ proc typeAllowedNode(marker: var IntSet, n: PNode, kind: TSymKind,
of nkNone..nkNilLit:
discard
else:
if n.kind == nkRecCase and kind in {skProc, skConst}:
if n.kind == nkRecCase and kind in {skProc, skFunc, skConst}:
return n[0].typ
for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i]
@ -1107,7 +1093,7 @@ proc matchType*(a: PType, pattern: openArray[tuple[k:TTypeKind, i:int]],
proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
flags: TTypeAllowedFlags = {}): PType =
assert(kind in {skVar, skLet, skConst, skProc, skParam, skResult})
assert(kind in {skVar, skLet, skConst, skProc, skFunc, skParam, skResult})
# if we have already checked the type, return true, because we stop the
# evaluation if something is wrong:
result = nil
@ -1116,7 +1102,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
var t = skipTypes(typ, abstractInst-{tyTypeDesc})
case t.kind
of tyVar:
if kind in {skProc, skConst}: return t
if kind in {skProc, skFunc, skConst}: return t
var t2 = skipTypes(t.sons[0], abstractInst-{tyTypeDesc})
case t2.kind
of tyVar:
@ -1144,7 +1130,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
of tyTypeClasses:
if not (tfGenericTypeParam in t.flags or taField notin flags): result = t
of tyGenericBody, tyGenericParam, tyGenericInvocation,
tyNone, tyForward, tyFromExpr, tyFieldAccessor:
tyNone, tyForward, tyFromExpr:
result = t
of tyNil:
if kind != skConst: result = t
@ -1160,7 +1146,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
of tyOpenArray, tyVarargs:
if kind != skParam: result = t
else: result = typeAllowedAux(marker, t.sons[0], skVar, flags)
of tySequence:
of tySequence, tyOpt:
if t.sons[0].kind != tyEmpty:
result = typeAllowedAux(marker, t.sons[0], skVar, flags+{taHeap})
of tyArray:
@ -1176,7 +1162,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
result = typeAllowedAux(marker, t.sons[i], kind, flags)
if result != nil: break
of tyObject, tyTuple:
if kind in {skProc, skConst} and
if kind in {skProc, skFunc, skConst} and
t.kind == tyObject and t.sons[0] != nil: return t
let flags = flags+{taField}
for i in countup(0, sonsLen(t) - 1):
@ -1188,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
# prevent cascading errors:
result = nil
of tyUnused, tyUnused0, tyUnused1, tyUnused2: internalError("typeAllowedAux")
of tyUnused, tyOptAsRef, tyUnused1, tyUnused2: internalError("typeAllowedAux")
proc typeAllowed*(t: PType, kind: TSymKind): PType =
# returns 'nil' on success and otherwise the part of the type that is
@ -1199,6 +1185,63 @@ proc typeAllowed*(t: PType, kind: TSymKind): PType =
proc align(address, alignment: BiggestInt): BiggestInt =
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
szNonConcreteType* = -3
szIllegalRecursion* = -2
@ -1353,13 +1396,21 @@ proc computeSizeAux(typ: PType, a: var BiggestInt): BiggestInt =
of tyStatic:
result = if typ.n != nil: computeSizeAux(typ.lastSon, a)
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:
#internalError("computeSizeAux()")
result = szUnknownSize
typ.size = result
typ.align = int16(a)
proc computeSize(typ: PType): BiggestInt =
proc computeSize*(typ: PType): BiggestInt =
var a: BiggestInt = 1
result = computeSizeAux(typ, a)
@ -1368,7 +1419,7 @@ proc getReturnType*(s: PSym): PType =
assert s.kind in skProcKinds
result = s.typ.sons[0]
proc getSize(typ: PType): BiggestInt =
proc getSize*(typ: PType): BiggestInt =
result = computeSize(typ)
if result < 0: internalError("getSize: " & $typ.kind)

View file

@ -19,7 +19,7 @@ import ast except getstr
import
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes,
parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
vmmarshal
vmmarshal, gorgeimpl
from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate
@ -66,7 +66,10 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
var info = c.debug[pc]
# we now use the same format as in system/except.nim
var s = toFilename(info)
var s = substr(toFilename(info), 0)
# this 'substr' prevents a strange corruption. XXX This needs to be
# investigated eventually but first attempts to fix it broke everything
# see the araq-wip-fixed-writebarrier branch.
var line = toLinenumber(info)
if line > 0:
add(s, '(')
@ -979,7 +982,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
let a = evalTemplate(macroCall, prc, genSymOwner)
var a = evalTemplate(macroCall, prc, genSymOwner)
if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef
ensureKind(rkNode)
regs[ra].node = a

View file

@ -7,50 +7,7 @@
# distribution, for details about the copyright.
#
import ast, types, msgs, os, osproc, streams, options, idents, securehash
proc readOutput(p: Process): (string, int) =
result[0] = ""
var output = p.outputStream
while not output.atEnd:
result[0].add(output.readLine)
result[0].add("\n")
if result[0].len > 0:
result[0].setLen(result[0].len - "\n".len)
result[1] = p.waitForExit
proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) =
let workingDir = parentDir(info.toFullPath)
if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache)
let filename = options.toGeneratedFile("gorge_" & $h, "txt")
var f: File
if open(f, filename):
result = (f.readAll, 0)
f.close
return
var readSuccessful = false
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
readSuccessful = true
writeFile(filename, result[0])
except IOError, OSError:
if not readSuccessful: result = ("", -1)
else:
try:
var p = startProcess(cmd, workingDir,
options={poEvalCommand, poStderrToStdout})
if input.len != 0:
p.inputStream.write(input)
p.inputStream.close()
result = p.readOutput
except IOError, OSError:
result = ("", -1)
import ast, types, msgs, os, streams, options, idents
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
try:
@ -250,6 +207,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result = mapTypeToBracket("ref", mRef, t, info)
of tyVar: result = mapTypeToBracket("var", mVar, t, info)
of tySequence: result = mapTypeToBracket("seq", mSeq, t, info)
of tyOpt: result = mapTypeToBracket("opt", mOpt, t, info)
of tyProc:
if inst:
result = newNodeX(nkProcTy)
@ -304,7 +262,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
of tyAnything: result = atomicType("anything", mNone)
of tyInferred: internalAssert false
of tyStatic, tyFromExpr, tyFieldAccessor:
of tyStatic, tyFromExpr:
if inst:
if t.n != nil: result = t.n.copyTree
else: result = atomicType("void", mVoid)
@ -313,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result.add atomicType("static", mNone)
if t.n != nil:
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 =
result = mapTypeToAstX(t, info, false, true)

View file

@ -1289,7 +1289,7 @@ proc checkCanEval(c: PCtx; n: PNode) =
if s.kind in {skVar, skTemp, skLet, skParam, skResult} and
not s.isOwnedBy(c.prc.sym) and s.owner != c.module and c.mode != emRepl:
cannotEval(n)
elif s.kind in {skProc, skConverter, skMethod,
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
cannotEval(n)
@ -1537,6 +1537,8 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
addSon(result, getNullValue(t.sons[i], info))
of tySet:
result = newNodeIT(nkCurly, info, t)
of tyOpt:
result = newNodeIT(nkNilLit, info, t)
else:
globalError(info, "cannot create null element for: " & $t.kind)
@ -1712,7 +1714,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
case s.kind
of skVar, skForVar, skTemp, skLet, skParam, skResult:
genRdVar(c, n, dest, flags)
of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator:
of skProc, skFunc, skConverter, skMacro, skTemplate, skMethod, skIterator:
# 'skTemplate' is only allowed for 'getAst' support:
if procIsCallback(c, s): discard
elif sfImportc in s.flags: c.importcSym(n.info, s)

View file

@ -30,7 +30,7 @@ type
wMacro, wMethod, wMixin, wMod, wNil,
wNot, wNotin, wObject, wOf, wOr, wOut, wProc, wPtr, wRaise, wRef, wReturn,
wShl, wShr, wStatic, wTemplate, wTry, wTuple, wType, wUsing, wVar,
wWhen, wWhile, wWith, wWithout, wXor, wYield,
wWhen, wWhile, wXor, wYield,
wColon, wColonColon, wEquals, wDot, wDotDot,
wStar, wMinus,
@ -116,7 +116,7 @@ const
"out", "proc", "ptr", "raise", "ref", "return",
"shl", "shr", "static",
"template", "try", "tuple", "type", "using", "var",
"when", "while", "with", "without", "xor",
"when", "while", "xor",
"yield",
":", "::", "=", ".", "..",

View file

@ -248,6 +248,8 @@ proc markWriteOrEscape(w: var W) =
for p in a.dest:
if p.kind == skParam and p.owner == w.owner:
incl(p.flags, sfWrittenTo)
if w.owner.kind == skFunc and p.typ.kind != tyVar:
localError(a.info, "write access to non-var parameter: " & p.name.s)
if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
var destIsParam = false