Merge branch 'devel' of https://github.com/nim-lang/Nim into fix_2753

This commit is contained in:
data-man
2018-05-19 16:19:29 +03:00
123 changed files with 6182 additions and 5928 deletions

View File

@@ -74,6 +74,7 @@
deprecated.
- The `terminal` module now exports additional procs for generating ANSI color
codes as strings.
- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
### Language additions

View File

@@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
of nkOfBranch, nkElse:
result = isPartOfAux(lastSon(n.sons[i]), b, marker)
if result == arYes: return
else: internalError("isPartOfAux(record case branch)")
else: discard "isPartOfAux(record case branch)"
of nkSym:
result = isPartOfAux(n.sym.typ, b, marker)
else: internalError(n.info, "isPartOfAux()")
else: discard
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo

View File

@@ -734,7 +734,7 @@ type
locOther # location is something other
TLocFlag* = enum
lfIndirect, # backend introduced a pointer
lfFullExternalName, # only used when 'gCmd == cmdPretty': Indicates
lfFullExternalName, # only used when 'conf.cmd == cmdPretty': Indicates
# that the symbol has been imported via 'importc: "fullname"' and
# no format string.
lfNoDeepCopy, # no need for a deep copy
@@ -1078,14 +1078,14 @@ template previouslyInferred*(t: PType): PType =
if t.sons.len > 1: t.lastSon else: nil
proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
info: TLineInfo): PSym =
info: TLineInfo; options: TOptions = {}): PSym =
# generates a symbol and initializes the hash field too
new(result)
result.name = name
result.kind = symKind
result.flags = {}
result.info = info
result.options = gOptions
result.options = options
result.owner = owner
result.offset = -1
result.id = getID()
@@ -1095,7 +1095,7 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym,
# writeStacktrace()
# MessageOut(name.s & " has id: " & toString(result.id))
var emptyNode* = newNode(nkEmpty)
var emptyNode* = newNode(nkEmpty) # XXX global variable here!
# There is a single empty node that is shared! Do not overwrite it!
proc isMetaType*(t: PType): bool =
@@ -1325,7 +1325,7 @@ proc copyType*(t: PType, owner: PSym, keepId: bool): PType =
proc exactReplica*(t: PType): PType = copyType(t, t.owner, true)
proc copySym*(s: PSym, keepId: bool = false): PSym =
result = newSym(s.kind, s.name, s.owner, s.info)
result = newSym(s.kind, s.name, s.owner, s.info, s.options)
#result.ast = nil # BUGFIX; was: s.ast which made problems
result.typ = s.typ
if keepId:
@@ -1344,8 +1344,9 @@ proc copySym*(s: PSym, keepId: bool = false): PSym =
if result.kind in {skVar, skLet, skField}:
result.guard = s.guard
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo): PSym =
result = newSym(s.kind, newIdent, s.owner, info)
proc createModuleAlias*(s: PSym, newIdent: PIdent, info: TLineInfo;
options: TOptions): PSym =
result = newSym(s.kind, newIdent, s.owner, info, options)
# keep ID!
result.ast = s.ast
result.id = s.id
@@ -1564,15 +1565,17 @@ proc getInt*(a: PNode): BiggestInt =
case a.kind
of nkCharLit..nkUInt64Lit: result = a.intVal
else:
internalError(a.info, "getInt")
result = 0
#internalError(a.info, "getInt")
doAssert false, "getInt"
#result = 0
proc getFloat*(a: PNode): BiggestFloat =
case a.kind
of nkFloatLiterals: result = a.floatVal
else:
internalError(a.info, "getFloat")
result = 0.0
doAssert false, "getFloat"
#internalError(a.info, "getFloat")
#result = 0.0
proc getStr*(a: PNode): string =
case a.kind
@@ -1581,16 +1584,18 @@ proc getStr*(a: PNode): string =
# let's hope this fixes more problems than it creates:
result = nil
else:
internalError(a.info, "getStr")
result = ""
doAssert false, "getStr"
#internalError(a.info, "getStr")
#result = ""
proc getStrOrChar*(a: PNode): string =
case a.kind
of nkStrLit..nkTripleStrLit: result = a.strVal
of nkCharLit..nkUInt64Lit: result = $chr(int(a.intVal))
else:
internalError(a.info, "getStrOrChar")
result = ""
doAssert false, "getStrOrChar"
#internalError(a.info, "getStrOrChar")
#result = ""
proc isGenericRoutine*(s: PSym): bool =
case s.kind
@@ -1689,9 +1694,9 @@ proc isException*(t: PType): bool =
base = base.lastSon
return false
proc isImportedException*(t: PType): bool =
proc isImportedException*(t: PType; conf: ConfigRef): bool =
assert(t != nil)
if optNoCppExceptions in gGlobalOptions:
if optNoCppExceptions in conf.globalOptions:
return false
let base = t.skipTypes({tyAlias, tyPtr, tyDistinct, tyGenericInst})

View File

@@ -180,7 +180,7 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
result = lookupInRecord(n.sons[i], field)
if result != nil: return
of nkRecCase:
if (n.sons[0].kind != nkSym): internalError(n.info, "lookupInRecord")
if (n.sons[0].kind != nkSym): return nil
result = lookupInRecord(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
@@ -188,10 +188,10 @@ proc lookupInRecord(n: PNode, field: PIdent): PSym =
of nkOfBranch, nkElse:
result = lookupInRecord(lastSon(n.sons[i]), field)
if result != nil: return
else: internalError(n.info, "lookupInRecord(record case branch)")
else: return nil
of nkSym:
if n.sym.name.id == field.id: result = n.sym
else: internalError(n.info, "lookupInRecord()")
else: return nil
proc getModule(s: PSym): PSym =
result = s
@@ -203,7 +203,7 @@ proc getSymFromList(list: PNode, ident: PIdent, start: int = 0): PSym =
if list.sons[i].kind == nkSym:
result = list.sons[i].sym
if result.name.id == ident.id: return
else: internalError(list.info, "getSymFromList")
else: return nil
result = nil
proc hashNode(p: RootRef): Hash =

View File

@@ -116,7 +116,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
else:
result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
else:
internalError("openArrayLoc: " & typeToString(a.t))
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else:
initLocExpr(p, n, a)
case skipTypes(a.t, abstractVar).kind
@@ -137,8 +137,8 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
of tyArray:
result = "$1, $2" % [rdLoc(a), rope(lengthOrd(lastSon(a.t)))]
else:
internalError("openArrayLoc: " & typeToString(a.t))
else: internalError("openArrayLoc: " & typeToString(a.t))
internalError(p.config, "openArrayLoc: " & typeToString(a.t))
else: internalError(p.config, "openArrayLoc: " & typeToString(a.t))
proc genArgStringToCString(p: BProc, n: PNode): Rope {.inline.} =
var a: TLoc
@@ -273,7 +273,7 @@ proc genOtherArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
result = genArgNoParam(p, ri.sons[i]) #, typ.n.sons[i].sym)
else:
if tfVarargs notin typ.flags:
localError(ri.info, "wrong argument count")
localError(p.config, ri.info, "wrong argument count")
result = nil
else:
result = genArgNoParam(p, ri.sons[i])
@@ -337,7 +337,7 @@ proc genThisArg(p: BProc; ri: PNode; i: int; typ: PType): Rope =
# for better or worse c2nim translates the 'this' argument to a 'var T'.
# However manual wrappers may also use 'ptr T'. In any case we support both
# for convenience.
internalAssert i < sonsLen(typ)
internalAssert p.config, i < sonsLen(typ)
assert(typ.n.sons[i].kind == nkSym)
# if the parameter is lying (tyVar) and thus we required an additional deref,
# skip the deref:
@@ -394,7 +394,7 @@ proc genPatternCall(p: BProc; ri: PNode; pat: string; typ: PType): Rope =
result.add genOtherArg(p, ri, k, typ)
result.add(~")")
else:
localError(ri.info, "call expression expected for C++ pattern")
localError(p.config, ri.info, "call expression expected for C++ pattern")
inc i
elif pat[i+1] == '.':
result.add genThisArg(p, ri, j, typ)
@@ -432,7 +432,7 @@ proc genInfixCall(p: BProc, le, ri: PNode, d: var TLoc) =
assert(sonsLen(typ) == sonsLen(typ.n))
# don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil
internalAssert p.config, pat != nil
if pat.contains({'#', '(', '@', '\''}):
var pl = genPatternCall(p, ri, pat, typ)
# simpler version of 'fixupCall' that works with the pl+params combination:
@@ -481,7 +481,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
# don't call '$' here for efficiency:
let pat = ri.sons[0].sym.loc.r.data
internalAssert pat != nil
internalAssert p.config, pat != nil
var start = 3
if ' ' in pat:
start = 1
@@ -501,7 +501,7 @@ proc genNamedParamCall(p: BProc, ri: PNode, d: var TLoc) =
for i in countup(start, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
internalError(ri.info, "varargs for objective C method?")
internalError(p.config, ri.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
add(pl, ~" ")

View File

@@ -13,7 +13,7 @@
proc int64Literal(i: BiggestInt): Rope =
if i > low(int64):
result = rfmt(nil, "IL64($1)", rope(i))
result = "IL64($1)" % [rope(i)]
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
@@ -26,12 +26,12 @@ proc intLiteral(i: BiggestInt): Rope =
# Nim has the same bug for the same reasons :-)
result = ~"(-2147483647 -1)"
elif i > low(int64):
result = rfmt(nil, "IL64($1)", rope(i))
result = "IL64($1)" % [rope(i)]
else:
result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil")
case n.kind
of nkCharLit..nkUInt64Lit:
case skipTypes(ty, abstractVarRange).kind
@@ -76,7 +76,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of nkFloat32Lit:
result = rope(n.floatVal.toStrMaxPrecision("f"))
else:
internalError(n.info, "genLiteral(" & $n.kind & ')')
internalError(p.config, n.info, "genLiteral(" & $n.kind & ')')
result = nil
proc genLiteral(p: BProc, n: PNode): Rope =
@@ -145,7 +145,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
of tyVar, tyLent: result = OnUnknown
of tyPtr: result = OnStack
of tyRef: result = OnHeap
else: internalError(n.info, "getStorageLoc")
else: doAssert(false, "getStorageLoc")
of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
result = getStorageLoc(n.sons[0])
else: result = OnUnknown
@@ -164,7 +164,7 @@ proc canMove(n: PNode): bool =
# result = false
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.storage == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC(p.config):
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
elif dest.storage == OnHeap:
# location is on heap
@@ -256,7 +256,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.storage == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC(p.config):
useStringh(p.module)
linefmt(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
@@ -290,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
genRefAssign(p, dest, src, flags)
else:
if dest.storage == OnStack or not usesNativeGC():
if dest.storage == OnStack or not usesNativeGC(p.config):
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
elif dest.storage == OnHeap:
# we use a temporary to care for the dreaded self assignment:
@@ -326,7 +326,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
elif needsComplexAssignment(ty):
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
discard getTypeDesc(p.module, ty)
internalAssert ty.n != nil
internalAssert p.config, ty.n != nil
genOptAsgnObject(p, dest, src, flags, ty.n, ty)
else:
genGenericAsgn(p, dest, src, flags)
@@ -363,7 +363,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
tyInt..tyUInt64, tyRange, tyVar, tyLent:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
else: internalError("genAssignment: " & $ty.kind)
else: internalError(p.config, "genAssignment: " & $ty.kind)
if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}:
#writeStackTrace()
@@ -409,7 +409,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
of tyPointer, tyChar, tyBool, tyEnum, tyCString,
tyInt..tyUInt64, tyRange, tyVar, tyLent:
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
else: internalError("genDeepCopy: " & $ty.kind)
else: internalError(p.config, "genDeepCopy: " & $ty.kind)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
if d.k != locNone:
@@ -450,14 +450,14 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if d.k != locNone: internalError(e.info, "binaryStmt")
if d.k != locNone: internalError(p.config, e.info, "binaryStmt")
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
if d.k != locNone: internalError(e.info, "unaryStmt")
if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
initLocExpr(p, e.sons[1], a)
lineCg(p, cpsStmts, frmt, [rdLoc(a)])
@@ -701,7 +701,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
of tyPtr:
d.storage = OnUnknown # BUGFIX!
else:
internalError(e.info, "genDeref " & $typ.kind)
internalError(p.config, e.info, "genDeref " & $typ.kind)
elif p.module.compileToCpp:
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
e.kind == nkHiddenDeref:
@@ -736,7 +736,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
initLocExpr(p, e.sons[0], a)
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
d.inheritLocation(a)
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
@@ -752,7 +752,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var r = rdLoc(a)
case e.sons[1].kind
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
else: internalError(p.config, e.info, "genTupleElem")
addf(r, ".Field$1", [rope(i)])
putIntoDest(p, d, e, r, a.storage)
@@ -769,7 +769,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
break
if not p.module.compileToCpp: add(r, ".Sup")
ty = ty.sons[0]
if result == nil: internalError(field.info, "genCheckedRecordField")
if result == nil: internalError(p.config, field.info, "genCheckedRecordField")
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
@@ -786,7 +786,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
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))
if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
addf(r, ".$1", [field.loc.r])
putIntoDest(p, d, e, r, a.storage)
@@ -832,9 +832,9 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
let field = lookupFieldAgain(p, ty, f, r)
if field.loc.r == nil: fillObjectFields(p.module, ty)
if field.loc.r == nil:
internalError(e.info, "genCheckedRecordField") # generate the checks:
internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
genFieldCheck(p, e, r, field)
add(r, rfmt(nil, ".$1", field.loc.r))
add(r, ropecg(p.module, ".$1", field.loc.r))
putIntoDest(p, d, e.sons[0], r, a.storage)
else:
genRecordField(p, e.sons[0], d)
@@ -859,10 +859,10 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
else:
let idx = getOrdValue(y)
if idx < firstOrd(ty) or idx > lastOrd(ty):
localError(x.info, errIndexOutOfBounds)
localError(p.config, x.info, "index out of bounds")
d.inheritLocation(a)
putIntoDest(p, d, n,
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
@@ -871,7 +871,7 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var ty = skipTypes(a.t, abstractVarRange)
inheritLocation(d, a)
putIntoDest(p, d, n,
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genIndexCheck(p: BProc; arr, idx: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
@@ -899,7 +899,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
inheritLocation(d, a)
putIntoDest(p, d, n,
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
var a, b: TLoc
@@ -919,9 +919,9 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
rdLoc(b), rdLoc(a), lenField(p))
if d.k == locNone: d.storage = OnHeap
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
a.r = rfmt(nil, "(*$1)", a.r)
a.r = ropecg(p.module, "(*$1)", a.r)
putIntoDest(p, d, n,
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
ropecg(p.module, "$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)
@@ -932,7 +932,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
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 & ')')
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# how to generate code?
@@ -977,7 +977,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe.
internalAssert n.kind == nkBracket
internalAssert p.config, n.kind == nkBracket
if platform.targetOS == osGenode:
# bypass libc and print directly to the Genode LOG session
var args: Rope = nil
@@ -1003,8 +1003,8 @@ proc genEcho(p: BProc, n: PNode) =
makeCString(repeat("%s", n.len) & tnl), args)
linefmt(p, cpsStmts, "fflush(stdout);$n")
proc gcUsage(n: PNode) =
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
proc gcUsage(conf: ConfigRef; n: PNode) =
if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nim code>
@@ -1033,20 +1033,20 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
inc(L)
add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 1].strVal))
else:
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
add(p.s(cpsStmts), appends)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {}) # no need for deep copying
gcUsage(e)
gcUsage(p.config, e)
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# <Nim code>
@@ -1071,19 +1071,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
inc(L)
add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
rdLoc(dest), rdLoc(a)))
else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
inc(L, len(e.sons[i + 2].strVal))
else:
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
add(appends, rfmt(p.module, "#appendString($1, $2);$n",
add(appends, ropecg(p.module, "#appendString($1, $2);$n",
rdLoc(dest), rdLoc(a)))
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
rdLoc(dest), lens, rope(L))
add(p.s(cpsStmts), appends)
gcUsage(e)
gcUsage(p.config, e)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
@@ -1106,9 +1106,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
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)
dest.r = ropecg(p.module, "$1->data[$2]", rdLoc(a), tmpL.r)
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
gcUsage(e)
gcUsage(p.config, e)
proc genReset(p: BProc, n: PNode) =
var a: TLoc
@@ -1131,7 +1131,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
let args = [getTypeDesc(p.module, typ),
genTypeInfo(p.module, typ, a.lode.info),
sizeExpr]
if a.storage == OnHeap and usesNativeGC():
if a.storage == OnHeap and usesNativeGC(p.config):
# use newObjRC1 as an optimization
if canFormAcycle(a.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
@@ -1154,7 +1154,7 @@ proc genNew(p: BProc, e: PNode) =
rawGenNew(p, a, se.rdLoc)
else:
rawGenNew(p, a, nil)
gcUsage(e)
gcUsage(p.config, e)
proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
let seqtype = skipTypes(dest.t, abstractVarRange)
@@ -1162,7 +1162,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
genTypeInfo(p.module, seqtype, dest.lode.info), length]
var call: TLoc
initLoc(call, locExpr, dest.lode, OnHeap)
if dest.storage == OnHeap and usesNativeGC():
if dest.storage == OnHeap and usesNativeGC(p.config):
if canFormAcycle(dest.t):
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
else:
@@ -1178,7 +1178,7 @@ proc genNewSeq(p: BProc, e: PNode) =
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
genNewSeqAux(p, a, b.rdLoc)
gcUsage(e)
gcUsage(p.config, e)
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
let seqtype = skipTypes(e.typ, abstractVarRange)
@@ -1188,7 +1188,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
"($1)#nimNewSeqOfCap($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
gcUsage(e)
gcUsage(p.config, e)
proc genConstExpr(p: BProc, n: PNode): Rope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
@@ -1230,7 +1230,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
rawGenNew(p, tmp, nil)
t = t.lastSon.skipTypes(abstractInst)
r = "(*$1)" % [r]
gcUsage(e)
gcUsage(p.config, e)
else:
constructLoc(p, tmp)
else:
@@ -1244,7 +1244,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
tmp2.r = r
let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r)
if field.loc.r == nil: fillObjectFields(p.module, ty)
if field.loc.r == nil: internalError(e.info, "genObjConstr")
if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr")
if it.len == 3 and optFieldCheck in p.options:
genFieldCheck(p, it.sons[2], r, field)
add(tmp2.r, ".")
@@ -1280,10 +1280,10 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
genNewSeqAux(p, dest[], 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(dest[]), intLiteral(i))
arr.r = ropecg(p.module, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
arr.storage = OnHeap # we know that sequences are on the heap
expr(p, n[i], arr)
gcUsage(n)
gcUsage(p.config, n)
if doesAlias:
if d.k == locNone:
d = tmp
@@ -1306,21 +1306,21 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
if L < 10:
for i in countup(0, L - 1):
initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), intLiteral(i))
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))
arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i))
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
else:
var i: TLoc
getTemp(p, getSysType(tyInt), i)
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope)
initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), rdLoc(i))
elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), rdLoc(i))
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), rdLoc(i))
arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
lineF(p, cpsStmts, "}$n", [])
@@ -1342,7 +1342,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
genAssignment(p, a, b, {}) # set the object type:
bt = skipTypes(refType.lastSon, abstractRange)
genObjectInit(p, cpsStmts, bt, a, false)
gcUsage(e)
gcUsage(p.config, e)
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
@@ -1356,10 +1356,10 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
inc p.module.labels
let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
when false:
# former version:
result = rfmt(p.module, "#isObj($1.m_type, $2)",
result = ropecg(p.module, "#isObj($1.m_type, $2)",
a, genTypeInfo(p.module, dest, info))
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
@@ -1372,7 +1372,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
if t.kind notin {tyVar, tyLent}: nilCheck = r
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
r = rfmt(nil, "(*$1)", r)
r = ropecg(p.module, "(*$1)", r)
t = skipTypes(t.lastSon, typedescInst)
discard getTypeDesc(p.module, t)
if not p.module.compileToCpp:
@@ -1380,12 +1380,12 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
add(r, ~".Sup")
t = skipTypes(t.sons[0], skipPtrs)
if isObjLackingTypeField(t):
globalError(x.info, errGenerated,
globalError(p.config, x.info,
"no 'of' operator available for pure objects")
if nilCheck != nil:
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
r = ropecg(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
else:
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r, x.info))
r = ropecg(p.module, "($1)", genOfHelper(p, dest, r, x.info))
putIntoDest(p, d, x, r, a.storage)
proc genOf(p: BProc, n: PNode, d: var TLoc) =
@@ -1425,7 +1425,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
of tyArray:
putIntoDest(p, b, e,
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
else: internalError(e.sons[0].info, "genRepr()")
else: internalError(p.config, e.sons[0].info, "genRepr()")
putIntoDest(p, d, e,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
@@ -1434,12 +1434,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
of tyEmpty, tyVoid:
localError(e.info, "'repr' doesn't support 'void' type")
localError(p.config, e.info, "'repr' doesn't support 'void' type")
else:
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t, e.info)]),
a.storage)
gcUsage(e)
gcUsage(p.config, e)
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
let t = e.sons[1].typ
@@ -1451,7 +1451,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
a.r = ropecg(p.module, frmt, [rdLoc(a)])
if d.k == locNone: getTemp(p, n.typ, d)
genAssignment(p, d, a, {})
gcUsage(n)
gcUsage(p.config, n)
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1]
@@ -1493,7 +1493,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ)))
else: putIntoDest(p, d, e, rope(lengthOrd(typ)))
else: internalError(e.info, "genArrayLen()")
else: internalError(p.config, e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
@@ -1511,11 +1511,11 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
lineCg(p, cpsStmts, setLenPattern, [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
gcUsage(e)
gcUsage(p.config, e)
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
gcUsage(e)
gcUsage(p.config, e)
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
# swap(a, b) -->
@@ -1541,7 +1541,7 @@ proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
proc fewCmps(s: PNode): bool =
# this function estimates whether it is better to emit code
# for constructing the set or generating a bunch of comparisons directly
if s.kind != nkCurly: internalError(s.info, "fewCmps")
if s.kind != nkCurly: return false
if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
result = false # it is better to emit the set generation code
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
@@ -1637,17 +1637,17 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)")
of mInSet:
genInOp(p, e, d)
else: internalError(e.info, "genSetOp()")
else: internalError(p.config, e.info, "genSetOp()")
else:
case op
of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n")
of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n")
of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')')
of mLtSet, mLeSet:
getTemp(p, getSysType(tyInt), i) # our counter
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, getSysType(tyBool), d)
if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d)
lineF(p, cpsStmts, lookupOpr[op],
[rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet:
@@ -1655,7 +1655,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
# we inline the simple for loop for better code generation:
getTemp(p, getSysType(tyInt), i) # our counter
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d)
@@ -1665,7 +1665,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
rope(lookupOpr[op])])
of mInSet: genInOp(p, e, d)
else: internalError(e.info, "genSetOp")
else: internalError(p.config, e.info, "genSetOp")
proc genOrd(p: BProc, e: PNode, d: var TLoc) =
unaryExprChar(p, e, d, "$1")
@@ -1753,7 +1753,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
putIntoDest(p, d, n,
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
a.storage)
gcUsage(n)
gcUsage(p.config, n)
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
var x: TLoc
@@ -1762,11 +1762,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e,
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
ropecg(p.module, "(!($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,
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")
@@ -1778,7 +1778,7 @@ 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, rfmt(nil, "(($4)($2) $1 ($4)($3))",
putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))",
rope(opr[m]), rdLoc(a), rdLoc(b),
getSimpleTypeDesc(p.module, e[1].typ)))
if optNaNCheck in p.options:
@@ -1887,12 +1887,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mEcho: genEcho(p, e[1].skipConv)
of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError, mSlurp..mQuoteAst:
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s))
of mSpawn:
let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
expr(p, n, d)
of mParallel:
let n = semparallel.liftParallel(p.module.module, e)
let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
expr(p, n, d)
of mDeepCopy:
var a, b: TLoc
@@ -1904,7 +1904,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
else:
when defined(debugMagics):
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
internalError(e.info, "genMagicExpr: " & $op)
internalError(p.config, e.info, "genMagicExpr: " & $op)
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
# example: { a..b, c, d, e, f..g }
@@ -1924,7 +1924,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
[rdLoc(d), getTypeDesc(p.module, e.typ)])
for it in e.sons:
if it.kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
initLocExpr(p, it.sons[0], a)
initLocExpr(p, it.sons[1], b)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
@@ -1940,7 +1940,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
for it in e.sons:
if it.kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
initLocExpr(p, it.sons[0], a)
initLocExpr(p, it.sons[1], b)
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
@@ -1984,7 +1984,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, n.sons[0], a)
initLocExpr(p, n.sons[1], b)
if n.sons[0].skipConv.kind == nkClosure:
internalError(n.info, "closure to closure created")
internalError(p.config, n.info, "closure to closure created")
# tasyncawait.nim breaks with this optimization:
when false:
if d.k != locNone:
@@ -2025,7 +2025,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
let theMacro = it[0].sym
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
makeCString theMacro.name.s,
theMacro.info.quotedFilename, it.info.line.int)
quotedFilename(p.config, theMacro.info), it.info.line.int)
else:
genStmts(p, it)
if n.len > 0: exprOrStmt
@@ -2146,11 +2146,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
#if sym.kind == skIterator:
# echo renderTree(sym.getBody, {renderIds})
if sfCompileTime in sym.flags:
localError(n.info, "request to generate code for .compileTime proc: " &
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
sym.name.s)
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.lode == nil:
internalError(n.info, "expr: proc not init " & sym.name.s)
internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skConst:
if isSimpleConst(sym.typ):
@@ -2168,10 +2168,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sym.loc.r == nil or sym.loc.t == nil:
#echo "FAILED FOR PRCO ", p.prc.name.s
#echo renderTree(p.prc.ast, {renderIds})
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
if emulatedThreadVars():
if emulatedThreadVars(p.config):
putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r)
else:
putLocIntoDest(p, d, sym.loc)
@@ -2181,16 +2181,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
if sym.loc.r == nil or sym.loc.t == nil:
#echo "FAILED FOR PRCO ", p.prc.name.s
#echo renderTree(p.prc.ast, {renderIds})
internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
putLocIntoDest(p, d, sym.loc)
of skParam:
if sym.loc.r == nil or sym.loc.t == nil:
# echo "FAILED FOR PRCO ", p.prc.name.s
# debug p.prc.typ.n
# echo renderTree(p.prc.ast, {renderIds})
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
putLocIntoDest(p, d, sym.loc)
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
of nkNilLit:
if not isEmptyType(n.typ):
putIntoDest(p, d, n, genLiteral(p, n))
@@ -2259,7 +2259,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
var sym = n.sons[namePos].sym
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.lode == nil:
internalError(n.info, "expr: proc not init " & sym.name.s)
internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of nkClosure: genClosure(p, n, d)
@@ -2267,7 +2267,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection: discard # consts generated lazily on use
of nkForStmt: internalError(n.info, "for statement not eliminated")
of nkForStmt: internalError(p.config, n.info, "for statement not eliminated")
of nkCaseStmt: genCase(p, n, d)
of nkReturnStmt: genReturnStmt(p, n)
of nkBreakStmt: genBreakStmt(p, n)
@@ -2295,7 +2295,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
initLocExpr(p, ex, a)
of nkAsmStmt: genAsmStmt(p, n)
of nkTryStmt:
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
genTryCpp(p, n, d)
else:
genTry(p, n, d)
@@ -2327,7 +2327,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
of nkState: genState(p, n)
of nkGotoState: genGotoState(p, n)
of nkBreakState: genBreakState(p, n)
else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode): Rope =
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
@@ -2363,7 +2363,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
if mapType(t) == ctArray: result = rope"{}"
else: result = rope"0"
else:
globalError(info, "cannot create null element for: " & $t.kind)
globalError(p.config, info, "cannot create null element for: " & $t.kind)
proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) =
case obj.kind
@@ -2389,7 +2389,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; cou
# not found, produce default value:
result.add getDefaultValue(p, field.typ, cons.info)
else:
localError(cons.info, "cannot create null element for: " & $obj)
localError(p.config, cons.info, "cannot create null element for: " & $obj)
proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) =
var base = t.sons[0]

View File

@@ -15,7 +15,7 @@
template detectVersion(field, corename) =
if m.g.field == 0:
let core = getCompilerProc(corename)
let core = getCompilerProc(m.g.graph, corename)
if core == nil or core.kind != skConst:
m.g.field = 1
else:
@@ -74,7 +74,7 @@ proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
of 0, 1: result = genStringLiteralDataOnlyV1(m, s)
of 2: result = genStringLiteralDataOnlyV2(m, s)
else:
localError(info, "cannot determine how to produce code for string literal")
localError(m.config, info, "cannot determine how to produce code for string literal")
proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope =
result = ropecg(m, "((#NimStringDesc*) &$1)",
@@ -88,4 +88,4 @@ proc genStringLiteral(m: BModule; n: PNode): Rope =
of 0, 1: result = genStringLiteralV1(m, n)
of 2: result = genStringLiteralV2(m, n)
else:
localError(n.info, "cannot determine how to produce code for string literal")
localError(m.config, n.info, "cannot determine how to produce code for string literal")

View File

@@ -45,28 +45,28 @@ const
]
NimMergeEndMark = "/*\tNIM_merge_END:*/"
proc genSectionStart*(fs: TCFileSection): Rope =
if compilationCachePresent:
proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(tnl)
add(result, "/*\t")
add(result, CFileSectionNames[fs])
add(result, ":*/")
add(result, tnl)
proc genSectionEnd*(fs: TCFileSection): Rope =
if compilationCachePresent:
proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & tnl)
proc genSectionStart*(ps: TCProcSection): Rope =
if compilationCachePresent:
proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(tnl)
add(result, "/*\t")
add(result, CProcSectionNames[ps])
add(result, ":*/")
add(result, tnl)
proc genSectionEnd*(ps: TCProcSection): Rope =
if compilationCachePresent:
proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
if compilationCachePresent(conf):
result = rope(NimMergeEndMark & tnl)
proc writeTypeCache(a: TypeCache, s: var string) =
@@ -96,7 +96,7 @@ proc writeIntSet(a: IntSet, s: var string) =
s.add('}')
proc genMergeInfo*(m: BModule): Rope =
if not compilationCachePresent: return nil
if not compilationCachePresent(m.config): return nil
var s = "/*\tNIM_merge_INFO:"
s.add(tnl)
s.add("typeCache:{")
@@ -161,7 +161,7 @@ proc readVerbatimSection(L: var TBaseLexer): Rope =
buf = L.buf
r.add(tnl)
of '\0':
internalError("ccgmerge: expected: " & NimMergeEndMark)
doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
break
else:
if atEndMark(buf, pos):
@@ -179,7 +179,7 @@ proc readKey(L: var TBaseLexer, result: var string) =
while buf[pos] in IdentChars:
result.add(buf[pos])
inc pos
if buf[pos] != ':': internalError("ccgmerge: ':' expected")
if buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected")
L.bufpos = pos + 1 # skip ':'
proc newFakeType(id: int): PType =
@@ -187,12 +187,12 @@ proc newFakeType(id: int): PType =
result.id = id
proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
var key = decodeStr(L.buf, L.bufpos)
if ^L.bufpos != ':': internalError("ccgmerge: ':' expected")
if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected")
inc L.bufpos
var value = decodeStr(L.buf, L.bufpos)
# XXX implement me
@@ -201,7 +201,7 @@ proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
inc L.bufpos
proc readIntSet(L: var TBaseLexer, result: var IntSet) =
if ^L.bufpos != '{': internalError("ccgmerge: '{' expected")
if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
inc L.bufpos
while ^L.bufpos != '}':
skipWhite(L)
@@ -225,7 +225,7 @@ proc processMergeInfo(L: var TBaseLexer, m: BModule) =
of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
of "flags":
m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
else: internalError("ccgmerge: unknown key: " & k)
else: doAssert(false, "ccgmerge: unknown key: " & k)
when not defined(nimhygiene):
{.pragma: inject.}
@@ -275,9 +275,9 @@ proc readMergeSections(cfilename: string, m: var TMergeSections) =
if sectionB >= 0 and sectionB <= high(TCProcSection).int:
m.p[TCProcSection(sectionB)] = verbatim
else:
internalError("ccgmerge: unknown section: " & k)
doAssert(false, "ccgmerge: unknown section: " & k)
else:
internalError("ccgmerge: '*/' expected")
doAssert(false, "ccgmerge: '*/' expected")
proc mergeRequired*(m: BModule): bool =
for i in cfsHeaders..cfsProcs:

View File

@@ -16,7 +16,7 @@ const
# above X strings a hash-switch for strings is generated
proc registerGcRoot(p: BProc, v: PSym) =
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
containsGarbageCollectedRef(v.loc.t):
# we register a specialized marked proc here; this has the advantage
# that it works out of the box for thread local storage then :-)
@@ -43,13 +43,13 @@ proc inExceptBlockLen(p: BProc): int =
proc genVarTuple(p: BProc, n: PNode) =
var tup, field: TLoc
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
var L = sonsLen(n)
# if we have a something that's been captured, use the lowering instead:
for i in countup(0, L-3):
if n[i].kind != nkSym:
genStmts(p, lowerTupleUnpacking(n, p.prc))
genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
return
genLineDir(p, n)
@@ -70,7 +70,7 @@ proc genVarTuple(p: BProc, n: PNode) =
if t.kind == tyTuple:
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
else:
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
putLocIntoDest(p, v.loc, field)
@@ -125,7 +125,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
proc endBlock(p: BProc) =
let topBlock = p.blocks.len - 1
var blockEnd = if p.blocks[topBlock].label != nil:
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label)
else:
~"}$n"
let frameLen = p.blocks[topBlock].frameLen
@@ -149,7 +149,7 @@ template preserveBreakIdx(body: untyped): untyped =
p.breakIdx = oldBreakIdx
proc genState(p: BProc, n: PNode) =
internalAssert n.len == 1
internalAssert p.config, n.len == 1
let n0 = n[0]
if n0.kind == nkIntLit:
let idx = n.sons[0].intVal
@@ -191,7 +191,7 @@ proc genBreakState(p: BProc, n: PNode) =
proc genGotoVar(p: BProc; value: PNode) =
if value.kind notin {nkCharLit..nkUInt64Lit}:
localError(value.info, "'goto' target must be a literal value")
localError(p.config, value.info, "'goto' target must be a literal value")
else:
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
@@ -325,7 +325,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
startBlock(p)
expr(p, it.sons[0], d)
endBlock(p)
else: internalError(n.info, "genIf()")
else: internalError(p.config, n.info, "genIf()")
if sonsLen(n) > 1: fixLabel(p, lend)
@@ -337,7 +337,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
for i in countup(1, howManyTrys):
let tryStmt = p.nestedTryStmts.pop
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop safe points generated by try
if not tryStmt.inExcept:
linefmt(p, cpsStmts, "#popSafePoint();$n")
@@ -356,7 +356,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
for i in countdown(howManyTrys-1, 0):
p.nestedTryStmts.add(stack[i])
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
# Pop exceptions that was handled by the
# except-blocks we are in
for i in countdown(howManyExcepts-1, 0):
@@ -383,7 +383,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
let it = caseStmt.sons[i]
for j in 0 .. it.len-2:
if it.sons[j].kind == nkRange:
localError(it.info, "range notation not available for computed goto")
localError(p.config, it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
@@ -398,19 +398,19 @@ proc genComputedGoto(p: BProc; n: PNode) =
let it = n.sons[i]
if it.kind == nkCaseStmt:
if lastSon(it).kind != nkOfBranch:
localError(it.info,
localError(p.config, it.info,
"case statement must be exhaustive for computed goto"); return
casePos = i
let aSize = lengthOrd(it.sons[0].typ)
if aSize > 10_000:
localError(it.info,
localError(p.config, it.info,
"case statement has too many cases for computed goto"); return
arraySize = aSize.int
if firstOrd(it.sons[0].typ) != 0:
localError(it.info,
localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return
if casePos < 0:
localError(n.info, "no case statement found for computed goto"); return
localError(p.config, n.info, "no case statement found for computed goto"); return
var id = p.labels+1
inc p.labels, arraySize+1
let tmp = "TMP$1_" % [id.rope]
@@ -444,7 +444,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
let it = caseStmt.sons[i]
for j in 0 .. it.len-2:
if it.sons[j].kind == nkRange:
localError(it.info, "range notation not available for computed goto")
localError(p.config, it.info, "range notation not available for computed goto")
return
let val = getOrdValue(it.sons[j])
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
@@ -548,7 +548,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
# an unnamed 'break' can only break a loop after 'transf' pass:
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
internalError(t.info, "no loop to break")
internalError(p.config, t.info, "no loop to break")
let label = assignLabel(p.blocks[idx])
blockLeaveActions(p,
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
@@ -571,7 +571,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
var e = rdLoc(a)
var typ = skipTypes(t[0].typ, abstractPtrs)
genLineDir(p, t)
if isImportedException(typ):
if isImportedException(typ, p.config):
lineF(p, cpsStmts, "throw $1;$n", [e])
else:
lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
@@ -579,7 +579,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
else:
genLineDir(p, t)
# reraise the last exception:
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
line(p, cpsStmts, ~"throw;$n")
else:
linefmt(p, cpsStmts, "#reraiseException();$n")
@@ -876,17 +876,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
p.module.includeHeader("<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName(p.module)
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
discard cgsym(p.module, "E_Base")
discard cgsym(p.module, "Exception")
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
if isDefined("nimStdSetjmp"):
if isDefined(p.config, "nimStdSetjmp"):
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
elif isDefined("nimSigSetjmp"):
elif isDefined(p.config, "nimSigSetjmp"):
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
elif isDefined("nimRawSetjmp"):
elif isDefined(p.config, "nimRawSetjmp"):
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
else:
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
@@ -1013,7 +1010,7 @@ proc genEmit(p: BProc, t: PNode) =
if p.prc == nil:
# top level emit pragma?
let section = determineSection(t[1])
genCLineDir(p.module.s[section], t.info)
genCLineDir(p.module.s[section], t.info, p.config)
add(p.module.s[section], s)
else:
genLineDir(p, t)
@@ -1139,4 +1136,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
proc genStmts(p: BProc, t: PNode) =
var a: TLoc
expr(p, t, a)
internalAssert a.k in {locNone, locTemp, locLocalVar}
internalAssert p.config, a.k in {locNone, locTemp, locLocalVar}

View File

@@ -12,11 +12,11 @@
# included from cgen.nim
proc emulatedThreadVars(): bool =
result = {optThreads, optTlsEmulation} <= gGlobalOptions
proc emulatedThreadVars(conf: ConfigRef): bool =
result = {optThreads, optTlsEmulation} <= conf.globalOptions
proc accessThreadLocalVar(p: BProc, s: PSym) =
if emulatedThreadVars() and not p.threadVarAccessed:
if emulatedThreadVars(p.config) and not p.threadVarAccessed:
p.threadVarAccessed = true
incl p.module.flags, usesThreadVars
addf(p.procSec(cpsLocals), "\tNimThreadVars* NimTV_;$n", [])
@@ -37,7 +37,7 @@ var
# made to be one.
proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
if emulatedThreadVars():
if emulatedThreadVars(m.config):
# we gather all thread locals var into a struct; we need to allocate
# storage for that somehow, can't use the thread local storage
# allocator for it :-(
@@ -46,7 +46,7 @@ proc declareThreadVar(m: BModule, s: PSym, isExtern: bool) =
addf(nimtv, "$1 $2;$n", [getTypeDesc(m, s.loc.t), s.loc.r])
else:
if isExtern: add(m.s[cfsVars], "extern ")
if optThreads in gGlobalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
if optThreads in m.config.globalOptions: add(m.s[cfsVars], "NIM_THREADVAR ")
add(m.s[cfsVars], getTypeDesc(m, s.loc.t))
addf(m.s[cfsVars], " $1;$n", [s.loc.r])
@@ -57,7 +57,7 @@ proc generateThreadLocalStorage(m: BModule) =
proc generateThreadVarsSize(m: BModule) =
if nimtv != nil:
let externc = if gCmd == cmdCompileToCpp or
let externc = if m.config.cmd == cmdCompileToCpp or
sfCompileToCpp in m.module.flags: "extern \"C\" "
else: ""
addf(m.s[cfsProcs],

View File

@@ -29,12 +29,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
for i in countup(0, sonsLen(n) - 1):
genTraverseProc(c, accessor, n.sons[i], typ)
of nkRecCase:
if (n.sons[0].kind != nkSym): internalError(n.info, "genTraverseProc")
if (n.sons[0].kind != nkSym): internalError(c.p.config, n.info, "genTraverseProc")
var p = c.p
let disc = n.sons[0].sym
if disc.loc.r == nil: fillObjectFields(c.p.module, typ)
if disc.loc.t == nil:
internalError(n.info, "genTraverseProc()")
internalError(c.p.config, n.info, "genTraverseProc()")
lineF(p, cpsStmts, "switch ($1.$2) {$n", [accessor, disc.loc.r])
for i in countup(1, sonsLen(n) - 1):
let branch = n.sons[i]
@@ -51,9 +51,9 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, n: PNode;
if field.typ.kind == tyVoid: return
if field.loc.r == nil: fillObjectFields(c.p.module, typ)
if field.loc.t == nil:
internalError(n.info, "genTraverseProc()")
internalError(c.p.config, n.info, "genTraverseProc()")
genTraverseProc(c, "$1.$2" % [accessor, field.loc.r], field.loc.t)
else: internalError(n.info, "genTraverseProc()")
else: internalError(c.p.config, n.info, "genTraverseProc()")
proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} =
if not m.compileToCpp:
@@ -72,12 +72,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
of tyArray:
let arraySize = lengthOrd(typ.sons[0])
var i: TLoc
getTemp(p, getSysType(tyInt), i)
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts)
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n",
i.r, arraySize.rope)
let oldLen = p.s(cpsStmts).len
genTraverseProc(c, rfmt(nil, "$1[$2]", accessor, i.r), typ.sons[1])
genTraverseProc(c, ropecg(c.p.module, "$1[$2]", accessor, i.r), typ.sons[1])
if p.s(cpsStmts).len == oldLen:
# do not emit dummy long loops for faster debug builds:
p.s(cpsStmts) = oldCode
@@ -92,12 +92,12 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) =
of tyTuple:
let typ = getUniqueType(typ)
for i in countup(0, sonsLen(typ) - 1):
genTraverseProc(c, rfmt(nil, "$1.Field$2", accessor, i.rope), typ.sons[i])
genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i])
of tyRef, tyString, tySequence:
lineCg(p, cpsStmts, c.visitorFrmt, accessor)
of tyProc:
if typ.callConv == ccClosure:
lineCg(p, cpsStmts, c.visitorFrmt, rfmt(nil, "$1.ClE_0", accessor))
lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor))
else:
discard
@@ -105,7 +105,7 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) =
var p = c.p
assert typ.kind == tySequence
var i: TLoc
getTemp(p, getSysType(tyInt), i)
getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i)
let oldCode = p.s(cpsStmts)
lineF(p, cpsStmts, "for ($1 = 0; $1 < $2->$3; $1++) {$n",
[i.r, accessor, rope(if c.p.module.compileToCpp: "len" else: "Sup.len")])
@@ -157,7 +157,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym; info: TLineInfo): Rope =
var sLoc = s.loc.r
result = getTempName(m)
if sfThread in s.flags and emulatedThreadVars():
if sfThread in s.flags and emulatedThreadVars(m.config):
accessThreadLocalVar(p, s)
sLoc = "NimTV_->" & sLoc

View File

@@ -122,7 +122,7 @@ proc getTypeName(m: BModule; typ: PType; sig: SigHash): Rope =
# check consistency:
assert($typ.loc.r == $(typ.typeName & $sig))
result = typ.loc.r
if result == nil: internalError("getTypeName: " & $typ.kind)
if result == nil: internalError(m.config, "getTypeName: " & $typ.kind)
proc mapSetType(typ: PType): TCTypeKind =
case int(getSize(typ))
@@ -142,7 +142,7 @@ proc mapType(typ: PType): TCTypeKind =
of tyOpenArray, tyArray, tyVarargs: result = ctArray
of tyObject, tyTuple: result = ctStruct
of tyUserTypeClasses:
internalAssert typ.isResolvedUserTypeClass
doAssert typ.isResolvedUserTypeClass
return mapType(typ.lastSon)
of tyGenericBody, tyGenericInst, tyGenericParam, tyDistinct, tyOrdinal,
tyTypeDesc, tyAlias, tySink, tyInferred:
@@ -156,7 +156,7 @@ proc mapType(typ: PType): TCTypeKind =
of 2: result = ctUInt16
of 4: result = ctInt32
of 8: result = ctInt64
else: internalError("mapType")
else: result = ctInt32
of tyRange: result = mapType(typ.sons[0])
of tyPtr, tyVar, tyLent, tyRef, tyOptAsRef:
var base = skipTypes(typ.lastSon, typedescInst)
@@ -183,8 +183,8 @@ proc mapType(typ: PType): TCTypeKind =
result = TCTypeKind(ord(typ.kind) - ord(tyInt) + ord(ctInt))
of tyStatic:
if typ.n != nil: result = mapType(lastSon typ)
else: internalError("mapType")
else: internalError("mapType")
else: doAssert(false, "mapType")
else: doAssert(false, "mapType")
proc mapReturnType(typ: PType): TCTypeKind =
#if skipTypes(typ, typedescInst).kind == tyArray: result = ctPtr
@@ -239,7 +239,7 @@ proc cacheGetType(tab: TypeCache; sig: SigHash): Rope =
result = tab.getOrDefault(sig)
proc addAbiCheck(m: BModule, t: PType, name: Rope) =
if isDefined("checkabi"):
if isDefined(m.config, "checkabi"):
addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
proc ccgIntroducedPtr(s: PSym): bool =
@@ -303,7 +303,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
of tyDistinct, tyRange, tyOrdinal: result = getSimpleTypeDesc(m, typ.sons[0])
of tyStatic:
if typ.n != nil: result = getSimpleTypeDesc(m, lastSon typ)
else: internalError("tyStatic for getSimpleTypeDesc")
else: internalError(m.config, "tyStatic for getSimpleTypeDesc")
of tyGenericInst, tyAlias, tySink:
result = getSimpleTypeDesc(m, lastSon typ)
else: result = nil
@@ -347,7 +347,7 @@ proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope =
else:
pushType(m, concrete)
doAssert m.forwTypeCache[sig] == result
else: internalError("getTypeForward(" & $typ.kind & ')')
else: internalError(m.config, "getTypeForward(" & $typ.kind & ')')
proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope =
## like getTypeDescAux but creates only a *weak* dependency. In other words
@@ -389,7 +389,7 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope,
else:
rettype = getTypeDescAux(m, t.sons[0], check)
for i in countup(1, sonsLen(t.n) - 1):
if t.n.sons[i].kind != nkSym: internalError(t.n.info, "genProcParams")
if t.n.sons[i].kind != nkSym: internalError(m.config, t.n.info, "genProcParams")
var param = t.n.sons[i].sym
if isCompileTimeOnly(param.typ): continue
if params != nil: add(params, ~", ")
@@ -442,7 +442,7 @@ proc mangleRecFieldName(m: BModule; field: PSym, rectype: PType): Rope =
result = field.loc.r
else:
result = rope(mangleField(m, field.name))
if result == nil: internalError(field.info, "mangleRecFieldName")
if result == nil: internalError(m.config, field.info, "mangleRecFieldName")
proc genRecordFieldsAux(m: BModule, n: PNode,
accessExpr: Rope, rectype: PType,
@@ -453,7 +453,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
for i in countup(0, sonsLen(n) - 1):
add(result, genRecordFieldsAux(m, n.sons[i], accessExpr, rectype, check))
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "genRecordFieldsAux")
if n.sons[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
add(result, genRecordFieldsAux(m, n.sons[0], accessExpr, rectype, check))
let uname = rope(mangle(n.sons[0].sym.name.s) & 'U')
let ae = if accessExpr != nil: "$1.$2" % [accessExpr, uname]
@@ -481,7 +481,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
addf(unionBody, "#pragma pack(pop)$n", [])
else:
add(unionBody, genRecordFieldsAux(m, k, ae, rectype, check))
else: internalError("genRecordFieldsAux(record case branch)")
else: internalError(m.config, "genRecordFieldsAux(record case branch)")
if unionBody != nil:
addf(result, "union{$n$1} $2;$n", [unionBody, uname])
of nkSym:
@@ -509,7 +509,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
# don't use fieldType here because we need the
# tyGenericInst for C++ template support
addf(result, "$1 $2;$n", [getTypeDescAux(m, field.loc.t, check), sname])
else: internalError(n.info, "genRecordFieldsAux()")
else: internalError(m.config, n.info, "genRecordFieldsAux()")
proc getRecordFields(m: BModule, typ: PType, check: var IntSet): Rope =
result = genRecordFieldsAux(m, typ.n, nil, typ, check)
@@ -556,7 +556,7 @@ proc getRecordDesc(m: BModule, typ: PType, name: Rope,
# proper request to generate popCurrentExceptionEx not possible for 2 reasons:
# generated function will be below declared Exception type and circular dependency
# between Exception and popCurrentExceptionEx function
result = genProcHeader(m, magicsys.getCompilerProc("popCurrentExceptionEx")) & ";" & rnl & result
result = genProcHeader(m, magicsys.getCompilerProc(m.g.graph, "popCurrentExceptionEx")) & ";" & rnl & result
hasField = true
else:
appcg(m, result, " {$n $1 Sup;$n",
@@ -606,7 +606,7 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType =
# Make sure the index refers to one of the generic params of the type.
# XXX: we should catch this earlier and report it as a semantic error.
if idx >= typ.len:
internalError "invalid apostrophe type parameter index"
doAssert false, "invalid apostrophe type parameter index"
result = typ.sons[idx]
for i in 1..stars:
@@ -619,7 +619,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
var t = origTyp.skipTypes(irrelevantForBackend)
if containsOrIncl(check, t.id):
if not (isImportedCppType(origTyp) or isImportedCppType(t)):
internalError("cannot generate C type for: " & typeToString(origTyp))
internalError(m.config, "cannot generate C type for: " & typeToString(origTyp))
# XXX: this BUG is hard to fix -> we need to introduce helper structs,
# but determining when this needs to be done is hard. We should split
# C type generation into an analysis and a code generation phase somehow.
@@ -697,7 +697,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
of 2: addf(m.s[cfsTypes], "typedef NU16 $1;$n", [result])
of 4: addf(m.s[cfsTypes], "typedef NI32 $1;$n", [result])
of 8: addf(m.s[cfsTypes], "typedef NI64 $1;$n", [result])
else: internalError(t.sym.info, "getTypeDescAux: enum")
else: internalError(m.config, t.sym.info, "getTypeDescAux: enum")
when false:
let owner = hashOwner(t.sym)
if not gDebugInfo.hasEnum(t.sym.name.s, t.sym.info.line, owner):
@@ -808,7 +808,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
if typeInSlot == nil or typeInSlot.kind == tyVoid:
result.add(~"void")
elif typeInSlot.kind == tyStatic:
internalAssert typeInSlot.n != nil
internalAssert m.config, typeInSlot.n != nil
result.add typeInSlot.n.renderTree
else:
result.add getTypeDescAux(m, typeInSlot, check)
@@ -875,7 +875,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
tyUserTypeClass, tyUserTypeClassInst, tyInferred:
result = getTypeDescAux(m, lastSon(t), check)
else:
internalError("getTypeDescAux(" & $t.kind & ')')
internalError(m.config, "getTypeDescAux(" & $t.kind & ')')
result = nil
# fixes bug #145:
excl(check, t.id)
@@ -915,7 +915,7 @@ template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
proc genProcHeader(m: BModule, prc: PSym): Rope =
var
rettype, params: Rope
genCLineDir(result, prc.info)
genCLineDir(result, prc.info, m.config)
# using static is needed for inline procs
if lfExportLib in prc.loc.flags:
if isHeaderFile in m.flags:
@@ -968,7 +968,7 @@ proc genTypeInfoAuxBase(m: BModule; typ, origType: PType;
if flags != 0:
addf(m.s[cfsTypeInit3], "$1.flags = $2;$n", [name, rope(flags)])
discard cgsym(m, "TNimType")
if isDefined("nimTypeNames"):
if isDefined(m.config, "nimTypeNames"):
var typename = typeToString(if origType.typeInst != nil: origType.typeInst
else: origType, preferName)
if typename == "ref object" and origType.skipTypes(skipPtrs).sym != nil:
@@ -1000,7 +1000,7 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
while lookupInRecord(objtype.n, d.name) == nil:
objtype = objtype.sons[0]
if objtype.sym == nil:
internalError(d.info, "anonymous obj with discriminator")
internalError(m.config, d.info, "anonymous obj with discriminator")
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
@@ -1034,7 +1034,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
assert L > 0
if field.loc.r == nil: fillObjectFields(m, typ)
if field.loc.t == nil:
internalError(n.info, "genObjectFields")
internalError(m.config, n.info, "genObjectFields")
addf(m.s[cfsTypeInit3], "$1.kind = 3;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n" & "$1.sons = &$6[0];$n" &
@@ -1050,7 +1050,7 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
case b.kind
of nkOfBranch:
if sonsLen(b) < 2:
internalError(b.info, "genObjectFields; nkOfBranch broken")
internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
for j in countup(0, sonsLen(b) - 2):
if b.sons[j].kind == nkRange:
var x = int(getOrdValue(b.sons[j].sons[0]))
@@ -1064,23 +1064,23 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
of nkElse:
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n",
[tmp, rope(L), tmp2])
else: internalError(n.info, "genObjectFields(nkRecCase)")
else: internalError(m.config, n.info, "genObjectFields(nkRecCase)")
of nkSym:
var field = n.sym
if field.bitsize == 0:
if field.loc.r == nil: fillObjectFields(m, typ)
if field.loc.t == nil:
internalError(n.info, "genObjectFields")
internalError(m.config, n.info, "genObjectFields")
addf(m.s[cfsTypeInit3], "$1.kind = 1;$n" &
"$1.offset = offsetof($2, $3);$n" & "$1.typ = $4;$n" &
"$1.name = $5;$n", [expr, getTypeDesc(m, origType),
field.loc.r, genTypeInfo(m, field.typ, info), makeCString(field.name.s)])
else: internalError(n.info, "genObjectFields")
else: internalError(m.config, n.info, "genObjectFields")
proc genObjectInfo(m: BModule, typ, origType: PType, name: Rope; info: TLineInfo) =
if typ.kind == tyObject:
if incompleteType(typ):
localError(info, "request for RTTI generation for incomplete object: " &
localError(m.config, info, "request for RTTI generation for incomplete object: " &
typeToString(typ))
genTypeInfoAux(m, typ, origType, name, info)
else:
@@ -1171,12 +1171,12 @@ proc genSetInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
proc genArrayInfo(m: BModule, typ: PType, name: Rope; info: TLineInfo) =
genTypeInfoAuxBase(m, typ, typ, name, genTypeInfo(m, typ.sons[1], info), info)
proc fakeClosureType(owner: PSym): PType =
proc fakeClosureType(m: BModule; owner: PSym): PType =
# we generate the same RTTI as for a tuple[pointer, ref tuple[]]
result = newType(tyTuple, owner)
result.rawAddSon(newType(tyPointer, owner))
var r = newType(tyRef, owner)
let obj = createObj(owner, owner.info, final=false)
let obj = createObj(m.g.graph, owner, owner.info, final=false)
r.rawAddSon(obj)
result.rawAddSon(r)
@@ -1227,19 +1227,19 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
of tyStatic:
if t.n != nil: result = genTypeInfo(m, lastSon t, info)
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
of tyUserTypeClasses:
internalAssert t.isResolvedUserTypeClass
internalAssert m.config, t.isResolvedUserTypeClass
return genTypeInfo(m, t.lastSon, info)
of tyProc:
if t.callConv != ccClosure:
genTypeInfoAuxBase(m, t, t, result, rope"0", info)
else:
let x = fakeClosureType(t.owner)
let x = fakeClosureType(m, t.owner)
genTupleInfo(m, x, x, result, info)
of tySequence, tyRef, tyOptAsRef:
genTypeInfoAux(m, t, t, result, info)
if gSelectedGC >= gcMarkAndSweep:
if m.config.selectedGC >= gcMarkAndSweep:
let markerProc = genTraverseProc(m, origType, sig)
addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc])
of tyPtr, tyRange: genTypeInfoAux(m, t, t, result, info)
@@ -1253,7 +1253,7 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope =
# BUGFIX: use consistently RTTI without proper field names; otherwise
# results are not deterministic!
genTupleInfo(m, t, origType, result, info)
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError(m.config, "genTypeInfo(" & $t.kind & ')')
if t.deepCopy != nil:
genDeepCopyProc(m, t.deepCopy, result)
elif origType.deepCopy != nil:

View File

@@ -53,7 +53,7 @@ proc hashString*(s: string): BiggestInt =
result = a
var
gTypeTable: array[TTypeKind, TIdTable]
gTypeTable: array[TTypeKind, TIdTable] # XXX globals here
gCanonicalTypes: array[TTypeKind, PType]
proc initTypeTables() =

View File

@@ -19,6 +19,7 @@ import
import strutils except `%` # collides with ropes.`%`
from modulegraphs import ModuleGraph
from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated
import dynlib
when not declared(dynlib.libCandidates):
@@ -92,6 +93,7 @@ proc useHeader(m: BModule, sym: PSym) =
proc cgsym(m: BModule, name: string): Rope
proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
assert m != nil
var i = 0
var length = len(frmt)
result = nil
@@ -115,15 +117,15 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
if i >= length or not (frmt[i] in {'0'..'9'}): break
num = j
if j > high(args) + 1:
internalError("ropes: invalid format string $" & $j)
internalError(m.config, "ropes: invalid format string $" & $j)
add(result, args[j-1])
of 'n':
if optLineDir notin gOptions: add(result, rnl)
if optLineDir notin m.config.options: add(result, rnl)
inc(i)
of 'N':
add(result, rnl)
inc(i)
else: internalError("ropes: invalid format string $" & frmt[i])
else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
inc(i)
var j = i
@@ -145,15 +147,10 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
if i - 1 >= start:
add(result, substr(frmt, start, i - 1))
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
ropecg(m, fmt, args)
var indent = "\t".rope
proc indentLine(p: BProc, r: Rope): Rope =
result = r
for i in countup(0, p.blocks.len-1):
prepend(result, indent)
prepend(result, "\t".rope)
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
args: varargs[Rope]) =
@@ -189,14 +186,14 @@ proc safeLineNm(info: TLineInfo): int =
result = toLinenumber(info)
if result < 0: result = 0 # negative numbers are not allowed in #line
proc genCLineDir(r: var Rope, filename: string, line: int) =
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
assert line >= 0
if optLineDir in gOptions:
if optLineDir in conf.options:
addf(r, "$N#line $2 $1$N",
[rope(makeSingleLineCString(filename)), rope(line)])
proc genCLineDir(r: var Rope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm)
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
genCLineDir(r, info.toFullPath, info.safeLineNm, conf)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
@@ -213,9 +210,9 @@ proc genLineDir(p: BProc, t: PNode) =
tt = tt.sons[1]
let line = tt.info.safeLineNm
if optEmbedOrigSrc in gGlobalOptions:
add(p.s(cpsStmts), ~"//" & tt.info.sourceLine & rnl)
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line)
if optEmbedOrigSrc in p.config.globalOptions:
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl)
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags):
if freshLineInfo(p, tt.info):
@@ -226,17 +223,17 @@ proc genLineDir(p: BProc, t: PNode) =
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
if freshLineInfo(p, tt.info):
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
line.rope, tt.info.quotedFilename)
line.rope, quotedFilename(p.config, tt.info))
proc postStmtActions(p: BProc) {.inline.} =
add(p.s(cpsStmts), p.module.injectStmt)
proc accessThreadLocalVar(p: BProc, s: PSym)
proc emulatedThreadVars(): bool {.inline.}
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
proc genProc(m: BModule, prc: PSym)
template compileToCpp(m: BModule): untyped =
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels)
@@ -265,7 +262,7 @@ proc rdCharLoc(a: TLoc): Rope =
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
takeAddr: bool) =
if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"):
if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
# init vtable in Exception object for polymorphic exceptions
includeHeader(p.module, "<new>")
linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
@@ -373,7 +370,7 @@ proc getIntTemp(p: BProc, result: var TLoc) =
linefmt(p, cpsLocals, "NI $1;$n", result.r)
result.k = locTemp
result.storage = OnStack
result.lode = lodeTyp getSysType(tyInt)
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo(), tyInt)
result.flags = {}
proc initGCFrame(p: BProc): Rope =
@@ -417,7 +414,7 @@ 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 nl = if optLineDir in p.config.options: "" else: tnl
let decl = localVarDecl(p, n) & ";" & nl
line(p, cpsLocals, decl)
localDebugInfo(p, n.sym)
@@ -511,24 +508,24 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
discard cgsym(p.module, "nimFrame")
if p.maxFrameLen > 0:
discard cgsym(p.module, "VarSlot")
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
result = ropecg(p.module, "\tnimfrs_($1, $2, $3, $4);$n",
procname, filename, p.maxFrameLen.rope,
p.blocks[0].frameLen.rope)
else:
result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
result = ropecg(p.module, "\tnimfr_($1, $2);$n", procname, filename)
proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
discard cgsym(p.module, "nimFrame")
addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " &
result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
" $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
frame, procname, filename, rope(line))
proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope =
result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
proc deinitFrame(p: BProc): Rope =
result = rfmt(p.module, "\t#popFrame();$n")
result = ropecg(p.module, "\t#popFrame();$n")
include ccgexprs
@@ -551,7 +548,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
var s: TStringSeq = @[]
libCandidates(lib.path.strVal, s)
rawMessage(hintDependency, lib.path.strVal)
rawMessage(m.config, hintDependency, lib.path.strVal)
var loadlib: Rope = nil
for i in countup(0, high(s)):
inc(m.labels)
@@ -575,7 +572,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
[tmp, rdLoc(dest)])
if lib.name == nil: internalError("loadDynamicLib")
if lib.name == nil: internalError(m.config, "loadDynamicLib")
proc mangleDynLibProc(sym: PSym): Rope =
if sfCompilerProc in sym.flags:
@@ -606,14 +603,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
var last = lastSon(n)
if last.kind == nkHiddenStdConv: last = last.sons[1]
internalAssert(last.kind == nkStrLit)
internalAssert(m.config, last.kind == nkStrLit)
let idx = last.strVal
if idx.len == 0:
add(m.initProc.s(cpsStmts), load)
elif idx.len == 1 and idx[0] in {'0'..'9'}:
add(m.extensionLoaders[idx[0]], load)
else:
internalError(sym.info, "wrong index: " & idx)
internalError(m.config, sym.info, "wrong index: " & idx)
else:
appcg(m, m.s[cfsDynLibInit],
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
@@ -639,18 +636,18 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
sym.typ.sym = nil # generate a new name
proc cgsym(m: BModule, name: string): Rope =
let sym = magicsys.getCompilerProc(name)
let sym = magicsys.getCompilerProc(m.g.graph, name)
if sym != nil:
case sym.kind
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: internalError(m.config, "cgsym: " & name & ": " & $sym.kind)
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
# we're picky here for the system module too:
rawMessage(errSystemNeeds, name)
rawMessage(m.config, errGenerated, "system module needs: " & name)
result = sym.loc.r
proc generateHeaders(m: BModule) =
@@ -687,7 +684,7 @@ proc closureSetup(p: BProc, prc: PSym) =
# prc.ast[paramsPos].last contains the type we're after:
var ls = lastSon(prc.ast[paramsPos])
if ls.kind != nkSym:
internalError(prc.info, "closure generation failed")
internalError(p.config, prc.info, "closure generation failed")
var env = ls.sym
#echo "created environment: ", env.id, " for ", prc.name.s
assignLocalVar(p, ls)
@@ -727,7 +724,7 @@ proc genProcAux(m: BModule, prc: PSym) =
assert(prc.ast != nil)
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
if resultPos >= prc.ast.len:
internalError(prc.info, "proc has no result symbol")
internalError(m.config, prc.info, "proc has no result symbol")
let resNode = prc.ast.sons[resultPos]
let res = resNode.sym # get result symbol
if not isInvalidReturnType(prc.typ.sons[0]):
@@ -742,7 +739,7 @@ proc genProcAux(m: BModule, prc: PSym) =
assignLocalVar(p, resNode)
assert(res.loc.r != nil)
initLocalVar(p, res, immediateAsgn=false)
returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
else:
fillResult(resNode)
assignParam(p, res)
@@ -764,15 +761,15 @@ proc genProcAux(m: BModule, prc: PSym) =
if sfPure in prc.flags:
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
header = "__declspec(naked) " & header
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
else:
generatedProc = rfmt(nil, "$N$1 {$N", header)
generatedProc = ropecg(p.module, "$N$1 {$N", header)
add(generatedProc, initGCFrame(p))
if optStackTrace in prc.options:
add(generatedProc, p.s(cpsLocals))
var procname = makeCString(prc.name.s)
add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info)))
else:
add(generatedProc, p.s(cpsLocals))
if optProfiler in prc.options:
@@ -791,10 +788,10 @@ proc genProcAux(m: BModule, prc: PSym) =
proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
result = (sfCompileToCpp in m.module.flags and
sfCompileToCpp notin sym.getModule().flags and
gCmd != cmdCompileToCpp) or (
m.config.cmd != cmdCompileToCpp) or (
sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
sym.magic == mNone and
gCmd == cmdCompileToCpp)
m.config.cmd == cmdCompileToCpp)
proc genProcPrototype(m: BModule, sym: PSym) =
useHeader(m, sym)
@@ -802,7 +799,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
if lfDynamicLib in sym.loc.flags:
if getModule(sym).id != m.module.id and
not containsOrIncl(m.declaredThings, sym.id):
add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
add(m.s[cfsVars], ropecg(m, "extern $1 $2;$n",
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
elif not containsOrIncl(m.declaredProtos, sym.id):
var header = genProcHeader(m, sym)
@@ -814,7 +811,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
header.add(" __attribute__((naked))")
if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
header.add(" __attribute__((noreturn))")
add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header))
proc genProcNoForward(m: BModule, prc: PSym) =
if lfImportCompilerProc in prc.loc.flags:
@@ -920,14 +917,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc addIntTypes(result: var Rope) {.inline.} =
proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
"#define NIM_INTBITS $1" & tnl, [
platform.CPU[targetCPU].intSize.rope])
if useNimNamespace : result.add("#define USE_NIM_NAMESPACE" & tnl)
if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl)
proc getCopyright(cfile: Cfile): Rope =
if optCompileOnly in gGlobalOptions:
proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
if optCompileOnly in conf.globalOptions:
result = ("/* Generated by Nim Compiler v$1 */$N" &
"/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
"/* The generated code is subject to the original license. */$N") %
@@ -942,11 +939,11 @@ proc getCopyright(cfile: Cfile): Rope =
rope(platform.OS[targetOS].name),
rope(platform.CPU[targetCPU].name),
rope(extccomp.CC[extccomp.cCompiler].name),
rope(getCompileCFileCmd(cfile))]
rope(getCompileCFileCmd(conf, cfile))]
proc getFileHeader(cfile: Cfile): Rope =
result = getCopyright(cfile)
addIntTypes(result)
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
result = getCopyright(conf, cfile)
addIntTypes(result, conf)
proc genFilenames(m: BModule): Rope =
discard cgsym(m, "dbgRegisterFilename")
@@ -1051,8 +1048,8 @@ proc genMainProc(m: BModule) =
var nimMain, otherMain: FormatStr
if platform.targetOS == osWindows and
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in gGlobalOptions:
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
if optGenGuiApp in m.config.globalOptions:
nimMain = WinNimMain
otherMain = WinCMain
else:
@@ -1062,7 +1059,7 @@ proc genMainProc(m: BModule) =
elif platform.targetOS == osGenode:
nimMain = GenodeNimMain
otherMain = ComponentConstruct
elif optGenDynLib in gGlobalOptions:
elif optGenDynLib in m.config.globalOptions:
nimMain = PosixNimDllMain
otherMain = PosixCDllMain
elif platform.targetOS == osStandalone:
@@ -1072,16 +1069,16 @@ proc genMainProc(m: BModule) =
nimMain = PosixNimMain
otherMain = PosixCMain
if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
if optEndb in gOptions:
if optEndb in m.config.options:
m.g.breakpoints.add(m.genFilenames)
let initStackBottomCall =
if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope
if platform.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
inc(m.labels)
appcg(m, m.s[cfsProcs], PreMainBody, [
m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
if emulatedThreadVars() and platform.targetOS != osStandalone:
if emulatedThreadVars(m.config) and platform.targetOS != osStandalone:
ropecg(m, "\t#initThreadVarsEmulation();$N")
else:
"".rope,
@@ -1089,12 +1086,12 @@ proc genMainProc(m: BModule) =
appcg(m, m.s[cfsProcs], nimMain,
[m.g.mainModInit, initStackBottomCall, rope(m.labels)])
if optNoMain notin gGlobalOptions:
if useNimNamespace:
if optNoMain notin m.config.globalOptions:
if optUseNimNamespace in m.config.globalOptions:
m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl
appcg(m, m.s[cfsProcs], otherMain, [])
if useNimNamespace: m.s[cfsProcs].add openNamespaceNim()
if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim()
proc getSomeInitName(m: PSym, suffix: string): Rope =
assert m.kind == skModule
@@ -1118,8 +1115,8 @@ proc registerModuleToMain(g: BModuleList; m: PSym) =
var
init = m.getInitName
datInit = m.getDatInitName
addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
if sfSystemModule notin m.flags:
addf(g.mainDatInit, "\t$1();$N", [datInit])
let initCall = "\t$1();$N" % [init]
@@ -1130,7 +1127,7 @@ proc registerModuleToMain(g: BModuleList; m: PSym) =
proc genInitCode(m: BModule) =
var initname = getInitName(m.module)
var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
var prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname]
if m.typeNodes > 0:
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
[m.typeNodesName, rope(m.typeNodes)])
@@ -1140,11 +1137,11 @@ proc genInitCode(m: BModule) =
add(prc, initGCFrame(m.initProc))
add(prc, genSectionStart(cpsLocals))
add(prc, genSectionStart(cpsLocals, m.config))
add(prc, m.preInitProc.s(cpsLocals))
add(prc, m.initProc.s(cpsLocals))
add(prc, m.postInitProc.s(cpsLocals))
add(prc, genSectionEnd(cpsLocals))
add(prc, genSectionEnd(cpsLocals, m.config))
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
# BUT: the generated init code might depend on a current frame, so
@@ -1152,33 +1149,33 @@ proc genInitCode(m: BModule) =
incl m.flags, frameDeclared
if preventStackTrace notin m.flags:
var procname = makeCString(m.module.name.s)
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
else:
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
add(prc, genSectionStart(cpsInit))
add(prc, genSectionStart(cpsInit, m.config))
add(prc, m.preInitProc.s(cpsInit))
add(prc, m.initProc.s(cpsInit))
add(prc, m.postInitProc.s(cpsInit))
add(prc, genSectionEnd(cpsInit))
add(prc, genSectionEnd(cpsInit, m.config))
add(prc, genSectionStart(cpsStmts))
add(prc, genSectionStart(cpsStmts, m.config))
add(prc, m.preInitProc.s(cpsStmts))
add(prc, m.initProc.s(cpsStmts))
add(prc, m.postInitProc.s(cpsStmts))
add(prc, genSectionEnd(cpsStmts))
add(prc, genSectionEnd(cpsStmts, m.config))
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
add(prc, deinitFrame(m.initProc))
add(prc, deinitGCFrame(m.initProc))
addf(prc, "}$N$N", [])
prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
prc.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N",
[getDatInitName(m.module)])
for i in cfsTypeInit1..cfsDynLibInit:
add(prc, genSectionStart(i))
add(prc, genSectionStart(i, m.config))
add(prc, m.s[i])
add(prc, genSectionEnd(i))
add(prc, genSectionEnd(i, m.config))
addf(prc, "}$N$N", [])
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
@@ -1193,18 +1190,19 @@ proc genInitCode(m: BModule) =
add(m.s[cfsInitProc], ex)
proc genModule(m: BModule, cfile: Cfile): Rope =
result = getFileHeader(cfile)
result = getFileHeader(m.config, cfile)
result.add(genMergeInfo(m))
generateThreadLocalStorage(m)
generateHeaders(m)
for i in countup(cfsHeaders, cfsProcs):
add(result, genSectionStart(i))
add(result, genSectionStart(i, m.config))
add(result, m.s[i])
add(result, genSectionEnd(i))
if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
add(result, genSectionEnd(i, m.config))
if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders:
result.add openNamespaceNim()
add(result, m.s[cfsInitProc])
if useNimNamespace: result.add closeNamespaceNim()
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
proc newPreInitProc(m: BModule): BProc =
result = newProc(nil, m)
@@ -1217,10 +1215,12 @@ proc newPostInitProc(m: BModule): BProc =
result.labels = 200_000
proc initProcOptions(m: BModule): TOptions =
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
let opts = m.config.options
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
new(result)
result.g = g
result.tmpBase = rope("TM" & $hashOwner(module) & "_")
result.headerFiles = @[]
result.declaredThings = initIntSet()
@@ -1241,14 +1241,13 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
result.forwardedProcs = @[]
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
result.g = g
# no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags:
incl result.flags, preventStackTrace
excl(result.preInitProc.options, optStackTrace)
excl(result.postInitProc.options, optStackTrace)
let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
else: ""
open(result.ndi, ndiName)
@@ -1309,18 +1308,19 @@ proc newModule(g: BModuleList; module: PSym): BModule =
growCache g.modules, module.position
g.modules[module.position] = result
template injectG(config) {.dirty.} =
template injectG() {.dirty.} =
if graph.backend == nil:
graph.backend = newModuleList(config)
graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
injectG(graph.config)
injectG()
result = newModule(g, module)
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
let f = if graph.config.headerFile.len > 0: graph.config.headerFile
else: graph.config.projectFull
g.generatedHeader = rawNewModule(g, module,
changeFileExt(completeCFilePath(f), hExt))
changeFileExt(completeCFilePath(graph.config, f), hExt))
incl g.generatedHeader.flags, isHeaderFile
proc writeHeader(m: BModule) =
@@ -1331,43 +1331,44 @@ proc writeHeader(m: BModule) =
var guard = "__$1__" % [m.filename.splitFile.name.rope]
result.addf("#ifndef $1$n#define $1$n", [guard])
addIntTypes(result)
addIntTypes(result, m.config)
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
add(result, genSectionStart(i))
add(result, genSectionStart(i, m.config))
add(result, m.s[i])
add(result, genSectionEnd(i))
if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
add(result, genSectionEnd(i, m.config))
if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders: result.add openNamespaceNim()
add(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions:
if optGenDynLib in m.config.globalOptions:
result.add("N_LIB_IMPORT ")
result.addf("N_CDECL(void, NimMain)(void);$n", [])
if useNimNamespace: result.add closeNamespaceNim()
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
result.addf("#endif /* $1 */$n", [guard])
writeRope(result, m.filename)
proc getCFile(m: BModule): string =
let ext =
if m.compileToCpp: ".cpp"
elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
else: ".c"
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG(graph.config)
injectG()
var m = newModule(g, module)
readMergeInfo(getCFile(m), m)
result = m
proc myProcess(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
if b == nil: return
var m = BModule(b)
if passes.skipCodegen(m.config, n): return
m.initProc.options = initProcOptions(m)
softRnl = if optLineDir in gOptions: noRnl else: rnl
softRnl = if optLineDir in m.config.options: noRnl else: rnl
genStmts(m.initProc, n)
proc finishModule(m: BModule) =
@@ -1377,18 +1378,18 @@ proc finishModule(m: BModule) =
# a ``for`` loop here
var prc = m.forwardedProcs[i]
if sfForward in prc.flags:
internalError(prc.info, "still forwarded: " & prc.name.s)
internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
genProcNoForward(m, prc)
inc(i)
assert(m.g.forwardedProcsCounter >= i)
dec(m.g.forwardedProcsCounter, i)
setLen(m.forwardedProcs, 0)
proc shouldRecompile(code: Rope, cfile: Cfile): bool =
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
result = true
if optForceFullMake notin gGlobalOptions:
if optForceFullMake notin m.config.globalOptions:
if not equalsFile(code, cfile.cname):
if isDefined("nimdiff"):
if isDefined(m.config, "nimdiff"):
if fileExists(cfile.cname):
copyFile(cfile.cname, cfile.cname & ".backup")
echo "diff ", cfile.cname, ".backup ", cfile.cname
@@ -1411,7 +1412,7 @@ proc writeModule(m: BModule, pending: bool) =
# generate code for the init statements of the module:
let cfile = getCFile(m)
if m.rd == nil or optForceFullMake in gGlobalOptions:
if m.rd == nil or optForceFullMake in m.config.globalOptions:
genInitCode(m)
finishTypeDescriptions(m)
if sfMainModule in m.module.flags:
@@ -1419,35 +1420,35 @@ proc writeModule(m: BModule, pending: bool) =
add(m.s[cfsProcHeaders], m.g.mainModProcs)
generateThreadVarsSize(m)
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
var code = genModule(m, cf)
when hasTinyCBackend:
if gCmd == cmdRun:
if conf.cmd == cmdRun:
tccgen.compileCCode($code)
return
if not shouldRecompile(code, cf): cf.flags = {CfileFlag.Cached}
addFileToCompile(cf)
if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
addFileToCompile(m.config, cf)
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
let cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
let cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
mergeFiles(cfile, m)
genInitCode(m)
finishTypeDescriptions(m)
var code = genModule(m, cf)
writeRope(code, cfile)
addFileToCompile(cf)
addFileToCompile(m.config, cf)
else:
# Consider: first compilation compiles ``system.nim`` and produces
# ``system.c`` but then compilation fails due to an error. This means
# that ``system.o`` is missing, so we need to call the C compiler for it:
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
addFileToCompile(cf)
addFileToCompile(m.config, cf)
close(m.ndi)
proc updateCachedModule(m: BModule) =
let cfile = getCFile(m)
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
if mergeRequired(m) and sfMainModule notin m.module.flags:
mergeFiles(cfile, m)
@@ -1458,12 +1459,13 @@ proc updateCachedModule(m: BModule) =
writeRope(code, cfile)
else:
cf.flags = {CfileFlag.Cached}
addFileToCompile(cf)
addFileToCompile(m.config, cf)
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
if b == nil: return
var m = BModule(b)
if passes.skipCodegen(m.config, n): return
# if the module is cached, we don't regenerate the main proc
# nor the dispatchers? But if the dispatchers changed?
# XXX emit the dispatchers into its own .c file?
@@ -1497,7 +1499,7 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
m.updateCachedModule
else:
m.writeModule(pending=true)
writeMapping(g.mapping)
writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View File

@@ -14,6 +14,7 @@ import
tables, ndi
from msgs import TLineInfo
from modulegraphs import ModuleGraph
type
TLabel* = Rope # for the C generator a label is just a rope
@@ -116,6 +117,7 @@ type
breakpoints*: Rope # later the breakpoints are inserted into the main proc
typeInfoMarker*: TypeCache
config*: ConfigRef
graph*: ModuleGraph
strVersion*, seqVersion*: int # version of the string/seq implementation to use
TCGen = object of TPassContext # represents a C source file
@@ -148,6 +150,9 @@ type
g*: BModuleList
ndi*: NdiFile
template config*(m: BModule): ConfigRef = m.g.config
template config*(p: BProc): ConfigRef = p.module.g.config
proc includeHeader*(this: BModule; header: string) =
if not this.headerFiles.contains header:
this.headerFiles.add header
@@ -165,14 +170,15 @@ proc newProc*(prc: PSym, module: BModule): BProc =
result.prc = prc
result.module = module
if prc != nil: result.options = prc.options
else: result.options = gOptions
else: result.options = module.config.options
newSeq(result.blocks, 1)
result.nestedTryStmts = @[]
result.finallySafePoints = @[]
result.sigConflicts = initCountTable[string]()
proc newModuleList*(config: ConfigRef): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: config)
proc newModuleList*(g: ModuleGraph): BModuleList =
BModuleList(modules: @[], typeInfoMarker: initTable[SigHash, Rope](), config: g.config,
graph: g)
iterator cgenModules*(g: BModuleList): BModule =
for i in 0..high(g.modules):

View File

@@ -11,9 +11,9 @@
import
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
sempass2, strutils, modulegraphs
sempass2, strutils, modulegraphs, configuration
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
var dest = skipTypes(d, abstractPtrs)
var source = skipTypes(n.typ, abstractPtrs)
if (source.kind == tyObject) and (dest.kind == tyObject):
@@ -24,12 +24,12 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
elif diff < 0:
result = newNodeIT(nkObjUpConv, n.info, d)
addSon(result, n)
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed")
elif diff > 0:
result = newNodeIT(nkObjDownConv, n.info, d)
addSon(result, n)
if not downcast:
internalError(n.info, "cgmeth.genConv: no downcast allowed")
internalError(conf, n.info, "cgmeth.genConv: no downcast allowed")
else:
result = n
else:
@@ -42,7 +42,7 @@ proc getDispatcher*(s: PSym): PSym =
let disp = dispn.sym
if sfDispatcher in disp.flags: result = disp
proc methodCall*(n: PNode): PNode =
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
result = n
# replace ordinary method by dispatcher method:
let disp = getDispatcher(result.sons[0].sym)
@@ -50,9 +50,9 @@ proc methodCall*(n: PNode): PNode =
result.sons[0].sym = disp
# change the arguments to up/downcasts to fit the dispatcher's parameters:
for i in countup(1, sonsLen(result)-1):
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true)
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
else:
localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
type
MethodResult = enum No, Invalid, Yes
@@ -130,7 +130,7 @@ proc createDispatcher(s: PSym): PSym =
attachDispatcher(disp, newSymNode(disp))
return disp
proc fixupDispatcher(meth, disp: PSym) =
proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
# We may have constructed the dispatcher from a method prototype
# and need to augment the incomplete dispatcher with information
# from later definitions, particularly the resultPos slot. Also,
@@ -149,7 +149,7 @@ proc fixupDispatcher(meth, disp: PSym) =
disp.typ.lockLevel = meth.typ.lockLevel
elif meth.typ.lockLevel != UnspecifiedLockLevel and
meth.typ.lockLevel != disp.typ.lockLevel:
message(meth.info, warnLockLevel,
message(conf, meth.info, warnLockLevel,
"method has lock level $1, but another method has $2" %
[$meth.typ.lockLevel, $disp.typ.lockLevel])
# XXX The following code silences a duplicate warning in
@@ -166,13 +166,13 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
of Yes:
add(g.methods[i].methods, s)
attachDispatcher(s, lastSon(disp.ast))
fixupDispatcher(s, disp)
fixupDispatcher(s, disp, g.config)
#echo "fixup ", disp.name.s, " ", disp.id
when useEffectSystem: checkMethodEffects(disp, s)
when useEffectSystem: checkMethodEffects(g, disp, s)
if {sfBase, sfFromGeneric} * s.flags == {sfBase} and
g.methods[i].methods[0] != s:
# already exists due to forwarding definition?
localError(s.info, "method is not a base")
localError(g.config, s.info, "method is not a base")
return
of No: discard
of Invalid:
@@ -183,10 +183,10 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
#if fromCache:
# internalError(s.info, "no method dispatcher found")
if witness != nil:
localError(s.info, "invalid declaration order; cannot attach '" & s.name.s &
localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
"' to method defined here: " & $witness.info)
elif sfBase notin s.flags:
message(s.info, warnUseBase)
message(g.config, s.info, warnUseBase)
proc relevantCol(methods: TSymSeq, col: int): bool =
# returns true iff the position is relevant
@@ -225,32 +225,33 @@ proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
a[j] = v
if h == 1: break
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym =
var base = lastSon(methods[0].ast).sym
result = base
var paramLen = sonsLen(base.typ)
var nilchecks = newNodeI(nkStmtList, base.info)
var disp = newNodeI(nkIfStmt, base.info)
var ands = getSysSym("and")
var iss = getSysSym("of")
var ands = getSysSym(g, unknownLineInfo(), "and")
var iss = getSysSym(g, unknownLineInfo(), "of")
let boolType = getSysType(g, unknownLineInfo(), tyBool)
for col in countup(1, paramLen - 1):
if contains(relevantCols, col):
let param = base.typ.n.sons[col].sym
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
addSon(nilchecks, newTree(nkCall,
newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param)))
newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param)))
for meth in countup(0, high(methods)):
var curr = methods[meth] # generate condition:
var cond: PNode = nil
for col in countup(1, paramLen - 1):
if contains(relevantCols, col):
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
var isn = newNodeIT(nkCall, base.info, boolType)
addSon(isn, newSymNode(iss))
let param = base.typ.n.sons[col].sym
addSon(isn, newSymNode(param))
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
if cond != nil:
var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
var a = newNodeIT(nkCall, base.info, boolType)
addSon(a, newSymNode(ands))
addSon(a, cond)
addSon(a, isn)
@@ -262,7 +263,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
addSon(call, newSymNode(curr))
for col in countup(1, paramLen - 1):
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
curr.typ.sons[col], false))
curr.typ.sons[col], false, g.config))
var ret: PNode
if retTyp != nil:
var a = newNodeI(nkFastAsgn, base.info)
@@ -290,4 +291,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
sortBucket(g.methods[bucket].methods, relevantCols)
addSon(result,
newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols)))
newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols)))

File diff suppressed because it is too large Load Diff

View File

@@ -12,77 +12,30 @@
import
strtabs, platform, strutils, idents
# We need to use a StringTableRef here as defined symbols are always guaranteed
# to be style insensitive. Otherwise hell would break lose.
var gSymbols: StringTableRef
const
catNone = "false"
proc defineSymbol*(symbol: string, value: string = "true") =
gSymbols[symbol] = value
proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
symbols[symbol] = value
proc undefSymbol*(symbol: string) =
gSymbols[symbol] = catNone
proc undefSymbol*(symbols: StringTableRef; symbol: string) =
symbols[symbol] = catNone
proc isDefined*(symbol: string): bool =
if gSymbols.hasKey(symbol):
result = gSymbols[symbol] != catNone
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
result = true
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
result = true
else:
case symbol.normalize
of "x86": result = targetCPU == cpuI386
of "itanium": result = targetCPU == cpuIa64
of "x8664": result = targetCPU == cpuAmd64
of "posix", "unix":
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
osAndroid}
of "linux":
result = targetOS in {osLinux, osAndroid}
of "bsd":
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
of "emulatedthreadvars":
result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
of "msdos": result = targetOS == osDos
of "mswindows", "win32": result = targetOS == osWindows
of "macintosh": result = targetOS in {osMacos, osMacosx}
of "sunos": result = targetOS == osSolaris
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[targetCPU].bit == 8
of "cpu16": result = CPU[targetCPU].bit == 16
of "cpu32": result = CPU[targetCPU].bit == 32
of "cpu64": result = CPU[targetCPU].bit == 64
of "nimrawsetjmp":
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
osDragonfly, osMacosx}
else: discard
#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string =
# result = if isDefined(symbol): gSymbols[symbol] else: nil
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
proc lookupSymbol*(symbol: string): string =
result = if isDefined(symbol): gSymbols[symbol] else: nil
proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
iterator definedSymbolNames*: string =
for key, val in pairs(gSymbols):
iterator definedSymbolNames*(symbols: StringTableRef): string =
for key, val in pairs(symbols):
if val != catNone: yield key
proc countDefinedSymbols*(): int =
proc countDefinedSymbols*(symbols: StringTableRef): int =
result = 0
for key, val in pairs(gSymbols):
for key, val in pairs(symbols):
if val != catNone: inc(result)
proc initDefines*() =
gSymbols = newStringTable(modeStyleInsensitive)
proc initDefines*(symbols: StringTableRef) =
# for bootstrapping purposes and old code:
template defineSymbol(s) = symbols.defineSymbol(s)
defineSymbol("nimhygiene")
defineSymbol("niminheritable")
defineSymbol("nimmixin")

360
compiler/configuration.nim Normal file
View File

@@ -0,0 +1,360 @@
#
#
# The Nim Compiler
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module contains the rather excessive configuration object that
## needs to be passed around to everything so that the compiler becomes
## more useful as a library.
import tables
const
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
type
TMsgKind* = enum
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
errXExpected,
errGridTableNotImplemented,
errGeneralParseError,
errNewSectionExpected,
errInvalidDirectiveX,
errGenerated,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnTypelessParam,
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintExecuting, hintLinking, hintDependency,
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintUser, hintUserRaw
const
MsgKindToStr*: array[TMsgKind, string] = [
errUnknown: "unknown error",
errInternal: "internal error: $1",
errIllFormedAstX: "illformed AST: $1",
errCannotOpenFile: "cannot open '$1'",
errXExpected: "'$1' expected",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errInvalidDirectiveX: "invalid directive: '$1'",
errGenerated: "$1",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
warnXIsNeverRead: "'$1' is never read",
warnXmightNotBeenInit: "'$1' might not have been initialized",
warnDeprecated: "$1 is deprecated",
warnConfigDeprecated: "config file '$1' is deprecated",
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
warnRedefinitionOfLabel: "redefinition of label '$1'",
warnUnknownSubstitutionX: "unknown substitution '$1'",
warnLanguageXNotSupported: "language '$1' not supported",
warnFieldXNotSupported: "field '$1' not supported",
warnCommentXIgnored: "comment '$1' ignored",
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
warnWriteToForeignHeap: "write to foreign heap",
warnUnsafeCode: "unsafe code: '$1'",
warnEachIdentIsTuple: "each identifier is a tuple",
warnShadowIdent: "shadowed identifier: '$1'",
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
warnProveField: "cannot prove that field '$1' is accessible",
warnProveIndex: "cannot prove index '$1' is valid",
warnGcUnsafe: "not GC-safe: '$1'",
warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized",
warnGcMem: "'$1' uses GC'ed memory",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
warnLockLevel: "$1",
warnResultShadowed: "Special variable 'result' is shadowed.",
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnUser: "$1",
hintSuccess: "operation successful",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintConvToBaseNotNeeded: "conversion to base object is not needed",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
hintExprAlwaysX: "expression evaluates always to '$1'",
hintQuitCalled: "quit() called",
hintProcessing: "$1",
hintCodeBegin: "generated code listing:",
hintCodeEnd: "end of listing",
hintConf: "used config file '$1'",
hintPath: "added path: '$1'",
hintConditionAlwaysTrue: "condition is always true: '$1'",
hintName: "name should be: '$1'",
hintPattern: "$1",
hintExecuting: "$1",
hintLinking: "",
hintDependency: "$1",
hintSource: "$1",
hintPerformance: "$1",
hintStackTrace: "$1",
hintGCStats: "$1",
hintUser: "$1",
hintUserRaw: "$1"]
const
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored",
"TypelessParam", "UseBase", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "User"]
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
"Source", "Performance", "StackTrace", "GCStats",
"User", "UserRaw"]
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
const
NotesVerbosity*: array[0..3, TNoteKinds] = [
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintSuccessX, hintPath, hintConf,
hintProcessing, hintPattern,
hintDependency,
hintExecuting, hintLinking,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintPath,
hintDependency,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
{low(TNoteKind)..high(TNoteKind)}]
const
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
#[
errStringLiteralExpected: "string literal expected",
errIntLiteralExpected: "integer literal expected",
errIdentifierExpected: "identifier expected, but found '$1'",
errNewlineExpected: "newline expected, but found '$1'",
errInvalidModuleName: "invalid module name: '$1'",
errOnOrOffExpected: "'on' or 'off' expected",
errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
errInvalidPragma: "invalid pragma",
errUnknownPragma: "unknown pragma: '$1'",
errAtPopWithoutPush: "'pop' without a 'push' pragma",
errEmptyAsm: "empty asm statement",
errInvalidIndentation: "invalid indentation",
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
errAttemptToRedefine: ,
errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
errStmtExpected: "statement expected",
errInvalidLabel: "'$1' is no label",
errInvalidCmdLineOption: "invalid command line option: '$1'",
errCmdLineArgExpected: "argument for command line option expected: '$1'",
errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
errInvalidVarSubstitution: "invalid variable substitution in '$1'",
errUnknownVar: "unknown variable: '$1'",
errUnknownCcompiler: "unknown C compiler: '$1'",
errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
,
errInvalidMultipleAsgn: "multiple assignment is not allowed",
errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
errUndeclaredField: "undeclared field: '$1'",
errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
errTypeExpected: "type expected",
errSystemNeeds: "system module needs '$1'",
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
errNotOverloadable: ,
errInvalidArgForX: "invalid argument for '$1'",
errStmtHasNoEffect: "statement has no effect",
,
errXExpectsArrayType: "'$1' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: ,
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: ,
errCannotEvalXBecauseIncompletelyDefined: ,
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
errNilAccess: "attempt to access a nil address",
errIndexOutOfBounds: "index out of bounds",
errIndexTypesDoNotMatch: "index types do not match",
errBracketsInvalidForType: "'[]' operator invalid for this type",
errValueOutOfSetBounds: "value out of set bounds",
errFieldNotInit: "field '$1' not initialized",
errExprXCannotBeCalled: "expression '$1' cannot be called",
errExprHasNoType: "expression has no type",
errExprXHasNoType:,
errCastNotInSafeMode: "'cast' not allowed in safe mode",
errExprCannotBeCastToX: ,
errCommaOrParRiExpected: "',' or ')' expected",
errCurlyLeOrParLeExpected: "'{' or '(' expected",
errSectionExpected: "section ('type', 'proc', etc.) expected",
errRangeExpected: "range expected",
errMagicOnlyInSystem: "'magic' only allowed in system module",
errPowerOfTwoExpected: "power of two expected",
errStringMayNotBeEmpty: "string literal may not be empty",
errCallConvExpected: "calling convention expected",
errProcOnlyOneCallConv: "a proc can only have one calling convention",
errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
errExprMustBeBool: "expression must be of type 'bool'",
errConstExprExpected: "constant expression expected",
errDuplicateCaseLabel: "duplicate case label",
errRangeIsEmpty: "range is empty",
,
errSelectorMustBeOrdinal: "selector must be of an ordinal type",
errOrdXMustNotBeNegative: "ord($1) must not be negative",
errLenXinvalid: "len($1) must be less than 32768",
errTypeXhasUnknownSize: "type '$1' has unknown size",
errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
errConstNeedsValue: "a constant needs a value",
errResultCannotBeOpenArray: "the result type cannot be on open array",
errSizeTooBig: "computing the type's size produced an overflow",
errInheritanceOnlyWithEnums: "inheritance only works with an enum",
errIllegalRecursionInTypeX:,
errCannotInstantiateX: "cannot instantiate: '$1'",
errTypeMismatch: "type mismatch: got <",
errButExpected: "but expected one of: ",
errButExpectedX: "but expected '$1'",
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
errWrongNumberOfArguments: "wrong number of arguments",
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
errXCannotBePassedToProcVar: ,
,
errImplOfXexpected: ,
errIllegalConvFromXtoY: ,
errCannotBindXTwice: "cannot bind parameter '$1' twice",
errInvalidOrderInArrayConstructor: ,
errInvalidOrderInEnumX: "invalid order in enum '$1'",
errEnumXHasHoles: "enum '$1' has holes",
errExceptExpected: "'except' or 'finally' expected",
errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
errOptionExpected: ,
errXisNoLabel: "'$1' is not a label",
errNotAllCasesCovered: "not all cases are covered",
errUnknownSubstitionVar: "unknown substitution variable: '$1'",
errComplexStmtRequiresInd: "complex statement requires indentation",
errXisNotCallable: "'$1' is not callable",
errNoPragmasAllowedForX: "no pragmas allowed for $1",
,
errInvalidParamKindX: "invalid param kind: '$1'",
errDefaultArgumentInvalid: "default argument invalid",
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
errNoReturnTypeForX: "no return type allowed for $1",
errConvNeedsOneArg: "a type conversion needs exactly one argument",
errInvalidPragmaX: ,
errXNotAllowedHere: "$1 not allowed here",
errXisNoType: "invalid type: '$1'",
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
errInvalidExpression: "invalid expression",
errInvalidExpressionX: "invalid expression: '$1'",
errEnumHasNoValueX: "enum has no value '$1'",
,
errNoCommand: "no command given",
errInvalidCommandX: "invalid command: '$1'",
errXNeedsParamObjectType: ,
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
errInstantiationFrom: "template/generic instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "'$1' expected",
,
errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errWhitespaceExpected: "whitespace expected, got '$1'",
errXisNoValidIndexFile: "'$1' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element '$1'",
errVarVarTypeNotAllowed: ,
errInstantiateXExplicitly: "instantiate '$1' explicitly",
errOnlyACallOpCanBeDelegator: ,
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators",
errXExpectsTwoArguments: "'$1' expects two arguments",
errXExpectsObjectTypes: "'$1' expects object types",
errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
errTooManyIterations: "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler",
errFieldXNotFound: "field '$1' cannot be found",
errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
errAssertionFailed: "assertion failed",
errCannotGenerateCodeForX: "cannot generate code for '$1'",
errXRequiresOneArgument: "$1 requires one parameter",
errUnhandledExceptionX: "unhandled exception: $1",
errCyclicTree: "macro returned a cyclic abstract syntax tree",
errXisNoMacroOrTemplate: "'$1' is no macro or template",
errXhasSideEffects: "'$1' can have side effects",
errWrongSymbolX:,
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
,
]#

View File

@@ -19,6 +19,7 @@ proc generateDot*(project: string)
type
TGen = object of TPassContext
module*: PSym
config: ConfigRef
PGen = ref TGen
var gDotGraph: Rope # the generated DOT file; we need a global variable
@@ -33,10 +34,10 @@ proc addDotDependency(c: PPassContext, n: PNode): PNode =
case n.kind
of nkImportStmt:
for i in countup(0, sonsLen(n) - 1):
var imported = getModuleName(n.sons[i])
var imported = getModuleName(g.config, n.sons[i])
addDependencyAux(g.module.name.s, imported)
of nkFromStmt, nkImportExceptStmt:
var imported = getModuleName(n.sons[0])
var imported = getModuleName(g.config, n.sons[0])
addDependencyAux(g.module.name.s, imported)
of nkStmtList, nkBlockStmt, nkStmtListExpr, nkBlockExpr:
for i in countup(0, sonsLen(n) - 1): discard addDotDependency(c, n.sons[i])
@@ -52,6 +53,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var g: PGen
new(g)
g.module = module
g.config = graph.config
result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View File

@@ -116,7 +116,8 @@ Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
strutils, options, dfa, lowerings, rodread, tables
strutils, options, dfa, lowerings, rodread, tables, modulegraphs,
configuration
const
InterestingSyms = {skVar, skResult, skLet}
@@ -130,6 +131,7 @@ type
tmp: PSym
destroys, topLevelVars: PNode
toDropBit: Table[int, PSym]
graph: ModuleGraph
proc getTemp(c: var Con; typ: PType; info: TLineInfo): PNode =
# XXX why are temps fields in an object here?
@@ -222,21 +224,21 @@ proc patchHead(s: PSym) =
template genOp(opr, opname) =
let op = opr
if op == nil:
globalError(dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator not found for type " & typeToString(t))
elif op.ast[genericParamsPos].kind != nkEmpty:
globalError(dest.info, "internal error: '" & opname & "' operator is generic")
globalError(c.graph.config, dest.info, "internal error: '" & opname & "' operator is generic")
patchHead op
result = newTree(nkCall, newSymNode(op), newTree(nkHiddenAddr, dest))
proc genSink(t: PType; dest: PNode): PNode =
proc genSink(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(if t.sink != nil: t.sink else: t.assignment, "=sink")
proc genCopy(t: PType; dest: PNode): PNode =
proc genCopy(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(t.assignment, "=")
proc genDestroy(t: PType; dest: PNode): PNode =
proc genDestroy(c: Con; t: PType; dest: PNode): PNode =
let t = t.skipTypes({tyGenericInst, tyAlias, tySink})
genOp(t.destructor, "=destroy")
@@ -249,14 +251,14 @@ proc dropBit(c: var Con; s: PSym): PSym =
proc registerDropBit(c: var Con; s: PSym) =
let result = newSym(skTemp, getIdent(s.name.s & "_AliveBit"), c.owner, s.info)
result.typ = getSysType(tyBool)
result.typ = getSysType(c.graph, s.info, tyBool)
let trueVal = newIntTypeNode(nkIntLit, 1, result.typ)
c.topLevelVars.add newTree(nkIdentDefs, newSymNode result, emptyNode, trueVal)
c.toDropBit[s.id] = result
# generate:
# if not sinkParam_AliveBit: `=destroy`(sinkParam)
c.destroys.add newTree(nkIfStmt,
newTree(nkElifBranch, newSymNode result, genDestroy(s.typ, newSymNode s)))
newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s)))
proc p(n: PNode; c: var Con): PNode
@@ -274,36 +276,36 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let bit = newSymNode dropBit(c, n.sym)
if optMoveCheck in c.owner.options:
result.add callCodegenProc("chckMove", bit)
result.add callCodegenProc(c.graph, "chckMove", bit)
result.add newTree(nkAsgn, bit,
newIntTypeNode(nkIntLit, 0, getSysType(tyBool)))
newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool)))
result.add n
proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
if ri.kind in constrExprs:
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
# watch out and no not transform 'ri' twice if it's a call:
let ri2 = copyNode(ri)
recurse(ri, ri2)
result.add ri2
elif ri.kind == nkSym and isHarmlessVar(ri.sym, c):
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
result.add p(ri, c)
elif ri.kind == nkSym and isSinkParam(ri.sym):
result = genSink(ri.typ, dest)
result = genSink(c, ri.typ, dest)
result.add destructiveMoveSink(ri, c)
else:
result = genCopy(ri.typ, dest)
result = genCopy(c, ri.typ, dest)
result.add p(ri, c)
proc passCopyToSink(n: PNode; c: var Con): PNode =
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = getTemp(c, n.typ, n.info)
if hasDestructor(n.typ):
var m = genCopy(n.typ, tmp)
var m = genCopy(c, n.typ, tmp)
m.add p(n, c)
result.add m
message(n.info, hintPerformance,
message(c.graph.config, n.info, hintPerformance,
"passing '$1' to a sink parameter introduces an implicit copy; " &
"use 'move($1)' to prevent it" % $n)
else:
@@ -312,7 +314,7 @@ proc passCopyToSink(n: PNode; c: var Con): PNode =
proc genReset(n: PNode; c: var Con): PNode =
result = newNodeI(nkCall, n.info)
result.add(newSymNode(createMagic("reset", mReset)))
result.add(newSymNode(createMagic(c.graph, "reset", mReset)))
# The mReset builtin does not take the address:
result.add n
@@ -345,7 +347,7 @@ proc p(n: PNode; c: var Con): PNode =
let L = it.len-1
let ri = it[L]
if it.kind == nkVarTuple and hasDestructor(ri.typ):
let x = lowerTupleUnpacking(it, c.owner)
let x = lowerTupleUnpacking(c.graph, it, c.owner)
result.add p(x, c)
elif it.kind == nkIdentDefs and hasDestructor(it[0].typ):
for j in 0..L-2:
@@ -354,7 +356,7 @@ proc p(n: PNode; c: var Con): PNode =
# move the variable declaration to the top of the frame:
c.addTopVar v
# make sure it's destroyed at the end of the proc:
c.destroys.add genDestroy(v.typ, v)
c.destroys.add genDestroy(c, v.typ, v)
if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c)
result.add r
@@ -400,11 +402,11 @@ proc p(n: PNode; c: var Con): PNode =
discard "produce temp creation"
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let tmp = getTemp(c, n.typ, n.info)
var sinkExpr = genSink(n.typ, tmp)
var sinkExpr = genSink(c, n.typ, tmp)
sinkExpr.add n
result.add sinkExpr
result.add tmp
c.destroys.add genDestroy(n.typ, tmp)
c.destroys.add genDestroy(c, n.typ, tmp)
else:
result = n
of nkAsgn, nkFastAsgn:
@@ -420,17 +422,18 @@ proc p(n: PNode; c: var Con): PNode =
result = copyNode(n)
recurse(n, result)
proc injectDestructorCalls*(owner: PSym; n: PNode): PNode =
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
when defined(nimDebugDestroys):
echo "injecting into ", n
var c: Con
c.owner = owner
c.tmp = newSym(skTemp, getIdent":d", owner, n.info)
c.tmpObj = createObj(owner, n.info)
c.tmpObj = createObj(g, owner, n.info)
c.tmp.typ = c.tmpObj
c.destroys = newNodeI(nkStmtList, n.info)
c.topLevelVars = newNodeI(nkVarSection, n.info)
c.toDropBit = initTable[int, PSym]()
c.graph = g
let cfg = constructCfg(owner, n)
shallowCopy(c.g, cfg)
c.jumpTargets = initIntSet()

View File

@@ -23,7 +23,7 @@
## "A GraphFree Approach to DataFlow Analysis" by Markus Mohnen.
## https://link.springer.com/content/pdf/10.1007/3-540-45937-5_6.pdf
import ast, astalgo, types, intsets, tables, msgs
import ast, astalgo, types, intsets, tables, msgs, options
type
InstrKind* = enum
@@ -102,14 +102,14 @@ proc genLabel(c: Con): TPosition =
proc jmpBack(c: var Con, n: PNode, p = TPosition(0)) =
let dist = p.int - c.code.len
internalAssert(-0x7fff < dist and dist < 0x7fff)
doAssert(-0x7fff < dist and dist < 0x7fff)
c.code.add Instr(n: n, kind: goto, dest: dist)
proc patch(c: var Con, p: TPosition) =
# patch with current index
let p = p.int
let diff = c.code.len - p
internalAssert(-0x7fff < diff and diff < 0x7fff)
doAssert(-0x7fff < diff and diff < 0x7fff)
c.code[p].dest = diff
proc popBlock(c: var Con; oldLen: int) =
@@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) =
if c.blocks[i].label == n.sons[0].sym:
c.blocks[i].fixups.add L1
return
globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
#globalError(n.info, "VM problem: cannot find 'break' target")
else:
c.blocks[c.blocks.high].fixups.add L1
@@ -334,7 +334,7 @@ proc gen(c: var Con; n: PNode) =
of nkVarSection, nkLetSection: genVarSection(c, n)
else: discard
proc dfa(code: seq[Instr]) =
proc dfa(code: seq[Instr]; conf: ConfigRef) =
var u = newSeq[IntSet](code.len) # usages
var d = newSeq[IntSet](code.len) # defs
var c = newSeq[IntSet](code.len) # consumed
@@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) =
of use, useWithinCall:
let s = code[i].sym
if s.id notin d[i]:
localError(code[i].n.info, "usage of uninitialized variable: " & s.name.s)
localError(conf, code[i].n.info, "usage of uninitialized variable: " & s.name.s)
if s.id in c[i]:
localError(code[i].n.info, "usage of an already consumed variable: " & s.name.s)
localError(conf, code[i].n.info, "usage of an already consumed variable: " & s.name.s)
else: discard
proc dataflowAnalysis*(s: PSym; body: PNode) =
proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
var c = Con(code: @[], blocks: @[])
gen(c, body)
when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
dfa(c.code)
dfa(c.code, conf)
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
## constructs a control flow graph for ``body``.

View File

@@ -16,7 +16,7 @@ import
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
packages/docutils/rst, packages/docutils/rstgen, times,
packages/docutils/highlite, sempass2, json, xmltree, cgi,
typesrenderer, astalgo, modulepaths
typesrenderer, astalgo, modulepaths, configuration
type
TSections = array[TSymKind, Rope]
@@ -29,6 +29,7 @@ type
jArray: JsonNode
types: TStrTable
isPureRst: bool
conf*: ConfigRef
PDoc* = ref TDocumentor ## Alias to type less.
@@ -53,42 +54,47 @@ proc attachToType(d: PDoc; p: PSym): PSym =
if params.len > 0: check(0)
for i in 2..<params.len: check(i)
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind:
var k: msgs.TMsgKind
case msgKind
of meCannotOpenFile: k = errCannotOpenFile
of meExpected: k = errXExpected
of meGridTableNotImplemented: k = errGridTableNotImplemented
of meNewSectionExpected: k = errNewSectionExpected
of meGeneralParseError: k = errGeneralParseError
of meInvalidDirective: k = errInvalidDirectiveX
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
of mwUnsupportedField: k = warnFieldXNotSupported
globalError(newLineInfo(filename, line, col), k, arg)
template declareClosures =
proc compilerMsgHandler(filename: string, line, col: int,
msgKind: rst.MsgKind, arg: string) {.procvar.} =
# translate msg kind:
var k: TMsgKind
case msgKind
of meCannotOpenFile: k = errCannotOpenFile
of meExpected: k = errXExpected
of meGridTableNotImplemented: k = errGridTableNotImplemented
of meNewSectionExpected: k = errNewSectionExpected
of meGeneralParseError: k = errGeneralParseError
of meInvalidDirective: k = errInvalidDirectiveX
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
of mwUnsupportedField: k = warnFieldXNotSupported
globalError(conf, newLineInfo(conf, filename, line, col), k, arg)
proc docgenFindFile(s: string): string {.procvar.} =
result = options.findFile(s)
if result.len == 0:
result = getCurrentDir() / s
if not existsFile(result): result = ""
proc docgenFindFile(s: string): string {.procvar.} =
result = options.findFile(conf, s)
if result.len == 0:
result = getCurrentDir() / s
if not existsFile(result): result = ""
proc parseRst(text, filename: string,
line, column: int, hasToc: var bool,
rstOptions: RstParseOptions): PRstNode =
rstOptions: RstParseOptions;
conf: ConfigRef): PRstNode =
declareClosures()
result = rstParse(text, filename, line, column, hasToc, rstOptions,
docgenFindFile, compilerMsgHandler)
proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
proc newDocumentor*(filename: string, conf: ConfigRef): PDoc =
declareClosures()
new(result)
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
options.gConfigVars, filename, {roSupportRawDirective},
result.conf = conf
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
conf.configVars, filename, {roSupportRawDirective},
docgenFindFile, compilerMsgHandler)
if config.hasKey("doc.googleAnalytics"):
if conf.configVars.hasKey("doc.googleAnalytics"):
result.analytics = """
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@@ -100,7 +106,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
ga('send', 'pageview');
</script>
""" % [config.getOrDefault"doc.googleAnalytics"]
""" % [conf.configVars.getOrDefault"doc.googleAnalytics"]
else:
result.analytics = ""
@@ -109,10 +115,10 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
result.jArray = newJArray()
initStrTable result.types
result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
localError(newLineInfo(d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if gCmd != cmdRst2tex: addf(dest, xml, args)
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
else: addf(dest, tex, args)
proc getVarIdx(varnames: openArray[string], id: string): int =
@@ -121,7 +127,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
return i
result = -1
proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
varnames: openArray[string],
varvalues: openArray[Rope]): Rope =
var i = 0
var L = len(frmt)
@@ -144,7 +151,8 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
if j > high(varvalues) + 1:
rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt)
num = j
add(result, varvalues[j - 1])
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
@@ -155,20 +163,23 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
var idx = getVarIdx(varnames, id)
if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id)
else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
of '{':
var id = ""
inc(i)
while frmt[i] != '}':
if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
while i < frmt.len and frmt[i] != '}':
add(id, frmt[i])
inc(i)
inc(i) # skip }
# search for the variable:
var idx = getVarIdx(varnames, id)
if i >= frmt.len:
rawMessage(conf, errGenerated, "expected closing '}'")
else:
inc(i) # skip }
# search for the variable:
let idx = getVarIdx(varnames, id)
if idx >= 0: add(result, varvalues[idx])
else: rawMessage(errUnknownSubstitionVar, id)
else: internalError("ropeFormatNamedVars")
else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
else:
add(result, "$")
var start = i
while i < L:
if frmt[i] != '$': inc(i)
@@ -181,7 +192,7 @@ proc genComment(d: PDoc, n: PNode): string =
if n.comment != nil:
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
toLinenumber(n.info), toColumn(n.info),
dummyHasToc, d.options), result)
dummyHasToc, d.options, d.conf), result)
proc genRecComment(d: PDoc, n: PNode): Rope =
if n == nil: return nil
@@ -220,37 +231,37 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
of tkEof:
break
of tkComment:
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
dispA(d.conf, result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
[rope(esc(d.target, literal))])
of tokKeywordLow..tokKeywordHigh:
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
dispA(d.conf, result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
[rope(literal)])
of tkOpr:
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
dispA(d.conf, result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
[rope(esc(d.target, literal))])
of tkStrLit..tkTripleStrLit:
dispA(result, "<span class=\"StringLit\">$1</span>",
dispA(d.conf, result, "<span class=\"StringLit\">$1</span>",
"\\spanStringLit{$1}", [rope(esc(d.target, literal))])
of tkCharLit:
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
dispA(d.conf, result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
[rope(esc(d.target, literal))])
of tkIntLit..tkUInt64Lit:
dispA(result, "<span class=\"DecNumber\">$1</span>",
dispA(d.conf, result, "<span class=\"DecNumber\">$1</span>",
"\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
of tkFloatLit..tkFloat128Lit:
dispA(result, "<span class=\"FloatNumber\">$1</span>",
dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
of tkSymbol:
dispA(result, "<span class=\"Identifier\">$1</span>",
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
of tkSpaces, tkInvalid:
add(result, literal)
of tkCurlyDotLe:
dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
dispA(d.conf, result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkCurlyDotRi:
dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
dispA(d.conf, result, "</div><span class=\"Other pragmaend\">$1</span>",
"\\spanOther{$1}",
[rope(esc(d.target, literal))])
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
@@ -259,7 +270,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
tkAccent, tkColonColon,
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
tkBracketLeColon:
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
[rope(esc(d.target, literal))])
proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
@@ -267,7 +278,7 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
of nkCallKinds:
if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and
n.len >= 2 and n.lastSon.kind == nkStmtList:
dispA(dest, "\n<strong class=\"examples_text\">$1</strong>\n",
dispA(d.conf, dest, "\n<strong class=\"examples_text\">$1</strong>\n",
"\n\\textbf{$1}\n", [rope"Examples:"])
inc d.listingCounter
let id = $d.listingCounter
@@ -336,7 +347,6 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
of nkOpenSymChoice, nkClosedSymChoice:
result = getName(d, n[0], splitAfter)
else:
internalError(n.info, "getName()")
result = ""
proc getNameIdent(n: PNode): PIdent =
@@ -366,7 +376,6 @@ proc getRstName(n: PNode): PRstNode =
of nkOpenSymChoice, nkClosedSymChoice:
result = getRstName(n[0])
else:
internalError(n.info, "getRstName()")
result = nil
proc newUniquePlainSymbol(d: PDoc, original: string): string =
@@ -490,22 +499,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
symbolOrIdEncRope = encodeUrl(symbolOrId).rope
var seeSrcRope: Rope = nil
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
if docItemSeeSrc.len > 0:
let cwd = getCurrentDir().canonicalizePath()
let cwd = canonicalizePath(d.conf, getCurrentDir())
var path = n.info.toFullPath
if path.startsWith(cwd):
path = path[cwd.len+1 .. ^1].replace('\\', '/')
let gitUrl = getConfigVar("git.url")
let gitUrl = getConfigVar(d.conf, "git.url")
if gitUrl.len > 0:
var commit = getConfigVar("git.commit")
var commit = getConfigVar(d.conf, "git.commit")
if commit.len == 0: commit = "master"
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
["path", "line", "url", "commit"], [rope path,
rope($n.info.line), rope gitUrl,
rope commit])])
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
@@ -516,7 +525,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
let att = attachToType(d, nameNode.sym)
if att != nil:
attype = rope esc(d.target, att.name.s)
add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
["name", "header", "desc", "itemID", "header_plain", "itemSym",
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"],
[rope(getName(d, nameNode, d.splitAfter)), result, comm,
@@ -569,9 +578,9 @@ proc traceDeps(d: PDoc, it: PNode) =
traceDeps(d, a)
else:
if d.section[k] != nil: add(d.section[k], ", ")
dispA(d.section[k],
dispA(d.conf, d.section[k],
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
"$1", [rope(getModuleName(it))])
"$1", [rope(getModuleName(d.conf, it))])
proc generateDoc*(d: PDoc, n: PNode) =
case n.kind
@@ -704,10 +713,10 @@ proc genSection(d: PDoc, kind: TSymKind) =
]
if d.section[kind] == nil: return
var title = sectionNames[kind].rope
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
@@ -723,7 +732,7 @@ proc genOutFile(d: PDoc): Rope =
genSection(d, i)
add(toc, d.toc[i])
if toc != nil:
toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
# Extract the title. Non API modules generate an entry in the index table.
@@ -737,13 +746,13 @@ proc genOutFile(d: PDoc): Rope =
let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
elif d.hasToc: "doc.body_toc"
else: "doc.body_no_toc"
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title",
"tableofcontents", "moduledesc", "date", "time", "content"],
[title.rope, toc, d.modDesc, rope(getDateStr()),
rope(getClockStr()), code])
if optCompileOnly notin gGlobalOptions:
if optCompileOnly notin d.conf.globalOptions:
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
[title.rope, toc, d.modDesc, rope(getDateStr()),
@@ -754,60 +763,60 @@ proc genOutFile(d: PDoc): Rope =
result = code
proc generateIndex*(d: PDoc) =
if optGenIndex in gGlobalOptions:
writeIndexFile(d[], splitFile(options.outFile).dir /
if optGenIndex in d.conf.globalOptions:
writeIndexFile(d[], splitFile(d.conf.outFile).dir /
splitFile(d.filename).name & IndexExt)
proc getOutFile2(filename, ext, dir: string): string =
if gWholeProject:
let d = if options.outFile != "": options.outFile else: dir
proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
if optWholeProject in conf.globalOptions:
let d = if conf.outFile != "": conf.outFile else: dir
createDir(d)
result = d / changeFileExt(filename, ext)
else:
result = getOutFile(filename, ext)
result = getOutFile(conf, filename, ext)
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
var content = genOutFile(d)
if optStdout in gGlobalOptions:
if optStdout in d.conf.globalOptions:
writeRope(stdout, content)
else:
writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning)
proc writeOutputJson*(d: PDoc, filename, outExt: string,
useWarning = false) =
let content = %*{"orig": d.filename,
"nimble": getPackageName(d.filename),
"nimble": getPackageName(d.conf, d.filename),
"entries": d.jArray}
if optStdout in gGlobalOptions:
if optStdout in d.conf.globalOptions:
write(stdout, $content)
else:
var f: File
if open(f, getOutFile2(splitFile(filename).name,
if open(f, getOutFile2(d.conf, splitFile(filename).name,
outExt, "jsondocs"), fmWrite):
write(f, $content)
close(f)
else:
discard "fixme: error report"
proc commandDoc*() =
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
proc commandDoc*(conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
var d = newDocumentor(conf.projectFull, conf)
d.hasToc = true
generateDoc(d, ast)
writeOutput(d, gProjectFull, HtmlExt)
writeOutput(d, conf.projectFull, HtmlExt)
generateIndex(d)
proc commandRstAux(filename, outExt: string) =
proc commandRstAux(conf: ConfigRef; filename, outExt: string) =
var filen = addFileExt(filename, "txt")
var d = newDocumentor(filen, options.gConfigVars)
var d = newDocumentor(filen, conf)
d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
status: int; content: string) =
var outp: string
if filename.len == 0:
inc(d.id)
let nameOnly = splitFile(d.filename).name
let subdir = getNimcacheDir() / nameOnly
let subdir = getNimcacheDir(conf) / nameOnly
createDir(subdir)
outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim")
elif isAbsolute(filename):
@@ -817,13 +826,13 @@ proc commandRstAux(filename, outExt: string) =
outp = splitFile(d.filename).dir / filename
writeFile(outp, content)
let cmd = cmd % quoteShell(outp)
rawMessage(hintExecuting, cmd)
rawMessage(conf, hintExecuting, cmd)
if execShellCmd(cmd) != status:
rawMessage(errExecutionOfProgramFailed, cmd)
rawMessage(conf, errGenerated, "executing of external program failed: " & cmd)
d.isPureRst = true
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
{roSupportRawDirective})
{roSupportRawDirective}, conf)
var modDesc = newStringOfCap(30_000)
#d.modDesc = newMutableRope(30_000)
renderRstToOut(d[], rst, modDesc)
@@ -832,50 +841,50 @@ proc commandRstAux(filename, outExt: string) =
writeOutput(d, filename, outExt)
generateIndex(d)
proc commandRst2Html*() =
commandRstAux(gProjectFull, HtmlExt)
proc commandRst2Html*(conf: ConfigRef) =
commandRstAux(conf, conf.projectFull, HtmlExt)
proc commandRst2TeX*() =
proc commandRst2TeX*(conf: ConfigRef) =
splitter = "\\-"
commandRstAux(gProjectFull, TexExt)
commandRstAux(conf, conf.projectFull, TexExt)
proc commandJson*() =
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
proc commandJson*(conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
var d = newDocumentor(conf.projectFull, conf)
d.hasToc = true
generateJson(d, ast)
let json = d.jArray
let content = rope(pretty(json))
if optStdout in gGlobalOptions:
if optStdout in d.conf.globalOptions:
writeRope(stdout, content)
else:
#echo getOutFile(gProjectFull, JsonExt)
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
writeRope(content, getOutFile(conf, conf.projectFull, JsonExt), useWarning = false)
proc commandTags*() =
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
proc commandTags*(conf: ConfigRef) =
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
var d = newDocumentor(conf.projectFull, conf)
d.hasToc = true
var
content: Rope
generateTags(d, ast, content)
if optStdout in gGlobalOptions:
if optStdout in d.conf.globalOptions:
writeRope(stdout, content)
else:
#echo getOutFile(gProjectFull, TagsExt)
writeRope(content, getOutFile(gProjectFull, TagsExt), useWarning = false)
writeRope(content, getOutFile(conf, conf.projectFull, TagsExt), useWarning = false)
proc commandBuildIndex*() =
var content = mergeIndexes(gProjectFull).rope
proc commandBuildIndex*(conf: ConfigRef) =
var content = mergeIndexes(conf.projectFull).rope
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title",
"tableofcontents", "moduledesc", "date", "time",
"content", "author", "version", "analytics"],
["Index".rope, nil, nil, rope(getDateStr()),
rope(getClockStr()), content, nil, nil, nil])
# no analytics because context is not available
writeRope(code, getOutFile("theindex", HtmlExt))
writeRope(code, getOutFile(conf, "theindex", HtmlExt))

View File

@@ -25,8 +25,8 @@ template closeImpl(body: untyped) {.dirty.} =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
#echo g.module.name.s, " ", g.module.owner.id, " ", gMainPackageId
if (g.module.owner.id == gMainPackageId and gWholeProject) or
sfMainModule in g.module.flags:
if (g.module.owner.id == gMainPackageId and optWholeProject in g.doc.conf.globalOptions) or
sfMainModule in g.module.flags:
body
try:
generateIndex(g.doc)
@@ -55,7 +55,7 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var g: PGen
new(g)
g.module = module
var d = newDocumentor(module.filename, options.gConfigVars)
var d = newDocumentor(module.filename, graph.config)
d.hasToc = true
g.doc = d
result = g

View File

@@ -14,11 +14,12 @@ import
rodread
type
TemplCtx {.pure, final.} = object
TemplCtx = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
config: ConfigRef
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
@@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
handleParam actual.sons[s.owner.typ.len + s.position - 1]
else:
internalAssert sfGenSym in s.flags or s.kind == skType
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
@@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
const
errWrongNumberOfArguments = "wrong number of arguments"
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
errTemplateInstantiationTooNested = "template instantiation too nested"
proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
var totalParams = case n.kind
@@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
if givenRegularParams < 0: givenRegularParams = 0
if totalParams > expectedRegularParams + genericParams:
globalError(n.info, errWrongNumberOfArguments)
globalError(conf, n.info, errWrongNumberOfArguments)
if totalParams < genericParams:
globalError(n.info, errMissingGenericParamsForTemplate,
globalError(conf, n.info, errMissingGenericParamsForTemplate %
n.renderTree)
result = newNodeI(nkArgList, n.info)
@@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
for i in givenRegularParams+1 .. expectedRegularParams:
let default = s.typ.n.sons[i].sym.ast
if default.isNil or default.kind == nkEmpty:
localError(n.info, errWrongNumberOfArguments)
localError(conf, n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode)
else:
addSon(result, default.copyTree)
@@ -108,7 +114,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
# to prevent endless recursion in template instantiation
const evalTemplateLimit* = 1000
var evalTemplateCounter* = 0
var evalTemplateCounter* = 0 # XXX remove this global
proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
when true:
@@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
result.add res
result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
globalError(n.info, errTemplateInstantiationTooNested)
globalError(conf, n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl, fromHlo)
var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
var ctx: TemplCtx
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner
ctx.config = conf
initIdTable(ctx.mapping)
let body = tmpl.getBody
@@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0]
else:
localError(result.info, errIllFormedAstX,
localError(conf, result.info, "illformed AST: " &
renderTree(result, {renderNoComments}))
else:
result = copyNode(body)

View File

@@ -14,7 +14,7 @@
import
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
std / sha1, streams
configuration, std / sha1, streams
#from debuginfo import writeDebugInfo
@@ -193,9 +193,9 @@ compiler bcc:
pic: "",
asmStmtFrmt: "__asm{$n$1$n}$n",
structStmtFmt: "$1 $2",
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
hasAttribute})
# Digital Mars C Compiler
compiler dmc:
@@ -376,80 +376,81 @@ proc nameToCC*(name: string): TSystemCC =
return i
result = ccNone
proc getConfigVar(c: TSystemCC, suffix: string): string =
proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
# for niminst support
let fullSuffix =
if gCmd == cmdCompileToCpp:
if conf.cmd == cmdCompileToCpp:
".cpp" & suffix
elif gCmd == cmdCompileToOC:
elif conf.cmd == cmdCompileToOC:
".objc" & suffix
elif gCmd == cmdCompileToJS:
elif conf.cmd == cmdCompileToJS:
".js" & suffix
else:
suffix
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
optCompileOnly notin gGlobalOptions:
optCompileOnly notin conf.globalOptions:
let fullCCname = platform.CPU[targetCPU].name & '.' &
platform.OS[targetOS].name & '.' &
CC[c].name & fullSuffix
result = getConfigVar(fullCCname)
result = getConfigVar(conf, fullCCname)
if result.len == 0:
# not overriden for this cross compilation setting?
result = getConfigVar(CC[c].name & fullSuffix)
result = getConfigVar(conf, CC[c].name & fullSuffix)
else:
result = getConfigVar(CC[c].name & fullSuffix)
result = getConfigVar(conf, CC[c].name & fullSuffix)
proc setCC*(ccname: string) =
proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
cCompiler = nameToCC(ccname)
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
compileOptions = getConfigVar(cCompiler, ".options.always")
if cCompiler == ccNone:
localError(conf, info, "unknown C compiler: '$1'" % ccname)
compileOptions = getConfigVar(conf, cCompiler, ".options.always")
linkOptions = ""
ccompilerpath = getConfigVar(cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[cCompiler].name)
proc addOpt(dest: var string, src: string) =
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
add(dest, src)
proc addLinkOption*(option: string) =
proc addLinkOption*(conf: ConfigRef; option: string) =
addOpt(linkOptions, option)
proc addCompileOption*(option: string) =
proc addCompileOption*(conf: ConfigRef; option: string) =
if strutils.find(compileOptions, option, 0) < 0:
addOpt(compileOptions, option)
proc addLinkOptionCmd*(option: string) =
proc addLinkOptionCmd*(conf: ConfigRef; option: string) =
addOpt(linkOptionsCmd, option)
proc addCompileOptionCmd*(option: string) =
proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
compileOptionsCmd.add(option)
proc initVars*() =
proc initVars*(conf: ConfigRef) =
# we need to define the symbol here, because ``CC`` may have never been set!
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
defineSymbol(CC[cCompiler].name)
addCompileOption(getConfigVar(cCompiler, ".options.always"))
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
defineSymbol(conf.symbols, CC[cCompiler].name)
addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always"))
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
if len(ccompilerpath) == 0:
ccompilerpath = getConfigVar(cCompiler, ".path")
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(cfile, createSubDir)
proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
result = completeGeneratedFilePath(conf, cfile, createSubDir)
proc toObjFile*(filename: string): string =
proc toObjFile*(conf: ConfigRef; filename: string): string =
# Object file for compilation
#if filename.endsWith(".cpp"):
# result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
#else:
result = changeFileExt(filename, CC[cCompiler].objExt)
proc addFileToCompile*(cf: Cfile) =
proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
toCompile.add(cf)
proc resetCompilationLists* =
proc resetCompilationLists*(conf: ConfigRef) =
toCompile.setLen 0
## XXX: we must associate these with their originating module
# when the module is loaded/unloaded it adds/removes its items
@@ -457,109 +458,112 @@ proc resetCompilationLists* =
# Maybe we can do that in checkDep on the other hand?
externalToLink.setLen 0
proc addExternalFileToLink*(filename: string) =
proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
externalToLink.insert(filename, 0)
proc execWithEcho(cmd: string, msg = hintExecuting): int =
rawMessage(msg, cmd)
proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
rawMessage(conf, msg, cmd)
result = execCmd(cmd)
proc execExternalProgram*(cmd: string, msg = hintExecuting) =
if execWithEcho(cmd, msg) != 0:
rawMessage(errExecutionOfProgramFailed, cmd)
proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
if execWithEcho(conf, cmd, msg) != 0:
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
cmd)
proc generateScript(projectFile: string, script: Rope) =
proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) =
let (dir, name, ext) = splitFile(projectFile)
writeRope(script, getNimcacheDir() / addFileExt("compile_" & name,
writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name,
platform.OS[targetOS].scriptExt))
copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h")
copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
proc getOptSpeed(c: TSystemCC): string =
result = getConfigVar(c, ".options.speed")
proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
result = getConfigVar(conf, c, ".options.speed")
if result == "":
result = CC[c].optSpeed # use default settings from this file
proc getDebug(c: TSystemCC): string =
result = getConfigVar(c, ".options.debug")
proc getDebug(conf: ConfigRef; c: TSystemCC): string =
result = getConfigVar(conf, c, ".options.debug")
if result == "":
result = CC[c].debug # use default settings from this file
proc getOptSize(c: TSystemCC): string =
result = getConfigVar(c, ".options.size")
proc getOptSize(conf: ConfigRef; c: TSystemCC): string =
result = getConfigVar(conf, c, ".options.size")
if result == "":
result = CC[c].optSize # use default settings from this file
proc noAbsolutePaths: bool {.inline.} =
proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
# We used to check current OS != specified OS, but this makes no sense
# really: Cross compilation from Linux to Linux for example is entirely
# reasonable.
# `optGenMapping` is included here for niminst.
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
result = conf.globalOptions * {optGenScript, optGenMapping} != {}
proc cFileSpecificOptions(cfilename: string): string =
proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
result = compileOptions
for option in compileOptionsCmd:
if strutils.find(result, option, 0) < 0:
addOpt(result, option)
var trunk = splitFile(cfilename).name
if optCDebug in gGlobalOptions:
var key = trunk & ".debug"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getDebug(cCompiler))
if optOptimizeSpeed in gOptions:
var key = trunk & ".speed"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSpeed(cCompiler))
elif optOptimizeSize in gOptions:
var key = trunk & ".size"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
else: addOpt(result, getOptSize(cCompiler))
var key = trunk & ".always"
if existsConfigVar(key): addOpt(result, getConfigVar(key))
let trunk = splitFile(cfilename).name
if optCDebug in conf.globalOptions:
let key = trunk & ".debug"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getDebug(conf, cCompiler))
if optOptimizeSpeed in conf.options:
let key = trunk & ".speed"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getOptSpeed(conf, cCompiler))
elif optOptimizeSize in conf.options:
let key = trunk & ".size"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
else: addOpt(result, getOptSize(conf, cCompiler))
let key = trunk & ".always"
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
proc getCompileOptions: string =
result = cFileSpecificOptions("__dummy__")
proc getCompileOptions(conf: ConfigRef): string =
result = cFileSpecificOptions(conf, "__dummy__")
proc getLinkOptions: string =
proc getLinkOptions(conf: ConfigRef): string =
result = linkOptions & " " & linkOptionsCmd & " "
for linkedLib in items(cLinkedLibs):
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
for libDir in items(cLibs):
result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell]))
proc needsExeExt(): bool {.inline.} =
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
proc needsExeExt(conf: ConfigRef): bool {.inline.} =
result = (optGenScript in conf.globalOptions and targetOS == osWindows) or
(platform.hostOS == osWindows)
proc getCompilerExe(compiler: TSystemCC; cfile: string): string =
result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"):
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string =
result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"):
CC[compiler].cppCompiler
else:
CC[compiler].compilerExe
if result.len == 0:
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
rawMessage(conf, errGenerated,
"Compiler '$1' doesn't support the requested target" %
CC[compiler].name)
proc getLinkerExe(compiler: TSystemCC): string =
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: compiler.getCompilerExe("")
elif gMixedMode and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
else: getCompilerExe(conf, compiler, "")
proc getCompileCFileCmd*(cfile: Cfile): string =
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
var c = cCompiler
var options = cFileSpecificOptions(cfile.cname)
var exe = getConfigVar(c, ".exe")
if exe.len == 0: exe = c.getCompilerExe(cfile.cname)
var options = cFileSpecificOptions(conf, cfile.cname)
var exe = getConfigVar(conf, c, ".exe")
if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
if needsExeExt(): exe = addFileExt(exe, "exe")
if optGenDynLib in gGlobalOptions and
if needsExeExt(conf): exe = addFileExt(exe, "exe")
if optGenDynLib in conf.globalOptions and
ospNeedsPIC in platform.OS[targetOS].props:
add(options, ' ' & CC[c].pic)
var includeCmd, compilePattern: string
if not noAbsolutePaths():
if not noAbsolutePaths(conf):
# compute include paths:
includeCmd = CC[c].includeCmd & quoteShell(libpath)
includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
for includeDir in items(cIncludes):
includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell]))
@@ -567,18 +571,18 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
compilePattern = joinPath(ccompilerpath, exe)
else:
includeCmd = ""
compilePattern = c.getCompilerExe(cfile.cname)
compilePattern = getCompilerExe(conf, c, cfile.cname)
var cf = if noAbsolutePaths(): extractFilename(cfile.cname)
var cf = if noAbsolutePaths(conf): extractFilename(cfile.cname)
else: cfile.cname
var objfile =
if cfile.obj.len == 0:
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths():
toObjFile(cf)
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
toObjFile(conf, cf)
else:
completeCFilePath(toObjFile(cf))
elif noAbsolutePaths():
completeCFilePath(conf, toObjFile(conf, cf))
elif noAbsolutePaths(conf):
extractFilename(cfile.obj)
else:
cfile.obj
@@ -587,30 +591,30 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
cf = quoteShell(cf)
result = quoteShell(compilePattern % [
"file", cf, "objfile", objfile, "options", options,
"include", includeCmd, "nim", getPrefixDir(),
"nim", getPrefixDir(), "lib", libpath])
"include", includeCmd, "nim", getPrefixDir(conf),
"nim", getPrefixDir(conf), "lib", conf.libpath])
add(result, ' ')
addf(result, CC[c].compileTmpl, [
"file", cf, "objfile", objfile,
"options", options, "include", includeCmd,
"nim", quoteShell(getPrefixDir()),
"nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
"nim", quoteShell(getPrefixDir(conf)),
"nim", quoteShell(getPrefixDir(conf)),
"lib", quoteShell(conf.libpath)])
proc footprint(cfile: Cfile): SecureHash =
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
result = secureHash(
$secureHashFile(cfile.cname) &
platform.OS[targetOS].name &
platform.CPU[targetCPU].name &
extccomp.CC[extccomp.cCompiler].name &
getCompileCFileCmd(cfile))
getCompileCFileCmd(conf, cfile))
proc externalFileChanged(cfile: Cfile): bool =
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
return false
var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1")
var currentHash = footprint(cfile)
var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
var currentHash = footprint(conf, cfile)
var f: File
if open(f, hashFile, fmRead):
let oldHash = parseSecureHash(f.readLine())
@@ -623,133 +627,137 @@ proc externalFileChanged(cfile: Cfile): bool =
f.writeLine($currentHash)
close(f)
proc addExternalFileToCompile*(c: var Cfile) =
if optForceFullMake notin gGlobalOptions and not externalFileChanged(c):
proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c):
c.flags.incl CfileFlag.Cached
toCompile.add(c)
proc addExternalFileToCompile*(filename: string) =
proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
var c = Cfile(cname: filename,
obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)),
obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)),
flags: {CfileFlag.External})
addExternalFileToCompile(c)
addExternalFileToCompile(conf, c)
proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq,
proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var TStringSeq,
prettyCmds: var TStringSeq) =
for it in list:
# call the C compiler for the .c file:
if it.flags.contains(CfileFlag.Cached): continue
var compileCmd = getCompileCFileCmd(it)
if optCompileOnly notin gGlobalOptions:
var compileCmd = getCompileCFileCmd(conf, it)
if optCompileOnly notin conf.globalOptions:
add(cmds, compileCmd)
let (_, name, _) = splitFile(it.cname)
add(prettyCmds, "CC: " & name)
if optGenScript in gGlobalOptions:
if optGenScript in conf.globalOptions:
add(script, compileCmd)
add(script, tnl)
proc getLinkCmd(projectfile, objfiles: string): string =
if optGenStaticLib in gGlobalOptions:
proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
if optGenStaticLib in conf.globalOptions:
var libname: string
if options.outFile.len > 0:
libname = options.outFile.expandTilde
if conf.outFile.len > 0:
libname = conf.outFile.expandTilde
if not libname.isAbsolute():
libname = getCurrentDir() / libname
else:
libname = (libNameTmpl() % splitFile(gProjectName).name)
libname = (libNameTmpl() % splitFile(conf.projectName).name)
result = CC[cCompiler].buildLib % ["libfile", libname,
"objfiles", objfiles]
else:
var linkerExe = getConfigVar(cCompiler, ".linkerexe")
if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe
var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe")
if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler)
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(): result = linkerExe
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
if noAbsolutePaths(conf): result = linkerExe
else: result = joinPath(ccompilerpath, linkerExe)
let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
let buildgui = if optGenGuiApp in conf.globalOptions: CC[cCompiler].buildGui
else: ""
var exefile, builddll: string
if optGenDynLib in gGlobalOptions:
if optGenDynLib in conf.globalOptions:
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
builddll = CC[cCompiler].buildDll
else:
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
builddll = ""
if options.outFile.len > 0:
exefile = options.outFile.expandTilde
if conf.outFile.len > 0:
exefile = conf.outFile.expandTilde
if not exefile.isAbsolute():
exefile = getCurrentDir() / exefile
if not noAbsolutePaths():
if not noAbsolutePaths(conf):
if not exefile.isAbsolute():
exefile = joinPath(splitFile(projectfile).dir, exefile)
when false:
if optCDebug in gGlobalOptions:
if optCDebug in conf.globalOptions:
writeDebugInfo(exefile.changeFileExt("ndb"))
exefile = quoteShell(exefile)
let linkOptions = getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")
var linkTmpl = getConfigVar(cCompiler, ".linkTmpl")
let linkOptions = getLinkOptions(conf) & " " &
getConfigVar(conf, cCompiler, ".options.linker")
var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl")
if linkTmpl.len == 0:
linkTmpl = CC[cCompiler].linkTmpl
result = quoteShell(result % ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
"exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath])
result.add ' '
addf(result, linkTmpl, ["builddll", builddll,
"buildgui", buildgui, "options", linkOptions,
"objfiles", objfiles, "exefile", exefile,
"nim", quoteShell(getPrefixDir()),
"lib", quoteShell(libpath)])
"nim", quoteShell(getPrefixDir(conf)),
"lib", quoteShell(conf.libpath)])
template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed =
template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed =
try:
body
except OSError:
let ose = (ref OSError)(getCurrentException())
if errorPrefix.len > 0:
rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
rawMessage(conf, errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
else:
rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode)
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
(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 execLinkCmd(conf: ConfigRef; linkCmd: string) =
tryExceptOSErrorMessage(conf, "invocation of external linker program failed."):
execExternalProgram(conf, linkCmd,
if optListCmd in conf.globalOptions or conf.verbosity > 1: hintExecuting else: hintLinking)
proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) =
proc execCmdsInParallel(conf: ConfigRef; 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 '" &
rawMessage(conf, 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()
if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors()
var res = 0
if gNumberOfProcessors <= 1:
if conf.numberOfProcessors <= 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])
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
res = execWithEcho(conf, cmds[i])
if res != 0:
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
cmds[i])
else:
tryExceptOSErrorMessage("invocation of external compiler program failed."):
if optListCmd in gGlobalOptions or gVerbosity > 1:
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
if optListCmd in conf.globalOptions or conf.verbosity > 1:
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath},
gNumberOfProcessors, afterRunEvent=runCb)
elif gVerbosity == 1:
conf.numberOfProcessors, afterRunEvent=runCb)
elif conf.verbosity == 1:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
conf.numberOfProcessors, prettyCb, afterRunEvent=runCb)
else:
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
gNumberOfProcessors, afterRunEvent=runCb)
conf.numberOfProcessors, afterRunEvent=runCb)
if res != 0:
if gNumberOfProcessors <= 1:
rawMessage(errExecutionOfProgramFailed, cmds.join())
if conf.numberOfProcessors <= 1:
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
cmds.join())
proc callCCompiler*(projectfile: string) =
proc callCCompiler*(conf: ConfigRef; projectfile: string) =
var
linkCmd: string
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
return # speed up that call if only compiling and no script shall be
# generated
#var c = cCompiler
@@ -758,36 +766,36 @@ proc callCCompiler*(projectfile: string) =
var prettyCmds: TStringSeq = @[]
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
compileCFile(toCompile, script, cmds, prettyCmds)
if optCompileOnly notin gGlobalOptions:
execCmdsInParallel(cmds, prettyCb)
if optNoLinking notin gGlobalOptions:
compileCFile(conf, toCompile, script, cmds, prettyCmds)
if optCompileOnly notin conf.globalOptions:
execCmdsInParallel(conf, cmds, prettyCb)
if optNoLinking notin conf.globalOptions:
# call the linker:
var objfiles = ""
for it in externalToLink:
let objFile = if noAbsolutePaths(): it.extractFilename else: it
let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
add(objfiles, ' ')
add(objfiles, quoteShell(
addFileExt(objFile, CC[cCompiler].objExt)))
for x in toCompile:
let objFile = if noAbsolutePaths(): x.obj.extractFilename else: x.obj
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj
add(objfiles, ' ')
add(objfiles, quoteShell(objFile))
linkCmd = getLinkCmd(projectfile, objfiles)
if optCompileOnly notin gGlobalOptions:
execLinkCmd(linkCmd)
linkCmd = getLinkCmd(conf, projectfile, objfiles)
if optCompileOnly notin conf.globalOptions:
execLinkCmd(conf, linkCmd)
else:
linkCmd = ""
if optGenScript in gGlobalOptions:
if optGenScript in conf.globalOptions:
add(script, linkCmd)
add(script, tnl)
generateScript(projectfile, script)
generateScript(conf, projectfile, script)
#from json import escapeJson
import json
proc writeJsonBuildInstructions*(projectfile: string) =
proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
template lit(x: untyped) = f.write x
template str(x: untyped) =
when compiles(escapeJson(x, buf)):
@@ -797,11 +805,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
else:
f.write escapeJson(x)
proc cfiles(f: File; buf: var string; clist: CfileList, isExternal: bool) =
proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) =
var pastStart = false
for it in clist:
if CfileFlag.Cached in it.flags: continue
let compileCmd = getCompileCFileCmd(it)
let compileCmd = getCompileCFileCmd(conf, it)
if pastStart: lit "],\L"
lit "["
str it.cname
@@ -810,11 +818,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
pastStart = true
lit "]\L"
proc linkfiles(f: File; buf, objfiles: var string; clist: CfileList;
proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList;
llist: seq[string]) =
var pastStart = false
for it in llist:
let objfile = if noAbsolutePaths(): it.extractFilename
let objfile = if noAbsolutePaths(conf): it.extractFilename
else: it
let objstr = addFileExt(objfile, CC[cCompiler].objExt)
add(objfiles, ' ')
@@ -835,25 +843,25 @@ proc writeJsonBuildInstructions*(projectfile: string) =
var buf = newStringOfCap(50)
let file = projectfile.splitFile.name
let jsonFile = toGeneratedFile(file, "json")
let jsonFile = toGeneratedFile(conf, file, "json")
var f: File
if open(f, jsonFile, fmWrite):
lit "{\"compile\":[\L"
cfiles(f, buf, toCompile, false)
cfiles(conf, f, buf, toCompile, false)
lit "],\L\"link\":[\L"
var objfiles = ""
# XXX add every file here that is to link
linkfiles(f, buf, objfiles, toCompile, externalToLink)
linkfiles(conf, f, buf, objfiles, toCompile, externalToLink)
lit "],\L\"linkcmd\": "
str getLinkCmd(projectfile, objfiles)
str getLinkCmd(conf, projectfile, objfiles)
lit "\L}\L"
close(f)
proc runJsonBuildInstructions*(projectfile: string) =
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
let file = projectfile.splitFile.name
let jsonFile = toGeneratedFile(file, "json")
let jsonFile = toGeneratedFile(conf, file, "json")
try:
let data = json.parseFile(jsonFile)
let toCompile = data["compile"]
@@ -870,32 +878,32 @@ proc runJsonBuildInstructions*(projectfile: string) =
let prettyCb = proc (idx: int) =
echo prettyCmds[idx]
execCmdsInParallel(cmds, prettyCb)
execCmdsInParallel(conf, cmds, prettyCb)
let linkCmd = data["linkcmd"]
doAssert linkCmd.kind == JString
execLinkCmd(linkCmd.getStr)
execLinkCmd(conf, linkCmd.getStr)
except:
echo getCurrentException().getStackTrace()
quit "error evaluating JSON file: " & jsonFile
proc genMappingFiles(list: CFileList): Rope =
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
for it in list:
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
proc writeMapping*(gSymbolMapping: Rope) =
if optGenMapping notin gGlobalOptions: return
proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
if optGenMapping notin conf.globalOptions: return
var code = rope("[C_Files]\n")
add(code, genMappingFiles(toCompile))
add(code, genMappingFiles(conf, toCompile))
add(code, "\n[C_Compiler]\nFlags=")
add(code, strutils.escape(getCompileOptions()))
add(code, strutils.escape(getCompileOptions(conf)))
add(code, "\n[Linker]\nFlags=")
add(code, strutils.escape(getLinkOptions() & " " &
getConfigVar(cCompiler, ".options.linker")))
add(code, strutils.escape(getLinkOptions(conf) & " " &
getConfigVar(conf, cCompiler, ".options.linker")))
add(code, "\n[Environment]\nlibpath=")
add(code, strutils.escape(libpath))
add(code, strutils.escape(conf.libpath))
addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
addf(code, "\n[Symbols]$n$1", [symbolMapping])
writeRope(code, joinPath(conf.projectPath, "mapping.txt"))

View File

@@ -27,7 +27,7 @@ type
emit, conc, toStr: string
curly, bracket, par: int
pendingExprLine: bool
config: ConfigRef
const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
@@ -70,9 +70,9 @@ proc parseLine(p: var TTmplParser) =
while j <= hi and p.x[j] == ' ': inc(j)
if p.x[0] == p.nimDirective and p.x[1] == '?':
if p.x.len >= 2 and p.x[0] == p.nimDirective and p.x[1] == '?':
newLine(p)
elif p.x[j] == p.nimDirective:
elif j < p.x.len and p.x[j] == p.nimDirective:
newLine(p)
inc(j)
while j <= hi and p.x[j] == ' ': inc(j)
@@ -90,7 +90,7 @@ proc parseLine(p: var TTmplParser) =
dec(p.indent, 2)
else:
p.info.col = int16(j)
localError(p.info, errXNotAllowedHere, "end")
localError(p.config, p.info, "'end' does not close a control flow construct")
llStreamWrite(p.outp, spaces(p.indent))
llStreamWrite(p.outp, "#end")
of "if", "when", "try", "while", "for", "block", "case", "proc", "iterator",
@@ -175,7 +175,7 @@ proc parseLine(p: var TTmplParser) =
llStreamWrite(p.outp, p.x[j])
inc(j)
if curly > 0:
localError(p.info, errXExpected, "}")
localError(p.config, p.info, "expected closing '}'")
break
llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc)
@@ -197,22 +197,23 @@ proc parseLine(p: var TTmplParser) =
inc(j)
else:
p.info.col = int16(j)
localError(p.info, errInvalidExpression, "$")
localError(p.config, p.info, "invalid expression")
else:
llStreamWrite(p.outp, p.x[j])
inc(j)
llStreamWrite(p.outp, "\\n\"")
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode; conf: ConfigRef): PLLStream =
var p: TTmplParser
p.info = newLineInfo(filename, 0, 0)
p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("")
p.inp = stdin
p.subsChar = charArg(call, "subschar", 1, '$')
p.nimDirective = charArg(call, "metachar", 2, '#')
p.emit = strArg(call, "emit", 3, "result.add")
p.conc = strArg(call, "conc", 4, " & ")
p.toStr = strArg(call, "tostring", 5, "$")
p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120)
# do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x):

View File

@@ -13,43 +13,44 @@ import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer
proc invalidPragma(n: PNode) =
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments}))
proc invalidPragma(conf: ConfigRef; n: PNode) =
localError(conf, n.info,
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
proc getArg(n: PNode, name: string, pos: int): PNode =
proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
result = nil
if n.kind in {nkEmpty..nkNilLit}: return
for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n)
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
return n.sons[i].sons[1]
elif i == pos:
return n.sons[i]
proc charArg*(n: PNode, name: string, pos: int, default: char): char =
var x = getArg(n, name, pos)
proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal))
else: invalidPragma(n)
else: invalidPragma(conf, n)
proc strArg*(n: PNode, name: string, pos: int, default: string): string =
var x = getArg(n, name, pos)
proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else: invalidPragma(n)
else: invalidPragma(conf, n)
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(n, name, pos)
proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(conf, n, name, pos)
if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else: invalidPragma(n)
else: invalidPragma(conf, n)
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(call, "startswith", 1, "")
var leading = boolArg(call, "leading", 2, true)
var trailing = boolArg(call, "trailing", 3, true)
proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(conf, call, "startswith", 1, "")
var leading = boolArg(conf, call, "leading", 2, true)
var trailing = boolArg(conf, call, "trailing", 3, true)
result = llStreamOpen("")
var line = newStringOfCap(80)
while llStreamReadLine(stdin, line):
@@ -60,10 +61,10 @@ proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
llStreamWriteln(result, line)
llStreamClose(stdin)
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(call, "sub", 1, "")
if len(sub) == 0: invalidPragma(call)
var by = strArg(call, "by", 2, "")
proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(conf, call, "sub", 1, "")
if len(sub) == 0: invalidPragma(conf, call)
var by = strArg(conf, call, "by", 2, "")
result = llStreamOpen("")
var line = newStringOfCap(80)
while llStreamReadLine(stdin, line):

View File

@@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) =
result[0].setLen(result[0].len - "\n".len)
result[1] = p.waitForExit
proc opGorge*(cmd, input, cache: string, info: TLineInfo): (string, int) =
proc opGorge*(cmd, input, cache: string, info: TLineInfo; conf: ConfigRef): (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")
let filename = options.toGeneratedFile(conf, "gorge_" & $h, "txt")
var f: File
if open(f, filename):
result = (f.readAll, 0)

View File

@@ -10,7 +10,7 @@
## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
saturate
saturate, modulegraphs, options, configuration
const
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@@ -83,18 +83,25 @@ proc isLetLocation(m: PNode, isApprox: bool): bool =
proc interestingCaseExpr*(m: PNode): bool = isLetLocation(m, true)
let
opLe = createMagic("<=", mLeI)
opLt = createMagic("<", mLtI)
opAnd = createMagic("and", mAnd)
opOr = createMagic("or", mOr)
opIsNil = createMagic("isnil", mIsNil)
opEq = createMagic("==", mEqI)
opAdd = createMagic("+", mAddI)
opSub = createMagic("-", mSubI)
opMul = createMagic("*", mMulI)
opDiv = createMagic("div", mDivI)
opLen = createMagic("len", mLengthSeq)
type
Operators* = object
opNot, opContains, opLe, opLt, opAnd, opOr, opIsNil, opEq: PSym
opAdd, opSub, opMul, opDiv, opLen: PSym
proc initOperators*(g: ModuleGraph): Operators =
result.opLe = createMagic(g, "<=", mLeI)
result.opLt = createMagic(g, "<", mLtI)
result.opAnd = createMagic(g, "and", mAnd)
result.opOr = createMagic(g, "or", mOr)
result.opIsNil = createMagic(g, "isnil", mIsNil)
result.opEq = createMagic(g, "==", mEqI)
result.opAdd = createMagic(g, "+", mAddI)
result.opSub = createMagic(g, "-", mSubI)
result.opMul = createMagic(g, "*", mMulI)
result.opDiv = createMagic(g, "div", mDivI)
result.opLen = createMagic(g, "len", mLengthSeq)
result.opNot = createMagic(g, "not", mNot)
result.opContains = createMagic(g, "contains", mInSet)
proc swapArgs(fact: PNode, newOp: PSym): PNode =
result = newNodeI(nkCall, fact.info, 3)
@@ -102,16 +109,16 @@ proc swapArgs(fact: PNode, newOp: PSym): PNode =
result.sons[1] = fact.sons[2]
result.sons[2] = fact.sons[1]
proc neg(n: PNode): PNode =
proc neg(n: PNode; o: Operators): PNode =
if n == nil: return nil
case n.getMagic
of mNot:
result = n.sons[1]
of someLt:
# not (a < b) == a >= b == b <= a
result = swapArgs(n, opLe)
result = swapArgs(n, o.opLe)
of someLe:
result = swapArgs(n, opLt)
result = swapArgs(n, o.opLt)
of mInSet:
if n.sons[1].kind != nkCurly: return nil
let t = n.sons[2].typ.skipTypes(abstractInst)
@@ -133,11 +140,11 @@ proc neg(n: PNode): PNode =
of mOr:
# not (a or b) --> not a and not b
let
a = n.sons[1].neg
b = n.sons[2].neg
a = n.sons[1].neg(o)
b = n.sons[2].neg(o)
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
@@ -147,7 +154,7 @@ proc neg(n: PNode): PNode =
else:
# leave not (a == 4) as it is
result = newNodeI(nkCall, n.info, 2)
result.sons[0] = newSymNode(opNot)
result.sons[0] = newSymNode(o.opNot)
result.sons[1] = n
proc buildCall(op: PSym; a: PNode): PNode =
@@ -181,7 +188,7 @@ proc `|div|`(a, b: PNode): PNode =
if a.kind in {nkCharLit..nkUInt64Lit}: result.intVal = a.intVal div b.intVal
else: result.floatVal = a.floatVal / b.floatVal
proc negate(a, b, res: PNode): PNode =
proc negate(a, b, res: PNode; o: Operators): PNode =
if b.kind in {nkCharLit..nkUInt64Lit} and b.intVal != low(BiggestInt):
var b = copyNode(b)
b.intVal = -b.intVal
@@ -189,11 +196,11 @@ proc negate(a, b, res: PNode): PNode =
b.intVal = b.intVal |+| a.intVal
result = b
else:
result = buildCall(opAdd, a, b)
result = buildCall(o.opAdd, a, b)
elif b.kind in {nkFloatLit..nkFloat64Lit}:
var b = copyNode(b)
b.floatVal = -b.floatVal
result = buildCall(opAdd, a, b)
result = buildCall(o.opAdd, a, b)
else:
result = res
@@ -205,7 +212,7 @@ proc lowBound*(x: PNode): PNode =
result = nkIntLit.newIntNode(firstOrd(x.typ))
result.info = x.info
proc highBound*(x: PNode): PNode =
proc highBound*(x: PNode; o: Operators): PNode =
let typ = x.typ.skipTypes(abstractInst)
result = if typ.kind == tyArray:
nkIntLit.newIntNode(lastOrd(typ))
@@ -213,23 +220,23 @@ proc highBound*(x: PNode): PNode =
x.sym.kind == skConst:
nkIntLit.newIntNode(x.sym.ast.len-1)
else:
opAdd.buildCall(opLen.buildCall(x), minusOne())
o.opAdd.buildCall(o.opLen.buildCall(x), minusOne())
result.info = x.info
proc reassociation(n: PNode): PNode =
proc reassociation(n: PNode; o: Operators): PNode =
result = n
# (foo+5)+5 --> foo+10; same for '*'
case result.getMagic
of someAdd:
if result[2].isValue and
result[1].getMagic in someAdd and result[1][2].isValue:
result = opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
result = o.opAdd.buildCall(result[1][1], result[1][2] |+| result[2])
if result[2].intVal == 0:
result = result[1]
of someMul:
if result[2].isValue and
result[1].getMagic in someMul and result[1][2].isValue:
result = opMul.buildCall(result[1][1], result[1][2] |*| result[2])
result = o.opMul.buildCall(result[1][1], result[1][2] |*| result[2])
if result[2].intVal == 1:
result = result[1]
elif result[2].intVal == 0:
@@ -243,12 +250,12 @@ proc pred(n: PNode): PNode =
else:
result = n
proc canon*(n: PNode): PNode =
proc canon*(n: PNode; o: Operators): PNode =
# XXX for now only the new code in 'semparallel' uses this
if n.safeLen >= 1:
result = shallowCopy(n)
for i in 0 ..< n.len:
result.sons[i] = canon(n.sons[i])
result.sons[i] = canon(n.sons[i], o)
elif n.kind == nkSym and n.sym.kind == skLet and
n.sym.ast.getMagic in (someEq + someAdd + someMul + someMin +
someMax + someHigh + {mUnaryLt} + someSub + someLen + someDiv):
@@ -263,24 +270,24 @@ proc canon*(n: PNode): PNode =
# (4 + foo) + 2 --> (foo + 4) + 2
of someHigh:
# high == len+(-1)
result = opAdd.buildCall(opLen.buildCall(result[1]), minusOne())
result = o.opAdd.buildCall(o.opLen.buildCall(result[1]), minusOne())
of mUnaryLt:
result = buildCall(opAdd, result[1], minusOne())
result = buildCall(o.opAdd, result[1], minusOne())
of someSub:
# x - 4 --> x + (-4)
result = negate(result[1], result[2], result)
result = negate(result[1], result[2], result, o)
of someLen:
result.sons[0] = opLen.newSymNode
result.sons[0] = o.opLen.newSymNode
of someLt:
# x < y same as x <= y-1:
let y = n[2].canon
let y = n[2].canon(o)
let p = pred(y)
let minus = if p != y: p else: opAdd.buildCall(y, minusOne()).canon
result = opLe.buildCall(n[1].canon, minus)
let minus = if p != y: p else: o.opAdd.buildCall(y, minusOne()).canon(o)
result = o.opLe.buildCall(n[1].canon(o), minus)
else: discard
result = skipConv(result)
result = reassociation(result)
result = reassociation(result, o)
# most important rule: (x-4) <= a.len --> x <= a.len+4
case result.getMagic
of someLe:
@@ -291,10 +298,10 @@ proc canon*(n: PNode): PNode =
case x.getMagic
of someSub:
result = buildCall(result[0].sym, x[1],
reassociation(opAdd.buildCall(y, x[2])))
reassociation(o.opAdd.buildCall(y, x[2]), o))
of someAdd:
# Rule A:
let plus = negate(y, x[2], nil).reassociation
let plus = negate(y, x[2], nil, o).reassociation(o)
if plus != nil: result = buildCall(result[0].sym, x[1], plus)
else: discard
elif y.kind in nkCallKinds and y.len == 3 and y[2].isValue and
@@ -303,9 +310,9 @@ proc canon*(n: PNode): PNode =
case y.getMagic
of someSub:
result = buildCall(result[0].sym, y[1],
reassociation(opAdd.buildCall(x, y[2])))
reassociation(o.opAdd.buildCall(x, y[2]), o))
of someAdd:
let plus = negate(x, y[2], nil).reassociation
let plus = negate(x, y[2], nil, o).reassociation(o)
# ensure that Rule A will not trigger afterwards with the
# additional 'not isLetLocation' constraint:
if plus != nil and not isLetLocation(x, true):
@@ -323,15 +330,15 @@ proc canon*(n: PNode): PNode =
result.sons[2] = y[1]
else: discard
proc `+@`*(a: PNode; b: BiggestInt): PNode =
canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a)
proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o)
proc usefulFact(n: PNode): PNode =
proc usefulFact(n: PNode; o: Operators): PNode =
case n.getMagic
of someEq:
if skipConv(n.sons[2]).kind == nkNilLit and (
isLetLocation(n.sons[1], false) or isVar(n.sons[1])):
result = opIsNil.buildCall(n.sons[1])
result = o.opIsNil.buildCall(n.sons[1])
else:
if isLetLocation(n.sons[1], true) or isLetLocation(n.sons[2], true):
# XXX algebraic simplifications! 'i-1 < a.len' --> 'i < a.len+1'
@@ -351,11 +358,11 @@ proc usefulFact(n: PNode): PNode =
result = n
of mAnd:
let
a = usefulFact(n.sons[1])
b = usefulFact(n.sons[2])
a = usefulFact(n.sons[1], o)
b = usefulFact(n.sons[2], o)
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a
result.sons[2] = b
elif a != nil:
@@ -363,9 +370,9 @@ proc usefulFact(n: PNode): PNode =
elif b != nil:
result = b
of mNot:
let a = usefulFact(n.sons[1])
let a = usefulFact(n.sons[1], o)
if a != nil:
result = a.neg
result = a.neg(o)
of mOr:
# 'or' sucks! (p.isNil or q.isNil) --> hard to do anything
# with that knowledge...
@@ -374,14 +381,14 @@ proc usefulFact(n: PNode): PNode =
# (x == 3) or (y == 2) ---> not ( not (x==3) and not (y == 2))
# not (x != 3 and y != 2)
let
a = usefulFact(n.sons[1]).neg
b = usefulFact(n.sons[2]).neg
a = usefulFact(n.sons[1], o).neg(o)
b = usefulFact(n.sons[2], o).neg(o)
if a != nil and b != nil:
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opAnd)
result.sons[0] = newSymNode(o.opAnd)
result.sons[1] = a
result.sons[2] = b
result = result.neg
result = result.neg(o)
elif n.kind == nkSym and n.sym.kind == skLet:
# consider:
# let a = 2 < x
@@ -389,32 +396,34 @@ proc usefulFact(n: PNode): PNode =
# ...
# We make can easily replace 'a' by '2 < x' here:
if n.sym.ast != nil:
result = usefulFact(n.sym.ast)
result = usefulFact(n.sym.ast, o)
elif n.kind == nkStmtListExpr:
result = usefulFact(n.lastSon)
result = usefulFact(n.lastSon, o)
type
TModel* = seq[PNode] # the "knowledge base"
TModel* = object
s*: seq[PNode] # the "knowledge base"
o*: Operators
proc addFact*(m: var TModel, nn: PNode) =
let n = usefulFact(nn)
if n != nil: m.add n
let n = usefulFact(nn, m.o)
if n != nil: m.s.add n
proc addFactNeg*(m: var TModel, n: PNode) =
let n = n.neg
let n = n.neg(m.o)
if n != nil: addFact(m, n)
proc canonOpr(opr: PSym): PSym =
case opr.magic
of someEq: result = opEq
of someLe: result = opLe
of someLt: result = opLt
of someLen: result = opLen
of someAdd: result = opAdd
of someSub: result = opSub
of someMul: result = opMul
of someDiv: result = opDiv
else: result = opr
proc sameOpr(a, b: PSym): bool =
case a.magic
of someEq: result = b.magic in someEq
of someLe: result = b.magic in someLe
of someLt: result = b.magic in someLt
of someLen: result = b.magic in someLen
of someAdd: result = b.magic in someAdd
of someSub: result = b.magic in someSub
of someMul: result = b.magic in someMul
of someDiv: result = b.magic in someDiv
else: result = a == b
proc sameTree*(a, b: PNode): bool =
result = false
@@ -425,7 +434,7 @@ proc sameTree*(a, b: PNode): bool =
of nkSym:
result = a.sym == b.sym
if not result and a.sym.magic != mNone:
result = a.sym.magic == b.sym.magic or canonOpr(a.sym) == canonOpr(b.sym)
result = a.sym.magic == b.sym.magic or sameOpr(a.sym, b.sym)
of nkIdent: result = a.ident.id == b.ident.id
of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal
of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal
@@ -462,8 +471,8 @@ proc invalidateFacts*(m: var TModel, n: PNode) =
# The same mechanism could be used for more complex data stored on the heap;
# procs that 'write: []' cannot invalidate 'n.kind' for instance. In fact, we
# could CSE these expressions then and help C's optimizer.
for i in 0..high(m):
if m[i] != nil and m[i].hasSubTree(n): m[i] = nil
for i in 0..high(m.s):
if m.s[i] != nil and m.s[i].hasSubTree(n): m.s[i] = nil
proc valuesUnequal(a, b: PNode): bool =
if a.isValue and b.isValue:
@@ -486,7 +495,7 @@ proc impliesEq(fact, eq: PNode): TImplication =
if sameTree(fact.sons[2], eq.sons[loc]) and isValue(eq.sons[val]):
if inSet(fact.sons[1], eq.sons[val]): result = impYes
else: result = impNo
of mNot, mOr, mAnd: internalError(eq.info, "impliesEq")
of mNot, mOr, mAnd: assert(false, "impliesEq")
else: discard
proc leImpliesIn(x, c, aSet: PNode): TImplication =
@@ -549,7 +558,7 @@ proc impliesIn(fact, loc, aSet: PNode): TImplication =
elif sameTree(fact.sons[2], loc):
# 4 < x --> 3 <= x
result = geImpliesIn(fact.sons[2], fact.sons[1].pred, aSet)
of mNot, mOr, mAnd: internalError(loc.info, "impliesIn")
of mNot, mOr, mAnd: assert(false, "impliesIn")
else: discard
proc valueIsNil(n: PNode): TImplication =
@@ -567,11 +576,11 @@ proc impliesIsNil(fact, eq: PNode): TImplication =
result = valueIsNil(fact.sons[2].skipConv)
elif sameTree(fact.sons[2], eq.sons[1]):
result = valueIsNil(fact.sons[1].skipConv)
of mNot, mOr, mAnd: internalError(eq.info, "impliesIsNil")
of mNot, mOr, mAnd: assert(false, "impliesIsNil")
else: discard
proc impliesGe(fact, x, c: PNode): TImplication =
internalAssert isLocation(x)
assert isLocation(x)
case fact.sons[0].sym.magic
of someEq:
if sameTree(fact.sons[1], x):
@@ -603,7 +612,7 @@ proc impliesGe(fact, x, c: PNode): TImplication =
# fact: 3 <= x; question: x >= 2 ? --> true iff 2 <= 3
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1]): result = impYes
of mNot, mOr, mAnd: internalError(x.info, "impliesGe")
of mNot, mOr, mAnd: assert(false, "impliesGe")
else: discard
proc impliesLe(fact, x, c: PNode): TImplication =
@@ -643,7 +652,7 @@ proc impliesLe(fact, x, c: PNode): TImplication =
if isValue(fact.sons[1]) and isValue(c):
if leValue(c, fact.sons[1].pred): result = impNo
of mNot, mOr, mAnd: internalError(x.info, "impliesLe")
of mNot, mOr, mAnd: assert(false, "impliesLe")
else: discard
proc impliesLt(fact, x, c: PNode): TImplication =
@@ -707,14 +716,14 @@ proc factImplies(fact, prop: PNode): TImplication =
proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds
for f in facts:
for f in facts.s:
# facts can be invalidated, in which case they are 'nil':
if not f.isNil:
result = f.factImplies(prop)
if result != impUnknown: return
proc impliesNotNil*(facts: TModel, arg: PNode): TImplication =
result = doesImply(facts, opIsNil.buildCall(arg).neg)
proc impliesNotNil*(m: TModel, arg: PNode): TImplication =
result = doesImply(m, m.o.opIsNil.buildCall(arg).neg(m.o))
proc simpleSlice*(a, b: PNode): BiggestInt =
# returns 'c' if a..b matches (i+c)..(i+c), -1 otherwise. (i)..(i) is matched
@@ -817,20 +826,20 @@ proc ple(m: TModel; a, b: PNode): TImplication =
if a.getMagic in someMul and a[2].isValue and a[1].getMagic in someDiv and
a[1][2].isValue:
# simplify (x div 4) * 2 <= y to x div (c div d) <= y
if ple(m, buildCall(opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
if ple(m, buildCall(m.o.opDiv, a[1][1], `|div|`(a[1][2], a[2])), b) == impYes:
return impYes
# x*3 + x == x*4. It follows that:
# x*3 + y <= x*4 if y <= x and 3 <= 4
if a =~ x*dc + y and b =~ x2*ec:
if sameTree(x, x2):
let ec1 = opAdd.buildCall(ec, minusOne())
let ec1 = m.o.opAdd.buildCall(ec, minusOne())
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? x:
return impYes
elif a =~ x*dc and b =~ x2*ec + y:
#echo "BUG cam ehrer e ", a, " <=? ", b
if sameTree(x, x2):
let ec1 = opAdd.buildCall(ec, minusOne())
let ec1 = m.o.opAdd.buildCall(ec, minusOne())
if x >=? 1 and ec >=? 1 and dc >=? 1 and dc <=? ec1 and y <=? zero():
return impYes
@@ -863,9 +872,9 @@ proc ple(m: TModel; a, b: PNode): TImplication =
# use the knowledge base:
return pleViaModel(m, a, b)
#return doesImply(m, opLe.buildCall(a, b))
#return doesImply(m, o.opLe.buildCall(a, b))
type TReplacements = seq[tuple[a,b: PNode]]
type TReplacements = seq[tuple[a, b: PNode]]
proc replaceSubTree(n, x, by: PNode): PNode =
if sameTree(n, x):
@@ -883,11 +892,11 @@ proc applyReplacements(n: PNode; rep: TReplacements): PNode =
proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
# now check for inferrable facts: a <= b and b <= c implies a <= c
for i in 0..m.high:
let fact = m[i]
for i in 0..m.s.high:
let fact = m.s[i]
if fact != nil and fact.getMagic in someLe:
# mark as used:
m[i] = nil
m.s[i] = nil
# i <= len-100
# i <=? len-1
# --> true if (len-100) <= (len-1)
@@ -919,7 +928,7 @@ proc pleViaModelRec(m: var TModel; a, b: PNode): TImplication =
proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
# compute replacements:
var replacements: TReplacements = @[]
for fact in model:
for fact in model.s:
if fact != nil and fact.getMagic in someEq:
let a = fact[1]
let b = fact[2]
@@ -929,12 +938,13 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
var a = aa
var b = bb
if replacements.len > 0:
m = @[]
m.s = @[]
m.o = model.o
# make the other facts consistent:
for fact in model:
for fact in model.s:
if fact != nil and fact.getMagic notin someEq:
# XXX 'canon' should not be necessary here, but it is
m.add applyReplacements(fact, replacements).canon
m.s.add applyReplacements(fact, replacements).canon(m.o)
a = applyReplacements(aa, replacements)
b = applyReplacements(bb, replacements)
else:
@@ -943,31 +953,31 @@ proc pleViaModel(model: TModel; aa, bb: PNode): TImplication =
result = pleViaModelRec(m, a, b)
proc proveLe*(m: TModel; a, b: PNode): TImplication =
let x = canon(opLe.buildCall(a, b))
let x = canon(m.o.opLe.buildCall(a, b), m.o)
#echo "ROOT ", renderTree(x[1]), " <=? ", renderTree(x[2])
result = ple(m, x[1], x[2])
if result == impUnknown:
# try an alternative: a <= b iff not (b < a) iff not (b+1 <= a):
let y = canon(opLe.buildCall(opAdd.buildCall(b, one()), a))
let y = canon(m.o.opLe.buildCall(m.o.opAdd.buildCall(b, one()), a), m.o)
result = ~ple(m, y[1], y[2])
proc addFactLe*(m: var TModel; a, b: PNode) =
m.add canon(opLe.buildCall(a, b))
m.s.add canon(m.o.opLe.buildCall(a, b), m.o)
proc settype(n: PNode): PType =
result = newType(tySet, n.typ.owner)
addSonSkipIntLit(result, n.typ)
proc buildOf(it, loc: PNode): PNode =
proc buildOf(it, loc: PNode; o: Operators): PNode =
var s = newNodeI(nkCurly, it.info, it.len-1)
s.typ = settype(loc)
for i in 0..it.len-2: s.sons[i] = it.sons[i]
result = newNodeI(nkCall, it.info, 3)
result.sons[0] = newSymNode(opContains)
result.sons[0] = newSymNode(o.opContains)
result.sons[1] = s
result.sons[2] = loc
proc buildElse(n: PNode): PNode =
proc buildElse(n: PNode; o: Operators): PNode =
var s = newNodeIT(nkCurly, n.info, settype(n.sons[0]))
for i in 1..n.len-2:
let branch = n.sons[i]
@@ -975,23 +985,23 @@ proc buildElse(n: PNode): PNode =
for j in 0..branch.len-2:
s.add(branch.sons[j])
result = newNodeI(nkCall, n.info, 3)
result.sons[0] = newSymNode(opContains)
result.sons[0] = newSymNode(o.opContains)
result.sons[1] = s
result.sons[2] = n.sons[0]
proc addDiscriminantFact*(m: var TModel, n: PNode) =
var fact = newNodeI(nkCall, n.info, 3)
fact.sons[0] = newSymNode(opEq)
fact.sons[0] = newSymNode(m.o.opEq)
fact.sons[1] = n.sons[0]
fact.sons[2] = n.sons[1]
m.add fact
m.s.add fact
proc addAsgnFact*(m: var TModel, key, value: PNode) =
var fact = newNodeI(nkCall, key.info, 3)
fact.sons[0] = newSymNode(opEq)
fact.sons[0] = newSymNode(m.o.opEq)
fact.sons[1] = key
fact.sons[2] = value
m.add fact
m.s.add fact
proc sameSubexprs*(m: TModel; a, b: PNode): bool =
# This should be used to check whether two *path expressions* refer to the
@@ -1004,7 +1014,7 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
# However, nil checking requires exactly the same mechanism! But for now
# we simply use sameTree and live with the unsoundness of the analysis.
var check = newNodeI(nkCall, a.info, 3)
check.sons[0] = newSymNode(opEq)
check.sons[0] = newSymNode(m.o.opEq)
check.sons[1] = a
check.sons[2] = b
result = m.doesImply(check) == impYes
@@ -1012,11 +1022,11 @@ proc sameSubexprs*(m: TModel; a, b: PNode): bool =
proc addCaseBranchFacts*(m: var TModel, n: PNode, i: int) =
let branch = n.sons[i]
if branch.kind == nkOfBranch:
m.add buildOf(branch, n.sons[0])
m.s.add buildOf(branch, n.sons[0], m.o)
else:
m.add n.buildElse.neg
m.s.add n.buildElse(m.o).neg(m.o)
proc buildProperFieldCheck(access, check: PNode): PNode =
proc buildProperFieldCheck(access, check: PNode; o: Operators): PNode =
if check.sons[1].kind == nkCurly:
result = copyTree(check)
if access.kind == nkDotExpr:
@@ -1028,10 +1038,10 @@ proc buildProperFieldCheck(access, check: PNode): PNode =
else:
# it is some 'not'
assert check.getMagic == mNot
result = buildProperFieldCheck(access, check.sons[1]).neg
result = buildProperFieldCheck(access, check.sons[1], o).neg(o)
proc checkFieldAccess*(m: TModel, n: PNode) =
proc checkFieldAccess*(m: TModel, n: PNode; conf: ConfigRef) =
for i in 1..n.len-1:
let check = buildProperFieldCheck(n.sons[0], n.sons[i])
let check = buildProperFieldCheck(n.sons[0], n.sons[i], m.o)
if check != nil and m.doesImply(check) != impYes:
message(n.info, warnProveField, renderTree(n.sons[0])); break
message(conf, n.info, warnProveField, renderTree(n.sons[0])); break

View File

@@ -12,12 +12,12 @@
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.
var rule: string
if optHints in gOptions and hintPattern in gNotes:
if optHints in c.config.options and hintPattern in c.config.notes:
rule = renderTree(n, {renderNoComments})
let s = n.sons[0].sym
case s.kind
@@ -27,8 +27,8 @@ proc evalPattern(c: PContext, n, orig: PNode): PNode =
result = semTemplateExpr(c, n, s, {efFromHlo})
else:
result = semDirectOp(c, n, {})
if optHints in gOptions and hintPattern in gNotes:
message(orig.info, hintPattern, rule & " --> '" &
if optHints in c.config.options and hintPattern in c.config.notes:
message(c.config, orig.info, hintPattern, rule & " --> '" &
renderTree(result, {renderNoComments}) & "'")
proc applyPatterns(c: PContext, n: PNode): PNode =
@@ -45,7 +45,7 @@ proc applyPatterns(c: PContext, n: PNode): PNode =
# better be safe than sorry, so check evalTemplateCounter too:
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
globalError(n.info, errTemplateInstantiationTooNested)
globalError(c.config, n.info, "template instantiation too nested")
# deactivate this pattern:
c.patterns[i] = nil
if x.kind == nkStmtList:
@@ -86,18 +86,18 @@ proc hlo(c: PContext, n: PNode): PNode =
else:
result = fitNode(c, n.typ, result, n.info)
# optimization has been applied so check again:
result = commonOptimizations(c.module, result)
result = commonOptimizations(c.graph, c.module, result)
result = hlo(c, result)
result = commonOptimizations(c.module, result)
result = commonOptimizations(c.graph, c.module, result)
proc hloBody(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
if c.patterns.len == 0 or optPatterns notin c.config.options: return n
c.hloLoopDetector = 0
result = hlo(c, n)
proc hloStmt(c: PContext, n: PNode): PNode =
# fast exit:
if c.patterns.len == 0 or optPatterns notin gOptions: return n
if c.patterns.len == 0 or optPatterns notin c.config.options: return n
c.hloLoopDetector = 0
result = hlo(c, n)

View File

@@ -36,20 +36,20 @@ proc setId*(id: int) {.inline.} =
proc idSynchronizationPoint*(idRange: int) =
gFrontEndId = (gFrontEndId div idRange + 1) * idRange + 1
proc toGid(f: string): string =
proc toGid(conf: ConfigRef; f: string): string =
# we used to use ``f.addFileExt("gid")`` (aka ``$project.gid``), but this
# will cause strange bugs if multiple projects are in the same folder, so
# we simply use a project independent name:
result = options.completeGeneratedFilePath("nim.gid")
result = options.completeGeneratedFilePath(conf, "nim.gid")
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
proc saveMaxIds*(conf: ConfigRef; project: string) =
var f = open(toGid(conf, project), fmWrite)
f.writeLine($gFrontEndId)
f.close()
proc loadMaxIds*(project: string) =
proc loadMaxIds*(conf: ConfigRef; project: string) =
var f: File
if open(f, project.toGid, fmRead):
if open(f, toGid(conf, project), fmRead):
var line = newStringOfCap(20)
if f.readLine(line):
var frontEndId = parseInt(line)

View File

@@ -11,16 +11,16 @@
import
intsets, strutils, os, ast, astalgo, msgs, options, idents, rodread, lookups,
semdata, passes, renderer, modulepaths, sigmatch
semdata, passes, renderer, modulepaths, sigmatch, configuration
proc evalImport*(c: PContext, n: PNode): PNode
proc evalFrom*(c: PContext, n: PNode): PNode
proc readExceptSet*(n: PNode): IntSet =
proc readExceptSet*(c: PContext, n: PNode): IntSet =
assert n.kind in {nkImportExceptStmt, nkExportExceptStmt}
result = initIntSet()
for i in 1 ..< n.len:
let ident = lookups.considerQuotedIdent(n[i])
let ident = lookups.considerQuotedIdent(c.config, n[i])
result.incl(ident.id)
proc importPureEnumField*(c: PContext; s: PSym) =
@@ -47,7 +47,7 @@ proc rawImportSymbol(c: PContext, s: PSym) =
for j in countup(0, sonsLen(etyp.n) - 1):
var e = etyp.n.sons[j].sym
if e.kind != skEnumField:
internalError(s.info, "rawImportSymbol")
internalError(c.config, s.info, "rawImportSymbol")
# BUGFIX: because of aliases for enums the symbol may already
# have been put into the symbol table
# BUGFIX: but only iff they are the same symbols!
@@ -69,14 +69,14 @@ proc rawImportSymbol(c: PContext, s: PSym) =
if hasPattern(s): addPattern(c, s)
proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
let ident = lookups.considerQuotedIdent(n)
let ident = lookups.considerQuotedIdent(c.config, n)
let s = strTableGet(fromMod.tab, ident)
if s == nil:
errorUndeclaredIdentifier(c, n.info, ident.s)
else:
if s.kind == skStub: loadStub(s)
if s.kind notin ExportableSymKinds:
internalError(n.info, "importSymbol: 2")
internalError(c.config, n.info, "importSymbol: 2")
# for an enumeration we have to add all identifiers
case s.kind
of skProcKinds:
@@ -84,7 +84,7 @@ proc importSymbol(c: PContext, n: PNode, fromMod: PSym) =
var it: TIdentIter
var e = initIdentIter(it, fromMod.tab, s.name)
while e != nil:
if e.name.id != s.name.id: internalError(n.info, "importSymbol: 3")
if e.name.id != s.name.id: internalError(c.config, n.info, "importSymbol: 3")
rawImportSymbol(c, e)
e = nextIdentIter(it, fromMod.tab)
else: rawImportSymbol(c, s)
@@ -96,7 +96,7 @@ proc importAllSymbolsExcept(c: PContext, fromMod: PSym, exceptSet: IntSet) =
if s.kind != skModule:
if s.kind != skEnumField:
if s.kind notin ExportableSymKinds:
internalError(s.info, "importAllSymbols: " & $s.kind)
internalError(c.config, s.info, "importAllSymbols: " & $s.kind)
if exceptSet.isNil or s.name.id notin exceptSet:
rawImportSymbol(c, s)
s = nextIter(i, fromMod.tab)
@@ -117,22 +117,23 @@ proc importForwarded(c: PContext, n: PNode, exceptSet: IntSet) =
elif exceptSet.isNil or s.name.id notin exceptSet:
rawImportSymbol(c, s)
of nkExportExceptStmt:
localError(n.info, errGenerated, "'export except' not implemented")
localError(c.config, n.info, "'export except' not implemented")
else:
for i in 0..safeLen(n)-1:
importForwarded(c, n.sons[i], exceptSet)
proc importModuleAs(n: PNode, realModule: PSym): PSym =
proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
result = realModule
if n.kind != nkImportAs: discard
elif n.len != 2 or n.sons[1].kind != nkIdent:
localError(n.info, errGenerated, "module alias must be an identifier")
localError(c.config, n.info, "module alias must be an identifier")
elif n.sons[1].ident.id != realModule.name.id:
# some misguided guy will write 'import abc.foo as foo' ...
result = createModuleAlias(realModule, n.sons[1].ident, realModule.info)
result = createModuleAlias(realModule, n.sons[1].ident, realModule.info,
c.config.options)
proc myImportModule(c: PContext, n: PNode): PSym =
var f = checkModuleName(n)
var f = checkModuleName(c.config, n)
if f != InvalidFileIDX:
let L = c.graph.importStack.len
let recursion = c.graph.importStack.find(f)
@@ -145,7 +146,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
err.add toFullPath(c.graph.importStack[i]) & " imports " &
toFullPath(c.graph.importStack[i+1])
c.recursiveDep = err
result = importModuleAs(n, gImportModule(c.graph, c.module, f, c.cache))
result = importModuleAs(c, n, gImportModule(c.graph, c.module, f, c.cache))
#echo "set back to ", L
c.graph.importStack.setLen(L)
# we cannot perform this check reliably because of
@@ -153,13 +154,13 @@ proc myImportModule(c: PContext, n: PNode): PSym =
when true:
if result.info.fileIndex == c.module.info.fileIndex and
result.info.fileIndex == n.info.fileIndex:
localError(n.info, errGenerated, "A module cannot import itself")
localError(c.config, n.info, "A module cannot import itself")
if sfDeprecated in result.flags:
if result.constraint != nil:
message(n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s)
message(c.config, n.info, warnDeprecated, result.constraint.strVal & "; " & result.name.s)
else:
message(n.info, warnDeprecated, result.name.s)
suggestSym(n.info, result, c.graph.usageSym, false)
message(c.config, n.info, warnDeprecated, result.name.s)
suggestSym(c.config, n.info, result, c.graph.usageSym, false)
proc impMod(c: PContext; it: PNode) =
let m = myImportModule(c, it)
@@ -189,7 +190,7 @@ proc evalImport(c: PContext, n: PNode): PNode =
proc evalFrom(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
@@ -200,10 +201,10 @@ proc evalFrom(c: PContext, n: PNode): PNode =
proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0])
if m != nil:
n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module
importAllSymbolsExcept(c, m, readExceptSet(n))
importAllSymbolsExcept(c, m, readExceptSet(c, n))
#importForwarded(c, m.ast, exceptSet)

View File

@@ -32,13 +32,15 @@ import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options,
nversion, nimsets, msgs, std / sha1, bitsets, idents, types, os, tables,
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
intsets, cgmeth, lowerings, sighashes
intsets, cgmeth, lowerings, sighashes, configuration
from modulegraphs import ModuleGraph
type
TJSGen = object of TPassContext
module: PSym
graph: ModuleGraph
config: ConfigRef
sigConflicts: CountTable[SigHash]
BModule = ref TJSGen
@@ -94,14 +96,14 @@ type
up: PProc # up the call chain; required for closure support
declaredGlobals: IntSet
var indent = "\t".rope
template config*(p: PProc): ConfigRef = p.module.config
proc indentLine(p: PProc, r: Rope): Rope =
result = r
var p = p
while true:
for i in countup(0, p.blocks.len - 1 + p.extraIndent):
prepend(result, indent)
prepend(result, "\t".rope)
if p.up == nil or p.up.prc != p.prc.owner:
break
p = p.up
@@ -194,7 +196,7 @@ proc mapType(typ: PType): TJSTypeKind =
else: result = etyNone
of tyProc: result = etyProc
of tyCString: result = etyString
of tyUnused, tyOptAsRef: internalError("mapType")
of tyUnused, tyOptAsRef: doAssert(false, "mapType")
proc mapType(p: PProc; typ: PType): TJSTypeKind =
result = mapType(typ)
@@ -243,7 +245,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
inc i
result = rope(x)
if s.name.s != "this" and s.kind != skField:
if optHotCodeReloading in gOptions:
if optHotCodeReloading in m.config.options:
# When hot reloading is enabled, we must ensure that the names
# of functions and types will be preserved across rebuilds:
add(result, idOrSig(s, m.module.name.s, m.sigConflicts))
@@ -286,18 +288,17 @@ proc genConstant(p: PProc, c: PSym)
proc useMagic(p: PProc, name: string) =
if name.len == 0: return
var s = magicsys.getCompilerProc(name)
var s = magicsys.getCompilerProc(p.module.graph, name)
if s != nil:
internalAssert s.kind in {skProc, skFunc, skMethod, skConverter}
internalAssert p.config, 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)
else:
# we used to exclude the system module from this check, but for DLL
# generation support this sloppyness leads to hard to detect bugs, so
# we're picky here for the system module too:
if p.prc != nil: globalError(p.prc.info, errSystemNeeds, name)
else: rawMessage(errSystemNeeds, name)
if p.prc != nil:
globalError(p.config, p.prc.info, "system module needs: " & name)
else:
rawMessage(p.config, errGenerated, "system module needs: " & name)
proc isSimpleExpr(p: PProc; n: PNode): bool =
# calls all the way down --> can stay expression based
@@ -547,7 +548,7 @@ proc genLineDir(p: PProc, n: PNode) =
proc genWhileStmt(p: PProc, n: PNode) =
var
cond: TCompRes
internalAssert isEmptyType(n.typ)
internalAssert p.config, isEmptyType(n.typ)
genLineDir(p, n)
inc(p.unique)
var length = len(p.blocks)
@@ -634,7 +635,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
useMagic(p, "isObj")
for j in countup(0, blen - 2):
if n.sons[i].sons[j].kind != nkType:
internalError(n.info, "genTryStmt")
internalError(p.config, n.info, "genTryStmt")
if orExpr != nil: add(orExpr, "||")
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
@@ -648,7 +649,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
if not generalCatchBranchExists:
useMagic(p, "reraiseException")
line(p, "else {" & tnl)
line(p, indent & "reraiseException();" & tnl)
line(p, "\treraiseException();" & tnl)
line(p, "}" & tnl)
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
line(p, "} finally {" & tnl)
@@ -701,7 +702,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
case e.kind
of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
[makeJSString(e.strVal, false)])
else: internalError(e.info, "jsgen.genCaseStmt: 2")
else: internalError(p.config, e.info, "jsgen.genCaseStmt: 2")
else:
gen(p, e, cond)
lineF(p, "case $1:$n", [cond.rdLoc])
@@ -715,7 +716,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
gen(p, it.sons[0], stmt)
moveInto(p, stmt, r)
lineF(p, "break;$n", [])
else: internalError(it.info, "jsgen.genCaseStmt")
else: internalError(p.config, it.info, "jsgen.genCaseStmt")
lineF(p, "}$n", [])
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
@@ -723,7 +724,7 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
let idx = len(p.blocks)
if n.sons[0].kind != nkEmpty:
# named block?
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genBlock")
var sym = n.sons[0].sym
sym.loc.k = locOther
sym.position = idx+1
@@ -749,7 +750,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
idx = len(p.blocks) - 1
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
if idx < 0 or not p.blocks[idx].isLoop:
internalError(n.info, "no loop to break")
internalError(p.config, n.info, "no loop to break")
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
lineF(p, "break L$1;$n", [rope(p.blocks[idx].id)])
@@ -874,7 +875,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
elif b.typ == etyBaseIndex:
lineF(p, "$# = $#;$n", [a.res, b.rdLoc])
else:
internalError(x.info, "genAsgn")
internalError(p.config, x.info, "genAsgn")
else:
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
@@ -904,18 +905,18 @@ proc genSwap(p: PProc, n: PNode) =
if mapType(p, skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
let tmp2 = p.getTemp(false)
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(n.info, "genSwap")
internalError(p.config, n.info, "genSwap")
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n",
[tmp, a.address, b.address])
tmp = tmp2
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;",
[tmp, a.res, b.res])
proc getFieldPosition(f: PNode): int =
proc getFieldPosition(p: PProc; f: PNode): int =
case f.kind
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
of nkSym: result = f.sym.position
else: internalError(f.info, "genFieldPosition")
else: internalError(p.config, f.info, "genFieldPosition")
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
@@ -923,13 +924,13 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
gen(p, b.sons[0], a)
if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
r.res = makeJSString("Field" & $getFieldPosition(p, b.sons[1]))
else:
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
if b.sons[1].kind != nkSym: internalError(p.config, b.sons[1].info, "genFieldAddr")
var f = b.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
r.res = makeJSString($f.loc.r)
internalAssert a.typ != etyBaseIndex
internalAssert p.config, a.typ != etyBaseIndex
r.address = a.res
r.kind = resExpr
@@ -939,9 +940,9 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
if otyp.kind == tyTuple:
r.res = ("$1.Field$2") %
[r.res, getFieldPosition(n.sons[1]).rope]
[r.res, getFieldPosition(p, n.sons[1]).rope]
else:
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
if n.sons[1].kind != nkSym: internalError(p.config, n.sons[1].info, "genFieldAccess")
var f = n.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
r.res = "$1.$2" % [r.res, f.loc.r]
@@ -951,7 +952,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes)
proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
internalAssert m.kind == nkCheckedFieldExpr
internalAssert p.config, m.kind == nkCheckedFieldExpr
genAddr(p, m, r) # XXX
proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
@@ -965,7 +966,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
gen(p, m.sons[0], a)
gen(p, m.sons[1], b)
internalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
internalAssert p.config, a.typ != etyBaseIndex and b.typ != etyBaseIndex
r.address = a.res
var typ = skipTypes(m.sons[0].typ, abstractPtrs)
if typ.kind == tyArray: first = firstOrd(typ.sons[0])
@@ -987,9 +988,9 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
genArrayAddr(p, n, r)
of tyTuple:
genFieldAddr(p, n, r)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = etyNone
if r.res == nil: internalError(n.info, "genArrayAccess")
if r.res == nil: internalError(p.config, n.info, "genArrayAccess")
if ty.kind == tyCString:
r.res = "$1.charCodeAt($2)" % [r.address, r.res]
else:
@@ -1009,7 +1010,7 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
case n.sons[0].kind
of nkSym:
let s = n.sons[0].sym
if s.loc.r == nil: internalError(n.info, "genAddr: 3")
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
case s.kind
of skVar, skLet, skResult:
r.kind = resExpr
@@ -1031,8 +1032,8 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
else:
# 'var openArray' for instance produces an 'addr' but this is harmless:
gen(p, n.sons[0], r)
#internalError(n.info, "genAddr: 4 " & renderTree(n))
else: internalError(n.info, "genAddr: 2")
#internalError(p.config, n.info, "genAddr: 4 " & renderTree(n))
else: internalError(p.config, n.info, "genAddr: 2")
of nkCheckedFieldExpr:
genCheckedFieldAddr(p, n, r)
of nkDotExpr:
@@ -1051,12 +1052,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
genArrayAddr(p, n.sons[0], r)
of tyTuple:
genFieldAddr(p, n.sons[0], r)
else: internalError(n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
else: internalError(p.config, n.sons[0].info, "expr(nkBracketExpr, " & $kindOfIndexedExpr & ')')
of nkObjDownConv:
gen(p, n.sons[0], r)
of nkHiddenDeref:
gen(p, n.sons[0].sons[0], r)
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
else: internalError(p.config, n.sons[0].info, "genAddr: " & $n.sons[0].kind)
proc thisParam(p: PProc; typ: PType): PType =
discard
@@ -1090,7 +1091,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
case s.kind
of skVar, skLet, skParam, skTemp, skResult, skForVar:
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
let k = mapType(p, s.typ)
if k == etyBaseIndex:
r.typ = etyBaseIndex
@@ -1107,7 +1108,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
of skConst:
genConstant(p, s)
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r
of skProc, skFunc, skConverter, skMethod:
discard mangleName(p.module, s)
@@ -1124,7 +1125,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
genProcForSymIfNeeded(p, s)
else:
if s.loc.r == nil:
internalError(n.info, "symbol has no generated name: " & s.name.s)
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r
r.kind = resVal
@@ -1145,7 +1146,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
elif t == etyBaseIndex:
r.res = "$1[0]" % [a.res]
else:
internalError(n.info, "genDeref")
internalError(p.config, n.info, "genDeref")
proc genArgNoParam(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
@@ -1205,14 +1206,14 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
# XXX look into this:
let jsp = countJsParams(typ)
if emitted != jsp and tfVarargs notin typ.flags:
localError(n.info, "wrong number of parameters emitted; expected: " & $jsp &
localError(p.config, n.info, "wrong number of parameters emitted; expected: " & $jsp &
" but got: " & $emitted)
r.kind = resExpr
proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
generated: var int; r: var TCompRes) =
if i >= n.len:
globalError(n.info, "wrong importcpp pattern; expected parameter at position " & $i &
globalError(p.config, n.info, "wrong importcpp pattern; expected parameter at position " & $i &
" but got only: " & $(n.len-1))
let it = n[i]
var paramType: PNode = nil
@@ -1266,7 +1267,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if sfInfixCall in f.flags:
let pat = n.sons[0].sym.loc.r.data
internalAssert pat != nil
internalAssert p.config, pat != nil
if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n.sons[0].typ, abstractInst)
assert(typ.kind == tyProc)
@@ -1276,7 +1277,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[1], r)
if r.typ == etyBaseIndex:
if r.address == nil:
globalError(n.info, "cannot invoke with infix syntax")
globalError(p.config, n.info, "cannot invoke with infix syntax")
r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.typ = etyNone
@@ -1295,7 +1296,7 @@ proc genCall(p: PProc, n: PNode, r: var TCompRes) =
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
let n = n[1].skipConv
internalAssert n.kind == nkBracket
internalAssert p.config, n.kind == nkBracket
useMagic(p, "toJSStr") # Used in rawEcho
useMagic(p, "rawEcho")
add(r.res, "rawEcho(")
@@ -1326,7 +1327,7 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
if output.len > 0: output.add(", ")
output.addf("$#: ", [mangleName(p.module, rec.sym)])
output.add(createVar(p, rec.sym.typ, false))
else: internalError(rec.info, "createRecordVarAux")
else: internalError(p.config, rec.info, "createRecordVarAux")
proc createObjInitList(p: PProc, typ: PType, excludedFieldIDs: IntSet, output: var Rope) =
var t = typ
@@ -1409,10 +1410,10 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
if t.n != nil:
result = createVar(p, lastSon t, indirect)
else:
internalError("createVar: " & $t.kind)
internalError(p.config, "createVar: " & $t.kind)
result = nil
else:
internalError("createVar: " & $t.kind)
internalError(p.config, "createVar: " & $t.kind)
result = nil
template returnType: untyped =
@@ -1424,7 +1425,7 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
s: Rope
varCode: string
varName = mangleName(p.module, v)
useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in gOptions
useReloadingGuard = sfGlobal in v.flags and optHotCodeReloading in p.config.options
if v.constraint.isNil:
if useReloadingGuard:
@@ -1482,7 +1483,7 @@ proc genVarStmt(p: PProc, n: PNode) =
var a = n.sons[i]
if a.kind != nkCommentStmt:
if a.kind == nkVarTuple:
let unpacked = lowerTupleUnpacking(a, p.prc)
let unpacked = lowerTupleUnpacking(p.module.graph, a, p.prc)
genStmt(p, unpacked)
else:
assert(a.kind == nkIdentDefs)
@@ -1519,7 +1520,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
case skipTypes(n.sons[1].typ, abstractVar).kind
of tyEnum, tyInt..tyUInt64, tyChar: gen(p, n.sons[1], r)
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)")
else: internalError(n.info, "genOrd")
else: internalError(p.config, n.info, "genOrd")
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes
@@ -1559,9 +1560,9 @@ proc genToArray(p: PProc; n: PNode; r: var TCompRes) =
gen(p, it[1], b)
r.res.add("$# => $#" % [a.rdLoc, b.rdLoc])
else:
localError(it.info, "'toArray' needs tuple constructors")
localError(p.config, it.info, "'toArray' needs tuple constructors")
else:
localError(x.info, "'toArray' needs an array literal")
localError(p.config, x.info, "'toArray' needs an array literal")
r.res.add(")")
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
@@ -1604,7 +1605,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
of tySet:
genReprAux(p, n, r, "reprSet", genTypeInfo(p, t))
of tyEmpty, tyVoid:
localError(n.info, "'repr' doesn't support 'void' type")
localError(p.config, n.info, "'repr' doesn't support 'void' type")
of tyPointer:
genReprAux(p, n, r, "reprPointer")
of tyOpenArray, tyVarargs:
@@ -1736,7 +1737,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mReset: genReset(p, n)
of mEcho: genEcho(p, n, r)
of mNLen..mNError, mSlurp, mStaticExec:
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
localError(p.config, n.info, errXMustBeCompileTime % n.sons[0].sym.name.s)
of mCopyStr:
binaryExpr(p, n, r, "", "($1.slice($2))")
of mCopyStrLast:
@@ -1754,7 +1755,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
genCall(p, n, r)
else:
genCall(p, n, r)
#else internalError(e.info, 'genMagic: ' + magicToStr[op]);
#else internalError(p.config, e.info, 'genMagic: ' + magicToStr[op]);
proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
var
@@ -1810,7 +1811,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
for i in countup(1, sonsLen(n) - 1):
if i > 1: add(initList, ", ")
var it = n.sons[i]
internalAssert it.kind == nkExprColonExpr
internalAssert p.config, it.kind == nkExprColonExpr
let val = it.sons[1]
gen(p, val, a)
var f = it.sons[0].sym
@@ -1866,7 +1867,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0].sons[0], r)
else:
gen(p, n.sons[0], r)
if r.res == nil: internalError(n.info, "convStrToCStr")
if r.res == nil: internalError(p.config, n.info, "convStrToCStr")
useMagic(p, "toJSStr")
r.res = "toJSStr($1)" % [r.res]
r.kind = resExpr
@@ -1878,13 +1879,13 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0].sons[0], r)
else:
gen(p, n.sons[0], r)
if r.res == nil: internalError(n.info, "convCStrToStr")
if r.res == nil: internalError(p.config, n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr")
r.res = "cstrToNimstr($1)" % [r.res]
r.kind = resExpr
proc genReturnStmt(p: PProc, n: PNode) =
if p.procDef == nil: internalError(n.info, "genReturnStmt")
if p.procDef == nil: internalError(p.config, n.info, "genReturnStmt")
p.beforeRetNeeded = true
if n.sons[0].kind != nkEmpty:
genStmt(p, n.sons[0])
@@ -1969,7 +1970,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
else:
result = ~tnl
if optHotCodeReloading in gOptions:
if optHotCodeReloading in p.config.options:
# Here, we introduce thunks that create the equivalent of a jump table
# for all global functions, because references to them may be stored
# in JavaScript variables. The added indirection ensures that such
@@ -2140,7 +2141,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection: discard
of nkForStmt, nkParForStmt:
internalError(n.info, "for statement not eliminated")
internalError(p.config, n.info, "for statement not eliminated")
of nkCaseStmt: genCaseJS(p, n, r)
of nkReturnStmt: genReturnStmt(p, n)
of nkBreakStmt: genBreakStmt(p, n)
@@ -2163,13 +2164,13 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
genSym(p, n.sons[namePos], r)
r.res = nil
of nkGotoState, nkState:
internalError(n.info, "first class iterators not implemented")
internalError(p.config, n.info, "first class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r)
of nkComesFrom:
discard "XXX to implement for better stack traces"
else: internalError(n.info, "gen: unknown node type: " & $n.kind)
else: internalError(p.config, n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals
var globals: PGlobals # XXX global variable here
proc newModule(module: PSym): BModule =
new(result)
@@ -2205,10 +2206,10 @@ proc genModule(p: PProc, n: PNode) =
add(p.body, frameDestroy(p))
proc myProcess(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
result = n
var m = BModule(b)
if m.module == nil: internalError(n.info, "myProcess")
let m = BModule(b)
if passes.skipCodegen(m.config, n): return n
if m.module == nil: internalError(m.config, n.info, "myProcess")
var p = newProc(globals, m, nil, m.module.options)
p.unique = globals.unique
genModule(p, n)
@@ -2235,11 +2236,11 @@ proc getClassName(t: PType): Rope =
if s.isNil or sfAnon in s.flags:
s = skipTypes(t, abstractPtrs).sym
if s.isNil or sfAnon in s.flags:
internalError("cannot retrieve class name")
doAssert(false, "cannot retrieve class name")
if s.loc.r != nil: result = s.loc.r
else: result = rope(s.name.s)
proc genClass(obj: PType; content: Rope; ext: string) =
proc genClass(conf: ConfigRef; obj: PType; content: Rope; ext: string) =
let cls = getClassName(obj)
let t = skipTypes(obj, abstractPtrs)
let extends = if t.kind == tyObject and t.sons[0] != nil:
@@ -2252,34 +2253,36 @@ proc genClass(obj: PType; content: Rope; ext: string) =
"class $#$# {$n$#$n}$n") %
[rope(VersionAsString), cls, extends, content]
let outfile = changeFileExt(completeCFilePath($cls), ext)
let outfile = changeFileExt(completeCFilePath(conf, $cls), ext)
discard writeRopeIfNotEqual(result, outfile)
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
result = myProcess(b, n)
var m = BModule(b)
if passes.skipCodegen(m.config, n): return n
if sfMainModule in m.module.flags:
let ext = "js"
let f = if globals.classes.len == 0: toFilename(FileIndex m.module.position)
else: "nimsystem"
let code = wholeCode(graph, m)
let outfile =
if options.outFile.len > 0:
if options.outFile.isAbsolute: options.outFile
else: getCurrentDir() / options.outFile
if m.config.outFile.len > 0:
if m.config.outFile.isAbsolute: m.config.outFile
else: getCurrentDir() / m.config.outFile
else:
changeFileExt(completeCFilePath(f), ext)
changeFileExt(completeCFilePath(m.config, f), ext)
discard writeRopeIfNotEqual(genHeader() & code, outfile)
for obj, content in items(globals.classes):
genClass(obj, content, ext)
genClass(m.config, obj, content, ext)
proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext =
internalError("symbol files are not possible with the JS code generator")
internalError(graph.config, "symbol files are not possible with the JS code generator")
result = nil
proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
var r = newModule(s)
r.graph = graph
r.config = graph.config
result = r
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View File

@@ -38,7 +38,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
makeJSString(field.name.s)]
of nkRecCase:
length = sonsLen(n)
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
if (n.sons[0].kind != nkSym): internalError(p.config, n.info, "genObjectFields")
field = n.sons[0].sym
s = genTypeInfo(p, field.typ)
for i in countup(1, length - 1):
@@ -47,7 +47,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
case b.kind
of nkOfBranch:
if sonsLen(b) < 2:
internalError(b.info, "genObjectFields; nkOfBranch broken")
internalError(p.config, b.info, "genObjectFields; nkOfBranch broken")
for j in countup(0, sonsLen(b) - 2):
if u != nil: add(u, ", ")
if b.sons[j].kind == nkRange:
@@ -57,7 +57,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
add(u, rope(getOrdValue(b.sons[j])))
of nkElse:
u = rope(lengthOrd(field.typ))
else: internalError(n.info, "genObjectFields(nkRecCase)")
else: internalError(p.config, n.info, "genObjectFields(nkRecCase)")
if result != nil: add(result, ", " & tnl)
addf(result, "[setConstr($1), $2]",
[u, genObjectFields(p, typ, lastSon(b))])
@@ -65,7 +65,7 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
"typ: $2, name: $4, sons: [$5]}") % [
mangleName(p.module, field), s,
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
else: internalError(n.info, "genObjectFields")
else: internalError(p.config, n.info, "genObjectFields")
proc objHasTypeField(t: PType): bool {.inline.} =
tfInheritable in t.flags or t.sons[0] != nil
@@ -104,7 +104,7 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
let length = sonsLen(typ.n)
var s: Rope = nil
for i in countup(0, length - 1):
if (typ.n.sons[i].kind != nkSym): internalError(typ.n.info, "genEnumInfo")
if (typ.n.sons[i].kind != nkSym): internalError(p.config, typ.n.info, "genEnumInfo")
let field = typ.n.sons[i].sym
if i > 0: add(s, ", " & tnl)
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
@@ -152,5 +152,5 @@ proc genTypeInfo(p: PProc, typ: PType): Rope =
of tyTuple: genTupleInfo(p, t, result)
of tyStatic:
if t.n != nil: result = genTypeInfo(p, lastSon t)
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError("genTypeInfo(" & $t.kind & ')')
else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')
else: internalError(p.config, "genTypeInfo(" & $t.kind & ')')

View File

@@ -11,7 +11,8 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, magicsys, rodread, lowerings, tables
idents, renderer, types, magicsys, rodread, lowerings, tables,
modulegraphs
discard """
The basic approach is that captured vars need to be put on the heap and
@@ -125,32 +126,32 @@ proc newCall(a: PSym, b: PNode): PNode =
result.add newSymNode(a)
result.add b
proc createStateType(iter: PSym): PType =
proc createStateType(g: ModuleGraph; iter: PSym): PType =
var n = newNodeI(nkRange, iter.info)
addSon(n, newIntNode(nkIntLit, -1))
addSon(n, newIntNode(nkIntLit, 0))
result = newType(tyRange, iter)
result.n = n
var intType = nilOrSysInt()
var intType = nilOrSysInt(g)
if intType.isNil: intType = newType(tyInt, iter)
rawAddSon(result, intType)
proc createStateField(iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info)
result.typ = createStateType(iter)
proc createStateField(g: ModuleGraph; iter: PSym): PSym =
result = newSym(skField, getIdent(":state"), iter, iter.info, {})
result.typ = createStateType(g, iter)
proc createEnvObj(owner: PSym; info: TLineInfo): PType =
proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
# YYY meh, just add the state field for every closure for now, it's too
# hard to figure out if it comes from a closure iterator:
result = createObj(owner, info, final=false)
rawAddField(result, createStateField(owner))
result = createObj(g, owner, info, final=false)
rawAddField(result, createStateField(g, owner))
proc getIterResult(iter: PSym): PSym =
if resultPos < iter.ast.len:
result = iter.ast.sons[resultPos].sym
else:
# XXX a bit hacky:
result = newSym(skResult, getIdent":result", iter, iter.info)
result = newSym(skResult, getIdent":result", iter, iter.info, {})
result.typ = iter.typ.sons[0]
incl(result.flags, sfUsed)
iter.ast.add newSymNode(result)
@@ -166,7 +167,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
assert sfFromGeneric in param.flags
#echo "produced environment: ", param.id, " for ", routine.id
proc getHiddenParam(routine: PSym): PSym =
proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
let params = routine.ast.sons[paramsPos]
let hidden = lastSon(params)
if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
@@ -174,7 +175,7 @@ proc getHiddenParam(routine: PSym): PSym =
assert sfFromGeneric in result.flags
else:
# writeStackTrace()
localError(routine.info, "internal error: could not find env param for " & routine.name.s)
localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
result = routine
proc getEnvParam*(routine: PSym): PSym =
@@ -208,14 +209,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
result.sons[0] = le
result.sons[1] = ri
proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode =
proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
result = newNodeIT(nkClosure, info, prc.typ)
result.add(newSymNode(prc))
if env == nil:
result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil)))
else:
if env.skipConv.kind == nkClosure:
localError(info, "internal error: taking closure of closure")
localError(g.config, info, "internal error: taking closure of closure")
result.add(env)
proc interestingIterVar(s: PSym): bool {.inline.} =
@@ -227,23 +228,23 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
template isIterator*(owner: PSym): bool =
owner.kind == skIterator and owner.typ.callConv == ccClosure
proc liftingHarmful(owner: PSym): bool {.inline.} =
proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
## lambda lifting can be harmful for JS-like code generators.
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
result = gCmd == cmdCompileToJS and not isCompileTime
result = conf.cmd == cmdCompileToJS and not isCompileTime
proc liftIterSym*(n: PNode; owner: PSym): PNode =
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
if liftingHarmful(owner): return n
if liftingHarmful(g.config, owner): return n
let iter = n.sym
assert iter.isIterator
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
let hp = getHiddenParam(iter)
let hp = getHiddenParam(g, iter)
var env: PNode
if owner.isIterator:
let it = getHiddenParam(owner)
let it = getHiddenParam(g, owner)
addUniqueField(it.typ.sons[0], hp)
env = indirectAccess(newSymNode(it), hp, hp.info)
else:
@@ -255,11 +256,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
addVar(v, env)
result.add(v)
# add 'new' statement:
result.add newCall(getSysSym"internalNew", env)
result.add makeClosure(iter, env, n.info)
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
result.add makeClosure(g, iter, env, n.info)
proc freshVarForClosureIter*(s, owner: PSym): PNode =
let envParam = getHiddenParam(owner)
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
let envParam = getHiddenParam(g, owner)
let obj = envParam.typ.lastSon
addField(obj, s)
@@ -269,18 +270,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode =
if field != nil:
result = rawIndirectAccess(access, field, s.info)
else:
localError(s.info, "internal error: cannot generate fresh variable")
localError(g.config, s.info, "internal error: cannot generate fresh variable")
result = access
# ------------------ new stuff -------------------------------------------
proc markAsClosure(owner: PSym; n: PNode) =
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
let s = n.sym
if illegalCapture(s):
localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
[s.name.s, typeToString(s.typ), $s.info])
elif owner.typ.callConv notin {ccClosure, ccDefault}:
localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
incl(owner.typ.flags, tfCapturesEnv)
owner.typ.callConv = ccClosure
@@ -290,12 +291,14 @@ type
processed, capturedVars: IntSet
ownerToType: Table[int, PType]
somethingToDo: bool
graph: ModuleGraph
proc initDetectionPass(fn: PSym): DetectionPass =
proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
result.processed = initIntSet()
result.capturedVars = initIntSet()
result.ownerToType = initTable[int, PType]()
result.processed.incl(fn.id)
result.graph = g
discard """
proc outer =
@@ -312,7 +315,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
result = c.ownerToType.getOrDefault(owner.id)
if result.isNil:
result = newType(tyRef, owner)
let obj = createEnvObj(owner, info)
let obj = createEnvObj(c.graph, owner, info)
rawAddSon(result, obj)
c.ownerToType[owner.id] = result
@@ -321,13 +324,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
let obj = refObj.lastSon
let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
if refObj == fieldType:
localError(dep.info, "internal error: invalid up reference computed")
localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
let upIdent = getIdent(upName)
let upField = lookupInRecord(obj.n, upIdent)
if upField != nil:
if upField.typ != fieldType:
localError(dep.info, "internal error: up references do not agree")
localError(c.graph.config, dep.info, "internal error: up references do not agree")
else:
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
result.typ = fieldType
@@ -369,7 +372,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
cp.typ = t
addHiddenParam(fn, cp)
elif cp.typ != t and fn.kind != skIterator:
localError(fn.info, "internal error: inconsistent environment type")
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
#echo "adding closure to ", fn.name.s
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
@@ -395,7 +398,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
addClosureParam(c, owner, n.info)
if interestingIterVar(s):
if not c.capturedVars.containsOrIncl(s.id):
let obj = getHiddenParam(owner).typ.lastSon
let obj = getHiddenParam(c.graph, owner).typ.lastSon
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
addField(obj, s)
# but always return because the rest of the proc is only relevant when
@@ -415,7 +418,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
"""
# mark 'owner' as taking a closure:
c.somethingToDo = true
markAsClosure(owner, n)
markAsClosure(c.graph, owner, n)
addClosureParam(c, owner, n.info)
#echo "capturing ", n.info
# variable 's' is actually captured:
@@ -440,7 +443,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
"""
let up = w.skipGenericOwner
#echo "up for ", w.name.s, " up ", up.name.s
markAsClosure(w, n)
markAsClosure(c.graph, w, n)
addClosureParam(c, w, n.info) # , ow
createUpField(c, w, up, n.info)
w = up
@@ -467,10 +470,10 @@ proc initLiftingPass(fn: PSym): LiftingPass =
result.processed.incl(fn.id)
result.envVars = initTable[int, PNode]()
proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
let s = n.sym
# Type based expression construction for simplicity:
let envParam = getHiddenParam(owner)
let envParam = getHiddenParam(g, owner)
if not envParam.isNil:
var access = newSymNode(envParam)
while true:
@@ -482,7 +485,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
let upField = lookupInRecord(obj.n, getIdent(upName))
if upField == nil: break
access = rawIndirectAccess(access, upField, n.info)
localError(n.info, "internal error: environment misses: " & s.name.s)
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
result = n
proc newEnvVar(owner: PSym; typ: PType): PNode =
@@ -501,22 +504,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
proc setupEnvVar(owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
if owner.isIterator:
return getHiddenParam(owner).newSymNode
return getHiddenParam(d.graph, owner).newSymNode
result = c.envvars.getOrDefault(owner.id)
if result.isNil:
let envVarType = d.ownerToType.getOrDefault(owner.id)
if envVarType.isNil:
localError owner.info, "internal error: could not determine closure type"
localError d.graph.config, owner.info, "internal error: could not determine closure type"
result = newEnvVar(owner, envVarType)
c.envVars[owner.id] = result
proc getUpViaParam(owner: PSym): PNode =
let p = getHiddenParam(owner)
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
let p = getHiddenParam(g, owner)
result = p.newSymNode
if owner.isIterator:
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName))
if upField == nil:
localError(owner.info, "could not find up reference for closure iter")
localError(g.config, owner.info, "could not find up reference for closure iter")
else:
result = rawIndirectAccess(result, upField, p.info)
@@ -526,7 +529,7 @@ proc rawClosureCreation(owner: PSym;
var env: PNode
if owner.isIterator:
env = getHiddenParam(owner).newSymNode
env = getHiddenParam(d.graph, owner).newSymNode
else:
env = setupEnvVar(owner, d, c)
if env.kind == nkSym:
@@ -534,7 +537,7 @@ proc rawClosureCreation(owner: PSym;
addVar(v, env)
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env))
result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
# add assignment statements for captured parameters:
for i in 1..<owner.typ.n.len:
let local = owner.typ.n[i].sym
@@ -545,7 +548,7 @@ proc rawClosureCreation(owner: PSym;
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
if upField != nil:
let up = getUpViaParam(owner)
let up = getUpViaParam(d.graph, owner)
if up != nil and upField.typ == up.typ:
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
up, env.info))
@@ -553,7 +556,7 @@ proc rawClosureCreation(owner: PSym;
# result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
# oldenv, env.info))
else:
localError(env.info, "internal error: cannot create up reference")
localError(d.graph.config, env.info, "internal error: cannot create up reference")
proc closureCreationForIter(iter: PNode;
d: DetectionPass; c: var LiftingPass): PNode =
@@ -561,10 +564,10 @@ proc closureCreationForIter(iter: PNode;
let owner = iter.sym.skipGenericOwner
var v = newSym(skVar, getIdent(envName), owner, iter.info)
incl(v.flags, sfShadowed)
v.typ = getHiddenParam(iter.sym).typ
v.typ = getHiddenParam(d.graph, iter.sym).typ
var vnode: PNode
if owner.isIterator:
let it = getHiddenParam(owner)
let it = getHiddenParam(d.graph, owner)
addUniqueField(it.typ.sons[0], v)
vnode = indirectAccess(newSymNode(it), v, v.info)
else:
@@ -572,7 +575,7 @@ proc closureCreationForIter(iter: PNode;
var vs = newNodeI(nkVarSection, iter.info)
addVar(vs, vnode)
result.add(vs)
result.add(newCall(getSysSym"internalNew", vnode))
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName))
if upField != nil:
@@ -581,8 +584,8 @@ proc closureCreationForIter(iter: PNode;
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
u, iter.info))
else:
localError(iter.info, "internal error: cannot create up reference for iter")
result.add makeClosure(iter.sym, vnode, iter.info)
localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter")
result.add makeClosure(d.graph, iter.sym, vnode, iter.info)
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
@@ -592,11 +595,11 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
if field != nil:
result = rawIndirectAccess(access, field, n.info)
else:
localError(n.info, "internal error: not part of closure object type")
localError(d.graph.config, n.info, "internal error: not part of closure object type")
result = n
proc getStateField(owner: PSym): PSym =
getHiddenParam(owner).typ.sons[0].n.sons[0].sym
proc getStateField(g: ModuleGraph; owner: PSym): PSym =
getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode
@@ -604,8 +607,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
if c.inContainer > 0:
localError(n.info, "invalid control flow: 'yield' within a constructor")
let state = getStateField(owner)
localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
let state = getStateField(d.graph, owner)
assert state != nil
assert state.typ != nil
assert state.typ.n != nil
@@ -615,7 +618,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
var retStmt = newNodeI(nkReturnStmt, n.info)
if n.sons[0].kind != nkEmpty:
@@ -628,7 +632,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
retStmt.add(emptyNode)
var stateLabelStmt = newNodeI(nkState, n.info)
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
getSysType(d.graph, n.info, tyInt)))
result = newNodeI(nkStmtList, n.info)
result.add(stateAsgnStmt)
@@ -637,16 +642,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
c: var LiftingPass): PNode =
let state = getStateField(owner)
let state = getStateField(d.graph, owner)
result = newNodeI(nkStmtList, n.info)
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
state, n.info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
result.add(stateAsgnStmt)
result.add(n)
proc wrapIterBody(n: PNode; owner: PSym): PNode =
proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
if not owner.isIterator: return n
when false:
# unfortunately control flow is still convoluted and we can end up
@@ -660,7 +665,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
let info = n.info
result = newNodeI(nkStmtList, info)
var gs = newNodeI(nkGotoState, info)
gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info))
gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
result.add(gs)
var state0 = newNodeI(nkState, info)
state0.add(newIntNode(nkIntLit, 0))
@@ -669,9 +674,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
result.add(n)
var stateAsgnStmt = newNodeI(nkAsgn, info)
stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam),
getStateField(owner), info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
getStateField(g, owner), info))
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
result.add(stateAsgnStmt)
proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
@@ -679,25 +684,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
let s = n.sym
if s == owner:
# recursive calls go through (lambda, hiddenParam):
let available = getHiddenParam(owner)
result = makeClosure(s, available.newSymNode, n.info)
let available = getHiddenParam(d.graph, owner)
result = makeClosure(d.graph, s, available.newSymNode, n.info)
elif s.isIterator:
result = closureCreationForIter(n, d, c)
elif s.skipGenericOwner == owner:
# direct dependency, so use the outer's env variable:
result = makeClosure(s, setupEnvVar(owner, d, c), n.info)
result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
else:
let available = getHiddenParam(owner)
let wanted = getHiddenParam(s).typ
let available = getHiddenParam(d.graph, owner)
let wanted = getHiddenParam(d.graph, s).typ
# ugh: call through some other inner proc;
var access = newSymNode(available)
while true:
if access.typ == wanted:
return makeClosure(s, access, n.info)
return makeClosure(d.graph, s, access, n.info)
let obj = access.typ.sons[0]
let upField = lookupInRecord(obj.n, getIdent(upName))
if upField == nil:
localError(n.info, "internal error: no environment found")
localError(d.graph.config, n.info, "internal error: no environment found")
return n
access = rawIndirectAccess(access, upField, n.info)
@@ -713,7 +718,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
# echo renderTree(s.getBody, {renderIds})
let oldInContainer = c.inContainer
c.inContainer = 0
let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s)
let body = wrapIterBody(d.graph, liftCapturedVars(s.getBody, s, d, c), s)
if c.envvars.getOrDefault(s.id).isNil:
s.ast.sons[bodyPos] = body
else:
@@ -723,9 +728,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
result = symToClosure(n, owner, d, c)
elif s.id in d.capturedVars:
if s.owner != owner:
result = accessViaEnvParam(n, owner)
result = accessViaEnvParam(d.graph, n, owner)
elif owner.isIterator and interestingIterVar(s):
result = accessViaEnvParam(n, owner)
result = accessViaEnvParam(d.graph, n, owner)
else:
result = accessViaEnvVar(n, owner, d, c)
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
@@ -791,8 +796,8 @@ proc semCaptureSym*(s, owner: PSym) =
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
# here
proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
var d = initDetectionPass(fn)
proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode =
var d = initDetectionPass(g, fn)
var c = initLiftingPass(fn)
# pretend 'fn' is a closure iterator for the analysis:
let oldKind = fn.kind
@@ -801,25 +806,25 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
fn.typ.callConv = ccClosure
d.ownerToType[fn.id] = ptrType
detectCapturedVars(body, fn, d)
result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn)
result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
fn.kind = oldKind
fn.typ.callConv = oldCC
proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
# XXX conf.cmd == cmdCompileToJS does not suffice! The compiletime stuff needs
# the transformation even when compiling to JS ...
# However we can do lifting for the stuff which is *only* compiletime.
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
if body.kind == nkEmpty or (
gCmd == cmdCompileToJS and not isCompileTime) or
g.config.cmd == cmdCompileToJS and not isCompileTime) or
fn.skipGenericOwner.kind != skModule:
# ignore forward declaration:
result = body
tooEarly = true
else:
var d = initDetectionPass(fn)
var d = initDetectionPass(g, fn)
detectCapturedVars(body, fn, d)
if not d.somethingToDo and fn.isIterator:
addClosureParam(d, fn, body.info)
@@ -829,7 +834,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
var newBody = liftCapturedVars(body, fn, d, c)
if c.envvars.getOrDefault(fn.id) != nil:
newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody)
result = wrapIterBody(newBody, fn)
result = wrapIterBody(g, newBody, fn)
else:
result = body
#if fn.name.s == "get2":
@@ -837,15 +842,12 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
# echo renderTree(result, {renderIds})
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
result = body
else:
# XXX implement it properly
result = body
# XXX implement it properly
result = body
# ------------------- iterator transformation --------------------------------
proc liftForLoop*(body: PNode; owner: PSym): PNode =
proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
# problem ahead: the iterator could be invoked indirectly, but then
# we don't know what environment to create here:
#
@@ -873,10 +875,10 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
nkBreakState(cl.state)
...
"""
if liftingHarmful(owner): return body
if liftingHarmful(g.config, owner): return body
var L = body.len
if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
localError(body.info, "ignored invalid for loop")
localError(g.config, body.info, "ignored invalid for loop")
return body
var call = body[L-2]
@@ -889,7 +891,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
# createClosure()
let iter = op.sym
let hp = getHiddenParam(iter)
let hp = getHiddenParam(g, iter)
env = newSym(skLet, iter.name, owner, body.info)
env.typ = hp.typ
env.flags = hp.flags
@@ -898,7 +900,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
addVar(v, newSymNode(env))
result.add(v)
# add 'new' statement:
result.add(newCall(getSysSym"internalNew", env.newSymNode))
result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
elif op.kind == nkStmtListExpr:
let closure = op.lastSon
if closure.kind == nkClosure:
@@ -908,7 +910,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
whileLoop.sons[1] = loopBody
result.add whileLoop
@@ -923,7 +925,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
addSon(vpart, ast.emptyNode) # no explicit type
if not env.isNil:
call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info)
call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
addSon(vpart, call)
addSon(v2, vpart)

View File

@@ -17,7 +17,7 @@
import
hashes, options, msgs, strutils, platform, idents, nimlexbase, llstream,
wordrecg
wordrecg, configuration
const
MaxLineLength* = 80 # lines longer than this lead to a warning
@@ -131,7 +131,7 @@ type
# like 0b01 or r"\L" are unaffected
commentOffsetA*, commentOffsetB*: int
TErrorHandler* = proc (info: TLineInfo; msg: TMsgKind; arg: string)
TErrorHandler* = proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string)
TLexer* = object of TBaseLexer
fileIdx*: FileIndex
indentAhead*: int # if > 0 an indendation has already been read
@@ -190,8 +190,8 @@ proc prettyTok*(tok: TToken): string =
if isKeyword(tok.tokType): result = "keyword " & tok.ident.s
else: result = tokToStr(tok)
proc printTok*(tok: TToken) =
msgWriteln($tok.line & ":" & $tok.col & "\t" &
proc printTok*(conf: ConfigRef; tok: TToken) =
msgWriteln(conf, $tok.line & ":" & $tok.col & "\t" &
TokTypeToStr[tok.tokType] & " " & tokToStr(tok))
proc initToken*(L: var TToken) =
@@ -234,7 +234,7 @@ proc openLexer*(lex: var TLexer, fileIdx: FileIndex, inputstream: PLLStream;
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
openLexer(lex, filename.fileInfoIdx, inputstream, cache, config)
openLexer(lex, fileInfoIdx(config, filename), inputstream, cache, config)
proc closeLexer*(lex: var TLexer) =
if lex.config != nil:
@@ -246,9 +246,9 @@ proc getLineInfo(L: TLexer): TLineInfo =
proc dispMessage(L: TLexer; info: TLineInfo; msg: TMsgKind; arg: string) =
if L.errorHandler.isNil:
msgs.message(info, msg, arg)
msgs.message(L.config, info, msg, arg)
else:
L.errorHandler(info, msg, arg)
L.errorHandler(L.config, info, msg, arg)
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "") =
L.dispMessage(getLineInfo(L), msg, arg)
@@ -274,7 +274,7 @@ template tokenEnd(tok, pos) {.dirty.} =
when defined(nimsuggest):
let colB = getColNumber(L, pos)+1
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.InToken
gTrackPos.col = colA.int16
colA = 0
@@ -285,7 +285,7 @@ template tokenEndIgnore(tok, pos) =
when defined(nimsuggest):
let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
gTrackPos.fileIndex = trackPosInvalidFileIdx
gTrackPos.line = 0'u16
colA = 0
@@ -299,7 +299,7 @@ template tokenEndPrevious(tok, pos) =
# the cursor in a string literal or comment:
let colB = getColNumber(L, pos)
if L.fileIdx == gTrackPos.fileIndex and gTrackPos.col in colA..colB and
L.lineNumber == gTrackPos.line.int and gIdeCmd in {ideSug, ideCon}:
L.lineNumber == gTrackPos.line.int and L.config.ideCmd in {ideSug, ideCon}:
L.cursor = CursorPosition.BeforeToken
gTrackPos = L.previousToken
gTrackPosAttached = true
@@ -341,7 +341,8 @@ proc getNumber(L: var TLexer, result: var TToken) =
break
if buf[pos] == '_':
if buf[pos+1] notin chars:
lexMessage(L, errInvalidToken, "_")
lexMessage(L, errGenerated,
"only single underscores may occur in a token: '__' is invalid")
break
add(tok.literal, '_')
inc(pos)
@@ -355,7 +356,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
inc(pos)
L.bufpos = pos
proc lexMessageLitNum(L: var TLexer, msg: TMsgKind, startpos: int) =
proc lexMessageLitNum(L: var TLexer, msg: string, startpos: int) =
# Used to get slightly human friendlier err messages.
# Note: the erroneous 'O' char in the character set is intentional
const literalishChars = {'A'..'F', 'a'..'f', '0'..'9', 'X', 'x', 'o', 'O',
@@ -376,7 +377,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
add(t.literal, L.buf[L.bufpos])
matchChars(L, t, {'0'..'9'})
L.bufpos = msgPos
lexMessage(L, msg, t.literal)
lexMessage(L, errGenerated, msg % t.literal)
var
startpos, endpos: int
@@ -398,7 +399,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
eatChar(L, result, '0')
case L.buf[L.bufpos]
of 'O':
lexMessageLitNum(L, errInvalidNumberOctalCode, startpos)
lexMessageLitNum(L, "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.", startpos)
of 'x', 'X':
eatChar(L, result, 'x')
matchUnderscoreChars(L, result, {'0'..'9', 'a'..'f', 'A'..'F'})
@@ -409,7 +410,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
eatChar(L, result, 'b')
matchUnderscoreChars(L, result, {'0'..'1'})
else:
internalError(getLineInfo(L), "getNumber")
internalError(L.config, getLineInfo(L), "getNumber")
else:
matchUnderscoreChars(L, result, {'0'..'9'})
if (L.buf[L.bufpos] == '.') and (L.buf[L.bufpos + 1] in {'0'..'9'}):
@@ -464,7 +465,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
result.tokType = tkInt8Lit
inc(postPos)
else:
lexMessageLitNum(L, errInvalidNumber, startpos)
lexMessageLitNum(L, "invalid number: '$1'", startpos)
of 'u', 'U':
inc(postPos)
if (L.buf[postPos] == '6') and (L.buf[postPos + 1] == '4'):
@@ -482,12 +483,12 @@ proc getNumber(L: var TLexer, result: var TToken) =
else:
result.tokType = tkUIntLit
else:
lexMessageLitNum(L, errInvalidNumber, startpos)
lexMessageLitNum(L, "invalid number: '$1'", startpos)
# Is there still a literalish char awaiting? Then it's an error!
if L.buf[postPos] in literalishChars or
(L.buf[postPos] == '.' and L.buf[postPos + 1] in {'0'..'9'}):
lexMessageLitNum(L, errInvalidNumber, startpos)
lexMessageLitNum(L, "invalid number: '$1'", startpos)
# Third stage, extract actual number
L.bufpos = startpos # restore position
@@ -528,7 +529,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
else:
break
else:
internalError(getLineInfo(L), "getNumber")
internalError(L.config, getLineInfo(L), "getNumber")
case result.tokType
of tkIntLit, tkInt64Lit: result.iNumber = xi
@@ -545,7 +546,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
# XXX: Test this on big endian machine!
of tkFloat64Lit, tkFloatLit:
result.fNumber = (cast[PFloat64](addr(xi)))[]
else: internalError(getLineInfo(L), "getNumber")
else: internalError(L.config, getLineInfo(L), "getNumber")
# Bounds checks. Non decimal literals are allowed to overflow the range of
# the datatype as long as their pattern don't overflow _bitwise_, hence
@@ -561,7 +562,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
if outOfRange:
#echo "out of range num: ", result.iNumber, " vs ", xi
lexMessageLitNum(L, errNumberOutOfRange, startpos)
lexMessageLitNum(L, "number out of range: '$1'", startpos)
else:
case result.tokType
@@ -590,7 +591,7 @@ proc getNumber(L: var TLexer, result: var TToken) =
result.iNumber > BiggestInt(uint32.high))
else: false
if outOfRange: lexMessageLitNum(L, errNumberOutOfRange, startpos)
if outOfRange: lexMessageLitNum(L, "number out of range: '$1'", startpos)
# Promote int literal to int64? Not always necessary, but more consistent
if result.tokType == tkIntLit:
@@ -598,9 +599,9 @@ proc getNumber(L: var TLexer, result: var TToken) =
result.tokType = tkInt64Lit
except ValueError:
lexMessageLitNum(L, errInvalidNumber, startpos)
lexMessageLitNum(L, "invalid number: '$1'", startpos)
except OverflowError, RangeError:
lexMessageLitNum(L, errNumberOutOfRange, startpos)
lexMessageLitNum(L, "number out of range: '$1'", startpos)
tokenEnd(result, postPos-1)
L.bufpos = postPos
@@ -626,8 +627,9 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '\'
case L.buf[L.bufpos]
of 'n', 'N':
if gOldNewlines:
if tok.tokType == tkCharLit: lexMessage(L, errNnotAllowedInCharacter)
if L.config.oldNewlines:
if tok.tokType == tkCharLit:
lexMessage(L, errGenerated, "\\n not allowed in character literal")
add(tok.literal, tnl)
else:
add(tok.literal, '\L')
@@ -696,8 +698,8 @@ proc getEscapedChar(L: var TLexer, tok: var TToken) =
var xi = 0
handleDecChars(L, xi)
if (xi <= 255): add(tok.literal, chr(xi))
else: lexMessage(L, errInvalidCharacterConstant)
else: lexMessage(L, errInvalidCharacterConstant)
else: lexMessage(L, errGenerated, "invalid character constant")
else: lexMessage(L, errGenerated, "invalid character constant")
proc newString(s: cstring, len: int): string =
## XXX, how come there is no support for this?
@@ -712,7 +714,7 @@ proc handleCRLF(L: var TLexer, pos: int): int =
if col > MaxLineLength:
lexMessagePos(L, hintLineTooLong, pos)
if optEmbedOrigSrc in gGlobalOptions:
if optEmbedOrigSrc in L.config.globalOptions:
let lineStart = cast[ByteAddress](L.buf) + L.lineStart
let line = newString(cast[cstring](lineStart), col)
addSourceLine(L.fileIdx, line)
@@ -761,7 +763,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
tokenEndIgnore(tok, pos)
var line2 = L.lineNumber
L.lineNumber = line
lexMessagePos(L, errClosingTripleQuoteExpected, L.lineStart)
lexMessagePos(L, errGenerated, L.lineStart, "closing \"\"\" expected, but end of file reached")
L.lineNumber = line2
L.bufpos = pos
break
@@ -784,7 +786,7 @@ proc getString(L: var TLexer, tok: var TToken, rawMode: bool) =
break
elif c in {CR, LF, nimlexbase.EndOfFile}:
tokenEndIgnore(tok, pos)
lexMessage(L, errClosingQuoteExpected)
lexMessage(L, errGenerated, "closing \" expected")
break
elif (c == '\\') and not rawMode:
L.bufpos = pos
@@ -800,12 +802,13 @@ proc getCharacter(L: var TLexer, tok: var TToken) =
inc(L.bufpos) # skip '
var c = L.buf[L.bufpos]
case c
of '\0'..pred(' '), '\'': lexMessage(L, errInvalidCharacterConstant)
of '\0'..pred(' '), '\'': lexMessage(L, errGenerated, "invalid character literal")
of '\\': getEscapedChar(L, tok)
else:
tok.literal = $c
inc(L.bufpos)
if L.buf[L.bufpos] != '\'': lexMessage(L, errMissingFinalQuote)
if L.buf[L.bufpos] != '\'':
lexMessage(L, errGenerated, "missing closing ' for character literal")
tokenEndIgnore(tok, L.bufpos)
inc(L.bufpos) # skip '
@@ -826,7 +829,7 @@ proc getSymbol(L: var TLexer, tok: var TToken) =
inc(pos)
of '_':
if buf[pos+1] notin SymChars:
lexMessage(L, errInvalidToken, "_")
lexMessage(L, errGenerated, "invalid token: trailing underscore")
break
inc(pos)
else: break
@@ -1014,7 +1017,7 @@ proc skip(L: var TLexer, tok: var TToken) =
inc(pos)
inc(tok.strongSpaceA)
of '\t':
if not L.allowTabs: lexMessagePos(L, errTabulatorsAreNotAllowed, pos)
if not L.allowTabs: lexMessagePos(L, errGenerated, pos, "tabulators are not allowed")
inc(pos)
of CR, LF:
tokenEndPrevious(tok, pos)
@@ -1119,7 +1122,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
tok.tokType = tkParLe
when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col < gTrackPos.col and
tok.line == gTrackPos.line.int and gIdeCmd == ideCon:
tok.line == gTrackPos.line.int and L.config.ideCmd == ideCon:
gTrackPos.col = tok.col.int16
of ')':
tok.tokType = tkParRi
@@ -1140,7 +1143,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
of '.':
when defined(nimsuggest):
if L.fileIdx == gTrackPos.fileIndex and tok.col+1 == gTrackPos.col and
tok.line == gTrackPos.line.int and gIdeCmd == ideSug:
tok.line == gTrackPos.line.int and L.config.ideCmd == ideSug:
tok.tokType = tkDot
L.cursor = CursorPosition.InToken
gTrackPos.col = tok.col.int16
@@ -1182,7 +1185,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
else:
tok.literal = $c
tok.tokType = tkInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
of '\"':
# check for extended raw string literal:
var rawMode = L.bufpos > 0 and L.buf[L.bufpos-1] in SymChars
@@ -1199,7 +1202,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
getNumber(L, tok)
let c = L.buf[L.bufpos]
if c in SymChars+{'_'}:
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
lexMessage(L, errGenerated, "invalid token: no whitespace between number and identifier")
else:
if c in OpChars:
getOperator(L, tok)
@@ -1209,6 +1212,6 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
else:
tok.literal = $c
tok.tokType = tkInvalid
lexMessage(L, errInvalidToken, c & " (\\" & $(ord(c)) & ')')
lexMessage(L, errGenerated, "invalid token: " & c & " (\\" & $(ord(c)) & ')')
inc(L.bufpos)
atTokenEnd()

View File

@@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym =
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
return params[i].sym
proc liftLocalsIfRequested*(prc: PSym; n: PNode): PNode =
proc liftLocalsIfRequested*(prc: PSym; n: PNode; conf: ConfigRef): PNode =
let liftDest = getPragmaVal(prc.ast, wLiftLocals)
if liftDest == nil: return n
let partialParam = lookupParam(prc.typ.n, liftDest)
if partialParam.isNil:
localError(liftDest.info, "'$1' is not a parameter of '$2'" %
localError(conf, liftDest.info, "'$1' is not a parameter of '$2'" %
[$liftDest, prc.name.s])
return n
let objType = partialParam.typ.skipTypes(abstractPtrs)
if objType.kind != tyObject or tfPartial notin objType.flags:
localError(liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
localError(conf, liftDest.info, "parameter '$1' is not a pointer to a partial object" % $liftDest)
return n
var c = Ctx(partialParam: partialParam, objType: objType)
let w = newTree(nkStmtList, n)

View File

@@ -11,23 +11,23 @@
import
intsets, ast, astalgo, idents, semdata, types, msgs, options, rodread,
renderer, wordrecg, idgen, nimfix.prettybase
renderer, wordrecg, idgen, nimfix.prettybase, configuration, strutils
proc ensureNoMissingOrUnusedSymbols(scope: PScope)
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope)
proc noidentError(n, origin: PNode) =
proc noidentError(conf: ConfigRef; n, origin: PNode) =
var m = ""
if origin != nil:
m.add "in expression '" & origin.renderTree & "': "
m.add "identifier expected, but found '" & n.renderTree & "'"
localError(n.info, m)
localError(conf, n.info, m)
proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
proc considerQuotedIdent*(conf: ConfigRef; n: PNode, origin: PNode = nil): PIdent =
## Retrieve a PIdent from a PNode, taking into account accent nodes.
## ``origin`` can be nil. If it is not nil, it is used for a better
## error message.
template handleError(n, origin: PNode) =
noidentError(n, origin)
noidentError(conf, n, origin)
result = getIdent"<Error>"
case n.kind
@@ -36,7 +36,7 @@ proc considerQuotedIdent*(n: PNode, origin: PNode = nil): PIdent =
of nkAccQuoted:
case n.len
of 0: handleError(n, origin)
of 1: result = considerQuotedIdent(n.sons[0], origin)
of 1: result = considerQuotedIdent(conf, n.sons[0], origin)
else:
var id = ""
for i in 0..<n.len:
@@ -71,7 +71,7 @@ proc rawCloseScope*(c: PContext) =
c.currentScope = c.currentScope.parent
proc closeScope*(c: PContext) =
ensureNoMissingOrUnusedSymbols(c.currentScope)
ensureNoMissingOrUnusedSymbols(c, c.currentScope)
rawCloseScope(c)
iterator walkScopes*(scope: PScope): PScope =
@@ -80,15 +80,15 @@ iterator walkScopes*(scope: PScope): PScope =
yield current
current = current.parent
proc skipAlias*(s: PSym; n: PNode): PSym =
proc skipAlias*(s: PSym; n: PNode; conf: ConfigRef): PSym =
if s == nil or s.kind != skAlias:
result = s
else:
result = s.owner
if gCmd == cmdPretty:
if conf.cmd == cmdPretty:
prettybase.replaceDeprecated(n.info, s, result)
else:
message(n.info, warnDeprecated, "use " & result.name.s & " instead; " &
message(conf, n.info, warnDeprecated, "use " & result.name.s & " instead; " &
s.name.s)
proc localSearchInScope*(c: PContext, s: PIdent): PSym =
@@ -125,14 +125,14 @@ proc errorSym*(c: PContext, n: PNode): PSym =
# ensure that 'considerQuotedIdent' can't fail:
if m.kind == nkDotExpr: m = m.sons[1]
let ident = if m.kind in {nkIdent, nkSym, nkAccQuoted}:
considerQuotedIdent(m)
considerQuotedIdent(c.config, m)
else:
getIdent("err:" & renderTree(m))
result = newSym(skError, ident, getCurrOwner(c), n.info)
result = newSym(skError, ident, getCurrOwner(c), n.info, {})
result.typ = errorType(c)
incl(result.flags, sfDiscardable)
# pretend it's imported from some unknown module to prevent cascading errors:
if gCmd != cmdInteractive and c.compilesContextId == 0:
if c.config.cmd != cmdInteractive and c.compilesContextId == 0:
c.importTable.addSym(result)
type
@@ -154,7 +154,7 @@ proc getSymRepr*(s: PSym): string =
else:
result = s.name.s
proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
proc ensureNoMissingOrUnusedSymbols(c: PContext; scope: PScope) =
# check if all symbols have been used and defined:
var it: TTabIter
var s = initTabIter(it, scope.symbols)
@@ -164,54 +164,53 @@ proc ensureNoMissingOrUnusedSymbols(scope: PScope) =
# too many 'implementation of X' errors are annoying
# and slow 'suggest' down:
if missingImpls == 0:
localError(s.info, errImplOfXexpected, getSymRepr(s))
localError(c.config, s.info, "implementation of '$1' expected" % getSymRepr(s))
inc missingImpls
elif {sfUsed, sfExported} * s.flags == {} and optHints in s.options:
# BUGFIX: check options in s!
if s.kind notin {skForVar, skParam, skMethod, skUnknown, skGenericParam}:
# XXX: implicit type params are currently skTypes
# maybe they can be made skGenericParam as well.
if s.typ != nil and tfImplicitTypeParam notin s.typ.flags and
s.typ.kind != tyGenericParam:
message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
message(c.config, s.info, hintXDeclaredButNotUsed, getSymRepr(s))
s = nextIter(it, scope.symbols)
proc wrongRedefinition*(info: TLineInfo, s: string) =
if gCmd != cmdInteractive:
localError(info, errAttemptToRedefine, s)
proc wrongRedefinition*(c: PContext; info: TLineInfo, s: string) =
if c.config.cmd != cmdInteractive:
localError(c.config, info, "redefinition of '$1'" % s)
proc addDecl*(c: PContext, sym: PSym, info: TLineInfo) =
if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(info, sym.name.s)
wrongRedefinition(c, info, sym.name.s)
proc addDecl*(c: PContext, sym: PSym) =
if not c.currentScope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s)
wrongRedefinition(c, sym.info, sym.name.s)
proc addPrelimDecl*(c: PContext, sym: PSym) =
discard c.currentScope.addUniqueSym(sym)
proc addDeclAt*(scope: PScope, sym: PSym) =
proc addDeclAt*(c: PContext; scope: PScope, sym: PSym) =
if not scope.addUniqueSym(sym):
wrongRedefinition(sym.info, sym.name.s)
wrongRedefinition(c, sym.info, sym.name.s)
proc addInterfaceDeclAux(c: PContext, sym: PSym) =
if sfExported in sym.flags:
# add to interface:
if c.module != nil: strTableAdd(c.module.tab, sym)
else: internalError(sym.info, "addInterfaceDeclAux")
else: internalError(c.config, sym.info, "addInterfaceDeclAux")
proc addInterfaceDeclAt*(c: PContext, scope: PScope, sym: PSym) =
addDeclAt(scope, sym)
addDeclAt(c, scope, sym)
addInterfaceDeclAux(c, sym)
proc addOverloadableSymAt*(scope: PScope, fn: PSym) =
proc addOverloadableSymAt*(c: PContext; scope: PScope, fn: PSym) =
if fn.kind notin OverloadableSyms:
internalError(fn.info, "addOverloadableSymAt")
internalError(c.config, fn.info, "addOverloadableSymAt")
return
let check = strTableGet(scope.symbols, fn.name)
if check != nil and check.kind notin OverloadableSyms:
wrongRedefinition(fn.info, fn.name.s)
wrongRedefinition(c, fn.info, fn.name.s)
else:
scope.addSym(fn)
@@ -222,12 +221,10 @@ proc addInterfaceDecl*(c: PContext, sym: PSym) =
proc addInterfaceOverloadableSymAt*(c: PContext, scope: PScope, sym: PSym) =
# it adds the symbol to the interface if appropriate
addOverloadableSymAt(scope, sym)
addOverloadableSymAt(c, scope, sym)
addInterfaceDeclAux(c, sym)
when defined(nimfix):
import strutils
# when we cannot find the identifier, retry with a changed identifer:
proc altSpelling(x: PIdent): PIdent =
case x.s[0]
@@ -255,7 +252,7 @@ proc errorUseQualifier*(c: PContext; info: TLineInfo; s: PSym) =
err.add candidate.owner.name.s & "." & candidate.name.s
candidate = nextIdentIter(ti, c.importTable.symbols)
inc i
localError(info, errGenerated, err)
localError(c.config, info, errGenerated, err)
proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
var err = "undeclared identifier: '" & name & "'"
@@ -264,13 +261,13 @@ proc errorUndeclaredIdentifier*(c: PContext; info: TLineInfo; name: string) =
err.add c.recursiveDep
# prevent excessive errors for 'nim check'
c.recursiveDep = nil
localError(info, errGenerated, err)
localError(c.config, info, errGenerated, err)
proc lookUp*(c: PContext, n: PNode): PSym =
# Looks up a symbol. Generates an error in case of nil.
case n.kind
of nkIdent:
result = searchInScopes(c, n.ident).skipAlias(n)
result = searchInScopes(c, n.ident).skipAlias(n, c.config)
if result == nil:
fixSpelling(n, n.ident, searchInScopes)
errorUndeclaredIdentifier(c, n.info, n.ident.s)
@@ -278,14 +275,14 @@ proc lookUp*(c: PContext, n: PNode): PSym =
of nkSym:
result = n.sym
of nkAccQuoted:
var ident = considerQuotedIdent(n)
result = searchInScopes(c, ident).skipAlias(n)
var ident = considerQuotedIdent(c.config, n)
result = searchInScopes(c, ident).skipAlias(n, c.config)
if result == nil:
fixSpelling(n, ident, searchInScopes)
errorUndeclaredIdentifier(c, n.info, ident.s)
result = errorSym(c, n)
else:
internalError(n.info, "lookUp")
internalError(c.config, n.info, "lookUp")
return
if contains(c.ambiguousSymbols, result.id):
errorUseQualifier(c, n.info, result)
@@ -299,11 +296,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
const allExceptModule = {low(TSymKind)..high(TSymKind)}-{skModule,skPackage}
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(n)
var ident = considerQuotedIdent(c.config, n)
if checkModule in flags:
result = searchInScopes(c, ident).skipAlias(n)
result = searchInScopes(c, ident).skipAlias(n, c.config)
else:
result = searchInScopes(c, ident, allExceptModule).skipAlias(n)
result = searchInScopes(c, ident, allExceptModule).skipAlias(n, c.config)
if result == nil and checkPureEnumFields in flags:
result = strTableGet(c.pureEnumFields, ident)
if result == nil and checkUndeclared in flags:
@@ -325,12 +322,12 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(n.sons[1])
ident = considerQuotedIdent(c.config, n.sons[1])
if ident != nil:
if m == c.module:
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n)
result = strTableGet(c.topLevelScope.symbols, ident).skipAlias(n, c.config)
else:
result = strTableGet(m.tab, ident).skipAlias(n)
result = strTableGet(m.tab, ident).skipAlias(n, c.config)
if result == nil and checkUndeclared in flags:
fixSpelling(n.sons[1], ident, searchInScopes)
errorUndeclaredIdentifier(c, n.sons[1].info, ident.s)
@@ -339,7 +336,7 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
result = n.sons[1].sym
elif checkUndeclared in flags and
n.sons[1].kind notin {nkOpenSymChoice, nkClosedSymChoice}:
localError(n.sons[1].info, errIdentifierExpected,
localError(c.config, n.sons[1].info, "identifier expected, but got: " &
renderTree(n.sons[1]))
result = errorSym(c, n.sons[1])
else:
@@ -349,11 +346,11 @@ proc qualifiedLookUp*(c: PContext, n: PNode, flags: set[TLookupFlag]): PSym =
proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
case n.kind
of nkIdent, nkAccQuoted:
var ident = considerQuotedIdent(n)
var ident = considerQuotedIdent(c.config, n)
o.scope = c.currentScope
o.mode = oimNoQualifier
while true:
result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n)
result = initIdentIter(o.it, o.scope.symbols, ident).skipAlias(n, c.config)
if result != nil:
break
else:
@@ -370,17 +367,17 @@ proc initOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
if n.sons[1].kind == nkIdent:
ident = n.sons[1].ident
elif n.sons[1].kind == nkAccQuoted:
ident = considerQuotedIdent(n.sons[1], n)
ident = considerQuotedIdent(c.config, n.sons[1], n)
if ident != nil:
if o.m == c.module:
# a module may access its private members:
result = initIdentIter(o.it, c.topLevelScope.symbols,
ident).skipAlias(n)
ident).skipAlias(n, c.config)
o.mode = oimSelfModule
else:
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n)
result = initIdentIter(o.it, o.m.tab, ident).skipAlias(n, c.config)
else:
noidentError(n.sons[1], n)
noidentError(c.config, n.sons[1], n)
result = errorSym(c, n.sons[1])
of nkClosedSymChoice, nkOpenSymChoice:
o.mode = oimSymChoice
@@ -408,18 +405,18 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
result = nil
of oimNoQualifier:
if o.scope != nil:
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n)
result = nextIdentIter(o.it, o.scope.symbols).skipAlias(n, c.config)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n)
result = initIdentIter(o.it, o.scope.symbols, o.it.name).skipAlias(n, c.config)
# BUGFIX: o.it.name <-> n.ident
else:
result = nil
of oimSelfModule:
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n)
result = nextIdentIter(o.it, c.topLevelScope.symbols).skipAlias(n, c.config)
of oimOtherModule:
result = nextIdentIter(o.it, o.m.tab).skipAlias(n)
result = nextIdentIter(o.it, o.m.tab).skipAlias(n, c.config)
of oimSymChoice:
if o.symChoiceIndex < sonsLen(n):
result = n.sons[o.symChoiceIndex].sym
@@ -430,19 +427,19 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
o.mode = oimSymChoiceLocalLookup
o.scope = c.currentScope
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
of oimSymChoiceLocalLookup:
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n)
result = nextIdentExcluding(o.it, o.scope.symbols, o.inSymChoice).skipAlias(n, c.config)
while result == nil:
o.scope = o.scope.parent
if o.scope == nil: break
result = firstIdentExcluding(o.it, o.scope.symbols,
n.sons[0].sym.name, o.inSymChoice).skipAlias(n)
n.sons[0].sym.name, o.inSymChoice).skipAlias(n, c.config)
if result != nil and result.kind == skStub: loadStub(result)

View File

@@ -12,18 +12,18 @@
const
genPrefix* = ":tmp" # prefix for generated names
import ast, astalgo, types, idents, magicsys, msgs, options
import ast, astalgo, types, idents, magicsys, msgs, options, modulegraphs
from trees import getMagic
proc newDeref*(n: PNode): PNode {.inline.} =
result = newNodeIT(nkHiddenDeref, n.info, n.typ.sons[0])
addSon(result, n)
proc newTupleAccess*(tup: PNode, i: int): PNode =
proc newTupleAccess*(g: ModuleGraph; tup: PNode, i: int): PNode =
result = newNodeIT(nkBracketExpr, tup.info, tup.typ.skipTypes(
abstractInst).sons[i])
addSon(result, copyTree(tup))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(tyInt))
var lit = newNodeIT(nkIntLit, tup.info, getSysType(g, tup.info, tyInt))
lit.intVal = i
addSon(result, lit)
@@ -44,12 +44,12 @@ proc newFastAsgnStmt(le, ri: PNode): PNode =
result.sons[0] = le
result.sons[1] = ri
proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
proc lowerTupleUnpacking*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
assert n.kind == nkVarTuple
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info)
var temp = newSym(skTemp, getIdent(genPrefix), owner, value.info, g.config.options)
temp.typ = skipTypes(value.typ, abstractInst)
incl(temp.flags, sfFromGeneric)
@@ -61,7 +61,7 @@ proc lowerTupleUnpacking*(n: PNode; owner: PSym): PNode =
result.add newAsgnStmt(tempAsNode, value)
for i in 0 .. n.len-3:
if n.sons[i].kind == nkSym: v.addVar(n.sons[i])
result.add newAsgnStmt(n.sons[i], newTupleAccess(tempAsNode, i))
result.add newAsgnStmt(n.sons[i], newTupleAccess(g, tempAsNode, i))
proc newTupleAccessRaw*(tup: PNode, i: int): PNode =
result = newNodeI(nkBracketExpr, tup.info)
@@ -77,7 +77,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
let value = n.lastSon
result = newNodeI(nkStmtList, n.info)
var temp = newSym(skLet, getIdent("_"), owner, value.info)
var temp = newSym(skLet, getIdent("_"), owner, value.info, owner.options)
var v = newNodeI(nkLetSection, value.info)
let tempAsNode = newSymNode(temp) #newIdentNode(getIdent(genPrefix & $temp.id), value.info)
@@ -95,7 +95,7 @@ proc lowerTupleUnpackingForAsgn*(n: PNode; owner: PSym): PNode =
proc lowerSwap*(n: PNode; owner: PSym): PNode =
result = newNodeI(nkStmtList, n.info)
# note: cannot use 'skTemp' here cause we really need the copy for the VM :-(
var temp = newSym(skVar, getIdent(genPrefix), owner, n.info)
var temp = newSym(skVar, getIdent(genPrefix), owner, n.info, owner.options)
temp.typ = n.sons[1].typ
incl(temp.flags, sfFromGeneric)
@@ -112,16 +112,16 @@ proc lowerSwap*(n: PNode; owner: PSym): PNode =
result.add newFastAsgnStmt(n[1], n[2])
result.add newFastAsgnStmt(n[2], tempAsNode)
proc createObj*(owner: PSym, info: TLineInfo; final=true): PType =
proc createObj*(g: ModuleGraph; owner: PSym, info: TLineInfo; final=true): PType =
result = newType(tyObject, owner)
if final:
rawAddSon(result, nil)
incl result.flags, tfFinal
else:
rawAddSon(result, getCompilerProc("RootObj").typ)
rawAddSon(result, getCompilerProc(g, "RootObj").typ)
result.n = newNodeI(nkRecList, info)
let s = newSym(skType, getIdent("Env_" & info.toFilename),
owner, info)
owner, info, owner.options)
incl s.flags, sfAnon
s.typ = result
result.sym = s
@@ -174,7 +174,8 @@ proc lookupInRecord(n: PNode, id: int): PSym =
proc addField*(obj: PType; s: PSym) =
# because of 'gensym' support, we have to mangle the name with its ID.
# This is hacky but the clean solution is much more complex than it looks.
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info,
s.options)
field.id = -s.id
let t = skipIntLit(s.typ)
field.typ = t
@@ -185,7 +186,8 @@ proc addField*(obj: PType; s: PSym) =
proc addUniqueField*(obj: PType; s: PSym): PSym {.discardable.} =
result = lookupInRecord(obj.n, s.id)
if result == nil:
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info)
var field = newSym(skField, getIdent(s.name.s & $obj.n.len), s.owner, s.info,
s.options)
field.id = -s.id
let t = skipIntLit(s.typ)
field.typ = t
@@ -218,7 +220,7 @@ proc indirectAccess*(a: PNode, b: int, info: TLineInfo): PNode =
#if field == nil:
# echo "FIELD ", b
# debug deref.typ
internalAssert field != nil
assert field != nil
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
addSon(result, deref)
@@ -242,7 +244,7 @@ proc indirectAccess(a: PNode, b: string, info: TLineInfo): PNode =
#if field == nil:
# echo "FIELD ", b
# debug deref.typ
internalAssert field != nil
assert field != nil
addSon(deref, a)
result = newNodeI(nkDotExpr, info)
addSon(result, deref)
@@ -278,12 +280,12 @@ proc genDeref*(n: PNode): PNode =
n.typ.skipTypes(abstractInst).sons[0])
result.add n
proc callCodegenProc*(name: string, arg1: PNode;
proc callCodegenProc*(g: ModuleGraph; name: string, arg1: PNode;
arg2, arg3, optionalArgs: PNode = nil): PNode =
result = newNodeI(nkCall, arg1.info)
let sym = magicsys.getCompilerProc(name)
let sym = magicsys.getCompilerProc(g, name)
if sym == nil:
localError(arg1.info, errSystemNeeds, name)
localError(g.config, arg1.info, "system module needs: " & name)
else:
result.add newSymNode(sym)
result.add arg1
@@ -333,9 +335,10 @@ proc typeNeedsNoDeepCopy(t: PType): bool =
if t.kind in {tyVar, tyLent, tySequence}: t = t.lastSon
result = not containsGarbageCollectedRef(t)
proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
proc addLocalVar(g: ModuleGraph; varSection, varInit: PNode; owner: PSym; typ: PType;
v: PNode; useShallowCopy=false): PSym =
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info)
result = newSym(skTemp, getIdent(genPrefix), owner, varSection.info,
owner.options)
result.typ = typ
incl(result.flags, sfFromGeneric)
@@ -349,7 +352,7 @@ proc addLocalVar(varSection, varInit: PNode; owner: PSym; typ: PType;
varInit.add newFastAsgnStmt(newSymNode(result), v)
else:
let deepCopyCall = newNodeI(nkCall, varInit.info, 3)
deepCopyCall.sons[0] = newSymNode(getSysMagic("deepCopy", mDeepCopy))
deepCopyCall.sons[0] = newSymNode(getSysMagic(g, varSection.info, "deepCopy", mDeepCopy))
deepCopyCall.sons[1] = newSymNode(result)
deepCopyCall.sons[2] = v
varInit.add deepCopyCall
@@ -384,23 +387,23 @@ stmtList:
"""
proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
proc createWrapperProc(g: ModuleGraph; f: PNode; threadParam, argsParam: PSym;
varSection, varInit, call, barrier, fv: PNode;
spawnKind: TSpawnResult): PSym =
var body = newNodeI(nkStmtList, f.info)
var threadLocalBarrier: PSym
if barrier != nil:
var varSection2 = newNodeI(nkVarSection, barrier.info)
threadLocalBarrier = addLocalVar(varSection2, nil, argsParam.owner,
threadLocalBarrier = addLocalVar(g, varSection2, nil, argsParam.owner,
barrier.typ, barrier)
body.add varSection2
body.add callCodegenProc("barrierEnter", threadLocalBarrier.newSymNode)
body.add callCodegenProc(g, "barrierEnter", threadLocalBarrier.newSymNode)
var threadLocalProm: PSym
if spawnKind == srByVar:
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
elif fv != nil:
internalAssert fv.typ.kind == tyGenericInst
threadLocalProm = addLocalVar(varSection, nil, argsParam.owner, fv.typ, fv)
internalAssert g.config, fv.typ.kind == tyGenericInst
threadLocalProm = addLocalVar(g, varSection, nil, argsParam.owner, fv.typ, fv)
body.add varSection
body.add varInit
if fv != nil and spawnKind != srByVar:
@@ -409,30 +412,30 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
"owner", fv.info), threadParam.newSymNode)
body.add callCodegenProc("nimArgsPassingDone", threadParam.newSymNode)
body.add callCodegenProc(g, "nimArgsPassingDone", threadParam.newSymNode)
if spawnKind == srByVar:
body.add newAsgnStmt(genDeref(threadLocalProm.newSymNode), call)
elif fv != nil:
let fk = fv.typ.sons[1].flowVarKind
if fk == fvInvalid:
localError(f.info, "cannot create a flowVar of type: " &
localError(g.config, f.info, "cannot create a flowVar of type: " &
typeToString(fv.typ.sons[1]))
body.add newAsgnStmt(indirectAccess(threadLocalProm.newSymNode,
if fk == fvGC: "data" else: "blob", fv.info), call)
if fk == fvGC:
let incRefCall = newNodeI(nkCall, fv.info, 2)
incRefCall.sons[0] = newSymNode(getSysMagic("GCref", mGCref))
incRefCall.sons[0] = newSymNode(getSysMagic(g, fv.info, "GCref", mGCref))
incRefCall.sons[1] = indirectAccess(threadLocalProm.newSymNode,
"data", fv.info)
body.add incRefCall
if barrier == nil:
# by now 'fv' is shared and thus might have beeen overwritten! we need
# to use the thread-local view instead:
body.add callCodegenProc("nimFlowVarSignal", threadLocalProm.newSymNode)
body.add callCodegenProc(g, "nimFlowVarSignal", threadLocalProm.newSymNode)
else:
body.add call
if barrier != nil:
body.add callCodegenProc("barrierLeave", threadLocalBarrier.newSymNode)
body.add callCodegenProc(g, "barrierLeave", threadLocalBarrier.newSymNode)
var params = newNodeI(nkFormalParams, f.info)
params.add emptyNode
@@ -449,7 +452,8 @@ proc createWrapperProc(f: PNode; threadParam, argsParam: PSym;
t.n.add argsParam.newSymNode
let name = (if f.kind == nkSym: f.sym.name.s else: genPrefix) & "Wrapper"
result = newSym(skProc, getIdent(name), argsParam.owner, f.info)
result = newSym(skProc, getIdent(name), argsParam.owner, f.info,
argsParam.options)
result.ast = newProcNode(nkProcDef, f.info, body, params, newSymNode(result))
result.typ = t
@@ -460,7 +464,7 @@ proc createCastExpr(argsParam: PSym; objType: PType): PNode =
result.typ = newType(tyPtr, objType.owner)
result.typ.rawAddSon(objType)
proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
proc setupArgsForConcurrency(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym,
castExpr, call,
varSection, varInit, result: PNode) =
let formals = n[0].typ.n
@@ -470,17 +474,17 @@ proc setupArgsForConcurrency(n: PNode; objType: PType; scratchObj: PSym,
# 'tyOpenArray':
var argType = n[i].typ.skipTypes(abstractInst)
if i < formals.len and formals[i].typ.kind in {tyVar, tyLent}:
localError(n[i].info, "'spawn'ed function cannot have a 'var' parameter")
localError(g.config, n[i].info, "'spawn'ed function cannot have a 'var' parameter")
#elif containsTyRef(argType):
# localError(n[i].info, "'spawn'ed function cannot refer to 'ref'/closure")
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, objType.owner, n.info)
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[i])
let temp = addLocalVar(varSection, varInit, objType.owner, argType,
let temp = addLocalVar(g, varSection, varInit, objType.owner, argType,
indirectAccess(castExpr, field, n.info))
call.add(newSymNode(temp))
@@ -501,20 +505,20 @@ proc getRoot*(n: PNode): PSym =
if getMagic(n) == mSlice: result = getRoot(n.sons[1])
else: discard
proc newIntLit*(value: BiggestInt): PNode =
proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
result = nkIntLit.newIntNode(value)
result.typ = getSysType(tyInt)
result.typ = getSysType(g, info, tyInt)
proc genHigh*(n: PNode): PNode =
proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray:
result = newIntLit(lastOrd(skipTypes(n.typ, abstractVar)))
result = newIntLit(g, n.info, lastOrd(skipTypes(n.typ, abstractVar)))
else:
result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(tyInt)
result.sons[0] = newSymNode(getSysMagic("high", mHigh))
result.typ = getSysType(g, n.info, tyInt)
result.sons[0] = newSymNode(getSysMagic(g, n.info, "high", mHigh))
result.sons[1] = n
proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
proc setupArgsForParallelism(g: ModuleGraph; n: PNode; objType: PType; scratchObj: PSym;
castExpr, call,
varSection, varInit, result: PNode) =
let formals = n[0].typ.n
@@ -529,16 +533,16 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
# localError(n.info, "'spawn'ed function cannot refer to 'ref'/closure")
let fieldname = if i < formals.len: formals[i].sym.name else: tmpName
var field = newSym(skField, fieldname, objType.owner, n.info)
var field = newSym(skField, fieldname, objType.owner, n.info, g.config.options)
if argType.kind in {tyVarargs, tyOpenArray}:
# important special case: we always create a zero-copy slice:
let slice = newNodeI(nkCall, n.info, 4)
slice.typ = n.typ
slice.sons[0] = newSymNode(createMagic("slice", mSlice))
slice.sons[0].typ = getSysType(tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info)
fieldB.typ = getSysType(tyInt)
slice.sons[0] = newSymNode(createMagic(g, "slice", mSlice))
slice.sons[0].typ = getSysType(g, n.info, tyInt) # fake type
var fieldB = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
fieldB.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldB)
if getMagic(n) == mSlice:
@@ -547,13 +551,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
var fieldA = newSym(skField, tmpName, objType.owner, n.info)
fieldA.typ = getSysType(tyInt)
var fieldA = newSym(skField, tmpName, objType.owner, n.info, g.config.options)
fieldA.typ = getSysType(g, n.info, tyInt)
objType.addField(fieldA)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldA), n[2])
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), n[3])
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldA.typ,
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldA.typ,
indirectAccess(castExpr, fieldA, n.info),
useShallowCopy=true)
slice.sons[2] = threadLocal.newSymNode
@@ -562,13 +566,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = a.typ
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(n))
result.add newFastAsgnStmt(newDotExpr(scratchObj, fieldB), genHigh(g, n))
slice.sons[2] = newIntLit(0)
slice.sons[2] = newIntLit(g, n.info, 0)
# the array itself does not need to go through a thread local variable:
slice.sons[1] = genDeref(indirectAccess(castExpr, field, n.info))
let threadLocal = addLocalVar(varSection,nil, objType.owner, fieldB.typ,
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, fieldB.typ,
indirectAccess(castExpr, fieldB, n.info),
useShallowCopy=true)
slice.sons[3] = threadLocal.newSymNode
@@ -580,7 +584,7 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = a.typ
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), a)
let threadLocal = addLocalVar(varSection,nil, objType.owner, field.typ,
let threadLocal = addLocalVar(g, varSection,nil, objType.owner, field.typ,
indirectAccess(castExpr, field, n.info),
useShallowCopy=true)
call.add(genDeref(threadLocal.newSymNode))
@@ -589,13 +593,13 @@ proc setupArgsForParallelism(n: PNode; objType: PType; scratchObj: PSym;
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n)
let threadLocal = addLocalVar(varSection, varInit,
let threadLocal = addLocalVar(g, varSection, varInit,
objType.owner, field.typ,
indirectAccess(castExpr, field, n.info),
useShallowCopy=true)
call.add(threadLocal.newSymNode)
proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
proc wrapProcForSpawn*(g: ModuleGraph; owner: PSym; spawnExpr: PNode; retType: PType;
barrier, dest: PNode = nil): PNode =
# if 'barrier' != nil, then it is in a 'parallel' section and we
# generate quite different code
@@ -603,35 +607,35 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
let spawnKind = spawnResult(retType, barrier!=nil)
case spawnKind
of srVoid:
internalAssert dest == nil
internalAssert g.config, dest == nil
result = newNodeI(nkStmtList, n.info)
of srFlowVar:
internalAssert dest == nil
internalAssert g.config, dest == nil
result = newNodeIT(nkStmtListExpr, n.info, retType)
of srByVar:
if dest == nil: localError(n.info, "'spawn' must not be discarded")
if dest == nil: localError(g.config, n.info, "'spawn' must not be discarded")
result = newNodeI(nkStmtList, n.info)
if n.kind notin nkCallKinds:
localError(n.info, "'spawn' takes a call expression")
localError(g.config, n.info, "'spawn' takes a call expression")
return
if optThreadAnalysis in gGlobalOptions:
if optThreadAnalysis in g.config.globalOptions:
if {tfThread, tfNoSideEffect} * n[0].typ.flags == {}:
localError(n.info, "'spawn' takes a GC safe call expression")
localError(g.config, n.info, "'spawn' takes a GC safe call expression")
var
threadParam = newSym(skParam, getIdent"thread", owner, n.info)
argsParam = newSym(skParam, getIdent"args", owner, n.info)
threadParam = newSym(skParam, getIdent"thread", owner, n.info, g.config.options)
argsParam = newSym(skParam, getIdent"args", owner, n.info, g.config.options)
block:
let ptrType = getSysType(tyPointer)
let ptrType = getSysType(g, n.info, tyPointer)
threadParam.typ = ptrType
argsParam.typ = ptrType
argsParam.position = 1
var objType = createObj(owner, n.info)
var objType = createObj(g, owner, n.info)
incl(objType.flags, tfFinal)
let castExpr = createCastExpr(argsParam, objType)
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info)
var scratchObj = newSym(skVar, getIdent"scratch", owner, n.info, g.config.options)
block:
scratchObj.typ = objType
incl(scratchObj.flags, sfFromGeneric)
@@ -644,36 +648,36 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
# templates and macros are in fact valid here due to the nature of
# the transformation:
if fn.kind == nkClosure:
localError(n.info, "closure in spawn environment is not allowed")
localError(g.config, n.info, "closure in spawn environment is not allowed")
if not (fn.kind == nkSym and fn.sym.kind in {skProc, skTemplate, skMacro,
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)
var field = newSym(skField, getIdent"fn", owner, n.info, g.config.options)
field.typ = argType
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), n[0])
fn = indirectAccess(castExpr, field, n.info)
elif fn.kind == nkSym and fn.sym.kind == skIterator:
localError(n.info, "iterator in spawn environment is not allowed")
localError(g.config, n.info, "iterator in spawn environment is not allowed")
elif fn.typ.callConv == ccClosure:
localError(n.info, "closure in spawn environment is not allowed")
localError(g.config, n.info, "closure in spawn environment is not allowed")
call.add(fn)
var varSection = newNodeI(nkVarSection, n.info)
var varInit = newNodeI(nkStmtList, n.info)
if barrier.isNil:
setupArgsForConcurrency(n, objType, scratchObj, castExpr, call,
setupArgsForConcurrency(g, n, objType, scratchObj, castExpr, call,
varSection, varInit, result)
else:
setupArgsForParallelism(n, objType, scratchObj, castExpr, call,
setupArgsForParallelism(g, n, objType, scratchObj, castExpr, call,
varSection, varInit, result)
var barrierAsExpr: PNode = nil
if barrier != nil:
let typ = newType(tyPtr, owner)
typ.rawAddSon(magicsys.getCompilerProc("Barrier").typ)
var field = newSym(skField, getIdent"barrier", owner, n.info)
typ.rawAddSon(magicsys.getCompilerProc(g, "Barrier").typ)
var field = newSym(skField, getIdent"barrier", owner, n.info, g.config.options)
field.typ = typ
objType.addField(field)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), barrier)
@@ -681,7 +685,7 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
var fvField, fvAsExpr: PNode = nil
if spawnKind == srFlowVar:
var field = newSym(skField, getIdent"fv", owner, n.info)
var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options)
field.typ = retType
objType.addField(field)
fvField = newDotExpr(scratchObj, field)
@@ -689,20 +693,20 @@ proc wrapProcForSpawn*(owner: PSym; spawnExpr: PNode; retType: PType;
# create flowVar:
result.add newFastAsgnStmt(fvField, callProc(spawnExpr[^1]))
if barrier == nil:
result.add callCodegenProc("nimFlowVarCreateSemaphore", fvField)
result.add callCodegenProc(g, "nimFlowVarCreateSemaphore", fvField)
elif spawnKind == srByVar:
var field = newSym(skField, getIdent"fv", owner, n.info)
var field = newSym(skField, getIdent"fv", owner, n.info, g.config.options)
field.typ = newType(tyPtr, objType.owner)
field.typ.rawAddSon(retType)
objType.addField(field)
fvAsExpr = indirectAccess(castExpr, field, n.info)
result.add newFastAsgnStmt(newDotExpr(scratchObj, field), genAddrOf(dest))
let wrapper = createWrapperProc(fn, threadParam, argsParam,
let wrapper = createWrapperProc(g, fn, threadParam, argsParam,
varSection, varInit, call,
barrierAsExpr, fvAsExpr, spawnKind)
result.add callCodegenProc("nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
result.add callCodegenProc(g, "nimSpawn" & $spawnExpr.len, wrapper.newSymNode,
genAddrOf(scratchObj.newSymNode), nil, spawnExpr)
if spawnKind == srFlowVar: result.add fvField

View File

@@ -10,63 +10,62 @@
# Built-in types and compilerprocs are registered here.
import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread,
modulegraphs
var systemModule*: PSym
export createMagic
var
gSysTypes: array[TTypeKind, PType]
compilerprocs: TStrTable
exposed: TStrTable
proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
proc nilOrSysInt*: PType = gSysTypes[tyInt]
proc registerSysType*(g: ModuleGraph; t: PType) =
if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t
proc registerSysType*(t: PType) =
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
proc newSysType(kind: TTypeKind, size: int): PType =
result = newType(kind, systemModule)
proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result = newType(kind, g.systemModule)
result.size = size
result.align = size.int16
proc getSysSym*(name: string): PSym =
result = strTableGet(systemModule.tab, getIdent(name))
proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
result = strTableGet(g.systemModule.tab, getIdent(name))
if result == nil:
rawMessage(errSystemNeeds, name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, g.systemModule)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc createMagic*(name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m
when false:
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m
let
opNot* = createMagic("not", mNot)
opContains* = createMagic("contains", mInSet)
when false:
let
opNot* = createMagic("not", mNot)
opContains* = createMagic("contains", mInSet)
proc getSysMagic*(name: string, m: TMagic): PSym =
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
var ti: TIdentIter
let id = getIdent(name)
var r = initIdentIter(ti, systemModule.tab, id)
var r = initIdentIter(ti, g.systemModule.tab, id)
while r != nil:
if r.kind == skStub: loadStub(r)
if r.magic == m:
# prefer the tyInt variant:
if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
result = r
r = nextIdentIter(ti, systemModule.tab)
r = nextIdentIter(ti, g.systemModule.tab)
if result != nil: return result
rawMessage(errSystemNeeds, name)
result = newSym(skError, id, systemModule, systemModule.info)
result.typ = newType(tyError, systemModule)
localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, g.systemModule, g.systemModule.info, {})
result.typ = newType(tyError, g.systemModule)
proc sysTypeFromName*(name: string): PType =
result = getSysSym(name).typ
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
result = getSysSym(g, info, name).typ
proc getSysType*(kind: TTypeKind): PType =
result = gSysTypes[kind]
proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
template sysTypeFromName(s: string): untyped = sysTypeFromName(g, info, s)
result = g.sysTypes[kind]
if result == nil:
case kind
of tyInt: result = sysTypeFromName("int")
@@ -88,51 +87,49 @@ proc getSysType*(kind: TTypeKind): PType =
of tyString: result = sysTypeFromName("string")
of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(tyNil, ptrSize)
else: internalError("request for typekind: " & $kind)
gSysTypes[kind] = result
of tyNil: result = newSysType(g, tyNil, ptrSize)
else: internalError(g.config, "request for typekind: " & $kind)
g.sysTypes[kind] = result
if result.kind != kind:
internalError("wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError("type not found: " & $kind)
internalError(g.config, "wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError(g.config, "type not found: " & $kind)
var
intTypeCache: array[-5..64, PType]
proc resetSysTypes*(g: ModuleGraph) =
g.systemModule = nil
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
proc resetSysTypes* =
systemModule = nil
initStrTable(compilerprocs)
initStrTable(exposed)
for i in low(gSysTypes)..high(gSysTypes):
gSysTypes[i] = nil
for i in low(g.intTypeCache)..high(g.intTypeCache):
g.intTypeCache[i] = nil
for i in low(intTypeCache)..high(intTypeCache):
intTypeCache[i] = nil
proc getIntLitType*(literal: PNode): PType =
proc getIntLitType*(g: ModuleGraph; literal: PNode): PType =
# we cache some common integer literal types for performance:
let value = literal.intVal
if value >= low(intTypeCache) and value <= high(intTypeCache):
result = intTypeCache[value.int]
if value >= low(g.intTypeCache) and value <= high(g.intTypeCache):
result = g.intTypeCache[value.int]
if result == nil:
let ti = getSysType(tyInt)
let ti = getSysType(g, literal.info, tyInt)
result = copyType(ti, ti.owner, false)
result.n = literal
intTypeCache[value.int] = result
g.intTypeCache[value.int] = result
else:
let ti = getSysType(tyInt)
let ti = getSysType(g, literal.info, tyInt)
result = copyType(ti, ti.owner, false)
result.n = literal
proc getFloatLitType*(literal: PNode): PType =
proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
# for now we do not cache these:
result = newSysType(tyFloat, size=8)
result = newSysType(g, tyFloat, size=8)
result.n = literal
proc skipIntLit*(t: PType): PType {.inline.} =
if t.n != nil:
if t.kind in {tyInt, tyFloat}:
return getSysType(t.kind)
result = t
if t.n != nil and t.kind in {tyInt, tyFloat}:
result = copyType(t, t.owner, false)
result.n = nil
else:
result = t
proc addSonSkipIntLit*(father, son: PType) =
if isNil(father.sons): father.sons = @[]
@@ -140,60 +137,59 @@ proc addSonSkipIntLit*(father, son: PType) =
add(father.sons, s)
propagateToOwner(father, s)
proc setIntLitType*(result: PNode) =
proc setIntLitType*(g: ModuleGraph; result: PNode) =
let i = result.intVal
case platform.intSize
of 8: result.typ = getIntLitType(result)
of 8: result.typ = getIntLitType(g, result)
of 4:
if i >= low(int32) and i <= high(int32):
result.typ = getIntLitType(result)
result.typ = getIntLitType(g, result)
else:
result.typ = getSysType(tyInt64)
result.typ = getSysType(g, result.info, tyInt64)
of 2:
if i >= low(int16) and i <= high(int16):
result.typ = getIntLitType(result)
result.typ = getIntLitType(g, result)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(tyInt32)
result.typ = getSysType(g, result.info, tyInt32)
else:
result.typ = getSysType(tyInt64)
result.typ = getSysType(g, result.info, tyInt64)
of 1:
# 8 bit CPUs are insane ...
if i >= low(int8) and i <= high(int8):
result.typ = getIntLitType(result)
result.typ = getIntLitType(g, result)
elif i >= low(int16) and i <= high(int16):
result.typ = getSysType(tyInt16)
result.typ = getSysType(g, result.info, tyInt16)
elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(tyInt32)
result.typ = getSysType(g, result.info, tyInt32)
else:
result.typ = getSysType(tyInt64)
else: internalError(result.info, "invalid int size")
proc getCompilerProc*(name: string): PSym =
let ident = getIdent(name)
result = strTableGet(compilerprocs, ident)
if result == nil:
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc registerCompilerProc*(s: PSym) =
strTableAdd(compilerprocs, s)
proc registerNimScriptSymbol*(s: PSym) =
# Nimscript symbols must be al unique:
let conflict = strTableGet(exposed, s.name)
if conflict == nil:
strTableAdd(exposed, s)
result.typ = getSysType(g, result.info, tyInt64)
else:
localError(s.info, "symbol conflicts with other .exportNims symbol at: " &
$conflict.info)
internalError(g.config, result.info, "invalid int size")
proc getNimScriptSymbol*(name: string): PSym =
strTableGet(exposed, getIdent(name))
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
let ident = getIdent(name)
result = strTableGet(g.compilerprocs, ident)
when false:
if result == nil:
result = strTableGet(g.rodCompilerprocs, ident)
if result != nil:
strTableAdd(g.compilerprocs, result)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc resetNimScriptSymbols*() = initStrTable(exposed)
proc registerCompilerProc*(g: ModuleGraph; s: PSym) =
strTableAdd(g.compilerprocs, s)
initStrTable(compilerprocs)
initStrTable(exposed)
proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
# Nimscript symbols must be al unique:
let conflict = strTableGet(g.exposed, s.name)
if conflict == nil:
strTableAdd(g.exposed, s)
else:
localError(g.config, s.info,
"symbol conflicts with other .exportNims symbol at: " & $conflict.info)
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)

View File

@@ -16,12 +16,12 @@ import
cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
docgen2, service, parser, modules, ccgutils, sigmatch, ropes,
modulegraphs, tables, rod
modulegraphs, tables, rod, configuration
from magicsys import systemModule, resetSysTypes
from magicsys import resetSysTypes
proc rodPass =
if gSymbolFiles in {enabledSf, writeOnlySf}:
proc rodPass(g: ModuleGraph) =
if g.config.symbolFiles in {enabledSf, writeOnlySf}:
registerPass(rodwritePass)
proc codegenPass =
@@ -46,54 +46,55 @@ proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
registerPass(gendependPass)
#registerPass(cleanupPass)
compileProject(graph, cache)
writeDepsFile(graph, gProjectFull)
generateDot(gProjectFull)
execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
' ' & changeFileExt(gProjectFull, "dot"))
let project = graph.config.projectFull
writeDepsFile(graph, project)
generateDot(project)
execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") &
' ' & changeFileExt(project, "dot"))
proc commandCheck(graph: ModuleGraph; cache: IdentCache) =
msgs.gErrorMax = high(int) # do not stop after first error
defineSymbol("nimcheck")
graph.config.errorMax = high(int) # do not stop after first error
defineSymbol(graph.config.symbols, "nimcheck")
semanticPasses() # use an empty backend for semantic checking only
rodPass()
rodPass(graph)
compileProject(graph, cache)
proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) =
msgs.gErrorMax = high(int) # do not stop after first error
graph.config.errorMax = high(int) # do not stop after first error
semanticPasses()
if json: registerPass(docgen2JsonPass)
else: registerPass(docgen2Pass)
#registerPass(cleanupPass())
compileProject(graph, cache)
finishDoc2Pass(gProjectName)
finishDoc2Pass(graph.config.projectName)
proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
extccomp.initVars()
let conf = graph.config
extccomp.initVars(conf)
semanticPasses()
registerPass(cgenPass)
rodPass()
rodPass(graph)
#registerPass(cleanupPass())
compileProject(graph, cache)
cgenWriteModules(graph.backend, graph.config)
if gCmd != cmdRun:
let proj = changeFileExt(gProjectFull, "")
extccomp.callCCompiler(proj)
extccomp.writeJsonBuildInstructions(proj)
if optGenScript in gGlobalOptions:
writeDepsFile(graph, toGeneratedFile(proj, ""))
cgenWriteModules(graph.backend, conf)
if conf.cmd != cmdRun:
let proj = changeFileExt(conf.projectFull, "")
extccomp.callCCompiler(conf, proj)
extccomp.writeJsonBuildInstructions(conf, proj)
if optGenScript in graph.config.globalOptions:
writeDepsFile(graph, toGeneratedFile(conf, proj, ""))
proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) =
let proj = changeFileExt(gProjectFull, "")
extccomp.runJsonBuildInstructions(proj)
let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj)
proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
#incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS)
#initDefines()
defineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("ecmascript") # For backward compatibility
defineSymbol("js")
defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
defineSymbol(graph.config.symbols, "js")
semanticPasses()
registerPass(JSgenPass)
compileProject(graph, cache)
@@ -101,19 +102,19 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
#incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM)
initDefines()
defineSymbol("nimscript")
when hasFFI: defineSymbol("nimffi")
initDefines(graph.config.symbols)
defineSymbol(graph.config.symbols, "nimscript")
when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(evalPass)
proc commandInteractive(graph: ModuleGraph; cache: IdentCache) =
msgs.gErrorMax = high(int) # do not stop after first error
graph.config.errorMax = high(int) # do not stop after first error
interactivePasses(graph, cache)
compileSystemModule(graph, cache)
if commandArgs.len > 0:
discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {})
if graph.config.commandArgs.len > 0:
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), cache, {})
else:
var m = graph.makeStdinModule()
incl(m.flags, sfMainModule)
@@ -125,7 +126,7 @@ proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache)
carryPasses(graph, nodes, module, cache, evalPasses)
proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
if systemModule == nil:
if graph.systemModule == nil:
interactivePasses(graph, cache)
compileSystemModule(graph, cache)
let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
@@ -133,7 +134,7 @@ proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
makeStdinModule(graph), cache)
proc commandScan(cache: IdentCache, config: ConfigRef) =
var f = addFileExt(mainCommandArg(), NimExt)
var f = addFileExt(mainCommandArg(config), NimExt)
var stream = llStreamOpen(f, fmRead)
if stream != nil:
var
@@ -143,159 +144,153 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
openLexer(L, f, stream, cache, config)
while true:
rawGetTok(L, tok)
printTok(tok)
printTok(config, tok)
if tok.tokType == tkEof: break
closeLexer(L)
else:
rawMessage(errCannotOpenFile, f)
rawMessage(config, errGenerated, "cannot open file: " & f)
const
SimulateCaasMemReset = false
PrintRopeCacheStats = false
proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
when SimulateCaasMemReset:
gGlobalOptions.incl(optCaasEnabled)
let conf = graph.config
setupModuleCache()
# In "nim serve" scenario, each command must reset the registered passes
clearPasses()
gLastCmdTime = epochTime()
searchPaths.add(options.libpath)
when false: # gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
conf.lastCmdTime = epochTime()
conf.searchPaths.add(conf.libpath)
setId(100)
case command.normalize
case conf.command.normalize
of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently
gCmd = cmdCompileToC
conf.cmd = cmdCompileToC
commandCompileToC(graph, cache)
of "cpp", "compiletocpp":
gCmd = cmdCompileToCpp
defineSymbol("cpp")
conf.cmd = cmdCompileToCpp
defineSymbol(graph.config.symbols, "cpp")
commandCompileToC(graph, cache)
of "objc", "compiletooc":
gCmd = cmdCompileToOC
defineSymbol("objc")
conf.cmd = cmdCompileToOC
defineSymbol(graph.config.symbols, "objc")
commandCompileToC(graph, cache)
of "run":
gCmd = cmdRun
conf.cmd = cmdRun
when hasTinyCBackend:
extccomp.setCC("tcc")
commandCompileToC(graph, cache)
else:
rawMessage(errInvalidCommandX, command)
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
of "js", "compiletojs":
gCmd = cmdCompileToJS
conf.cmd = cmdCompileToJS
commandCompileToJS(graph, cache)
of "doc0":
wantMainModule()
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
commandDoc()
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
commandDoc(conf)
of "doc2", "doc":
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
defineSymbol("nimdoc")
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, false)
of "rst2html":
gCmd = cmdRst2html
loadConfigs(DocConfig, cache)
commandRst2Html()
conf.cmd = cmdRst2html
loadConfigs(DocConfig, cache, conf)
commandRst2Html(conf)
of "rst2tex":
gCmd = cmdRst2tex
loadConfigs(DocTexConfig, cache)
commandRst2TeX()
conf.cmd = cmdRst2tex
loadConfigs(DocTexConfig, cache, conf)
commandRst2TeX(conf)
of "jsondoc0":
wantMainModule()
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
wantMainModule()
defineSymbol("nimdoc")
commandJson()
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc")
commandJson(conf)
of "jsondoc2", "jsondoc":
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
wantMainModule()
defineSymbol("nimdoc")
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, true)
of "ctags":
wantMainModule()
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
wantMainModule()
defineSymbol("nimdoc")
commandTags()
wantMainModule(conf)
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc")
commandTags(conf)
of "buildindex":
gCmd = cmdDoc
loadConfigs(DocConfig, cache)
commandBuildIndex()
conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf)
commandBuildIndex(conf)
of "gendepend":
gCmd = cmdGenDepend
conf.cmd = cmdGenDepend
commandGenDepend(graph, cache)
of "dump":
gCmd = cmdDump
if getConfigVar("dump.format") == "json":
wantMainModule()
conf.cmd = cmdDump
if getConfigVar(conf, "dump.format") == "json":
wantMainModule(conf)
var definedSymbols = newJArray()
for s in definedSymbolNames(): definedSymbols.elems.add(%s)
for s in definedSymbolNames(conf.symbols): definedSymbols.elems.add(%s)
var libpaths = newJArray()
for dir in searchPaths: libpaths.elems.add(%dir)
for dir in conf.searchPaths: libpaths.elems.add(%dir)
var dumpdata = % [
(key: "version", val: %VersionAsString),
(key: "project_path", val: %gProjectFull),
(key: "project_path", val: %conf.projectFull),
(key: "defined_symbols", val: definedSymbols),
(key: "lib_paths", val: libpaths)
]
msgWriteln($dumpdata, {msgStdout, msgSkipHook})
msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook})
else:
msgWriteln("-- list of currently defined symbols --",
msgWriteln(conf, "-- list of currently defined symbols --",
{msgStdout, msgSkipHook})
for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook})
msgWriteln("-- end of list --", {msgStdout, msgSkipHook})
for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook})
msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook})
for it in searchPaths: msgWriteln(it)
for it in conf.searchPaths: msgWriteln(conf, it)
of "check":
gCmd = cmdCheck
conf.cmd = cmdCheck
commandCheck(graph, cache)
of "parse":
gCmd = cmdParse
wantMainModule()
discard parseFile(FileIndex gProjectMainIdx, cache, graph.config)
conf.cmd = cmdParse
wantMainModule(conf)
discard parseFile(FileIndex conf.projectMainIdx, cache, conf)
of "scan":
gCmd = cmdScan
wantMainModule()
commandScan(cache, graph.config)
msgWriteln("Beware: Indentation tokens depend on the parser's state!")
conf.cmd = cmdScan
wantMainModule(conf)
commandScan(cache, conf)
msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of "secret":
gCmd = cmdInteractive
conf.cmd = cmdInteractive
commandInteractive(graph, cache)
of "e":
commandEval(graph, cache, mainCommandArg())
commandEval(graph, cache, mainCommandArg(conf))
of "nop", "help":
# prevent the "success" message:
gCmd = cmdDump
conf.cmd = cmdDump
of "jsonscript":
gCmd = cmdJsonScript
conf.cmd = cmdJsonScript
commandJsonScript(graph, cache)
else:
rawMessage(errInvalidCommandX, command)
rawMessage(conf, errGenerated, "invalid command: " & conf.command)
if msgs.gErrorCounter == 0 and
gCmd notin {cmdInterpret, cmdRun, cmdDump}:
if conf.errorCounter == 0 and
conf.cmd notin {cmdInterpret, cmdRun, cmdDump}:
when declared(system.getMaxMem):
let usedMem = formatSize(getMaxMem()) & " peakmem"
else:
let usedMem = formatSize(getTotalMem())
rawMessage(hintSuccessX, [$graph.config.linesCompiled,
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
rawMessage(conf, hintSuccessX, [$conf.linesCompiled,
formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3),
usedMem,
if condSyms.isDefined("release"): "Release Build"
if isDefined(conf, "release"): "Release Build"
else: "Debug Build"])
when PrintRopeCacheStats:
@@ -306,9 +301,6 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
ffDecimal, 3)
when SimulateCaasMemReset:
resetMemory()
resetAttributes(conf)
resetAttributes()
proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
#proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())

View File

@@ -25,7 +25,7 @@
## - Its dependent module stays the same.
##
import ast, intsets, tables, options, rod, msgs, hashes
import ast, intsets, tables, options, rod, msgs, hashes, idents
type
ModuleGraph* = ref object
@@ -44,6 +44,12 @@ type
usageSym*: PSym # for nimsuggest
owners*: seq[PSym]
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable
exposed*: TStrTable
intTypeCache*: array[-5..64, PType]
opContains*, opNot*: PSym
proc hash*(x: FileIndex): Hash {.borrow.}
@@ -52,6 +58,10 @@ proc hash*(x: FileIndex): Hash {.borrow.}
proc stopCompile*(g: ModuleGraph): bool {.inline.} =
result = doStopCompile != nil and doStopCompile()
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo(), {})
result.magic = m
proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
result = ModuleGraph()
initStrTable(result.packageSyms)
@@ -65,6 +75,10 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
result.config = config
result.owners = @[]
result.methods = @[]
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
result.opNot = createMagic(result, "not", mNot)
result.opContains = createMagic(result, "contains", mInSet)
proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms)
@@ -75,6 +89,8 @@ proc resetAllModules*(g: ModuleGraph) =
usageSym = nil
owners = @[]
methods = @[]
initStrTable(compilerprocs)
initStrTable(exposed)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:

View File

@@ -113,16 +113,16 @@ when false:
localError(pkg.info, "package name must be an identifier or string literal")
result = ""
proc getModuleName*(n: PNode): string =
proc getModuleName*(conf: ConfigRef; n: PNode): string =
# This returns a short relative module name without the nim extension
# e.g. like "system", "importer" or "somepath/module"
# The proc won't perform any checks that the path is actually valid
case n.kind
of nkStrLit, nkRStrLit, nkTripleStrLit:
try:
result = pathSubs(n.strVal, n.info.toFullPath().splitFile().dir)
result = pathSubs(conf, n.strVal, n.info.toFullPath().splitFile().dir)
except ValueError:
localError(n.info, "invalid path: " & n.strVal)
localError(conf, n.info, "invalid path: " & n.strVal)
result = n.strVal
of nkIdent:
result = n.ident.s
@@ -137,7 +137,7 @@ proc getModuleName*(n: PNode): string =
n.sons[0] = n.sons[1]
n.sons[1] = n.sons[2]
n.sons.setLen(2)
return getModuleName(n.sons[0])
return getModuleName(conf, n.sons[0])
when false:
if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$":
if n0.kind == nkIdent and n0.ident.s == "/":
@@ -146,16 +146,16 @@ proc getModuleName*(n: PNode): string =
localError(n.info, "only '/' supported with $package notation")
result = ""
else:
let modname = getModuleName(n[2])
let modname = getModuleName(conf, n[2])
if $n1 == "std":
template attempt(a) =
let x = addFileExt(a, "nim")
if fileExists(x): return x
for candidate in stdlibDirs:
attempt(options.libpath / candidate / modname)
attempt(conf.libpath / candidate / modname)
# hacky way to implement 'x / y /../ z':
result = getModuleName(n1)
result = getModuleName(conf, n1)
result.add renderTree(n0, {renderNoComments})
result.add modname
of nkPrefix:
@@ -169,19 +169,19 @@ proc getModuleName*(n: PNode): string =
of nkDotExpr:
result = renderTree(n, {renderNoComments}).replace(".", "/")
of nkImportAs:
result = getModuleName(n.sons[0])
result = getModuleName(conf, n.sons[0])
else:
localError(n.info, errGenerated, "invalid module name: '$1'" % n.renderTree)
localError(conf, n.info, "invalid module name: '$1'" % n.renderTree)
result = ""
proc checkModuleName*(n: PNode; doLocalError=true): FileIndex =
proc checkModuleName*(conf: ConfigRef; n: PNode; doLocalError=true): FileIndex =
# This returns the full canonical path for a given module import
let modulename = n.getModuleName
let fullPath = findModule(modulename, n.info.toFullPath)
let modulename = getModuleName(conf, n)
let fullPath = findModule(conf, modulename, n.info.toFullPath)
if fullPath.len == 0:
if doLocalError:
let m = if modulename.len > 0: modulename else: $n
localError(n.info, errCannotOpenFile, m)
localError(conf, n.info, "cannot open file: " & m)
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
result = fileInfoIdx(conf, fullPath)

View File

@@ -11,10 +11,11 @@
import
ast, astalgo, magicsys, std / sha1, rodread, msgs, cgendata, sigmatch, options,
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod
idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs, rod,
configuration
proc resetSystemArtifacts*() =
magicsys.resetSysTypes()
proc resetSystemArtifacts*(g: ModuleGraph) =
magicsys.resetSysTypes(g)
proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
@@ -25,11 +26,11 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
let filename = fileIdx.toFullPath
result.name = getIdent(splitFile(filename).name)
if not isNimIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
rawMessage(graph.config, errGenerated, "invalid module name: " & result.name.s)
result.info = newLineInfo(fileIdx, 1, 1)
let
pck = getPackageName(filename)
pck = getPackageName(graph.config, filename)
pck2 = if pck.len > 0: pck else: "unknown"
pack = getIdent(pck2)
var packSym = graph.packageSyms.strTableGet(pack)
@@ -49,7 +50,7 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
strTableAdd(result.tab, result) # a module knows itself
let existing = strTableGet(packSym.tab, result.name)
if existing != nil and existing.info.fileIndex != result.info.fileIndex:
localError(result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
localError(graph.config, result.info, "module names need to be unique per Nimble package; module clashes with " & existing.info.fileIndex.toFullPath)
# strTableIncl() for error corrections:
discard strTableIncl(packSym.tab, result)
@@ -65,7 +66,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
gMainPackageId = result.owner.id
when false:
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
if conf.cmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, cache)
if result.id < 0:
internalError("handleSymbolFile should have set the module's ID")
@@ -74,7 +75,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
discard
result.id = getModuleId(fileIdx, toFullPath(fileIdx))
discard processModule(graph, result,
if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil,
rd, cache)
#if optCaasEnabled in gGlobalOptions:
# gMemCacheData[fileIdx].needsRecompile = Recompiled
@@ -85,7 +86,7 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
initStrTable(result.tab)
result.ast = nil
discard processModule(graph, result,
if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil,
nil, cache)
graph.markClientsDirty(fileIdx)
when false:
@@ -97,13 +98,15 @@ proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, f
proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
cache: IdentCache): PSym {.procvar.} =
# this is called by the semantic checking phase
assert graph.config != nil
result = compileModule(graph, fileIdx, cache, {})
graph.addDep(s, fileIdx)
#if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s)
# restore the notes for outer module:
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
else: ForeignPackageNotes
graph.config.notes =
if s.owner.id == gMainPackageId: graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
cache: IdentCache): PNode {.procvar.} =
@@ -112,23 +115,24 @@ proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
graph.addIncludeDep(s.position.FileIndex, fileIdx)
proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
if magicsys.systemModule == nil:
systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
if graph.systemModule == nil:
systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
discard graph.compileModule(systemFileIdx, cache, {sfSystemModule})
proc wantMainModule* =
if gProjectFull.len == 0:
fatal(gCmdLineInfo, errCommandExpectsFilename)
gProjectMainIdx = int32 addFileExt(gProjectFull, NimExt).fileInfoIdx
proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.len == 0:
fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename")
conf.projectMainIdx = int32 fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
proc compileProject*(graph: ModuleGraph; cache: IdentCache;
projectFileIdx = InvalidFileIDX) =
wantMainModule()
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(gProjectMainIdx) else: projectFileIdx
let conf = graph.config
wantMainModule(conf)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim")
let projectFile = if projectFileIdx == InvalidFileIDX: FileIndex(conf.projectMainIdx) else: projectFileIdx
graph.importStack.add projectFile
if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
@@ -137,7 +141,7 @@ proc compileProject*(graph: ModuleGraph; cache: IdentCache;
discard graph.compileModule(projectFile, cache, {sfMainModule})
proc makeModule*(graph: ModuleGraph; filename: string): PSym =
result = graph.newModule(fileInfoIdx filename)
result = graph.newModule(fileInfoIdx(graph.config, filename))
result.id = getID()
proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin"

View File

@@ -8,481 +8,13 @@
#
import
options, strutils, os, tables, ropes, platform, terminal, macros
options, strutils, os, tables, ropes, platform, terminal, macros,
configuration
const
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
#type
# MsgConfig* = ref object of RootObj
type
TMsgKind* = enum
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
errStringLiteralExpected,
errIntLiteralExpected, errInvalidCharacterConstant,
errClosingTripleQuoteExpected, errClosingQuoteExpected,
errTabulatorsAreNotAllowed, errInvalidToken,
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
errOperatorExpected, errTokenExpected,
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
errExceptionAlreadyHandled,
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound,
errNoneBoehmRefcExpectedButXFound,
errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
errExprExpected, errUndeclaredField,
errUndeclaredRoutine, errUseQualifier,
errTypeExpected,
errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
errConstantDivisionByZero, errOrdinalTypeExpected,
errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected,
errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
errMagicOnlyInSystem, errPowerOfTwoExpected,
errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
errVarForOutParamNeededX,
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
errAmbiguousCallXYZ, errWrongNumberOfArguments,
errWrongNumberOfArgumentsInCall,
errMissingGenericParamsForTemplate,
errXCannotBePassedToProcVar,
errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
errInvalidOrderInArrayConstructor,
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
errXNotAllowedHere, errInvalidControlFlowX,
errXisNoType, errCircumNeedsPointer, errInvalidExpression,
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
errNamedExprNotAllowed, errXExpectsOneTypeParam,
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
errNoReturnTypeDeclared,
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
errXNeedsParamObjectType,
errTemplateInstantiationTooNested, errMacroInstantiationTooNested,
errInstantiationFrom,
errInvalidIndexValueForTuple, errCommandExpectsFilename,
errMainModuleMustBeSpecified,
errXExpected,
errTIsNotAConcreteType,
errCastToANonConcreteType,
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
errMacroBodyDependsOnGenericTypes,
errDestructorNotGenericEnough,
errInlineIteratorsAsProcParams,
errXExpectsTwoArguments,
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
errXCannotBeClosure, errXMustBeCompileTime,
errCannotInferTypeOfTheLiteral,
errCannotInferReturnType,
errCannotInferStaticParam,
errGenericLambdaNotAllowed,
errProcHasNoConcreteType,
errCompilerDoesntSupportTarget,
errInOutFlagNotExtern,
errUser,
warnCannotOpenFile,
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
warnDeprecated, warnConfigDeprecated,
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
warnUnknownSubstitutionX, warnLanguageXNotSupported,
warnFieldXNotSupported, warnCommentXIgnored,
warnTypelessParam,
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
warnEachIdentIsTuple, warnShadowIdent,
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
warnInconsistentSpacing, warnUser,
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue, hintName, hintPattern,
hintExecuting, hintLinking, hintDependency,
hintSource, hintPerformance, hintStackTrace, hintGCStats,
hintUser, hintUserRaw
const
MsgKindToStr*: array[TMsgKind, string] = [
errUnknown: "unknown error",
errInternal: "internal error: $1",
errIllFormedAstX: "illformed AST: $1",
errCannotOpenFile: "cannot open '$1'",
errGenerated: "$1",
errStringLiteralExpected: "string literal expected",
errIntLiteralExpected: "integer literal expected",
errInvalidCharacterConstant: "invalid character constant",
errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
errClosingQuoteExpected: "closing \" expected",
errTabulatorsAreNotAllowed: "tabulators are not allowed",
errInvalidToken: "invalid token: $1",
errInvalidNumber: "$1 is not a valid number",
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
errNumberOutOfRange: "number $1 out of valid range",
errNnotAllowedInCharacter: "\\n not allowed in character literal",
errClosingBracketExpected: "closing ']' expected, but end of file reached",
errMissingFinalQuote: "missing final ' for character literal",
errIdentifierExpected: "identifier expected, but found '$1'",
errNewlineExpected: "newline expected, but found '$1'",
errInvalidModuleName: "invalid module name: '$1'",
errOperatorExpected: "operator expected, but found '$1'",
errTokenExpected: "'$1' expected",
errRecursiveDependencyX: "recursive dependency: '$1'",
errOnOrOffExpected: "'on' or 'off' expected",
errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
errInvalidPragma: "invalid pragma",
errUnknownPragma: "unknown pragma: '$1'",
errInvalidDirectiveX: "invalid directive: '$1'",
errAtPopWithoutPush: "'pop' without a 'push' pragma",
errEmptyAsm: "empty asm statement",
errInvalidIndentation: "invalid indentation",
errExceptionAlreadyHandled: "exception already handled",
errYieldNotAllowedHere: "'yield' only allowed in an iterator",
errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions",
errCannotReturnExpr: "current routine cannot return an expression",
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
errAttemptToRedefine: "redefinition of '$1'",
errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
errStmtExpected: "statement expected",
errInvalidLabel: "'$1' is no label",
errInvalidCmdLineOption: "invalid command line option: '$1'",
errCmdLineArgExpected: "argument for command line option expected: '$1'",
errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
errInvalidVarSubstitution: "invalid variable substitution in '$1'",
errUnknownVar: "unknown variable: '$1'",
errUnknownCcompiler: "unknown C compiler: '$1'",
errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
errUnknownOS: "unknown OS: '$1'",
errUnknownCPU: "unknown CPU: '$1'",
errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
errInvalidMultipleAsgn: "multiple assignment is not allowed",
errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
errExprExpected: "expression expected, but found '$1'",
errUndeclaredField: "undeclared field: '$1'",
errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
errTypeExpected: "type expected",
errSystemNeeds: "system module needs '$1'",
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
errNotOverloadable: "overloaded '$1' leads to ambiguous calls",
errInvalidArgForX: "invalid argument for '$1'",
errStmtHasNoEffect: "statement has no effect",
errXExpectsTypeOrValue: "'$1' expects a type or value",
errXExpectsArrayType: "'$1' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: "division by zero",
errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: "over- or underflow",
errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely",
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
errUndeclaredFieldX: "undeclared field: '$1'",
errNilAccess: "attempt to access a nil address",
errIndexOutOfBounds: "index out of bounds",
errIndexTypesDoNotMatch: "index types do not match",
errBracketsInvalidForType: "'[]' operator invalid for this type",
errValueOutOfSetBounds: "value out of set bounds",
errFieldInitTwice: "field initialized twice: '$1'",
errFieldNotInit: "field '$1' not initialized",
errExprXCannotBeCalled: "expression '$1' cannot be called",
errExprHasNoType: "expression has no type",
errExprXHasNoType: "expression '$1' has no type (or is ambiguous)",
errCastNotInSafeMode: "'cast' not allowed in safe mode",
errExprCannotBeCastToX: "expression cannot be cast to $1",
errCommaOrParRiExpected: "',' or ')' expected",
errCurlyLeOrParLeExpected: "'{' or '(' expected",
errSectionExpected: "section ('type', 'proc', etc.) expected",
errRangeExpected: "range expected",
errMagicOnlyInSystem: "'magic' only allowed in system module",
errPowerOfTwoExpected: "power of two expected",
errStringMayNotBeEmpty: "string literal may not be empty",
errCallConvExpected: "calling convention expected",
errProcOnlyOneCallConv: "a proc can only have one calling convention",
errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
errExprMustBeBool: "expression must be of type 'bool'",
errConstExprExpected: "constant expression expected",
errDuplicateCaseLabel: "duplicate case label",
errRangeIsEmpty: "range is empty",
errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
errSelectorMustBeOrdinal: "selector must be of an ordinal type",
errOrdXMustNotBeNegative: "ord($1) must not be negative",
errLenXinvalid: "len($1) must be less than 32768",
errWrongNumberOfVariables: "wrong number of variables",
errExprCannotBeRaised: "only a 'ref object' can be raised",
errBreakOnlyInLoop: "'break' only allowed in loop construct",
errTypeXhasUnknownSize: "type '$1' has unknown size",
errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
errConstNeedsValue: "a constant needs a value",
errResultCannotBeOpenArray: "the result type cannot be on open array",
errSizeTooBig: "computing the type's size produced an overflow",
errSetTooBig: "set is too large",
errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
errInheritanceOnlyWithEnums: "inheritance only works with an enum",
errIllegalRecursionInTypeX: "illegal recursion in type '$1'",
errCannotInstantiateX: "cannot instantiate: '$1'",
errExprHasNoAddress: "expression has no address",
errXStackEscape: "address of '$1' may not escape its stack frame",
errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable",
errPureTypeMismatch: "type mismatch",
errTypeMismatch: "type mismatch: got <",
errButExpected: "but expected one of: ",
errButExpectedX: "but expected '$1'",
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
errWrongNumberOfArguments: "wrong number of arguments",
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar",
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
errImplOfXNotAllowed: "implementation of '$1' is not allowed",
errImplOfXexpected: "implementation of '$1' expected",
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
errDiscardValueX: "value of type '$1' has to be discarded",
errInvalidDiscard: "statement returns no value that can be discarded",
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
errCannotBindXTwice: "cannot bind parameter '$1' twice",
errInvalidOrderInArrayConstructor: "invalid order in array constructor",
errInvalidOrderInEnumX: "invalid order in enum '$1'",
errEnumXHasHoles: "enum '$1' has holes",
errExceptExpected: "'except' or 'finally' expected",
errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
errOptionExpected: "option expected, but found '$1'",
errXisNoLabel: "'$1' is not a label",
errNotAllCasesCovered: "not all cases are covered",
errUnknownSubstitionVar: "unknown substitution variable: '$1'",
errComplexStmtRequiresInd: "complex statement requires indentation",
errXisNotCallable: "'$1' is not callable",
errNoPragmasAllowedForX: "no pragmas allowed for $1",
errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
errInvalidParamKindX: "invalid param kind: '$1'",
errDefaultArgumentInvalid: "default argument invalid",
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
errNoReturnTypeForX: "no return type allowed for $1",
errConvNeedsOneArg: "a type conversion needs exactly one argument",
errInvalidPragmaX: "invalid pragma: $1",
errXNotAllowedHere: "$1 not allowed here",
errInvalidControlFlowX: "invalid control flow: $1",
errXisNoType: "invalid type: '$1'",
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
errInvalidExpression: "invalid expression",
errInvalidExpressionX: "invalid expression: '$1'",
errEnumHasNoValueX: "enum has no value '$1'",
errNamedExprExpected: "named expression expected",
errNamedExprNotAllowed: "named expression not allowed here",
errXExpectsOneTypeParam: "'$1' expects one type parameter",
errArrayExpectsTwoTypeParams: "array expects two type parameters",
errInvalidVisibilityX: "invalid visibility: '$1'",
errInitHereNotAllowed: "initialization not allowed here",
errXCannotBeAssignedTo: "'$1' cannot be assigned to",
errIteratorNotAllowed: "iterators can only be defined at the module's top level",
errXNeedsReturnType: "$1 needs a return type",
errNoReturnTypeDeclared: "no return type declared",
errNoCommand: "no command given",
errInvalidCommandX: "invalid command: '$1'",
errXOnlyAtModuleScope: "'$1' is only allowed at top level",
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
errInstantiationFrom: "template/generic instantiation from here",
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
errCommandExpectsFilename: "command expects a filename argument",
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
errXExpected: "'$1' expected",
errTIsNotAConcreteType: "'$1' is not a concrete type.",
errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
errInvalidSectionStart: "invalid section start",
errGridTableNotImplemented: "grid table is not implemented",
errGeneralParseError: "general parse error",
errNewSectionExpected: "new section expected",
errWhitespaceExpected: "whitespace expected, got '$1'",
errXisNoValidIndexFile: "'$1' is no valid index file",
errCannotRenderX: "cannot render reStructuredText element '$1'",
errVarVarTypeNotAllowed: "type 'var var' is not allowed",
errInstantiateXExplicitly: "instantiate '$1' explicitly",
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type",
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
"A destructor must be associated will all instantiations of a generic type",
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
"templates, macros and other inline iterators",
errXExpectsTwoArguments: "'$1' expects two arguments",
errXExpectsObjectTypes: "'$1' expects object types",
errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
errTooManyIterations: "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler",
errCannotInterpretNodeX: "cannot evaluate '$1'",
errFieldXNotFound: "field '$1' cannot be found",
errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
errAssertionFailed: "assertion failed",
errCannotGenerateCodeForX: "cannot generate code for '$1'",
errXRequiresOneArgument: "$1 requires one parameter",
errUnhandledExceptionX: "unhandled exception: $1",
errCyclicTree: "macro returned a cyclic abstract syntax tree",
errXisNoMacroOrTemplate: "'$1' is no macro or template",
errXhasSideEffects: "'$1' can have side effects",
errIteratorExpected: "iterator within for loop context expected",
errLetNeedsInit: "'let' symbol requires an initialization",
errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread",
errWrongSymbolX: "usage of '$1' is a user-defined error",
errIllegalCaptureX: "illegal capture '$1'",
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
errCannotInferReturnType: "cannot infer the return type of the proc",
errCannotInferStaticParam: "cannot infer the value of the static param `$1`",
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
"it is used as an operand to another routine and the types " &
"of the generic paramers can be inferred from the expected signature.",
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target",
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
errUser: "$1",
warnCannotOpenFile: "cannot open '$1'",
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
warnXIsNeverRead: "'$1' is never read",
warnXmightNotBeenInit: "'$1' might not have been initialized",
warnDeprecated: "$1 is deprecated",
warnConfigDeprecated: "config file '$1' is deprecated",
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
warnRedefinitionOfLabel: "redefinition of label '$1'",
warnUnknownSubstitutionX: "unknown substitution '$1'",
warnLanguageXNotSupported: "language '$1' not supported",
warnFieldXNotSupported: "field '$1' not supported",
warnCommentXIgnored: "comment '$1' ignored",
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
warnWriteToForeignHeap: "write to foreign heap",
warnUnsafeCode: "unsafe code: '$1'",
warnEachIdentIsTuple: "each identifier is a tuple",
warnShadowIdent: "shadowed identifier: '$1'",
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
warnProveField: "cannot prove that field '$1' is accessible",
warnProveIndex: "cannot prove index '$1' is valid",
warnGcUnsafe: "not GC-safe: '$1'",
warnGcUnsafe2: "$1",
warnUninit: "'$1' might not have been initialized",
warnGcMem: "'$1' uses GC'ed memory",
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
warnLockLevel: "$1",
warnResultShadowed: "Special variable 'result' is shadowed.",
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
warnUser: "$1",
hintSuccess: "operation successful",
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
hintLineTooLong: "line too long",
hintXDeclaredButNotUsed: "'$1' is declared but not used",
hintConvToBaseNotNeeded: "conversion to base object is not needed",
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
hintExprAlwaysX: "expression evaluates always to '$1'",
hintQuitCalled: "quit() called",
hintProcessing: "$1",
hintCodeBegin: "generated code listing:",
hintCodeEnd: "end of listing",
hintConf: "used config file '$1'",
hintPath: "added path: '$1'",
hintConditionAlwaysTrue: "condition is always true: '$1'",
hintName: "name should be: '$1'",
hintPattern: "$1",
hintExecuting: "$1",
hintLinking: "",
hintDependency: "$1",
hintSource: "$1",
hintPerformance: "$1",
hintStackTrace: "$1",
hintGCStats: "$1",
hintUser: "$1",
hintUserRaw: "$1"]
const
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
"XIsNeverRead", "XmightNotBeenInit",
"Deprecated", "ConfigDeprecated",
"SmallLshouldNotBeUsed", "UnknownMagic",
"RedefinitionOfLabel", "UnknownSubstitutionX",
"LanguageXNotSupported", "FieldXNotSupported",
"CommentXIgnored",
"TypelessParam", "UseBase", "WriteToForeignHeap",
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
"Spacing", "User"]
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
"Source", "Performance", "StackTrace", "GCStats",
"User", "UserRaw"]
const
fatalMin* = errUnknown
fatalMax* = errInternal
errMin* = errUnknown
errMax* = errUser
warnMin* = warnCannotOpenFile
warnMax* = pred(hintSuccess)
hintMin* = hintSuccess
hintMax* = high(TMsgKind)
static:
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
type
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
TNoteKinds* = set[TNoteKind]
TFileInfo* = object
fullPath: string # This is a canonical full filesystem path
projPath*: string # This is relative to the project's root
@@ -527,35 +59,11 @@ type
proc `==`*(a, b: FileIndex): bool {.borrow.}
const
NotesVerbosity*: array[0..3, TNoteKinds] = [
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintSuccessX, hintPath, hintConf,
hintProcessing, hintPattern,
hintDependency,
hintExecuting, hintLinking,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
warnProveField, warnProveIndex,
warnGcUnsafe,
hintPath,
hintDependency,
hintCodeBegin, hintCodeEnd,
hintSource, hintStackTrace,
hintGCStats},
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
{low(TNoteKind)..high(TNoteKind)}]
const
InvalidFileIDX* = FileIndex(-1)
var
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting}
filenameToIndexTbl = initTable[string, FileIndex]()
fileInfos*: seq[TFileInfo] = @[]
systemFileIdx*: FileIndex
@@ -591,8 +99,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
result.shortName = fileName.changeFileExt("")
result.quotedName = fileName.makeCString
result.quotedFullName = fullPath.makeCString
if optEmbedOrigSrc in gGlobalOptions or true:
result.lines = @[]
result.lines = @[]
when defined(nimpretty):
if result.fullPath.len > 0:
try:
@@ -606,22 +113,22 @@ when defined(nimpretty):
proc fileSection*(fid: FileIndex; a, b: int): string =
substr(fileInfos[fid.int].fullContent, a, b)
proc fileInfoKnown*(filename: string): bool =
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
var
canon: string
try:
canon = canonicalizePath(filename)
canon = canonicalizePath(conf, filename)
except:
canon = filename
result = filenameToIndexTbl.hasKey(canon)
proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
var
canon: string
pseudoPath = false
try:
canon = canonicalizePath(filename)
canon = canonicalizePath(conf, filename)
shallow(canon)
except:
canon = filename
@@ -635,39 +142,32 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
isKnownFile = false
result = fileInfos.len.FileIndex
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
else: canon.shortenDir))
else: shortenDir(conf, canon)))
filenameToIndexTbl[canon] = result
proc fileInfoIdx*(filename: string): FileIndex =
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
var dummy: bool
result = fileInfoIdx(filename, dummy)
result = fileInfoIdx(conf, filename, dummy)
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
result.fileIndex = fileInfoIdx
result.line = uint16(line)
result.col = int16(col)
proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
result = newLineInfo(filename.fileInfoIdx, line, col)
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
fileInfos.add(newFileInfo("", "command line"))
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
when false:
fileInfos.add(newFileInfo("", "command line"))
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
fileInfos.add(newFileInfo("", "compilation artifact"))
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
fileInfos.add(newFileInfo("", "compilation artifact"))
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
raise newException(ERecoverableError, msg)
proc sourceLine*(i: TLineInfo): Rope
var
gNotes*: TNoteKinds = NotesVerbosity[1] # defaults to verbosity of 1
gErrorCounter*: int = 0 # counts the number of errors
gHintCounter*: int = 0
gWarnCounter*: int = 0
gErrorMax*: int = 1 # stop after gErrorMax errors
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope
proc unknownLineInfo*(): TLineInfo =
result.line = uint16(0)
@@ -767,10 +267,10 @@ template toFilename*(info: TLineInfo): string =
template toFullPath*(info: TLineInfo): string =
info.fileIndex.toFullPath
proc toMsgFilename*(info: TLineInfo): string =
proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
if info.fileIndex.int32 < 0:
result = "???"
elif gListFullPaths:
elif optListFullPaths in conf.globalOptions:
result = fileInfos[info.fileIndex.int32].fullPath
else:
result = fileInfos[info.fileIndex.int32].projPath
@@ -805,7 +305,7 @@ type
msgSkipHook ## skip message hook even if it is present
MsgFlags* = set[MsgFlag]
proc msgWriteln*(s: string, flags: MsgFlags = {}) =
proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
## Writes given message string to stderr by default.
## If ``--stdout`` option is given, writes to stdout instead. If message hook
## is present, then it is used to output message rather than stderr/stdout.
@@ -813,11 +313,11 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) =
## This is used for 'nim dump' etc. where we don't have nimsuggest
## support.
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
#if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
if not isNil(writelnHook) and msgSkipHook notin flags:
writelnHook(s)
elif optStdout in gGlobalOptions or msgStdout in flags:
elif optStdout in conf.globalOptions or msgStdout in flags:
if eStdOut in errorOutputs:
writeLine(stdout, s)
flushFile(stdout)
@@ -858,13 +358,13 @@ template callWritelnHook(args: varargs[string, `$`]) =
template styledMsgWriteln*(args: varargs[typed]) =
if not isNil(writelnHook):
callIgnoringStyle(callWritelnHook, nil, args)
elif optStdout in gGlobalOptions:
elif optStdout in conf.globalOptions:
if eStdOut in errorOutputs:
callIgnoringStyle(writeLine, stdout, args)
flushFile(stdout)
else:
if eStdErr in errorOutputs:
if optUseColors in gGlobalOptions:
if optUseColors in conf.globalOptions:
callStyledWriteLineStderr(args)
else:
callIgnoringStyle(writeLine, stderr, args)
@@ -892,27 +392,27 @@ proc log*(s: string) {.procvar.} =
f.writeLine(s)
close(f)
proc quit(msg: TMsgKind) =
if defined(debug) or msg == errInternal or hintStackTrace in gNotes:
proc quit(conf: ConfigRef; msg: TMsgKind) =
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
if stackTraceAvailable() and isNil(writelnHook):
writeStackTrace()
else:
styledMsgWriteln(fgRed, "No stack traceback available\n" &
"To create a stacktrace, rerun compilation with ./koch temp " &
options.command & " <file>")
conf.command & " <file>")
quit 1
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
if msg >= fatalMin and msg <= fatalMax:
if gCmd == cmdIdeTools: log(s)
quit(msg)
if conf.cmd == cmdIdeTools: log(s)
quit(conf, msg)
if msg >= errMin and msg <= errMax:
inc(gErrorCounter)
options.gExitcode = 1'i8
if gErrorCounter >= gErrorMax:
quit(msg)
elif eh == doAbort and gCmd != cmdIdeTools:
quit(msg)
inc(conf.errorCounter)
conf.exitcode = 1'i8
if conf.errorCounter >= conf.errorMax:
quit(conf, msg)
elif eh == doAbort and conf.cmd != cmdIdeTools:
quit(conf, msg)
elif eh == doRaise:
raiseRecoverableError(s)
@@ -922,26 +422,27 @@ proc `==`*(a, b: TLineInfo): bool =
proc exactEquals*(a, b: TLineInfo): bool =
result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col
proc writeContext(lastinfo: TLineInfo) =
proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
const instantiationFrom = "template/generic instantiation from here"
var info = lastinfo
for i in countup(0, len(msgContext) - 1):
if msgContext[i] != lastinfo and msgContext[i] != info:
if structuredErrorHook != nil:
structuredErrorHook(msgContext[i], getMessageStr(errInstantiationFrom, ""),
structuredErrorHook(msgContext[i], instantiationFrom,
Severity.Error)
else:
styledMsgWriteln(styleBright,
PosFormat % [toMsgFilename(msgContext[i]),
PosFormat % [toMsgFilename(conf, msgContext[i]),
coordToStr(msgContext[i].line.int),
coordToStr(msgContext[i].col+1)],
resetStyle,
getMessageStr(errInstantiationFrom, ""))
instantiationFrom)
info = msgContext[i]
proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
var
title: string
color: ForegroundColor
@@ -950,62 +451,62 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
case msg
of errMin..errMax:
sev = Severity.Error
writeContext(unknownLineInfo())
writeContext(conf, unknownLineInfo())
title = ErrorTitle
color = ErrorColor
of warnMin..warnMax:
sev = Severity.Warning
if optWarns notin gOptions: return
if msg notin gNotes: return
writeContext(unknownLineInfo())
if optWarns notin conf.options: return
if msg notin conf.notes: return
writeContext(conf, unknownLineInfo())
title = WarningTitle
color = WarningColor
kind = WarningsToStr[ord(msg) - ord(warnMin)]
inc(gWarnCounter)
inc(conf.warnCounter)
of hintMin..hintMax:
sev = Severity.Hint
if optHints notin gOptions: return
if msg notin gNotes: return
if optHints notin conf.options: return
if msg notin conf.notes: return
title = HintTitle
color = HintColor
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
inc(gHintCounter)
inc(conf.hintCounter)
let s = msgKindToString(msg) % args
if structuredErrorHook != nil:
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(msg):
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil:
styledMsgWriteln(color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind))
else:
styledMsgWriteln(color, title, resetStyle, s)
handleError(msg, doAbort, s)
handleError(conf, msg, doAbort, s)
proc rawMessage*(msg: TMsgKind, arg: string) =
rawMessage(msg, [arg])
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
rawMessage(conf, msg, [arg])
proc resetAttributes* =
if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
proc resetAttributes*(conf: ConfigRef) =
if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
terminal.resetAttributes(stderr)
proc writeSurroundingSrc(info: TLineInfo) =
proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
const indent = " "
msgWriteln(indent & $info.sourceLine)
msgWriteln(indent & spaces(info.col) & '^')
msgWriteln(conf, indent & $sourceLine(conf, info))
msgWriteln(conf, indent & spaces(info.col) & '^')
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
let title = case msg
of warnMin..warnMax: WarningTitle
of hintMin..hintMax: HintTitle
else: ErrorTitle
result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
coordToStr(info.col+1)] &
title &
getMessageStr(msg, arg)
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
eh: TErrorHandling) =
var
title: string
@@ -1016,7 +517,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
case msg
of errMin..errMax:
sev = Severity.Error
writeContext(info)
writeContext(conf, info)
title = ErrorTitle
color = ErrorColor
# we try to filter error messages so that not two error message
@@ -1025,101 +526,101 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
lastError = info
of warnMin..warnMax:
sev = Severity.Warning
ignoreMsg = optWarns notin gOptions or msg notin gNotes
if not ignoreMsg: writeContext(info)
ignoreMsg = optWarns notin conf.options or msg notin conf.notes
if not ignoreMsg: writeContext(conf, info)
title = WarningTitle
color = WarningColor
kind = WarningsToStr[ord(msg) - ord(warnMin)]
inc(gWarnCounter)
inc(conf.warnCounter)
of hintMin..hintMax:
sev = Severity.Hint
ignoreMsg = optHints notin gOptions or msg notin gNotes
ignoreMsg = optHints notin conf.options or msg notin conf.notes
title = HintTitle
color = HintColor
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
inc(gHintCounter)
inc(conf.hintCounter)
# NOTE: currently line info line numbers start with 1,
# but column numbers start with 0, however most editors expect
# first column to be 1, so we need to +1 here
let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
coordToStr(info.col+1)]
let s = getMessageStr(msg, arg)
if not ignoreMsg:
if structuredErrorHook != nil:
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
if not ignoreMsgBecauseOfIdeTools(msg):
if not ignoreMsgBecauseOfIdeTools(conf, msg):
if kind != nil:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
KindColor, `%`(KindFormat, kind))
else:
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
if hintSource in gNotes:
info.writeSurroundingSrc
handleError(msg, eh, s)
if hintSource in conf.notes:
conf.writeSurroundingSrc(info)
handleError(conf, msg, eh, s)
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
# this fixes bug #7080 so that it is at least obvious 'fatal'
# was executed.
errorOutputs = {eStdOut, eStdErr}
liMessage(info, msg, arg, doAbort)
liMessage(conf, info, msg, arg, doAbort)
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doRaise)
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doRaise)
proc globalError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doRaise)
proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doRaise)
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
proc localError*(info: TLineInfo, arg: string) =
liMessage(info, errGenerated, arg, doNothing)
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
liMessage(conf, info, errGenerated, arg, doNothing)
proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
localError(info, format % params)
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
localError(conf, info, format % params)
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(info, msg, arg, doNothing)
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
liMessage(conf, info, msg, arg, doNothing)
proc internalError*(info: TLineInfo, errMsg: string) =
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
writeContext(info)
liMessage(info, errInternal, errMsg, doAbort)
proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
writeContext(conf, info)
liMessage(conf, info, errInternal, errMsg, doAbort)
proc internalError*(errMsg: string) =
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
writeContext(unknownLineInfo())
rawMessage(errInternal, errMsg)
proc internalError*(conf: ConfigRef; errMsg: string) =
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
writeContext(conf, unknownLineInfo())
rawMessage(conf, errInternal, errMsg)
template assertNotNil*(e): untyped =
if e == nil: internalError($instantiationInfo())
template assertNotNil*(conf: ConfigRef; e): untyped =
if e == nil: internalError(conf, $instantiationInfo())
e
template internalAssert*(e: bool) =
if not e: internalError($instantiationInfo())
template internalAssert*(conf: ConfigRef, e: bool) =
if not e: internalError(conf, $instantiationInfo())
proc addSourceLine*(fileIdx: FileIndex, line: string) =
fileInfos[fileIdx.int32].lines.add line.rope
proc sourceLine*(i: TLineInfo): Rope =
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope =
if i.fileIndex.int32 < 0: return nil
if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
if not optPreserveOrigSource(conf) and fileInfos[i.fileIndex.int32].lines.len == 0:
try:
for line in lines(i.toFullPath):
addSourceLine i.fileIndex, line.string
except IOError:
discard
internalAssert i.fileIndex.int32 < fileInfos.len
assert i.fileIndex.int32 < fileInfos.len
# can happen if the error points to EOF:
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
proc quotedFilename*(i: TLineInfo): Rope =
internalAssert i.fileIndex.int32 >= 0
if optExcessiveStackTrace in gGlobalOptions:
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
assert i.fileIndex.int32 >= 0
if optExcessiveStackTrace in conf.globalOptions:
result = fileInfos[i.fileIndex.int32].quotedFullName
else:
result = fileInfos[i.fileIndex.int32].quotedName
@@ -1127,26 +628,22 @@ proc quotedFilename*(i: TLineInfo): Rope =
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err
of rInvalidFormatStr:
internalError("ropes: invalid format string: " & msg)
internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg)
of rCannotOpenFile:
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
proc listWarnings*() =
msgWriteln("Warnings:")
proc listWarnings*(conf: ConfigRef) =
msgWriteln(conf, "Warnings:")
for warn in warnMin..warnMax:
msgWriteln(" [$1] $2" % [
if warn in gNotes: "x" else: " ",
msgs.WarningsToStr[ord(warn) - ord(warnMin)]
msgWriteln(conf, " [$1] $2" % [
if warn in conf.notes: "x" else: " ",
configuration.WarningsToStr[ord(warn) - ord(warnMin)]
])
proc listHints*() =
msgWriteln("Hints:")
proc listHints*(conf: ConfigRef) =
msgWriteln(conf, "Hints:")
for hint in hintMin..hintMax:
msgWriteln(" [$1] $2" % [
if hint in gNotes: "x" else: " ",
msgs.HintsToStr[ord(hint) - ord(hintMin)]
msgWriteln(conf, " [$1] $2" % [
if hint in conf.notes: "x" else: " ",
configuration.HintsToStr[ord(hint) - ord(hintMin)]
])
# enable colors by default on terminals
if terminal.isatty(stderr):
incl(gGlobalOptions, optUseColors)

View File

@@ -21,7 +21,7 @@ when defined(i386) and defined(windows) and defined(vcc):
import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service,
nodejs, scriptconfig, idents, modulegraphs
nodejs, scriptconfig, idents, modulegraphs, configuration
when hasTinyCBackend:
import tccgen
@@ -37,69 +37,70 @@ proc prependCurDir(f: string): string =
else:
result = f
proc handleCmdLine(cache: IdentCache; config: ConfigRef) =
proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
condsyms.initDefines(conf.symbols)
if paramCount() == 0:
writeCommandLineUsage()
writeCommandLineUsage(conf, conf.helpWritten)
else:
# Process command line arguments:
processCmdLine(passCmd1, "", config)
if gProjectName == "-":
gProjectName = "stdinfile"
gProjectFull = "stdinfile"
gProjectPath = canonicalizePath getCurrentDir()
gProjectIsStdin = true
elif gProjectName != "":
processCmdLine(passCmd1, "", conf)
if conf.projectName == "-":
conf.projectName = "stdinfile"
conf.projectFull = "stdinfile"
conf.projectPath = canonicalizePath(conf, getCurrentDir())
conf.projectIsStdin = true
elif conf.projectName != "":
try:
gProjectFull = canonicalizePath(gProjectName)
conf.projectFull = canonicalizePath(conf, conf.projectName)
except OSError:
gProjectFull = gProjectName
let p = splitFile(gProjectFull)
conf.projectFull = conf.projectName
let p = splitFile(conf.projectFull)
let dir = if p.dir.len > 0: p.dir else: getCurrentDir()
gProjectPath = canonicalizePath dir
gProjectName = p.name
conf.projectPath = canonicalizePath(conf, dir)
conf.projectName = p.name
else:
gProjectPath = canonicalizePath getCurrentDir()
loadConfigs(DefaultConfig, config) # load all config files
let scriptFile = gProjectFull.changeFileExt("nims")
conf.projectPath = canonicalizePath(conf, getCurrentDir())
loadConfigs(DefaultConfig, conf) # load all config files
let scriptFile = conf.projectFull.changeFileExt("nims")
if fileExists(scriptFile):
runNimScript(cache, scriptFile, freshDefines=false, config)
runNimScript(cache, scriptFile, freshDefines=false, conf)
# 'nim foo.nims' means to just run the NimScript file and do nothing more:
if scriptFile == gProjectFull: return
elif fileExists(gProjectPath / "config.nims"):
if scriptFile == conf.projectFull: return
elif fileExists(conf.projectPath / "config.nims"):
# directory wide NimScript file
runNimScript(cache, gProjectPath / "config.nims", freshDefines=false, config)
runNimScript(cache, conf.projectPath / "config.nims", freshDefines=false, conf)
# now process command line arguments again, because some options in the
# command line can overwite the config file's settings
extccomp.initVars()
processCmdLine(passCmd2, "", config)
if options.command == "":
rawMessage(errNoCommand, command)
mainCommand(newModuleGraph(config), cache)
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
extccomp.initVars(conf)
processCmdLine(passCmd2, "", conf)
if conf.command == "":
rawMessage(conf, errGenerated, "command missing")
mainCommand(newModuleGraph(conf), cache)
if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
#echo(GC_getStatistics())
if msgs.gErrorCounter == 0:
if conf.errorCounter == 0:
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.run(config.arguments)
if optRun in gGlobalOptions:
if gCmd == cmdCompileToJS:
if conf.cmd == cmdRun:
tccgen.run(conf.arguments)
if optRun in conf.globalOptions:
if conf.cmd == cmdCompileToJS:
var ex: string
if options.outFile.len > 0:
ex = options.outFile.prependCurDir.quoteShell
if conf.outFile.len > 0:
ex = conf.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram(findNodeJs() & " " & ex & ' ' & config.arguments)
completeCFilePath(conf, changeFileExt(conf.projectFull, "js").prependCurDir))
execExternalProgram(conf, findNodeJs() & " " & ex & ' ' & conf.arguments)
else:
var binPath: string
if options.outFile.len > 0:
if conf.outFile.len > 0:
# If the user specified an outFile path, use that directly.
binPath = options.outFile.prependCurDir
binPath = conf.outFile.prependCurDir
else:
# Figure out ourselves a valid binary name.
binPath = changeFileExt(gProjectFull, ExeExt).prependCurDir
binPath = changeFileExt(conf.projectFull, ExeExt).prependCurDir
var ex = quoteShell(binPath)
execExternalProgram(ex & ' ' & config.arguments)
execExternalProgram(conf, ex & ' ' & conf.arguments)
when declared(GC_setMaxPause):
GC_setMaxPause 2_000
@@ -107,10 +108,10 @@ when declared(GC_setMaxPause):
when compileOption("gc", "v2") or compileOption("gc", "refc"):
# the new correct mark&sweet collector is too slow :-/
GC_disableMarkAndSweep()
condsyms.initDefines()
when not defined(selftest):
handleCmdLine(newIdentCache(), newConfigRef())
let conf = newConfigRef()
handleCmdLine(newIdentCache(), conf)
when declared(GC_setMaxPause):
echo GC_getStatistics()
msgQuit(int8(msgs.gErrorCounter > 0))
msgQuit(int8(conf.errorCounter > 0))

View File

@@ -9,11 +9,12 @@
## Implements some helper procs for Nimble (Nim's package manager) support.
import parseutils, strutils, strtabs, os, options, msgs, sequtils
import parseutils, strutils, strtabs, os, options, msgs, sequtils,
configuration
proc addPath*(path: string, info: TLineInfo) =
if not options.searchPaths.contains(path):
options.searchPaths.insert(path, 0)
proc addPath*(conf: ConfigRef; path: string, info: TLineInfo) =
if not conf.searchPaths.contains(path):
conf.searchPaths.insert(path, 0)
type
Version* = distinct string
@@ -84,7 +85,7 @@ proc getPathVersion*(p: string): tuple[name, version: string] =
result.name = p[0 .. sepIdx - 1]
result.version = p.substr(sepIdx + 1)
proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) =
proc addPackage(conf: ConfigRef; packages: StringTableRef, p: string; info: TLineInfo) =
let (name, ver) = getPathVersion(p)
if isValidVersion(ver):
let version = newVersion(ver)
@@ -92,14 +93,14 @@ proc addPackage(packages: StringTableRef, p: string; info: TLineInfo) =
(not packages.hasKey(name)):
packages[name] = $version
else:
localError(info, "invalid package name: " & p)
localError(conf, info, "invalid package name: " & p)
iterator chosen(packages: StringTableRef): string =
for key, val in pairs(packages):
let res = if val.len == 0: key else: key & '-' & val
yield res
proc addNimblePath(p: string, info: TLineInfo) =
proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
var path = p
let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
if nimbleLinks.len > 0:
@@ -111,23 +112,23 @@ proc addNimblePath(p: string, info: TLineInfo) =
if not path.isAbsolute():
path = p / path
if not contains(options.searchPaths, path):
message(info, hintPath, path)
options.lazyPaths.insert(path, 0)
if not contains(conf.searchPaths, path):
message(conf, info, hintPath, path)
conf.lazyPaths.insert(path, 0)
proc addPathRec(dir: string, info: TLineInfo) =
proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
var packages = newStringTable(modeStyleInsensitive)
var pos = dir.len-1
if dir[pos] in {DirSep, AltSep}: inc(pos)
for k,p in os.walkDir(dir):
if k == pcDir and p[pos] != '.':
addPackage(packages, p, info)
addPackage(conf, packages, p, info)
for p in packages.chosen:
addNimblePath(p, info)
addNimblePath(conf, p, info)
proc nimblePath*(path: string, info: TLineInfo) =
addPathRec(path, info)
addNimblePath(path, info)
proc nimblePath*(conf: ConfigRef; path: string, info: TLineInfo) =
addPathRec(conf, path, info)
addNimblePath(conf, path, info)
when isMainModule:
proc v(s: string): Version = s.newVersion

View File

@@ -11,7 +11,7 @@
import
llstream, nversion, commands, os, strutils, msgs, platform, condsyms, lexer,
options, idents, wordrecg, strtabs
options, idents, wordrecg, strtabs, configuration
# ---------------- configuration file parser -----------------------------
# we use Nim's scanner here to save space and work
@@ -27,12 +27,12 @@ proc parseAtom(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
ppGetTok(L, tok)
result = parseExpr(L, tok, config)
if tok.tokType == tkParRi: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\')\'")
else: lexMessage(L, errGenerated, "expected closing ')'")
elif tok.ident.id == ord(wNot):
ppGetTok(L, tok)
result = not parseAtom(L, tok, config)
else:
result = isDefined(tok.ident)
result = isDefined(config, tok.ident.s)
ppGetTok(L, tok)
proc parseAndExpr(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
@@ -53,12 +53,12 @@ proc evalppIf(L: var TLexer, tok: var TToken; config: ConfigRef): bool =
ppGetTok(L, tok) # skip 'if' or 'elif'
result = parseExpr(L, tok, config)
if tok.tokType == tkColon: ppGetTok(L, tok)
else: lexMessage(L, errTokenExpected, "\':\'")
else: lexMessage(L, errGenerated, "expected ':'")
var condStack: seq[bool] = @[]
#var condStack: seq[bool] = @[]
proc doEnd(L: var TLexer, tok: var TToken) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
proc doEnd(L: var TLexer, tok: var TToken; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
ppGetTok(L, tok) # skip 'end'
setLen(condStack, high(condStack))
@@ -66,20 +66,22 @@ type
TJumpDest = enum
jdEndif, jdElseEndif
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef)
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool])
proc doElse(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
ppGetTok(L, tok)
if tok.tokType == tkColon: ppGetTok(L, tok)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config)
if condStack[high(condStack)]: jumpToDirective(L, tok, jdEndif, config, condStack)
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef) =
if high(condStack) < 0: lexMessage(L, errTokenExpected, "@if")
proc doElif(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
if high(condStack) < 0: lexMessage(L, errGenerated, "expected @if")
var res = evalppIf(L, tok, config)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config)
if condStack[high(condStack)] or not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
else: condStack[high(condStack)] = true
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef) =
proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: ConfigRef;
condStack: var seq[bool]) =
var nestedIfs = 0
while true:
if tok.ident != nil and tok.ident.s == "@":
@@ -89,39 +91,39 @@ proc jumpToDirective(L: var TLexer, tok: var TToken, dest: TJumpDest; config: Co
inc(nestedIfs)
of wElse:
if dest == jdElseEndif and nestedIfs == 0:
doElse(L, tok, config)
doElse(L, tok, config, condStack)
break
of wElif:
if dest == jdElseEndif and nestedIfs == 0:
doElif(L, tok, config)
doElif(L, tok, config, condStack)
break
of wEnd:
if nestedIfs == 0:
doEnd(L, tok)
doEnd(L, tok, condStack)
break
if nestedIfs > 0: dec(nestedIfs)
else:
discard
ppGetTok(L, tok)
elif tok.tokType == tkEof:
lexMessage(L, errTokenExpected, "@end")
lexMessage(L, errGenerated, "expected @end")
else:
ppGetTok(L, tok)
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
ppGetTok(L, tok) # skip @
case whichKeyword(tok.ident)
of wIf:
setLen(condStack, len(condStack) + 1)
let res = evalppIf(L, tok, config)
condStack[high(condStack)] = res
if not res: jumpToDirective(L, tok, jdElseEndif, config)
of wElif: doElif(L, tok, config)
of wElse: doElse(L, tok, config)
of wEnd: doEnd(L, tok)
if not res: jumpToDirective(L, tok, jdElseEndif, config, condStack)
of wElif: doElif(L, tok, config, condStack)
of wElse: doElse(L, tok, config, condStack)
of wEnd: doEnd(L, tok, condStack)
of wWrite:
ppGetTok(L, tok)
msgs.msgWriteln(strtabs.`%`(tokToStr(tok), options.gConfigVars,
msgs.msgWriteln(config, strtabs.`%`(tokToStr(tok), config.configVars,
{useEnvironment, useKey}))
ppGetTok(L, tok)
else:
@@ -144,55 +146,57 @@ proc parseDirective(L: var TLexer, tok: var TToken; config: ConfigRef) =
ppGetTok(L, tok)
os.putEnv(key, os.getEnv(key) & tokToStr(tok))
ppGetTok(L, tok)
else: lexMessage(L, errInvalidDirectiveX, tokToStr(tok))
else:
lexMessage(L, errGenerated, "invalid directive: '$1'" % tokToStr(tok))
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef) =
proc confTok(L: var TLexer, tok: var TToken; config: ConfigRef; condStack: var seq[bool]) =
ppGetTok(L, tok)
while tok.ident != nil and tok.ident.s == "@":
parseDirective(L, tok, config) # else: give the token to the parser
parseDirective(L, tok, config, condStack) # else: give the token to the parser
proc checkSymbol(L: TLexer, tok: TToken) =
if tok.tokType notin {tkSymbol..tkInt64Lit, tkStrLit..tkTripleStrLit}:
lexMessage(L, errIdentifierExpected, tokToStr(tok))
lexMessage(L, errGenerated, "expected identifier, but got: " & tokToStr(tok))
proc parseAssignment(L: var TLexer, tok: var TToken; config: ConfigRef) =
proc parseAssignment(L: var TLexer, tok: var TToken;
config: ConfigRef; condStack: var seq[bool]) =
if tok.ident.s == "-" or tok.ident.s == "--":
confTok(L, tok, config) # skip unnecessary prefix
confTok(L, tok, config, condStack) # skip unnecessary prefix
var info = getLineInfo(L, tok) # save for later in case of an error
checkSymbol(L, tok)
var s = tokToStr(tok)
confTok(L, tok, config) # skip symbol
confTok(L, tok, config, condStack) # skip symbol
var val = ""
while tok.tokType == tkDot:
add(s, '.')
confTok(L, tok, config)
confTok(L, tok, config, condStack)
checkSymbol(L, tok)
add(s, tokToStr(tok))
confTok(L, tok, config)
confTok(L, tok, config, condStack)
if tok.tokType == tkBracketLe:
# BUGFIX: val, not s!
# BUGFIX: do not copy '['!
confTok(L, tok, config)
confTok(L, tok, config, condStack)
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok, config)
if tok.tokType == tkBracketRi: confTok(L, tok, config)
else: lexMessage(L, errTokenExpected, "']'")
confTok(L, tok, config, condStack)
if tok.tokType == tkBracketRi: confTok(L, tok, config, condStack)
else: lexMessage(L, errGenerated, "expected closing ']'")
add(val, ']')
let percent = tok.ident != nil and tok.ident.s == "%="
if tok.tokType in {tkColon, tkEquals} or percent:
if len(val) > 0: add(val, ':')
confTok(L, tok, config) # skip ':' or '=' or '%'
confTok(L, tok, config, condStack) # skip ':' or '=' or '%'
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok, config) # skip symbol
confTok(L, tok, config, condStack) # skip symbol
while tok.ident != nil and tok.ident.s == "&":
confTok(L, tok, config)
confTok(L, tok, config, condStack)
checkSymbol(L, tok)
add(val, tokToStr(tok))
confTok(L, tok, config)
confTok(L, tok, config, condStack)
if percent:
processSwitch(s, strtabs.`%`(val, options.gConfigVars,
processSwitch(s, strtabs.`%`(val, config.configVars,
{useEnvironment, useEmpty}), passPP, info, config)
else:
processSwitch(s, val, passPP, info, config)
@@ -207,48 +211,49 @@ proc readConfigFile(filename: string; cache: IdentCache; config: ConfigRef) =
initToken(tok)
openLexer(L, filename, stream, cache, config)
tok.tokType = tkEof # to avoid a pointless warning
confTok(L, tok, config) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config)
if len(condStack) > 0: lexMessage(L, errTokenExpected, "@end")
var condStack: seq[bool] = @[]
confTok(L, tok, config, condStack) # read in the first token
while tok.tokType != tkEof: parseAssignment(L, tok, config, condStack)
if len(condStack) > 0: lexMessage(L, errGenerated, "expected @end")
closeLexer(L)
rawMessage(hintConf, filename)
rawMessage(config, hintConf, filename)
proc getUserConfigPath(filename: string): string =
result = joinPath(getConfigDir(), filename)
proc getSystemConfigPath(filename: string): string =
proc getSystemConfigPath(conf: ConfigRef; filename: string): string =
# try standard configuration file (installation did not distribute files
# the UNIX way)
let p = getPrefixDir()
let p = getPrefixDir(conf)
result = joinPath([p, "config", filename])
when defined(unix):
if not existsFile(result): result = joinPath([p, "etc", filename])
if not existsFile(result): result = "/etc/" & filename
proc loadConfigs*(cfg: string; cache: IdentCache; config: ConfigRef = nil) =
setDefaultLibpath()
proc loadConfigs*(cfg: string; cache: IdentCache; conf: ConfigRef) =
setDefaultLibpath(conf)
if optSkipConfigFile notin gGlobalOptions:
readConfigFile(getSystemConfigPath(cfg), cache, config)
if optSkipConfigFile notin conf.globalOptions:
readConfigFile(getSystemConfigPath(conf, cfg), cache, conf)
if optSkipUserConfigFile notin gGlobalOptions:
readConfigFile(getUserConfigPath(cfg), cache, config)
if optSkipUserConfigFile notin conf.globalOptions:
readConfigFile(getUserConfigPath(cfg), cache, conf)
var pd = if gProjectPath.len > 0: gProjectPath else: getCurrentDir()
if optSkipParentConfigFiles notin gGlobalOptions:
let pd = if conf.projectPath.len > 0: conf.projectPath else: getCurrentDir()
if optSkipParentConfigFiles notin conf.globalOptions:
for dir in parentDirs(pd, fromRoot=true, inclusive=false):
readConfigFile(dir / cfg, cache, config)
readConfigFile(dir / cfg, cache, conf)
if optSkipProjConfigFile notin gGlobalOptions:
readConfigFile(pd / cfg, cache, config)
if optSkipProjConfigFile notin conf.globalOptions:
readConfigFile(pd / cfg, cache, conf)
if gProjectName.len != 0:
if conf.projectName.len != 0:
# new project wide config file:
var projectConfig = changeFileExt(gProjectFull, "nimcfg")
var projectConfig = changeFileExt(conf.projectFull, "nimcfg")
if not fileExists(projectConfig):
projectConfig = changeFileExt(gProjectFull, "nim.cfg")
readConfigFile(projectConfig, cache, config)
projectConfig = changeFileExt(conf.projectFull, "nim.cfg")
readConfigFile(projectConfig, cache, conf)
proc loadConfigs*(cfg: string; config: ConfigRef = nil) =
proc loadConfigs*(cfg: string; conf: ConfigRef) =
# for backwards compatibility only.
loadConfigs(cfg, newIdentCache(), config)
loadConfigs(cfg, newIdentCache(), conf)

View File

@@ -38,7 +38,7 @@ In addition, all command line options of Nim are supported.
proc mainCommand =
registerPass verbosePass
registerPass semPass
gCmd = cmdPretty
conf.cmd = cmdPretty
searchPaths.add options.libpath
if gProjectFull.len != 0:
# current path is always looked first for modules

View File

@@ -13,7 +13,8 @@
import
strutils, os, intsets, strtabs
import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents]
import ".." / [options, ast, astalgo, msgs, semdata, ropes, idents,
configuration]
import prettybase
type
@@ -24,11 +25,11 @@ var
gStyleCheck*: StyleCheck
gCheckExtern*, gOnlyMainfile*: bool
proc overwriteFiles*() =
let doStrip = options.getConfigVar("pretty.strip").normalize == "on"
proc overwriteFiles*(conf: ConfigRef) =
let doStrip = options.getConfigVar(conf, "pretty.strip").normalize == "on"
for i in 0 .. high(gSourceFiles):
if gSourceFiles[i].dirty and not gSourceFiles[i].isNimfixFile and
(not gOnlyMainfile or gSourceFiles[i].fileIdx == gProjectMainIdx.FileIndex):
(not gOnlyMainfile or gSourceFiles[i].fileIdx == conf.projectMainIdx.FileIndex):
let newFile = if gOverWrite: gSourceFiles[i].fullpath
else: gSourceFiles[i].fullpath.changeFileExt(".pretty.nim")
try:
@@ -41,7 +42,7 @@ proc overwriteFiles*() =
f.write(gSourceFiles[i].newline)
f.close
except IOError:
rawMessage(errCannotOpenFile, newFile)
rawMessage(conf, errGenerated, "cannot open file: " & newFile)
proc `=~`(s: string, a: openArray[string]): bool =
for x in a:
@@ -110,25 +111,25 @@ proc replaceInFile(info: TLineInfo; newName: string) =
system.shallowCopy(gSourceFiles[info.fileIndex.int].lines[info.line.int-1], x)
gSourceFiles[info.fileIndex.int].dirty = true
proc checkStyle(info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
proc checkStyle(conf: ConfigRef; info: TLineInfo, s: string, k: TSymKind; sym: PSym) =
let beau = beautifyName(s, k)
if s != beau:
if gStyleCheck == StyleCheck.Auto:
sym.name = getIdent(beau)
replaceInFile(info, beau)
else:
message(info, hintName, beau)
message(conf, info, hintName, beau)
proc styleCheckDefImpl(info: TLineInfo; s: PSym; k: TSymKind) =
proc styleCheckDefImpl(conf: ConfigRef; info: TLineInfo; s: PSym; k: TSymKind) =
# operators stay as they are:
if k in {skResult, skTemp} or s.name.s[0] notin prettybase.Letters: return
if k in {skType, skGenericParam} and sfAnon in s.flags: return
if {sfImportc, sfExportc} * s.flags == {} or gCheckExtern:
checkStyle(info, s.name.s, k, s)
checkStyle(conf, info, s.name.s, k, s)
template styleCheckDef*(info: TLineInfo; s: PSym; k: TSymKind) =
when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(info, s, k)
if gStyleCheck != StyleCheck.None: styleCheckDefImpl(conf, info, s, k)
template styleCheckDef*(info: TLineInfo; s: PSym) =
styleCheckDef(info, s, s.kind)
@@ -151,4 +152,4 @@ proc styleCheckUseImpl(info: TLineInfo; s: PSym) =
template styleCheckUse*(info: TLineInfo; s: PSym) =
when defined(nimfix):
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(info, s)
if gStyleCheck != StyleCheck.None: styleCheckUseImpl(conf, info, s)

View File

@@ -12,27 +12,10 @@
import
ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
proc toBitSet*(s: PNode, b: var TBitSet)
# this function is used for case statement checking:
proc overlap*(a, b: PNode): bool
proc inSet*(s: PNode, elem: PNode): bool
proc someInSet*(s: PNode, a, b: PNode): bool
proc emptyRange*(a, b: PNode): bool
proc setHasRange*(s: PNode): bool
# returns true if set contains a range (needed by the code generator)
# these are used for constant folding:
proc unionSets*(a, b: PNode): PNode
proc diffSets*(a, b: PNode): PNode
proc intersectSets*(a, b: PNode): PNode
proc symdiffSets*(a, b: PNode): PNode
proc containsSets*(a, b: PNode): bool
proc equalSets*(a, b: PNode): bool
proc cardSet*(a: PNode): BiggestInt
# implementation
proc inSet(s: PNode, elem: PNode): bool =
proc inSet*(s: PNode, elem: PNode): bool =
assert s.kind == nkCurly
if s.kind != nkCurly:
internalError(s.info, "inSet")
#internalError(s.info, "inSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -44,7 +27,7 @@ proc inSet(s: PNode, elem: PNode): bool =
return true
result = false
proc overlap(a, b: PNode): bool =
proc overlap*(a, b: PNode): bool =
if a.kind == nkRange:
if b.kind == nkRange:
# X..Y and C..D overlap iff (X <= D and C <= Y)
@@ -58,10 +41,11 @@ proc overlap(a, b: PNode): bool =
else:
result = sameValue(a, b)
proc someInSet(s: PNode, a, b: PNode): bool =
proc someInSet*(s: PNode, a, b: PNode): bool =
# checks if some element of a..b is in the set s
assert s.kind == nkCurly
if s.kind != nkCurly:
internalError(s.info, "SomeInSet")
#internalError(s.info, "SomeInSet")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
@@ -74,7 +58,7 @@ proc someInSet(s: PNode, a, b: PNode): bool =
return true
result = false
proc toBitSet(s: PNode, b: var TBitSet) =
proc toBitSet*(s: PNode, b: var TBitSet) =
var first, j: BiggestInt
first = firstOrd(s.typ.sons[0])
bitSetInit(b, int(getSize(s.typ)))
@@ -87,7 +71,7 @@ proc toBitSet(s: PNode, b: var TBitSet) =
else:
bitSetIncl(b, getOrdValue(s.sons[i]) - first)
proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
proc toTreeSet*(s: TBitSet, settype: PType, info: TLineInfo): PNode =
var
a, b, e, first: BiggestInt # a, b are interval borders
elemType: PType
@@ -128,18 +112,18 @@ template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
op(x, y)
result = toTreeSet(x, a.typ, a.info)
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc unionSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
proc diffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
proc intersectSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
proc symdiffSets*(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
proc containsSets(a, b: PNode): bool =
proc containsSets*(a, b: PNode): bool =
var x, y: TBitSet
toBitSet(a, x)
toBitSet(b, y)
result = bitSetContains(x, y)
proc equalSets(a, b: PNode): bool =
proc equalSets*(a, b: PNode): bool =
var x, y: TBitSet
toBitSet(a, x)
toBitSet(b, y)
@@ -156,20 +140,19 @@ proc deduplicate*(a: PNode): PNode =
toBitSet(a, x)
result = toTreeSet(x, a.typ, a.info)
proc cardSet(a: PNode): BiggestInt =
proc cardSet*(a: PNode): BiggestInt =
var x: TBitSet
toBitSet(a, x)
result = bitSetCard(x)
proc setHasRange(s: PNode): bool =
proc setHasRange*(s: PNode): bool =
assert s.kind == nkCurly
if s.kind != nkCurly:
internalError(s.info, "SetHasRange")
return false
for i in countup(0, sonsLen(s) - 1):
if s.sons[i].kind == nkRange:
return true
result = false
proc emptyRange(a, b: PNode): bool =
proc emptyRange*(a, b: PNode): bool =
result = not leValue(a, b) # a > b iff not (a <= b)

View File

@@ -15,3 +15,6 @@ const
VersionAsString* = system.NimVersion
RodFileVersion* = "1223" # modify this if the rod-format changes!
NimCompilerApiVersion* = 1 ## Check for the existance of this before accessing it
## as older versions of the compiler API do not
## declare this.

View File

@@ -8,7 +8,9 @@
#
import
os, strutils, strtabs, osproc, sets
os, strutils, strtabs, osproc, sets, configuration, platform
from terminal import isatty
const
hasTinyCBackend* = defined(tinyc)
@@ -17,7 +19,6 @@ const
hasFFI* = defined(useFFI)
newScopeForIf* = true
useCaas* = not defined(noCaas)
noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
copyrightYear* = "2018"
type # please make sure we have under 32 options
@@ -71,6 +72,11 @@ type # please make sure we have under 32 options
optIdeTerse # idetools: use terse descriptions
optNoCppExceptions # use C exception handling even with CPP
optExcessiveStackTrace # fully qualified module filenames
optWholeProject # for 'doc2': output any dependency
optListFullPaths
optNoNimblePath
optDynlibOverrideAll
optUseNimNamespace
TGlobalOptions* = set[TGlobalOption]
@@ -112,74 +118,177 @@ type
destructor,
notnil
SymbolFilesOption* = enum
disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
ConfigRef* = ref object ## eventually all global configuration should be moved here
linesCompiled*: int # all lines that have been compiled
options*: TOptions
globalOptions*: TGlobalOptions
exitcode*: int8
cmd*: TCommands # the command
selectedGC*: TGCMode # the selected GC
verbosity*: int # how verbose the compiler is
numberOfProcessors*: int # number of processors
evalExpr*: string # expression for idetools --eval
lastCmdTime*: float # when caas is enabled, we measure each command
symbolFiles*: SymbolFilesOption
cppDefines*: HashSet[string]
headerFile*: string
features*: set[Feature]
arguments*: string ## the arguments to be passed to the program that
## should be run
helpWritten*: bool
ideCmd*: IdeCmd
oldNewlines*: bool
enableNotes*: TNoteKinds
disableNotes*: TNoteKinds
foreignPackageNotes*: TNoteKinds
notes*: TNoteKinds
mainPackageNotes*: TNoteKinds
errorCounter*: int
hintCounter*: int
warnCounter*: int
errorMax*: int
configVars*: StringTableRef
symbols*: StringTableRef ## We need to use a StringTableRef here as defined
## symbols are always guaranteed to be style
## insensitive. Otherwise hell would break lose.
packageCache*: StringTableRef
searchPaths*: seq[string]
lazyPaths*: seq[string]
outFile*, prefixDir*, libpath*, nimcacheDir*: string
dllOverrides, moduleOverrides*: StringTableRef
projectName*: string # holds a name like 'nim'
projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
projectFull*: string # projectPath/projectName
projectIsStdin*: bool # whether we're compiling from stdin
projectMainIdx*: int32 # the canonical path id of the main module
command*: string # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] # any arguments after the main command
keepComments*: bool # whether the parser needs to keep comments
implicitImports*: seq[string] # modules that are to be implicitly imported
implicitIncludes*: seq[string] # modules that are to be implicitly included
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
proc newConfigRef*(): ConfigRef =
result = ConfigRef(cppDefines: initSet[string](),
headerFile: "", features: {})
proc cppDefine*(c: ConfigRef; define: string) =
c.cppDefines.incl define
var
gIdeCmd*: IdeCmd
gOldNewlines*: bool
const
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
optMoveCheck}
var
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
optHints, optStackTrace, optLineTrace,
optPatterns, optNilCheck, optMoveCheck}
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
gExitcode*: int8
gCmd*: TCommands = cmdNone # the command
gSelectedGC* = gcRefc # the selected GC
searchPaths*: seq[string] = @[]
lazyPaths*: seq[string] = @[]
outFile*: string = ""
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
# The string uses the formatting variables `path` and `line`.
#headerFile*: string = ""
gVerbosity* = 1 # how verbose the compiler is
gNumberOfProcessors*: int # number of processors
gWholeProject*: bool # for 'doc2': output any dependency
gEvalExpr* = "" # expression for idetools --eval
gLastCmdTime*: float # when caas is enabled, we measure each command
gListFullPaths*: bool
gPreciseStack*: bool = false
gNoNimblePath* = false
gDynlibOverrideAll*: bool
useNimNamespace*: bool
DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
optHints, optStackTrace, optLineTrace,
optPatterns, optNilCheck, optMoveCheck}
DefaultGlobalOptions* = {optThreadAnalysis}
type
SymbolFilesOption* = enum
disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
template newPackageCache*(): untyped =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
var gSymbolFiles*: SymbolFilesOption
proc newConfigRef*(): ConfigRef =
result = ConfigRef(
selectedGC: gcRefc,
verbosity: 1,
options: DefaultOptions,
globalOptions: DefaultGlobalOptions,
evalExpr: "",
cppDefines: initSet[string](),
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting},
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
configVars: newStringTable(modeStyleInsensitive),
symbols: newStringTable(modeStyleInsensitive),
packageCache: newPackageCache(),
searchPaths: @[],
lazyPaths: @[],
outFile: "", prefixDir: "", libpath: "", nimcacheDir: "",
dllOverrides: newStringTable(modeCaseInsensitive),
moduleOverrides: newStringTable(modeStyleInsensitive),
projectName: "", # holds a name like 'nim'
projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
projectFull: "", # projectPath/projectName
projectIsStdin: false, # whether we're compiling from stdin
projectMainIdx: 0'i32, # the canonical path id of the main module
command: "", # the main command (e.g. cc, check, scan, etc)
commandArgs: @[], # any arguments after the main command
keepComments: true, # whether the parser needs to keep comments
implicitImports: @[], # modules that are to be implicitly imported
implicitIncludes: @[], # modules that are to be implicitly included
docSeeSrcUrl: ""
)
# enable colors by default on terminals
if terminal.isatty(stderr):
incl(result.globalOptions, optUseColors)
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
template preciseStack*(): bool = gPreciseStack
proc newPartialConfigRef*(): ConfigRef =
## create a new ConfigRef that is only good enough for error reporting.
result = ConfigRef(
selectedGC: gcRefc,
verbosity: 1,
options: DefaultOptions,
globalOptions: DefaultGlobalOptions,
foreignPackageNotes: {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting},
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1])
template compilationCachePresent*: untyped =
gSymbolFiles in {enabledSf, writeOnlySf}
proc cppDefine*(c: ConfigRef; define: string) =
c.cppDefines.incl define
proc isDefined*(conf: ConfigRef; symbol: string): bool =
if conf.symbols.hasKey(symbol):
result = conf.symbols[symbol] != "false"
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
result = true
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
result = true
else:
case symbol.normalize
of "x86": result = targetCPU == cpuI386
of "itanium": result = targetCPU == cpuIa64
of "x8664": result = targetCPU == cpuAmd64
of "posix", "unix":
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
osQnx, osAtari, osAix,
osHaiku, osVxWorks, osSolaris, osNetbsd,
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
osAndroid}
of "linux":
result = targetOS in {osLinux, osAndroid}
of "bsd":
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
of "emulatedthreadvars":
result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
of "msdos": result = targetOS == osDos
of "mswindows", "win32": result = targetOS == osWindows
of "macintosh": result = targetOS in {osMacos, osMacosx}
of "sunos": result = targetOS == osSolaris
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
of "cpu8": result = CPU[targetCPU].bit == 8
of "cpu16": result = CPU[targetCPU].bit == 16
of "cpu32": result = CPU[targetCPU].bit == 32
of "cpu64": result = CPU[targetCPU].bit == 64
of "nimrawsetjmp":
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
osDragonfly, osMacosx}
else: discard
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
template compilationCachePresent*(conf: ConfigRef): untyped =
conf.symbolFiles in {enabledSf, writeOnlySf}
# {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
template optPreserveOrigSource*: untyped =
optEmbedOrigSrc in gGlobalOptions
template optPreserveOrigSource*(conf: ConfigRef): untyped =
optEmbedOrigSrc in conf.globalOptions
const
genSubDir* = "nimcache"
@@ -194,82 +303,62 @@ const
DocConfig* = "nimdoc.cfg"
DocTexConfig* = "nimdoc.tex.cfg"
# additional configuration variables:
var
gConfigVars* = newStringTable(modeStyleInsensitive)
gDllOverrides = newStringTable(modeCaseInsensitive)
gModuleOverrides* = newStringTable(modeStyleInsensitive)
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
libpath* = ""
gProjectName* = "" # holds a name like 'nim'
gProjectPath* = "" # holds a path like /home/alice/projects/nim/compiler/
gProjectFull* = "" # projectPath/projectName
gProjectIsStdin* = false # whether we're compiling from stdin
gProjectMainIdx*: int32 # the canonical path id of the main module
nimcacheDir* = ""
command* = "" # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] = @[] # any arguments after the main command
gKeepComments*: bool = true # whether the parser needs to keep comments
implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
const oKeepVariableNames* = true
template compilingLib*: bool =
template compilingLib*(conf: ConfigRef): bool =
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
proc mainCommandArg*: string =
proc mainCommandArg*(conf: ConfigRef): string =
## This is intended for commands like check or parse
## which will work on the main project file unless
## explicitly given a specific file argument
if commandArgs.len > 0:
result = commandArgs[0]
if conf.commandArgs.len > 0:
result = conf.commandArgs[0]
else:
result = gProjectName
result = conf.projectName
proc existsConfigVar*(key: string): bool =
result = hasKey(gConfigVars, key)
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
result = hasKey(conf.configVars, key)
proc getConfigVar*(key: string): string =
result = gConfigVars.getOrDefault key
proc getConfigVar*(conf: ConfigRef; key: string): string =
result = conf.configVars.getOrDefault key
proc setConfigVar*(key, val: string) =
gConfigVars[key] = val
proc setConfigVar*(conf: ConfigRef; key, val: string) =
conf.configVars[key] = val
proc getOutFile*(filename, ext: string): string =
if options.outFile != "": result = options.outFile
proc getOutFile*(conf: ConfigRef; filename, ext: string): string =
if conf.outFile != "": result = conf.outFile
else: result = changeFileExt(filename, ext)
proc getPrefixDir*(): string =
proc getPrefixDir*(conf: ConfigRef): string =
## Gets the prefix dir, usually the parent directory where the binary resides.
##
## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir``
## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir``
## global.
if gPrefixDir != "": result = gPrefixDir
else:
result = splitPath(getAppDir()).head
if conf.prefixDir != "": result = conf.prefixDir
else: result = splitPath(getAppDir()).head
proc setDefaultLibpath*() =
proc setDefaultLibpath*(conf: ConfigRef) =
# set default value (can be overwritten):
if libpath == "":
if conf.libpath == "":
# choose default libpath:
var prefix = getPrefixDir()
var prefix = getPrefixDir(conf)
when defined(posix):
if prefix == "/usr": libpath = "/usr/lib/nim"
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
else: libpath = joinPath(prefix, "lib")
else: libpath = joinPath(prefix, "lib")
if prefix == "/usr": conf.libpath = "/usr/lib/nim"
elif prefix == "/usr/local": conf.libpath = "/usr/local/lib/nim"
else: conf.libpath = joinPath(prefix, "lib")
else: conf.libpath = joinPath(prefix, "lib")
# Special rule to support other tools (nimble) which import the compiler
# modules and make use of them.
let realNimPath = findExe("nim")
# Find out if $nim/../../lib/system.nim exists.
let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
if not fileExists(libpath / "system.nim") and
let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
if not fileExists(conf.libpath / "system.nim") and
fileExists(parentNimlibPath / "system.nim"):
libpath = parentNimLibPath
conf.libpath = parentNimLibPath
proc canonicalizePath*(path: string): string =
proc canonicalizePath*(conf: ConfigRef; path: string): string =
# on Windows, 'expandFilename' calls getFullPathName which doesn't do
# case corrections, so we have to use this convoluted way of retrieving
# the true filename (see tests/modules and Nimble uses 'import Uri' instead
@@ -281,12 +370,12 @@ proc canonicalizePath*(path: string): string =
else:
result = path.expandFilename
proc shortenDir*(dir: string): string =
proc shortenDir*(conf: ConfigRef; dir: string): string =
## returns the interesting part of a dir
var prefix = gProjectPath & DirSep
var prefix = conf.projectPath & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
prefix = getPrefixDir() & DirSep
prefix = getPrefixDir(conf) & DirSep
if startsWith(dir, prefix):
return substr(dir, len(prefix))
result = dir
@@ -297,114 +386,89 @@ proc removeTrailingDirSep*(path: string): string =
else:
result = path
proc disableNimblePath*() =
gNoNimblePath = true
lazyPaths.setLen(0)
proc disableNimblePath*(conf: ConfigRef) =
incl conf.globalOptions, optNoNimblePath
conf.lazyPaths.setLen(0)
include packagehandling
proc getNimcacheDir*: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir
proc getNimcacheDir*(conf: ConfigRef): string =
result = if conf.nimcacheDir.len > 0: conf.nimcacheDir
else: shortenDir(conf, conf.projectPath) / genSubDir
proc pathSubs*(p, config: string): string =
proc pathSubs*(conf: ConfigRef; p, config: string): string =
let home = removeTrailingDirSep(os.getHomeDir())
result = unixToNativePath(p % [
"nim", getPrefixDir(),
"lib", libpath,
"nim", getPrefixDir(conf),
"lib", conf.libpath,
"home", home,
"config", config,
"projectname", options.gProjectName,
"projectpath", options.gProjectPath,
"projectdir", options.gProjectPath,
"nimcache", getNimcacheDir()])
"projectname", conf.projectName,
"projectpath", conf.projectPath,
"projectdir", conf.projectPath,
"nimcache", getNimcacheDir(conf)])
if "~/" in result:
result = result.replace("~/", home & '/')
proc toGeneratedFile*(path, ext: string): string =
proc toGeneratedFile*(conf: ConfigRef; path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path)
#if len(head) > 0: head = shortenDir(head & dirSep)
result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)])
result = joinPath([getNimcacheDir(conf), changeFileExt(tail, ext)])
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
when noTimeMachine:
var alreadyExcludedDirs = initSet[string]()
proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
## Calls a macosx command on the directory to exclude it from backups.
##
## The macosx tmutil command is invoked to mark the specified path as an
## item to be excluded from time machine backups. If a path already exists
## with files before excluding it, newer files won't be added to the
## directory, but previous files won't be removed from the backup until the
## user deletes that directory.
##
## The whole proc is optional and will ignore all kinds of errors. The only
## way to be sure that it works is to call ``tmutil isexcluded path``.
if alreadyExcludedDirs.contains(dir): return
alreadyExcludedDirs.incl(dir)
try:
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
discard p.waitForExit
p.close
except Exception:
discard
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = true): string =
var (head, tail) = splitPath(f)
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
var subdir = getNimcacheDir() # / head
var subdir = getNimcacheDir(conf) # / head
if createSubDir:
try:
createDir(subdir)
when noTimeMachine:
excludeDirFromTimeMachine(subdir)
except OSError:
writeLine(stdout, "cannot create directory: " & subdir)
quit(1)
result = joinPath(subdir, tail)
#echo "completeGeneratedFilePath(", f, ") = ", result
proc rawFindFile(f: string): string =
for it in searchPaths:
proc rawFindFile(conf: ConfigRef; f: string): string =
for it in conf.searchPaths:
result = joinPath(it, f)
if existsFile(result):
return result.canonicalizePath
return canonicalizePath(conf, result)
result = ""
proc rawFindFile2(f: string): string =
for i, it in lazyPaths:
proc rawFindFile2(conf: ConfigRef; f: string): string =
for i, it in conf.lazyPaths:
result = joinPath(it, f)
if existsFile(result):
# bring to front
for j in countDown(i,1):
swap(lazyPaths[j], lazyPaths[j-1])
swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
return result.canonicalizePath
return canonicalizePath(conf, result)
result = ""
template patchModule() {.dirty.} =
if result.len > 0 and gModuleOverrides.len > 0:
let key = getPackageName(result) & "_" & splitFile(result).name
if gModuleOverrides.hasKey(key):
let ov = gModuleOverrides[key]
template patchModule(conf: ConfigRef) {.dirty.} =
if result.len > 0 and conf.moduleOverrides.len > 0:
let key = getPackageName(conf, result) & "_" & splitFile(result).name
if conf.moduleOverrides.hasKey(key):
let ov = conf.moduleOverrides[key]
if ov.len > 0: result = ov
proc findFile*(f: string): string {.procvar.} =
proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
if f.isAbsolute:
result = if f.existsFile: f else: ""
else:
result = f.rawFindFile
result = rawFindFile(conf, f)
if result.len == 0:
result = f.toLowerAscii.rawFindFile
result = rawFindFile(conf, f.toLowerAscii)
if result.len == 0:
result = f.rawFindFile2
result = rawFindFile2(conf, f)
if result.len == 0:
result = f.toLowerAscii.rawFindFile2
patchModule()
result = rawFindFile2(conf, f.toLowerAscii)
patchModule(conf)
proc findModule*(modulename, currentModule: string): string =
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
# returns path to module
when defined(nimfix):
# '.nimfix' modules are preferred over '.nim' modules so that specialized
@@ -414,16 +478,16 @@ proc findModule*(modulename, currentModule: string): string =
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(m)
result = findFile(conf, m)
if existsFile(result): return result
let m = addFileExt(modulename, NimExt)
let currentPath = currentModule.splitFile.dir
result = currentPath / m
if not existsFile(result):
result = findFile(m)
patchModule()
result = findFile(conf, m)
patchModule(conf)
proc findProjectNimFile*(pkg: string): string =
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
var candidates: seq[string] = @[]
for k, f in os.walkDir(pkg, relative=true):
@@ -448,11 +512,12 @@ proc canonDynlibName(s: string): string =
else:
result = s.substr(start)
proc inclDynlibOverride*(lib: string) =
gDllOverrides[lib.canonDynlibName] = "true"
proc inclDynlibOverride*(conf: ConfigRef; lib: string) =
conf.dllOverrides[lib.canonDynlibName] = "true"
proc isDynlibOverride*(lib: string): bool =
result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName)
proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
result = optDynlibOverrideAll in conf.globalOptions or
conf.dllOverrides.hasKey(lib.canonDynlibName)
proc binaryStrSearch*(x: openArray[string], y: string): int =
var a = 0

View File

@@ -15,23 +15,16 @@ iterator myParentDirs(p: string): string =
if current.len == 0: break
yield current
template newPackageCache(): untyped =
newStringTable(when FileSystemCaseSensitive:
modeCaseInsensitive
else:
modeCaseSensitive)
proc resetPackageCache*(conf: ConfigRef) =
conf.packageCache = newPackageCache()
var packageCache = newPackageCache()
proc resetPackageCache*() = packageCache = newPackageCache()
proc getPackageName*(path: string): string =
proc getPackageName*(conf: ConfigRef; path: string): string =
var parents = 0
block packageSearch:
for d in myParentDirs(path):
if packageCache.hasKey(d):
if conf.packageCache.hasKey(d):
#echo "from cache ", d, " |", packageCache[d], "|", path.splitFile.name
return packageCache[d]
return conf.packageCache[d]
inc parents
for file in walkFiles(d / "*.nimble"):
result = file.splitFile.name
@@ -43,12 +36,12 @@ proc getPackageName*(path: string): string =
if result.isNil: result = ""
for d in myParentDirs(path):
#echo "set cache ", d, " |", result, "|", parents
packageCache[d] = result
conf.packageCache[d] = result
dec parents
if parents <= 0: break
proc withPackageName*(path: string): string =
let x = path.getPackageName
proc withPackageName*(conf: ConfigRef; path: string): string =
let x = getPackageName(conf, path)
if x.len == 0:
result = path
else:

View File

@@ -10,7 +10,8 @@
## This module implements the pattern matching features for term rewriting
## macro support.
import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees
import strutils, ast, astalgo, types, msgs, idents, renderer, wordrecg, trees,
options
# we precompile the pattern here for efficiency into some internal
# stack based VM :-) Why? Because it's fun; I did no benchmarks to see if that
@@ -41,8 +42,8 @@ type
const
MaxStackSize* = 64 ## max required stack size by the VM
proc patternError(n: PNode) =
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc patternError(n: PNode; conf: ConfigRef) =
localError(conf, n.info, "illformed AST: " & renderTree(n, {renderNoComments}))
proc add(code: var TPatternCode, op: TOpcode) {.inline.} =
add(code, chr(ord(op)))
@@ -53,42 +54,42 @@ proc whichAlias*(p: PSym): TAliasRequest =
else:
result = aqNone
proc compileConstraints(p: PNode, result: var TPatternCode) =
proc compileConstraints(p: PNode, result: var TPatternCode; conf: ConfigRef) =
case p.kind
of nkCallKinds:
if p.sons[0].kind != nkIdent:
patternError(p.sons[0])
patternError(p.sons[0], conf)
return
let op = p.sons[0].ident
if p.len == 3:
if op.s == "|" or op.id == ord(wOr):
compileConstraints(p.sons[1], result)
compileConstraints(p.sons[2], result)
compileConstraints(p.sons[1], result, conf)
compileConstraints(p.sons[2], result, conf)
result.add(ppOr)
elif op.s == "&" or op.id == ord(wAnd):
compileConstraints(p.sons[1], result)
compileConstraints(p.sons[2], result)
compileConstraints(p.sons[1], result, conf)
compileConstraints(p.sons[2], result, conf)
result.add(ppAnd)
else:
patternError(p)
patternError(p, conf)
elif p.len == 2 and (op.s == "~" or op.id == ord(wNot)):
compileConstraints(p.sons[1], result)
compileConstraints(p.sons[1], result, conf)
result.add(ppNot)
else:
patternError(p)
patternError(p, conf)
of nkAccQuoted, nkPar:
if p.len == 1:
compileConstraints(p.sons[0], result)
compileConstraints(p.sons[0], result, conf)
else:
patternError(p)
patternError(p, conf)
of nkIdent:
let spec = p.ident.s.normalize
case spec
of "atom": result.add(ppAtom)
of "lit": result.add(ppLit)
of "sym": result.add(ppSym)
of "atom": result.add(ppAtom)
of "lit": result.add(ppLit)
of "sym": result.add(ppSym)
of "ident": result.add(ppIdent)
of "call": result.add(ppCall)
of "call": result.add(ppCall)
of "alias": result[0] = chr(aqShouldAlias.ord)
of "noalias": result[0] = chr(aqNoAlias.ord)
of "lvalue": result.add(ppLValue)
@@ -97,24 +98,24 @@ proc compileConstraints(p: PNode, result: var TPatternCode) =
of "nosideeffect": result.add(ppNoSideEffect)
else:
# check all symkinds:
internalAssert int(high(TSymKind)) < 255
internalAssert conf, int(high(TSymKind)) < 255
for i in low(TSymKind)..high(TSymKind):
if cmpIgnoreStyle(($i).substr(2), spec) == 0:
result.add(ppSymKind)
result.add(chr(i.ord))
return
# check all nodekinds:
internalAssert int(high(TNodeKind)) < 255
internalAssert conf, int(high(TNodeKind)) < 255
for i in low(TNodeKind)..high(TNodeKind):
if cmpIgnoreStyle($i, spec) == 0:
result.add(ppNodeKind)
result.add(chr(i.ord))
return
patternError(p)
patternError(p, conf)
else:
patternError(p)
patternError(p, conf)
proc semNodeKindConstraints*(p: PNode): PNode =
proc semNodeKindConstraints*(p: PNode; conf: ConfigRef): PNode =
## does semantic checking for a node kind pattern and compiles it into an
## efficient internal format.
assert p.kind == nkCurlyExpr
@@ -123,11 +124,11 @@ proc semNodeKindConstraints*(p: PNode): PNode =
result.strVal.add(chr(aqNone.ord))
if p.len >= 2:
for i in 1..<p.len:
compileConstraints(p.sons[i], result.strVal)
compileConstraints(p.sons[i], result.strVal, conf)
if result.strVal.len > MaxStackSize-1:
internalError(p.info, "parameter pattern too complex")
internalError(conf, p.info, "parameter pattern too complex")
else:
patternError(p)
patternError(p, conf)
result.strVal.add(ppEof)
type

View File

@@ -27,7 +27,7 @@ when isMainModule:
outp.close
import
llstream, lexer, idents, strutils, ast, astalgo, msgs, options
llstream, lexer, idents, strutils, ast, astalgo, msgs, options, configuration
type
TParser* = object # A TParser object represents a file that
@@ -97,7 +97,7 @@ proc openParser*(p: var TParser, fileIdx: FileIndex, inputStream: PLLStream,
proc openParser*(p: var TParser, filename: string, inputStream: PLLStream,
cache: IdentCache; config: ConfigRef;
strongSpaces=false) =
openParser(p, filename.fileInfoIdx, inputStream, cache, config, strongSpaces)
openParser(p, fileInfoIdx(config, filename), inputStream, cache, config, strongSpaces)
proc closeParser(p: var TParser) =
## Close a parser, freeing up its resources.
@@ -107,9 +107,13 @@ proc parMessage(p: TParser, msg: TMsgKind, arg = "") =
## Produce and emit the parser message `arg` to output.
lexMessageTok(p.lex, msg, p.tok, arg)
proc parMessage(p: TParser, msg: TMsgKind, tok: TToken) =
proc parMessage(p: TParser, msg: string, tok: TToken) =
## Produce and emit a parser message to output about the token `tok`
parMessage(p, msg, prettyTok(tok))
parMessage(p, errGenerated, msg % prettyTok(tok))
proc parMessage(p: TParser, arg: string) =
## Produce and emit the parser message `arg` to output.
lexMessageTok(p.lex, errGenerated, p.tok, arg)
template withInd(p, body: untyped) =
let oldInd = p.currInd
@@ -142,6 +146,12 @@ proc skipComment(p: var TParser, node: PNode) =
proc flexComment(p: var TParser, node: PNode) =
if p.tok.indent < 0 or realInd(p): rawSkipComment(p, node)
const
errInvalidIndentation = "invalid indentation"
errIdentifierExpected = "identifier expected, but got '$1'"
errExprExpected = "expression expected, but found '$1'"
errTokenExpected = "'$1' expected"
proc skipInd(p: var TParser) =
if p.tok.indent >= 0:
if not realInd(p): parMessage(p, errInvalidIndentation)
@@ -160,11 +170,11 @@ proc getTokNoInd(p: var TParser) =
proc expectIdentOrKeyw(p: TParser) =
if p.tok.tokType != tkSymbol and not isKeyword(p.tok.tokType):
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok))
proc expectIdent(p: TParser) =
if p.tok.tokType != tkSymbol:
lexMessage(p.lex, errIdentifierExpected, prettyTok(p.tok))
lexMessage(p.lex, errGenerated, errIdentifierExpected % prettyTok(p.tok))
proc eat(p: var TParser, tokType: TTokType) =
## Move the parser to the next token if the current token is of type
@@ -172,7 +182,8 @@ proc eat(p: var TParser, tokType: TTokType) =
if p.tok.tokType == tokType:
getTok(p)
else:
lexMessageTok(p.lex, errTokenExpected, p.tok, TokTypeToStr[tokType])
lexMessage(p.lex, errGenerated,
"expected: '" & TokTypeToStr[tokType] & "', but got: '" & prettyTok(p.tok) & "'")
proc parLineInfo(p: TParser): TLineInfo =
## Retrieve the line information associated with the parser's current state.
@@ -886,7 +897,7 @@ proc parsePragma(p: var TParser): PNode =
skipComment(p, a)
optPar(p)
if p.tok.tokType in {tkCurlyDotRi, tkCurlyRi}: getTok(p)
else: parMessage(p, errTokenExpected, ".}")
else: parMessage(p, "expected '.}'")
dec p.inPragma
proc identVis(p: var TParser; allowDot=false): PNode =
@@ -947,7 +958,7 @@ proc parseIdentColonEquals(p: var TParser, flags: TDeclaredIdentFlags): PNode =
else:
addSon(result, newNodeP(nkEmpty, p))
if p.tok.tokType != tkEquals and withBothOptional notin flags:
parMessage(p, errColonOrEqualsExpected, p.tok)
parMessage(p, "':' or '=' expected, but got '$1'", p.tok)
if p.tok.tokType == tkEquals:
getTok(p)
optInd(p, result)
@@ -1020,7 +1031,7 @@ proc parseParamList(p: var TParser, retColon = true): PNode =
parMessage(p, errGenerated, "the syntax is 'parameter: var T', not 'var parameter: T'")
break
else:
parMessage(p, errTokenExpected, ")")
parMessage(p, "expected closing ')'")
break
addSon(result, a)
if p.tok.tokType notin {tkComma, tkSemiColon}: break
@@ -1181,7 +1192,7 @@ proc primary(p: var TParser, mode: TPrimaryMode): PNode =
if mode == pmTypeDef:
result = parseTypeClass(p)
else:
parMessage(p, errInvalidToken, p.tok)
parMessage(p, "the 'concept' keyword is only valid in 'type' sections")
of tkStatic:
let info = parLineInfo(p)
getTokNoInd(p)
@@ -1291,7 +1302,7 @@ proc postExprBlocks(p: var TParser, x: PNode): PNode =
if nextBlock.kind == nkElse: break
else:
if openingParams.kind != nkEmpty:
parMessage(p, errTokenExpected, ":")
parMessage(p, "expected ':'")
proc parseExprStmt(p: var TParser): PNode =
#| exprStmt = simpleExpr
@@ -1527,7 +1538,7 @@ proc parseTry(p: var TParser; isExpr: bool): PNode =
addSon(b, parseStmt(p))
addSon(result, b)
if b.kind == nkFinally: break
if b == nil: parMessage(p, errTokenExpected, "except")
if b == nil: parMessage(p, "expected 'except'")
proc parseExceptBlock(p: var TParser, kind: TNodeKind): PNode =
#| exceptBlock = 'except' colcom stmt
@@ -1582,7 +1593,7 @@ proc parseAsm(p: var TParser): PNode =
of tkTripleStrLit: addSon(result,
newStrNodeP(nkTripleStrLit, p.tok.literal, p))
else:
parMessage(p, errStringLiteralExpected)
parMessage(p, "the 'asm' statement takes a string literal")
addSon(result, ast.emptyNode)
return
getTok(p)
@@ -1761,7 +1772,7 @@ proc parseEnum(p: var TParser): PNode =
p.tok.tokType == tkEof:
break
if result.len <= 1:
lexMessageTok(p.lex, errIdentifierExpected, p.tok, prettyTok(p.tok))
parMessage(p, errIdentifierExpected, p.tok)
proc parseObjectPart(p: var TParser): PNode
proc parseObjectWhen(p: var TParser): PNode =
@@ -2124,7 +2135,7 @@ proc parseStmt(p: var TParser): PNode =
case p.tok.tokType
of tkIf, tkWhile, tkCase, tkTry, tkFor, tkBlock, tkAsm, tkProc, tkFunc,
tkIterator, tkMacro, tkType, tkConst, tkWhen, tkVar:
parMessage(p, errComplexStmtRequiresInd)
parMessage(p, "complex statement requires indentation")
result = ast.emptyNode
else:
if p.inSemiStmtList > 0:

View File

@@ -10,22 +10,26 @@
## implements some little helper passes
import
strutils, ast, astalgo, passes, idents, msgs, options, idgen
strutils, ast, astalgo, passes, idents, msgs, options, idgen, configuration
from modulegraphs import ModuleGraph
type
VerboseRef = ref object of TPassContext
config: ConfigRef
proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
#MessageOut('compiling ' + s.name.s);
result = nil # we don't need a context
rawMessage(hintProcessing, s.name.s)
result = VerboseRef(config: graph.config)
rawMessage(graph.config, hintProcessing, s.name.s)
proc verboseProcess(context: PPassContext, n: PNode): PNode =
result = n
if context != nil: internalError("logpass: context is not nil")
if gVerbosity == 3:
let v = VerboseRef(context)
if v.config.verbosity == 3:
# system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing)
message(n.info, hintProcessing, $idgen.gFrontendId)
incl(v.config.notes, hintProcessing)
message(v.config, n.info, hintProcessing, $idgen.gFrontendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)

View File

@@ -13,7 +13,8 @@
import
strutils, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod
nimsets, syntaxes, times, rodread, idgen, modulegraphs, reorder, rod,
configuration
type
@@ -57,11 +58,11 @@ var
# implementation
proc skipCodegen*(n: PNode): bool {.inline.} =
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
# can be used by codegen passes to determine whether they should do
# something with `n`. Currently, this ignores `n` and uses the global
# error count instead.
result = msgs.gErrorCounter > 0
result = config.errorCounter > 0
const
maxPasses = 10
@@ -139,20 +140,21 @@ proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
m = gPasses[i].close(graph, a[i], m)
a[i] = nil # free the memory here
proc resolveMod(module, relativeTo: string): FileIndex =
let fullPath = findModule(module, relativeTo)
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
let fullPath = findModule(conf, module, relativeTo)
if fullPath.len == 0:
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
result = fileInfoIdx(conf, fullPath)
proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKind,
a: var TPassContextArray; m: PSym) =
# XXX fixme this should actually be relative to the config file!
let gCmdLineInfo = newLineInfo(FileIndex(0), 1, 1)
let relativeTo = m.info.toFullPath
for module in items(implicits):
# implicit imports should not lead to a module importing itself
if m.position != resolveMod(module, relativeTo).int32:
if m.position != resolveMod(conf, module, relativeTo).int32:
var importStmt = newNodeI(nodeKind, gCmdLineInfo)
var str = newStrNode(nkStrLit, module)
str.info = gCmdLineInfo
@@ -202,7 +204,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
let filename = fileIdx.toFullPathConsiderDirty
s = llStreamOpen(filename, fmRead)
if s == nil:
rawMessage(errCannotOpenFile, filename)
rawMessage(graph.config, errCannotOpenFile, filename)
return false
else:
s = stream
@@ -214,8 +216,8 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
# modules to include between compilation runs? we'd need to track that
# in ROD files. I think we should enable this feature only
# for the interactive mode.
processImplicits implicitImports, nkImportStmt, a, module
processImplicits implicitIncludes, nkIncludeStmt, a, module
processImplicits graph.config, graph.config.implicitImports, nkImportStmt, a, module
processImplicits graph.config, graph.config.implicitIncludes, nkIncludeStmt, a, module
while true:
if graph.stopCompile(): break

View File

@@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
of "*": result = matchNested(c, p, n, rpn=false)
of "**": result = matchNested(c, p, n, rpn=true)
of "~": result = not matches(c, p.sons[1], n)
else: internalError(p.info, "invalid pattern")
else: doAssert(false, "invalid pattern")
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
# add(a, b)
elif p.kind == nkCurlyExpr:
@@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
# constraint not fulfilled:
if not ok: return nil
markUsed(n.info, s, c.graph.usageSym)
markUsed(c.config, n.info, s, c.graph.usageSym)
if ctx.subMatch:
assert m.len == 3
m.sons[1] = result

View File

@@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
let iter = n[1]
if iter.kind != nkSym or iter.sym.kind != skIterator:
localError(iter.info, "first argument needs to be an iterator")
localError(c.config, iter.info, "first argument needs to be an iterator")
return
if n[2].typ.isNil:
localError(n[2].info, "second argument needs to be a type")
localError(c.config, n[2].info, "second argument needs to be a type")
return
if n[3].kind != nkIdent:
localError(n[3].info, "third argument needs to be an identifier")
localError(c.config, n[3].info, "third argument needs to be an identifier")
return
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
localError(n[2].info,
localError(c.config, n[2].info,
"type must be a non-generic ref|ptr to object with state field")
return
let body = liftIterToProc(iter.sym, iter.sym.getBody, t)
let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t)
let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
prc.typ = copyType(iter.sym.typ, prc, false)

File diff suppressed because it is too large Load Diff

View File

@@ -14,14 +14,12 @@ import
ast, astalgo, msgs, semdata, types, trees, strutils
proc equalGenericParams(procA, procB: PNode): bool =
if sonsLen(procA) != sonsLen(procB): return
if sonsLen(procA) != sonsLen(procB): return false
for i in countup(0, sonsLen(procA) - 1):
if procA.sons[i].kind != nkSym:
internalError(procA.info, "equalGenericParams")
return
return false
if procB.sons[i].kind != nkSym:
internalError(procB.info, "equalGenericParams")
return
return false
let a = procA.sons[i].sym
let b = procB.sons[i].sym
if a.name.id != b.name.id or
@@ -57,7 +55,7 @@ proc searchForProcOld*(c: PContext, scope: PScope, fn: PSym): PSym =
of paramsEqual:
return
of paramsIncompatible:
localError(fn.info, errNotOverloadable, fn.name.s)
localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
return
of paramsNotEqual:
discard
@@ -76,10 +74,10 @@ proc searchForProcNew(c: PContext, scope: PScope, fn: PSym): PSym =
let message = ("public implementation '$1' has non-public " &
"forward declaration in $2") %
[getProcHeader(result), $result.info]
localError(fn.info, errGenerated, message)
localError(c.config, fn.info, message)
return
of paramsIncompatible:
localError(fn.info, errNotOverloadable, fn.name.s)
localError(c.config, fn.info, "overloaded '$1' leads to ambiguous calls" % fn.name.s)
return
of paramsNotEqual:
discard

View File

@@ -10,7 +10,7 @@
# This module implements the renderer of the standard Nim representation.
import
lexer, options, idents, strutils, ast, msgs
lexer, options, idents, strutils, ast, msgs, configuration
type
TRenderFlag* = enum
@@ -40,6 +40,7 @@ type
when defined(nimpretty):
pendingNewlineCount: int
fid*: FileIndex
config*: ConfigRef
# We render the source code in a two phases: The first
# determines how long the subtree will likely be, the second
@@ -90,7 +91,7 @@ const
MaxLineLen = 80
LineCommentColumn = 30
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
g.comStack = @[]
g.tokens = @[]
g.indent = 0
@@ -102,6 +103,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
g.pendingNL = -1
g.pendingWhitespace = -1
g.inGenericParams = false
g.config = config
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
var length = len(g.tokens)
@@ -377,7 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string =
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
else: result = "[type node]"
else:
internalError("rnimsyn.atom " & $n.kind)
internalError(g.config, "rnimsyn.atom " & $n.kind)
result = ""
proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
@@ -1422,11 +1424,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gTypeClassTy(g, n)
else:
#nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
var g: TSrcGen
initSrcGen(g, renderFlags)
initSrcGen(g, renderFlags, newPartialConfigRef())
# do not indent the initial statement list so that
# writeFile("file.nim", repr n)
# produces working Nim code:
@@ -1444,7 +1446,7 @@ proc renderModule*(n: PNode, infile, outfile: string,
var
f: File
g: TSrcGen
initSrcGen(g, renderFlags)
initSrcGen(g, renderFlags, newPartialConfigRef())
g.fid = fid
for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i])
@@ -1454,16 +1456,14 @@ proc renderModule*(n: PNode, infile, outfile: string,
nkCommentStmt: putNL(g)
else: discard
gcoms(g)
if optStdout in gGlobalOptions:
write(stdout, g.buf)
elif open(f, outfile, fmWrite):
if open(f, outfile, fmWrite):
write(f, g.buf)
close(f)
else:
rawMessage(errCannotOpenFile, outfile)
rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
initSrcGen(r, renderFlags)
initSrcGen(r, renderFlags, newPartialConfigRef())
gsub(r, n)
proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =

View File

@@ -1,7 +1,8 @@
import
intsets, ast, idents, algorithm, renderer, parser, ospaths, strutils,
sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables
sequtils, msgs, modulegraphs, syntaxes, options, modulepaths, tables,
configuration
type
DepN = ref object
@@ -151,10 +152,10 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
for a in n:
if a.kind == nkIncludeStmt:
for i in 0..<a.len:
var f = checkModuleName(a.sons[i])
var f = checkModuleName(graph.config, a.sons[i])
if f != InvalidFileIDX:
if containsOrIncl(includedFiles, f.int):
localError(a.info, errRecursiveDependencyX, f.toFilename)
localError(graph.config, a.info, "recursive dependency: '$1'" % f.toFilename)
else:
let nn = includeModule(graph, module, f, cache)
let nnn = expandIncludes(graph, module, nn, modulePath,
@@ -189,7 +190,7 @@ proc haveSameKind(dns: seq[DepN]): bool =
if dn.pnode.kind != kind:
return false
proc mergeSections(comps: seq[seq[DepN]], res: PNode) =
proc mergeSections(conf: ConfigRef; comps: seq[seq[DepN]], res: PNode) =
# Merges typeSections and ConstSections when they form
# a strong component (ex: circular type definition)
for c in comps:
@@ -229,7 +230,7 @@ proc mergeSections(comps: seq[seq[DepN]], res: PNode) =
wmsg &= "line " & $cs[^1].pnode.info.line &
" depends on line " & $cs[j].pnode.info.line &
": " & cs[^1].expls[ci] & "\n"
message(cs[0].pnode.info, warnUser, wmsg)
message(conf, cs[0].pnode.info, warnUser, wmsg)
var i = 0
while i < cs.len:
@@ -441,4 +442,4 @@ proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PN
var g = buildGraph(n, deps)
let comps = getStrongComponents(g)
mergeSections(comps, result)
mergeSections(graph.config, comps, result)

View File

@@ -90,7 +90,8 @@
import
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables
ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables,
configuration
type
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
@@ -143,6 +144,7 @@ type
origFile: string
inViewMode: bool
cache*: IdentCache
config: ConfigRef
PRodReader* = ref TRodReader
@@ -222,14 +224,14 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
var fl = decodeStr(r.s, r.pos)
result.ident = r.cache.getIdent(fl)
else:
internalError(result.info, "decodeNode: nkIdent")
internalError(r.config, result.info, "decodeNode: nkIdent")
of nkSym:
if r.s[r.pos] == '!':
inc(r.pos)
var id = decodeVInt(r.s, r.pos)
result.sym = rrGetSym(r, id, result.info)
else:
internalError(result.info, "decodeNode: nkSym")
internalError(r.config, result.info, "decodeNode: nkSym")
else:
var i = 0
while r.s[r.pos] != ')':
@@ -241,9 +243,9 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil))
inc i
if r.s[r.pos] == ')': inc(r.pos)
else: internalError(result.info, "decodeNode: ')' missing")
else: internalError(r.config, result.info, "decodeNode: ')' missing")
else:
internalError(fInfo, "decodeNode: '(' missing " & $r.pos)
internalError(r.config, fInfo, "decodeNode: '(' missing " & $r.pos)
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, fInfo, nil)
@@ -277,7 +279,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
else:
loc.r = nil
if r.s[r.pos] == '>': inc(r.pos)
else: internalError(info, "decodeLoc " & r.s[r.pos])
else: internalError(r.config, info, "decodeLoc " & r.s[r.pos])
proc decodeType(r: PRodReader, info: TLineInfo): PType =
result = nil
@@ -294,7 +296,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
setId(result.id)
if debugIds: registerID(result)
else:
internalError(info, "decodeType: no id")
internalError(r.config, info, "decodeType: no id")
# here this also avoids endless recursion for recursive type
idTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
@@ -345,14 +347,14 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
doAssert r.s[r.pos] == '\20'
inc(r.pos)
let y = rrGetSym(r, decodeVInt(r.s, r.pos), info)
result.methods.safeAdd((x, y))
result.methods.add((x, y))
decodeLoc(r, result.loc, info)
while r.s[r.pos] == '^':
inc(r.pos)
if r.s[r.pos] == '(':
inc(r.pos)
if r.s[r.pos] == ')': inc(r.pos)
else: internalError(info, "decodeType ^(" & r.s[r.pos])
else: internalError(r.config, info, "decodeType ^(" & r.s[r.pos])
rawAddSon(result, nil)
else:
var d = decodeVInt(r.s, r.pos)
@@ -364,10 +366,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
new(result)
inc(r.pos)
result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 1")
if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 1")
inc(r.pos)
result.name = rope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 2")
if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 2")
inc(r.pos)
result.path = decodeNode(r, info)
@@ -385,7 +387,7 @@ proc decodeInstantiations(r: PRodReader; info: TLineInfo;
if r.s[r.pos] == '\20':
inc(r.pos)
ii.compilesId = decodeVInt(r.s, r.pos)
s.safeAdd ii
s.add ii
proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
var
@@ -403,12 +405,12 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
id = decodeVInt(r.s, r.pos)
setId(id)
else:
internalError(info, "decodeSym: no id")
internalError(r.config, info, "decodeSym: no id")
if r.s[r.pos] == '&':
inc(r.pos)
ident = r.cache.getIdent(decodeStr(r.s, r.pos))
else:
internalError(info, "decodeSym: no ident")
internalError(r.config, info, "decodeSym: no ident")
#echo "decoding: {", ident.s
result = r.syms.getOrDefault(id)
if result == nil:
@@ -417,7 +419,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
r.syms[result.id] = result
if debugIds: registerID(result)
elif result.id != id:
internalError(info, "decodeSym: wrong id")
internalError(r.config, info, "decodeSym: wrong id")
elif result.kind != skStub and not r.inViewMode:
# we already loaded the symbol
return
@@ -465,7 +467,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
of skType, skGenericParam:
while r.s[r.pos] == '\14':
inc(r.pos)
result.typeInstCache.safeAdd rrGetType(r, decodeVInt(r.s, r.pos), result.info)
result.typeInstCache.add rrGetType(r, decodeVInt(r.s, r.pos), result.info)
of routineKinds:
decodeInstantiations(r, result.info, result.procInstCache)
if r.s[r.pos] == '\16':
@@ -512,7 +514,7 @@ proc skipSection(r: PRodReader) =
else: discard
inc(r.pos)
else:
internalError("skipSection " & $r.line)
internalError(r.config, "skipSection " & $r.line)
proc rdWord(r: PRodReader): string =
result = ""
@@ -530,7 +532,7 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
if debugIds: registerID(result)
proc processInterf(r: PRodReader, module: PSym) =
if r.interfIdx == 0: internalError("processInterf")
if r.interfIdx == 0: internalError(r.config, "processInterf")
r.pos = r.interfIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
@@ -543,7 +545,7 @@ proc processInterf(r: PRodReader, module: PSym) =
r.syms[s.id] = s
proc processCompilerProcs(r: PRodReader, module: PSym) =
if r.compilerProcsIdx == 0: internalError("processCompilerProcs")
if r.compilerProcsIdx == 0: internalError(r.config, "processCompilerProcs")
r.pos = r.compilerProcsIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos)
@@ -621,26 +623,26 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
of "OPTIONS":
inc(r.pos) # skip ':'
r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
if options.gOptions != r.options: r.reason = rrOptions
if r.config.options != r.options: r.reason = rrOptions
of "GOPTIONS":
inc(r.pos) # skip ':'
var dep = cast[TGlobalOptions](int32(decodeVInt(r.s, r.pos)))
if gGlobalOptions-harmlessOptions != dep-harmlessOptions:
if r.config.globalOptions-harmlessOptions != dep-harmlessOptions:
r.reason = rrOptions
of "CMD":
inc(r.pos) # skip ':'
var dep = cast[TCommands](int32(decodeVInt(r.s, r.pos)))
if cmdChangeTriggersRecompilation(dep, gCmd): r.reason = rrOptions
if cmdChangeTriggersRecompilation(dep, r.config.cmd): r.reason = rrOptions
of "DEFINES":
inc(r.pos) # skip ':'
d = 0
while r.s[r.pos] > '\x0A':
w = decodeStr(r.s, r.pos)
inc(d)
if not condsyms.isDefined(r.cache.getIdent(w)):
if not isDefined(r.config, w):
r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
if r.s[r.pos] == ' ': inc(r.pos)
if d != countDefinedSymbols(): r.reason = rrDefines
if d != countDefinedSymbols(r.config.symbols): r.reason = rrDefines
of "FILES":
inc(r.pos, 2) # skip "(\10"
inc(r.line)
@@ -648,7 +650,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
let finalPath = decodeStr(r.s, r.pos)
#let resolvedPath = relativePath.findModule(r.origFile)
#let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
r.files.add(fileInfoIdx(r.config, finalPath))
inc(r.pos) # skip #10
inc(r.line)
if r.s[r.pos] == ')': inc(r.pos)
@@ -696,7 +698,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
r.initIdx = r.pos + 2 # "(\10"
skipSection(r)
else:
internalError("invalid section: '" & section &
internalError(r.config, "invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
#MsgWriteln("skipping section: " & section &
# " at " & $r.line & " in " & r.filename)
@@ -712,9 +714,11 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool =
result = s == token.len
proc newRodReader(modfilename: string, hash: SecureHash,
readerIndex: int; cache: IdentCache): PRodReader =
readerIndex: int; cache: IdentCache;
config: ConfigRef): PRodReader =
new(result)
result.cache = cache
result.config = config
try:
result.memfile = memfiles.open(modfilename)
except OSError:
@@ -757,13 +761,13 @@ proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
# load the type:
var oldPos = r.pos
var d = iiTableGet(r.index.tab, id)
if d == InvalidKey: internalError(info, "rrGetType")
if d == InvalidKey: internalError(r.config, info, "rrGetType")
r.pos = d + r.dataIdx
result = decodeType(r, info)
r.pos = oldPos
type
TFileModuleRec{.final.} = object
TFileModuleRec = object
filename*: string
reason*: TReasonForRecompile
rd*: PRodReader
@@ -776,7 +780,7 @@ var gMods*: TFileModuleMap = @[]
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
# all compiled modules
if rd.dataIdx == 0: internalError(info, "dataIdx == 0")
if rd.dataIdx == 0: internalError(rd.config, info, "dataIdx == 0")
var oldPos = rd.pos
rd.pos = offset + rd.dataIdx
result = decodeSym(rd, info)
@@ -811,7 +815,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
if moduleID < 0:
var x = ""
encodeVInt(id, x)
internalError(info, "missing from both indexes: +" & x)
internalError(r.config, info, "missing from both indexes: +" & x)
var rd = getReader(moduleID)
doAssert rd != nil
d = iiTableGet(rd.index.tab, id)
@@ -821,14 +825,14 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
var x = ""
encodeVInt(id, x)
when false: findSomeWhere(id)
internalError(info, "rrGetSym: no reader found: +" & x)
internalError(r.config, info, "rrGetSym: no reader found: +" & x)
else:
# own symbol:
result = decodeSymSafePos(r, d, info)
if result != nil and result.kind == skStub: rawLoadStub(result)
proc loadInitSection*(r: PRodReader): PNode =
if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection")
if r.initIdx == 0 or r.dataIdx == 0: internalError(r.config, "loadInitSection")
var oldPos = r.pos
r.pos = r.initIdx
result = newNode(nkStmtList)
@@ -845,7 +849,7 @@ proc loadConverters(r: PRodReader) =
# We have to ensure that no exported converter is a stub anymore, and the
# import mechanism takes care of the rest.
if r.convertersIdx == 0 or r.dataIdx == 0:
internalError("importConverters")
internalError(r.config, "importConverters")
r.pos = r.convertersIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
@@ -854,7 +858,7 @@ proc loadConverters(r: PRodReader) =
proc loadMethods(r: PRodReader) =
if r.methodsIdx == 0 or r.dataIdx == 0:
internalError("loadMethods")
internalError(r.config, "loadMethods")
r.pos = r.methodsIdx
while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos)
@@ -872,7 +876,7 @@ proc getHash*(fileIdx: FileIndex): SecureHash =
template growCache*(cache, pos) =
if cache.len <= pos: cache.setLen(pos+1)
proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonForRecompile =
assert fileIdx != InvalidFileIDX
growCache gMods, fileIdx.int32
if gMods[fileIdx.int32].reason != rrEmpty:
@@ -882,8 +886,8 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
var hash = getHash(fileIdx)
gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles
result = rrNone
var rodfile = toGeneratedFile(filename.withPackageName, RodExt)
var r = newRodReader(rodfile, hash, fileIdx.int32, cache)
var rodfile = toGeneratedFile(conf, conf.withPackageName(filename), RodExt)
var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf)
if r == nil:
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else:
@@ -894,30 +898,30 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
# NOTE: we need to process the entire module graph so that no ID will
# be used twice! However, compilation speed does not suffer much from
# this, since results are cached.
var res = checkDep(systemFileIdx, cache)
var res = checkDep(systemFileIdx, cache, conf)
if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i], cache)
res = checkDep(r.modDeps[i], cache, conf)
if res != rrNone:
result = rrModDeps
# we cannot break here, because of side-effects of `checkDep`
if result != rrNone:
rawMessage(hintProcessing, reasonToFrmt[result] % filename)
if result != rrNone or optForceFullMake in gGlobalOptions:
rawMessage(conf, hintProcessing, reasonToFrmt[result] % filename)
if result != rrNone or optForceFullMake in conf.globalOptions:
# recompilation is necessary:
if r != nil: memfiles.close(r.memfile)
r = nil
gMods[fileIdx.int32].rd = r
gMods[fileIdx.int32].reason = result # now we know better
proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodReader =
if conf.symbolFiles in {disabledSf, writeOnlySf, v2Sf}:
module.id = getID()
return nil
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
idgen.loadMaxIds(conf, conf.projectPath / conf.projectName)
let fileIdx = module.fileIdx
discard checkDep(fileIdx, cache)
if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
discard checkDep(fileIdx, cache, conf)
#if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
result = gMods[fileIdx.int32].rd
if result != nil:
module.id = result.moduleID
@@ -930,19 +934,20 @@ proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
module.id = getID()
proc rawLoadStub(s: PSym) =
if s.kind != skStub: internalError("loadStub")
assert s.kind == skStub
#if s.kind != skStub: internalError("loadStub")
var rd = gMods[s.position].rd
var theId = s.id # used for later check
var d = iiTableGet(rd.index.tab, s.id)
if d == InvalidKey: internalError("loadStub: invalid key")
#if d == InvalidKey: internalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, unknownLineInfo())
if rs != s:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
internalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId:
internalError(rs.info, "loadStub: wrong ID")
#MessageOut('loaded stub: ' + s.name.s);
when false:
if rs != s:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
internalError(rs.info, "loadStub: wrong symbol")
elif rs.id != theId:
internalError(rs.info, "loadStub: wrong ID")
proc loadStub*(s: PSym) =
## loads the stub symbol `s`.
@@ -1030,9 +1035,8 @@ proc writeSym(f: File; s: PSym) =
if s.magic != mNone:
f.write('@')
f.write($s.magic)
if s.options != gOptions:
f.write('!')
f.write($s.options)
f.write('!')
f.write($s.options)
if s.position != 0:
f.write('%')
f.write($s.position)
@@ -1083,9 +1087,10 @@ proc writeType(f: File; t: PType) =
f.write("]\n")
proc viewFile(rodfile: string) =
var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache())
let conf = newConfigRef()
var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache(), conf)
if r == nil:
rawMessage(errGenerated, "cannot open file (or maybe wrong version):" &
rawMessage(conf, errGenerated, "cannot open file (or maybe wrong version):" &
rodfile)
return
r.inViewMode = true
@@ -1133,9 +1138,9 @@ proc viewFile(rodfile: string) =
outf.write("FILES(\n")
while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule(r.origFile)
let resolvedPath = findModule(conf, relativePath, r.origFile)
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx)
r.files.add(fileInfoIdx(conf, finalPath))
inc(r.pos) # skip #10
inc(r.line)
outf.writeLine finalPath
@@ -1227,7 +1232,7 @@ proc viewFile(rodfile: string) =
if r.s[r.pos] == ')': inc r.pos
outf.write("<not supported by viewer>)\n")
else:
internalError("invalid section: '" & section &
internalError(r.config, "invalid section: '" & section &
"' at " & $r.line & " in " & r.filename)
skipSection(r)
if r.s[r.pos] == '\x0A':

View File

@@ -37,12 +37,13 @@ type
files: TStringSeq
origFile: string
cache: IdentCache
config: ConfigRef
PRodWriter = ref TRodWriter
proc getDefines(): string =
proc getDefines(conf: ConfigRef): string =
result = ""
for d in definedSymbolNames():
for d in definedSymbolNames(conf.symbols):
if result.len != 0: add(result, " ")
add(result, d)
@@ -57,8 +58,10 @@ proc fileIdx(w: PRodWriter, filename: string): int =
template filename*(w: PRodWriter): string =
toFilename(FileIndex w.module.position)
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache;
config: ConfigRef): PRodWriter =
new(result)
result.config = config
result.sstack = @[]
result.tstack = @[]
initIiTable(result.index.tab)
@@ -67,8 +70,8 @@ proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter
result.imports.r = ""
result.hash = hash
result.module = module
result.defines = getDefines()
result.options = options.gOptions
result.defines = getDefines(config)
result.options = config.options
result.files = @[]
result.inclDeps = ""
result.modDeps = ""
@@ -83,14 +86,14 @@ proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter
proc addModDep(w: PRodWriter, dep: string; info: TLineInfo) =
if w.modDeps.len != 0: add(w.modDeps, ' ')
let resolved = dep.findModule(info.toFullPath)
let resolved = findModule(w.config, dep, info.toFullPath)
encodeVInt(fileIdx(w, resolved), w.modDeps)
const
rodNL = "\x0A"
proc addInclDep(w: PRodWriter, dep: string; info: TLineInfo) =
let resolved = dep.findModule(info.toFullPath)
let resolved = findModule(w.config, dep, info.toFullPath)
encodeVInt(fileIdx(w, resolved), w.inclDeps)
add(w.inclDeps, " ")
encodeStr($secureHashFile(resolved), w.inclDeps)
@@ -201,7 +204,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
result.add("[]")
return
# we need no surrounding [] here because the type is in a line of its own
if t.kind == tyForward: internalError("encodeType: tyForward")
if t.kind == tyForward: internalError(w.config, "encodeType: tyForward")
# for the new rodfile viewer we use a preceding [ so that the data section
# can easily be disambiguated:
add(result, '[')
@@ -454,7 +457,7 @@ proc processStacks(w: PRodWriter, finalPass: bool) =
oldS = slen
oldT = tlen
if finalPass and (oldS != 0 or oldT != 0):
internalError("could not serialize some forwarded symbols/types")
internalError(w.config, "could not serialize some forwarded symbols/types")
proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
pushSym(w, s)
@@ -476,8 +479,8 @@ proc addStmt(w: PRodWriter, n: PNode) =
proc writeRod(w: PRodWriter) =
processStacks(w, true)
var f: File
if not open(f, completeGeneratedFilePath(changeFileExt(
w.filename.withPackageName, RodExt)),
if not open(f, completeGeneratedFilePath(w.config, changeFileExt(
withPackageName(w.config, w.filename), RodExt)),
fmWrite):
#echo "couldn't write rod file for: ", w.filename
return
@@ -506,12 +509,12 @@ proc writeRod(w: PRodWriter) =
f.write(rodNL)
var goptions = "GOPTIONS:"
encodeVInt(cast[int32](gGlobalOptions), goptions)
encodeVInt(cast[int32](w.config.globalOptions), goptions)
f.write(goptions)
f.write(rodNL)
var cmd = "CMD:"
encodeVInt(cast[int32](gCmd), cmd)
encodeVInt(cast[int32](w.config.cmd), cmd)
f.write(cmd)
f.write(rodNL)
@@ -587,17 +590,17 @@ proc process(c: PPassContext, n: PNode): PNode =
of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
nkTemplateDef, nkMacroDef:
let s = n.sons[namePos].sym
if s == nil: internalError(n.info, "rodwrite.process")
if s == nil: internalError(w.config, n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
internalError(n.info, "rodwrite.process: body is nil")
internalError(w.config, n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
addInterfaceSym(w, s)
of nkMethodDef:
let s = n.sons[namePos].sym
if s == nil: internalError(n.info, "rodwrite.process")
if s == nil: internalError(w.config, n.info, "rodwrite.process")
if n.sons[bodyPos] == nil:
internalError(n.info, "rodwrite.process: body is nil")
internalError(w.config, n.info, "rodwrite.process: body is nil")
if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
sfForward notin s.flags:
pushSym(w, s)
@@ -612,7 +615,7 @@ proc process(c: PPassContext, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
if a.sons[0].kind != nkSym: internalError(w.config, a.info, "rodwrite.process")
var s = a.sons[0].sym
addInterfaceSym(w, s)
# this takes care of enum fields too
@@ -627,22 +630,22 @@ proc process(c: PPassContext, n: PNode): PNode =
# end
of nkImportStmt:
for i in countup(0, sonsLen(n) - 1):
addModDep(w, getModuleName(n.sons[i]), n.info)
addModDep(w, getModuleName(w.config, n.sons[i]), n.info)
addStmt(w, n)
of nkFromStmt, nkImportExceptStmt:
addModDep(w, getModuleName(n.sons[0]), n.info)
addModDep(w, getModuleName(w.config, n.sons[0]), n.info)
addStmt(w, n)
of nkIncludeStmt:
for i in countup(0, sonsLen(n) - 1):
addInclDep(w, getModuleName(n.sons[i]), n.info)
addInclDep(w, getModuleName(w.config, n.sons[i]), n.info)
of nkPragma:
addStmt(w, n)
else:
discard
proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
if module.id < 0: internalError("rodwrite: module ID not set")
var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache)
if module.id < 0: internalError(g.config, "rodwrite: module ID not set")
var w = newRodWriter(rodread.getHash FileIndex module.position, module, cache, g.config)
rawAddInterfaceSym(w, module)
result = w
@@ -650,7 +653,7 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
result = process(c, n)
var w = PRodWriter(c)
writeRod(w)
idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
idgen.saveMaxIds(graph.config, graph.config.projectPath / graph.config.projectName)
const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)

View File

@@ -13,7 +13,7 @@
import
ast, modules, idents, passes, passaux, condsyms,
options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
os, times, osproc, wordrecg, strtabs, modulegraphs
os, times, osproc, wordrecg, strtabs, modulegraphs, configuration
# we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle, contains
@@ -26,11 +26,12 @@ proc listDirs(a: VmArgs, filter: set[PathComponent]) =
setResult(a, result)
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
config: ConfigRef): PEvalContext =
graph: ModuleGraph): PEvalContext =
# For Nimble we need to export 'setupVM'.
result = newCtx(module, cache, config)
result = newCtx(module, cache, graph)
result.mode = emRepl
registerAdditionalOps(result)
let conf = graph.config
# captured vars:
var errorMsg: string
@@ -98,13 +99,13 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
cbconf thisDir:
setResult(a, vthisDir)
cbconf put:
options.setConfigVar(getString(a, 0), getString(a, 1))
options.setConfigVar(conf, getString(a, 0), getString(a, 1))
cbconf get:
setResult(a, options.getConfigVar(a.getString 0))
setResult(a, options.getConfigVar(conf, a.getString 0))
cbconf exists:
setResult(a, options.existsConfigVar(a.getString 0))
setResult(a, options.existsConfigVar(conf, a.getString 0))
cbconf nimcacheDir:
setResult(a, options.getNimcacheDir())
setResult(a, options.getNimcacheDir(conf))
cbconf paramStr:
setResult(a, os.paramStr(int a.getInt 0))
cbconf paramCount:
@@ -114,67 +115,66 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
cbconf cmpIgnoreCase:
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
cbconf setCommand:
options.command = a.getString 0
conf.command = a.getString 0
let arg = a.getString 1
if arg.len > 0:
gProjectName = arg
conf.projectName = arg
let path =
if gProjectName.isAbsolute: gProjectName
else: gProjectPath / gProjectName
if conf.projectName.isAbsolute: conf.projectName
else: conf.projectPath / conf.projectName
try:
gProjectFull = canonicalizePath(path)
conf.projectFull = canonicalizePath(conf, path)
except OSError:
gProjectFull = path
conf.projectFull = path
cbconf getCommand:
setResult(a, options.command)
setResult(a, conf.command)
cbconf switch:
processSwitch(a.getString 0, a.getString 1, passPP, module.info, config)
processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf)
cbconf hintImpl:
processSpecificNote(a.getString 0, wHint, passPP, module.info,
a.getString 1)
a.getString 1, conf)
cbconf warningImpl:
processSpecificNote(a.getString 0, wWarning, passPP, module.info,
a.getString 1)
a.getString 1, conf)
cbconf patchFile:
let key = a.getString(0) & "_" & a.getString(1)
var val = a.getString(2).addFileExt(NimExt)
if {'$', '~'} in val:
val = pathSubs(val, vthisDir)
val = pathSubs(conf, val, vthisDir)
elif not isAbsolute(val):
val = vthisDir / val
gModuleOverrides[key] = val
conf.moduleOverrides[key] = val
cbconf selfExe:
setResult(a, os.getAppFilename())
cbconf cppDefine:
if config != nil:
options.cppDefine(config, a.getString(0))
options.cppDefine(conf, a.getString(0))
proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true; config: ConfigRef) =
rawMessage(hintConf, scriptName)
freshDefines=true; conf: ConfigRef) =
rawMessage(conf, hintConf, scriptName)
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
let graph = newModuleGraph(config)
if freshDefines: initDefines()
let graph = newModuleGraph(conf)
if freshDefines: initDefines(conf.symbols)
defineSymbol("nimscript")
defineSymbol("nimconfig")
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(semPass)
registerPass(evalPass)
searchPaths.add(options.libpath)
conf.searchPaths.add(conf.libpath)
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName, config)
vm.globalCtx = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule(cache)
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts()
resetSystemArtifacts(graph)
vm.globalCtx = nil
# do not remove the defined symbols
#initDefines()
undefSymbol("nimscript")
undefSymbol("nimconfig")
undefSymbol(conf.symbols, "nimscript")
undefSymbol(conf.symbols, "nimconfig")

View File

@@ -16,7 +16,7 @@ import
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings, pluginsupport, plugins.active, rod
semparallel, lowerings, pluginsupport, plugins.active, rod, configuration
from modulegraphs import ModuleGraph
@@ -33,7 +33,7 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode
proc semProcBody(c: PContext, n: PNode): PNode
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode
proc changeType(n: PNode, newType: PType, check: bool)
proc changeType(c: PContext; n: PNode, newType: PType, check: bool)
proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType
@@ -64,14 +64,14 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
# templates perform some quick check whether the cursor is actually in
# the generic or template.
when defined(nimsuggest):
if gCmd == cmdIdeTools and requiresCheck:
if c.config.cmd == cmdIdeTools and requiresCheck:
#if optIdeDebug in gGlobalOptions:
# echo "passing to safeSemExpr: ", renderTree(n)
discard safeSemExpr(c, n)
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
if arg.typ.isNil:
localError(arg.info, errExprXHasNoType,
localError(c.config, arg.info, "expression has no type: " &
renderTree(arg, {renderNoComments}))
# error correction:
result = copyTree(arg)
@@ -79,14 +79,14 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
else:
result = indexTypesMatch(c, formal, arg.typ, arg)
if result == nil:
typeMismatch(info, formal, arg.typ)
typeMismatch(c.config, info, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
else:
let x = result.skipConv
if x.kind in {nkPar, nkTupleConstr} and formal.kind != tyExpr:
changeType(x, formal, check=true)
changeType(c, x, formal, check=true)
else:
result = skipHiddenSubConv(result)
#result.typ = takeType(formal, arg.typ)
@@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType =
commonType(x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
when defined(nimsuggest):
suggestDecl(c, n, result)
@@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# and sfGenSym in n.sym.flags:
result = n.sym
if result.kind != kind:
localError(n.info, "cannot use symbol of kind '" &
localError(c.config, n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'")
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym:
@@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind;
proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags)
if t != nil:
if t == typ:
localError(info, "invalid type: '" & typeToString(typ) &
localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
else:
localError(info, "invalid type: '" & typeToString(t) &
localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(typ.n.info, typ, skProc)
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
result = evaluated
let expectedType = eOrig.typ.skipTypes({tyStatic})
if hasCycle(result):
globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further")
globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further")
result = errorNode(c, eOrig)
else:
semmacrosanity.annotateType(result, expectedType)
semmacrosanity.annotateType(result, expectedType, c.config)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
@@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil: return
result = getConstExpr(c.module, e)
result = getConstExpr(c.module, e, c.graph)
if result != nil: return
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
let oldErrorCount = c.config.errorCounter
let oldErrorMax = c.config.errorMax
let oldErrorOutputs = errorOutputs
errorOutputs = {}
msgs.gErrorMax = high(int)
c.config.errorMax = high(int)
try:
result = evalConstExpr(c.module, c.cache, c.graph.config, e)
result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty:
result = nil
else:
@@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
except ERecoverableError:
result = nil
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
errorOutputs = oldErrorOutputs
const
errConstExprExpected = "constant expression expected"
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
localError(n.info, errConstExprExpected)
localError(c.config, n.info, errConstExprExpected)
return n
result = getConstExpr(c.module, e)
result = getConstExpr(c.module, e, c.graph)
if result == nil:
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
result = evalConstExpr(c.module, c.cache, c.graph.config, e)
result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty:
if e.info != n.info:
pushInfoContext(n.info)
localError(e.info, errConstExprExpected)
localError(c.config, e.info, errConstExprExpected)
popInfoContext()
else:
localError(e.info, errConstExprExpected)
localError(c.config, e.info, errConstExprExpected)
# error correction:
result = e
else:
@@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
result = semExprWithType(c, n, flags)
if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result)
var evaluated = getConstExpr(c.module, result, c.graph)
if evaluated != nil: return evaluated
evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated
@@ -379,7 +382,7 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
## contains.
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
globalError(s.info, errTemplateInstantiationTooNested)
globalError(c.config, s.info, "template instantiation too nested")
c.friendModules.add(s.owner.getModule)
result = macroResult
@@ -421,43 +424,46 @@ proc semAfterMacroCall(c: PContext, call, macroResult: PNode,
dec(evalTemplateCounter)
discard c.friendModules.pop()
const
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
flags: TExprFlags = {}): PNode =
pushInfoContext(nOrig.info)
markUsed(n.info, sym, c.graph.usageSym)
markUsed(c.config, n.info, sym, c.graph.usageSym)
styleCheckUse(n.info, sym)
if sym == c.p.owner:
globalError(n.info, errRecursiveDependencyX, sym.name.s)
globalError(c.config, n.info, "recursive dependency: '$1'" % sym.name.s)
let genericParams = if sfImmediate in sym.flags: 0
else: sym.ast[genericParamsPos].len
let suppliedParams = max(n.safeLen - 1, 0)
if suppliedParams < genericParams:
globalError(n.info, errMissingGenericParamsForTemplate, n.renderTree)
globalError(c.config, n.info, errMissingGenericParamsForTemplate % n.renderTree)
#if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.cache, c.graph.config, n, nOrig, sym)
result = evalMacroCall(c.module, c.cache, c.graph, n, nOrig, sym)
if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, sym, result)
popInfoContext()
proc forceBool(c: PContext, n: PNode): PNode =
result = fitNode(c, getSysType(tyBool), n, n.info)
result = fitNode(c, getSysType(c.graph, n.info, tyBool), n, n.info)
if result == nil: result = n
proc semConstBoolExpr(c: PContext, n: PNode): PNode =
let nn = semExprWithType(c, n)
result = fitNode(c, getSysType(tyBool), nn, nn.info)
result = fitNode(c, getSysType(c.graph, n.info, tyBool), nn, nn.info)
if result == nil:
localError(n.info, errConstExprExpected)
localError(c.config, n.info, errConstExprExpected)
return nn
result = getConstExpr(c.module, result)
result = getConstExpr(c.module, result, c.graph)
if result == nil:
localError(n.info, errConstExprExpected)
localError(c.config, n.info, errConstExprExpected)
result = nn
proc semGenericStmt(c: PContext, n: PNode): PNode
@@ -470,14 +476,14 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
var prc = c.generics[i].inst.sym
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)
internalError(c.config, prc.info, "no code for " & prc.name.s)
else:
addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var c = newContext(graph, module, cache)
if c.p != nil: internalError(module.info, "sem.myOpen")
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExpr
c.semTryExpr = tryExpr
@@ -495,14 +501,14 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
c.importTable = openScope(c)
c.importTable.addSym(module) # a module knows itself
if sfSystemModule in module.flags:
magicsys.systemModule = module # set global variable!
graph.systemModule = module
c.topLevelScope = openScope(c)
# don't be verbose unless the module belongs to the main package:
if module.owner.id == gMainPackageId:
gNotes = gMainPackageNotes
graph.config.notes = graph.config.mainPackageNotes
else:
if gMainPackageNotes == {}: gMainPackageNotes = gNotes
gNotes = ForeignPackageNotes
if graph.config.mainPackageNotes == {}: graph.config.mainPackageNotes = graph.config.notes
graph.config.notes = graph.config.foreignPackageNotes
result = c
proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
@@ -511,30 +517,30 @@ proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContex
proc replayMethodDefs(graph: ModuleGraph; rd: PRodReader) =
for m in items(rd.methods): methodDef(graph, m, true)
proc isImportSystemStmt(n: PNode): bool =
if magicsys.systemModule == nil: return false
proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
if g.systemModule == nil: return false
case n.kind
of nkImportStmt:
for x in n:
if x.kind == nkIdent:
let f = checkModuleName(x, false)
if f == magicsys.systemModule.info.fileIndex:
let f = checkModuleName(g.config, x, false)
if f == g.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:
let f = checkModuleName(g.config, n[0], false)
if f == g.systemModule.info.fileIndex:
return true
else: discard
proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
if n.kind == nkDefer:
localError(n.info, "defer statement not supported at top level")
if c.topStmts == 0 and not isImportSystemStmt(n):
localError(c.config, n.info, "defer statement not supported at top level")
if c.topStmts == 0 and not isImportSystemStmt(c.graph, n):
if sfSystemModule notin c.module.flags and
n.kind notin {nkEmpty, nkCommentStmt}:
c.importTable.addSym magicsys.systemModule # import the "System" identifier
importAllSymbols(c, magicsys.systemModule)
c.importTable.addSym c.graph.systemModule # import the "System" identifier
importAllSymbols(c, c.graph.systemModule)
inc c.topStmts
else:
inc c.topStmts
@@ -556,11 +562,11 @@ proc semStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
if result.kind != nkEmpty: addSon(a, result)
result = a
result = hloStmt(c, result)
if gCmd == cmdInteractive and not isEmptyType(result.typ):
if c.config.cmd == cmdInteractive and not isEmptyType(result.typ):
result = buildEchoStmt(c, result)
if gCmd == cmdIdeTools:
if c.config.cmd == cmdIdeTools:
appendToModule(c.module, result)
result = transformStmt(c.module, result)
result = transformStmt(c.graph, c.module, result)
proc recoverContext(c: PContext) =
# clean up in case of a semantic error: We clean up the stacks, etc. This is
@@ -573,7 +579,7 @@ proc recoverContext(c: PContext) =
proc myProcess(context: PPassContext, n: PNode): PNode =
var c = PContext(context)
# no need for an expensive 'try' if we stop after the first error anyway:
if msgs.gErrorMax <= 1:
if c.config.errorMax <= 1:
result = semStmtAndGenerateGenerics(c, n)
else:
let oldContextLen = msgs.getInfoContextLen()
@@ -589,16 +595,16 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
result = nil
else:
result = ast.emptyNode
#if gCmd == cmdIdeTools: findSuggest(c, n)
#if c.config.cmd == cmdIdeTools: findSuggest(c, n)
rod.storeNode(c.module, result)
proc testExamples(c: PContext) =
let inp = toFullPath(c.module.info)
let outp = inp.changeFileExt"" & "_examples.nim"
renderModule(c.runnableExamples, inp, outp)
let backend = if isDefined("js"): "js"
elif isDefined("cpp"): "cpp"
elif isDefined("objc"): "objc"
let backend = if isDefined(c.config, "js"): "js"
elif isDefined(c.config, "cpp"): "cpp"
elif isDefined(c.config, "objc"): "objc"
else: "c"
if os.execShellCmd("nim " & backend & " -r " & outp) != 0:
quit "[Examples] failed"
@@ -606,13 +612,13 @@ proc testExamples(c: PContext) =
proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
var c = PContext(context)
if gCmd == cmdIdeTools and not c.suggestionsMade:
if c.config.cmd == cmdIdeTools and not c.suggestionsMade:
suggestSentinel(c)
closeScope(c) # close module's scope
rawCloseScope(c) # imported symbols; don't check for unused ones!
result = newNode(nkStmtList)
if n != nil:
internalError(n.info, "n is not nil") #result := n;
internalError(c.config, n.info, "n is not nil") #result := n;
addCodeForGenerics(c, result)
if c.module.ast != nil:
result.add(c.module.ast)

View File

@@ -33,7 +33,7 @@ proc at(a, i: PNode, elemType: PType): PNode =
proc liftBodyTup(c: var TLiftCtx; t: PType; body, x, y: PNode) =
for i in 0 ..< t.len:
let lit = lowerings.newIntLit(i)
let lit = lowerings.newIntLit(c.c.graph, x.info, i)
liftBodyAux(c, t.sons[i], body, x.at(lit, t.sons[i]), y.at(lit, t.sons[i]))
proc dotField(x: PNode, f: PSym): PNode =
@@ -66,15 +66,15 @@ proc liftBodyObj(c: var TLiftCtx; n, body, x, y: PNode) =
liftBodyObj(c, n[i].lastSon, branch.sons[L-1], x, y)
caseStmt.add(branch)
body.add(caseStmt)
localError(c.info, "cannot lift assignment operator to 'case' object")
localError(c.c.config, c.info, "cannot lift assignment operator to 'case' object")
of nkRecList:
for t in items(n): liftBodyObj(c, t, body, x, y)
else:
illFormedAstLocal(n)
illFormedAstLocal(n, c.c.config)
proc genAddr(c: PContext; x: PNode): PNode =
if x.kind == nkHiddenDeref:
checkSonsLen(x, 1)
checkSonsLen(x, 1, c.config)
result = x.sons[0]
else:
result = newNodeIT(nkHiddenAddr, x.info, makeVarType(c, x.typ))
@@ -82,7 +82,7 @@ proc genAddr(c: PContext; x: PNode): PNode =
proc newAsgnCall(c: PContext; op: PSym; x, y: PNode): PNode =
if sfError in op.flags:
localError(x.info, errWrongSymbolX, op.name.s)
localError(c.config, x.info, "usage of '$1' is a user-defined error" % op.name.s)
result = newNodeI(nkCall, x.info)
result.add newSymNode(op)
result.add genAddr(c, x)
@@ -124,7 +124,7 @@ proc considerAsgnOrSink(c: var TLiftCtx; t: PType; body, x, y: PNode;
op = field
if op == nil:
op = liftBody(c.c, t, c.kind, c.info)
markUsed(c.info, op, c.c.graph.usageSym)
markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op)
body.add newAsgnCall(c.c, op, x, y)
result = true
@@ -134,7 +134,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDestructor:
let op = t.destructor
if op != nil:
markUsed(c.info, op, c.c.graph.usageSym)
markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op)
body.add destructorCall(c.c, op, x)
result = true
@@ -145,7 +145,7 @@ proc considerOverloadedOp(c: var TLiftCtx; t: PType; body, x, y: PNode): bool =
of attachedDeepCopy:
let op = t.deepCopy
if op != nil:
markUsed(c.info, op, c.c.graph.usageSym)
markUsed(c.c.config, c.info, op, c.c.graph.usageSym)
styleCheckUse(c.info, op)
body.add newDeepCopyCall(op, x, y)
result = true
@@ -163,37 +163,37 @@ proc addVar(father, v, value: PNode) =
proc declareCounter(c: var TLiftCtx; body: PNode; first: BiggestInt): PNode =
var temp = newSym(skTemp, getIdent(lowerings.genPrefix), c.fn, c.info)
temp.typ = getSysType(tyInt)
temp.typ = getSysType(c.c.graph, body.info, tyInt)
incl(temp.flags, sfFromGeneric)
var v = newNodeI(nkVarSection, c.info)
result = newSymNode(temp)
v.addVar(result, lowerings.newIntLit(first))
v.addVar(result, lowerings.newIntLit(c.c.graph, body.info, first))
body.add v
proc genBuiltin(magic: TMagic; name: string; i: PNode): PNode =
proc genBuiltin(g: ModuleGraph; magic: TMagic; name: string; i: PNode): PNode =
result = newNodeI(nkCall, i.info)
result.add createMagic(name, magic).newSymNode
result.add createMagic(g, name, magic).newSymNode
result.add i
proc genWhileLoop(c: var TLiftCtx; i, dest: PNode): PNode =
result = newNodeI(nkWhileStmt, c.info, 2)
let cmp = genBuiltin(mLeI, "<=", i)
cmp.add genHigh(dest)
cmp.typ = getSysType(tyBool)
let cmp = genBuiltin(c.c.graph, mLeI, "<=", i)
cmp.add genHigh(c.c.graph, dest)
cmp.typ = getSysType(c.c.graph, c.info, tyBool)
result.sons[0] = cmp
result.sons[1] = newNodeI(nkStmtList, c.info)
proc addIncStmt(body, i: PNode) =
let incCall = genBuiltin(mInc, "inc", i)
incCall.add lowerings.newIntLit(1)
proc addIncStmt(c: var TLiftCtx; body, i: PNode) =
let incCall = genBuiltin(c.c.graph, mInc, "inc", i)
incCall.add lowerings.newIntLit(c.c.graph, c.info, 1)
body.add incCall
proc newSeqCall(c: PContext; x, y: PNode): PNode =
# don't call genAddr(c, x) here:
result = genBuiltin(mNewSeq, "newSeq", x)
let lenCall = genBuiltin(mLengthSeq, "len", y)
lenCall.typ = getSysType(tyInt)
result = genBuiltin(c.graph, mNewSeq, "newSeq", x)
let lenCall = genBuiltin(c.graph, mLengthSeq, "len", y)
lenCall.typ = getSysType(c.graph, x.info, tyInt)
result.add lenCall
proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
@@ -212,7 +212,7 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
let elemType = t.lastSon
liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType),
y.at(i, elemType))
addIncStmt(whileLoop.sons[1], i)
addIncStmt(c, whileLoop.sons[1], i)
body.add whileLoop
else:
defaultOp(c, t, body, x, y)
@@ -231,20 +231,20 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
# have to go through some indirection; we delegate this to the codegen:
let call = newNodeI(nkCall, c.info, 2)
call.typ = t
call.sons[0] = newSymNode(createMagic("deepCopy", mDeepCopy))
call.sons[0] = newSymNode(createMagic(c.c.graph, "deepCopy", mDeepCopy))
call.sons[1] = y
body.add newAsgnStmt(x, call)
of tyVarargs, tyOpenArray:
localError(c.info, errGenerated, "cannot copy openArray")
localError(c.c.config, c.info, "cannot copy openArray")
of tyFromExpr, tyProxy, tyBuiltInTypeClass, tyUserTypeClass,
tyUserTypeClassInst, tyCompositeTypeClass, tyAnd, tyOr, tyNot, tyAnything,
tyGenericParam, tyGenericBody, tyNil, tyExpr, tyStmt,
tyTypeDesc, tyGenericInvocation, tyForward:
internalError(c.info, "assignment requested for type: " & typeToString(t))
internalError(c.c.config, c.info, "assignment requested for type: " & typeToString(t))
of tyOrdinal, tyRange, tyInferred,
tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink:
liftBodyAux(c, lastSon(t), body, x, y)
of tyUnused, tyOptAsRef: internalError("liftBodyAux")
of tyUnused, tyOptAsRef: internalError(c.c.config, "liftBodyAux")
proc newProcType(info: TLineInfo; owner: PSym): PType =
result = newType(tyProc, owner)

View File

@@ -202,24 +202,31 @@ proc presentFailedCandidates(c: PContext, n: PNode, errors: CandidateErrors):
result = (prefer, candidates)
const
errTypeMismatch = "type mismatch: got <"
errButExpected = "but expected one of: "
errUndeclaredField = "undeclared field: '$1'"
errUndeclaredRoutine = "attempting to call undeclared routine: '$1'"
errAmbiguousCallXYZ = "ambiguous call; both $1 and $2 match for: $3"
proc notFoundError*(c: PContext, n: PNode, errors: CandidateErrors) =
# Gives a detailed error message; this is separated from semOverloadedCall,
# as semOverlodedCall is already pretty slow (and we need this information
# only in case of an error).
if errorOutputs == {}:
# fail fast:
globalError(n.info, errTypeMismatch, "")
globalError(c.config, n.info, "type mismatch")
if errors.len == 0:
localError(n.info, errExprXCannotBeCalled, n[0].renderTree)
localError(c.config, n.info, "expression '$1' cannot be called" % n[0].renderTree)
return
let (prefer, candidates) = presentFailedCandidates(c, n, errors)
var result = msgKindToString(errTypeMismatch)
var result = errTypeMismatch
add(result, describeArgs(c, n, 1, prefer))
add(result, '>')
if candidates != "":
add(result, "\n" & msgKindToString(errButExpected) & "\n" & candidates)
localError(n.info, errGenerated, result & "\nexpression: " & $n)
add(result, "\n" & errButExpected & "\n" & candidates)
localError(c.config, n.info, result & "\nexpression: " & $n)
proc bracketNotFoundError(c: PContext; n: PNode) =
var errors: CandidateErrors = @[]
@@ -234,7 +241,7 @@ proc bracketNotFoundError(c: PContext; n: PNode) =
enabled: false))
symx = nextOverloadIter(o, c, headSymbol)
if errors.len == 0:
localError(n.info, "could not resolve: " & $n)
localError(c.config, n.info, "could not resolve: " & $n)
else:
notFoundError(c, n, errors)
@@ -277,7 +284,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
else: return
if nfDotField in n.flags:
internalAssert f.kind == nkIdent and n.sonsLen >= 2
internalAssert c.config, f.kind == nkIdent and n.len >= 2
# leave the op head symbol empty,
# we are going to try multiple variants
@@ -306,13 +313,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
if overloadsState == csEmpty and result.state == csEmpty:
if nfDotField in n.flags and nfExplicitCall notin n.flags:
localError(n.info, errUndeclaredField, considerQuotedIdent(f, n).s)
localError(c.config, n.info, errUndeclaredField % considerQuotedIdent(c.config, f, n).s)
else:
localError(n.info, errUndeclaredRoutine, considerQuotedIdent(f, n).s)
localError(c.config, n.info, errUndeclaredRoutine % considerQuotedIdent(c.config, f, n).s)
return
elif result.state != csMatch:
if nfExprCall in n.flags:
localError(n.info, errExprXCannotBeCalled,
localError(c.config, n.info, "expression '$1' cannot be called" %
renderTree(n, {renderNoComments}))
else:
if {nfDotField, nfDotSetter} * n.flags != {}:
@@ -322,13 +329,13 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
return
if alt.state == csMatch and cmpCandidates(result, alt) == 0 and
not sameMethodDispatcher(result.calleeSym, alt.calleeSym):
internalAssert result.state == csMatch
internalAssert c.config, result.state == csMatch
#writeMatches(result)
#writeMatches(alt)
if errorOutputs == {}:
# quick error message for performance of 'compiles' built-in:
globalError(n.info, errGenerated, "ambiguous call")
elif gErrorCounter == 0:
globalError(c.config, n.info, errGenerated, "ambiguous call")
elif c.config.errorCounter == 0:
# don't cascade errors
var args = "("
for i in countup(1, sonsLen(n) - 1):
@@ -336,7 +343,7 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
add(args, typeToString(n.sons[i].typ))
add(args, ")")
localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
localError(c.config, n.info, errAmbiguousCallXYZ % [
getProcHeader(result.calleeSym), getProcHeader(alt.calleeSym),
args])
@@ -377,7 +384,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
result.typ = generateTypeInstance(c, m.bindings, arg.info,
formal.skipTypes({tyCompositeTypeClass}))
else:
typeMismatch(arg.info, formal, arg.typ)
typeMismatch(c.config, arg.info, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
@@ -385,7 +392,7 @@ proc inferWithMetatype(c: PContext, formal: PType,
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
assert x.state == csMatch
var finalCallee = x.calleeSym
markUsed(n.sons[0].info, finalCallee, c.graph.usageSym)
markUsed(c.config, n.sons[0].info, finalCallee, c.graph.usageSym)
styleCheckUse(n.sons[0].info, finalCallee)
assert finalCallee.ast != nil
if x.hasFauxMatch:
@@ -411,7 +418,7 @@ proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
of skType:
x.call.add newSymNode(s, n.info)
else:
internalAssert false
internalAssert c.config, false
result = x.call
instGenericConvertersSons(c, result, x)
@@ -435,7 +442,7 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
# this may be triggered, when the explain pragma is used
if errors.len > 0:
let (_, candidates) = presentFailedCandidates(c, n, errors)
message(n.info, hintUserRaw,
message(c.config, n.info, hintUserRaw,
"Non-matching candidates for " & renderTree(n) & "\n" &
candidates)
result = semResolvedCall(c, n, r)
@@ -468,8 +475,8 @@ proc semOverloadedCall(c: PContext, n, nOrig: PNode,
else:
notFoundError(c, n, errors)
proc explicitGenericInstError(n: PNode): PNode =
localError(n.info, errCannotInstantiateX, renderTree(n))
proc explicitGenericInstError(c: PContext; n: PNode): PNode =
localError(c.config, n.info, errCannotInstantiateX % renderTree(n))
result = n
proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
@@ -484,7 +491,7 @@ proc explicitGenericSym(c: PContext, n: PNode, s: PSym): PNode =
if tm in {isNone, isConvertible}: return nil
var newInst = generateInstance(c, s, m.bindings, n.info)
newInst.typ.flags.excl tfUnresolved
markUsed(n.info, s, c.graph.usageSym)
markUsed(c.config, n.info, s, c.graph.usageSym)
styleCheckUse(n.info, s)
result = newSymNode(newInst, n.info)
@@ -500,11 +507,11 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# number of generic type parameters:
if safeLen(s.ast.sons[genericParamsPos]) != n.len-1:
let expected = safeLen(s.ast.sons[genericParamsPos])
localError(n.info, errGenerated, "cannot instantiate: " & renderTree(n) &
"; got " & $(n.len-1) & " type(s) but expected " & $expected)
localError(c.config, n.info, errGenerated, "cannot instantiate: '" & renderTree(n) &
"'; got " & $(n.len-1) & " type(s) but expected " & $expected)
return n
result = explicitGenericSym(c, n, s)
if result == nil: result = explicitGenericInstError(n)
if result == nil: result = explicitGenericInstError(c, n)
elif a.kind in {nkClosedSymChoice, nkOpenSymChoice}:
# choose the generic proc with the proper number of type parameters.
# XXX I think this could be improved by reusing sigmatch.paramTypesMatch.
@@ -522,10 +529,10 @@ proc explicitGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode =
# get rid of nkClosedSymChoice if not ambiguous:
if result.len == 1 and a.kind == nkClosedSymChoice:
result = result[0]
elif result.len == 0: result = explicitGenericInstError(n)
# candidateCount != 1: return explicitGenericInstError(n)
elif result.len == 0: result = explicitGenericInstError(c, n)
# candidateCount != 1: return explicitGenericInstError(c, n)
else:
result = explicitGenericInstError(n)
result = explicitGenericInstError(c, n)
proc searchForBorrowProc(c: PContext, startScope: PScope, fn: PSym): PSym =
# Searchs for the fn in the symbol table. If the parameter lists are suitable

View File

@@ -14,7 +14,7 @@ import
wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef,
modulegraphs
modulegraphs, configuration
type
TOptionEntry* = object # entries to put on a stack for pragma parsing
@@ -140,6 +140,8 @@ type
# would otherwise fail.
runnableExamples*: PNode
template config*(c: PContext): ConfigRef = c.graph.config
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
result.genericSym = s
result.inst = inst
@@ -165,7 +167,7 @@ proc pushOwner*(c: PContext; owner: PSym) =
proc popOwner*(c: PContext) =
var length = len(c.graph.owners)
if length > 0: setLen(c.graph.owners, length - 1)
else: internalError("popOwner")
else: internalError(c.config, "popOwner")
proc lastOptionEntry*(c: PContext): POptionEntry =
result = c.optionStack[^1]
@@ -201,19 +203,19 @@ proc considerGenSyms*(c: PContext; n: PNode) =
for i in 0..<n.safeLen:
considerGenSyms(c, n.sons[i])
proc newOptionEntry*(): POptionEntry =
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
new(result)
result.options = gOptions
result.options = conf.options
result.defaultCC = ccDefault
result.dynlib = nil
result.notes = gNotes
result.notes = conf.notes
proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext =
new(result)
result.ambiguousSymbols = initIntSet()
result.optionStack = @[]
result.libs = @[]
result.optionStack.add(newOptionEntry())
result.optionStack.add(newOptionEntry(graph.config))
result.module = module
result.friendModules = @[module]
result.converters = @[]
@@ -256,7 +258,7 @@ proc newTypeS*(kind: TTypeKind, c: PContext): PType =
proc makePtrType*(c: PContext, baseType: PType): PType =
result = newTypeS(tyPtr, c)
addSonSkipIntLit(result, baseType.assertNotNil)
addSonSkipIntLit(result, baseType)
proc makeTypeWithModifier*(c: PContext,
modifier: TTypeKind,
@@ -267,25 +269,26 @@ proc makeTypeWithModifier*(c: PContext,
result = baseType
else:
result = newTypeS(modifier, c)
addSonSkipIntLit(result, baseType.assertNotNil)
addSonSkipIntLit(result, baseType)
proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
if baseType.kind == kind:
result = baseType
else:
result = newTypeS(kind, c)
addSonSkipIntLit(result, baseType.assertNotNil)
addSonSkipIntLit(result, baseType)
proc makeTypeDesc*(c: PContext, typ: PType): PType =
if typ.kind == tyTypeDesc:
result = typ
else:
result = newTypeS(tyTypeDesc, c)
result.addSonSkipIntLit(typ.assertNotNil)
result.addSonSkipIntLit(typ)
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
let typedesc = makeTypeDesc(c, typ)
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc)
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info,
c.config.options).linkTo(typedesc)
return newSymNode(sym, info)
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
@@ -340,21 +343,20 @@ proc makeNotType*(c: PContext, t1: PType): PType =
result.flags.incl(t1.flags * {tfHasStatic})
result.flags.incl tfHasMeta
proc nMinusOne*(n: PNode): PNode =
proc nMinusOne(c: PContext; n: PNode): PNode =
result = newNode(nkCall, n.info, @[
newSymNode(getSysMagic("pred", mPred)),
n])
newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n])
# Remember to fix the procs below this one when you make changes!
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
let intType = getSysType(tyInt)
let intType = getSysType(c.graph, n.info, tyInt)
result = newTypeS(tyRange, c)
result.sons = @[intType]
if n.typ != nil and n.typ.n == nil:
result.flags.incl tfUnresolved
result.n = newNode(nkRange, n.info, @[
newIntTypeNode(nkIntLit, 0, intType),
makeStaticExpr(c, n.nMinusOne)])
makeStaticExpr(c, nMinusOne(c, n))])
template rangeHasUnresolvedStatic*(t: PType): bool =
tfUnresolved in t.flags
@@ -373,7 +375,8 @@ proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
dest.size = - 1
proc makeRangeType*(c: PContext; first, last: BiggestInt;
info: TLineInfo; intType = getSysType(tyInt)): PType =
info: TLineInfo; intType: PType = nil): PType =
let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
var n = newNodeI(nkRange, info)
addSon(n, newIntTypeNode(nkIntLit, first, intType))
addSon(n, newIntTypeNode(nkIntLit, last, intType))
@@ -386,17 +389,17 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =
incl(s.flags, sfAddrTaken)
# XXX add to 'c' for global analysis
proc illFormedAst*(n: PNode) =
globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc illFormedAst*(n: PNode; conf: ConfigRef) =
globalError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc illFormedAstLocal*(n: PNode) =
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
proc checkSonsLen*(n: PNode, length: int) =
if sonsLen(n) != length: illFormedAst(n)
proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
if sonsLen(n) != length: illFormedAst(n, conf)
proc checkMinSonsLen*(n: PNode, length: int) =
if sonsLen(n) < length: illFormedAst(n)
proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
if sonsLen(n) < length: illFormedAst(n, conf)
proc isTopLevel*(c: PContext): bool {.inline.} =
result = c.currentScope.depthLevel <= 2

File diff suppressed because it is too large Load Diff

View File

@@ -16,16 +16,17 @@ type
tupleIndex: int
field: PSym
replaceByFieldName: bool
c: PContext
proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
case n.kind
of nkEmpty..pred(nkIdent), succ(nkSym)..nkNilLit: result = n
of nkIdent, nkSym:
result = n
let ident = considerQuotedIdent(n)
let ident = considerQuotedIdent(c.c.config, n)
var L = sonsLen(forLoop)
if c.replaceByFieldName:
if ident.id == considerQuotedIdent(forLoop[0]).id:
if ident.id == considerQuotedIdent(c.c.config, forLoop[0]).id:
let fieldName = if c.tupleType.isNil: c.field.name.s
elif c.tupleType.n.isNil: "Field" & $c.tupleIndex
else: c.tupleType.n.sons[c.tupleIndex].sym.name.s
@@ -33,7 +34,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
return
# other fields:
for i in ord(c.replaceByFieldName)..L-3:
if ident.id == considerQuotedIdent(forLoop[i]).id:
if ident.id == considerQuotedIdent(c.c.config, forLoop[i]).id:
var call = forLoop.sons[L-2]
var tupl = call.sons[i+1-ord(c.replaceByFieldName)]
if c.field.isNil:
@@ -47,7 +48,7 @@ proc instFieldLoopBody(c: TFieldInstCtx, n: PNode, forLoop: PNode): PNode =
break
else:
if n.kind == nkContinueStmt:
localError(n.info, errGenerated,
localError(c.c.config, n.info,
"'continue' not supported in a 'fields' loop")
result = copyNode(n)
newSons(result, sonsLen(n))
@@ -63,6 +64,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
case typ.kind
of nkSym:
var fc: TFieldInstCtx # either 'tup[i]' or 'field' is valid
fc.c = c.c
fc.field = typ.sym
fc.replaceByFieldName = c.m == mFieldPairs
openScope(c.c)
@@ -76,7 +78,7 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
let L = forLoop.len
let call = forLoop.sons[L-2]
if call.len > 2:
localError(forLoop.info, errGenerated,
localError(c.c.config, forLoop.info,
"parallel 'fields' iterator does not work for 'case' objects")
return
# iterate over the selector:
@@ -99,17 +101,17 @@ proc semForObjectFields(c: TFieldsCtx, typ, forLoop, father: PNode) =
of nkRecList:
for t in items(typ): semForObjectFields(c, t, forLoop, father)
else:
illFormedAstLocal(typ)
illFormedAstLocal(typ, c.c.config)
proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
# so that 'break' etc. work as expected, we produce
# a 'while true: stmt; break' loop ...
result = newNodeI(nkWhileStmt, n.info, 2)
var trueSymbol = strTableGet(magicsys.systemModule.tab, getIdent"true")
var trueSymbol = strTableGet(c.graph.systemModule.tab, getIdent"true")
if trueSymbol == nil:
localError(n.info, errSystemNeeds, "true")
localError(c.config, n.info, "system needs: 'true'")
trueSymbol = newSym(skUnknown, getIdent"true", getCurrOwner(c), n.info)
trueSymbol.typ = getSysType(tyBool)
trueSymbol.typ = getSysType(c.graph, n.info, tyBool)
result.sons[0] = newSymNode(trueSymbol, n.info)
var stmts = newNodeI(nkStmtList, n.info)
@@ -118,18 +120,18 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var length = sonsLen(n)
var call = n.sons[length-2]
if length-2 != sonsLen(call)-1 + ord(m==mFieldPairs):
localError(n.info, errWrongNumberOfVariables)
localError(c.config, n.info, errWrongNumberOfVariables)
return result
const skippedTypesForFields = abstractVar - {tyTypeDesc} + tyUserTypeClasses
var tupleTypeA = skipTypes(call.sons[1].typ, skippedTypesForFields)
if tupleTypeA.kind notin {tyTuple, tyObject}:
localError(n.info, errGenerated, "no object or tuple type")
localError(c.config, n.info, errGenerated, "no object or tuple type")
return result
for i in 1..call.len-1:
var tupleTypeB = skipTypes(call.sons[i].typ, skippedTypesForFields)
if not sameType(tupleTypeA, tupleTypeB):
typeMismatch(call.sons[i].info, tupleTypeA, tupleTypeB)
typeMismatch(c.config, call.sons[i].info, tupleTypeA, tupleTypeB)
inc(c.p.nestedLoopCounter)
if tupleTypeA.kind == tyTuple:
@@ -139,6 +141,7 @@ proc semForFields(c: PContext, n: PNode, m: TMagic): PNode =
var fc: TFieldInstCtx
fc.tupleType = tupleTypeA
fc.tupleIndex = i
fc.c = c
fc.replaceByFieldName = m == mFieldPairs
var body = instFieldLoopBody(fc, loopBody, n)
inc c.inUnrolledContext

View File

@@ -13,84 +13,16 @@
import
strutils, options, ast, astalgo, trees, treetab, nimsets, times,
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
commands, magicsys
commands, magicsys, modulegraphs, strtabs
proc getConstExpr*(m: PSym, n: PNode): PNode
# evaluates the constant expression or returns nil if it is no constant
# expression
proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
proc leValueConv*(a, b: PNode): bool
proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
proc newStrNodeT*(strVal: string, n: PNode): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ):
result = true
proc foldAdd(a, b: BiggestInt, n: PNode): PNode =
let res = a +% b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n)
proc foldSub*(a, b: BiggestInt, n: PNode): PNode =
let res = a -% b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n)
proc foldAbs*(a: BiggestInt, n: PNode): PNode =
if a != firstOrd(n.typ):
result = newIntNodeT(a, n)
proc foldMod*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a mod b, n)
proc foldModU*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a %% b, n)
proc foldDiv*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
result = newIntNodeT(a div b, n)
proc foldDivU*(a, b: BiggestInt, n: PNode): PNode =
if b != 0'i64:
result = newIntNodeT(a /% b, n)
proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
let res = a *% b
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
let resAsFloat = toBiggestFloat(res)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd and checkInRange(n, res):
return newIntNodeT(res, n)
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res):
return newIntNodeT(res, n)
# implementation
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
case skipTypes(n.typ, abstractVarRange).kind
of tyInt:
result = newIntNode(nkIntLit, intVal)
# See bug #6989. 'pred' et al only produce an int literal type if the
# original type was 'int', not a distinct int etc.
if n.typ.kind == tyInt:
result.typ = getIntLitType(result)
result.typ = getIntLitType(g, result)
else:
result.typ = n.typ
# hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
@@ -103,20 +35,82 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
result.typ = n.typ
result.info = n.info
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
result = newFloatNode(nkFloatLit, floatVal)
if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
result.typ = getFloatLitType(result)
result.typ = getFloatLitType(g, result)
else:
result.typ = n.typ
result.info = n.info
proc newStrNodeT(strVal: string, n: PNode): PNode =
proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
result = newStrNode(nkStrLit, strVal)
result.typ = n.typ
result.info = n.info
proc ordinalValToString*(a: PNode): string =
proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
# evaluates the constant expression or returns nil if it is no constant
# expression
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
proc checkInRange(n: PNode, res: BiggestInt): bool =
if res in firstOrd(n.typ)..lastOrd(n.typ):
result = true
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a +% b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n, g)
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a -% b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
checkInRange(n, res):
result = newIntNodeT(res, n, g)
proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if a != firstOrd(n.typ):
result = newIntNodeT(a, n, g)
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a mod b, n, g)
proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a %% b, n, g)
proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
result = newIntNodeT(a div b, n, g)
proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64:
result = newIntNodeT(a /% b, n, g)
proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
let res = a *% b
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
let resAsFloat = toBiggestFloat(res)
# Fast path for normal case: small multiplicands, and no info
# is lost in either method.
if resAsFloat == floatProd and checkInRange(n, res):
return newIntNodeT(res, n, g)
# Somebody somewhere lost info. Close enough, or way off? Note
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
# The difference either is or isn't significant compared to the
# true value (of which floatProd is a good approximation).
# abs(diff)/abs(prod) <= 1/32 iff
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
checkInRange(n, res):
return newIntNodeT(res, n, g)
proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
# ordinal
var x = getInt(a)
@@ -128,14 +122,14 @@ proc ordinalValToString*(a: PNode): string =
of tyEnum:
var n = t.n
for i in countup(0, sonsLen(n) - 1):
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
var field = n.sons[i].sym
if field.position == x:
if field.ast == nil:
return field.name.s
else:
return field.ast.strVal
internalError(a.info, "no symbol for ordinal value: " & $x)
internalError(g.config, a.info, "no symbol for ordinal value: " & $x)
else:
result = $x
@@ -154,12 +148,12 @@ proc pickIntRange(a, b: PType): PType =
proc isIntRangeOrLit(t: PType): bool =
result = isIntRange(t) or isIntLit(t)
proc makeRange(typ: PType, first, last: BiggestInt): PType =
proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
let minA = min(first, last)
let maxA = max(first, last)
let lowerNode = newIntNode(nkIntLit, minA)
if typ.kind == tyInt and minA == maxA:
result = getIntLitType(lowerNode)
result = getIntLitType(g, lowerNode)
elif typ.kind in {tyUint, tyUInt64}:
# these are not ordinal types, so you get no subrange type for these:
result = typ
@@ -171,7 +165,7 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
var n = newNode(nkRange)
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
@@ -181,9 +175,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
proc evalIs(n, a: PNode): PNode =
# XXX: This should use the standard isOpImpl
internalAssert a.kind == nkSym and a.sym.kind == skType
internalAssert n.sonsLen == 3 and
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
#internalAssert a.kind == nkSym and a.sym.kind == skType
#internalAssert n.sonsLen == 3 and
# n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
let t1 = a.sym.typ
@@ -207,113 +201,113 @@ proc evalIs(n, a: PNode): PNode =
result = newIntNode(nkIntLit, ord(match))
result.typ = n.typ
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
# b and c may be nil
result = nil
case m
of mOrd: result = newIntNodeT(getOrdValue(a), n)
of mChr: result = newIntNodeT(getInt(a), n)
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
of mNot: result = newIntNodeT(1 - getInt(a), n)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
of mBitnotI: result = newIntNodeT(not getInt(a), n)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
of mChr: result = newIntNodeT(getInt(a), n, g)
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g)
of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit:
result = newIntNodeT(0, n)
result = newIntNodeT(0, n, g)
elif a.kind in {nkStrLit..nkTripleStrLit}:
result = newIntNodeT(len a.strVal, n)
result = newIntNodeT(len a.strVal, n, g)
else:
result = newIntNodeT(sonsLen(a), n) # BUGFIX
result = newIntNodeT(sonsLen(a), n, g)
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n)
result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
# XXX: Hides overflow/underflow
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
of mAbsI: result = foldAbs(getInt(a), n)
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
of mAbsI: result = foldAbs(getInt(a), n, g)
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n)
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n)
of mPred: result = foldSub(getOrdValue(a), getInt(b), n)
of mAddI: result = foldAdd(getInt(a), getInt(b), n)
of mSubI: result = foldSub(getInt(a), getInt(b), n)
of mMulI: result = foldMul(getInt(a), getInt(b), n)
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g)
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g)
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
of mMinI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
else: result = newIntNodeT(getInt(a), n)
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
else: result = newIntNodeT(getInt(a), n, g)
of mMaxI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
else: result = newIntNodeT(getInt(b), n)
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
else: result = newIntNodeT(getInt(b), n, g)
of mShlI:
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
else: internalError(n.info, "constant folding for shl")
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
else: internalError(g.config, n.info, "constant folding for shl")
of mShrI:
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n, g)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: internalError(n.info, "constant folding for shr")
of mDivI: result = foldDiv(getInt(a), getInt(b), n)
of mModI: result = foldMod(getInt(a), getInt(b), n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
else: internalError(g.config, n.info, "constant folding for shr")
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
of mModI: result = foldMod(getInt(a), getInt(b), n, g)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
of mDivF64:
if getFloat(b) == 0.0:
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n)
else: result = newFloatNodeT(Inf, n)
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
else: result = newFloatNodeT(Inf, n, g)
else:
result = newFloatNodeT(getFloat(a) / getFloat(b), n)
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
of mMaxF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
else: result = newFloatNodeT(getFloat(b), n)
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
else: result = newFloatNodeT(getFloat(b), n, g)
of mMinF64:
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
else: result = newFloatNodeT(getFloat(a), n)
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
else: result = newFloatNodeT(getFloat(a), n, g)
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
of mLtI, mLtB, mLtEnum, mLtCh:
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)
of mLeI, mLeB, mLeEnum, mLeCh:
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n, g)
of mEqI, mEqB, mEqEnum, mEqCh:
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n, g)
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n, g)
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n, g)
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n, g)
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n, g)
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
of mLtU, mLtU64:
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
of mModU: result = foldModU(getInt(a), getInt(b), n)
of mDivU: result = foldDivU(getInt(a), getInt(b), n)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
of mModU: result = foldModU(getInt(a), getInt(b), n, g)
of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g)
of mLtSet:
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g)
of mMulSet:
result = nimsets.intersectSets(a, b)
result.info = n.info
@@ -326,125 +320,125 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of mSymDiffSet:
result = nimsets.symdiffSets(a, b)
result.info = n.info
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
of mRepr:
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
discard
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n)
else: result = newStrNodeT("true", n)
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
else: result = newStrNodeT("true", n, g)
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
of mCopyStrLast:
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
int(getOrdValue(c))), n)
of mFloatToStr: result = newStrNodeT($getFloat(a), n)
int(getOrdValue(c))), n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr:
if a.kind == nkBracket:
var s = ""
for b in a.sons:
s.add b.getStrOrChar
result = newStrNodeT(s, n)
result = newStrNodeT(s, n, g)
else:
result = newStrNodeT(getStrOrChar(a), n)
result = newStrNodeT(getStrOrChar(a), n, g)
of mStrToStr: result = a
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
of mArrToSeq:
result = copyTree(a)
result.typ = n.typ
of mCompileOption:
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
result = newIntNodeT(ord(commands.testCompileOption(g.config, a.getStr, n.info)), n, g)
of mCompileOptionArg:
result = newIntNodeT(ord(
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
testCompileOptionArg(g.config, getStr(a), getStr(b), n.info)), n, g)
of mEqProc:
result = newIntNodeT(ord(
exprStructuralEquivalent(a, b, strictSymEquality=true)), n)
exprStructuralEquivalent(a, b, strictSymEquality=true)), n, g)
else: discard
proc getConstIfExpr(c: PSym, n: PNode): PNode =
proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
result = nil
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.len == 2:
var e = getConstExpr(c, it.sons[0])
var e = getConstExpr(c, it.sons[0], g)
if e == nil: return nil
if getOrdValue(e) != 0:
if result == nil:
result = getConstExpr(c, it.sons[1])
result = getConstExpr(c, it.sons[1], g)
if result == nil: return
elif it.len == 1:
if result == nil: result = getConstExpr(c, it.sons[0])
else: internalError(it.info, "getConstIfExpr()")
if result == nil: result = getConstExpr(c, it.sons[0], g)
else: internalError(g.config, it.info, "getConstIfExpr()")
proc leValueConv(a, b: PNode): bool =
proc leValueConv*(a, b: PNode): bool =
result = false
case a.kind
of nkCharLit..nkUInt64Lit:
case b.kind
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
else: internalError(a.info, "leValueConv")
else: result = false #internalError(a.info, "leValueConv")
of nkFloatLit..nkFloat128Lit:
case b.kind
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
else: internalError(a.info, "leValueConv")
else: internalError(a.info, "leValueConv")
else: result = false # internalError(a.info, "leValueConv")
else: result = false # internalError(a.info, "leValueConv")
proc magicCall(m: PSym, n: PNode): PNode =
proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
if sonsLen(n) <= 1: return
var s = n.sons[0].sym
var a = getConstExpr(m, n.sons[1])
var a = getConstExpr(m, n.sons[1], g)
var b, c: PNode
if a == nil: return
if sonsLen(n) > 2:
b = getConstExpr(m, n.sons[2])
b = getConstExpr(m, n.sons[2], g)
if b == nil: return
if sonsLen(n) > 3:
c = getConstExpr(m, n.sons[3])
c = getConstExpr(m, n.sons[3], g)
if c == nil: return
result = evalOp(s.magic, n, a, b, c)
result = evalOp(s.magic, n, a, b, c, g)
proc getAppType(n: PNode): PNode =
if gGlobalOptions.contains(optGenDynLib):
result = newStrNodeT("lib", n)
elif gGlobalOptions.contains(optGenStaticLib):
result = newStrNodeT("staticlib", n)
elif gGlobalOptions.contains(optGenGuiApp):
result = newStrNodeT("gui", n)
proc getAppType(n: PNode; g: ModuleGraph): PNode =
if g.config.globalOptions.contains(optGenDynLib):
result = newStrNodeT("lib", n, g)
elif g.config.globalOptions.contains(optGenStaticLib):
result = newStrNodeT("staticlib", n, g)
elif g.config.globalOptions.contains(optGenGuiApp):
result = newStrNodeT("gui", n, g)
else:
result = newStrNodeT("console", n)
result = newStrNodeT("console", n, g)
proc rangeCheck(n: PNode, value: BiggestInt) =
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
var err = false
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true)
else:
err = value < firstOrd(n.typ) or value > lastOrd(n.typ)
if err:
localError(n.info, errGenerated, "cannot convert " & $value &
localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ))
proc foldConv*(n, a: PNode; check = false): PNode =
proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode =
# XXX range checks?
case skipTypes(n.typ, abstractRange).kind
of tyInt..tyInt64, tyUInt..tyUInt64:
case skipTypes(a.typ, abstractRange).kind
of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n)
of tyChar: result = newIntNodeT(getOrdValue(a), n)
result = newIntNodeT(int(getFloat(a)), n, g)
of tyChar: result = newIntNodeT(getOrdValue(a), n, g)
else:
result = a
result.typ = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit}:
rangeCheck(n, result.intVal)
rangeCheck(n, result.intVal, g)
of tyFloat..tyFloat64:
case skipTypes(a.typ, abstractRange).kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n)
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
else:
result = a
result.typ = n.typ
@@ -454,19 +448,19 @@ proc foldConv*(n, a: PNode; check = false): PNode =
result = a
result.typ = n.typ
proc getArrayConstr(m: PSym, n: PNode): PNode =
proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode =
if n.kind == nkBracket:
result = n
else:
result = getConstExpr(m, n)
result = getConstExpr(m, n, g)
if result == nil: result = n
proc foldArrayAccess(m: PSym, n: PNode): PNode =
var x = getConstExpr(m, n.sons[0])
proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
var x = getConstExpr(m, n.sons[0], g)
if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
return
var y = getConstExpr(m, n.sons[1])
var y = getConstExpr(m, n.sons[1], g)
if y == nil: return
var idx = getOrdValue(y)
@@ -476,24 +470,24 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
else:
localError(n.info, errIndexOutOfBounds)
localError(g.config, n.info, "index out of bounds: " & $n)
of nkBracket:
idx = idx - x.typ.firstOrd
if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
else: localError(n.info, errIndexOutOfBounds)
else: localError(g.config, n.info, "index out of bounds: " & $n)
of nkStrLit..nkTripleStrLit:
result = newNodeIT(nkCharLit, x.info, n.typ)
if idx >= 0 and idx < len(x.strVal):
result.intVal = ord(x.strVal[int(idx)])
elif idx == len(x.strVal):
elif idx == len(x.strVal) and optLaxStrings in g.config.options:
discard
else:
localError(n.info, errIndexOutOfBounds)
localError(g.config, n.info, "index out of bounds: " & $n)
else: discard
proc foldFieldAccess(m: PSym, n: PNode): PNode =
proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
# a real field access; proc calls have already been transformed
var x = getConstExpr(m, n.sons[0])
var x = getConstExpr(m, n.sons[0], g)
if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
var field = n.sons[1].sym
@@ -507,13 +501,13 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
return
localError(n.info, errFieldXNotFound, field.name.s)
localError(g.config, n.info, "field not found: " & field.name.s)
proc foldConStrStr(m: PSym, n: PNode): PNode =
proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = ""
for i in countup(1, sonsLen(n) - 1):
let a = getConstExpr(m, n.sons[i])
let a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil
result.strVal.add(getStrOrChar(a))
@@ -525,7 +519,7 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
else:
result.typ = s.typ
proc getConstExpr(m: PSym, n: PNode): PNode =
proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
result = nil
proc getSrcTimestamp(): DateTime =
@@ -545,32 +539,35 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
var s = n.sym
case s.kind
of skEnumField:
result = newIntNodeT(s.position, n)
result = newIntNodeT(s.position, n, g)
of skConst:
case s.magic
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g)
of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
"yyyy-MM-dd"), n)
"yyyy-MM-dd"), n, g)
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
"HH:mm:ss"), n)
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)
of mNegInf: result = newFloatNodeT(NegInf, n)
"HH:mm:ss"), n, g)
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g)
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g)
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g)
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g)
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g)
of mAppType: result = getAppType(n, g)
of mNaN: result = newFloatNodeT(NaN, n, g)
of mInf: result = newFloatNodeT(Inf, n, g)
of mNegInf: result = newFloatNodeT(NegInf, n, g)
of mIntDefine:
if isDefined(s.name):
result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
if isDefined(g.config, s.name.s):
try:
result = newIntNodeT(g.config.symbols[s.name.s].parseInt, n, g)
except ValueError:
localError(g.config, n.info, "expression is not an integer literal")
of mStrDefine:
if isDefined(s.name):
result = newStrNodeT(lookupSymbol(s.name), n)
if isDefined(g.config, s.name.s):
result = newStrNodeT(g.config.symbols[s.name.s], n, g)
else:
result = copyTree(s.ast)
of {skProc, skFunc, skMethod}:
of skProc, skFunc, skMethod:
result = n
of skType:
# XXX gensym'ed symbols can come here and cannot be resolved. This is
@@ -590,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkCharLit..nkNilLit:
result = copyNode(n)
of nkIfExpr:
result = getConstIfExpr(m, n)
result = getConstIfExpr(m, n, g)
of nkCallKinds:
if n.sons[0].kind != nkSym: return
var s = n.sons[0].sym
@@ -603,68 +600,67 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of mSizeOf:
var a = n.sons[1]
if computeSize(a.typ) < 0:
localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
"sizeof")
localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
result = nil
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(a.typ), n)
result = newIntNodeT(getSize(a.typ), n, g)
else:
result = nil
# XXX: size computation for complex types is still wrong
of mLow:
result = newIntNodeT(firstOrd(n.sons[1].typ), n)
result = newIntNodeT(firstOrd(n.sons[1].typ), n, g)
of mHigh:
if skipTypes(n.sons[1].typ, abstractVar).kind notin
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g)
else:
var a = getArrayConstr(m, n.sons[1])
var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket:
# we can optimize it away:
result = newIntNodeT(sonsLen(a)-1, n)
result = newIntNodeT(sonsLen(a)-1, n, g)
of mLengthOpenArray:
var a = getArrayConstr(m, n.sons[1])
var a = getArrayConstr(m, n.sons[1], g)
if a.kind == nkBracket:
# we can optimize it away! This fixes the bug ``len(134)``.
result = newIntNodeT(sonsLen(a), n)
result = newIntNodeT(sonsLen(a), n, g)
else:
result = magicCall(m, n)
result = magicCall(m, n, g)
of mLengthArray:
# It doesn't matter if the argument is const or not for mLengthArray.
# This fixes bug #544.
result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
of mConStrStr:
result = foldConStrStr(m, n)
result = foldConStrStr(m, n, g)
of mIs:
let a = getConstExpr(m, n[1])
let a = getConstExpr(m, n[1], g)
if a != nil and a.kind == nkSym and a.sym.kind == skType:
result = evalIs(n, a)
else:
result = magicCall(m, n)
result = magicCall(m, n, g)
except OverflowError:
localError(n.info, errOverOrUnderflow)
localError(g.config, n.info, "over- or underflow")
except DivByZeroError:
localError(n.info, errConstantDivisionByZero)
localError(g.config, n.info, "division by zero")
of nkAddr:
var a = getConstExpr(m, n.sons[0])
var a = getConstExpr(m, n.sons[0], g)
if a != nil:
result = n
n.sons[0] = a
of nkBracket:
result = copyTree(n)
for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i])
var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil
result.sons[i] = a
incl(result.flags, nfAllConst)
of nkRange:
var a = getConstExpr(m, n.sons[0])
var a = getConstExpr(m, n.sons[0], g)
if a == nil: return
var b = getConstExpr(m, n.sons[1])
var b = getConstExpr(m, n.sons[1], g)
if b == nil: return
result = copyNode(n)
addSon(result, a)
@@ -672,7 +668,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
of nkCurly:
result = copyTree(n)
for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i])
var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil
result.sons[i] = a
incl(result.flags, nfAllConst)
@@ -688,45 +684,45 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
result = copyTree(n)
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i].sons[1])
var a = getConstExpr(m, n.sons[i].sons[1], g)
if a == nil: return nil
result.sons[i].sons[1] = a
else:
for i in countup(0, sonsLen(n) - 1):
var a = getConstExpr(m, n.sons[i])
var a = getConstExpr(m, n.sons[i], g)
if a == nil: return nil
result.sons[i] = a
incl(result.flags, nfAllConst)
of nkChckRangeF, nkChckRange64, nkChckRange:
var a = getConstExpr(m, n.sons[0])
var a = getConstExpr(m, n.sons[0], g)
if a == nil: return
if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
result = a # a <= x and x <= b
result.typ = n.typ
else:
localError(n.info, errGenerated, `%`(
msgKindToString(errIllegalConvFromXtoY),
[typeToString(n.sons[0].typ), typeToString(n.typ)]))
localError(g.config, n.info,
"conversion from $1 to $2 is invalid" %
[typeToString(n.sons[0].typ), typeToString(n.typ)])
of nkStringToCString, nkCStringToString:
var a = getConstExpr(m, n.sons[0])
var a = getConstExpr(m, n.sons[0], g)
if a == nil: return
result = a
result.typ = n.typ
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n.sons[1])
var a = getConstExpr(m, n.sons[1], g)
if a == nil: return
result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
of nkCast:
var a = getConstExpr(m, n.sons[1])
var a = getConstExpr(m, n.sons[1], g)
if a == nil: return
if n.typ != nil and n.typ.kind in NilableTypes:
# we allow compile-time 'cast' for pointer types:
result = a
result.typ = n.typ
of nkBracketExpr: result = foldArrayAccess(m, n)
of nkDotExpr: result = foldFieldAccess(m, n)
of nkBracketExpr: result = foldArrayAccess(m, n, g)
of nkDotExpr: result = foldFieldAccess(m, n, g)
of nkStmtListExpr:
if n.len == 2 and n[0].kind == nkComesFrom:
result = getConstExpr(m, n[1])
result = getConstExpr(m, n[1], g)
else:
discard

View File

@@ -17,13 +17,13 @@
# included from sem.nim
proc getIdentNode(n: PNode): PNode =
proc getIdentNode(c: PContext; n: PNode): PNode =
case n.kind
of nkPostfix: result = getIdentNode(n.sons[1])
of nkPragmaExpr: result = getIdentNode(n.sons[0])
of nkPostfix: result = getIdentNode(c, n.sons[1])
of nkPragmaExpr: result = getIdentNode(c, n.sons[0])
of nkIdent, nkAccQuoted, nkSym: result = n
else:
illFormedAst(n)
illFormedAst(n, c.config)
result = n
type
@@ -103,8 +103,8 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym,
proc lookup(c: PContext, n: PNode, flags: TSemGenericFlags,
ctx: var GenericCtx): PNode =
result = n
let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident).skipAlias(n)
let ident = considerQuotedIdent(c.config, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s == nil:
s = strTableGet(c.pureEnumFields, ident)
if s != nil and contains(c.ambiguousSymbols, s.id):
@@ -140,8 +140,8 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
result = n
let n = n[1]
let ident = considerQuotedIdent(n)
var s = searchInScopes(c, ident).skipAlias(n)
let ident = considerQuotedIdent(c.config, n)
var s = searchInScopes(c, ident).skipAlias(n, c.config)
if s != nil and s.kind in routineKinds:
isMacro = s.kind in {skTemplate, skMacro}
if withinBind in flags:
@@ -158,7 +158,7 @@ proc fuzzyLookup(c: PContext, n: PNode, flags: TSemGenericFlags,
result = newDot(result, syms)
proc addTempDecl(c: PContext; n: PNode; kind: TSymKind) =
let s = newSymS(skUnknown, getIdentNode(n), c)
let s = newSymS(skUnknown, getIdentNode(c, n), c)
addPrelimDecl(c, s)
styleCheckDef(n.info, s, kind)
@@ -169,7 +169,7 @@ proc semGenericStmt(c: PContext, n: PNode,
when defined(nimsuggest):
if withinTypeDesc in flags: inc c.inTypeContext
#if gCmd == cmdIdeTools: suggestStmt(c, n)
#if conf.cmd == cmdIdeTools: suggestStmt(c, n)
semIdeForTemplateOrGenericCheck(n, ctx.cursorInBody)
case n.kind
@@ -201,13 +201,13 @@ proc semGenericStmt(c: PContext, n: PNode,
result = semMixinStmt(c, n, ctx.toMixin)
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkCommand, nkCallStrLit:
# check if it is an expression macro:
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
let fn = n.sons[0]
var s = qualifiedLookUp(c, fn, {})
if s == nil and
{withinMixin, withinConcept}*flags == {} and
fn.kind in {nkIdent, nkAccQuoted} and
considerQuotedIdent(fn).id notin ctx.toMixin:
considerQuotedIdent(c.config, fn).id notin ctx.toMixin:
errorUndeclaredIdentifier(c, n.info, fn.renderTree)
var first = int ord(withinConcept in flags)
@@ -285,7 +285,7 @@ proc semGenericStmt(c: PContext, n: PNode,
withBracketExpr ctx, n.sons[0]:
result = semGenericStmt(c, result, flags, ctx)
of nkAsgn, nkFastAsgn:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
let a = n.sons[0]
let b = n.sons[1]
@@ -323,7 +323,7 @@ proc semGenericStmt(c: PContext, n: PNode,
n.sons[0] = semGenericStmt(c, n.sons[0], flags, ctx)
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
checkMinSonsLen(a, 1, c.config)
var L = sonsLen(a)
for j in countup(0, L-2):
a.sons[j] = semGenericStmt(c, a.sons[j], flags, ctx)
@@ -340,23 +340,23 @@ proc semGenericStmt(c: PContext, n: PNode,
closeScope(c)
closeScope(c)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
openScope(c)
if n.sons[0].kind != nkEmpty:
addTempDecl(c, n.sons[0], skLabel)
n.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
closeScope(c)
of nkTryStmt:
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
n.sons[0] = semGenericStmtScope(c, n.sons[0], flags, ctx)
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
checkMinSonsLen(a, 1, c.config)
var L = sonsLen(a)
openScope(c)
for j in countup(0, L-2):
if a.sons[j].isInfixAs():
addTempDecl(c, getIdentNode(a.sons[j][2]), skLet)
addTempDecl(c, getIdentNode(c, a.sons[j][2]), skLet)
a.sons[j].sons[1] = semGenericStmt(c, a.sons[j][1], flags+{withinTypeDesc}, ctx)
else:
a.sons[j] = semGenericStmt(c, a.sons[j], flags+{withinTypeDesc}, ctx)
@@ -367,44 +367,44 @@ proc semGenericStmt(c: PContext, n: PNode,
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skVar)
addTempDecl(c, getIdentNode(c, a.sons[j]), skVar)
of nkGenericParams:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
# do not perform symbol lookup for default expressions
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skType)
addTempDecl(c, getIdentNode(c, a.sons[j]), skType)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
addTempDecl(c, getIdentNode(a.sons[0]), skConst)
if (a.kind != nkConstDef): illFormedAst(a, c.config)
checkSonsLen(a, 3, c.config)
addTempDecl(c, getIdentNode(c, a.sons[0]), skConst)
a.sons[1] = semGenericStmt(c, a.sons[1], flags+{withinTypeDesc}, ctx)
a.sons[2] = semGenericStmt(c, a.sons[2], flags, ctx)
of nkTypeSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
addTempDecl(c, getIdentNode(a.sons[0]), skType)
if (a.kind != nkTypeDef): illFormedAst(a, c.config)
checkSonsLen(a, 3, c.config)
addTempDecl(c, getIdentNode(c, a.sons[0]), skType)
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.kind != nkTypeDef): illFormedAst(a, c.config)
checkSonsLen(a, 3, c.config)
if a.sons[1].kind != nkEmpty:
openScope(c)
a.sons[1] = semGenericStmt(c, a.sons[1], flags, ctx)
@@ -421,28 +421,28 @@ proc semGenericStmt(c: PContext, n: PNode,
case n.sons[i].kind
of nkEnumFieldDef: a = n.sons[i].sons[0]
of nkIdent: a = n.sons[i]
else: illFormedAst(n)
addDecl(c, newSymS(skUnknown, getIdentNode(a), c))
else: illFormedAst(n, c.config)
addDecl(c, newSymS(skUnknown, getIdentNode(c, a), c))
of nkObjectTy, nkTupleTy, nkTupleClassTy:
discard
of nkFormalParams:
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
if n.sons[0].kind != nkEmpty:
n.sons[0] = semGenericStmt(c, n.sons[0], flags+{withinTypeDesc}, ctx)
for i in countup(1, sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var L = sonsLen(a)
a.sons[L-2] = semGenericStmt(c, a.sons[L-2], flags+{withinTypeDesc}, ctx)
a.sons[L-1] = semGenericStmt(c, a.sons[L-1], flags, ctx)
for j in countup(0, L-3):
addTempDecl(c, getIdentNode(a.sons[j]), skParam)
addTempDecl(c, getIdentNode(c, a.sons[j]), skParam)
of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef,
nkFuncDef, nkIteratorDef, nkLambdaKinds:
checkSonsLen(n, bodyPos + 1)
checkSonsLen(n, bodyPos + 1, c.config)
if n.sons[namePos].kind != nkEmpty:
addTempDecl(c, getIdentNode(n.sons[0]), skProc)
addTempDecl(c, getIdentNode(c, n.sons[0]), skProc)
openScope(c)
n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos],
flags, ctx)
@@ -463,7 +463,7 @@ proc semGenericStmt(c: PContext, n: PNode,
closeScope(c)
of nkPragma, nkPragmaExpr: discard
of nkExprColonExpr, nkExprEqExpr:
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
result.sons[1] = semGenericStmt(c, n.sons[1], flags, ctx)
else:
for i in countup(0, sonsLen(n) - 1):

View File

@@ -54,10 +54,13 @@ proc pushProcCon*(c: PContext; owner: PSym) =
rawPushProcCon(c, owner)
rawHandleSelf(c, owner)
const
errCannotInstantiateX = "cannot instantiate: '$1'"
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
internalAssert n.kind == nkGenericParams
internalAssert c.config, n.kind == nkGenericParams
for i, a in n.pairs:
internalAssert a.kind == nkSym
internalAssert c.config, a.kind == nkSym
var q = a.sym
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
continue
@@ -71,10 +74,10 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
# later by semAsgn in return type inference scenario
t = q.typ
else:
localError(a.info, errCannotInstantiateX, s.name.s)
localError(c.config, a.info, errCannotInstantiateX % s.name.s)
t = errorType(c)
elif t.kind == tyGenericParam:
localError(a.info, errCannotInstantiateX, q.name.s)
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
t = errorType(c)
elif t.kind == tyGenericInvocation:
#t = instGenericContainer(c, a, t)
@@ -145,7 +148,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
freshGenSyms(b, result, orig, symMap)
b = semProcBody(c, b)
b = hloBody(c, b)
n.sons[bodyPos] = transformBody(c.module, b, result)
n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
#echo "code instantiated ", result.name.s
excl(result.flags, sfForward)
dec c.inGenericInst
@@ -174,7 +177,7 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
allowMetaTypes = false): PType =
internalAssert header.kind == tyGenericInvocation
internalAssert c.config, header.kind == tyGenericInvocation
var
typeMap: LayeredIdTable
@@ -199,7 +202,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
var param: PSym
template paramSym(kind): untyped =
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
if genParam.kind == tyStatic:
param = paramSym skConst
@@ -233,14 +236,12 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
# at this point semtypinst have to become part of sem, because it
# will need to use openScope, addDecl, etc.
#addDecl(c, prc)
pushInfoContext(info)
var typeMap = initLayeredTypeMap(pt)
var cl = initTypeVars(c, addr(typeMap), info, nil)
var result = instCopyType(cl, prc.typ)
let originalParams = result.n
result.n = originalParams.shallowCopy
for i in 1 ..< result.len:
# twrong_field_caching requires these 'resetIdTable' calls:
if i > 1:
@@ -248,7 +249,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
resetIdTable(cl.localCache)
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
propagateToOwner(result, result.sons[i])
internalAssert originalParams[i].kind == nkSym
internalAssert c.config, originalParams[i].kind == nkSym
when true:
let oldParam = originalParams[i].sym
let param = copySym(oldParam)
@@ -285,9 +286,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
## The `pt` parameter is a type-unsafe mapping table used to link generic
## parameters to their concrete types within the generic instance.
# no need to instantiate generic templates/macros:
internalAssert fn.kind notin {skMacro, skTemplate}
internalAssert c.config, fn.kind notin {skMacro, skTemplate}
# generates an instantiated proc
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
if c.instCounter > 1000: internalError(c.config, fn.ast.info, "nesting too deep")
inc(c.instCounter)
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
@@ -306,7 +307,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
openScope(c)
let gp = n.sons[genericParamsPos]
internalAssert gp.kind != nkEmpty
internalAssert c.config, gp.kind != nkEmpty
n.sons[namePos] = newSymNode(result)
pushInfoContext(info)
var entry = TInstantiation.new

View File

@@ -10,7 +10,7 @@
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, astalgo, msgs, types
import ast, astalgo, msgs, types, options
proc ithField(n: PNode, field: var int): PSym =
result = nil
@@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym =
result = ithField(n.sons[i], field)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
if n.sons[0].kind != nkSym: return
result = ithField(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
@@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym =
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
else: discard
of nkSym:
if field == 0: result = n.sym
else: dec(field)
else: discard
proc annotateType*(n: PNode, t: PType) =
proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
let x = t.skipTypes(abstractInst+{tyRange})
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
@@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) =
var j = i-1
let field = x.n.ithField(j)
if field.isNil:
globalError n.info, "invalid field at index " & $i
globalError conf, n.info, "invalid field at index " & $i
else:
internalAssert(n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ)
internalAssert(conf, n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ, conf)
of nkPar, nkTupleConstr:
if x.kind == tyTuple:
n.typ = t
for i in 0 ..< n.len:
if i >= x.len: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i])
if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
else:
globalError(n.info, "() must have a tuple type")
globalError(conf, n.info, "() must have a tuple type")
of nkBracket:
if x.kind in {tyArray, tySequence, tyOpenArray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(n.info, "[] must have some form of array type")
globalError(conf, n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
for m in n: annotateType(m, x.elemType)
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(n.info, "{} must have the set type")
globalError(conf, n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
else:
globalError(n.info, "float literal must have some float type")
globalError(conf, n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
else:
globalError(n.info, "integer literal must have some int type")
globalError(conf, n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}:
n.typ = t
else:
globalError(n.info, "string literal must be of some string type")
globalError(conf, n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes:
n.typ = t
else:
globalError(n.info, "nil literal must be of some pointer type")
globalError(conf, n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -16,7 +16,7 @@ proc semAddr(c: PContext; n: PNode; isUnsafeAddr=false): PNode =
if x.kind == nkSym:
x.sym.flags.incl(sfAddrTaken)
if isAssignable(c, x, isUnsafeAddr) notin {arLValue, arLocalLValue}:
localError(n.info, errExprHasNoAddress)
localError(c.config, n.info, errExprHasNoAddress)
result.add x
result.typ = makePtrType(c, x.typ)
@@ -43,7 +43,7 @@ proc semArrGet(c: PContext; n: PNode; flags: TExprFlags): PNode =
let x = copyTree(n)
x.sons[0] = newIdentNode(getIdent"[]", n.info)
bracketNotFoundError(c, x)
#localError(n.info, "could not resolve: " & $n)
#localError(c.config, n.info, "could not resolve: " & $n)
result = n
proc semArrPut(c: PContext; n: PNode; flags: TExprFlags): PNode =
@@ -64,24 +64,24 @@ proc semAsgnOpr(c: PContext; n: PNode): PNode =
proc semIsPartOf(c: PContext, n: PNode, flags: TExprFlags): PNode =
var r = isPartOf(n[1], n[2])
result = newIntNodeT(ord(r), n)
result = newIntNodeT(ord(r), n, c.graph)
proc expectIntLit(c: PContext, n: PNode): int =
let x = c.semConstExpr(c, n)
case x.kind
of nkIntLit..nkInt64Lit: result = int(x.intVal)
else: localError(n.info, errIntLiteralExpected)
else: localError(c.config, n.info, errIntLiteralExpected)
proc semInstantiationInfo(c: PContext, n: PNode): PNode =
result = newNodeIT(nkTupleConstr, n.info, n.typ)
let idx = expectIntLit(c, n.sons[1])
let useFullPaths = expectIntLit(c, n.sons[2])
let info = getInfoContext(idx)
var filename = newNodeIT(nkStrLit, n.info, getSysType(tyString))
var filename = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString))
filename.strVal = if useFullPaths != 0: info.toFullPath else: info.toFilename
var line = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
var line = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
line.intVal = toLinenumber(info)
var column = newNodeIT(nkIntLit, n.info, getSysType(tyInt))
var column = newNodeIT(nkIntLit, n.info, getSysType(c.graph, n.info, tyInt))
column.intVal = toColumn(info)
result.add(filename)
result.add(line)
@@ -110,10 +110,10 @@ proc uninstantiate(t: PType): PType =
of tyCompositeTypeClass: uninstantiate t.sons[1]
else: t
proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym): PNode =
const skippedTypes = {tyTypeDesc, tyAlias, tySink}
let trait = traitCall[0]
internalAssert trait.kind == nkSym
internalAssert c.config, trait.kind == nkSym
var operand = operand.skipTypes(skippedTypes)
template operand2: PType =
@@ -140,7 +140,7 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
of "genericHead":
var res = uninstantiate(operand)
if res == operand and res.kind notin tyMagicGenerics:
localError(traitCall.info,
localError(c.config, traitCall.info,
"genericHead expects a generic type. The given type was " &
typeToString(operand))
return newType(tyError, context).toNode(traitCall.info)
@@ -151,19 +151,19 @@ proc evalTypeTrait(traitCall: PNode, operand: PType, context: PSym): PNode =
let t = operand.skipTypes({tyVar, tyLent, tyGenericInst, tyAlias, tySink, tyInferred})
let complexObj = containsGarbageCollectedRef(t) or
hasDestructor(t)
result = newIntNodeT(ord(not complexObj), traitCall)
result = newIntNodeT(ord(not complexObj), traitCall, c.graph)
else:
localError(traitCall.info, "unknown trait")
localError(c.config, traitCall.info, "unknown trait")
result = emptyNode
proc semTypeTraits(c: PContext, n: PNode): PNode =
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
let t = n.sons[1].typ
internalAssert t != nil and t.kind == tyTypeDesc
internalAssert c.config, t != nil and t.kind == tyTypeDesc
if t.sonsLen > 0:
# This is either a type known to sem or a typedesc
# param to a regular proc (again, known at instantiation)
result = evalTypeTrait(n, t, getCurrOwner(c))
result = evalTypeTrait(c, n, t, getCurrOwner(c))
else:
# a typedesc variable, pass unmodified to evals
result = n
@@ -176,7 +176,7 @@ proc semOrd(c: PContext, n: PNode): PNode =
elif parType.kind == tySet:
result.typ = makeRangeType(c, firstOrd(parType), lastOrd(parType), n.info)
else:
localError(n.info, errOrdinalTypeExpected)
localError(c.config, n.info, errOrdinalTypeExpected)
result.typ = errorType(c)
proc semBindSym(c: PContext, n: PNode): PNode =
@@ -185,13 +185,13 @@ proc semBindSym(c: PContext, n: PNode): PNode =
let sl = semConstExpr(c, n.sons[1])
if sl.kind notin {nkStrLit, nkRStrLit, nkTripleStrLit}:
localError(n.sons[1].info, errStringLiteralExpected)
localError(c.config, n.sons[1].info, errStringLiteralExpected)
return errorNode(c, n)
let isMixin = semConstExpr(c, n.sons[2])
if isMixin.kind != nkIntLit or isMixin.intVal < 0 or
isMixin.intVal > high(TSymChoiceRule).int:
localError(n.sons[2].info, errConstExprExpected)
localError(c.config, n.sons[2].info, errConstExprExpected)
return errorNode(c, n)
let id = newIdentNode(getIdent(sl.strVal), n.info)
@@ -225,9 +225,9 @@ proc semOf(c: PContext, n: PNode): PNode =
let y = skipTypes(n.sons[2].typ, abstractPtrs-{tyTypeDesc})
if x.kind == tyTypeDesc or y.kind != tyTypeDesc:
localError(n.info, errXExpectsObjectTypes, "of")
localError(c.config, n.info, "'of' takes object types")
elif b.kind != tyObject or a.kind != tyObject:
localError(n.info, errXExpectsObjectTypes, "of")
localError(c.config, n.info, "'of' takes object types")
else:
let diff = inheritanceDiff(a, b)
# | returns: 0 iff `a` == `b`
@@ -236,26 +236,26 @@ proc semOf(c: PContext, n: PNode): PNode =
# | returns: `maxint` iff `a` and `b` are not compatible at all
if diff <= 0:
# optimize to true:
message(n.info, hintConditionAlwaysTrue, renderTree(n))
message(c.config, n.info, hintConditionAlwaysTrue, renderTree(n))
result = newIntNode(nkIntLit, 1)
result.info = n.info
result.typ = getSysType(tyBool)
result.typ = getSysType(c.graph, n.info, tyBool)
return result
elif diff == high(int):
localError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
localError(c.config, n.info, "'$1' cannot be of this subtype" % typeToString(a))
else:
localError(n.info, errXExpectsTwoArguments, "of")
n.typ = getSysType(tyBool)
localError(c.config, n.info, "'of' takes 2 arguments")
n.typ = getSysType(c.graph, n.info, tyBool)
result = n
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode =
case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
result = semTypeOf(c, n.sons[1])
of mArrGet: result = semArrGet(c, n, flags)
of mArrPut: result = semArrPut(c, n, flags)
@@ -267,8 +267,8 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mIsPartOf: result = semIsPartOf(c, n, flags)
of mTypeTrait: result = semTypeTraits(c, n)
of mAstToStr:
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
result.typ = getSysType(tyString)
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph)
result.typ = getSysType(c.graph, n.info, tyString)
of mInstantiationInfo: result = semInstantiationInfo(c, n)
of mOrd: result = semOrd(c, n)
of mOf: result = semOf(c, n)
@@ -281,11 +281,11 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
of mDotDot:
result = n
of mRoof:
localError(n.info, "builtin roof operator is not supported anymore")
localError(c.config, n.info, "builtin roof operator is not supported anymore")
of mPlugin:
let plugin = getPlugin(n[0].sym)
if plugin.isNil:
localError(n.info, "cannot find plugin " & n[0].sym.name.s)
localError(c.config, n.info, "cannot find plugin " & n[0].sym.name.s)
result = n
else:
result = plugin(c, n)

View File

@@ -39,32 +39,32 @@ proc mergeInitStatus(existing: var InitStatus, newStatus: InitStatus) =
of initUnknown:
discard
proc invalidObjConstr(n: PNode) =
proc invalidObjConstr(c: PContext, n: PNode) =
if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s[0] == ':':
localError(n.info, "incorrect object construction syntax; use a space after the colon")
localError(c.config, n.info, "incorrect object construction syntax; use a space after the colon")
else:
localError(n.info, "incorrect object construction syntax")
localError(c.config, n.info, "incorrect object construction syntax")
proc locateFieldInInitExpr(field: PSym, initExpr: PNode): PNode =
proc locateFieldInInitExpr(c: PContext, field: PSym, initExpr: PNode): PNode =
# Returns the assignment nkExprColonExpr node or nil
let fieldId = field.name.id
for i in 1 ..< initExpr.len:
let assignment = initExpr[i]
if assignment.kind != nkExprColonExpr:
invalidObjConstr(assignment)
invalidObjConstr(c, assignment)
continue
if fieldId == considerQuotedIdent(assignment[0]).id:
if fieldId == considerQuotedIdent(c.config, assignment[0]).id:
return assignment
proc semConstrField(c: PContext, flags: TExprFlags,
field: PSym, initExpr: PNode): PNode =
let assignment = locateFieldInInitExpr(field, initExpr)
let assignment = locateFieldInInitExpr(c, field, initExpr)
if assignment != nil:
if nfSem in assignment.flags: return assignment[1]
if not fieldVisible(c, field):
localError(initExpr.info,
"the field '$1' is not accessible.", [field.name.s])
localError(c.config, initExpr.info,
"the field '$1' is not accessible." % [field.name.s])
return
var initValue = semExprFlagDispatched(c, assignment[1], flags)
@@ -101,25 +101,25 @@ iterator directFieldsInRecList(recList: PNode): PNode =
if recList.kind == nkSym:
yield recList
else:
internalAssert recList.kind == nkRecList
doAssert recList.kind == nkRecList
for field in recList:
if field.kind != nkSym: continue
yield field
template quoteStr(s: string): string = "'" & s & "'"
proc fieldsPresentInInitExpr(fieldsRecList, initExpr: PNode): string =
proc fieldsPresentInInitExpr(c: PContext, fieldsRecList, initExpr: PNode): string =
result = ""
for field in directFieldsInRecList(fieldsRecList):
let assignment = locateFieldInInitExpr(field.sym, initExpr)
let assignment = locateFieldInInitExpr(c, field.sym, initExpr)
if assignment != nil:
if result.len != 0: result.add ", "
result.add field.sym.name.s.quoteStr
proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string =
proc missingMandatoryFields(c: PContext, fieldsRecList, initExpr: PNode): string =
for r in directFieldsInRecList(fieldsRecList):
if {tfNotNil, tfNeedsInit} * r.sym.typ.flags != {}:
let assignment = locateFieldInInitExpr(r.sym, initExpr)
let assignment = locateFieldInInitExpr(c, r.sym, initExpr)
if assignment == nil:
if result == nil:
result = r.sym.name.s
@@ -127,10 +127,10 @@ proc missingMandatoryFields(fieldsRecList, initExpr: PNode): string =
result.add ", "
result.add r.sym.name.s
proc checkForMissingFields(recList, initExpr: PNode) =
let missing = missingMandatoryFields(recList, initExpr)
proc checkForMissingFields(c: PContext, recList, initExpr: PNode) =
let missing = missingMandatoryFields(c, recList, initExpr)
if missing != nil:
localError(initExpr.info, "fields not initialized: $1.", [missing])
localError(c.config, initExpr.info, "fields not initialized: $1.", [missing])
proc semConstructFields(c: PContext, recNode: PNode,
initExpr: PNode, flags: TExprFlags): InitStatus =
@@ -146,14 +146,14 @@ proc semConstructFields(c: PContext, recNode: PNode,
template fieldsPresentInBranch(branchIdx: int): string =
let branch = recNode[branchIdx]
let fields = branch[branch.len - 1]
fieldsPresentInInitExpr(fields, initExpr)
fieldsPresentInInitExpr(c, fields, initExpr)
template checkMissingFields(branchNode: PNode) =
let fields = branchNode[branchNode.len - 1]
checkForMissingFields(fields, initExpr)
checkForMissingFields(c, fields, initExpr)
let discriminator = recNode.sons[0];
internalAssert discriminator.kind == nkSym
let discriminator = recNode.sons[0]
internalAssert c.config, discriminator.kind == nkSym
var selectedBranch = -1
for i in 1 ..< recNode.len:
@@ -164,9 +164,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
if selectedBranch != -1:
let prevFields = fieldsPresentInBranch(selectedBranch)
let currentFields = fieldsPresentInBranch(i)
localError(initExpr.info,
"The fields ($1) and ($2) cannot be initialized together, " &
"because they are from conflicting branches in the case object.",
localError(c.config, initExpr.info,
("The fields '$1' and '$2' cannot be initialized together, " &
"because they are from conflicting branches in the case object.") %
[prevFields, currentFields])
result = initConflict
else:
@@ -179,9 +179,9 @@ proc semConstructFields(c: PContext, recNode: PNode,
discriminator.sym, initExpr)
if discriminatorVal == nil:
let fields = fieldsPresentInBranch(selectedBranch)
localError(initExpr.info,
"you must provide a compile-time value for the discriminator '$1' " &
"in order to prove that it's safe to initialize $2.",
localError(c.config, initExpr.info,
("you must provide a compile-time value for the discriminator '$1' " &
"in order to prove that it's safe to initialize $2.") %
[discriminator.sym.name.s, fields])
mergeInitStatus(result, initNone)
else:
@@ -189,7 +189,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
template wrongBranchError(i) =
let fields = fieldsPresentInBranch(i)
localError(initExpr.info,
localError(c.config, initExpr.info,
"a case selecting discriminator '$1' with value '$2' " &
"appears in the object construction, but the field(s) $3 " &
"are in conflict with this value.",
@@ -219,7 +219,7 @@ proc semConstructFields(c: PContext, recNode: PNode,
# value was given to the discrimator. We can assume that it will be
# initialized to zero and this will select a particular branch as
# a result:
let matchedBranch = recNode.pickCaseBranch newIntLit(0)
let matchedBranch = recNode.pickCaseBranch newIntLit(c.graph, initExpr.info, 0)
checkMissingFields matchedBranch
else:
result = initPartial
@@ -239,20 +239,17 @@ proc semConstructFields(c: PContext, recNode: PNode,
result = if e != nil: initFull else: initNone
else:
internalAssert false
internalAssert c.config, false
proc semConstructType(c: PContext, initExpr: PNode,
t: PType, flags: TExprFlags): InitStatus =
var t = t
result = initUnknown
while true:
let status = semConstructFields(c, t.n, initExpr, flags)
mergeInitStatus(result, status)
if status in {initPartial, initNone, initUnknown}:
checkForMissingFields t.n, initExpr
checkForMissingFields c, t.n, initExpr
let base = t.sons[0]
if base == nil: break
t = skipTypes(base, skipPtrs)
@@ -263,13 +260,13 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
for child in n: result.add child
if t == nil:
localError(n.info, errGenerated, "object constructor needs an object type")
localError(c.config, n.info, errGenerated, "object constructor needs an object type")
return
t = skipTypes(t, {tyGenericInst, tyAlias, tySink})
if t.kind == tyRef: t = skipTypes(t.sons[0], {tyGenericInst, tyAlias, tySink})
if t.kind != tyObject:
localError(n.info, errGenerated, "object constructor needs an object type")
localError(c.config, n.info, errGenerated, "object constructor needs an object type")
return
# Check if the object is fully initialized by recursively testing each
@@ -296,17 +293,16 @@ proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
let field = result[i]
if nfSem notin field.flags:
if field.kind != nkExprColonExpr:
invalidObjConstr(field)
invalidObjConstr(c, field)
continue
let id = considerQuotedIdent(field[0])
let id = considerQuotedIdent(c.config, field[0])
# This node was not processed. There are two possible reasons:
# 1) It was shadowed by a field with the same name on the left
for j in 1 ..< i:
let prevId = considerQuotedIdent(result[j][0])
let prevId = considerQuotedIdent(c.config, result[j][0])
if prevId.id == id.id:
localError(field.info, errFieldInitTwice, id.s)
localError(c.config, field.info, errFieldInitTwice % id.s)
return
# 2) No such field exists in the constructed type
localError(field.info, errUndeclaredFieldX, id.s)
localError(c.config, field.info, errUndeclaredFieldX % id.s)
return

View File

@@ -23,7 +23,8 @@
import
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
renderer, types
renderer, types, modulegraphs, options
from trees import getMagic
from strutils import `%`
@@ -73,12 +74,15 @@ type
# the 'parallel' section
currentSpawnId: int
inLoop: int
graph: ModuleGraph
proc initAnalysisCtx(): AnalysisCtx =
proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx =
result.locals = @[]
result.slices = @[]
result.args = @[]
result.guards = @[]
result.guards.s = @[]
result.guards.o = initOperators(g)
result.graph = g
proc lookupSlot(c: AnalysisCtx; s: PSym): int =
for i in 0..<c.locals.len:
@@ -117,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
if isLocal(n):
let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil:
localError(n.info, "invalid usage of counter after increment")
localError(c.graph.config, n.info, "invalid usage of counter after increment")
else:
for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i])
@@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree
proc checkLe(c: AnalysisCtx; a, b: PNode) =
case proveLe(c.guards, a, b)
of impUnknown:
localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
of impYes: discard
of impNo:
localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
checkLe(c, arr.lowBound, idx)
checkLe(c, idx, arr.highBound)
checkLe(c, idx, arr.highBound(c.guards.o))
proc addLowerBoundAsFacts(c: var AnalysisCtx) =
for v in c.locals:
@@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) =
proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
checkLocal(c, n)
let le = le.canon
let ri = ri.canon
let le = le.canon(c.guards.o)
let ri = ri.canon(c.guards.o)
# perform static bounds checking here; and not later!
let oldState = c.guards.len
let oldState = c.guards.s.len
addLowerBoundAsFacts(c)
c.checkBounds(x, le)
c.checkBounds(x, ri)
c.guards.setLen(oldState)
c.guards.s.setLen(oldState)
c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0))
proc overlap(m: TModel; x,y,c,d: PNode) =
proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) =
# X..Y and C..D overlap iff (X <= D and C <= Y)
case proveLe(m, c, y)
of impUnknown:
case proveLe(m, x, d)
of impNo: discard
of impUnknown, impYes:
localError(x.info,
localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d])
of impYes:
case proveLe(m, x, d)
of impUnknown:
localError(x.info,
localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?x, ?d, ?x, ?y, ?c, ?d])
of impYes:
localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" %
localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d])
of impNo: discard
of impNo: discard
@@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode =
if isLocal(n):
let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil:
result = n +@ c.locals[s].stride.intVal
result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o)
else:
result = n
elif n.safeLen > 0:
@@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
addLowerBoundAsFacts(c)
# Every slice used in a loop needs to be disjoint with itself:
for x,a,b,id,inLoop in items(c.slices):
if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b))
if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b))
# Another tricky example is:
# while true:
# spawn f(a[i])
@@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
# XXX strictly speaking, 'or' is not correct here and it needs to
# be 'and'. However this prevents too many obviously correct programs
# like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
overlap(c.guards, x.a, x.b, y.a, y.b)
overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
k >= 0 and m >= 0):
# ah I cannot resist the temptation and add another sweet heuristic:
# if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we
# check they are disjoint and k < stride and m < stride:
overlap(c.guards, x.a, x.b, y.a, y.b)
overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
let stride = min(c.stride(x.a), c.stride(y.a))
if k < stride and m < stride:
discard
else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b])
else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b])
proc analyse(c: var AnalysisCtx; n: PNode)
@@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
proc analyseCase(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0])
let oldFacts = c.guards.len
let oldFacts = c.guards.s.len
for i in 1..<n.len:
let branch = n.sons[i]
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
addCaseBranchFacts(c.guards, n, i)
for i in 0 ..< branch.len:
analyse(c, branch.sons[i])
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
proc analyseIf(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0].sons[0])
let oldFacts = c.guards.len
addFact(c.guards, canon(n.sons[0].sons[0]))
let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0].sons[0], c.guards.o))
analyse(c, n.sons[0].sons[1])
for i in 1..<n.len:
let branch = n.sons[i]
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
for j in 0..i-1:
addFactNeg(c.guards, canon(n.sons[j].sons[0]))
addFactNeg(c.guards, canon(n.sons[j].sons[0], c.guards.o))
if branch.len > 1:
addFact(c.guards, canon(branch.sons[0]))
addFact(c.guards, canon(branch.sons[0], c.guards.o))
for i in 0 ..< branch.len:
analyse(c, branch.sons[i])
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
proc analyse(c: var AnalysisCtx; n: PNode) =
case n.kind
@@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
c.addSlice(n, n[0], n[1], n[1])
analyseSons(c, n)
of nkReturnStmt, nkRaiseStmt, nkTryStmt:
localError(n.info, "invalid control flow for 'parallel'")
localError(c.graph.config, n.info, "invalid control flow for 'parallel'")
# 'break' that leaves the 'parallel' section is not valid either
# or maybe we should generate a 'try' XXX
of nkVarSection, nkLetSection:
@@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
if it[j].isLocal:
let slot = c.getSlot(it[j].sym)
if slot.lower.isNil: slot.lower = value
else: internalError(it.info, "slot already has a lower bound")
else: internalError(c.graph.config, it.info, "slot already has a lower bound")
if not isSpawned: analyse(c, value)
of nkCaseStmt: analyseCase(c, n)
of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
@@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else:
# loop may never execute:
let oldState = c.locals.len
let oldFacts = c.guards.len
addFact(c.guards, canon(n.sons[0]))
let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0], c.guards.o))
analyse(c, n.sons[1])
setLen(c.locals, oldState)
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
# we know after the loop the negation holds:
if not hasSubnodeWith(n.sons[1], nkBreakStmt):
addFactNeg(c.guards, canon(n.sons[0]))
addFactNeg(c.guards, canon(n.sons[0], c.guards.o))
dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
@@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else:
analyseSons(c, n)
proc transformSlices(n: PNode): PNode =
proc transformSlices(g: ModuleGraph; n: PNode): PNode =
if n.kind in nkCallKinds and n[0].kind == nkSym:
let op = n[0].sym
if op.name.s == "[]" and op.fromSystem:
result = copyNode(n)
let opSlice = newSymNode(createMagic("slice", mSlice))
opSlice.typ = getSysType(tyInt)
let opSlice = newSymNode(createMagic(g, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
result.add opSlice
result.add n[1]
let slice = n[2].skipStmtList
@@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode =
if n.safeLen > 0:
result = shallowCopy(n)
for i in 0 ..< n.len:
result.sons[i] = transformSlices(n.sons[i])
result.sons[i] = transformSlices(g, n.sons[i])
else:
result = n
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode
proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode
proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
result = shallowCopy(n)
for i in 0 ..< n.len:
result.sons[i] = transformSpawn(owner, n.sons[i], barrier)
result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier)
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
case n.kind
of nkVarSection, nkLetSection:
result = nil
for it in n:
let b = it.lastSon
if getMagic(b) == mSpawn:
if it.len != 3: localError(it.info, "invalid context for 'spawn'")
let m = transformSlices(b)
if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'")
let m = transformSlices(g, b)
if result.isNil:
result = newNodeI(nkStmtList, n.info)
result.add n
let t = b[1][0].typ.sons[0]
if spawnResult(t, true) == srByVar:
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
it.sons[it.len-1] = emptyNode
else:
it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
if result.isNil: result = n
of nkAsgn, nkFastAsgn:
let b = n[1]
if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
spawnResult(t, true) == srByVar):
let m = transformSlices(b)
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
result = transformSpawnSons(owner, n, barrier)
let m = transformSlices(g, b)
return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0])
result = transformSpawnSons(g, owner, n, barrier)
of nkCallKinds:
if getMagic(n) == mSpawn:
result = transformSlices(n)
return wrapProcForSpawn(owner, result, n.typ, barrier, nil)
result = transformSpawnSons(owner, n, barrier)
result = transformSlices(g, n)
return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil)
result = transformSpawnSons(g, owner, n, barrier)
elif n.safeLen > 0:
result = transformSpawnSons(owner, n, barrier)
result = transformSpawnSons(g, owner, n, barrier)
else:
result = n
@@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) =
proc generateAliasChecks(a: AnalysisCtx; result: PNode) =
discard "too implement"
proc liftParallel*(owner: PSym; n: PNode): PNode =
proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
# this needs to be called after the 'for' loop elimination
# first pass:
@@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
# - detect used arguments
#echo "PAR ", renderTree(n)
var a = initAnalysisCtx()
var a = initAnalysisCtx(g)
let body = n.lastSon
analyse(a, body)
if a.spawns == 0:
localError(n.info, "'parallel' section without 'spawn'")
localError(g.config, n.info, "'parallel' section without 'spawn'")
checkSlicesAreDisjoint(a)
checkArgs(a, body)
var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent"barrier", owner, n.info)
temp.typ = magicsys.getCompilerProc("Barrier").typ
temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp)
varSection.addVar tempNode
@@ -489,6 +493,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
generateAliasChecks(a, result)
result.add varSection
result.add callCodegenProc("openBarrier", barrier)
result.add transformSpawn(owner, body, barrier)
result.add callCodegenProc("closeBarrier", barrier)
result.add callCodegenProc(g, "openBarrier", barrier)
result.add transformSpawn(g, owner, body, barrier)
result.add callCodegenProc(g, "closeBarrier", barrier)

View File

@@ -9,7 +9,8 @@
import
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
wordrecg, strutils, options, guards, writetracking
wordrecg, strutils, options, guards, writetracking, configuration,
modulegraphs
when defined(useDfa):
import dfa
@@ -52,6 +53,8 @@ type
locked: seq[PNode] # locked locations
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
maxLockLevel, currLockLevel: TLockLevel
config: ConfigRef
graph: ModuleGraph
PEffects = var TEffects
proc `<`(a, b: TLockLevel): bool {.borrow.}
@@ -72,24 +75,23 @@ proc getLockLevel(t: PType): TLockLevel =
proc lockLocations(a: PEffects; pragma: PNode) =
if pragma.kind != nkExprColonExpr:
localError(pragma.info, errGenerated, "locks pragma without argument")
localError(a.config, pragma.info, "locks pragma without argument")
return
var firstLL = TLockLevel(-1'i16)
for x in pragma[1]:
let thisLL = getLockLevel(x.typ)
if thisLL != 0.TLockLevel:
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
localError(x.info, "invalid lock level: " & $thisLL)
localError(a.config, x.info, "invalid lock level: " & $thisLL)
elif firstLL < 0.TLockLevel: firstLL = thisLL
elif firstLL != thisLL:
localError(x.info, errGenerated,
localError(a.config, x.info,
"multi-lock requires the same static lock level for every operand")
a.maxLockLevel = max(a.maxLockLevel, firstLL)
a.locked.add x
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
localError(pragma.info, errGenerated,
"invalid nested locking")
localError(a.config, pragma.info, "invalid nested locking")
a.currLockLevel = firstLL
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
@@ -102,7 +104,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
# message(n.info, warnUnguardedAccess, renderTree(n))
#else:
if not a.isTopLevel:
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
localError(a.config, n.info, "unguarded access: " & renderTree(n))
# 'guard*' are checks which are concerned with 'guard' annotations
# (var x{.guard: y.}: int)
@@ -125,7 +127,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
if ty == nil: break
ty = ty.skipTypes(skipPtrs)
if field == nil:
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
localError(a.config, n.info, "invalid guard field: " & g.name.s)
return
g = field
#ri.sym.guard = field
@@ -138,13 +140,13 @@ proc guardDotAccess(a: PEffects; n: PNode) =
for L in a.locked:
#if a.guards.sameSubexprs(dot, L): return
if guards.sameTree(dot, L): return
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
localError(a.config, n.info, "unguarded access: " & renderTree(n))
else:
guardGlobal(a, n, g)
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
template compileToCpp(a): untyped =
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
a.config.cmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
if a.inTryStmt > 0 and not compileToCpp(a):
incl(s.flags, sfVolatile)
@@ -167,9 +169,9 @@ proc initVarViaNew(a: PEffects, n: PNode) =
elif isLocalVar(a, s):
makeVolatile(a, s)
proc warnAboutGcUnsafe(n: PNode) =
proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
#assert false
message(n.info, warnGcUnsafe, renderTree(n))
message(conf, n.info, warnGcUnsafe, renderTree(n))
proc markGcUnsafe(a: PEffects; reason: PSym) =
if not a.inEnforcedGcSafe:
@@ -184,7 +186,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
a.owner.gcUnsafetyReason = reason.sym
else:
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
a.owner, reason.info)
a.owner, reason.info, {})
when true:
template markSideEffect(a: PEffects; reason: typed) =
@@ -194,42 +196,42 @@ else:
a.hasSideEffect = true
markGcUnsafe(a, reason)
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
let u = s.gcUnsafetyReason
if u != nil and not cycleCheck.containsOrIncl(u.id):
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
case u.kind
of skLet, skVar:
message(s.info, msgKind,
message(conf, s.info, msgKind,
("'$#' is not GC-safe as it accesses '$#'" &
" which is a global using GC'ed memory") % [s.name.s, u.name.s])
of routineKinds:
# recursive call *always* produces only a warning so the full error
# message is printed:
listGcUnsafety(u, true, cycleCheck)
message(s.info, msgKind,
listGcUnsafety(u, true, cycleCheck, conf)
message(conf, s.info, msgKind,
"'$#' is not GC-safe as it calls '$#'" %
[s.name.s, u.name.s])
of skParam, skForVar:
message(s.info, msgKind,
message(conf, s.info, msgKind,
"'$#' is not GC-safe as it performs an indirect call via '$#'" %
[s.name.s, u.name.s])
else:
message(u.info, msgKind,
message(conf, u.info, msgKind,
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
var cycleCheck = initIntSet()
listGcUnsafety(s, onlyWarning, cycleCheck)
listGcUnsafety(s, onlyWarning, cycleCheck, conf)
proc useVar(a: PEffects, n: PNode) =
let s = n.sym
if isLocalVar(a, s):
if s.id notin a.init:
if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
message(n.info, warnProveInit, s.name.s)
message(a.config, n.info, warnProveInit, s.name.s)
else:
message(n.info, warnUninit, s.name.s)
message(a.config, n.info, warnUninit, s.name.s)
# prevent superfluous warnings about the same variable:
a.init.add s.id
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
@@ -257,34 +259,30 @@ proc addToIntersection(inter: var TIntersection, s: int) =
proc throws(tracked, n: PNode) =
if n.typ == nil or n.typ.kind != tyError: tracked.add n
proc getEbase(): PType =
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
else: sysTypeFromName"E_Base"
proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
result = g.sysTypeFromName(info, "Exception")
proc excType(n: PNode): PType =
proc excType(g: ModuleGraph; n: PNode): PType =
# reraise is like raising E_Base:
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
result = skipTypes(t, skipPtrs)
proc createRaise(n: PNode): PNode =
proc createRaise(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
result.typ = getEbase()
result.typ = getEbase(g, n.info)
if not n.isNil: result.info = n.info
proc createTag(n: PNode): PNode =
proc createTag(g: ModuleGraph; n: PNode): PNode =
result = newNode(nkType)
if getCompilerProc("RootEffect") != nil:
result.typ = sysTypeFromName"RootEffect"
else:
result.typ = sysTypeFromName"TEffect"
result.typ = g.sysTypeFromName(n.info, "RootEffect")
if not n.isNil: result.info = n.info
proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
assert e.kind != nkRaiseStmt
var aa = a.exc
for i in a.bottom ..< aa.len:
if sameType(aa[i].excType, e.excType):
if not useLineInfo or gCmd == cmdDoc: return
if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
if not useLineInfo or a.config.cmd == cmdDoc: return
elif aa[i].info == e.info: return
throws(a.exc, e)
@@ -292,25 +290,25 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
var aa = a.tags
for i in 0 ..< aa.len:
if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
if not useLineInfo or gCmd == cmdDoc: return
if not useLineInfo or a.config.cmd == cmdDoc: return
elif aa[i].info == e.info: return
throws(a.tags, e)
proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
if b.isNil:
addEffect(a, createRaise(comesFrom))
addEffect(a, createRaise(a.graph, comesFrom))
else:
for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
proc mergeTags(a: PEffects, b, comesFrom: PNode) =
if b.isNil:
addTag(a, createTag(comesFrom))
addTag(a, createTag(a.graph, comesFrom))
else:
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
proc listEffects(a: PEffects) =
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
#if a.maxLockLevel != 0:
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
@@ -320,7 +318,7 @@ proc catches(tracked: PEffects, e: PType) =
var i = tracked.bottom
while i < L:
# r supertype of e?
if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
tracked.exc.sons[i] = tracked.exc.sons[L-1]
dec L
else:
@@ -489,7 +487,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
if lockLevel >= tracked.currLockLevel:
# if in lock section:
if tracked.currLockLevel > 0.TLockLevel:
localError n.info, errGenerated,
localError tracked.config, n.info, errGenerated,
"expected lock level < " & $tracked.currLockLevel &
" but got lock level " & $lockLevel
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
@@ -503,22 +501,22 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
mergeTags(tracked, tagSpec, n)
if notGcSafe(s.typ) and sfImportc notin s.flags:
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, s)
if tfNoSideEffect notin s.typ.flags:
markSideEffect(tracked, s)
mergeLockLevels(tracked, n, s.getLockLevel)
proc procVarcheck(n: PNode) =
proc procVarcheck(n: PNode; conf: ConfigRef) =
if n.kind in nkSymChoices:
for x in n: procVarCheck(x)
for x in n: procVarCheck(x, conf)
elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s)
localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
let n = n.skipConv
if paramType.isNil or paramType.kind != tyTypeDesc:
procVarcheck skipConvAndClosure(n)
procVarcheck skipConvAndClosure(n), tracked.config
#elif n.kind in nkSymChoices:
# echo "came here"
let paramType = paramType.skipTypesOrNil(abstractInst)
@@ -534,15 +532,16 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
return
case impliesNotNil(tracked.guards, n)
of impUnknown:
message(n.info, errGenerated,
message(tracked.config, n.info, errGenerated,
"cannot prove '$1' is not nil" % n.renderTree)
of impNo:
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
message(tracked.config, n.info, errGenerated,
"'$1' is provably nil" % n.renderTree)
of impYes: discard
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
addEffect(tracked, createRaise(n))
addTag(tracked, createTag(n))
addEffect(tracked, createRaise(tracked.graph, n))
addTag(tracked, createTag(tracked.graph, n))
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
else: op.lockLevel
#if lockLevel == UnknownLockLevel:
@@ -557,7 +556,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
let a = skipConvAndClosure(n)
let op = a.typ
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
internalAssert op.n.sons[0].kind == nkEffectList
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
let s = n.skipConv
if s.kind == nkSym and s.sym.kind in routineKinds:
@@ -572,7 +571,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
assumeTheWorst(tracked, n, op)
# assume GcUnsafe unless in its type; 'forward' does not matter:
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, a)
elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
markSideEffect(tracked, a)
@@ -580,7 +579,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
mergeTags(tracked, effectList.sons[tagEffects], n)
if notGcSafe(op):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, a)
elif tfNoSideEffect notin op.flags:
markSideEffect(tracked, a)
@@ -592,7 +591,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
# XXX figure out why this can be a non tyProc here. See httpclient.nim for an
# example that triggers it.
if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
localError(n.info, $n & " is not GC safe")
localError(tracked.config, n.info, $n & " is not GC safe")
notNilCheck(tracked, n, paramType)
proc breaksBlock(n: PNode): bool =
@@ -608,18 +607,18 @@ proc breaksBlock(n: PNode): bool =
proc trackCase(tracked: PEffects, n: PNode) =
track(tracked, n.sons[0])
let oldState = tracked.init.len
let oldFacts = tracked.guards.len
let oldFacts = tracked.guards.s.len
let stringCase = skipTypes(n.sons[0].typ,
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
warnProveField in gNotes
warnProveField in tracked.config.notes
var inter: TIntersection = @[]
var toCover = 0
for i in 1..<n.len:
let branch = n.sons[i]
setLen(tracked.init, oldState)
if interesting:
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
addCaseBranchFacts(tracked.guards, n, i)
for i in 0 ..< branch.len:
track(tracked, branch.sons[i])
@@ -632,11 +631,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
for id, count in items(inter):
if count >= toCover: tracked.init.add id
# else we can't merge
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
proc trackIf(tracked: PEffects, n: PNode) =
track(tracked, n.sons[0].sons[0])
let oldFacts = tracked.guards.len
let oldFacts = tracked.guards.s.len
addFact(tracked.guards, n.sons[0].sons[0])
let oldState = tracked.init.len
@@ -649,7 +648,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
for i in 1..<n.len:
let branch = n.sons[i]
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
for j in 0..i-1:
addFactNeg(tracked.guards, n.sons[j].sons[0])
if branch.len > 1:
@@ -665,7 +664,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
for id, count in items(inter):
if count >= toCover: tracked.init.add id
# else we can't merge as it is not exhaustive
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
proc trackBlock(tracked: PEffects, n: PNode) =
if n.kind in {nkStmtList, nkStmtListExpr}:
@@ -693,7 +692,7 @@ proc paramType(op: PType, i: int): PType =
proc cstringCheck(tracked: PEffects; n: PNode) =
if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
message(n.info, warnUnsafeCode, renderTree(n))
message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
proc track(tracked: PEffects, n: PNode) =
case n.kind
@@ -735,7 +734,7 @@ proc track(tracked: PEffects, n: PNode) =
if notGcSafe(op) and not importedFromC(a):
# and it's not a recursive call:
if not (a.kind == nkSym and a.sym == tracked.owner):
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
markGcUnsafe(tracked, a)
if tfNoSideEffect notin op.flags and not importedFromC(a):
# and it's not a recursive call:
@@ -753,7 +752,7 @@ proc track(tracked: PEffects, n: PNode) =
# var s: seq[notnil]; newSeq(s, 0) is a special case!
discard
else:
message(arg.info, warnProveInit, $arg)
message(tracked.config, arg.info, warnProveInit, $arg)
for i in 0 ..< safeLen(n):
track(tracked, n.sons[i])
of nkDotExpr:
@@ -761,7 +760,8 @@ proc track(tracked: PEffects, n: PNode) =
for i in 0 ..< len(n): track(tracked, n.sons[i])
of nkCheckedFieldExpr:
track(tracked, n.sons[0])
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
if warnProveField in tracked.config.notes:
checkFieldAccess(tracked.guards, n, tracked.config)
of nkTryStmt: trackTryStmt(tracked, n)
of nkPragma: trackPragmaStmt(tracked, n)
of nkAsgn, nkFastAsgn:
@@ -798,11 +798,11 @@ proc track(tracked: PEffects, n: PNode) =
else:
# loop may never execute:
let oldState = tracked.init.len
let oldFacts = tracked.guards.len
let oldFacts = tracked.guards.s.len
addFact(tracked.guards, n.sons[0])
track(tracked, n.sons[1])
setLen(tracked.init, oldState)
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
of nkForStmt, nkParForStmt:
# we are very conservative here and assume the loop is never executed:
let oldState = tracked.init.len
@@ -811,13 +811,13 @@ proc track(tracked: PEffects, n: PNode) =
setLen(tracked.init, oldState)
of nkObjConstr:
when false: track(tracked, n.sons[0])
let oldFacts = tracked.guards.len
let oldFacts = tracked.guards.s.len
for i in 1 ..< len(n):
let x = n.sons[i]
track(tracked, x)
if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
addDiscriminantFact(tracked.guards, x)
setLen(tracked.guards, oldFacts)
setLen(tracked.guards.s, oldFacts)
of nkPragmaBlock:
let pragmaList = n.sons[0]
let oldLocked = tracked.locked.len
@@ -844,31 +844,31 @@ proc track(tracked: PEffects, n: PNode) =
else:
for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
proc subtypeRelation(spec, real: PNode): bool =
result = safeInheritanceDiff(real.excType, spec.typ) <= 0
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) =
# check that any real exception is listed in 'spec'; mark those as used;
# report any unused exception
var used = initIntSet()
for r in items(real):
block search:
for s in 0 ..< spec.len:
if effectPredicate(spec[s], r):
if effectPredicate(g, spec[s], r):
used.incl(s)
break search
# XXX call graph analysis would be nice here!
pushInfoContext(spec.info)
localError(r.info, errGenerated, msg & typeToString(r.typ))
localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
popInfoContext()
# hint about unnecessarily listed exception types:
if hints:
for s in 0 ..< spec.len:
if not used.contains(s):
message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
proc checkMethodEffects*(disp, branch: PSym) =
proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
## checks for consistent effects for multi methods.
let actual = branch.typ.n.sons[0]
if actual.len != effectListLen: return
@@ -876,42 +876,42 @@ proc checkMethodEffects*(disp, branch: PSym) =
let p = disp.ast.sons[pragmasPos]
let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):
checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
"can raise an unlisted exception: ", hints=off, subtypeRelation)
let tagsSpec = effectSpec(p, wTags)
if not isNil(tagsSpec):
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
"can have an unlisted effect: ", hints=off, subtypeRelation)
if sfThread in disp.flags and notGcSafe(branch.typ):
localError(branch.info, "base method is GC-safe, but '$1' is not" %
localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
branch.name.s)
if branch.typ.lockLevel > disp.typ.lockLevel:
when true:
message(branch.info, warnLockLevel,
message(g.config, branch.info, warnLockLevel,
"base method has lock level $1, but dispatcher has $2" %
[$branch.typ.lockLevel, $disp.typ.lockLevel])
else:
# XXX make this an error after bigbreak has been released:
localError(branch.info,
localError(g.config, branch.info,
"base method has lock level $1, but dispatcher has $2" %
[$branch.typ.lockLevel, $disp.typ.lockLevel])
proc setEffectsForProcType*(t: PType, n: PNode) =
proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
var effects = t.n.sons[0]
internalAssert t.kind == tyProc and effects.kind == nkEffectList
if t.kind != tyProc or effects.kind != nkEffectList: return
let
raisesSpec = effectSpec(n, wRaises)
tagsSpec = effectSpec(n, wTags)
if not isNil(raisesSpec) or not isNil(tagsSpec):
internalAssert effects.len == 0
internalAssert g.config, effects.len == 0
newSeq(effects.sons, effectListLen)
if not isNil(raisesSpec):
effects.sons[exceptionEffects] = raisesSpec
if not isNil(tagsSpec):
effects.sons[tagEffects] = tagsSpec
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
newSeq(effects.sons, effectListLen)
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
@@ -922,52 +922,55 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
t.tags = effects.sons[tagEffects]
t.owner = s
t.init = @[]
t.guards = @[]
t.guards.s = @[]
t.guards.o = initOperators(g)
t.locked = @[]
t.graph = g
t.config = g.config
proc trackProc*(s: PSym, body: PNode) =
proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) =
var effects = s.typ.n.sons[0]
internalAssert effects.kind == nkEffectList
if effects.kind != nkEffectList: return
# effects already computed?
if sfForward in s.flags: return
if effects.len == effectListLen: return
var t: TEffects
initEffects(effects, s, t)
initEffects(g, effects, s, t)
track(t, body)
if not isEmptyType(s.typ.sons[0]) and
{tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
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")
message(g.config, body.info, warnProveInit, "result")
let p = s.ast.sons[pragmasPos]
let raisesSpec = effectSpec(p, wRaises)
if not isNil(raisesSpec):
checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
hints=on, subtypeRelation)
# after the check, use the formal spec:
effects.sons[exceptionEffects] = raisesSpec
let tagsSpec = effectSpec(p, wTags)
if not isNil(tagsSpec):
checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
hints=off, subtypeRelation)
# after the check, use the formal spec:
effects.sons[tagEffects] = tagsSpec
if sfThread in s.flags and t.gcUnsafe:
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
listGcUnsafety(s, onlyWarning=false)
listGcUnsafety(s, onlyWarning=false, g.config)
else:
listGcUnsafety(s, onlyWarning=true)
listGcUnsafety(s, onlyWarning=true, g.config)
#localError(s.info, warnGcUnsafe2, s.name.s)
if sfNoSideEffect in s.flags and t.hasSideEffect:
when false:
listGcUnsafety(s, onlyWarning=false)
listGcUnsafety(s, onlyWarning=false, g.config)
else:
localError(s.info, errXhasSideEffects, s.name.s)
localError(g.config, s.info, "'$1' can have side effects" % s.name.s)
if not t.gcUnsafe:
s.typ.flags.incl tfGcSafe
if not t.hasSideEffect and sfSideEffect notin s.flags:
@@ -976,7 +979,7 @@ proc trackProc*(s: PSym, body: PNode) =
s.typ.lockLevel = t.maxLockLevel
elif t.maxLockLevel > s.typ.lockLevel:
#localError(s.info,
message(s.info, warnLockLevel,
message(g.config, s.info, warnLockLevel,
"declared lock level is $1, but real lock level is $2" %
[$s.typ.lockLevel, $t.maxLockLevel])
when defined(useDfa):
@@ -984,12 +987,12 @@ proc trackProc*(s: PSym, body: PNode) =
dataflowAnalysis(s, body)
when false: trackWrites(s, body)
proc trackTopLevelStmt*(module: PSym; n: PNode) =
proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) =
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
return
var effects = newNode(nkEffectList, n.info)
var t: TEffects
initEffects(effects, module, t)
initEffects(g, effects, module, t)
t.isToplevel = true
track(t, n)

File diff suppressed because it is too large Load Diff

View File

@@ -26,6 +26,9 @@ discard """
a way to achieve lexical scoping at compile time.
"""
const
errImplOfXNotAllowed = "implementation of '$1' is not allowed"
type
TSymBinding = enum
spNone, spGenSym, spInject
@@ -60,7 +63,7 @@ proc symChoice(c: PContext, n: PNode, s: PSym, r: TSymChoiceRule): PNode =
# (s.kind notin routineKinds or s.magic != mNone):
# for instance 'nextTry' is both in tables.nim and astalgo.nim ...
result = newSymNode(s, n.info)
markUsed(n.info, s, c.graph.usageSym)
markUsed(c.config, n.info, s, c.graph.usageSym)
else:
# semantic checking requires a type; ``fitNode`` deals with it
# appropriately
@@ -91,20 +94,20 @@ proc semBindStmt(c: PContext, n: PNode, toBind: var IntSet): PNode =
else:
for x in items(sc): toBind.incl(x.sym.id)
else:
illFormedAst(a)
illFormedAst(a, c.config)
result = newNodeI(nkEmpty, n.info)
proc semMixinStmt(c: PContext, n: PNode, toMixin: var IntSet): PNode =
for i in 0 ..< n.len:
toMixin.incl(considerQuotedIdent(n.sons[i]).id)
toMixin.incl(considerQuotedIdent(c.config, n.sons[i]).id)
result = newNodeI(nkEmpty, n.info)
proc replaceIdentBySym(n: var PNode, s: PNode) =
proc replaceIdentBySym(c: PContext; n: var PNode, s: PNode) =
case n.kind
of nkPostfix: replaceIdentBySym(n.sons[1], s)
of nkPragmaExpr: replaceIdentBySym(n.sons[0], s)
of nkPostfix: replaceIdentBySym(c, n.sons[1], s)
of nkPragmaExpr: replaceIdentBySym(c, n.sons[0], s)
of nkIdent, nkAccQuoted, nkSym: n = s
else: illFormedAst(n)
else: illFormedAst(n, c.config)
type
TemplCtx = object
@@ -129,7 +132,7 @@ proc getIdentNode(c: var TemplCtx, n: PNode): PNode =
result = newSymNode(s, n.info)
of nkAccQuoted, nkSym: result = n
else:
illFormedAst(n)
illFormedAst(n, c.c.config)
result = n
proc isTemplParam(c: TemplCtx, n: PNode): bool {.inline.} =
@@ -163,7 +166,7 @@ proc onlyReplaceParams(c: var TemplCtx, n: PNode): PNode =
result.sons[i] = onlyReplaceParams(c, n.sons[i])
proc newGenSym(kind: TSymKind, n: PNode, c: var TemplCtx): PSym =
result = newSym(kind, considerQuotedIdent(n), c.owner, n.info)
result = newSym(kind, considerQuotedIdent(c.c.config, n), c.owner, n.info)
incl(result.flags, sfGenSym)
incl(result.flags, sfShadowed)
@@ -184,12 +187,12 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
n = onlyReplaceParams(c, n)
return
else:
illFormedAst(x)
illFormedAst(x, c.c.config)
let ident = getIdentNode(c, x)
if not isTemplParam(c, ident):
c.toInject.incl(x.ident.id)
else:
replaceIdentBySym(n, ident)
replaceIdentBySym(c.c, n, ident)
else:
let ident = getIdentNode(c, n)
if not isTemplParam(c, ident):
@@ -203,17 +206,17 @@ proc addLocalDecl(c: var TemplCtx, n: var PNode, k: TSymKind) =
#
# We need to ensure that both 'a' produce the same gensym'ed symbol.
# So we need only check the *current* scope.
let s = localSearchInScope(c.c, considerQuotedIdent ident)
let s = localSearchInScope(c.c, considerQuotedIdent(c.c.config, ident))
if s != nil and s.owner == c.owner and sfGenSym in s.flags:
styleCheckUse(n.info, s)
replaceIdentBySym(n, newSymNode(s, n.info))
replaceIdentBySym(c.c, n, newSymNode(s, n.info))
else:
let local = newGenSym(k, ident, c)
addPrelimDecl(c.c, local)
styleCheckDef(n.info, local)
replaceIdentBySym(n, newSymNode(local, n.info))
replaceIdentBySym(c.c, n, newSymNode(local, n.info))
else:
replaceIdentBySym(n, ident)
replaceIdentBySym(c.c, n, ident)
proc semTemplSymbol(c: PContext, n: PNode, s: PSym): PNode =
incl(s.flags, sfUsed)
@@ -249,7 +252,7 @@ proc semRoutineInTemplName(c: var TemplCtx, n: PNode): PNode =
proc semRoutineInTemplBody(c: var TemplCtx, n: PNode, k: TSymKind): PNode =
result = n
checkSonsLen(n, bodyPos + 1)
checkSonsLen(n, bodyPos + 1, c.c.config)
# routines default to 'inject':
if n.kind notin nkLambdaKinds and symBinding(n.sons[pragmasPos]) == spGenSym:
let ident = getIdentNode(c, n.sons[namePos])
@@ -281,8 +284,8 @@ proc semTemplSomeDecl(c: var TemplCtx, n: PNode, symKind: TSymKind; start=0) =
for i in countup(start, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a)
checkMinSonsLen(a, 3)
if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): illFormedAst(a, c.c.config)
checkMinSonsLen(a, 3, c.c.config)
var L = sonsLen(a)
when defined(nimsuggest):
inc c.c.inTypeContext
@@ -354,7 +357,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
n.sons[0] = semTemplBody(c, n.sons[0])
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
checkMinSonsLen(a, 1, c.c.config)
var L = sonsLen(a)
for j in countup(0, L-2):
a.sons[j] = semTemplBody(c, a.sons[j])
@@ -371,7 +374,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
closeScope(c)
closeScope(c)
of nkBlockStmt, nkBlockExpr, nkBlockType:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.c.config)
openScope(c)
if n.sons[0].kind != nkEmpty:
addLocalDecl(c, n.sons[0], skLabel)
@@ -384,11 +387,11 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
n.sons[1] = semTemplBody(c, n.sons[1])
closeScope(c)
of nkTryStmt:
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.c.config)
n.sons[0] = semTemplBodyScope(c, n.sons[0])
for i in countup(1, sonsLen(n)-1):
var a = n.sons[i]
checkMinSonsLen(a, 1)
checkMinSonsLen(a, 1, c.c.config)
var L = sonsLen(a)
openScope(c)
for j in countup(0, L-2):
@@ -402,15 +405,15 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
of nkVarSection: semTemplSomeDecl(c, n, skVar)
of nkLetSection: semTemplSomeDecl(c, n, skLet)
of nkFormalParams:
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.c.config)
n.sons[0] = semTemplBody(c, n.sons[0])
semTemplSomeDecl(c, n, skParam, 1)
of nkConstSection:
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkConstDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.kind != nkConstDef): illFormedAst(a, c.c.config)
checkSonsLen(a, 3, c.c.config)
addLocalDecl(c, a.sons[0], skConst)
a.sons[1] = semTemplBody(c, a.sons[1])
a.sons[2] = semTemplBody(c, a.sons[2])
@@ -418,14 +421,14 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
checkSonsLen(a, 3, c.c.config)
addLocalDecl(c, a.sons[0], skType)
for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i]
if a.kind == nkCommentStmt: continue
if (a.kind != nkTypeDef): illFormedAst(a)
checkSonsLen(a, 3)
if (a.kind != nkTypeDef): illFormedAst(a, c.c.config)
checkSonsLen(a, 3, c.c.config)
if a.sons[1].kind != nkEmpty:
openScope(c)
a.sons[1] = semTemplBody(c, a.sons[1])
@@ -468,7 +471,7 @@ proc semTemplBody(c: var TemplCtx, n: PNode): PNode =
for i in 0 ..< n.len: result.add(n[i])
result = semTemplBodySons(c, result)
of nkAsgn, nkFastAsgn:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.c.config)
let a = n.sons[0]
let b = n.sons[1]
@@ -610,9 +613,9 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
result = n
if sfCustomPragma in s.flags:
if n.sons[bodyPos].kind != nkEmpty:
localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s)
elif n.sons[bodyPos].kind == nkEmpty:
localError(n.info, errImplOfXexpected, s.name.s)
localError(c.config, n.info, "implementation of '$1' expected" % s.name.s)
var proto = searchForProc(c, c.currentScope, s)
if proto == nil:
addInterfaceOverloadableSymAt(c, c.currentScope, s)
@@ -655,7 +658,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
if s != nil and s.owner == c.owner and s.kind == skParam:
result = newParam(c, n, s)
else:
localError(n.info, errInvalidExpression)
localError(c.c.config, n.info, "invalid expression")
result = n
proc stupidStmtListExpr(n: PNode): bool =
@@ -675,7 +678,7 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
# we support '(pattern){x}' to bind a subpattern to a parameter 'x';
# '(pattern){|x}' does the same but the matches will be gathered in 'x'
if n.len != 2:
localError(n.info, errInvalidExpression)
localError(c.c.config, n.info, "invalid expression")
elif n.sons[1].kind == nkIdent:
n.sons[0] = semPatternBody(c, n.sons[0])
n.sons[1] = expectParam(c, n.sons[1])
@@ -685,9 +688,9 @@ proc semPatternBody(c: var TemplCtx, n: PNode): PNode =
n.sons[0] = semPatternBody(c, n.sons[0])
n.sons[1].sons[1] = expectParam(c, n.sons[1].sons[1])
else:
localError(n.info, errInvalidExpression)
localError(c.c.config, n.info, "invalid expression")
else:
localError(n.info, errInvalidExpression)
localError(c.c.config, n.info, "invalid expression")
of nkStmtList, nkStmtListExpr:
if stupidStmtListExpr(n):
result = semPatternBody(c, n.lastSon)
@@ -759,5 +762,5 @@ proc semPattern(c: PContext, n: PNode): PNode =
if result.len == 1:
result = result.sons[0]
elif result.len == 0:
localError(n.info, errInvalidExpression)
localError(c.config, n.info, "a pattern cannot be empty")
closeScope(c)

View File

@@ -10,6 +10,33 @@
# this module does the semantic checking of type declarations
# included from sem.nim
const
errStringLiteralExpected = "string literal expected"
errIntLiteralExpected = "integer literal expected"
errWrongNumberOfVariables = "wrong number of variables"
errInvalidOrderInEnumX = "invalid order in enum '$1'"
errOrdinalTypeExpected = "ordinal type expected"
errSetTooBig = "set is too large"
errBaseTypeMustBeOrdinal = "base type of a set must be an ordinal"
errInheritanceOnlyWithNonFinalObjects = "inheritance only works with non-final objects"
errXExpectsOneTypeParam = "'$1' expects one type parameter"
errArrayExpectsTwoTypeParams = "array expects two type parameters"
errInvalidVisibilityX = "invalid visibility: '$1'"
errInitHereNotAllowed = "initialization not allowed here"
errXCannotBeAssignedTo = "'$1' cannot be assigned to"
errIteratorNotAllowed = "iterators can only be defined at the module's top level"
errXNeedsReturnType = "$1 needs a return type"
errNoReturnTypeDeclared = "no return type declared"
errTIsNotAConcreteType = "'$1' is not a concrete type"
errTypeExpected = "type expected"
errXOnlyAtModuleScope = "'$1' is only allowed at top level"
errDuplicateCaseLabel = "duplicate case label"
errMacroBodyDependsOnGenericTypes = "the macro body cannot be compiled, " &
"because the parameter '$1' has a generic type"
errIllegalRecursionInTypeX = "illegal recursion in type '$1'"
errNoGenericParamsAllowedForX = "no generic parameters allowed for $1"
errInOutFlagNotExtern = "the '$1' modifier can be used only with imported types"
proc newOrPrevType(kind: TTypeKind, prev: PType, c: PContext): PType =
if prev == nil:
result = newTypeS(kind, c)
@@ -34,11 +61,11 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
base = nil
result = newOrPrevType(tyEnum, prev, c)
result.n = newNodeI(nkEnumTy, n.info)
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
if n.sons[0].kind != nkEmpty:
base = semTypeNode(c, n.sons[0].sons[0], nil)
if base.kind != tyEnum:
localError(n.sons[0].info, errInheritanceOnlyWithEnums)
localError(c.config, n.sons[0].info, "inheritance only works with an enum")
counter = lastOrd(base) + 1
rawAddSon(result, base)
let isPure = result.sym != nil and sfPure in result.sym.flags
@@ -58,9 +85,9 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
else:
localError(strVal.info, errStringLiteralExpected)
localError(c.config, strVal.info, errStringLiteralExpected)
else:
localError(v.info, errWrongNumberOfVariables)
localError(c.config, v.info, errWrongNumberOfVariables)
of tyString, tyCString:
strVal = v
x = counter
@@ -69,7 +96,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
if i != 1:
if x != counter: incl(result.flags, tfEnumHasHoles)
if x < counter:
localError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
localError(c.config, n.sons[i].info, errInvalidOrderInEnumX % e.name.s)
x = counter
e.ast = strVal # might be nil
counter = x
@@ -78,7 +105,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
of nkIdent, nkAccQuoted:
e = newSymS(skEnumField, n.sons[i], c)
else:
illFormedAst(n[i])
illFormedAst(n[i], c.config)
e.typ = result
e.position = int(counter)
if e.position == 0: hasNull = true
@@ -87,12 +114,13 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
incl(e.flags, sfExported)
if not isPure: strTableAdd(c.module.tab, e)
addSon(result.n, newSymNode(e))
let conf = c.config
styleCheckDef(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)
wrongRedefinition(c, e.info, e.name.s)
inc(counter)
if not hasNull: incl(result.flags, tfNeedsInit)
@@ -104,11 +132,11 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType =
if base.kind in {tyGenericInst, tyAlias, tySink}: base = lastSon(base)
if base.kind != tyGenericParam:
if not isOrdinalType(base):
localError(n.info, errOrdinalTypeExpected)
localError(c.config, n.info, errOrdinalTypeExpected)
elif lengthOrd(base) > MaxSetElements:
localError(n.info, errSetTooBig)
localError(c.config, n.info, errSetTooBig)
else:
localError(n.info, errXExpectsOneTypeParam, "set")
localError(c.config, n.info, errXExpectsOneTypeParam % "set")
addSonSkipIntLit(result, errorType(c))
proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
@@ -117,10 +145,10 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string,
if sonsLen(n) == 2:
var base = semTypeNode(c, n.sons[1], nil)
if base.kind == tyVoid:
localError(n.info, errTIsNotAConcreteType, typeToString(base))
localError(c.config, n.info, errTIsNotAConcreteType % typeToString(base))
addSonSkipIntLit(result, base)
else:
localError(n.info, errXExpectsOneTypeParam, kindStr)
localError(c.config, n.info, errXExpectsOneTypeParam % kindStr)
addSonSkipIntLit(result, errorType(c))
proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
@@ -129,9 +157,9 @@ proc semVarargs(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[1], nil)
addSonSkipIntLit(result, base)
if sonsLen(n) == 3:
result.n = newIdentNode(considerQuotedIdent(n.sons[2]), n.sons[2].info)
result.n = newIdentNode(considerQuotedIdent(c.config, n.sons[2]), n.sons[2].info)
else:
localError(n.info, errXExpectsOneTypeParam, "varargs")
localError(c.config, n.info, errXExpectsOneTypeParam % "varargs")
addSonSkipIntLit(result, errorType(c))
proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
@@ -140,7 +168,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
else:
let isCall = int ord(n.kind in nkCallKinds+{nkBracketExpr})
let n = if n[0].kind == nkBracket: n[0] else: n
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
var t = semTypeNode(c, n.lastSon, nil)
if t.kind == tyTypeDesc and tfUnresolved notin t.flags:
t = t.base
@@ -155,7 +183,7 @@ proc semAnyRef(c: PContext; n: PNode; kind: TTypeKind; prev: PType): PType =
let region = semTypeNode(c, ni, nil)
if region.skipTypes({tyGenericInst, tyAlias, tySink}).kind notin {
tyError, tyObject}:
message n[i].info, errGenerated, "region needs to be an object type"
message c.config, n[i].info, errGenerated, "region needs to be an object type"
addSonSkipIntLit(result, region)
addSonSkipIntLit(result, t)
if tfPartial in result.flags:
@@ -167,7 +195,7 @@ proc semVarType(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyVar, prev, c)
var base = semTypeNode(c, n.sons[0], nil).skipTypes({tyTypeDesc})
if base.kind == tyVar:
localError(n.info, errVarVarTypeNotAllowed)
localError(c.config, n.info, "type 'var var' is not allowed")
base = base.sons[0]
addSonSkipIntLit(result, base)
else:
@@ -181,7 +209,7 @@ proc semDistinct(c: PContext, n: PNode, prev: PType): PType =
proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
assert isRange(n)
checkSonsLen(n, 3)
checkSonsLen(n, 3, c.config)
result = newOrPrevType(tyRange, prev, c)
result.n = newNodeI(nkRange, n.info)
# always create a 'valid' range type, but overwrite it later
@@ -189,7 +217,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
addSonSkipIntLit(result, errorType(c))
if (n[1].kind == nkEmpty) or (n[2].kind == nkEmpty):
localError(n.info, errRangeIsEmpty)
localError(c.config, n.info, "range is empty")
var range: array[2, PNode]
range[0] = semExprWithType(c, n[1], {efDetermineType})
@@ -204,11 +232,11 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
if not hasUnknownTypes:
if not sameType(rangeT[0].skipTypes({tyRange}), rangeT[1].skipTypes({tyRange})):
localError(n.info, errPureTypeMismatch)
localError(c.config, n.info, "type mismatch")
elif not rangeT[0].isOrdinalType:
localError(n.info, errOrdinalTypeExpected)
localError(c.config, n.info, "ordinal type expected")
elif enumHasHoles(rangeT[0]):
localError(n.info, errEnumXHasHoles, rangeT[0].sym.name.s)
localError(c.config, n.info, "enum '$1' has holes" % typeToString(rangeT[0]))
for i in 0..1:
if hasGenericArguments(range[i]):
@@ -218,7 +246,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
result.n.addSon semConstExpr(c, range[i])
if weakLeValue(result.n[0], result.n[1]) == impNo:
localError(n.info, errRangeIsEmpty)
localError(c.config, n.info, "range is empty")
result[0] = rangeT[0]
@@ -239,13 +267,13 @@ proc semRange(c: PContext, n: PNode, prev: PType): PType =
n.sons[1].floatVal < 0.0:
incl(result.flags, tfNeedsInit)
else:
if n[1].kind == nkInfix and considerQuotedIdent(n[1][0]).s == "..<":
localError(n[0].info, "range types need to be constructed with '..', '..<' is not supported")
if n[1].kind == nkInfix and considerQuotedIdent(c.config, n[1][0]).s == "..<":
localError(c.config, n[0].info, "range types need to be constructed with '..', '..<' is not supported")
else:
localError(n.sons[0].info, errRangeExpected)
localError(c.config, n.sons[0].info, "expected range")
result = newOrPrevType(tyError, prev, c)
else:
localError(n.info, errXExpectsOneTypeParam, "range")
localError(c.config, n.info, errXExpectsOneTypeParam % "range")
result = newOrPrevType(tyError, prev, c)
proc semArrayIndex(c: PContext, n: PNode): PType =
@@ -257,7 +285,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
result = makeRangeWithStaticExpr(c, e.typ.n)
elif e.kind in {nkIntLit..nkUInt64Lit}:
if e.intVal < 0:
localError(n[1].info,
localError(c.config, n[1].info,
"Array length can't be negative, but was " & $e.intVal)
result = makeRangeType(c, 0, e.intVal-1, n.info, e.typ)
elif e.kind == nkSym and e.typ.kind == tyStatic:
@@ -265,12 +293,12 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
return semArrayIndex(c, e.sym.ast)
if not isOrdinalType(e.typ.lastSon):
let info = if n.safeLen > 1: n[1].info else: n.info
localError(info, errOrdinalTypeExpected)
localError(c.config, info, errOrdinalTypeExpected)
result = makeRangeWithStaticExpr(c, e)
if c.inGenericContext > 0: result.flags.incl tfUnresolved
elif e.kind in nkCallKinds and hasGenericArguments(e):
if not isOrdinalType(e.typ):
localError(n[1].info, errOrdinalTypeExpected)
localError(c.config, n[1].info, errOrdinalTypeExpected)
# This is an int returning call, depending on an
# yet unknown generic param (see tgenericshardcases).
# We are going to construct a range type that will be
@@ -286,7 +314,7 @@ proc semArrayIndex(c: PContext, n: PNode): PType =
x.typ.skipTypes({tyTypeDesc}))
else:
result = x.typ.skipTypes({tyTypeDesc})
#localError(n[1].info, errConstExprExpected)
#localError(c.config, n[1].info, errConstExprExpected)
proc semArray(c: PContext, n: PNode, prev: PType): PType =
var base: PType
@@ -299,9 +327,9 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
if indxB.skipTypes({tyRange}).kind in {tyUInt, tyUInt64}:
discard
elif not isOrdinalType(indxB):
localError(n.sons[1].info, errOrdinalTypeExpected)
localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
elif enumHasHoles(indxB):
localError(n.sons[1].info, errEnumXHasHoles,
localError(c.config, n.sons[1].info, "enum '$1' has holes" %
typeToString(indxB.skipTypes({tyRange})))
base = semTypeNode(c, n.sons[2], nil)
# ensure we only construct a tyArray when there was no error (bug #3048):
@@ -311,7 +339,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
rawAddSonNoPropagationOfTypeFlags(result, indx)
addSonSkipIntLit(result, base)
else:
localError(n.info, errArrayExpectsTwoTypeParams)
localError(c.config, n.info, errArrayExpectsTwoTypeParams)
result = newOrPrevType(tyError, prev, c)
proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
@@ -320,10 +348,10 @@ proc semOrdinal(c: PContext, n: PNode, prev: PType): PType =
var base = semTypeNode(c, n.sons[1], nil)
if base.kind != tyGenericParam:
if not isOrdinalType(base):
localError(n.sons[1].info, errOrdinalTypeExpected)
localError(c.config, n.sons[1].info, errOrdinalTypeExpected)
addSonSkipIntLit(result, base)
else:
localError(n.info, errXExpectsOneTypeParam, "ordinal")
localError(c.config, n.info, errXExpectsOneTypeParam % "ordinal")
result = newOrPrevType(tyError, prev, c)
proc semTypeIdent(c: PContext, n: PNode): PSym =
@@ -334,7 +362,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if result.isNil:
result = qualifiedLookUp(c, n, {checkAmbiguity, checkUndeclared})
if result != nil:
markUsed(n.info, result, c.graph.usageSym)
markUsed(c.config, n.info, result, c.graph.usageSym)
styleCheckUse(n.info, result)
if result.kind == skParam and result.typ.kind == tyTypeDesc:
# This is a typedesc param. is it already bound?
@@ -345,7 +373,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
if bound != nil: return bound
return result
if result.typ.sym == nil:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
result = result.typ.sym.copySym
result.typ = copyType(result.typ, result.typ.owner, true)
@@ -359,7 +387,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
result.typ.flags.excl tfWildcard
return
else:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.kind != skType:
@@ -370,7 +398,7 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
amb = nextOverloadIter(ov, c, n)
if amb != nil: result = amb
else:
if result.kind != skError: localError(n.info, errTypeExpected)
if result.kind != skError: localError(c.config, n.info, errTypeExpected)
return errorSym(c, n)
if result.typ.kind != tyGenericParam:
# XXX get rid of this hack!
@@ -385,12 +413,12 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
n.info = oldInfo
n.typ = result.typ
else:
localError(n.info, errIdentifierExpected)
localError(c.config, n.info, "identifier expected")
result = errorSym(c, n)
proc semAnonTuple(c: PContext, n: PNode, prev: PType): PType =
if sonsLen(n) == 0:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyTuple, prev, c)
for it in n:
addSonSkipIntLit(result, semTypeNode(c, it, nil))
@@ -403,27 +431,27 @@ proc semTuple(c: PContext, n: PNode, prev: PType): PType =
var counter = 0
for i in countup(ord(n.kind == nkBracketExpr), sonsLen(n) - 1):
var a = n.sons[i]
if (a.kind != nkIdentDefs): illFormedAst(a)
checkMinSonsLen(a, 3)
if (a.kind != nkIdentDefs): illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var length = sonsLen(a)
if a.sons[length - 2].kind != nkEmpty:
typ = semTypeNode(c, a.sons[length - 2], nil)
else:
localError(a.info, errTypeExpected)
localError(c.config, a.info, errTypeExpected)
typ = errorType(c)
if a.sons[length - 1].kind != nkEmpty:
localError(a.sons[length - 1].info, errInitHereNotAllowed)
localError(c.config, a.sons[length - 1].info, errInitHereNotAllowed)
for j in countup(0, length - 3):
var field = newSymG(skField, a.sons[j], c)
field.typ = typ
field.position = counter
inc(counter)
if containsOrIncl(check, field.name.id):
localError(a.sons[j].info, errAttemptToRedefine, field.name.s)
localError(c.config, a.sons[j].info, "attempt to redefine: '" & field.name.s & "'")
else:
addSon(result.n, newSymNode(field))
addSonSkipIntLit(result, typ)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, field)
if result.n.len == 0: result.n = nil
proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
@@ -434,23 +462,23 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
# for gensym'ed identifiers the identifier may already have been
# transformed to a symbol and we need to use that here:
result = newSymG(kind, n.sons[1], c)
var v = considerQuotedIdent(n.sons[0])
var v = considerQuotedIdent(c.config, n.sons[0])
if sfExported in allowed and v.id == ord(wStar):
incl(result.flags, sfExported)
else:
if not (sfExported in allowed):
localError(n.sons[0].info, errXOnlyAtModuleScope, "export")
localError(c.config, n.sons[0].info, errXOnlyAtModuleScope % "export")
else:
localError(n.sons[0].info, errInvalidVisibilityX, renderTree(n[0]))
localError(c.config, n.sons[0].info, errInvalidVisibilityX % renderTree(n[0]))
else:
illFormedAst(n)
illFormedAst(n, c.config)
else:
result = newSymG(kind, n, c)
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym =
if n.kind == nkPragmaExpr:
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
result = semIdentVis(c, kind, n.sons[0], allowed)
case kind
of skType:
@@ -463,7 +491,7 @@ proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
else: discard
else:
result = semIdentVis(c, kind, n, allowed)
if gCmd == cmdPretty: styleCheckDef(n.info, result)
if c.config.cmd == cmdPretty: styleCheckDef(n.info, result)
proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
let ex = t[branchIndex][currentEx].skipConv
@@ -471,10 +499,10 @@ proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
for j in countup(0, sonsLen(t.sons[i]) - 2):
if i == branchIndex and j == currentEx: break
if overlap(t.sons[i].sons[j].skipConv, ex):
localError(ex.info, errDuplicateCaseLabel)
localError(c.config, ex.info, errDuplicateCaseLabel)
proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
checkMinSonsLen(t, 1)
checkMinSonsLen(t, 1, c.config)
let ac = semConstExpr(c, a)
let bc = semConstExpr(c, b)
let at = fitNode(c, t.sons[0].typ, ac, ac.info).skipConvTakeType
@@ -483,21 +511,21 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode
result = newNodeI(nkRange, a.info)
result.add(at)
result.add(bt)
if emptyRange(ac, bc): localError(b.info, errRangeIsEmpty)
if emptyRange(ac, bc): localError(c.config, b.info, "range is empty")
else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
proc semCaseBranchRange(c: PContext, t, b: PNode,
covered: var BiggestInt): PNode =
checkSonsLen(b, 3)
checkSonsLen(b, 3, c.config)
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
proc semCaseBranchSetElem(c: PContext, t, b: PNode,
covered: var BiggestInt): PNode =
if isRange(b):
checkSonsLen(b, 3)
checkSonsLen(b, 3, c.config)
result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
elif b.kind == nkRange:
checkSonsLen(b, 2)
checkSonsLen(b, 2, c.config)
result = semBranchRange(c, t, b.sons[0], b.sons[1], covered)
else:
result = fitNode(c, t.sons[0].typ, b, b.info)
@@ -520,7 +548,7 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
delSon(branch, 0)
return
elif r.kind notin {nkCurly, nkBracket} or len(r) == 0:
checkMinSonsLen(t, 1)
checkMinSonsLen(t, 1, c.config)
branch.sons[i] = skipConv(fitNode(c, t.sons[0].typ, r, r.info))
inc(covered)
else:
@@ -546,37 +574,37 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
father: PNode, rectype: PType) =
var a = copyNode(n)
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
semRecordNodeAux(c, n.sons[0], check, pos, a, rectype)
if a.sons[0].kind != nkSym:
internalError("semRecordCase: discriminant is no symbol")
internalError(c.config, "semRecordCase: discriminant is no symbol")
return
incl(a.sons[0].sym.flags, sfDiscriminant)
var covered: BiggestInt = 0
var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
if not isOrdinalType(typ):
localError(n.info, errSelectorMustBeOrdinal)
localError(c.config, n.info, "selector must be of an ordinal type")
elif firstOrd(typ) != 0:
localError(n.info, errGenerated, "low(" & $a.sons[0].sym.name.s &
localError(c.config, n.info, "low(" & $a.sons[0].sym.name.s &
") must be 0 for discriminant")
elif lengthOrd(typ) > 0x00007FFF:
localError(n.info, errLenXinvalid, a.sons[0].sym.name.s)
localError(c.config, n.info, "len($1) must be less than 32768" % a.sons[0].sym.name.s)
var chckCovered = true
for i in countup(1, sonsLen(n) - 1):
var b = copyTree(n.sons[i])
addSon(a, b)
case n.sons[i].kind
of nkOfBranch:
checkMinSonsLen(b, 2)
checkMinSonsLen(b, 2, c.config)
semCaseBranch(c, a, b, i, covered)
of nkElse:
chckCovered = false
checkSonsLen(b, 1)
else: illFormedAst(n)
checkSonsLen(b, 1, c.config)
else: illFormedAst(n, c.config)
delSon(b, sonsLen(b) - 1)
semRecordNodeAux(c, lastSon(n.sons[i]), check, pos, b, rectype)
if chckCovered and (covered != lengthOrd(a.sons[0].typ)):
localError(a.info, errNotAllCasesCovered)
if chckCovered and covered != lengthOrd(a.sons[0].typ):
localError(c.config, a.info, "not all cases are covered")
addSon(father, a)
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
@@ -587,22 +615,22 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
var branch: PNode = nil # the branch to take
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it == nil: illFormedAst(n)
if it == nil: illFormedAst(n, c.config)
var idx = 1
case it.kind
of nkElifBranch:
checkSonsLen(it, 2)
checkSonsLen(it, 2, c.config)
if c.inGenericContext == 0:
var e = semConstBoolExpr(c, it.sons[0])
if e.kind != nkIntLit: internalError(e.info, "semRecordNodeAux")
if e.kind != nkIntLit: internalError(c.config, e.info, "semRecordNodeAux")
elif e.intVal != 0 and branch == nil: branch = it.sons[1]
else:
it.sons[0] = forceBool(c, semExprWithType(c, it.sons[0]))
of nkElse:
checkSonsLen(it, 1)
checkSonsLen(it, 1, c.config)
if branch == nil: branch = it.sons[0]
idx = 0
else: illFormedAst(n)
else: illFormedAst(n, c.config)
if c.inGenericContext > 0:
# use a new check intset here for each branch:
var newCheck: IntSet
@@ -626,16 +654,16 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
semRecordNodeAux(c, n.sons[i], check, pos, a, rectype)
if a != father: addSon(father, a)
of nkIdentDefs:
checkMinSonsLen(n, 3)
checkMinSonsLen(n, 3, c.config)
var length = sonsLen(n)
var a: PNode
if father.kind != nkRecList and length>=4: a = newNodeI(nkRecList, n.info)
else: a = ast.emptyNode
if n.sons[length-1].kind != nkEmpty:
localError(n.sons[length-1].info, errInitHereNotAllowed)
localError(c.config, n.sons[length-1].info, errInitHereNotAllowed)
var typ: PType
if n.sons[length-2].kind == nkEmpty:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
typ = errorType(c)
else:
typ = semTypeNode(c, n.sons[length-2], nil)
@@ -644,7 +672,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
else: rectype.sym
for i in countup(0, sonsLen(n)-3):
var f = semIdentWithPragma(c, skField, n.sons[i], {sfExported})
suggestSym(n.sons[i].info, f, c.graph.usageSym)
suggestSym(c.config, n.sons[i].info, f, c.graph.usageSym)
f.typ = typ
f.position = pos
if fieldOwner != nil and
@@ -654,7 +682,7 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
f.flags = f.flags + ({sfImportc, sfExportc} * fieldOwner.flags)
inc(pos)
if containsOrIncl(check, f.name.id):
localError(n.sons[i].info, errAttemptToRedefine, f.name.s)
localError(c.config, n.sons[i].info, "attempt to redefine: '" & f.name.s & "'")
if a.kind == nkEmpty: addSon(father, newSymNode(f))
else: addSon(a, newSymNode(f))
styleCheckDef(f)
@@ -664,29 +692,29 @@ proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
# inherited from generic/partial specialized parent second check.
# There is no branch validity check here
if containsOrIncl(check, n.sym.name.id):
localError(n.info, errAttemptToRedefine, n.sym.name.s)
localError(c.config, n.info, "attempt to redefine: '" & n.sym.name.s & "'")
addSon(father, n)
of nkEmpty: discard
else: illFormedAst(n)
else: illFormedAst(n, c.config)
proc addInheritedFieldsAux(c: PContext, check: var IntSet, pos: var int,
n: PNode) =
case n.kind
of nkRecCase:
if (n.sons[0].kind != nkSym): internalError(n.info, "addInheritedFieldsAux")
if (n.sons[0].kind != nkSym): internalError(c.config, n.info, "addInheritedFieldsAux")
addInheritedFieldsAux(c, check, pos, n.sons[0])
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
addInheritedFieldsAux(c, check, pos, lastSon(n.sons[i]))
else: internalError(n.info, "addInheritedFieldsAux(record case branch)")
else: internalError(c.config, n.info, "addInheritedFieldsAux(record case branch)")
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
addInheritedFieldsAux(c, check, pos, n.sons[i])
of nkSym:
incl(check, n.sym.name.id)
inc(pos)
else: internalError(n.info, "addInheritedFieldsAux()")
else: internalError(c.config, n.info, "addInheritedFieldsAux()")
proc skipGenericInvocation(t: PType): PType {.inline.} =
result = t
@@ -709,12 +737,12 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
var pos = 0
var base, realBase: PType = nil
# n.sons[0] contains the pragmas (if any). We process these later...
checkSonsLen(n, 3)
checkSonsLen(n, 3, c.config)
if n.sons[1].kind != nkEmpty:
realBase = semTypeNode(c, n.sons[1].sons[0], nil)
base = skipTypesOrNil(realBase, skipPtrs)
if base.isNil:
localError(n.info, errIllegalRecursionInTypeX, "object")
localError(c.config, n.info, "cannot inherit from a type that is not an object type")
else:
var concreteBase = skipGenericInvocation(base)
if concreteBase.kind in {tyObject, tyGenericParam,
@@ -727,11 +755,11 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
addInheritedFields(c, check, pos, concreteBase)
else:
if concreteBase.kind != tyError:
localError(n.sons[1].info, "inheritance only works with non-final objects; " &
localError(c.config, n.sons[1].info, "inheritance only works with non-final objects; " &
"to enable inheritance write '" & typeToString(realBase) & " of RootObj'")
base = nil
realBase = nil
if n.kind != nkObjectTy: internalError(n.info, "semObjectNode")
if n.kind != nkObjectTy: internalError(c.config, n.info, "semObjectNode")
result = newOrPrevType(tyObject, prev, c)
rawAddSon(result, realBase)
if result.n.isNil:
@@ -769,8 +797,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
addDecl(c, param)
else:
# within a macro, every param has the type NimNode!
let nn = if getCompilerProc("NimNode") != nil: getSysSym"NimNode"
else: getSysSym"PNimrodNode"
let nn = getSysSym(c.graph, param.info, "NimNode")
var a = copySym(param)
a.typ = nn.typ
addDecl(c, a)
@@ -780,7 +807,7 @@ proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
let typedescId = getIdent"typedesc"
template shouldHaveMeta(t) =
internalAssert tfHasMeta in t.flags
internalAssert c.config, tfHasMeta in t.flags
# result.lastSon.flags.incl tfHasMeta
proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
@@ -838,7 +865,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
if tfUnresolved in paramType.flags: return # already lifted
let base = paramType.base.maybeLift
if base.isMetaType and procKind == skMacro:
localError(info, errMacroBodyDependsOnGenericTypes, paramName)
localError(c.config, info, errMacroBodyDependsOnGenericTypes % paramName)
result = addImplicitGeneric(c.newTypeWithSons(tyStatic, @[base]))
result.flags.incl({tfHasStatic, tfUnresolved})
@@ -870,7 +897,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
else:
for i in 0 ..< paramType.len:
if paramType.sons[i] == paramType:
globalError(info, errIllegalRecursionInTypeX, typeToString(paramType))
globalError(c.config, info, errIllegalRecursionInTypeX % typeToString(paramType))
var lifted = liftingWalk(paramType.sons[i])
if lifted != nil:
paramType.sons[i] = lifted
@@ -939,7 +966,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
result = addImplicitGeneric(copyType(paramType, getCurrOwner(c), false))
of tyGenericParam:
markUsed(info, paramType.sym, c.graph.usageSym)
markUsed(c.config, info, paramType.sym, c.graph.usageSym)
styleCheckUse(info, paramType.sym)
if tfWildcard in paramType.flags:
paramType.flags.excl tfWildcard
@@ -952,7 +979,7 @@ proc liftParamType(c: PContext, procKind: TSymKind, genericParams: PNode,
proc semParamType(c: PContext, n: PNode, constraint: var PNode): PType =
if n.kind == nkCurlyExpr:
result = semTypeNode(c, n.sons[0], nil)
constraint = semNodeKindConstraints(n)
constraint = semNodeKindConstraints(n, c.config)
else:
result = semTypeNode(c, n, nil)
@@ -971,7 +998,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# for historical reasons (code grows) this is invoked for parameter
# lists too and then 'isType' is false.
var cl: IntSet
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
result = newProcType(c, n.info, prev)
if genericParams != nil and sonsLen(genericParams) == 0:
cl = initIntSet()
@@ -985,8 +1012,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
# skip this parameter here. It'll then be re-generated in another LL
# pass over this instantiation:
if a.kind == nkSym and sfFromGeneric in a.sym.flags: continue
illFormedAst(a)
checkMinSonsLen(a, 3)
illFormedAst(a, c.config)
checkMinSonsLen(a, 3, c.config)
var
typ: PType = nil
def: PNode = nil
@@ -1009,7 +1036,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if not containsGenericType(typ):
def = fitNode(c, typ, def, def.info)
if not hasType and not hasDefault:
if isType: localError(a.info, "':' expected")
if isType: localError(c.config, a.info, "':' expected")
if kind in {skTemplate, skMacro}:
typ = newTypeS(tyExpr, c)
elif skipTypes(typ, {tyGenericInst, tyAlias, tySink}).kind == tyVoid:
@@ -1020,7 +1047,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
let param = strTableGet(c.signatures, arg.name)
if param != nil: typ = param.typ
else:
localError(a.info, "typeless parameters are obsolete")
localError(c.config, a.info, "typeless parameters are obsolete")
typ = errorType(c)
let lifted = liftParamType(c, kind, genericParams, typ,
arg.name.s, arg.info)
@@ -1031,11 +1058,11 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
inc(counter)
if def != nil and def.kind != nkEmpty: arg.ast = copyTree(def)
if containsOrIncl(check, arg.name.id):
localError(a.sons[j].info, errAttemptToRedefine, arg.name.s)
localError(c.config, a.sons[j].info, "attempt to redefine: '" & arg.name.s & "'")
addSon(result.n, newSymNode(arg))
rawAddSon(result, finalType)
addParamOrResult(c, arg, kind)
if gCmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
if c.config.cmd == cmdPretty: styleCheckDef(a.sons[j].info, arg)
var r: PType
if n.sons[0].kind != nkEmpty:
@@ -1085,7 +1112,7 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
n.sym.typ.flags.excl tfWildcard
proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
checkMinSonsLen(n, 1)
checkMinSonsLen(n, 1, c.config)
var length = sonsLen(n)
for i in countup(0, length - 2):
n.sons[i] = semStmt(c, n.sons[i])
@@ -1098,7 +1125,7 @@ proc semStmtListType(c: PContext, n: PNode, prev: PType): PType =
proc semBlockType(c: PContext, n: PNode, prev: PType): PType =
inc(c.p.nestedBlockCounter)
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
openScope(c)
if n.sons[0].kind notin {nkEmpty, nkSym}:
addDecl(c, newSymS(skLabel, n.sons[0], c))
@@ -1120,20 +1147,20 @@ proc semObjectTypeForInheritedGenericInst(c: PContext, n: PNode, t: PType) =
realBase = t.sons[0]
base = skipTypesOrNil(realBase, skipPtrs)
if base.isNil:
localError(n.info, errIllegalRecursionInTypeX, "object")
localError(c.config, n.info, errIllegalRecursionInTypeX % "object")
else:
let concreteBase = skipGenericInvocation(base)
if concreteBase.kind == tyObject and tfFinal notin concreteBase.flags:
addInheritedFields(c, check, pos, concreteBase)
else:
if concreteBase.kind != tyError:
localError(n.info, errInheritanceOnlyWithNonFinalObjects)
localError(c.config, n.info, errInheritanceOnlyWithNonFinalObjects)
var newf = newNodeI(nkRecList, n.info)
semRecordNodeAux(c, t.n, check, pos, newf, t)
proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if s.typ == nil:
localError(n.info, "cannot instantiate the '$1' $2" %
localError(c.config, n.info, "cannot instantiate the '$1' $2" %
[s.name.s, ($s.kind).substr(2).toLowerAscii])
return newOrPrevType(tyError, prev, c)
@@ -1146,7 +1173,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
template addToResult(typ) =
if typ.isNil:
internalAssert false
internalAssert c.config, false
rawAddSon(result, typ)
else: addSonSkipIntLit(result, typ)
@@ -1158,7 +1185,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
elif t.kind != tyGenericBody:
# we likely got code of the form TypeA[TypeB] where TypeA is
# not generic.
localError(n.info, errNoGenericParamsAllowedForX, s.name.s)
localError(c.config, n.info, errNoGenericParamsAllowedForX % s.name.s)
return newOrPrevType(tyError, prev, c)
else:
var m = newCandidate(c, t)
@@ -1169,7 +1196,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
let err = "cannot instantiate " & typeToString(t) & "\n" &
"got: <" & describeArgs(c, n) & ">\n" &
"but expected: <" & describeArgs(c, t.n, 0) & ">"
localError(n.info, errGenerated, err)
localError(c.config, n.info, errGenerated, err)
return newOrPrevType(tyError, prev, c)
var isConcrete = true
@@ -1187,7 +1214,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
if isConcrete:
if s.ast == nil and s.typ.kind != tyCompositeTypeClass:
# XXX: What kind of error is this? is it still relevant?
localError(n.info, errCannotInstantiateX, s.name.s)
localError(c.config, n.info, errCannotInstantiateX % s.name.s)
result = newOrPrevType(tyError, prev, c)
else:
result = instGenericContainer(c, n.info, result,
@@ -1197,7 +1224,7 @@ proc semGeneric(c: PContext, n: PNode, s: PSym, prev: PType): PType =
# generic/partial specialized parent
let tx = result.skipTypes(abstractPtrs, 50)
if tx.isNil:
localError(n.info, "invalid recursion in type '$1'" % typeToString(result[0]))
localError(c.config, n.info, "invalid recursion in type '$1'" % typeToString(result[0]))
return errorType(c)
if tx != result and tx.kind == tyObject and tx.sons[0] != nil:
semObjectTypeForInheritedGenericInst(c, n, tx)
@@ -1226,7 +1253,7 @@ proc semTypeExpr(c: PContext, n: PNode; prev: PType): PType =
let alias = maybeAliasType(c, result, prev)
if alias != nil: result = alias
else:
localError(n.info, errTypeExpected, n.renderTree)
localError(c.config, n.info, "expected type, but got: " & n.renderTree)
result = errorType(c)
proc freshType(res, prev: PType): PType {.inline.} =
@@ -1277,7 +1304,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
dummyName = param
dummyType = candidateTypeSlot
internalAssert dummyName.kind == nkIdent
internalAssert c.config, dummyName.kind == nkIdent
var dummyParam = newSym(if modifier == tyTypeDesc: skType else: skVar,
dummyName.ident, owner, param.info)
dummyParam.typ = dummyType
@@ -1289,7 +1316,7 @@ proc semTypeClass(c: PContext, n: PNode, prev: PType): PType =
proc semProcTypeWithScope(c: PContext, n: PNode,
prev: PType, kind: TSymKind): PType =
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
openScope(c)
result = semProcTypeNode(c, n.sons[0], nil, prev, kind, isType=true)
# start with 'ccClosure', but of course pragmas can overwrite this:
@@ -1299,7 +1326,7 @@ proc semProcTypeWithScope(c: PContext, n: PNode,
s.typ = result
if n.sons[1].kind != nkEmpty and n.sons[1].len > 0:
pragma(c, s, n.sons[1], procTypePragmas)
when useEffectSystem: setEffectsForProcType(result, n.sons[1])
when useEffectSystem: setEffectsForProcType(c.graph, result, n.sons[1])
closeScope(c)
proc maybeAliasType(c: PContext; typeExpr, prev: PType): PType =
@@ -1320,19 +1347,19 @@ proc symFromExpectedTypeNode(c: PContext, n: PNode): PSym =
if n.kind == nkType:
result = symFromType(n.typ, n.info)
else:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
result = errorSym(c, n)
proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = nil
inc c.inTypeContext
if gCmd == cmdIdeTools: suggestExpr(c, n)
if c.config.cmd == cmdIdeTools: suggestExpr(c, n)
case n.kind
of nkEmpty: discard
of nkTypeOfExpr:
# for ``type(countup(1,3))``, see ``tests/ttoseq``.
checkSonsLen(n, 1)
checkSonsLen(n, 1, c.config)
let typExpr = semExprWithType(c, n.sons[0], {efInTypeof})
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
@@ -1362,21 +1389,21 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = freshType(result, prev)
result.flags.excl(tfNotNil)
else:
localError(n.info, errGenerated, "invalid type")
localError(c.config, n.info, errGenerated, "invalid type")
elif n[0].kind notin nkIdentKinds:
result = semTypeExpr(c, n, prev)
else:
let op = considerQuotedIdent(n.sons[0])
let op = considerQuotedIdent(c.config, n.sons[0])
if op.id in {ord(wAnd), ord(wOr)} or op.s == "|":
checkSonsLen(n, 3)
checkSonsLen(n, 3, c.config)
var
t1 = semTypeNode(c, n.sons[1], nil)
t2 = semTypeNode(c, n.sons[2], nil)
if t1 == nil:
localError(n.sons[1].info, errTypeExpected)
localError(c.config, n.sons[1].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif t2 == nil:
localError(n.sons[2].info, errTypeExpected)
localError(c.config, n.sons[2].info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
else:
result = if op.id == ord(wAnd): makeAndType(c, t1, t2)
@@ -1390,20 +1417,20 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = freshType(result, prev)
result.flags.incl(tfNotNil)
if notnil notin c.features:
localError(n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
localError(c.config, n.info, "enable the 'not nil' annotation with {.experimental: \"notnil\".}")
else:
localError(n.info, errGenerated, "invalid type")
localError(c.config, n.info, errGenerated, "invalid type")
of 2:
let negated = semTypeNode(c, n.sons[1], prev)
result = makeNotType(c, negated)
else:
localError(n.info, errGenerated, "invalid type")
localError(c.config, n.info, errGenerated, "invalid type")
elif op.id == ord(wPtr):
result = semAnyRef(c, n, tyPtr, prev)
elif op.id == ord(wRef):
result = semAnyRef(c, n, tyRef, prev)
elif op.id == ord(wType):
checkSonsLen(n, 2)
checkSonsLen(n, 2, c.config)
let typExpr = semExprWithType(c, n.sons[1], {efInTypeof})
fixupTypeOf(c, prev, typExpr)
result = typExpr.typ
@@ -1417,7 +1444,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
if whenResult.kind == nkStmtList: whenResult.kind = nkStmtListType
result = semTypeNode(c, whenResult, prev)
of nkBracketExpr:
checkMinSonsLen(n, 2)
checkMinSonsLen(n, 2, c.config)
var head = n.sons[0]
var s = if head.kind notin nkCallKinds: semTypeIdent(c, head)
else: symFromExpectedTypeNode(c, semExpr(c, head))
@@ -1444,7 +1471,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
result = newOrPrevType(tyVar, prev, c)
var base = semTypeNode(c, n.sons[1], nil)
if base.kind in {tyVar, tyLent}:
localError(n.info, errVarVarTypeNotAllowed)
localError(c.config, n.info, "type 'var var' is not allowed")
base = base.sons[0]
addSonSkipIntLit(result, base)
of mRef: result = semAnyRef(c, n, tyRef, prev)
@@ -1454,13 +1481,13 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkDotExpr:
let typeExpr = semExpr(c, n)
if typeExpr.typ.isNil:
localError(n.info, "object constructor needs an object type;" &
localError(c.config, n.info, "object constructor needs an object type;" &
" for named arguments use '=' instead of ':'")
result = errorType(c)
elif typeExpr.typ.kind == tyFromExpr:
result = typeExpr.typ
elif typeExpr.typ.kind != tyTypeDesc:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
result = errorType(c)
else:
result = typeExpr.typ.base
@@ -1476,10 +1503,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkIdent, nkAccQuoted:
var s = semTypeIdent(c, n)
if s.typ == nil:
if s.kind != skError: localError(n.info, errTypeExpected)
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
elif s.kind == skParam and s.typ.kind == tyTypeDesc:
internalAssert s.typ.base.kind != tyNone and prev == nil
internalAssert c.config, s.typ.base.kind != tyNone and prev == nil
result = s.typ.base
elif prev == nil:
result = s.typ
@@ -1506,10 +1533,10 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
else:
assignType(prev, t)
result = prev
markUsed(n.info, n.sym, c.graph.usageSym)
markUsed(c.config, n.info, n.sym, c.graph.usageSym)
styleCheckUse(n.info, n.sym)
else:
if s.kind != skError: localError(n.info, errTypeExpected)
if s.kind != skError: localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
of nkObjectTy: result = semObjectNode(c, n, prev)
of nkTupleTy: result = semTuple(c, n, prev)
@@ -1547,7 +1574,7 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
of nkStmtListType: result = semStmtListType(c, n, prev)
of nkBlockType: result = semBlockType(c, n, prev)
else:
localError(n.info, errTypeExpected)
localError(c.config, n.info, errTypeExpected)
result = newOrPrevType(tyError, prev, c)
n.typ = result
dec c.inTypeContext
@@ -1600,10 +1627,10 @@ proc processMagicType(c: PContext, m: PSym) =
of mChar: setMagicType(m, tyChar, 1)
of mString:
setMagicType(m, tyString, ptrSize)
rawAddSon(m.typ, getSysType(tyChar))
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
of mCstring:
setMagicType(m, tyCString, ptrSize)
rawAddSon(m.typ, getSysType(tyChar))
rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar))
of mPointer: setMagicType(m, tyPointer, ptrSize)
of mEmptySet:
setMagicType(m, tySet, 1)
@@ -1649,8 +1676,8 @@ proc processMagicType(c: PContext, m: PSym) =
case m.name.s
of "lent": setMagicType(m, tyLent, ptrSize)
of "sink": setMagicType(m, tySink, 0)
else: localError(m.info, errTypeExpected)
else: localError(m.info, errTypeExpected)
else: localError(c.config, m.info, errTypeExpected)
else: localError(c.config, m.info, errTypeExpected)
proc semGenericConstraints(c: PContext, x: PType): PType =
result = newTypeWithSons(c, tyGenericParam, @[x])
@@ -1658,11 +1685,11 @@ proc semGenericConstraints(c: PContext, x: PType): PType =
proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
result = copyNode(n)
if n.kind != nkGenericParams:
illFormedAst(n)
illFormedAst(n, c.config)
return
for i in countup(0, sonsLen(n)-1):
var a = n.sons[i]
if a.kind != nkIdentDefs: illFormedAst(n)
if a.kind != nkIdentDefs: illFormedAst(n, c.config)
let L = a.len
var def = a[^1]
let constraint = a[^2]
@@ -1708,7 +1735,7 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
if paramName.safeLen == 2:
if not nimEnableCovariance or paramName[0].ident.s == "in":
if father == nil or sfImportc notin father.sym.flags:
localError(paramName.info, errInOutFlagNotExtern, paramName[0].ident.s)
localError(c.config, paramName.info, errInOutFlagNotExtern % $paramName[0])
covarianceFlag = if paramName[0].ident.s == "in": tfContravariant
else: tfCovariant
if father != nil: father.flags.incl tfCovariant

View File

@@ -14,21 +14,21 @@ import ast, astalgo, msgs, types, magicsys, semdata, renderer, options
const
tfInstClearedFlags = {tfHasMeta, tfUnresolved}
proc checkPartialConstructedType(info: TLineInfo, t: PType) =
proc checkPartialConstructedType(conf: ConfigRef; info: TLineInfo, t: PType) =
if tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic")
localError(conf, info, "invalid pragma: acyclic")
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
localError(info, errVarVarTypeNotAllowed)
localError(conf, info, "type 'var var' is not allowed")
proc checkConstructedType*(info: TLineInfo, typ: PType) =
proc checkConstructedType*(conf: ConfigRef; info: TLineInfo, typ: PType) =
var t = typ.skipTypes({tyDistinct})
if t.kind in tyTypeClasses: discard
elif tfAcyclic in t.flags and skipTypes(t, abstractInst).kind != tyObject:
localError(info, errInvalidPragmaX, "acyclic")
localError(conf, info, "invalid pragma: acyclic")
elif t.kind in {tyVar, tyLent} and t.sons[0].kind in {tyVar, tyLent}:
localError(info, errVarVarTypeNotAllowed)
localError(conf, info, "type 'var var' is not allowed")
elif computeSize(t) == szIllegalRecursion:
localError(info, errIllegalRecursionInTypeX, typeToString(t))
localError(conf, info, "illegal recursion in type '" & typeToString(t) & "'")
when false:
if t.kind == tyObject and t.sons[0] != nil:
if t.sons[0].kind != tyObject or tfFinal in t.sons[0].flags:
@@ -36,9 +36,8 @@ proc checkConstructedType*(info: TLineInfo, typ: PType) =
proc searchInstTypes*(key: PType): PType =
let genericTyp = key.sons[0]
internalAssert genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and
genericTyp.sym != nil
if not (genericTyp.kind == tyGenericBody and
key.sons[0] == genericTyp and genericTyp.sym != nil): return
if genericTyp.sym.typeInstCache == nil:
return
@@ -195,19 +194,19 @@ proc replaceTypeVarsN(cl: var TReplTypeVars, n: PNode; start=0): PNode =
var branch: PNode = nil # the branch to take
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it == nil: illFormedAst(n)
if it == nil: illFormedAst(n, cl.c.config)
case it.kind
of nkElifBranch:
checkSonsLen(it, 2)
checkSonsLen(it, 2, cl.c.config)
var cond = prepareNode(cl, it.sons[0])
var e = cl.c.semConstExpr(cl.c, cond)
if e.kind != nkIntLit:
internalError(e.info, "ReplaceTypeVarsN: when condition not a bool")
internalError(cl.c.config, e.info, "ReplaceTypeVarsN: when condition not a bool")
if e.intVal != 0 and branch == nil: branch = it.sons[1]
of nkElse:
checkSonsLen(it, 1)
checkSonsLen(it, 1, cl.c.config)
if branch == nil: branch = it.sons[0]
else: illFormedAst(n)
else: illFormedAst(n, cl.c.config)
if branch != nil:
result = replaceTypeVarsN(cl, branch)
else:
@@ -244,14 +243,14 @@ proc lookupTypeVar(cl: var TReplTypeVars, t: PType): PType =
result = cl.typeMap.lookup(t)
if result == nil:
if cl.allowMetaTypes or tfRetType in t.flags: return
localError(t.sym.info, errCannotInstantiateX, typeToString(t))
localError(cl.c.config, t.sym.info, "cannot instantiate: '" & typeToString(t) & "'")
result = errorType(cl.c)
# In order to prevent endless recursions, we must remember
# this bad lookup and replace it with errorType everywhere.
# These code paths are only active in "nim check"
cl.typeMap.put(t, result)
elif result.kind == tyGenericParam and not cl.allowMetaTypes:
internalError(cl.info, "substitution with generic parameter")
internalError(cl.c.config, cl.info, "substitution with generic parameter")
proc instCopyType*(cl: var TReplTypeVars, t: PType): PType =
# XXX: relying on allowMetaTypes is a kludge
@@ -278,7 +277,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# is difficult to handle:
const eqFlags = eqTypeFlags + {tfGcSafe}
var body = t.sons[0]
if body.kind != tyGenericBody: internalError(cl.info, "no generic body")
if body.kind != tyGenericBody: internalError(cl.c.config, cl.info, "no generic body")
var header: PType = t
# search for some instantiation here:
if cl.allowMetaTypes:
@@ -351,7 +350,7 @@ proc handleGenericInvocation(cl: var TReplTypeVars, t: PType): PType =
# handleGenericInvocation will handle the alias-to-alias-to-alias case
if newbody.isGenericAlias: newbody = newbody.skipGenericAlias
rawAddSon(result, newbody)
checkPartialConstructedType(cl.info, newbody)
checkPartialConstructedType(cl.c.config, cl.info, newbody)
let dc = newbody.deepCopy
if cl.allowMetaTypes == false:
if dc != nil and sfFromGeneric notin newbody.deepCopy.flags:
@@ -417,7 +416,7 @@ proc propagateFieldFlags(t: PType, n: PNode) =
# The type must be fully instantiated!
if n.isNil:
return
internalAssert n.kind != nkRecWhen
#internalAssert n.kind != nkRecWhen
case n.kind
of nkSym:
propagateToOwner(t, n.sym.typ)
@@ -454,7 +453,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
result.kind = tyUserTypeClassInst
of tyGenericBody:
localError(cl.info, errCannotInstantiateX, typeToString(t))
localError(cl.c.config, cl.info, "cannot instantiate: '" & typeToString(t) & "'")
result = errorType(cl.c)
#result = replaceTypeVarsT(cl, lastSon(t))
@@ -533,7 +532,7 @@ proc replaceTypeVarsTAux(cl: var TReplTypeVars, t: PType): PType =
case result.kind
of tyArray:
let idx = result.sons[0]
internalAssert idx.kind != tyStatic
internalAssert cl.c.config, idx.kind != tyStatic
of tyObject, tyTuple:
propagateFieldFlags(result, result.n)

View File

@@ -11,7 +11,7 @@
import
times, commands, options, msgs, nimconf,
extccomp, strutils, os, platform, parseopt, idents
extccomp, strutils, os, platform, parseopt, idents, configuration
when useCaas:
import net
@@ -42,17 +42,17 @@ proc processCmdLine*(pass: TCmdLinePass, cmd: string; config: ConfigRef) =
of cmdArgument:
if processArgument(pass, p, argsCount, config): break
if pass == passCmd2:
if optRun notin gGlobalOptions and config.arguments.len > 0 and options.command.normalize != "run":
rawMessage(errArgsNeedRunOption, [])
if optRun notin config.globalOptions and config.arguments.len > 0 and config.command.normalize != "run":
rawMessage(config, errGenerated, errArgsNeedRunOption)
proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; config: ConfigRef) =
template execute(cmd) =
curCaasCmd = cmd
processCmdLine(passCmd2, cmd, config)
action(cache)
gErrorCounter = 0
config.errorCounter = 0
let typ = getConfigVar("server.type")
let typ = getConfigVar(config, "server.type")
case typ
of "stdin":
while true:
@@ -65,9 +65,9 @@ proc serve*(cache: IdentCache; action: proc (cache: IdentCache){.nimcall.}; conf
of "tcp", "":
when useCaas:
var server = newSocket()
let p = getConfigVar("server.port")
let p = getConfigVar(config, "server.port")
let port = if p.len > 0: parseInt(p).Port else: 6000.Port
server.bindAddr(port, getConfigVar("server.address"))
server.bindAddr(port, getConfigVar(config, "server.address"))
var inp = "".TaintedString
server.listen()
var stdoutSocket = newSocket()

View File

@@ -99,7 +99,7 @@ type
const
isNilConversion = isConvertible # maybe 'isIntConv' fits better?
proc markUsed*(info: TLineInfo, s: PSym; usageSym: var PSym)
proc markUsed*(conf: ConfigRef; info: TLineInfo, s: PSym; usageSym: var PSym)
template hasFauxMatch*(c: TCandidate): bool = c.fauxMatch != tyNone
@@ -152,13 +152,13 @@ proc initCandidate*(ctx: PContext, c: var TCandidate, callee: PSym,
for i in 1..min(sonsLen(typeParams), sonsLen(binding)-1):
var formalTypeParam = typeParams.sons[i-1].typ
var bound = binding[i].typ
internalAssert bound != nil
if formalTypeParam.kind == tyTypeDesc:
if bound.kind != tyTypeDesc:
bound = makeTypeDesc(ctx, bound)
else:
bound = bound.skipTypes({tyTypeDesc})
put(c, formalTypeParam, bound)
if bound != nil:
if formalTypeParam.kind == tyTypeDesc:
if bound.kind != tyTypeDesc:
bound = makeTypeDesc(ctx, bound)
else:
bound = bound.skipTypes({tyTypeDesc})
put(c, formalTypeParam, bound)
proc newCandidate*(ctx: PContext, callee: PSym,
binding: PNode, calleeScope = -1): TCandidate =
@@ -362,8 +362,8 @@ proc concreteType(c: TCandidate, t: PType): PType =
# proc sort[T](cmp: proc(a, b: T): int = cmp)
if result.kind != tyGenericParam: break
of tyGenericInvocation:
internalError("cannot resolve type: " & typeToString(t))
result = t
doAssert(false, "cannot resolve type: " & typeToString(t))
else:
result = t # Note: empty is valid here
@@ -519,8 +519,8 @@ proc recordRel(c: var TCandidate, f, a: PType): TTypeRelation =
if f.n != nil and a.n != nil:
for i in countup(0, sonsLen(f.n) - 1):
# check field names:
if f.n.sons[i].kind != nkSym: internalError(f.n.info, "recordRel")
elif a.n.sons[i].kind != nkSym: internalError(a.n.info, "recordRel")
if f.n.sons[i].kind != nkSym: return isNone
elif a.n.sons[i].kind != nkSym: return isNone
else:
var x = f.n.sons[i].sym
var y = a.n.sons[i].sym
@@ -612,7 +612,7 @@ proc procTypeRel(c: var TCandidate, f, a: PType): TTypeRelation =
if tfNoSideEffect in f.flags and tfNoSideEffect notin a.flags:
return isNone
elif tfThread in f.flags and a.flags * {tfThread, tfNoSideEffect} == {} and
optThreadAnalysis in gGlobalOptions:
optThreadAnalysis in c.c.config.globalOptions:
# noSideEffect implies ``tfThread``!
return isNone
elif f.flags * {tfIterator} != a.flags * {tfIterator}:
@@ -661,7 +661,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
matchedConceptContext.prev = prevMatchedConcept
matchedConceptContext.depth = prevMatchedConcept.depth + 1
if prevMatchedConcept.depth > 4:
localError(body.info, $body & " too nested for type matching")
localError(m.c.graph.config, body.info, $body & " too nested for type matching")
return nil
openScope(c)
@@ -686,7 +686,7 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
if alreadyBound != nil: typ = alreadyBound
template paramSym(kind): untyped =
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info)
newSym(kind, typeParamName, typeClass.sym, typeClass.sym.info, {})
block addTypeParam:
for prev in typeParams:
@@ -760,19 +760,20 @@ proc matchUserTypeClass*(m: var TCandidate; ff, a: PType): PType =
result.n = checkedBody
proc shouldSkipDistinct(rules: PNode, callIdent: PIdent): bool =
proc shouldSkipDistinct(m: TCandidate; rules: PNode, callIdent: PIdent): bool =
# XXX This is bad as 'considerQuotedIdent' can produce an error!
if rules.kind == nkWith:
for r in rules:
if r.considerQuotedIdent == callIdent: return true
if considerQuotedIdent(m.c.graph.config, r) == callIdent: return true
return false
else:
for r in rules:
if r.considerQuotedIdent == callIdent: return false
if considerQuotedIdent(m.c.graph.config, r) == callIdent: return false
return true
proc maybeSkipDistinct(t: PType, callee: PSym): PType =
proc maybeSkipDistinct(m: TCandidate; t: PType, callee: PSym): PType =
if t != nil and t.kind == tyDistinct and t.n != nil and
shouldSkipDistinct(t.n, callee.name):
shouldSkipDistinct(m, t.n, callee.name):
result = t.base
else:
result = t
@@ -868,11 +869,11 @@ proc inferStaticParam*(c: var TCandidate, lhs: PNode, rhs: BiggestInt): bool =
return false
proc failureToInferStaticParam(n: PNode) =
proc failureToInferStaticParam(conf: ConfigRef; n: PNode) =
let staticParam = n.findUnresolvedStatic
let name = if staticParam != nil: staticParam.sym.name.s
else: "unknown"
localError(n.info, errCannotInferStaticParam, name)
localError(conf, n.info, "cannot infer the value of the static param '" & name & "'")
proc inferStaticsInRange(c: var TCandidate,
inferred, concrete: PType): TTypeRelation =
@@ -886,7 +887,7 @@ proc inferStaticsInRange(c: var TCandidate,
if inferStaticParam(c, exp, rhs):
return isGeneric
else:
failureToInferStaticParam exp
failureToInferStaticParam(c.c.graph.config, exp)
if lowerBound.kind == nkIntLit:
if upperBound.kind == nkIntLit:
@@ -999,7 +1000,8 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
of tyStatic:
candidate = computedType
else:
localError(f.n.info, errTypeExpected)
# XXX What is this non-sense? Error reporting in signature matching?
discard "localError(f.n.info, errTypeExpected)"
else:
discard
@@ -1013,7 +1015,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
template doBind: bool = trDontBind notin flags
# var and static arguments match regular modifier-free types
var a = aOrig.skipTypes({tyStatic, tyVar, tyLent}).maybeSkipDistinct(c.calleeSym)
var a = maybeSkipDistinct(c, aOrig.skipTypes({tyStatic, tyVar, tyLent}), c.calleeSym)
# XXX: Theoretically, maybeSkipDistinct could be called before we even
# start the param matching process. This could be done in `prepareOperand`
# for example, but unfortunately `prepareOperand` is not called in certain
@@ -1442,7 +1444,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
(sonsLen(x) - 1 == sonsLen(f)):
for i in countup(1, sonsLen(f) - 1):
if x.sons[i].kind == tyGenericParam:
internalError("wrong instantiated type!")
internalError(c.c.graph.config, "wrong instantiated type!")
elif typeRel(c, f.sons[i], x.sons[i]) <= isSubtype:
# Workaround for regression #4589
if f.sons[i].kind != tyTypeDesc: return
@@ -1474,7 +1476,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
if x == nil:
discard "maybe fine (for eg. a==tyNil)"
elif x.kind in {tyGenericInvocation, tyGenericParam}:
internalError("wrong instantiated type!")
internalError(c.c.graph.config, "wrong instantiated type!")
else:
put(c, f.sons[i], x)
@@ -1597,7 +1599,7 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
if f.sonsLen == 0:
result = isGeneric
else:
internalAssert a.sons != nil and a.sons.len > 0
internalAssert c.c.graph.config, a.sons != nil and a.sons.len > 0
c.typedescMatched = true
var aa = a
while aa.kind in {tyTypeDesc, tyGenericParam} and aa.len > 0:
@@ -1739,13 +1741,13 @@ proc typeRelImpl(c: var TCandidate, f, aOrig: PType,
if not exprStructuralEquivalent(aOrig.n, reevaluated.typ.n):
result = isNone
else:
localError(f.n.info, errTypeExpected)
localError(c.c.graph.config, f.n.info, "type expected")
result = isNone
of tyNone:
if a.kind == tyNone: result = isEqual
else:
internalError " unknown type kind " & $f.kind
internalError c.c.graph.config, " unknown type kind " & $f.kind
proc cmpTypes*(c: PContext, f, a: PType): TTypeRelation =
var m: TCandidate
@@ -1758,7 +1760,7 @@ proc getInstantiatedType(c: PContext, arg: PNode, m: TCandidate,
if result == nil:
result = generateTypeInstance(c, m.bindings, arg, f)
if result == nil:
internalError(arg.info, "getInstantiatedType")
internalError(c.graph.config, arg.info, "getInstantiatedType")
result = errorType(c)
proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
@@ -1771,7 +1773,7 @@ proc implicitConv(kind: TNodeKind, f: PType, arg: PNode, m: TCandidate,
result.typ = errorType(c)
else:
result.typ = f
if result.typ == nil: internalError(arg.info, "implicitConv")
if result.typ == nil: internalError(c.graph.config, arg.info, "implicitConv")
addSon(result, ast.emptyNode)
addSon(result, arg)
@@ -1792,7 +1794,7 @@ proc userConvMatch(c: PContext, m: var TCandidate, f, a: PType,
dest = generateTypeInstance(c, m.bindings, arg, dest)
let fdest = typeRel(m, f, dest)
if fdest in {isEqual, isGeneric}:
markUsed(arg.info, c.converters[i], c.graph.usageSym)
markUsed(c.config, arg.info, c.converters[i], c.graph.usageSym)
var s = newSymNode(c.converters[i])
s.typ = c.converters[i].typ
s.info = arg.info
@@ -2069,7 +2071,7 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
result = nil
elif y.state == csMatch and cmpCandidates(x, y) == 0:
if x.state != csMatch:
internalError(arg.info, "x.state is not csMatch")
internalError(m.c.graph.config, arg.info, "x.state is not csMatch")
# ambiguous: more than one symbol fits!
# See tsymchoice_for_expr as an example. 'f.kind == tyExpr' should match
# anyway:
@@ -2077,12 +2079,11 @@ proc paramTypesMatch*(m: var TCandidate, f, a: PType,
else: result = nil
else:
# only one valid interpretation found:
markUsed(arg.info, arg.sons[best].sym, m.c.graph.usageSym)
markUsed(m.c.config, arg.info, arg.sons[best].sym, m.c.graph.usageSym)
styleCheckUse(arg.info, arg.sons[best].sym)
result = paramTypesMatchAux(m, f, arg.sons[best].typ, arg.sons[best],
argOrig)
proc setSon(father: PNode, at: int, son: PNode) =
let oldLen = father.len
if oldLen <= at:
@@ -2118,10 +2119,10 @@ proc prepareOperand(c: PContext; a: PNode): PNode =
result = a
considerGenSyms(c, result)
proc prepareNamedParam(a: PNode) =
proc prepareNamedParam(a: PNode; conf: ConfigRef) =
if a.sons[0].kind != nkIdent:
var info = a.sons[0].info
a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0]), info)
a.sons[0] = newIdentNode(considerQuotedIdent(conf, a.sons[0]), info)
proc arrayConstr(c: PContext, n: PNode): PType =
result = newTypeS(tyArray, c)
@@ -2186,9 +2187,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
elif n.sons[a].kind == nkExprEqExpr:
# named param
# check if m.callee has such a param:
prepareNamedParam(n.sons[a])
prepareNamedParam(n.sons[a], c.config)
if n.sons[a].sons[0].kind != nkIdent:
localError(n.sons[a].info, errNamedParamHasToBeIdent)
localError(c.config, n.sons[a].info, "named parameter has to be an identifier")
m.state = csNoMatch
return
formal = getSymFromList(m.callee.n, n.sons[a].sons[0].ident, 1)
@@ -2231,8 +2232,9 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
# we have no formal here to snoop at:
n.sons[a] = prepareOperand(c, n.sons[a])
if skipTypes(n.sons[a].typ, abstractVar-{tyTypeDesc}).kind==tyString:
addSon(m.call, implicitConv(nkHiddenStdConv, getSysType(tyCString),
copyTree(n.sons[a]), m, c))
addSon(m.call, implicitConv(nkHiddenStdConv,
getSysType(c.graph, n.sons[a].info, tyCString),
copyTree(n.sons[a]), m, c))
else:
addSon(m.call, copyTree(n.sons[a]))
elif formal != nil and formal.typ.kind == tyVarargs:
@@ -2255,7 +2257,7 @@ proc matchesAux(c: PContext, n, nOrig: PNode,
return
else:
if m.callee.n.sons[f].kind != nkSym:
internalError(n.sons[a].info, "matches")
internalError(c.config, n.sons[a].info, "matches")
return
formal = m.callee.n.sons[f].sym
if containsOrIncl(marker, formal.position) and container.isNil:
@@ -2363,7 +2365,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
var m: TCandidate
initCandidate(c, m, dc.typ)
if col >= dc.typ.len:
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
return nil
var f = dc.typ.sons[col]
@@ -2372,7 +2374,7 @@ proc instTypeBoundOp*(c: PContext; dc: PSym; t: PType; info: TLineInfo;
else:
if f.kind == tyVar: f = f.lastSon
if typeRel(m, f, t) == isNone:
localError(info, errGenerated, "cannot instantiate '" & dc.name.s & "'")
localError(c.config, info, "cannot instantiate: '" & dc.name.s & "'")
else:
result = c.semGenerateInstance(c, dc, m.bindings, info)
if op == attachedDeepCopy:

View File

@@ -32,7 +32,7 @@
# included from sigmatch.nim
import algorithm, prefixmatches
import algorithm, prefixmatches, configuration
from wordrecg import wDeprecated
when defined(nimsuggest):
@@ -106,7 +106,7 @@ proc cmpSuggestions(a, b: Suggest): int =
# independent of hashing order:
result = cmp(a.name.s, b.name.s)
proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
proc symToSuggest(conf: ConfigRef; s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
quality: range[0..100]; prefix: PrefixMatch;
inTypeContext: bool; scope: int): Suggest =
new(result)
@@ -125,7 +125,7 @@ proc symToSuggest(s: PSym, isLocal: bool, section: IdeCmd, info: TLineInfo;
if u.fileIndex == info.fileIndex: inc c
result.localUsages = c
result.symkind = s.kind
if optIdeTerse notin gGlobalOptions:
if optIdeTerse notin conf.globalOptions:
result.qualifiedPath = @[]
if not isLocal and s.kind != skModule:
let ow = s.owner
@@ -192,8 +192,8 @@ proc suggestResult(s: Suggest) =
else:
suggestWriteln($s)
proc produceOutput(a: var Suggestions) =
if gIdeCmd in {ideSug, ideCon}:
proc produceOutput(a: var Suggestions; conf: ConfigRef) =
if conf.ideCmd in {ideSug, ideCon}:
a.sort cmpSuggestions
when defined(debug):
# debug code
@@ -237,7 +237,7 @@ proc fieldVisible*(c: PContext, f: PSym): bool {.inline.} =
proc suggestField(c: PContext, s: PSym; f: PNode; info: TLineInfo; outputs: var Suggestions) =
var pm: PrefixMatch
if filterSym(s, f, pm) and fieldVisible(c, s):
outputs.add(symToSuggest(s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0))
outputs.add(symToSuggest(c.config, s, isLocal=true, ideSug, info, 100, pm, c.inTypeContext > 0, 0))
proc getQuality(s: PSym): range[0..100] =
if s.typ != nil and s.typ.len > 1:
@@ -256,7 +256,7 @@ template wholeSymTab(cond, section: untyped) =
let it {.inject.} = item
var pm {.inject.}: PrefixMatch
if cond:
outputs.add(symToSuggest(it, isLocal = isLocal, section, info, getQuality(it),
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, section, info, getQuality(it),
pm, c.inTypeContext > 0, scopeN))
proc suggestSymList(c: PContext, list, f: PNode; info: TLineInfo, outputs: var Suggestions) =
@@ -330,7 +330,7 @@ proc suggestEverything(c: PContext, n, f: PNode, outputs: var Suggestions) =
for it in items(scope.symbols):
var pm: PrefixMatch
if filterSym(it, f, pm):
outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, n.info, 0, pm,
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, n.info, 0, pm,
c.inTypeContext > 0, scopeN))
#if scope == c.topLevelScope and f.isNil: break
@@ -342,18 +342,18 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
when defined(nimsuggest):
if n.kind == nkSym and n.sym.kind == skError and suggestVersion == 0:
# consider 'foo.|' where 'foo' is some not imported module.
let fullPath = findModule(n.sym.name.s, n.info.toFullPath)
let fullPath = findModule(c.config, n.sym.name.s, n.info.toFullPath)
if fullPath.len == 0:
# error: no known module name:
typ = nil
else:
let m = gImportModule(c.graph, c.module, fullpath.fileInfoIdx, c.cache)
let m = gImportModule(c.graph, c.module, fileInfoIdx(c.config, fullpath), c.cache)
if m == nil: typ = nil
else:
for it in items(n.sym.tab):
if filterSym(it, field, pm):
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100))
outputs.add(symToSuggest(m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None,
outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -100))
outputs.add(symToSuggest(c.config, m, isLocal=false, ideMod, n.info, 100, PrefixMatch.None,
c.inTypeContext > 0, -99))
if typ == nil:
@@ -363,11 +363,11 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
# all symbols accessible, because we are in the current module:
for it in items(c.topLevelScope.symbols):
if filterSym(it, field, pm):
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
else:
for it in items(n.sym.tab):
if filterSym(it, field, pm):
outputs.add(symToSuggest(it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
outputs.add(symToSuggest(c.config, it, isLocal=false, ideSug, n.info, 100, pm, c.inTypeContext > 0, -99))
else:
# fallback:
suggestEverything(c, n, field, outputs)
@@ -426,29 +426,29 @@ when defined(nimsuggest):
s.allUsages.add(info)
var
lastLineInfo*: TLineInfo
lastLineInfo*: TLineInfo # XXX global here
proc findUsages(info: TLineInfo; s: PSym; usageSym: var PSym) =
proc findUsages(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
if suggestVersion == 1:
if usageSym == nil and isTracked(info, s.name.s.len):
usageSym = s
suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
elif s == usageSym:
if lastLineInfo != info:
suggestResult(symToSuggest(s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
suggestResult(symToSuggest(conf, s, isLocal=false, ideUse, info, 100, PrefixMatch.None, false, 0))
lastLineInfo = info
when defined(nimsuggest):
proc listUsages*(s: PSym) =
proc listUsages*(conf: ConfigRef; s: PSym) =
#echo "usages ", len(s.allUsages)
for info in s.allUsages:
let x = if info == s.info and info.col == s.info.col: ideDef else: ideUse
suggestResult(symToSuggest(s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
suggestResult(symToSuggest(conf, s, isLocal=false, x, info, 100, PrefixMatch.None, false, 0))
proc findDefinition(info: TLineInfo; s: PSym) =
proc findDefinition(conf: ConfigRef; info: TLineInfo; s: PSym) =
if s.isNil: return
if isTracked(info, s.name.s.len):
suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
suggestQuit()
proc ensureIdx[T](x: var T, y: int) =
@@ -457,7 +457,7 @@ proc ensureIdx[T](x: var T, y: int) =
proc ensureSeq[T](x: var seq[T]) =
if x == nil: newSeq(x, 0)
proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
proc suggestSym*(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.inline.} =
## misnamed: should be 'symDeclared'
when defined(nimsuggest):
if suggestVersion == 0:
@@ -466,44 +466,44 @@ proc suggestSym*(info: TLineInfo; s: PSym; usageSym: var PSym; isDecl=true) {.in
else:
s.addNoDup(info)
if gIdeCmd == ideUse:
findUsages(info, s, usageSym)
elif gIdeCmd == ideDef:
findDefinition(info, s)
elif gIdeCmd == ideDus and s != nil:
if conf.ideCmd == ideUse:
findUsages(conf, info, s, usageSym)
elif conf.ideCmd == ideDef:
findDefinition(conf, info, s)
elif conf.ideCmd == ideDus and s != nil:
if isTracked(info, s.name.s.len):
suggestResult(symToSuggest(s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
findUsages(info, s, usageSym)
elif gIdeCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex:
suggestResult(symToSuggest(s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
elif gIdeCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and
suggestResult(symToSuggest(conf, s, isLocal=false, ideDef, info, 100, PrefixMatch.None, false, 0))
findUsages(conf, info, s, usageSym)
elif conf.ideCmd == ideHighlight and info.fileIndex == gTrackPos.fileIndex:
suggestResult(symToSuggest(conf, s, isLocal=false, ideHighlight, info, 100, PrefixMatch.None, false, 0))
elif conf.ideCmd == ideOutline and info.fileIndex == gTrackPos.fileIndex and
isDecl:
suggestResult(symToSuggest(s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
suggestResult(symToSuggest(conf, s, isLocal=false, ideOutline, info, 100, PrefixMatch.None, false, 0))
proc warnAboutDeprecated(info: TLineInfo; s: PSym) =
proc warnAboutDeprecated(conf: ConfigRef; info: TLineInfo; s: PSym) =
if s.kind in routineKinds:
let n = s.ast[pragmasPos]
if n.kind != nkEmpty:
for it in n:
if whichPragma(it) == wDeprecated and it.safeLen == 2 and
it[1].kind in {nkStrLit..nkTripleStrLit}:
message(info, warnDeprecated, it[1].strVal & "; " & s.name.s)
message(conf, info, warnDeprecated, it[1].strVal & "; " & s.name.s)
return
message(info, warnDeprecated, s.name.s)
message(conf, info, warnDeprecated, s.name.s)
proc markUsed(info: TLineInfo; s: PSym; usageSym: var PSym) =
proc markUsed(conf: ConfigRef; info: TLineInfo; s: PSym; usageSym: var PSym) =
incl(s.flags, sfUsed)
if s.kind == skEnumField and s.owner != nil:
incl(s.owner.flags, sfUsed)
if {sfDeprecated, sfError} * s.flags != {}:
if sfDeprecated in s.flags: warnAboutDeprecated(info, s)
if sfError in s.flags: localError(info, errWrongSymbolX, s.name.s)
if sfDeprecated in s.flags: warnAboutDeprecated(conf, info, s)
if sfError in s.flags: localError(conf, info, "usage of '$1' is a user-defined error" % s.name.s)
when defined(nimsuggest):
suggestSym(info, s, usageSym, false)
suggestSym(conf, info, s, usageSym, false)
proc useSym*(sym: PSym; usageSym: var PSym): PNode =
proc useSym*(conf: ConfigRef; sym: PSym; usageSym: var PSym): PNode =
result = newSymNode(sym)
markUsed(result.info, sym, usageSym)
markUsed(conf, result.info, sym, usageSym)
proc safeSemExpr*(c: PContext, n: PNode): PNode =
# use only for idetools support!
@@ -534,9 +534,9 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) =
if c.compilesContextId > 0: return
inc(c.compilesContextId)
var outputs: Suggestions = @[]
if gIdeCmd == ideSug:
if c.config.ideCmd == ideSug:
sugExpr(c, n, outputs)
elif gIdeCmd == ideCon:
elif c.config.ideCmd == ideCon:
if n.kind in nkCallKinds:
var a = copyNode(n)
var x = safeSemExpr(c, n.sons[0])
@@ -550,8 +550,8 @@ proc suggestExprNoCheck*(c: PContext, n: PNode) =
suggestCall(c, a, n, outputs)
dec(c.compilesContextId)
if outputs.len > 0 and gIdeCmd in {ideSug, ideCon, ideDef}:
produceOutput(outputs)
if outputs.len > 0 and c.config.ideCmd in {ideSug, ideCon, ideDef}:
produceOutput(outputs, c.config)
suggestQuit()
proc suggestExpr*(c: PContext, n: PNode) =
@@ -570,11 +570,11 @@ proc suggestStmt*(c: PContext, n: PNode) =
proc suggestEnum*(c: PContext; n: PNode; t: PType) =
var outputs: Suggestions = @[]
suggestSymList(c, t.n, nil, n.info, outputs)
produceOutput(outputs)
produceOutput(outputs, c.config)
if outputs.len > 0: suggestQuit()
proc suggestSentinel*(c: PContext) =
if gIdeCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
if c.config.ideCmd != ideSug or c.module.position != gTrackPos.fileIndex.int32: return
if c.compilesContextId > 0: return
inc(c.compilesContextId)
var outputs: Suggestions = @[]
@@ -587,7 +587,7 @@ proc suggestSentinel*(c: PContext) =
for it in items(scope.symbols):
var pm: PrefixMatch
if filterSymNoOpr(it, nil, pm):
outputs.add(symToSuggest(it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN))
outputs.add(symToSuggest(c.config, it, isLocal = isLocal, ideSug, newLineInfo(gTrackPos.fileIndex, -1, -1), 0, PrefixMatch.None, false, scopeN))
dec(c.compilesContextId)
produceOutput(outputs)
produceOutput(outputs, c.config)

View File

@@ -11,7 +11,7 @@
import
strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
filters, filter_tmpl, renderer
filters, filter_tmpl, renderer, configuration
type
TFilterKind* = enum
@@ -30,12 +30,14 @@ type
skin*: TParserKind
parser*: TParser
template config(p: TParsers): ConfigRef = p.parser.lex.config
proc parseAll*(p: var TParsers): PNode =
case p.skin
of skinStandard, skinStrongSpaces:
result = parser.parseAll(p.parser)
of skinEndX:
internalError("parser to implement")
internalError(p.config, "parser to implement")
result = ast.emptyNode
proc parseTopLevelStmt*(p: var TParsers): PNode =
@@ -43,7 +45,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
of skinStandard, skinStrongSpaces:
result = parser.parseTopLevelStmt(p.parser)
of skinEndX:
internalError("parser to implement")
internalError(p.config, "parser to implement")
result = ast.emptyNode
proc utf8Bom(s: string): int =
@@ -86,42 +88,44 @@ proc getFilter(ident: PIdent): TFilterKind =
return i
result = filtNone
proc getParser(ident: PIdent): TParserKind =
proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind =
for i in countup(low(TParserKind), high(TParserKind)):
if cmpIgnoreStyle(ident.s, parserNames[i]) == 0:
return i
rawMessage(errInvalidDirectiveX, ident.s)
localError(conf, n.info, "unknown parser: " & ident.s)
proc getCallee(n: PNode): PIdent =
proc getCallee(conf: ConfigRef; n: PNode): PIdent =
if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
result = n.sons[0].ident
elif n.kind == nkIdent:
result = n.ident
else:
rawMessage(errXNotAllowedHere, renderTree(n))
localError(conf, n.info, "invalid filter: " & renderTree(n))
proc applyFilter(p: var TParsers, n: PNode, filename: string,
stdin: PLLStream): PLLStream =
var ident = getCallee(n)
var ident = getCallee(p.config, n)
var f = getFilter(ident)
case f
of filtNone:
p.skin = getParser(ident)
p.skin = getParser(p.config, n, ident)
result = stdin
of filtTemplate:
result = filterTmpl(stdin, filename, n)
result = filterTmpl(stdin, filename, n, p.config)
of filtStrip:
result = filterStrip(stdin, filename, n)
result = filterStrip(p.config, stdin, filename, n)
of filtReplace:
result = filterReplace(stdin, filename, n)
result = filterReplace(p.config, stdin, filename, n)
if f != filtNone:
if hintCodeBegin in gNotes:
rawMessage(hintCodeBegin, [])
msgWriteln(result.s)
rawMessage(hintCodeEnd, [])
assert p.config != nil
if hintCodeBegin in p.config.notes:
rawMessage(p.config, hintCodeBegin, [])
msgWriteln(p.config, result.s)
rawMessage(p.config, hintCodeEnd, [])
proc evalPipe(p: var TParsers, n: PNode, filename: string,
start: PLLStream): PLLStream =
assert p.config != nil
result = start
if n.kind == nkEmpty: return
if n.kind == nkInfix and n[0].kind == nkIdent and n[0].ident.s == "|":
@@ -137,10 +141,12 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
proc openParsers*(p: var TParsers, fileIdx: FileIndex, inputstream: PLLStream;
cache: IdentCache; config: ConfigRef) =
assert config != nil
var s: PLLStream
p.skin = skinStandard
let filename = fileIdx.toFullPathConsiderDirty
var pipe = parsePipe(filename, inputstream, cache, config)
p.config() = config
if pipe != nil: s = evalPipe(p, pipe, filename, inputstream)
else: s = inputstream
case p.skin
@@ -158,7 +164,7 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode
f: File
let filename = fileIdx.toFullPathConsiderDirty
if not open(f, filename):
rawMessage(errCannotOpenFile, filename)
rawMessage(config, errGenerated, "cannot open file: " & filename)
return
openParsers(p, fileIdx, llStreamOpen(f), cache, config)
result = parseAll(p)

View File

@@ -21,7 +21,8 @@
import
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals,
modulegraphs
type
PTransNode* = distinct PNode
@@ -44,6 +45,7 @@ type
nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
deferDetected, tooEarly, needsDestroyPass: bool
graph: ModuleGraph
PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
@@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) =
c.transCon = t
proc popTransCon(c: PTransf) =
if (c.transCon == nil): internalError("popTransCon")
if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
c.transCon = c.transCon.next
proc getCurrOwner(c: PTransf): PSym =
@@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
incl(r.flags, sfFromGeneric)
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly:
result = freshVarForClosureIter(r, owner)
result = freshVarForClosureIter(c.graph, r, owner)
else:
result = newSymNode(r)
@@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
if s.typ != nil and s.typ.callConv == ccClosure:
if s.kind == skIterator:
if c.tooEarly: return n
else: return liftIterSym(n, getCurrOwner(c))
else: return liftIterSym(c.graph, n, getCurrOwner(c))
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)
return makeClosure(c.graph, s, nil, n.info)
#elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
# echo n.info, " come heer for ", c.tooEarly
# if not c.tooEarly:
@@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
if sfBorrow in s.flags and s.kind in routineKinds:
# simply exchange the symbol:
b = s.getBody
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
b = newSymNode(b.sym, n.info)
else:
b = n
@@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode =
proc freshVar(c: PTransf; v: PSym): PNode =
let owner = getCurrOwner(c)
if owner.isIterator and not c.tooEarly:
result = freshVarForClosureIter(v, owner)
result = freshVarForClosureIter(c.graph, v, owner)
else:
var newVar = copySym(v)
incl(newVar.flags, sfFromGeneric)
@@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
result[i] = PTransNode(it)
elif it.kind == nkIdentDefs:
if it.sons[0].kind == nkSym:
internalAssert(it.len == 3)
internalAssert(c.graph.config, it.len == 3)
let x = freshVar(c, it.sons[0].sym)
idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
var defs = newTransNode(nkIdentDefs, it.info, 3)
if importantComments():
if importantComments(c.graph.config):
# keep documentation information:
PNode(defs).comment = it.comment
defs[0] = x.PTransNode
@@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
result[i] = transform(c, it)
else:
if it.kind != nkVarTuple:
internalError(it.info, "transformVarSection: not nkVarTuple")
internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
var L = sonsLen(it)
var defs = newTransNode(it.kind, it.info, L)
for j in countup(0, L-3):
@@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
if it.kind == nkCommentStmt:
result[i] = PTransNode(it)
else:
if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
if it.sons[0].kind != nkSym:
internalError(it.info, "transformConstSection")
internalError(c.graph.config, it.info, "transformConstSection")
result[i] = PTransNode(it)
@@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
# XXX: BUG: what if `n` is an expression with side-effects?
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
transform(c, newTupleAccess(n, i))))
transform(c, newTupleAccess(c.graph, n, i))))
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
case n.kind
@@ -356,7 +358,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
result = transformSons(c, n)
if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
var n = result.PNode
case n.sons[0].kind
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
@@ -382,21 +384,21 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
PNode(result).typ = n.typ
proc generateThunk(prc: PNode, dest: PType): PNode =
proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
## a closure.
# we cannot generate a proper thunk here for GC-safety reasons
# (see internal documentation):
if gCmd == cmdCompileToJS: return prc
if c.graph.config.cmd == cmdCompileToJS: return prc
result = newNodeIT(nkClosure, prc.info, dest)
var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
conv.add(emptyNode)
conv.add(prc)
if prc.kind == nkClosure:
internalError(prc.info, "closure to closure created")
internalError(c.graph.config, prc.info, "closure to closure created")
result.add(conv)
result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
proc transformConv(c: PTransf, n: PNode): PTransNode =
# numeric types need range checks:
@@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
of tyProc:
result = transformSons(c, n)
if dest.callConv == ccClosure and source.callConv == ccDefault:
result = generateThunk(result[1].PNode, dest).PTransNode
result = generateThunk(c, result[1].PNode, dest).PTransNode
else:
result = transformSons(c, n)
@@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
if n.kind == nkVarSection:
let x = n.sons[0].sons[0]
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
internalError(x.info, "bah " & x.sym.name.s & " " &
internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
else:
for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
@@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
proc transformFor(c: PTransf, n: PNode): PTransNode =
# generate access statements for the parameters (unless they are constant)
# put mapping from formal parameters to actual parameters
if n.kind != nkForStmt: internalError(n.info, "transformFor")
if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
var length = sonsLen(n)
var call = n.sons[length - 2]
@@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
if not c.tooEarly:
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
else:
result[1] = newNode(nkEmpty).PTransNode
discard c.breakSyms.pop
@@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
while (j < sonsLen(n)):
let b = transform(c, n.sons[j]).PNode
if not isConstExpr(b): break
a = evalOp(op.magic, n, a, b, nil)
a = evalOp(op.magic, n, a, b, nil, c.graph)
inc(j)
add(result, a.PTransNode)
if len(result) == 2: result = result[1]
@@ -708,18 +710,18 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
let t = lastSon(s.sons[0].sym.ast)
if t.kind != nkSym or sfDispatcher notin t.sym.flags:
methodDef(s.sons[0].sym, false)
result = methodCall(s).PTransNode
result = methodCall(s, c.graph.config).PTransNode
else:
result = s.PTransNode
proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
result = transformSons(c, n)
if n[0].isInfixAs() and (not isImportedException(n[0][1].typ)):
if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
let excTypeNode = n[0][1]
let actions = newTransNode(nkStmtListExpr, n[1], 2)
# Generating `let exc = (excType)(getCurrentException())`
# -> getCurrentException()
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode))
# -> (excType)
let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
convNode[0] = PTransNode(ast.emptyNode)
@@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
cnst.len != 0
proc commonOptimizations*(c: PSym, n: PNode): PNode =
proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
result = n
for i in 0 ..< n.safeLen:
result.sons[i] = commonOptimizations(c, n.sons[i])
result.sons[i] = commonOptimizations(g, c, n.sons[i])
var op = getMergeOp(n)
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
result = newNodeIT(nkCall, n.info, n.typ)
@@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
while j < sonsLen(args):
let b = args.sons[j]
if not isConstExpr(b): break
a = evalOp(op.magic, result, a, b, nil)
a = evalOp(op.magic, result, a, b, nil, g)
inc(j)
add(result, a)
if len(result) == 2: result = result[1]
else:
var cnst = getConstExpr(c, n)
var cnst = getConstExpr(c, n, g)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
result = cnst
@@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
let L = n.len-1
result[L] = transform(c, n.sons[L])
# XXX comment handling really sucks:
if importantComments():
if importantComments(c.graph.config):
PNode(result).comment = n.comment
of nkClosure:
# it can happen that for-loop-inlining produced a fresh
@@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
when false:
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
var cnst = getConstExpr(c.module, PNode(result))
var cnst = getConstExpr(c.module, PNode(result), c.graph)
# we inline constants if they are not complex constants:
if cnst != nil and not dontInlineConstant(n, cnst):
result = PTransNode(cnst) # do not miss an optimization
@@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
popTransCon(c)
incl(result.flags, nfTransf)
proc openTransf(module: PSym, filename: string): PTransf =
proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
new(result)
result.contSyms = @[]
result.breakSyms = @[]
result.module = module
result.graph = g
proc flattenStmts(n: PNode) =
var goOn = true
@@ -967,46 +970,46 @@ template liftDefer(c, root) =
if c.deferDetected:
liftDeferAux(root)
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
if nfTransf in n.flags or prc.kind in {skTemplate}:
result = n
else:
var c = openTransf(module, "")
result = liftLambdas(prc, n, c.tooEarly)
var c = openTransf(g, module, "")
result = liftLambdas(g, prc, n, c.tooEarly)
#result = n
result = processTransf(c, result, prc)
liftDefer(c, result)
#result = liftLambdas(prc, result)
when useEffectSystem: trackProc(prc, result)
result = liftLocalsIfRequested(prc, result)
when useEffectSystem: trackProc(g, prc, result)
result = liftLocalsIfRequested(prc, result, g.config)
if c.needsDestroyPass: #and newDestructors:
result = injectDestructorCalls(prc, result)
result = injectDestructorCalls(g, prc, result)
incl(result.flags, nfTransf)
#if prc.name.s == "testbody":
# echo renderTree(result)
proc transformStmt*(module: PSym, n: PNode): PNode =
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(module, "")
var c = openTransf(g, module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
#result = liftLambdasForTopLevel(module, result)
when useEffectSystem: trackTopLevelStmt(module, result)
when useEffectSystem: trackTopLevelStmt(g, module, result)
#if n.info ?? "temp.nim":
# echo renderTree(result, {renderIds})
if c.needsDestroyPass:
result = injectDestructorCalls(module, result)
result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf)
proc transformExpr*(module: PSym, n: PNode): PNode =
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
if nfTransf in n.flags:
result = n
else:
var c = openTransf(module, "")
var c = openTransf(g, module, "")
result = processTransf(c, n, module)
liftDefer(c, result)
if c.needsDestroyPass:
result = injectDestructorCalls(module, result)
result = injectDestructorCalls(g, module, result)
incl(result.flags, nfTransf)

View File

@@ -10,7 +10,7 @@
# this module contains routines for accessing and iterating over types
import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options
type
TPreferedDesc* = enum
@@ -92,8 +92,9 @@ proc getOrdValue*(n: PNode): BiggestInt =
of nkNilLit: result = 0
of nkHiddenStdConv: result = getOrdValue(n.sons[1])
else:
localError(n.info, errOrdinalTypeExpected)
result = 0
#localError(n.info, errOrdinalTypeExpected)
# XXX check usages of getOrdValue
result = high(BiggestInt)
proc isIntLit*(t: PType): bool {.inline.} =
result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
@@ -105,14 +106,14 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
result = sym.owner.name.s & '.' & sym.name.s & '('
var n = sym.typ.n
for i in countup(1, sonsLen(n) - 1):
var p = n.sons[i]
let p = n.sons[i]
if p.kind == nkSym:
add(result, p.sym.name.s)
add(result, ": ")
add(result, typeToString(p.sym.typ, prefer))
if i != sonsLen(n)-1: add(result, ", ")
else:
internalError("getProcHeader")
result.add renderTree(p)
add(result, ')')
if n.sons[0].typ != nil:
result.add(": " & typeToString(n.sons[0].typ, prefer))
@@ -195,10 +196,10 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
of nkOfBranch, nkElse:
result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
if result: return
else: internalError("searchTypeNodeForAux(record case branch)")
else: discard
of nkSym:
result = searchTypeForAux(n.sym.typ, p, marker)
else: internalError(n.info, "searchTypeNodeForAux()")
else: discard
proc searchTypeForAux(t: PType, predicate: TTypePredicate,
marker: var IntSet): bool =
@@ -244,7 +245,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
if t == nil: return
case t.kind
of tyObject:
if (t.n != nil):
if t.n != nil:
if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
return frEmbedded
for i in countup(0, sonsLen(t) - 1):
@@ -453,16 +454,17 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if t.sons[0].kind == tyNone: result = "typedesc"
else: result = "type " & typeToString(t.sons[0])
of tyStatic:
internalAssert t.len > 0
if prefer == preferGenericArg and t.n != nil:
result = t.n.renderTree
else:
result = "static[" & typeToString(t.sons[0]) & "]"
result = "static[" & (if t.len > 0: typeToString(t.sons[0]) else: "") & "]"
if t.n != nil: result.add "(" & renderTree(t.n) & ")"
of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil
if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
return t.sym.owner.name.s
if t.sym != nil and t.sym.owner != nil:
if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
return t.sym.owner.name.s
else:
result = "<invalid tyUserTypeClass>"
of tyBuiltInTypeClass:
result = case t.base.kind:
of tyVar: "var"
@@ -496,7 +498,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyNot:
result = "not " & typeToString(t.sons[0])
of tyExpr:
internalAssert t.len == 0
#internalAssert t.len == 0
result = "untyped"
of tyFromExpr:
result = renderTree(t.n)
@@ -616,9 +618,9 @@ proc firstOrd*(t: PType): BiggestInt =
result = firstOrd(lastSon(t))
of tyOrdinal:
if t.len > 0: result = firstOrd(lastSon(t))
else: internalError("invalid kind for firstOrd(" & $t.kind & ')')
else: internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
else:
internalError("invalid kind for firstOrd(" & $t.kind & ')')
internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
result = 0
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
@@ -656,9 +658,9 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
of tyProxy: result = 0
of tyOrdinal:
if t.len > 0: result = lastOrd(lastSon(t))
else: internalError("invalid kind for lastOrd(" & $t.kind & ')')
else: internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
else:
internalError("invalid kind for lastOrd(" & $t.kind & ')')
internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
result = 0
proc lengthOrd*(t: PType): BiggestInt =
@@ -748,7 +750,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
proc sameConstraints(a, b: PNode): bool =
if isNil(a) and isNil(b): return true
internalAssert a.len == b.len
if a.len != b.len: return false
for i in 1 ..< a.len:
if not exprStructuralEquivalent(a[i].sym.constraint,
b[i].sym.constraint):
@@ -807,7 +809,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
var y = b.n.sons[i].sym
result = x.name.id == y.name.id
if not result: break
else: internalError(a.n.info, "sameTuple")
else:
return false
elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
result = false
@@ -997,7 +1000,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck()
result = sameTypeAux(a.lastSon, b.lastSon, c)
of tyNone: result = false
of tyUnused, tyOptAsRef: internalError("sameFlags")
of tyUnused, tyOptAsRef: result = false
proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure()
@@ -1191,7 +1194,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, tyOptAsRef: internalError("typeAllowedAux")
of tyUnused, tyOptAsRef: result = t
proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
# returns 'nil' on success and otherwise the part of the type that is
@@ -1280,7 +1283,8 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
if res < 0: return res
maxSize = max(maxSize, res)
maxAlign = max(maxAlign, b)
else: internalError("computeRecSizeAux(record case branch)")
else:
return szIllegalRecursion
currOffset = align(currOffset, maxAlign) + maxSize
result = align(result, maxAlign) + maxSize
a = maxAlign
@@ -1441,7 +1445,8 @@ proc getReturnType*(s: PSym): PType =
proc getSize*(typ: PType): BiggestInt =
result = computeSize(typ)
if result < 0: internalError("getSize: " & $typ.kind)
#if result < 0: internalError("getSize: " & $typ.kind)
# XXX review all usages of 'getSize'
proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
case t.kind
@@ -1469,8 +1474,7 @@ proc baseOfDistinct*(t: PType): PType =
while it.kind in {tyPtr, tyRef}:
parent = it
it = it.lastSon
if it.kind == tyDistinct:
internalAssert parent != nil
if it.kind == tyDistinct and parent != nil:
parent.sons[0] = it.sons[0]
proc safeInheritanceDiff*(a, b: PType): int =
@@ -1502,8 +1506,9 @@ type
proc compatibleEffects*(formal, actual: PType): EffectsCompat =
# for proc type compatibility checking:
assert formal.kind == tyProc and actual.kind == tyProc
internalAssert formal.n.sons[0].kind == nkEffectList
internalAssert actual.n.sons[0].kind == nkEffectList
if formal.n.sons[0].kind != nkEffectList or
actual.n.sons[0].kind != nkEffectList:
return efTagsUnknown
var spec = formal.n.sons[0]
if spec.len != 0:
@@ -1628,14 +1633,14 @@ proc skipHiddenSubConv*(n: PNode): PNode =
else:
result = n
proc typeMismatch*(info: TLineInfo, formal, actual: PType) =
proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError:
let named = typeToString(formal)
let desc = typeToString(formal, preferDesc)
let x = if named == desc: named else: named & " = " & desc
var msg = msgKindToString(errTypeMismatch) &
var msg = "type mismatch: got <" &
typeToString(actual) & "> " &
msgKindToString(errButExpectedX) % [x]
"but expected '" & x & "'"
if formal.kind == tyProc and actual.kind == tyProc:
case compatibleEffects(formal, actual)
@@ -1650,4 +1655,4 @@ proc typeMismatch*(info: TLineInfo, formal, actual: PType) =
msg.add "\n.tag effect is 'any tag allowed'"
of efLockLevelsDiffer:
msg.add "\nlock levels differ"
localError(info, errGenerated, msg)
localError(conf, info, msg)

View File

@@ -17,7 +17,6 @@ proc renderPlainSymbolName*(n: PNode): string =
## Use this on documentation name nodes to extract the *raw* symbol name,
## without decorations, parameters, or anything. That can be used as the base
## for the HTML hyperlinks.
result = ""
case n.kind
of nkPostfix, nkAccQuoted:
result = renderPlainSymbolName(n[n.len-1])
@@ -28,7 +27,8 @@ proc renderPlainSymbolName*(n: PNode): string =
of nkPragmaExpr:
result = renderPlainSymbolName(n[0])
else:
internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
result = ""
#internalError(n.info, "renderPlainSymbolName() with " & $n.kind)
assert(not result.isNil)
proc renderType(n: PNode): string =
@@ -105,7 +105,8 @@ proc renderParamTypes(found: var seq[string], n: PNode) =
for i in 0 ..< typePos:
found.add(typeStr)
else:
internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
found.add($n)
#internalError(n.info, "renderParamTypes(found,n) with " & $n.kind)
proc renderParamTypes*(n: PNode, sep = defaultParamSeparator): string =
## Returns the types contained in `n` joined by `sep`.

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, gorgeimpl
vmmarshal, gorgeimpl, configuration
from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate
@@ -61,7 +61,7 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
while x != nil:
inc calls
x = x.next
msgWriteln($calls & " calls omitted\n")
msgWriteln(c.config, $calls & " calls omitted\n")
return
stackTraceAux(c, x.next, x.comesFrom, recursionLimit-1)
var info = c.debug[pc]
@@ -78,19 +78,19 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
if x.prc != nil:
for k in 1..max(1, 25-s.len): add(s, ' ')
add(s, x.prc.name.s)
msgWriteln(s)
msgWriteln(c.config, s)
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: TMsgKind, arg = "", n: PNode = nil) =
msgWriteln("stack trace: (most recent call last)")
msg: string, n: PNode = nil) =
msgWriteln(c.config, "stack trace: (most recent call last)")
stackTraceAux(c, tos, pc)
# XXX test if we want 'globalError' for every mode
let lineInfo = if n == nil: c.debug[pc] else: n.info
if c.mode == emRepl: globalError(lineInfo, msg, arg)
else: localError(lineInfo, msg, arg)
if c.mode == emRepl: globalError(c.config, lineInfo, msg)
else: localError(c.config, lineInfo, msg)
proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
c.currentExceptionA.sons[3].skipColon.strVal)
when not defined(nimComputedGoto):
@@ -314,7 +314,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc
return -1
proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
if desttyp.kind == tyString:
if dest.kind != rkNode:
myreset(dest)
@@ -329,7 +329,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
else:
for i in 0..<n.len:
if n.sons[i].kind != nkSym: internalError("opConv for enum")
if n.sons[i].kind != nkSym: internalError(c.config, "opConv for enum")
let f = n.sons[i].sym
if f.position == x:
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
@@ -359,7 +359,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
of tyChar:
dest.node.strVal = $chr(src.intVal)
else:
internalError("cannot convert to string " & desttyp.typeToString)
internalError(c.config, "cannot convert to string " & desttyp.typeToString)
else:
case skipTypes(desttyp, abstractRange).kind
of tyInt..tyInt64:
@@ -408,9 +408,9 @@ template handleJmpBack() {.dirty.} =
if allowInfiniteLoops in c.features:
c.loopIterations = MaxLoopIterations
else:
msgWriteln("stack trace: (most recent call last)")
msgWriteln(c.config, "stack trace: (most recent call last)")
stackTraceAux(c, tos, pc)
globalError(c.debug[pc], errTooManyIterations)
globalError(c.config, c.debug[pc], errTooManyIterations)
dec(c.loopIterations)
proc recSetFlagIsRef(arg: PNode) =
@@ -440,6 +440,17 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
for i in oldLen ..< newLen:
node.sons[i] = newNodeI(typeKind, info)
const
errIndexOutOfBounds = "index out of bounds"
errNilAccess = "attempt to access a nil address"
errOverOrUnderflow = "over- or underflow"
errConstantDivisionByZero = "division by zero"
errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
errTooManyIterations = "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler"
errFieldXNotFound = "node lacks field: "
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start
var tos = tos
@@ -453,7 +464,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
#if c.traceActive:
when traceCode:
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
# message(c.debug[pc], warnUser, "Trace")
# message(c.config, c.debug[pc], warnUser, "Trace")
case instr.opcode
of opcEof: return regs[ra]
@@ -586,7 +597,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode:
regs[ra].nodeAddr = addr(regs[rb].node)
else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'addr'")
stackTrace(c, tos, pc, "limited VM support for 'addr'")
of opcLdDeref:
# a = b[]
let ra = instr.regA
@@ -629,7 +640,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, errOverOrUnderflow)
of opcAddImmInt:
decodeBImm(rkInt)
#message(c.debug[pc], warnUser, "came here")
#message(c.config, c.debug[pc], warnUser, "came here")
#debug regs[rb].node
let
bVal = regs[rb].intVal
@@ -898,17 +909,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else: copyTree(a.sym.ast)
else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
stackTrace(c, tos, pc, "node is not a symbol")
of opcEcho:
let rb = instr.regB
if rb == 1:
msgWriteln(regs[ra].node.strVal, {msgStdout})
msgWriteln(c.config, regs[ra].node.strVal, {msgStdout})
else:
var outp = ""
for i in ra..ra+rb-1:
#if regs[i].kind != rkNode: debug regs[i]
outp.add(regs[i].node.strVal)
msgWriteln(outp, {msgStdout})
msgWriteln(c.config, outp, {msgStdout})
of opcContainsSet:
decodeBC(rkInt)
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
@@ -937,9 +948,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rc = instr.regC
if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
stackTrace(c, tos, pc,
errIllegalConvFromXtoY % [
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
of opcIndCall, opcIndCallAsgn:
# dest = call regStart, n; where regStart = fn, arg1, ...
let rb = instr.regB
@@ -955,20 +966,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
currentLineInfo: c.debug[pc]))
elif sfImportc in prc.flags:
if allowFFI notin c.features:
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
globalError(c.config, c.debug[pc], "VM not allowed to do FFI")
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep
# 'regs' in a register:
when hasFFI:
let prcValue = c.globals.sons[prc.position-1]
if prcValue.kind == nkEmpty:
globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
globalError(c.config, c.debug[pc], "canot run " & prc.name.s)
let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
rb+1, rc-1, c.debug[pc])
if newValue.kind != nkEmpty:
assert instr.opcode == opcIndCallAsgn
putIntoReg(regs[ra], newValue)
else:
globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
globalError(c.config, c.debug[pc], "VM not built with FFI support")
elif prc.kind != skTemplate:
let newPc = compile(c, prc)
# tricky: a recursion is also a jump back, so we use the same
@@ -978,7 +989,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
newSeq(newFrame.slots, prc.offset+ord(isClosure))
if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
for i in 1 .. rc-1:
newFrame.slots[i] = regs[rb+i]
if isClosure:
@@ -1000,7 +1011,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef
ensureKind(rkNode)
@@ -1085,7 +1096,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNew:
ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc])
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
regs[ra].node.flags.incl nfIsRef
of opcNewSeq:
let typ = c.types[instr.regBx - wordExcess]
@@ -1097,7 +1108,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.typ = typ
newSeq(regs[ra].node.sons, count)
for i in 0 ..< count:
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
of opcNewStr:
decodeB(rkNode)
regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@@ -1109,7 +1120,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLdNull:
ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc])
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
# opcLdNull really is the gist of the VM's problems: should it load
# a fresh null to regs[ra].node or to regs[ra].node[]? This really
# depends on whether regs[ra] represents the variable itself or wether
@@ -1156,7 +1167,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
of opcQuit:
if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
message(c.debug[pc], hintQuitCalled)
message(c.config, c.debug[pc], hintQuitCalled)
msgQuit(int8(getOrdValue(regs[ra].regToNode)))
else:
return TFullReg(kind: rkNone)
@@ -1182,14 +1193,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
of opcReset:
internalError(c.debug[pc], "too implement")
internalError(c.config, c.debug[pc], "too implement")
of opcNarrowS:
decodeB(rkInt)
let min = -(1.BiggestInt shl (rb-1))
let max = (1.BiggestInt shl (rb-1))-1
if regs[ra].intVal < min or regs[ra].intVal > max:
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errUnhandledExceptionX) % "value out of range")
stackTrace(c, tos, pc, "unhandled exception: value out of range")
of opcNarrowU:
decodeB(rkInt)
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
@@ -1223,7 +1233,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if u.kind notin {nkEmpty..nkNilLit}:
u.add(regs[rc].node)
else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u
of opcNAddMultiple:
decodeBC(rkNode)
@@ -1233,7 +1243,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# XXX can be optimized:
for i in 0..<x.len: u.add(x.sons[i])
else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u
of opcNKind:
decodeB(rkInt)
@@ -1245,34 +1255,34 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if a.kind == nkSym:
regs[ra].intVal = ord(a.sym.kind)
else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
stackTrace(c, tos, pc, "node is not a symbol")
c.comesFromHeuristic = regs[rb].node.info
of opcNIntVal:
decodeB(rkInt)
let a = regs[rb].node
case a.kind
of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
else: stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNFloatVal:
decodeB(rkFloat)
let a = regs[rb].node
case a.kind
of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSymbol:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkSym:
regs[ra].node = copyNode(a)
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNIdent:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkIdent:
regs[ra].node = copyNode(a)
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNGetType:
let rb = instr.regB
let rc = instr.regC
@@ -1283,28 +1293,28 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
of 1:
# typeKind opcode:
ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind)
#else:
# stackTrace(c, tos, pc, errGenerated, "node has no type")
# stackTrace(c, tos, pc, "node has no type")
of 2:
# getTypeInst opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
else:
# getTypeImpl opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
of opcNStrVal:
decodeB(rkNode)
createStr regs[ra]
@@ -1319,12 +1329,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of nkSym:
regs[ra].node.strVal = a.sym.name.s
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcSlurp:
decodeB(rkNode)
createStr regs[ra]
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
c.module)
c.module, c.config)
of opcGorge:
decodeBC(rkNode)
inc pc
@@ -1333,29 +1343,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
createStr regs[ra]
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
regs[rc].node.strVal, regs[rd].node.strVal,
c.debug[pc])[0]
c.debug[pc], c.config)[0]
of opcNError:
decodeB(rkNode)
let a = regs[ra].node
let b = regs[rb].node
stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b)
stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b)
of opcNWarning:
message(c.debug[pc], warnUser, regs[ra].node.strVal)
message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal)
of opcNHint:
message(c.debug[pc], hintUser, regs[ra].node.strVal)
message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal)
of opcParseExprToAst:
decodeB(rkNode)
# c.debug[pc].line.int - countLines(regs[rb].strVal) ?
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax:
error = formatMsg(info, msg, arg))
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax:
error = formatMsg(conf, info, msg, arg))
if not error.isNil:
c.errorFlag = error
elif sonsLen(ast) != 1:
c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements")
c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated,
"expected expression, but got multiple statements")
else:
regs[ra].node = ast.sons[0]
of opcParseStmtToAst:
@@ -1363,9 +1374,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax:
error = formatMsg(info, msg, arg))
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax:
error = formatMsg(conf, info, msg, arg))
if not error.isNil:
c.errorFlag = error
else:
@@ -1377,7 +1388,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcCallSite:
ensureKind(rkNode)
if c.callsite != nil: regs[ra].node = c.callsite
else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
of opcNGetFile:
decodeB(rkNode)
let n = regs[rb].node
@@ -1439,13 +1450,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcStrToIdent:
decodeB(rkNode)
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
else:
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
regs[ra].node.ident = getIdent(regs[rb].node.strVal)
of opcSetType:
if regs[ra].kind != rkNode:
internalError(c.debug[pc], "cannot set type")
internalError(c.config, c.debug[pc], "cannot set type")
regs[ra].node.typ = c.types[instr.regBx - wordExcess]
of opcConv:
let rb = instr.regB
@@ -1454,9 +1465,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
inc pc
let srctyp = c.types[c.code[pc].regBx - wordExcess]
if opConv(regs[ra], regs[rb], desttyp, srctyp):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
if opConv(c, regs[ra], regs[rb], desttyp, srctyp):
stackTrace(c, tos, pc,
errIllegalConvFromXtoY % [
typeToString(srctyp), typeToString(desttyp)])
of opcCast:
let rb = instr.regB
@@ -1469,7 +1480,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let dest = fficast(regs[rb], desttyp)
asgnRef(regs[ra], dest)
else:
globalError(c.debug[pc], "cannot evaluate cast")
globalError(c.config, c.debug[pc], "cannot evaluate cast")
of opcNSetIntVal:
decodeB(rkNode)
var dest = regs[ra].node
@@ -1477,7 +1488,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkInt}:
dest.intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNSetFloatVal:
decodeB(rkNode)
var dest = regs[ra].node
@@ -1485,26 +1496,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkFloat}:
dest.floatVal = regs[rb].floatVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSetSymbol:
decodeB(rkNode)
var dest = regs[ra].node
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
dest.sym = regs[rb].node.sym
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNSetIdent:
decodeB(rkNode)
var dest = regs[ra].node
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
dest.ident = regs[rb].node.ident
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNSetType:
decodeB(rkNode)
let b = regs[rb].node
internalAssert b.kind == nkSym and b.sym.kind == skType
internalAssert regs[ra].node != nil
internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
internalAssert c.config, regs[ra].node != nil
regs[ra].node.typ = b.sym.typ
of opcNSetStrVal:
decodeB(rkNode)
@@ -1515,12 +1526,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
dest.comment = regs[rb].node.strVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcNNewNimNode:
decodeBC(rkNode)
var k = regs[rb].intVal
if k < 0 or k > ord(high(TNodeKind)):
internalError(c.debug[pc],
internalError(c.config, c.debug[pc],
"request to create a NimNode of invalid kind")
let cc = regs[rc].node
@@ -1554,7 +1565,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let name = if regs[rc].node.strVal.len == 0: ":tmp"
else: regs[rc].node.strVal
if k < 0 or k > ord(high(TSymKind)):
internalError(c.debug[pc], "request to create symbol of invalid kind")
internalError(c.config, c.debug[pc], "request to create symbol of invalid kind")
var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc])
incl(sym.flags, sfGenSym)
regs[ra].node = newSymNode(sym)
@@ -1563,7 +1574,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# type trait operation
decodeB(rkNode)
var typ = regs[rb].node.typ
internalAssert typ != nil
internalAssert c.config, typ != nil
while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
createStr regs[ra]
regs[ra].node.strVal = typ.typeToString(preferExported)
@@ -1572,14 +1583,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rb = instr.regB
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config))
of opcMarshalStore:
decodeB(rkNode)
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
createStrKeepNode(regs[ra])
if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
of opcToNarrowInt:
decodeBC(rkInt)
let mask = (1'i64 shl rc) - 1 # 0xFF
@@ -1601,7 +1612,7 @@ proc execute(c: PCtx, start: int): PNode =
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
if sym.kind in routineKinds:
if sym.typ.len-1 != args.len:
localError(sym.info,
localError(c.config, sym.info,
"NimScript: expected $# arguments, but got $#" % [
$(sym.typ.len-1), $args.len])
else:
@@ -1613,18 +1624,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
# setup parameters:
if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info))
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
# XXX We could perform some type checking here.
for i in 1..<sym.typ.len:
putIntoReg(tos.slots[i], args[i-1])
result = rawExecute(c, start, tos).regToNode
else:
localError(sym.info,
localError(c.config, sym.info,
"NimScript: attempt to call non-routine: " & sym.name.s)
proc evalStmt*(c: PCtx, n: PNode) =
let n = transformExpr(c.module, n)
let n = transformExpr(c.graph, c.module, n)
let start = genStmt(c, n)
# execute new instructions; this redundant opcEof check saves us lots
# of allocations in 'execute':
@@ -1632,13 +1643,13 @@ proc evalStmt*(c: PCtx, n: PNode) =
discard execute(c, start)
proc evalExpr*(c: PCtx, n: PNode): PNode =
let n = transformExpr(c.module, n)
let n = transformExpr(c.graph, c.module, n)
let start = genExpr(c, n)
assert c.code[start].opcode != opcEof
result = execute(c, start)
proc getGlobalValue*(c: PCtx; s: PSym): PNode =
internalAssert s.kind in {skLet, skVar} and sfGlobal in s.flags
internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
result = c.globals.sons[s.position-1]
include vmops
@@ -1649,9 +1660,9 @@ include vmops
var
globalCtx*: PCtx
proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) =
proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) =
if globalCtx.isNil:
globalCtx = newCtx(module, cache, config)
globalCtx = newCtx(module, cache, graph)
registerAdditionalOps(globalCtx)
else:
refresh(globalCtx, module)
@@ -1662,21 +1673,20 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
#pushStackFrame(c, newStackFrame())
# XXX produce a new 'globals' environment here:
setupGlobalCtx(module, cache, graph.config)
setupGlobalCtx(module, cache, graph)
result = globalCtx
when hasFFI:
globalCtx.features = {allowFFI, allowCast}
var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code:
if oldErrorCount == msgs.gErrorCounter:
evalStmt(PCtx(c), n)
if c.oldErrorCount == c.config.errorCounter:
evalStmt(c, n)
result = emptyNode
else:
result = n
oldErrorCount = msgs.gErrorCounter
c.oldErrorCount = c.config.errorCounter
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
myProcess(c, n)
@@ -1684,10 +1694,10 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
const evalPass* = makePass(myOpen, nil, myProcess, myClose)
proc evalConstExprAux(module: PSym; cache: IdentCache;
config: ConfigRef; prc: PSym, n: PNode,
g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode =
let n = transformExpr(module, n)
setupGlobalCtx(module, cache, config)
let n = transformExpr(g, module, n)
setupGlobalCtx(module, cache, g)
var c = globalCtx
let oldMode = c.mode
defer: c.mode = oldMode
@@ -1702,17 +1712,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
result = rawExecute(c, start, tos).regToNode
if result.info.col < 0: result.info = n.info
proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode =
result = evalConstExprAux(module, cache, config, nil, e, emConst)
proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode =
result = evalConstExprAux(module, cache, g, nil, e, emConst)
proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr)
proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr)
proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt)
proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) =
discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) =
discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt)
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind
@@ -1740,20 +1750,20 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
const evalMacroLimit = 1000
var evalMacroCounter: int
proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
n, nOrig: PNode, sym: PSym): PNode =
# XXX globalError() is ugly here, but I don't know a better solution for now
inc(evalMacroCounter)
if evalMacroCounter > evalMacroLimit:
globalError(n.info, errMacroInstantiationTooNested)
globalError(g.config, n.info, "macro instantiation too nested")
# immediate macros can bypass any type and arity checking so we check the
# arity here too:
if sym.typ.len > n.safeLen and sym.typ.len > 1:
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
setupGlobalCtx(module, cache, config)
setupGlobalCtx(module, cache, g)
var c = globalCtx
c.comesFromHeuristic.line = 0'u16
@@ -1787,16 +1797,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
else:
dec(evalMacroCounter)
c.callsite = nil
localError(n.info, "expected " & $gp.len &
localError(c.config, n.info, "expected " & $gp.len &
" generic parameter(s)")
elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}:
dec(evalMacroCounter)
c.callsite = nil
globalError(n.info, "static[T] or typedesc nor supported for .immediate macros")
globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros")
# temporary storage:
#for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode
if result.info.line < 0: result.info = n.info
if cyclicTree(result): globalError(n.info, errCyclicTree)
if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
dec(evalMacroCounter)
c.callsite = nil

View File

@@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine.
## An instruction is 1-3 int32s in memory, it is a register based VM.
import ast, passes, msgs, idents, intsets, options
import ast, passes, msgs, idents, intsets, options, modulegraphs
const
byteExcess* = 128 # we use excess-K for immediates
@@ -207,18 +207,19 @@ type
errorFlag*: string
cache*: IdentCache
config*: ConfigRef
graph*: ModuleGraph
oldErrorCount*: int
TPosition* = distinct int
PEvalContext* = PCtx
proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx =
let conf = if config != nil: config else: newConfigRef()
proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
cache: cache, config: conf)
cache: cache, config: g.config, graph: g)
proc refresh*(c: PCtx, module: PSym) =
c.module = module

View File

@@ -9,18 +9,18 @@
import ast, types, msgs, os, streams, options, idents
proc opSlurp*(file: string, info: TLineInfo, module: PSym): string =
proc opSlurp*(file: string, info: TLineInfo, module: PSym; conf: ConfigRef): string =
try:
var filename = parentDir(info.toFullPath) / file
if not fileExists(filename):
filename = file.findFile
filename = findFile(conf, file)
result = readFile(filename)
# we produce a fake include statement for every slurped filename, so that
# the module dependencies are accurate:
appendToModule(module, newNode(nkIncludeStmt, info, @[
newStrNode(nkStrLit, filename)]))
except IOError:
localError(info, errCannotOpenFile, file)
localError(conf, info, "cannot open file: " & file)
result = ""
proc atomicTypeX(name: string; m: TMagic; t: PType; info: TLineInfo): PNode =
@@ -271,7 +271,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
of tyOr: result = mapTypeToBracket("or", mOr, t, info)
of tyNot: result = mapTypeToBracket("not", mNot, t, info)
of tyAnything: result = atomicType("anything", mNone)
of tyInferred: internalAssert false
of tyInferred: assert false
of tyStatic, tyFromExpr:
if inst:
if t.n != nil: result = t.n.copyTree
@@ -281,7 +281,7 @@ proc mapTypeToAstX(t: PType; info: TLineInfo;
result.add atomicType("static", mNone)
if t.n != nil:
result.add t.n.copyTree
of tyUnused, tyOptAsRef: internalError("mapTypeToAstX")
of tyUnused, tyOptAsRef: assert(false, "mapTypeToAstX")
proc opMapTypeToAst*(t: PType; info: TLineInfo): PNode =
result = mapTypeToAstX(t, info, false, true)

View File

@@ -120,7 +120,7 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) =
c.code.add(ins)
c.debug.add(n.info)
else:
localError(n.info, errGenerated,
localError(c.config, n.info,
"VM: immediate value does not fit into an int8")
proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
@@ -137,7 +137,7 @@ proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) =
c.code.add(ins)
c.debug.add(n.info)
else:
localError(n.info, errGenerated,
localError(c.config, n.info,
"VM: immediate value does not fit into an int16")
proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
@@ -151,7 +151,7 @@ proc genLabel(c: PCtx): TPosition =
proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) =
let dist = p.int - c.code.len
internalAssert(-0x7fff < dist and dist < 0x7fff)
internalAssert(c.config, -0x7fff < dist and dist < 0x7fff)
gABx(c, n, opcJmpBack, 0, dist)
proc patch(c: PCtx, p: TPosition) =
@@ -159,7 +159,7 @@ proc patch(c: PCtx, p: TPosition) =
let p = p.int
let diff = c.code.len - p
#c.jumpTargets.incl(c.code.len)
internalAssert(-0x7fff < diff and diff < 0x7fff)
internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
let oldInstr = c.code[p]
# opcode and regA stay the same:
c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or
@@ -201,7 +201,7 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
c.slots[i] = (inUse: true, kind: k)
return TRegister(i)
if c.maxSlots >= high(TRegister):
globalError(cc.bestEffort, "VM problem: too many registers required")
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
result = TRegister(c.maxSlots)
c.slots[c.maxSlots] = (inUse: true, kind: k)
inc c.maxSlots
@@ -223,7 +223,7 @@ proc getTempRange(cc: PCtx; n: int; kind: TSlotKind): TRegister =
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
return
if c.maxSlots+n >= high(TRegister):
globalError(cc.bestEffort, "VM problem: too many registers required")
globalError(cc.config, cc.bestEffort, "VM problem: too many registers required")
result = TRegister(c.maxSlots)
inc c.maxSlots, n
for k in result .. result+n-1: c.slots[k] = (inUse: true, kind: kind)
@@ -251,7 +251,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {})
proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
var d: TDest = dest
gen(c, n, d, flags)
#internalAssert d == dest # issue #7407
#internalAssert c.config, d == dest # issue #7407
proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
var tmp: TDest = -1
@@ -261,7 +261,7 @@ proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
var tmp: TDest = -1
gen(c, n, tmp, flags)
#internalAssert tmp >= 0 # 'nim check' does not like this internalAssert.
#internalAssert c.config, tmp >= 0 # 'nim check' does not like this internalAssert.
if tmp >= 0:
result = TRegister(tmp)
@@ -320,7 +320,7 @@ proc genBreak(c: PCtx; n: PNode) =
if c.prc.blocks[i].label == n.sons[0].sym:
c.prc.blocks[i].fixups.add L1
return
globalError(n.info, errGenerated, "VM problem: cannot find 'break' target")
globalError(c.config, n.info, "VM problem: cannot find 'break' target")
else:
c.prc.blocks[c.prc.blocks.high].fixups.add L1
@@ -378,7 +378,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int =
#assert(n.kind != nkCall)
n.flags.incl nfAllConst
c.constants.add n.canonValue
internalAssert result < 0x7fff
internalAssert c.config, result < 0x7fff
proc sameConstant*(a, b: PNode): bool =
result = false
@@ -405,10 +405,10 @@ proc genLiteral(c: PCtx; n: PNode): int =
if sameConstant(c.constants[i], n): return i
result = rawGenLiteral(c, n)
proc unused(n: PNode; x: TDest) {.inline.} =
proc unused(c: PCtx; n: PNode; x: TDest) {.inline.} =
if x >= 0:
#debug(n)
globalError(n.info, "not unused")
globalError(c.config, n.info, "not unused")
proc genCase(c: PCtx; n: PNode; dest: var TDest) =
# if (!expr1) goto L1;
@@ -424,7 +424,7 @@ proc genCase(c: PCtx; n: PNode; dest: var TDest) =
if not isEmptyType(n.typ):
if dest < 0: dest = getTemp(c, n.typ)
else:
unused(n, dest)
unused(c, n, dest)
var endings: seq[TPosition] = @[]
withTemp(tmp, n.sons[0].typ):
c.gen(n.sons[0], tmp)
@@ -451,7 +451,7 @@ proc genType(c: PCtx; typ: PType): int =
if sameType(t, typ): return i
result = c.types.len
c.types.add(typ)
internalAssert(result <= 0x7fff)
internalAssert(c.config, result <= 0x7fff)
proc genTry(c: PCtx; n: PNode; dest: var TDest) =
if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ)
@@ -525,7 +525,7 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
var r: TRegister = x+i
c.gen(n.sons[i], r)
if i >= fntyp.len:
internalAssert tfVarargs in fntyp.flags
internalAssert c.config, tfVarargs in fntyp.flags
c.gABx(n, opcSetType, r, c.genType(n.sons[i].typ))
if dest < 0:
c.gABC(n, opcIndCall, 0, x, n.len)
@@ -540,12 +540,12 @@ proc needsAsgnPatch(n: PNode): bool =
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
proc genField(n: PNode): TRegister =
proc genField(c: PCtx; n: PNode): TRegister =
if n.kind != nkSym or n.sym.kind != skField:
globalError(n.info, "no field symbol")
globalError(c.config, n.info, "no field symbol")
let s = n.sym
if s.position > high(result):
globalError(n.info,
globalError(c.config, n.info,
"too large offset! cannot generate code for: " & s.name.s)
result = s.position
@@ -572,7 +572,7 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
# XXX field checks here
let left = if le.kind == nkDotExpr: le else: le.sons[0]
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
let idx = genField(left.sons[1])
let idx = genField(c, left.sons[1])
c.gABC(left, opcWrObj, dest, idx, value)
c.freeTemp(dest)
of nkDerefExpr, nkHiddenDeref:
@@ -779,7 +779,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
let tmp3 = c.getTemp(n.sons[1].typ)
if dest < 0: dest = c.getTemp(n[0].typ)
proc mkIntLit(ival: int): int =
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(tyInt)))
result = genLiteral(c, newIntTypeNode(nkIntLit, ival, getSysType(c.graph, n.info, tyInt)))
if src.kind in unsignedIntegers and dst.kind in signedIntegers:
# cast unsigned to signed integer of same size
# signedVal = (unsignedVal xor offset) -% offset
@@ -802,7 +802,7 @@ proc genIntCast(c: PCtx; n: PNode; dest: var TDest) =
c.freeTemp(tmp2)
c.freeTemp(tmp3)
else:
globalError(n.info, errGenerated, "VM is only allowed to 'cast' between integers of same size")
globalError(c.config, n.info, "VM is only allowed to 'cast' between integers of same size")
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
case m
@@ -818,7 +818,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mSucc, mAddI:
c.genAddSubInt(n, dest, opcAddInt)
of mInc, mDec:
unused(n, dest)
unused(c, n, dest)
let opc = if m == mInc: opcAddInt else: opcSubInt
let d = c.genx(n.sons[1])
if n.sons[2].isInt8Lit:
@@ -832,10 +832,10 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.freeTemp(d)
of mOrd, mChr, mArrToSeq: c.gen(n.sons[1], dest)
of mNew, mNewFinalize:
unused(n, dest)
unused(c, n, dest)
c.genNew(n)
of mNewSeq:
unused(n, dest)
unused(c, n, dest)
c.genNewSeq(n)
of mNewSeqOfCap: c.genNewSeqOfCap(n, dest)
of mNewString:
@@ -855,7 +855,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mLengthStr, mXLenStr:
genUnaryABI(c, n, dest, opcLenStr)
of mIncl, mExcl:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
var tmp = c.genx(n.sons[2])
c.genSetType(n.sons[1], d)
@@ -952,19 +952,19 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mInSet: genBinarySet(c, n, dest, opcContainsSet)
of mRepr: genUnaryABC(c, n, dest, opcRepr)
of mExit:
unused(n, dest)
unused(c, n, dest)
var tmp = c.genx(n.sons[1])
c.gABC(n, opcQuit, tmp)
c.freeTemp(tmp)
of mSetLengthStr, mSetLengthSeq:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
var tmp = c.genx(n.sons[2])
c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
c.genAsgnPatch(n.sons[1], d)
c.freeTemp(tmp)
of mSwap:
unused(n, dest)
unused(c, n, dest)
c.gen(lowerSwap(n, if c.prc == nil: c.module else: c.prc.sym))
of mIsNil: genUnaryABC(c, n, dest, opcIsNil)
of mCopyStr:
@@ -996,7 +996,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
# skip 'nkHiddenAddr':
let d2AsNode = n.sons[2].sons[0]
if needsAsgnPatch(d2AsNode):
d2 = c.getTemp(getSysType(tyFloat))
d2 = c.getTemp(getSysType(c.graph, n.info, tyFloat))
else:
d2 = c.genx(d2AsNode)
var
@@ -1009,13 +1009,13 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genAsgnPatch(d2AsNode, d2)
c.freeTemp(d2)
of mReset:
unused(n, dest)
unused(c, n, dest)
var d = c.genx(n.sons[1])
c.gABC(n, opcReset, d)
of mOf, mIs:
if dest < 0: dest = c.getTemp(n.typ)
var tmp = c.genx(n.sons[1])
var idx = c.getTemp(getSysType(tyInt))
var idx = c.getTemp(getSysType(c.graph, n.info, tyInt))
var typ = n.sons[2].typ
if m == mOf: typ = typ.skipTypes(abstractPtrs-{tyTypeDesc})
c.gABx(n, opcLdImmInt, idx, c.genType(typ))
@@ -1023,7 +1023,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.freeTemp(tmp)
c.freeTemp(idx)
of mSizeOf:
globalError(n.info, errCannotInterpretNodeX, renderTree(n))
globalError(c.config, n.info, "cannot run in the VM: " & renderTree(n))
of mHigh:
if dest < 0: dest = c.getTemp(n.typ)
let tmp = c.genx(n.sons[1])
@@ -1034,23 +1034,23 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABI(n, opcLenSeq, dest, tmp, 1)
c.freeTemp(tmp)
of mEcho:
unused(n, dest)
unused(c, n, dest)
let n = n[1].skipConv
let x = c.getTempRange(n.len, slotTempUnknown)
internalAssert n.kind == nkBracket
internalAssert c.config, n.kind == nkBracket
for i in 0..<n.len:
var r: TRegister = x+i
c.gen(n.sons[i], r)
c.gABC(n, opcEcho, x, n.len)
c.freeTempRange(x, n.len)
of mAppendStrCh:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddStrCh)
of mAppendStrStr:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddStrStr)
of mAppendSeqElem:
unused(n, dest)
unused(c, n, dest)
genBinaryStmtVar(c, n, opcAddSeqElem)
of mParseExprToAst:
genUnaryABC(c, n, dest, opcParseExprToAst)
@@ -1068,7 +1068,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mGetImpl: genUnaryABC(c, n, dest, opcGetImpl)
of mNChild: genBinaryABC(c, n, dest, opcNChild)
of mNSetChild, mNDel:
unused(n, dest)
unused(c, n, dest)
var
tmp1 = c.genx(n.sons[1])
tmp2 = c.genx(n.sons[2])
@@ -1098,22 +1098,22 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
#genUnaryABC(c, n, dest, opcNGetType)
of mNStrVal: genUnaryABC(c, n, dest, opcNStrVal)
of mNSetIntVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetIntVal)
of mNSetFloatVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetFloatVal)
of mNSetSymbol:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetSymbol)
of mNSetIdent:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetIdent)
of mNSetType:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetType)
of mNSetStrVal:
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNSetStrVal)
of mNNewNimNode: genBinaryABC(c, n, dest, opcNNewNimNode)
of mNCopyNimNode: genUnaryABC(c, n, dest, opcNCopyNimNode)
@@ -1124,7 +1124,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcNBindSym, dest, idx)
else:
localError(n.info, "invalid bindSym usage")
localError(c.config, n.info, "invalid bindSym usage")
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
@@ -1138,12 +1138,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of "getColumn":
genUnaryABC(c, n, dest, opcNGetColumn)
else:
internalAssert false
internalAssert c.config, false
of mNHint:
unused(n, dest)
unused(c, n, dest)
genUnaryStmt(c, n, opcNHint)
of mNWarning:
unused(n, dest)
unused(c, n, dest)
genUnaryStmt(c, n, opcNWarning)
of mNError:
if n.len <= 1:
@@ -1151,7 +1151,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.gABC(n, opcQueryErrorFlag, dest)
else:
# setter
unused(n, dest)
unused(c, n, dest)
genBinaryStmt(c, n, opcNError)
of mNCallSite:
if dest < 0: dest = c.getTemp(n.typ)
@@ -1162,7 +1162,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
c.genCall(n, dest)
of mExpandToAst:
if n.len != 2:
globalError(n.info, errGenerated, "expandToAst requires 1 argument")
globalError(c.config, n.info, "expandToAst requires 1 argument")
let arg = n.sons[1]
if arg.kind in nkCallKinds:
#if arg[0].kind != nkSym or arg[0].sym.kind notin {skTemplate, skMacro}:
@@ -1172,12 +1172,12 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
# do not call clearDest(n, dest) here as getAst has a meta-type as such
# produces a value
else:
globalError(n.info, "expandToAst requires a call expression")
globalError(c.config, n.info, "expandToAst requires a call expression")
of mRunnableExamples:
discard "just ignore any call to runnableExamples"
else:
# mGCref, mGCunref,
globalError(n.info, "cannot generate code for: " & $m)
globalError(c.config, n.info, "cannot generate code for: " & $m)
proc genMarshalLoad(c: PCtx, n: PNode, dest: var TDest) =
## Signature: proc to*[T](data: string): T
@@ -1306,14 +1306,14 @@ proc setSlot(c: PCtx; v: PSym) =
if v.position == 0:
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
if c.prc.maxSlots >= high(TRegister):
globalError(v.info, "cannot generate code; too many registers required")
globalError(c.config, v.info, "cannot generate code; too many registers required")
v.position = c.prc.maxSlots
c.prc.slots[v.position] = (inUse: true,
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
inc c.prc.maxSlots
proc cannotEval(n: PNode) {.noinline.} =
globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
globalError(c.config, n.info, "cannot evaluate at compile time: " &
n.renderTree)
proc isOwnedBy(a, b: PSym): bool =
@@ -1333,10 +1333,10 @@ proc checkCanEval(c: PCtx; n: PNode) =
if {sfCompileTime, sfGlobal} <= s.flags: return
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)
cannotEval(c, n)
elif s.kind in {skProc, skFunc, skConverter, skMethod,
skIterator} and sfForward in s.flags:
cannotEval(n)
cannotEval(c, n)
proc isTemp(c: PCtx; dest: TDest): bool =
result = dest >= 0 and c.prc.slots[dest].kind >= slotTempUnknown
@@ -1378,7 +1378,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
# XXX field checks here
let left = if le.kind == nkDotExpr: le else: le.sons[0]
let dest = c.genx(left.sons[0], {gfAddrOf, gfFieldAccess})
let idx = genField(left.sons[1])
let idx = genField(c, left.sons[1])
let tmp = c.genx(ri)
c.preventFalseAlias(left, opcWrObj, dest, idx, tmp)
c.freeTemp(tmp)
@@ -1398,7 +1398,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(val)
else:
if s.kind == skForVar: c.setSlot s
internalAssert s.position > 0 or (s.position == 0 and
internalAssert c.config, s.position > 0 or (s.position == 0 and
s.kind in {skParam,skResult})
var dest: TRegister = s.position + ord(s.kind == skParam)
assert le.typ != nil
@@ -1424,15 +1424,15 @@ proc importcSym(c: PCtx; info: TLineInfo; s: PSym) =
c.globals.add(importcSymbol(s))
s.position = c.globals.len
else:
localError(info, errGenerated, "VM is not allowed to 'importc'")
localError(c.config, info, "VM is not allowed to 'importc'")
else:
localError(info, errGenerated,
localError(c.config, info,
"cannot 'importc' variable at compile time")
proc getNullValue*(typ: PType, info: TLineInfo): PNode
proc getNullValue*(typ: PType, info: TLineInfo; conf: ConfigRef): PNode
proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
c.globals.add(getNullValue(s.typ, n.info))
c.globals.add(getNullValue(s.typ, n.info, c.config))
s.position = c.globals.len
# This is rather hard to support, due to the laziness of the VM code
# generator. See tests/compile/tmacro2 for why this is necessary:
@@ -1451,7 +1451,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
if sfCompileTime in s.flags or c.mode == emRepl:
discard
elif s.position == 0:
cannotEval(n)
cannotEval(c, n)
if s.position == 0:
if sfImportc in s.flags: c.importcSym(n.info, s)
else: genGlobalInit(c, n, s)
@@ -1472,13 +1472,13 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
s.kind in {skParam,skResult}):
if dest < 0:
dest = s.position + ord(s.kind == skParam)
internalAssert(c.prc.slots[dest].kind < slotSomeTemp)
internalAssert(c.config, c.prc.slots[dest].kind < slotSomeTemp)
else:
# we need to generate an assignment:
genAsgn(c, dest, n, c.prc.slots[dest].kind >= slotSomeTemp)
else:
# see tests/t99bott for an example that triggers it:
cannotEval(n)
cannotEval(c, n)
template needsRegLoad(): untyped =
gfAddrOf notin flags and fitsRegister(n.typ.skipTypes({tyVar, tyLent}))
@@ -1502,7 +1502,7 @@ proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
proc genObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
let a = c.genx(n.sons[0], flags)
let b = genField(n.sons[1])
let b = genField(c, n.sons[1])
if dest < 0: dest = c.getTemp(n.typ)
if needsRegLoad():
var cc = c.getTemp(n.typ)
@@ -1526,22 +1526,22 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
else:
genArrAccess2(c, n, dest, opcLdArr, flags)
proc getNullValueAux(obj: PNode, result: PNode) =
proc getNullValueAux(obj: PNode, result: PNode; conf: ConfigRef) =
case obj.kind
of nkRecList:
for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result)
for i in countup(0, sonsLen(obj) - 1): getNullValueAux(obj.sons[i], result, conf)
of nkRecCase:
getNullValueAux(obj.sons[0], result)
getNullValueAux(obj.sons[0], result, conf)
for i in countup(1, sonsLen(obj) - 1):
getNullValueAux(lastSon(obj.sons[i]), result)
getNullValueAux(lastSon(obj.sons[i]), result, conf)
of nkSym:
let field = newNodeI(nkExprColonExpr, result.info)
field.add(obj)
field.add(getNullValue(obj.sym.typ, result.info))
field.add(getNullValue(obj.sym.typ, result.info, conf))
addSon(result, field)
else: globalError(result.info, "cannot create null element for: " & $obj)
else: globalError(conf, result.info, "cannot create null element for: " & $obj)
proc getNullValue(typ: PType, info: TLineInfo): PNode =
proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
var t = skipTypes(typ, abstractRange-{tyTypeDesc})
result = emptyNode
case t.kind
@@ -1570,17 +1570,17 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
# initialize inherited fields:
var base = t.sons[0]
while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result)
getNullValueAux(skipTypes(base, skipPtrs).n, result, conf)
base = base.sons[0]
getNullValueAux(t.n, result)
getNullValueAux(t.n, result, conf)
of tyArray:
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
addSon(result, getNullValue(elemType(t), info))
addSon(result, getNullValue(elemType(t), info, conf))
of tyTuple:
result = newNodeIT(nkTupleConstr, info, t)
for i in countup(0, sonsLen(t) - 1):
addSon(result, getNullValue(t.sons[i], info))
addSon(result, getNullValue(t.sons[i], info, conf))
of tySet:
result = newNodeIT(nkCurly, info, t)
of tyOpt:
@@ -1588,7 +1588,7 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tySequence:
result = newNodeIT(nkBracket, info, t)
else:
globalError(info, "cannot create null element for: " & $t.kind)
globalError(conf, info, "cannot create null element for: " & $t.kind)
proc ldNullOpcode(t: PType): TOpcode =
assert t != nil
@@ -1602,7 +1602,7 @@ proc genVarSection(c: PCtx; n: PNode) =
for i in 0 .. a.len-3:
if not a[i].sym.isGlobal: setSlot(c, a[i].sym)
checkCanEval(c, a[i])
c.gen(lowerTupleUnpacking(a, c.getOwner))
c.gen(lowerTupleUnpacking(c.graph, a, c.getOwner))
elif a.sons[0].kind == nkSym:
let s = a.sons[0].sym
checkCanEval(c, a.sons[0])
@@ -1610,7 +1610,7 @@ proc genVarSection(c: PCtx; n: PNode) =
if s.position == 0:
if sfImportc in s.flags: c.importcSym(a.info, s)
else:
let sa = getNullValue(s.typ, a.info)
let sa = getNullValue(s.typ, a.info, c.config)
#if s.ast.isNil: getNullValue(s.typ, a.info)
#else: canonValue(s.ast)
assert sa.kind != nkCall
@@ -1652,7 +1652,7 @@ proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
c.gABx(n, opcLdNull, dest, c.genType(n.typ))
let intType = getSysType(tyInt)
let intType = getSysType(c.graph, n.info, tyInt)
let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
if seqType.kind == tySequence:
var tmp = c.getTemp(intType)
@@ -1696,13 +1696,13 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
for i in 1..<n.len:
let it = n.sons[i]
if it.kind == nkExprColonExpr and it.sons[0].kind == nkSym:
let idx = genField(it.sons[0])
let idx = genField(c, it.sons[0])
let tmp = c.genx(it.sons[1])
c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
dest, idx, tmp)
c.freeTemp(tmp)
else:
globalError(n.info, "invalid object constructor")
globalError(c.config, n.info, "invalid object constructor")
proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
if dest < 0: dest = c.getTemp(n.typ)
@@ -1711,7 +1711,7 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
for i in 0..<n.len:
let it = n.sons[i]
if it.kind == nkExprColonExpr:
let idx = genField(it.sons[0])
let idx = genField(c, it.sons[0])
let tmp = c.genx(it.sons[1])
c.preventFalseAlias(it.sons[1], whichAsgnOpc(it.sons[1], opcWrObj),
dest, idx, tmp)
@@ -1786,9 +1786,9 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if c.prc.sym != nil and c.prc.sym.kind == skMacro:
genRdVar(c, n, dest, flags)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
else:
globalError(n.info, errGenerated, "cannot generate code for: " & s.name.s)
globalError(c.config, n.info, "cannot generate code for: " & s.name.s)
of nkCallKinds:
if n.sons[0].kind == nkSym:
let s = n.sons[0].sym
@@ -1812,10 +1812,10 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
genLit(c, n, dest)
of nkUIntLit..pred(nkNilLit): genLit(c, n, dest)
of nkNilLit:
if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info), dest)
else: unused(n, dest)
if not n.typ.isEmptyType: genLit(c, getNullValue(n.typ, n.info, c.config), dest)
else: unused(c, n, dest)
of nkAsgn, nkFastAsgn:
unused(n, dest)
unused(c, n, dest)
genAsgn(c, n.sons[0], n.sons[1], n.kind == nkAsgn)
of nkDotExpr: genObjAccess(c, n, dest, flags)
of nkCheckedFieldExpr: genCheckedObjAccess(c, n, dest, flags)
@@ -1828,20 +1828,20 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
gen(c, n.sons[0].sons[1], dest)
of nkCaseStmt: genCase(c, n, dest)
of nkWhileStmt:
unused(n, dest)
unused(c, n, dest)
genWhile(c, n)
of nkBlockExpr, nkBlockStmt: genBlock(c, n, dest)
of nkReturnStmt:
unused(n, dest)
unused(c, n, dest)
genReturn(c, n)
of nkRaiseStmt:
genRaise(c, n)
of nkBreakStmt:
unused(n, dest)
unused(c, n, dest)
genBreak(c, n)
of nkTryStmt: genTry(c, n, dest)
of nkStmtList:
#unused(n, dest)
#unused(c, n, dest)
# XXX Fix this bug properly, lexim triggers it
for x in n: gen(c, x)
of nkStmtListExpr:
@@ -1851,17 +1851,17 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPragmaBlock:
gen(c, n.lastSon, dest, flags)
of nkDiscardStmt:
unused(n, dest)
unused(c, n, dest)
gen(c, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n.sons[1], dest)
of nkObjDownConv:
genConv(c, n, n.sons[0], dest)
of nkVarSection, nkLetSection:
unused(n, dest)
unused(c, n, dest)
genVarSection(c, n)
of declarativeDefs, nkMacroDef:
unused(n, dest)
unused(c, n, dest)
of nkLambdaKinds:
#let s = n.sons[namePos].sym
#discard genProc(c, s)
@@ -1881,7 +1881,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
dest = tmp0
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
nkTemplateDef, nkIncludeStmt, nkImportStmt, nkFromStmt:
unused(n, dest)
unused(c, n, dest)
of nkStringToCString, nkCStringToString:
gen(c, n.sons[0], dest)
of nkBracket: genArrayConstr(c, n, dest)
@@ -1898,7 +1898,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkComesFrom:
discard "XXX to implement for better stack traces"
else:
globalError(n.info, errGenerated, "cannot generate VM code for " & $n)
globalError(c.config, n.info, "cannot generate VM code for " & $n)
proc removeLastEof(c: PCtx) =
let last = c.code.len-1
@@ -1915,7 +1915,7 @@ proc genStmt*(c: PCtx; n: PNode): int =
c.gen(n, d)
c.gABC(n, opcEof)
if d >= 0:
globalError(n.info, errGenerated, "VM problem: dest register is set")
globalError(c.config, n.info, "VM problem: dest register is set")
proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
c.removeLastEof
@@ -1924,7 +1924,7 @@ proc genExpr*(c: PCtx; n: PNode, requiresValue = true): int =
c.gen(n, d)
if d < 0:
if requiresValue:
globalError(n.info, errGenerated, "VM problem: dest register is not set")
globalError(c.config, n.info, "VM problem: dest register is not set")
d = 0
c.gABC(n, opcEof, d)
@@ -1939,7 +1939,7 @@ proc genParams(c: PCtx; params: PNode) =
c.prc.maxSlots = max(params.len, 1)
proc finalJumpTarget(c: PCtx; pc, diff: int) =
internalAssert(-0x7fff < diff and diff < 0x7fff)
internalAssert(c.config, -0x7fff < diff and diff < 0x7fff)
let oldInstr = c.code[pc]
# opcode and regA stay the same:
c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or

View File

@@ -9,7 +9,8 @@
## Implements marshaling for the VM.
import streams, json, intsets, tables, ast, astalgo, idents, types, msgs
import streams, json, intsets, tables, ast, astalgo, idents, types, msgs,
options
proc ptrToInt(x: PNode): int {.inline.} =
result = cast[int](x) # don't skip alignment
@@ -28,37 +29,38 @@ proc getField(n: PNode; position: int): PSym =
of nkOfBranch, nkElse:
result = getField(lastSon(n.sons[i]), position)
if result != nil: return
else: internalError(n.info, "getField(record case branch)")
else: discard
of nkSym:
if n.sym.position == position: result = n.sym
else: discard
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet)
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet; conf: ConfigRef)
proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet) =
internalAssert x.kind == nkObjConstr
proc storeObj(s: var string; typ: PType; x: PNode; stored: var IntSet; conf: ConfigRef) =
assert x.kind == nkObjConstr
let start = 1
for i in countup(start, sonsLen(x) - 1):
if i > start: s.add(", ")
var it = x.sons[i]
if it.kind == nkExprColonExpr:
internalAssert it.sons[0].kind == nkSym
let field = it.sons[0].sym
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it.sons[1], stored)
if it.sons[0].kind == nkSym:
let field = it.sons[0].sym
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it.sons[1], stored, conf)
elif typ.n != nil:
let field = getField(typ.n, i)
s.add(escapeJson(field.name.s))
s.add(": ")
storeAny(s, field.typ, it, stored)
storeAny(s, field.typ, it, stored, conf)
proc skipColon*(n: PNode): PNode =
result = n
if n.kind == nkExprColonExpr:
result = n.sons[1]
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet;
conf: ConfigRef) =
case t.kind
of tyNone: assert false
of tyBool: s.add($(a.intVal != 0))
@@ -74,7 +76,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
s.add("[")
for i in 0 .. a.len-1:
if i > 0: s.add(", ")
storeAny(s, t.elemType, a[i], stored)
storeAny(s, t.elemType, a[i], stored, conf)
s.add("]")
of tyTuple:
s.add("{")
@@ -82,11 +84,11 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
if i > 0: s.add(", ")
s.add("\"Field" & $i)
s.add("\": ")
storeAny(s, t.sons[i], a[i].skipColon, stored)
storeAny(s, t.sons[i], a[i].skipColon, stored, conf)
s.add("}")
of tyObject:
s.add("{")
storeObj(s, t, a, stored)
storeObj(s, t, a, stored, conf)
s.add("}")
of tySet:
s.add("[")
@@ -94,15 +96,16 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
if i > 0: s.add(", ")
if a[i].kind == nkRange:
var x = copyNode(a[i][0])
storeAny(s, t.lastSon, x, stored)
storeAny(s, t.lastSon, x, stored, conf)
while x.intVal+1 <= a[i][1].intVal:
s.add(", ")
storeAny(s, t.lastSon, x, stored)
storeAny(s, t.lastSon, x, stored, conf)
inc x.intVal
else:
storeAny(s, t.lastSon, a[i], stored)
storeAny(s, t.lastSon, a[i], stored, conf)
s.add("]")
of tyRange, tyGenericInst, tyAlias, tySink: storeAny(s, t.lastSon, a, stored)
of tyRange, tyGenericInst, tyAlias, tySink:
storeAny(s, t.lastSon, a, stored, conf)
of tyEnum:
# we need a slow linear search because of enums with holes:
for e in items(t.n):
@@ -121,7 +124,7 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
s.add("[")
s.add($x.ptrToInt)
s.add(", ")
storeAny(s, t.lastSon, a, stored)
storeAny(s, t.lastSon, a, stored, conf)
s.add("]")
of tyString, tyCString:
if a.kind == nkNilLit or a.strVal.isNil: s.add("null")
@@ -129,14 +132,15 @@ proc storeAny(s: var string; t: PType; a: PNode; stored: var IntSet) =
of tyInt..tyInt64, tyUInt..tyUInt64: s.add($a.intVal)
of tyFloat..tyFloat128: s.add($a.floatVal)
else:
internalError a.info, "cannot marshal at compile-time " & t.typeToString
internalError conf, a.info, "cannot marshal at compile-time " & t.typeToString
proc storeAny*(s: var string; t: PType; a: PNode) =
proc storeAny*(s: var string; t: PType; a: PNode; conf: ConfigRef) =
var stored = initIntSet()
storeAny(s, t, a, stored)
storeAny(s, t, a, stored, conf)
proc loadAny(p: var JsonParser, t: PType,
tab: var Table[BiggestInt, PNode]): PNode =
tab: var Table[BiggestInt, PNode];
conf: ConfigRef): PNode =
case t.kind
of tyNone: assert false
of tyBool:
@@ -170,7 +174,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkBracket)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.elemType, tab)
result.add loadAny(p, t.elemType, tab, conf)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
of tySequence:
@@ -182,7 +186,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkBracket)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.elemType, tab)
result.add loadAny(p, t.elemType, tab, conf)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "")
else:
@@ -198,7 +202,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
if i >= t.len:
raiseParseErr(p, "too many fields to tuple type " & typeToString(t))
result.add loadAny(p, t.sons[i], tab)
result.add loadAny(p, t.sons[i], tab, conf)
inc i
if p.kind == jsonObjectEnd: next(p)
else: raiseParseErr(p, "'}' end of object expected")
@@ -220,7 +224,7 @@ proc loadAny(p: var JsonParser, t: PType,
setLen(result.sons, pos + 1)
let fieldNode = newNode(nkExprColonExpr)
fieldNode.addSon(newSymNode(newSym(skField, ident, nil, unknownLineInfo())))
fieldNode.addSon(loadAny(p, field.typ, tab))
fieldNode.addSon(loadAny(p, field.typ, tab, conf))
result.sons[pos] = fieldNode
if p.kind == jsonObjectEnd: next(p)
else: raiseParseErr(p, "'}' end of object expected")
@@ -229,7 +233,7 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
result = newNode(nkCurly)
while p.kind != jsonArrayEnd and p.kind != jsonEof:
result.add loadAny(p, t.lastSon, tab)
result.add loadAny(p, t.lastSon, tab, conf)
next(p)
if p.kind == jsonArrayEnd: next(p)
else: raiseParseErr(p, "']' end of array expected")
@@ -248,7 +252,7 @@ proc loadAny(p: var JsonParser, t: PType,
if p.kind == jsonInt:
let idx = p.getInt
next(p)
result = loadAny(p, t.lastSon, tab)
result = loadAny(p, t.lastSon, tab, conf)
tab[idx] = result
else: raiseParseErr(p, "index for ref type expected")
if p.kind == jsonArrayEnd: next(p)
@@ -275,14 +279,15 @@ proc loadAny(p: var JsonParser, t: PType,
next(p)
return
raiseParseErr(p, "float expected")
of tyRange, tyGenericInst, tyAlias, tySink: result = loadAny(p, t.lastSon, tab)
of tyRange, tyGenericInst, tyAlias, tySink:
result = loadAny(p, t.lastSon, tab, conf)
else:
internalError "cannot marshal at compile-time " & t.typeToString
internalError conf, "cannot marshal at compile-time " & t.typeToString
proc loadAny*(s: string; t: PType): PNode =
proc loadAny*(s: string; t: PType; conf: ConfigRef): PNode =
var tab = initTable[BiggestInt, PNode]()
var p: JsonParser
open(p, newStringStream(s), "unknown file")
next(p)
result = loadAny(p, t, tab)
result = loadAny(p, t, tab, conf)
close(p)

View File

@@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
from options import gProjectPath
template mathop(op) {.dirty.} =
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
@@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord),
newStrNode(nkStrLit, f))
proc gorgeExWrapper(a: VmArgs) {.nimcall.} =
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
a.currentLineInfo)
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
proc getProjectPathWrapper(a: VmArgs) {.nimcall.} =
setResult a, gProjectPath
proc registerAdditionalOps*(c: PCtx) =
proc gorgeExWrapper(a: VmArgs) =
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
a.currentLineInfo, c.config)
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
proc getProjectPathWrapper(a: VmArgs) =
setResult a, c.config.projectPath
wrap1f_math(sqrt)
wrap1f_math(ln)
wrap1f_math(log10)

View File

@@ -15,7 +15,7 @@
## * Computing an aliasing relation based on the assignments. This relation
## is then used to compute the 'writes' and 'escapes' effects.
import intsets, idents, ast, astalgo, trees, renderer, msgs, types
import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options
const
debug = false
@@ -180,7 +180,7 @@ proc deps(w: var W; n: PNode) =
let last = lastSon(child)
if last.kind == nkEmpty: continue
if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}:
internalAssert child.len-2 == last.len
if child.len-2 != last.len: return
for i in 0 .. child.len-3:
deps(w, child.sons[i], last.sons[i], {})
else:
@@ -220,7 +220,7 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
# x = f(..., y, ....)
for i in 0 ..< a.srcNoTc: addNoDup a.src[i]
proc markWriteOrEscape(w: var W) =
proc markWriteOrEscape(w: var W; conf: ConfigRef) =
## Both 'writes' and 'escapes' effects ultimately only care
## about *parameters*.
## However, due to aliasing, even locals that might not look as parameters
@@ -249,7 +249,7 @@ proc markWriteOrEscape(w: var W) =
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)
localError(conf, a.info, "write access to non-var parameter: " & p.name.s)
if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
var destIsParam = false
@@ -263,14 +263,14 @@ proc markWriteOrEscape(w: var W) =
if p.kind == skParam and p.owner == w.owner:
incl(p.flags, sfEscapes)
proc trackWrites*(owner: PSym; body: PNode) =
proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) =
var w: W
w.owner = owner
w.assignments = @[]
# Phase 1: Collect and preprocess any assignments in the proc body:
deps(w, body)
# Phase 2: Compute the 'writes' and 'escapes' effects:
markWriteOrEscape(w)
markWriteOrEscape(w, conf)
if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and
containsGarbageCollectedRef(owner.typ.sons[0]):
incl(owner.typ.flags, tfReturnsNew)

Some files were not shown because too many files have changed in this diff Show More