diff options
Diffstat (limited to 'compiler')
100 files changed, 5403 insertions, 5342 deletions
diff --git a/compiler/aliases.nim b/compiler/aliases.nim index 490ac987a..f79210dd7 100644 --- a/compiler/aliases.nim +++ b/compiler/aliases.nim @@ -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 diff --git a/compiler/ast.nim b/compiler/ast.nim index 2cace380d..5a84b2b02 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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}) diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index a35fa4fbb..d98a42b34 100644 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -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 = diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2ddc88509..7d355db5f 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -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, ~" ") diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 5b3f6c3d2..352402e0e 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -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, d) - 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] diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index b17a5eedd..cfe71375e 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -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") diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index f667be70f..4b4f9c0e6 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -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: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 510dbfc18..91a3add70 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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 @@ -165,7 +165,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") @@ -184,7 +184,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): @@ -228,7 +228,7 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) = 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]) @@ -362,7 +362,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) proc genReturnStmt(p: BProc, t: PNode) = @@ -386,7 +386,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]) @@ -401,19 +401,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] @@ -447,7 +447,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)]) @@ -551,7 +551,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, @@ -574,7 +574,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", @@ -582,7 +582,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") @@ -879,17 +879,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) @@ -1016,7 +1013,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) @@ -1142,4 +1139,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} diff --git a/compiler/ccgthreadvars.nim b/compiler/ccgthreadvars.nim index 505b69eab..da5c624b7 100644 --- a/compiler/ccgthreadvars.nim +++ b/compiler/ccgthreadvars.nim @@ -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], diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 1bb2ba98d..c265064a1 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -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 diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 56fb379bd..7b44cddad 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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: diff --git a/compiler/ccgutils.nim b/compiler/ccgutils.nim index 48648bdde..a6080a808 100644 --- a/compiler/ccgutils.nim +++ b/compiler/ccgutils.nim @@ -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() = diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 693930fbc..133e86cea 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -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 @@ -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,21 +1149,21 @@ 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)) @@ -1176,9 +1173,9 @@ proc genInitCode(m: BModule) = [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) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index f8167acdc..ce3fc2f90 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -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): diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim index 0513e88f4..1d72952e2 100644 --- a/compiler/cgmeth.nim +++ b/compiler/cgmeth.nim @@ -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))) diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim index 193a812e1..86b63e34b 100644 --- a/compiler/closureiters.nim +++ b/compiler/closureiters.nim @@ -132,10 +132,11 @@ import intsets, strutils, options, ast, astalgo, trees, treetab, msgs, idents, - renderer, types, magicsys, rodread, lowerings, lambdalifting + renderer, types, magicsys, rodread, lowerings, lambdalifting, modulegraphs type Ctx = object + g: ModuleGraph fn: PSym stateVarSym: PSym # :state variable. nil if env already introduced by lambdalifting tmpResultSym: PSym # Used when we return, but finally has to interfere @@ -156,7 +157,8 @@ type proc newStateAccess(ctx: var Ctx): PNode = if ctx.stateVarSym.isNil: - result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), getStateField(ctx.fn), ctx.fn.info) + result = rawIndirectAccess(newSymNode(getEnvParam(ctx.fn)), + getStateField(ctx.g, ctx.fn), ctx.fn.info) else: result = newSymNode(ctx.stateVarSym) @@ -168,7 +170,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode = proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode = # Creates state assignment: # :state = stateNo - ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt))) + ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt))) proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym = result = newSym(skVar, getIdent(name), ctx.fn, ctx.fn.info) @@ -197,14 +199,14 @@ proc newTmpResultAccess(ctx: var Ctx): PNode = ctx.tmpResultSym = ctx.newEnvVar(":tmpResult", ctx.fn.typ[0]) ctx.newEnvVarAccess(ctx.tmpResultSym) -proc newUnrollFinallyAccess(ctx: var Ctx): PNode = +proc newUnrollFinallyAccess(ctx: var Ctx, info: TLineInfo): PNode = if ctx.unrollFinallySym.isNil: - ctx.unrollFinallySym = ctx.newEnvVar(":unrollFinally", getSysType(tyBool)) + ctx.unrollFinallySym = ctx.newEnvVar(":unrollFinally", ctx.g.getSysType(info, tyBool)) ctx.newEnvVarAccess(ctx.unrollFinallySym) proc newCurExcAccess(ctx: var Ctx): PNode = if ctx.curExcSym.isNil: - ctx.curExcSym = ctx.newEnvVar(":curExc", callCodegenProc("getCurrentException", emptyNode).typ) + ctx.curExcSym = ctx.newEnvVar(":curExc", ctx.g.callCodegenProc("getCurrentException", emptyNode).typ) ctx.newEnvVarAccess(ctx.curExcSym) proc newState(ctx: var Ctx, n, gotoOut: PNode): int = @@ -213,7 +215,7 @@ proc newState(ctx: var Ctx, n, gotoOut: PNode): int = # Returns index of the newly created state result = ctx.states.len - let resLit = newIntLit(result) + let resLit = ctx.g.newIntLit(n.info, result) let s = newNodeI(nkState, n.info) s.add(resLit) s.add(n) @@ -222,7 +224,7 @@ proc newState(ctx: var Ctx, n, gotoOut: PNode): int = if not gotoOut.isNil: assert(gotoOut.len == 0) - gotoOut.add(newIntLit(result)) + gotoOut.add(ctx.g.newIntLit(gotoOut.info, result)) proc toStmtList(n: PNode): PNode = result = n @@ -303,13 +305,14 @@ proc newNullifyCurExc(ctx: var Ctx, info: TLineInfo): PNode = nilnode.typ = curExc.typ result = newTree(nkAsgn, curExc, nilnode) -proc newOr(a, b: PNode): PNode {.inline.} = - result = newTree(nkCall, newSymNode(getSysMagic("or", mOr)), a, b) - result.typ = getSysType(tyBool) +proc newOr(g: ModuleGraph, a, b: PNode): PNode {.inline.} = + result = newTree(nkCall, newSymNode(g.getSysMagic(a.info, "or", mOr)), a, b) + result.typ = g.getSysType(a.info, tyBool) result.info = a.info proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} = var ifStmt = newNodeI(nkIfStmt, n.info) + let g = ctx.g for c in n: if c.kind == nkExceptBranch: var ifBranch: PNode @@ -319,16 +322,16 @@ proc collectExceptState(ctx: var Ctx, n: PNode): PNode {.inline.} = for i in 0 .. c.len - 2: assert(c[i].kind == nkType) let nextCond = newTree(nkCall, - newSymNode(getSysMagic("of", mOf)), - callCodegenProc("getCurrentException", emptyNode), + newSymNode(g.getSysMagic(c.info, "of", mOf)), + g.callCodegenProc("getCurrentException", emptyNode), c[i]) - nextCond.typ = getSysType(tyBool) + nextCond.typ = ctx.g.getSysType(c.info, tyBool) nextCond.info = c.info if cond.isNil: cond = nextCond else: - cond = newOr(cond, nextCond) + cond = g.newOr(cond, nextCond) ifBranch = newNodeI(nkElifBranch, c.info) ifBranch.add(cond) @@ -354,16 +357,16 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) = block: # :unrollFinally = true branchBody.add(newTree(nkAsgn, - ctx.newUnrollFinallyAccess(), - newIntTypeNode(nkIntLit, 1, getSysType(tyBool)))) + ctx.newUnrollFinallyAccess(n.info), + newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool)))) block: # :curExc = getCurrentException() branchBody.add(newTree(nkAsgn, ctx.newCurExcAccess(), - callCodegenProc("getCurrentException", emptyNode))) + ctx.g.callCodegenProc("getCurrentException", emptyNode))) block: # goto nearestFinally - branchBody.add(newTree(nkGotoState, newIntLit(ctx.nearestFinally))) + branchBody.add(newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally))) let elseBranch = newTree(nkElse, branchBody) n[1].add(elseBranch) @@ -423,9 +426,9 @@ proc convertExprBodyToAsgn(ctx: Ctx, exprBody: PNode, res: PSym): PNode = result = newNodeI(nkStmtList, exprBody.info) ctx.addExprAssgn(result, exprBody, res) -proc newNotCall(e: PNode): PNode = - result = newTree(nkCall, newSymNode(getSysMagic("not", mNot), e.info), e) - result.typ = getSysType(tyBool) +proc newNotCall(g: ModuleGraph; e: PNode): PNode = + result = newTree(nkCall, newSymNode(g.getSysMagic(e.info, "not", mNot), e.info), e) + result.typ = g.getSysType(e.info, tyBool) proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = result = n @@ -458,7 +461,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = needsSplit = true result = newNodeI(nkStmtListExpr, n.info) - if n.typ.isNil: internalError("lowerStmtListExprs: constr typ.isNil") + if n.typ.isNil: internalError(ctx.g.config, "lowerStmtListExprs: constr typ.isNil") result.typ = n.typ for i in 0 ..< n.len: @@ -530,7 +533,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = newBranch[1] = branchBody else: - internalError("lowerStmtListExpr(nkIf): " & $branch.kind) + internalError(ctx.g.config, "lowerStmtListExpr(nkIf): " & $branch.kind) if isExpr: result.add(ctx.newEnvVarAccess(tmp)) @@ -560,7 +563,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = of nkFinally: discard else: - internalError("lowerStmtListExpr(nkTryStmt): " & $branch.kind) + internalError(ctx.g.config, "lowerStmtListExpr(nkTryStmt): " & $branch.kind) result.add(n) result.add(ctx.newEnvVarAccess(tmp)) @@ -592,7 +595,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = of nkElse: branch[0] = ctx.convertExprBodyToAsgn(branch[0], tmp) else: - internalError("lowerStmtListExpr(nkCaseStmt): " & $branch.kind) + internalError(ctx.g.config, "lowerStmtListExpr(nkCaseStmt): " & $branch.kind) result.add(n) result.add(ctx.newEnvVarAccess(tmp)) @@ -623,7 +626,7 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = var check = ctx.newEnvVarAccess(tmp) if n[0].sym.magic == mOr: - check = newNotCall(check) + check = ctx.g.newNotCall(check) cond = n[2] let ifBody = newNodeI(nkStmtList, cond.info) @@ -727,11 +730,11 @@ proc lowerStmtListExprs(ctx: var Ctx, n: PNode, needsSplit: var bool): PNode = if condNeedsSplit: let (st, ex) = exprToStmtList(n[0]) let brk = newTree(nkBreakStmt, emptyNode) - let branch = newTree(nkElifBranch, newNotCall(ex), brk) + let branch = newTree(nkElifBranch, ctx.g.newNotCall(ex), brk) let check = newTree(nkIfStmt, branch) let newBody = newTree(nkStmtList, st, check, n[1]) - n[0] = newSymNode(getSysSym("true")) + n[0] = newSymNode(ctx.g.getSysSym(n[0].info, "true")) n[1] = newBody else: for i in 0 ..< n.len: @@ -747,8 +750,8 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode = let curExc = ctx.newCurExcAccess() let nilnode = newNode(nkNilLit) nilnode.typ = curExc.typ - let cmp = newTree(nkCall, newSymNode(getSysMagic("==", mEqRef), info), curExc, nilnode) - cmp.typ = getSysType(tyBool) + let cmp = newTree(nkCall, newSymNode(ctx.g.getSysMagic(info, "==", mEqRef), info), curExc, nilnode) + cmp.typ = ctx.g.getSysType(info, tyBool) let asgn = newTree(nkFastAsgn, newSymNode(getClosureIterResult(ctx.fn), info), @@ -758,12 +761,12 @@ proc newEndFinallyNode(ctx: var Ctx, info: TLineInfo): PNode = let branch = newTree(nkElifBranch, cmp, retStmt) # The C++ backend requires `getCurrentException` here. - let raiseStmt = newTree(nkRaiseStmt, callCodegenProc("getCurrentException", emptyNode)) + let raiseStmt = newTree(nkRaiseStmt, ctx.g.callCodegenProc("getCurrentException", emptyNode)) raiseStmt.info = info let elseBranch = newTree(nkElse, raiseStmt) let ifBody = newTree(nkIfStmt, branch, elseBranch) - let elifBranch = newTree(nkElifBranch, ctx.newUnrollFinallyAccess(), ifBody) + let elifBranch = newTree(nkElifBranch, ctx.newUnrollFinallyAccess(info), ifBody) elifBranch.info = info result = newTree(nkIfStmt, elifBranch) @@ -779,8 +782,8 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = block: # :unrollFinally = true let asgn = newNodeI(nkAsgn, n.info) - asgn.add(ctx.newUnrollFinallyAccess()) - asgn.add(newIntTypeNode(nkIntLit, 1, getSysType(tyBool))) + asgn.add(ctx.newUnrollFinallyAccess(n.info)) + asgn.add(newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool))) result.add(asgn) if n[0].kind != nkEmpty: @@ -791,8 +794,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode = result.add(ctx.newNullifyCurExc(n.info)) - let goto = newNodeI(nkGotoState, n.info) - goto.add(newIntLit(ctx.nearestFinally)) + let goto = newTree(nkGotoState, ctx.g.newIntLit(n.info, ctx.nearestFinally)) result.add(goto) of nkCharLit..nkUInt64Lit, nkFloatLit..nkFloat128Lit, nkStrLit..nkTripleStrLit, @@ -831,7 +833,7 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode n.sons.setLen(i + 1) discard ctx.newState(s, go) if ctx.transformClosureIteratorBody(s, gotoOut) != s: - internalError("transformClosureIteratorBody != s") + internalError(ctx.g.config, "transformClosureIteratorBody != s") break of nkYieldStmt: @@ -940,24 +942,24 @@ proc transformClosureIteratorBody(ctx: var Ctx, n: PNode, gotoOut: PNode): PNode ctx.curExcHandlingState = exceptIdx if ctx.transformReturnsInTry(tryBody) != tryBody: - internalError("transformReturnsInTry != tryBody") + internalError(ctx.g.config, "transformReturnsInTry != tryBody") if ctx.transformClosureIteratorBody(tryBody, outToFinally) != tryBody: - internalError("transformClosureIteratorBody != tryBody") + internalError(ctx.g.config, "transformClosureIteratorBody != tryBody") ctx.curExcHandlingState = finallyIdx ctx.addElseToExcept(exceptBody) if ctx.transformReturnsInTry(exceptBody) != exceptBody: - internalError("transformReturnsInTry != exceptBody") + internalError(ctx.g.config, "transformReturnsInTry != exceptBody") if ctx.transformClosureIteratorBody(exceptBody, outToFinally) != exceptBody: - internalError("transformClosureIteratorBody != exceptBody") + internalError(ctx.g.config, "transformClosureIteratorBody != exceptBody") ctx.curExcHandlingState = oldExcHandlingState ctx.nearestFinally = oldNearestFinally if ctx.transformClosureIteratorBody(finallyBody, gotoOut) != finallyBody: - internalError("transformClosureIteratorBody != finallyBody") + internalError(ctx.g.config, "transformClosureIteratorBody != finallyBody") of nkGotoState, nkForStmt: - internalError("closure iter " & $n.kind) + internalError(ctx.g.config, "closure iter " & $n.kind) else: for i in 0 ..< n.len: @@ -1074,11 +1076,11 @@ proc skipThroughEmptyStates(ctx: var Ctx, n: PNode): PNode = for i in 0 ..< n.len: n[i] = ctx.skipThroughEmptyStates(n[i]) -proc newArrayType(n: int, t: PType, owner: PSym): PType = +proc newArrayType(g: ModuleGraph; n: int, t: PType, owner: PSym): PType = result = newType(tyArray, owner) let rng = newType(tyRange, owner) - rng.n = newTree(nkRange, newIntLit(0), newIntLit(n)) + rng.n = newTree(nkRange, g.newIntLit(owner.info, 0), g.newIntLit(owner.info, n)) rng.rawAddSon(t) result.rawAddSon(rng) @@ -1086,14 +1088,14 @@ proc newArrayType(n: int, t: PType, owner: PSym): PType = proc createExceptionTable(ctx: var Ctx): PNode {.inline.} = result = newNodeI(nkBracket, ctx.fn.info) - result.typ = newArrayType(ctx.exceptionTable.len, getSysType(tyInt16), ctx.fn) + result.typ = ctx.g.newArrayType(ctx.exceptionTable.len, ctx.g.getSysType(ctx.fn.info, tyInt16), ctx.fn) for i in ctx.exceptionTable: let elem = newIntNode(nkIntLit, i) - elem.typ = getSysType(tyInt16) + elem.typ = ctx.g.getSysType(ctx.fn.info, tyInt16) result.add(elem) -proc newCatchBody(ctx: var Ctx): PNode {.inline.} = +proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} = # Generates the code: # :state = exceptionTable[:state] # if :state == 0: raise @@ -1102,7 +1104,10 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} = # :state = -:state # :curExc = getCurrentException() - result = newNodeI(nkStmtList, ctx.fn.info) + result = newNodeI(nkStmtList, info) + + let intTyp = ctx.g.getSysType(info, tyInt) + let boolTyp = ctx.g.getSysType(info, tyBool) # :state = exceptionTable[:state] block: @@ -1111,7 +1116,7 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} = let getNextState = newTree(nkBracketExpr, ctx.createExceptionTable(), ctx.newStateAccess()) - getNextState.typ = getSysType(tyInt) + getNextState.typ = intTyp # :state = exceptionTable[:state] result.add(ctx.newStateAssgn(getNextState)) @@ -1119,10 +1124,10 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} = # if :state == 0: raise block: let cond = newTree(nkCall, - getSysMagic("==", mEqI).newSymNode(), + ctx.g.getSysMagic(info, "==", mEqI).newSymNode(), ctx.newStateAccess(), - newIntTypeNode(nkIntLit, 0, getSysType(tyInt))) - cond.typ = getSysType(tyBool) + newIntTypeNode(nkIntLit, 0, intTyp)) + cond.typ = boolTyp let raiseStmt = newTree(nkRaiseStmt, emptyNode) let ifBranch = newTree(nkElifBranch, cond, raiseStmt) @@ -1132,26 +1137,26 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} = # :unrollFinally = :state > 0 block: let cond = newTree(nkCall, - getSysMagic("<", mLtI).newSymNode, - newIntTypeNode(nkIntLit, 0, getSysType(tyInt)), + ctx.g.getSysMagic(info, "<", mLtI).newSymNode, + newIntTypeNode(nkIntLit, 0, intTyp), ctx.newStateAccess()) - cond.typ = getSysType(tyBool) + cond.typ = boolTyp - let asgn = newTree(nkAsgn, ctx.newUnrollFinallyAccess(), cond) + let asgn = newTree(nkAsgn, ctx.newUnrollFinallyAccess(info), cond) result.add(asgn) # if :state < 0: :state = -:state block: let cond = newTree(nkCall, - getSysMagic("<", mLtI).newSymNode, + ctx.g.getSysMagic(info, "<", mLtI).newSymNode, ctx.newStateAccess(), - newIntTypeNode(nkIntLit, 0, getSysType(tyInt))) - cond.typ = getSysType(tyBool) + newIntTypeNode(nkIntLit, 0, intTyp)) + cond.typ = boolTyp let negateState = newTree(nkCall, - getSysMagic("-", mUnaryMinusI).newSymNode, + ctx.g.getSysMagic(info, "-", mUnaryMinusI).newSymNode, ctx.newStateAccess()) - negateState.typ = getSysType(tyInt) + negateState.typ = intTyp let ifBranch = newTree(nkElifBranch, cond, ctx.newStateAssgn(negateState)) let ifStmt = newTree(nkIfStmt, ifBranch) @@ -1161,15 +1166,15 @@ proc newCatchBody(ctx: var Ctx): PNode {.inline.} = block: result.add(newTree(nkAsgn, ctx.newCurExcAccess(), - callCodegenProc("getCurrentException", emptyNode))) + ctx.g.callCodegenProc("getCurrentException", emptyNode))) proc wrapIntoTryExcept(ctx: var Ctx, n: PNode): PNode {.inline.} = let setupExc = newTree(nkCall, - newSymNode(getCompilerProc("closureIterSetupExc")), + newSymNode(ctx.g.getCompilerProc("closureIterSetupExc")), ctx.newCurExcAccess()) let tryBody = newTree(nkStmtList, setupExc, n) - let exceptBranch = newTree(nkExceptBranch, ctx.newCatchBody()) + let exceptBranch = newTree(nkExceptBranch, ctx.newCatchBody(ctx.fn.info)) result = newTree(nkTryStmt, tryBody, exceptBranch) @@ -1179,7 +1184,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode = # gotoState :state # body # Might get wrapped in try-except let loopBody = newNodeI(nkStmtList, n.info) - result = newTree(nkWhileStmt, newSymNode(getSysSym("true")), loopBody) + result = newTree(nkWhileStmt, newSymNode(ctx.g.getSysSym(n.info, "true")), loopBody) result.info = n.info if not ctx.stateVarSym.isNil: @@ -1195,7 +1200,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode = let gs = newNodeI(nkGotoState, n.info) gs.add(ctx.newStateAccess()) - gs.add(newIntLit(ctx.states.len - 1)) + gs.add(ctx.g.newIntLit(n.info, ctx.states.len - 1)) var blockBody = newTree(nkStmtList, gs, n) if ctx.hasExceptions: @@ -1205,7 +1210,7 @@ proc wrapIntoStateLoop(ctx: var Ctx, n: PNode): PNode = loopBody.add(blockStmt) proc deleteEmptyStates(ctx: var Ctx) = - let goOut = newTree(nkGotoState, newIntLit(-1)) + let goOut = newTree(nkGotoState, ctx.g.newIntLit(TLineInfo(), -1)) ctx.exitStateIdx = ctx.newState(goOut, nil) # Apply new state indexes and mark unused states with -1 @@ -1238,8 +1243,9 @@ proc deleteEmptyStates(ctx: var Ctx) = else: inc i -proc transformClosureIterator*(fn: PSym, n: PNode): PNode = +proc transformClosureIterator*(g: ModuleGraph; fn: PSym, n: PNode): PNode = var ctx: Ctx + ctx.g = g ctx.fn = fn if getEnvParam(fn).isNil: @@ -1247,13 +1253,13 @@ proc transformClosureIterator*(fn: PSym, n: PNode): PNode = # be handled specially by lambda lifting. Local temp vars (if needed) # should folllow the same logic. ctx.stateVarSym = newSym(skVar, getIdent(":state"), fn, fn.info) - ctx.stateVarSym.typ = createClosureIterStateType(fn) + ctx.stateVarSym.typ = g.createClosureIterStateType(fn) ctx.stateLoopLabel = newSym(skLabel, getIdent(":stateLoop"), fn, fn.info) let n = n.toStmtList discard ctx.newState(n, nil) - let gotoOut = newTree(nkGotoState, newIntLit(-1)) + let gotoOut = newTree(nkGotoState, g.newIntLit(n.info, -1)) # Splitting transformation discard ctx.transformClosureIteratorBody(n, gotoOut) diff --git a/compiler/commands.nim b/compiler/commands.nim index d8d8ae4b7..09f63f0f5 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -18,7 +18,6 @@ template bootSwitch(name, expr, userString) = bootSwitch(usedRelease, defined(release), "-d:release") bootSwitch(usedGnuReadline, defined(useLinenoise), "-d:useLinenoise") -bootSwitch(usedNoCaas, defined(noCaas), "-d:noCaas") bootSwitch(usedBoehm, defined(boehmgc), "--gc:boehm") bootSwitch(usedMarkAndSweep, defined(gcmarkandsweep), "--gc:markAndSweep") bootSwitch(usedGenerational, defined(gcgenerational), "--gc:generational") @@ -27,34 +26,24 @@ bootSwitch(usedNoGC, defined(nogc), "--gc:none") import os, msgs, options, nversion, condsyms, strutils, extccomp, platform, - wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils + wordrecg, parseutils, nimblecmd, idents, parseopt, sequtils, configuration # but some have deps to imported modules. Yay. bootSwitch(usedTinyC, hasTinyCBackend, "-d:tinyc") -bootSwitch(usedAvoidTimeMachine, noTimeMachine, "-d:avoidTimeMachine") bootSwitch(usedNativeStacktrace, defined(nativeStackTrace) and nativeStackTraceSupported, "-d:nativeStackTrace") bootSwitch(usedFFI, hasFFI, "-d:useFFI") - -proc writeCommandLineUsage*() - type TCmdLinePass* = enum passCmd1, # first pass over the command line passCmd2, # second pass over the command line passPP # preprocessor called processCommand() -proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) -proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef) - -# implementation - const HelpMessage = "Nim Compiler Version $1 [$2: $3]\n" & - "Compiled at $4 $5\n" & + "Compiled at $4\n" & "Copyright (c) 2006-" & copyrightYear & " by Andreas Rumpf\n" const @@ -69,66 +58,68 @@ const proc getCommandLineDesc(): string = result = (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & Usage -proc helpOnError(pass: TCmdLinePass) = +proc helpOnError(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(getCommandLineDesc(), {msgStdout}) + msgWriteln(conf, getCommandLineDesc(), {msgStdout}) msgQuit(0) -proc writeAdvancedUsage(pass: TCmdLinePass) = +proc writeAdvancedUsage(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, (HelpMessage % [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & AdvancedUsage, {msgStdout}) msgQuit(0) -proc writeFullhelp(pass: TCmdLinePass) = +proc writeFullhelp(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]) & + CPU[platform.hostCPU].name, CompileDate]) & Usage & AdvancedUsage, {msgStdout}) msgQuit(0) -proc writeVersionInfo(pass: TCmdLinePass) = +proc writeVersionInfo(conf: ConfigRef; pass: TCmdLinePass) = if pass == passCmd1: - msgWriteln(`%`(HelpMessage, [VersionAsString, + msgWriteln(conf, `%`(HelpMessage, [VersionAsString, platform.OS[platform.hostOS].name, - CPU[platform.hostCPU].name, CompileDate, CompileTime]), + CPU[platform.hostCPU].name, CompileDate]), {msgStdout}) const gitHash = gorge("git log -n 1 --format=%H").strip when gitHash.len == 40: - msgWriteln("git hash: " & gitHash, {msgStdout}) + msgWriteln(conf, "git hash: " & gitHash, {msgStdout}) - msgWriteln("active boot switches:" & usedRelease & usedAvoidTimeMachine & - usedTinyC & usedGnuReadline & usedNativeStacktrace & usedNoCaas & + msgWriteln(conf, "active boot switches:" & usedRelease & + usedTinyC & usedGnuReadline & usedNativeStacktrace & usedFFI & usedBoehm & usedMarkAndSweep & usedGenerational & usedGoGC & usedNoGC, {msgStdout}) msgQuit(0) -var - helpWritten: bool - -proc writeCommandLineUsage() = +proc writeCommandLineUsage*(conf: ConfigRef; helpWritten: var bool) = if not helpWritten: - msgWriteln(getCommandLineDesc(), {msgStdout}) + msgWriteln(conf, getCommandLineDesc(), {msgStdout}) helpWritten = true proc addPrefix(switch: string): string = if len(switch) == 1: result = "-" & switch else: result = "--" & switch -proc invalidCmdLineOption(pass: TCmdLinePass, switch: string, info: TLineInfo) = - if switch == " ": localError(info, errInvalidCmdLineOption, "-") - else: localError(info, errInvalidCmdLineOption, addPrefix(switch)) +const + errInvalidCmdLineOption = "invalid command line option: '$1'" + errOnOrOffExpectedButXFound = "'on' or 'off' expected, but '$1' found" + errOnOffOrListExpectedButXFound = "'on', 'off' or 'list' expected, but '$1' found" + +proc invalidCmdLineOption(conf: ConfigRef; pass: TCmdLinePass, switch: string, info: TLineInfo) = + if switch == " ": localError(conf, info, errInvalidCmdLineOption % "-") + else: localError(conf, info, errInvalidCmdLineOption % addPrefix(switch)) -proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, +proc splitSwitch(conf: ConfigRef; switch: string, cmd, arg: var string, pass: TCmdLinePass, info: TLineInfo) = cmd = "" var i = 0 @@ -141,46 +132,41 @@ proc splitSwitch(switch: string, cmd, arg: var string, pass: TCmdLinePass, inc(i) if i >= len(switch): arg = "" elif switch[i] in {':', '=', '['}: arg = substr(switch, i + 1) - else: invalidCmdLineOption(pass, switch, info) + else: invalidCmdLineOption(conf, pass, switch, info) -proc processOnOffSwitch(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitch(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) + of "on": conf.options = conf.options + op + of "off": conf.options = conf.options - op + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc processOnOffSwitchOrList(op: TOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchOrList(conf: ConfigRef; op: TOptions, arg: string, pass: TCmdLinePass, info: TLineInfo): bool = result = false case arg.normalize - of "on": gOptions = gOptions + op - of "off": gOptions = gOptions - op - else: - if arg == "list": - result = true - else: - localError(info, errOnOffOrListExpectedButXFound, arg) + of "on": conf.options = conf.options + op + of "off": conf.options = conf.options - op + of "list": result = true + else: localError(conf, info, errOnOffOrListExpectedButXFound % arg) -proc processOnOffSwitchG(op: TGlobalOptions, arg: string, pass: TCmdLinePass, +proc processOnOffSwitchG(conf: ConfigRef; op: TGlobalOptions, arg: string, pass: TCmdLinePass, info: TLineInfo) = case arg.normalize - of "on": gGlobalOptions = gGlobalOptions + op - of "off": gGlobalOptions = gGlobalOptions - op - else: localError(info, errOnOrOffExpectedButXFound, arg) - -proc expectArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg == "": localError(info, errCmdLineArgExpected, addPrefix(switch)) + of "on": conf.globalOptions = conf.globalOptions + op + of "off": conf.globalOptions = conf.globalOptions - op + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) -proc expectNoArg(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = - if arg != "": localError(info, errCmdLineNoArgExpected, addPrefix(switch)) +proc expectArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg == "": + localError(conf, info, "argument for command line option expected: '$1'" % addPrefix(switch)) -var - enableNotes: TNoteKinds - disableNotes: TNoteKinds +proc expectNoArg(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = + if arg != "": + localError(conf, info, "invalid argument for command line option: '$1'" % addPrefix(switch)) proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, - info: TLineInfo; orig: string) = + info: TLineInfo; orig: string; conf: ConfigRef) = var id = "" # arg = "X]:on|off" var i = 0 var n = hintMin @@ -188,122 +174,127 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, add(id, arg[i]) inc(i) if i < len(arg) and (arg[i] == ']'): inc(i) - else: invalidCmdLineOption(pass, orig, info) + else: invalidCmdLineOption(conf, pass, orig, info) if i < len(arg) and (arg[i] in {':', '='}): inc(i) - else: invalidCmdLineOption(pass, orig, info) + else: invalidCmdLineOption(conf, pass, orig, info) if state == wHint: - let x = findStr(msgs.HintsToStr, id) + let x = findStr(configuration.HintsToStr, id) if x >= 0: n = TNoteKind(x + ord(hintMin)) - else: localError(info, "unknown hint: " & id) + else: localError(conf, info, "unknown hint: " & id) else: - let x = findStr(msgs.WarningsToStr, id) + let x = findStr(configuration.WarningsToStr, id) if x >= 0: n = TNoteKind(x + ord(warnMin)) - else: localError(info, "unknown warning: " & id) + else: localError(conf, info, "unknown warning: " & id) case substr(arg, i).normalize of "on": - incl(gNotes, n) - incl(gMainPackageNotes, n) - incl(enableNotes, n) + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) + incl(conf.enableNotes, n) of "off": - excl(gNotes, n) - excl(gMainPackageNotes, n) - incl(disableNotes, n) - excl(ForeignPackageNotes, n) - else: localError(info, errOnOrOffExpectedButXFound, arg) - -proc processCompile(filename: string) = - var found = findFile(filename) + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + incl(conf.disableNotes, n) + excl(conf.foreignPackageNotes, n) + else: localError(conf, info, errOnOrOffExpectedButXFound % arg) + +proc processCompile(conf: ConfigRef; filename: string) = + var found = findFile(conf, filename) if found == "": found = filename - extccomp.addExternalFileToCompile(found) + extccomp.addExternalFileToCompile(conf, found) + +const + 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" -proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = +proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo): bool = case switch.normalize of "gc": case arg.normalize - of "boehm": result = gSelectedGC == gcBoehm - of "refc": result = gSelectedGC == gcRefc - of "v2": result = gSelectedGC == gcV2 - of "markandsweep": result = gSelectedGC == gcMarkAndSweep - of "generational": result = gSelectedGC == gcGenerational - of "go": result = gSelectedGC == gcGo - of "none": result = gSelectedGC == gcNone - of "stack", "regions": result = gSelectedGC == gcRegions - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + of "boehm": result = conf.selectedGC == gcBoehm + of "refc": result = conf.selectedGC == gcRefc + of "v2": result = conf.selectedGC == gcV2 + of "markandsweep": result = conf.selectedGC == gcMarkAndSweep + of "generational": result = conf.selectedGC == gcGenerational + of "go": result = conf.selectedGC == gcGo + of "none": result = conf.selectedGC == gcNone + of "stack", "regions": result = conf.selectedGC == gcRegions + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "opt": case arg.normalize - of "speed": result = contains(gOptions, optOptimizeSpeed) - of "size": result = contains(gOptions, optOptimizeSize) - of "none": result = gOptions * {optOptimizeSpeed, optOptimizeSize} == {} - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) - of "verbosity": result = $gVerbosity == arg + of "speed": result = contains(conf.options, optOptimizeSpeed) + of "size": result = contains(conf.options, optOptimizeSize) + of "none": result = conf.options * {optOptimizeSpeed, optOptimizeSize} == {} + else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) + of "verbosity": result = $conf.verbosity == arg of "app": case arg.normalize - of "gui": result = contains(gGlobalOptions, optGenGuiApp) - of "console": result = not contains(gGlobalOptions, optGenGuiApp) - of "lib": result = contains(gGlobalOptions, optGenDynLib) and - not contains(gGlobalOptions, optGenGuiApp) - of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and - not contains(gGlobalOptions, optGenGuiApp) - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + of "gui": result = contains(conf.globalOptions, optGenGuiApp) + of "console": result = not contains(conf.globalOptions, optGenGuiApp) + of "lib": result = contains(conf.globalOptions, optGenDynLib) and + not contains(conf.globalOptions, optGenGuiApp) + of "staticlib": result = contains(conf.globalOptions, optGenStaticLib) and + not contains(conf.globalOptions, optGenGuiApp) + else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "dynliboverride": - result = isDynlibOverride(arg) - else: invalidCmdLineOption(passCmd1, switch, info) + result = isDynlibOverride(conf, arg) + else: invalidCmdLineOption(conf, passCmd1, switch, info) -proc testCompileOption*(switch: string, info: TLineInfo): bool = +proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool = case switch.normalize - of "debuginfo": result = contains(gGlobalOptions, optCDebug) - of "compileonly", "c": result = contains(gGlobalOptions, optCompileOnly) - of "nolinking": result = contains(gGlobalOptions, optNoLinking) - of "nomain": result = contains(gGlobalOptions, optNoMain) - of "forcebuild", "f": result = contains(gGlobalOptions, optForceFullMake) - of "warnings", "w": result = contains(gOptions, optWarns) - of "hints": result = contains(gOptions, optHints) - of "threadanalysis": result = contains(gGlobalOptions, optThreadAnalysis) - of "stacktrace": result = contains(gOptions, optStackTrace) - of "linetrace": result = contains(gOptions, optLineTrace) - of "debugger": result = contains(gOptions, optEndb) - of "profiler": result = contains(gOptions, optProfiler) - of "memtracker": result = contains(gOptions, optMemTracker) - of "checks", "x": result = gOptions * ChecksOptions == ChecksOptions + of "debuginfo": result = contains(conf.globalOptions, optCDebug) + of "compileonly", "c": result = contains(conf.globalOptions, optCompileOnly) + of "nolinking": result = contains(conf.globalOptions, optNoLinking) + of "nomain": result = contains(conf.globalOptions, optNoMain) + of "forcebuild", "f": result = contains(conf.globalOptions, optForceFullMake) + of "warnings", "w": result = contains(conf.options, optWarns) + of "hints": result = contains(conf.options, optHints) + of "threadanalysis": result = contains(conf.globalOptions, optThreadAnalysis) + of "stacktrace": result = contains(conf.options, optStackTrace) + of "linetrace": result = contains(conf.options, optLineTrace) + of "debugger": result = contains(conf.options, optEndb) + of "profiler": result = contains(conf.options, optProfiler) + of "memtracker": result = contains(conf.options, optMemTracker) + of "checks", "x": result = conf.options * ChecksOptions == ChecksOptions of "floatchecks": - result = gOptions * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} - of "infchecks": result = contains(gOptions, optInfCheck) - of "nanchecks": result = contains(gOptions, optNaNCheck) - of "nilchecks": result = contains(gOptions, optNilCheck) - of "objchecks": result = contains(gOptions, optObjCheck) - of "fieldchecks": result = contains(gOptions, optFieldCheck) - of "rangechecks": result = contains(gOptions, optRangeCheck) - of "boundchecks": result = contains(gOptions, optBoundsCheck) - of "overflowchecks": result = contains(gOptions, optOverflowCheck) - of "movechecks": result = contains(gOptions, optMoveCheck) - of "linedir": result = contains(gOptions, optLineDir) - of "assertions", "a": result = contains(gOptions, optAssert) - of "run", "r": result = contains(gGlobalOptions, optRun) - of "symbolfiles": result = gSymbolFiles != disabledSf - of "genscript": result = contains(gGlobalOptions, optGenScript) - of "threads": result = contains(gGlobalOptions, optThreads) - of "taintmode": result = contains(gGlobalOptions, optTaintMode) - of "tlsemulation": result = contains(gGlobalOptions, optTlsEmulation) - of "implicitstatic": result = contains(gOptions, optImplicitStatic) - of "patterns": result = contains(gOptions, optPatterns) - of "excessivestacktrace": result = contains(gGlobalOptions, optExcessiveStackTrace) - else: invalidCmdLineOption(passCmd1, switch, info) - -proc processPath(path: string, info: TLineInfo, + result = conf.options * {optNaNCheck, optInfCheck} == {optNaNCheck, optInfCheck} + of "infchecks": result = contains(conf.options, optInfCheck) + of "nanchecks": result = contains(conf.options, optNaNCheck) + of "nilchecks": result = contains(conf.options, optNilCheck) + of "objchecks": result = contains(conf.options, optObjCheck) + of "fieldchecks": result = contains(conf.options, optFieldCheck) + of "rangechecks": result = contains(conf.options, optRangeCheck) + of "boundchecks": result = contains(conf.options, optBoundsCheck) + of "overflowchecks": result = contains(conf.options, optOverflowCheck) + of "movechecks": result = contains(conf.options, optMoveCheck) + of "linedir": result = contains(conf.options, optLineDir) + of "assertions", "a": result = contains(conf.options, optAssert) + of "run", "r": result = contains(conf.globalOptions, optRun) + of "symbolfiles": result = conf.symbolFiles != disabledSf + of "genscript": result = contains(conf.globalOptions, optGenScript) + of "threads": result = contains(conf.globalOptions, optThreads) + of "taintmode": result = contains(conf.globalOptions, optTaintMode) + of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation) + of "implicitstatic": result = contains(conf.options, optImplicitStatic) + of "patterns": result = contains(conf.options, optPatterns) + of "excessivestacktrace": result = contains(conf.globalOptions, optExcessiveStackTrace) + else: invalidCmdLineOption(conf, passCmd1, switch, info) + +proc processPath(conf: ConfigRef; path: string, info: TLineInfo, notRelativeToProj = false): string = let p = if os.isAbsolute(path) or '$' in path: path elif notRelativeToProj: getCurrentDir() / path else: - options.gProjectPath / path + conf.projectPath / path try: - result = pathSubs(p, info.toFullPath().splitFile().dir) + result = pathSubs(conf, p, info.toFullPath().splitFile().dir) except ValueError: - localError(info, "invalid path: " & p) + localError(conf, info, "invalid path: " & p) result = p -proc processCfgPath(path: string, info: TLineInfo): string = +proc processCfgPath(conf: ConfigRef; path: string, info: TLineInfo): string = let path = if path[0] == '"': strutils.unescape(path) else: path let basedir = info.toFullPath().splitFile().dir let p = if os.isAbsolute(path) or '$' in path: @@ -311,431 +302,436 @@ proc processCfgPath(path: string, info: TLineInfo): string = else: basedir / path try: - result = pathSubs(p, basedir) + result = pathSubs(conf, p, basedir) except ValueError: - localError(info, "invalid path: " & p) + localError(conf, info, "invalid path: " & p) result = p -proc trackDirty(arg: string, info: TLineInfo) = +const + errInvalidNumber = "$1 is not a valid number" + +proc trackDirty(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') - if a.len != 4: localError(info, errTokenExpected, - "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN") + if a.len != 4: localError(conf, info, + "DIRTY_BUFFER,ORIGINAL_FILE,LINE,COLUMN expected") var line, column: int if parseUtils.parseInt(a[2], line) <= 0: - localError(info, errInvalidNumber, a[1]) + localError(conf, info, errInvalidNumber % a[1]) if parseUtils.parseInt(a[3], column) <= 0: - localError(info, errInvalidNumber, a[2]) + localError(conf, info, errInvalidNumber % a[2]) - let dirtyOriginalIdx = a[1].fileInfoIdx + let dirtyOriginalIdx = fileInfoIdx(conf, a[1]) if dirtyOriginalIdx.int32 >= 0: msgs.setDirtyFile(dirtyOriginalIdx, a[0]) gTrackPos = newLineInfo(dirtyOriginalIdx, line, column) -proc track(arg: string, info: TLineInfo) = +proc track(conf: ConfigRef; arg: string, info: TLineInfo) = var a = arg.split(',') - if a.len != 3: localError(info, errTokenExpected, "FILE,LINE,COLUMN") + if a.len != 3: localError(conf, info, "FILE,LINE,COLUMN expected") var line, column: int if parseUtils.parseInt(a[1], line) <= 0: - localError(info, errInvalidNumber, a[1]) + localError(conf, info, errInvalidNumber % a[1]) if parseUtils.parseInt(a[2], column) <= 0: - localError(info, errInvalidNumber, a[2]) - gTrackPos = newLineInfo(a[0], line, column) + localError(conf, info, errInvalidNumber % a[2]) + gTrackPos = newLineInfo(conf, a[0], line, column) -proc dynlibOverride(switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = +proc dynlibOverride(conf: ConfigRef; switch, arg: string, pass: TCmdLinePass, info: TLineInfo) = if pass in {passCmd2, passPP}: - expectArg(switch, arg, pass, info) - options.inclDynlibOverride(arg) + expectArg(conf, switch, arg, pass, info) + options.inclDynlibOverride(conf, arg) -proc processSwitch(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; - config: ConfigRef) = +proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; + conf: ConfigRef) = var theOS: TSystemOS cpu: TSystemCPU key, val: string case switch.normalize of "path", "p": - expectArg(switch, arg, pass, info) - addPath(if pass == passPP: processCfgPath(arg, info) else: processPath(arg, info), info) + expectArg(conf, switch, arg, pass, info) + addPath(conf, if pass == passPP: processCfgPath(conf, arg, info) else: processPath(conf, arg, info), info) of "nimblepath", "babelpath": # keep the old name for compat - if pass in {passCmd2, passPP} and not options.gNoNimblePath: - expectArg(switch, arg, pass, info) - var path = processPath(arg, info, notRelativeToProj=true) + if pass in {passCmd2, passPP} and optNoNimblePath notin conf.globalOptions: + expectArg(conf, switch, arg, pass, info) + var path = processPath(conf, arg, info, notRelativeToProj=true) let nimbleDir = getEnv("NIMBLE_DIR") if nimbleDir.len > 0 and pass == passPP: path = nimbleDir / "pkgs" - nimblePath(path, info) + nimblePath(conf, path, info) of "nonimblepath", "nobabelpath": - expectNoArg(switch, arg, pass, info) - disableNimblePath() + expectNoArg(conf, switch, arg, pass, info) + disableNimblePath(conf) of "excludepath": - expectArg(switch, arg, pass, info) - let path = processPath(arg, info) + expectArg(conf, switch, arg, pass, info) + let path = processPath(conf, arg, info) - options.searchPaths.keepItIf( cmpPaths(it, path) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, path) != 0 ) + conf.searchPaths.keepItIf(cmpPaths(it, path) != 0) + conf.lazyPaths.keepItIf(cmpPaths(it, path) != 0) if (len(path) > 0) and (path[len(path) - 1] == DirSep): let strippedPath = path[0 .. (len(path) - 2)] - options.searchPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) - options.lazyPaths.keepItIf( cmpPaths(it, strippedPath) != 0 ) + conf.searchPaths.keepItIf(cmpPaths(it, strippedPath) != 0) + conf.lazyPaths.keepItIf(cmpPaths(it, strippedPath) != 0) of "nimcache": - expectArg(switch, arg, pass, info) - options.nimcacheDir = processPath(arg, info, true) + expectArg(conf, switch, arg, pass, info) + conf.nimcacheDir = processPath(conf, arg, info, true) of "out", "o": - expectArg(switch, arg, pass, info) - options.outFile = arg + expectArg(conf, switch, arg, pass, info) + conf.outFile = arg of "docseesrcurl": - expectArg(switch, arg, pass, info) - options.docSeeSrcUrl = arg + expectArg(conf, switch, arg, pass, info) + conf.docSeeSrcUrl = arg of "mainmodule", "m": discard "allow for backwards compatibility, but don't do anything" of "define", "d": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if {':', '='} in arg: - splitSwitch(arg, key, val, pass, info) - defineSymbol(key, val) + splitSwitch(conf, arg, key, val, pass, info) + defineSymbol(conf.symbols, key, val) else: - defineSymbol(arg) + defineSymbol(conf.symbols, arg) of "undef", "u": - expectArg(switch, arg, pass, info) - undefSymbol(arg) + expectArg(conf, switch, arg, pass, info) + undefSymbol(conf.symbols, arg) of "symbol": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) # deprecated, do nothing of "compile": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: processCompile(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: processCompile(conf, arg) of "link": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: addExternalFileToLink(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: addExternalFileToLink(conf, arg) of "debuginfo": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optCDebug) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optCDebug) of "embedsrc": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optEmbedOrigSrc) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optEmbedOrigSrc) of "compileonly", "c": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optCompileOnly) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optCompileOnly) of "nolinking": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoLinking) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optNoLinking) of "nomain": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoMain) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optNoMain) of "forcebuild", "f": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optForceFullMake) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optForceFullMake) of "project": - expectNoArg(switch, arg, pass, info) - gWholeProject = true + expectNoArg(conf, switch, arg, pass, info) + incl conf.globalOptions, optWholeProject of "gc": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "boehm": - gSelectedGC = gcBoehm - defineSymbol("boehmgc") + conf.selectedGC = gcBoehm + defineSymbol(conf.symbols, "boehmgc") of "refc": - gSelectedGC = gcRefc + conf.selectedGC = gcRefc of "v2": - gSelectedGC = gcV2 + conf.selectedGC = gcV2 of "markandsweep": - gSelectedGC = gcMarkAndSweep - defineSymbol("gcmarkandsweep") + conf.selectedGC = gcMarkAndSweep + defineSymbol(conf.symbols, "gcmarkandsweep") of "generational": - gSelectedGC = gcGenerational - defineSymbol("gcgenerational") + conf.selectedGC = gcGenerational + defineSymbol(conf.symbols, "gcgenerational") of "go": - gSelectedGC = gcGo - defineSymbol("gogc") + conf.selectedGC = gcGo + defineSymbol(conf.symbols, "gogc") of "none": - gSelectedGC = gcNone - defineSymbol("nogc") + conf.selectedGC = gcNone + defineSymbol(conf.symbols, "nogc") of "stack", "regions": - gSelectedGC= gcRegions - defineSymbol("gcregions") - else: localError(info, errNoneBoehmRefcExpectedButXFound, arg) + conf.selectedGC= gcRegions + defineSymbol(conf.symbols, "gcregions") + else: localError(conf, info, errNoneBoehmRefcExpectedButXFound % arg) of "warnings", "w": - if processOnOffSwitchOrList({optWarns}, arg, pass, info): listWarnings() - of "warning": processSpecificNote(arg, wWarning, pass, info, switch) - of "hint": processSpecificNote(arg, wHint, pass, info, switch) + if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) + of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) + of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) of "hints": - if processOnOffSwitchOrList({optHints}, arg, pass, info): listHints() - of "threadanalysis": processOnOffSwitchG({optThreadAnalysis}, arg, pass, info) - of "stacktrace": processOnOffSwitch({optStackTrace}, arg, pass, info) - of "excessivestacktrace": processOnOffSwitchG({optExcessiveStackTrace}, arg, pass, info) - of "linetrace": processOnOffSwitch({optLineTrace}, arg, pass, info) + if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) + of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) + of "stacktrace": processOnOffSwitch(conf, {optStackTrace}, arg, pass, info) + of "excessivestacktrace": processOnOffSwitchG(conf, {optExcessiveStackTrace}, arg, pass, info) + of "linetrace": processOnOffSwitch(conf, {optLineTrace}, arg, pass, info) of "debugger": case arg.normalize of "on", "endb": - gOptions.incl optEndb - defineSymbol("endb") + conf.options.incl optEndb + defineSymbol(conf.symbols, "endb") of "off": - gOptions.excl optEndb - undefSymbol("endb") + conf.options.excl optEndb + undefSymbol(conf.symbols, "endb") of "native", "gdb": - incl(gGlobalOptions, optCDebug) - gOptions = gOptions + {optLineDir} - {optEndb} - defineSymbol("nimTypeNames", nil) # type names are used in gdb pretty printing - undefSymbol("endb") + incl(conf.globalOptions, optCDebug) + conf.options = conf.options + {optLineDir} - {optEndb} + defineSymbol(conf.symbols, "nimTypeNames") # type names are used in gdb pretty printing + undefSymbol(conf.symbols, "endb") else: - localError(info, "expected endb|gdb but found " & arg) + localError(conf, info, "expected endb|gdb but found " & arg) of "profiler": - processOnOffSwitch({optProfiler}, arg, pass, info) - if optProfiler in gOptions: defineSymbol("profiler") - else: undefSymbol("profiler") + processOnOffSwitch(conf, {optProfiler}, arg, pass, info) + if optProfiler in conf.options: defineSymbol(conf.symbols, "profiler") + else: undefSymbol(conf.symbols, "profiler") of "memtracker": - processOnOffSwitch({optMemTracker}, arg, pass, info) - if optMemTracker in gOptions: defineSymbol("memtracker") - else: undefSymbol("memtracker") + processOnOffSwitch(conf, {optMemTracker}, arg, pass, info) + if optMemTracker in conf.options: defineSymbol(conf.symbols, "memtracker") + else: undefSymbol(conf.symbols, "memtracker") of "hotcodereloading": - processOnOffSwitch({optHotCodeReloading}, arg, pass, info) - if optHotCodeReloading in gOptions: defineSymbol("hotcodereloading") - else: undefSymbol("hotcodereloading") + processOnOffSwitch(conf, {optHotCodeReloading}, arg, pass, info) + if optHotCodeReloading in conf.options: defineSymbol(conf.symbols, "hotcodereloading") + else: undefSymbol(conf.symbols, "hotcodereloading") of "oldnewlines": case arg.normalize of "on": - options.gOldNewlines = true - defineSymbol("nimOldNewlines") + conf.oldNewlines = true + defineSymbol(conf.symbols, "nimOldNewlines") of "off": - options.gOldNewlines = false - undefSymbol("nimOldNewlines") + conf.oldNewlines = false + undefSymbol(conf.symbols, "nimOldNewlines") else: - localError(info, errOnOrOffExpectedButXFound, arg) - of "laxstrings": processOnOffSwitch({optLaxStrings}, arg, pass, info) - of "checks", "x": processOnOffSwitch(ChecksOptions, arg, pass, info) + localError(conf, info, errOnOrOffExpectedButXFound % arg) + of "laxstrings": processOnOffSwitch(conf, {optLaxStrings}, arg, pass, info) + of "checks", "x": processOnOffSwitch(conf, ChecksOptions, arg, pass, info) of "floatchecks": - processOnOffSwitch({optNaNCheck, optInfCheck}, arg, pass, info) - of "infchecks": processOnOffSwitch({optInfCheck}, arg, pass, info) - of "nanchecks": processOnOffSwitch({optNaNCheck}, arg, pass, info) - of "nilchecks": processOnOffSwitch({optNilCheck}, arg, pass, info) - of "objchecks": processOnOffSwitch({optObjCheck}, arg, pass, info) - of "fieldchecks": processOnOffSwitch({optFieldCheck}, arg, pass, info) - of "rangechecks": processOnOffSwitch({optRangeCheck}, arg, pass, info) - of "boundchecks": processOnOffSwitch({optBoundsCheck}, arg, pass, info) - of "overflowchecks": processOnOffSwitch({optOverflowCheck}, arg, pass, info) - of "movechecks": processOnOffSwitch({optMoveCheck}, arg, pass, info) - of "linedir": processOnOffSwitch({optLineDir}, arg, pass, info) - of "assertions", "a": processOnOffSwitch({optAssert}, arg, pass, info) + processOnOffSwitch(conf, {optNaNCheck, optInfCheck}, arg, pass, info) + of "infchecks": processOnOffSwitch(conf, {optInfCheck}, arg, pass, info) + of "nanchecks": processOnOffSwitch(conf, {optNaNCheck}, arg, pass, info) + of "nilchecks": processOnOffSwitch(conf, {optNilCheck}, arg, pass, info) + of "objchecks": processOnOffSwitch(conf, {optObjCheck}, arg, pass, info) + of "fieldchecks": processOnOffSwitch(conf, {optFieldCheck}, arg, pass, info) + of "rangechecks": processOnOffSwitch(conf, {optRangeCheck}, arg, pass, info) + of "boundchecks": processOnOffSwitch(conf, {optBoundsCheck}, arg, pass, info) + of "overflowchecks": processOnOffSwitch(conf, {optOverflowCheck}, arg, pass, info) + of "movechecks": processOnOffSwitch(conf, {optMoveCheck}, arg, pass, info) + of "linedir": processOnOffSwitch(conf, {optLineDir}, arg, pass, info) + of "assertions", "a": processOnOffSwitch(conf, {optAssert}, arg, pass, info) of "deadcodeelim": discard # deprecated, dead code elim always on of "threads": - processOnOffSwitchG({optThreads}, arg, pass, info) - #if optThreads in gGlobalOptions: incl(gNotes, warnGcUnsafe) - of "tlsemulation": processOnOffSwitchG({optTlsEmulation}, arg, pass, info) - of "taintmode": processOnOffSwitchG({optTaintMode}, arg, pass, info) + processOnOffSwitchG(conf, {optThreads}, arg, pass, info) + #if optThreads in conf.globalOptions: incl(conf.notes, warnGcUnsafe) + of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) + of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "implicitstatic": - processOnOffSwitch({optImplicitStatic}, arg, pass, info) + processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info) of "patterns": - processOnOffSwitch({optPatterns}, arg, pass, info) + processOnOffSwitch(conf, {optPatterns}, arg, pass, info) of "opt": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "speed": - incl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + incl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) of "size": - excl(gOptions, optOptimizeSpeed) - incl(gOptions, optOptimizeSize) + excl(conf.options, optOptimizeSpeed) + incl(conf.options, optOptimizeSize) of "none": - excl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) - else: localError(info, errNoneSpeedOrSizeExpectedButXFound, arg) + excl(conf.options, optOptimizeSpeed) + excl(conf.options, optOptimizeSize) + else: localError(conf, info, errNoneSpeedOrSizeExpectedButXFound % arg) of "app": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) case arg.normalize of "gui": - incl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("guiapp") + incl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "guiapp") of "console": - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("executable") - defineSymbol("consoleapp") + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "executable") + defineSymbol(conf.symbols, "consoleapp") of "lib": - incl(gGlobalOptions, optGenDynLib) - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("dll") + incl(conf.globalOptions, optGenDynLib) + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "dll") of "staticlib": - incl(gGlobalOptions, optGenStaticLib) - excl(gGlobalOptions, optGenGuiApp) - defineSymbol("library") - defineSymbol("staticlib") - else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + incl(conf.globalOptions, optGenStaticLib) + excl(conf.globalOptions, optGenGuiApp) + defineSymbol(conf.symbols, "library") + defineSymbol(conf.symbols, "staticlib") + else: localError(conf, info, errGuiConsoleOrLibExpectedButXFound % arg) of "passc", "t": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addCompileOptionCmd(conf, arg) of "passl", "l": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(arg) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: extccomp.addLinkOptionCmd(conf, arg) of "cincludes": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cIncludes.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cIncludes.add processPath(conf, arg, info) of "clibdir": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cLibs.add processPath(conf, arg, info) of "clib": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(info) + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: cLinkedLibs.add processPath(conf, arg, info) of "header": - if config != nil: config.headerFile = arg - incl(gGlobalOptions, optGenIndex) + if conf != nil: conf.headerFile = arg + incl(conf.globalOptions, optGenIndex) of "index": - processOnOffSwitchG({optGenIndex}, arg, pass, info) + processOnOffSwitchG(conf, {optGenIndex}, arg, pass, info) of "import": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitImports.add arg + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: conf.implicitImports.add arg of "include": - expectArg(switch, arg, pass, info) - if pass in {passCmd2, passPP}: implicitIncludes.add arg + expectArg(conf, switch, arg, pass, info) + if pass in {passCmd2, passPP}: conf.implicitIncludes.add arg of "listcmd": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optListCmd) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optListCmd) of "genmapping": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optGenMapping) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optGenMapping) of "os": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd1, passPP}: theOS = platform.nameToOS(arg) - if theOS == osNone: localError(info, errUnknownOS, arg) + if theOS == osNone: localError(conf, info, "unknown OS: '$1'" % arg) elif theOS != platform.hostOS: setTarget(theOS, targetCPU) of "cpu": - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) if pass in {passCmd1, passPP}: cpu = platform.nameToCPU(arg) - if cpu == cpuNone: localError(info, errUnknownCPU, arg) + if cpu == cpuNone: localError(conf, info, "unknown CPU: '$1'" % arg) elif cpu != platform.hostCPU: setTarget(targetOS, cpu) of "run", "r": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optRun) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optRun) of "verbosity": - expectArg(switch, arg, pass, info) - gVerbosity = parseInt(arg) - gNotes = NotesVerbosity[gVerbosity] - incl(gNotes, enableNotes) - excl(gNotes, disableNotes) - gMainPackageNotes = gNotes + expectArg(conf, switch, arg, pass, info) + conf.verbosity = parseInt(arg) + conf.notes = NotesVerbosity[conf.verbosity] + incl(conf.notes, conf.enableNotes) + excl(conf.notes, conf.disableNotes) + conf.mainPackageNotes = conf.notes of "parallelbuild": - expectArg(switch, arg, pass, info) - gNumberOfProcessors = parseInt(arg) + expectArg(conf, switch, arg, pass, info) + conf.numberOfProcessors = parseInt(arg) of "version", "v": - expectNoArg(switch, arg, pass, info) - writeVersionInfo(pass) + expectNoArg(conf, switch, arg, pass, info) + writeVersionInfo(conf, pass) of "advanced": - expectNoArg(switch, arg, pass, info) - writeAdvancedUsage(pass) + expectNoArg(conf, switch, arg, pass, info) + writeAdvancedUsage(conf, pass) of "fullhelp": - expectNoArg(switch, arg, pass, info) - writeFullhelp(pass) + expectNoArg(conf, switch, arg, pass, info) + writeFullhelp(conf, pass) of "help", "h": - expectNoArg(switch, arg, pass, info) - helpOnError(pass) + expectNoArg(conf, switch, arg, pass, info) + helpOnError(conf, pass) of "symbolfiles": case arg.normalize - of "on": gSymbolFiles = enabledSf - of "off": gSymbolFiles = disabledSf - of "writeonly": gSymbolFiles = writeOnlySf - of "readonly": gSymbolFiles = readOnlySf - of "v2": gSymbolFiles = v2Sf - else: localError(info, errOnOrOffExpectedButXFound, arg) + of "on": conf.symbolFiles = enabledSf + of "off": conf.symbolFiles = disabledSf + of "writeonly": conf.symbolFiles = writeOnlySf + of "readonly": conf.symbolFiles = readOnlySf + of "v2": conf.symbolFiles = v2Sf + else: localError(conf, info, "invalid option for --symbolFiles: " & arg) of "skipcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipConfigFile) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optSkipConfigFile) of "skipprojcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipProjConfigFile) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optSkipProjConfigFile) of "skipusercfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipUserConfigFile) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optSkipUserConfigFile) of "skipparentcfg": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optSkipParentConfigFiles) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optSkipParentConfigFiles) of "genscript", "gendeps": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optGenScript) - incl(gGlobalOptions, optCompileOnly) - of "colors": processOnOffSwitchG({optUseColors}, arg, pass, info) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optGenScript) + incl(conf.globalOptions, optCompileOnly) + of "colors": processOnOffSwitchG(conf, {optUseColors}, arg, pass, info) of "lib": - expectArg(switch, arg, pass, info) - libpath = processPath(arg, info, notRelativeToProj=true) + expectArg(conf, switch, arg, pass, info) + conf.libpath = processPath(conf, arg, info, notRelativeToProj=true) of "putenv": - expectArg(switch, arg, pass, info) - splitSwitch(arg, key, val, pass, info) + expectArg(conf, switch, arg, pass, info) + splitSwitch(conf, arg, key, val, pass, info) os.putEnv(key, val) of "cc": - expectArg(switch, arg, pass, info) - setCC(arg) + expectArg(conf, switch, arg, pass, info) + setCC(conf, arg, info) of "track": - expectArg(switch, arg, pass, info) - track(arg, info) + expectArg(conf, switch, arg, pass, info) + track(conf, arg, info) of "trackdirty": - expectArg(switch, arg, pass, info) - trackDirty(arg, info) + expectArg(conf, switch, arg, pass, info) + trackDirty(conf, arg, info) of "suggest": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideSug + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideSug of "def": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideDef + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideDef of "eval": - expectArg(switch, arg, pass, info) - gEvalExpr = arg + expectArg(conf, switch, arg, pass, info) + conf.evalExpr = arg of "context": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideCon + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideCon of "usages": - expectNoArg(switch, arg, pass, info) - gIdeCmd = ideUse + expectNoArg(conf, switch, arg, pass, info) + conf.ideCmd = ideUse of "stdout": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optStdout) + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optStdout) of "listfullpaths": - expectNoArg(switch, arg, pass, info) - gListFullPaths = true + expectNoArg(conf, switch, arg, pass, info) + incl conf.globalOptions, optListFullPaths of "dynliboverride": - dynlibOverride(switch, arg, pass, info) + dynlibOverride(conf, switch, arg, pass, info) of "dynliboverrideall": - expectNoArg(switch, arg, pass, info) - gDynlibOverrideAll = true + expectNoArg(conf, switch, arg, pass, info) + incl conf.globalOptions, optDynlibOverrideAll of "cs": # only supported for compatibility. Does nothing. - expectArg(switch, arg, pass, info) + expectArg(conf, switch, arg, pass, info) of "experimental": if arg.len == 0: - config.features.incl oldExperimentalFeatures + conf.features.incl oldExperimentalFeatures else: try: - config.features.incl parseEnum[Feature](arg) + conf.features.incl parseEnum[Feature](arg) except ValueError: - localError(info, "unknown experimental feature") + localError(conf, info, "unknown experimental feature") of "nocppexceptions": - expectNoArg(switch, arg, pass, info) - incl(gGlobalOptions, optNoCppExceptions) - defineSymbol("noCppExceptions") + expectNoArg(conf, switch, arg, pass, info) + incl(conf.globalOptions, optNoCppExceptions) + defineSymbol(conf.symbols, "noCppExceptions") of "cppdefine": - expectArg(switch, arg, pass, info) - if config != nil: - config.cppDefine(arg) + expectArg(conf, switch, arg, pass, info) + if conf != nil: + conf.cppDefine(arg) of "newruntime": - expectNoArg(switch, arg, pass, info) - doAssert(config != nil) - incl(config.features, destructor) - defineSymbol("nimNewRuntime") + expectNoArg(conf, switch, arg, pass, info) + doAssert(conf != nil) + incl(conf.features, destructor) + defineSymbol(conf.symbols, "nimNewRuntime") of "cppcompiletonamespace": - expectNoArg(switch, arg, pass, info) - useNimNamespace = true - defineSymbol("cppCompileToNamespace") + expectNoArg(conf, switch, arg, pass, info) + incl conf.globalOptions, optUseNimNamespace + defineSymbol(conf.symbols, "cppCompileToNamespace") else: - if strutils.find(switch, '.') >= 0: options.setConfigVar(switch, arg) - else: invalidCmdLineOption(pass, switch, info) + if strutils.find(switch, '.') >= 0: options.setConfigVar(conf, switch, arg) + else: invalidCmdLineOption(conf, pass, switch, info) + +template gCmdLineInfo*(): untyped = newLineInfo(config, "command line", 1, 1) -proc processCommand(switch: string, pass: TCmdLinePass; config: ConfigRef) = +proc processCommand*(switch: string, pass: TCmdLinePass; config: ConfigRef) = var cmd, arg: string - splitSwitch(switch, cmd, arg, pass, gCmdLineInfo) + splitSwitch(config, switch, cmd, arg, pass, gCmdLineInfo) processSwitch(cmd, arg, pass, gCmdLineInfo, config) @@ -755,17 +751,17 @@ proc processArgument*(pass: TCmdLinePass; p: OptParser; if argsCount == 0: # nim filename.nims is the same as "nim e filename.nims": if p.key.endswith(".nims"): - options.command = "e" - options.gProjectName = unixToNativePath(p.key) + config.command = "e" + config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true elif pass != passCmd2: - options.command = p.key + config.command = p.key else: - if pass == passCmd1: options.commandArgs.add p.key + if pass == passCmd1: config.commandArgs.add p.key if argsCount == 1: # support UNIX style filenames everywhere for portable build scripts: - options.gProjectName = unixToNativePath(p.key) + config.projectName = unixToNativePath(p.key) config.arguments = cmdLineRest(p) result = true inc argsCount diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index f8a75e68e..773c0faf9 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -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 undefSymbol*(symbol: string) = - gSymbols[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 isDefined*(symbol: PIdent): bool = isDefined(symbol.s) +proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") = + symbols[symbol] = value -proc lookupSymbol*(symbol: string): string = - result = if isDefined(symbol): gSymbols[symbol] else: nil +proc undefSymbol*(symbols: StringTableRef; symbol: string) = + symbols[symbol] = catNone -proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s) +#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string = +# result = if isDefined(symbol): gSymbols[symbol] else: nil -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") diff --git a/compiler/configuration.nim b/compiler/configuration.nim new file mode 100644 index 000000000..f9f0e623c --- /dev/null +++ b/compiler/configuration.nim @@ -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", +, +]# diff --git a/compiler/depends.nim b/compiler/depends.nim index 2b600c1da..732404232 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -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) diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index cd16469de..31c735794 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -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() diff --git a/compiler/dfa.nim b/compiler/dfa.nim index bc9d13870..0fd706178 100644 --- a/compiler/dfa.nim +++ b/compiler/dfa.nim @@ -23,7 +23,7 @@ ## "A Graph–Free Approach to Data–Flow 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``. diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e1a70a23e..7ab2f0eee 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -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) - -proc docgenFindFile(s: string): string {.procvar.} = - result = options.findFile(s) - if result.len == 0: - result = getCurrentDir() / s - if not existsFile(result): result = "" +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(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)) diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 118f1c7c5..d9a73e1cd 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -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 diff --git a/compiler/evaltempl.nim b/compiler/evaltempl.nim index 502430815..01c56ec9c 100644 --- a/compiler/evaltempl.nim +++ b/compiler/evaltempl.nim @@ -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) diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index f8938e3af..3f0e6f611 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -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)) - -proc getCompileOptions: string = - result = cFileSpecificOptions("__dummy__") - -proc getLinkOptions: string = + 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(conf: ConfigRef): string = + result = cFileSpecificOptions(conf, "__dummy__") + +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")) diff --git a/compiler/filter_tmpl.nim b/compiler/filter_tmpl.nim index 545bea950..f93355e6b 100644 --- a/compiler/filter_tmpl.nim +++ b/compiler/filter_tmpl.nim @@ -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): diff --git a/compiler/filters.nim b/compiler/filters.nim index 37df628ed..3ebbad678 100644 --- a/compiler/filters.nim +++ b/compiler/filters.nim @@ -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): diff --git a/compiler/gorgeimpl.nim b/compiler/gorgeimpl.nim index 80302b4b5..44c7651bc 100644 --- a/compiler/gorgeimpl.nim +++ b/compiler/gorgeimpl.nim @@ -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) diff --git a/compiler/guards.nim b/compiler/guards.nim index 94af5202d..d39ea799b 100644 --- a/compiler/guards.nim +++ b/compiler/guards.nim @@ -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 diff --git a/compiler/hlo.nim b/compiler/hlo.nim index c4288c362..8251e3179 100644 --- a/compiler/hlo.nim +++ b/compiler/hlo.nim @@ -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) diff --git a/compiler/idgen.nim b/compiler/idgen.nim index c6b1a4d07..7d103ffd7 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -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) diff --git a/compiler/importer.nim b/compiler/importer.nim index a5c361864..90e774a50 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -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) diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 2ae3426ab..25b554f7b 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -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) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim index f440ee7da..f9e4246eb 100644 --- a/compiler/jstypes.nim +++ b/compiler/jstypes.nim @@ -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 & ')') diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim index 43ff50190..40e5bb6b0 100644 --- a/compiler/lambdalifting.nim +++ b/compiler/lambdalifting.nim @@ -11,7 +11,7 @@ import intsets, strutils, options, ast, astalgo, trees, treetab, msgs, - 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 +125,32 @@ proc newCall(a: PSym, b: PNode): PNode = result.add newSymNode(a) result.add b -proc createClosureIterStateType*(iter: PSym): PType = +proc createClosureIterStateType*(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 = +proc createStateField(g: ModuleGraph; iter: PSym): PSym = result = newSym(skField, getIdent(":state"), iter, iter.info) - result.typ = createClosureIterStateType(iter) + result.typ = createClosureIterStateType(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 getClosureIterResult*(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 +166,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 +174,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 +208,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 +227,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 +255,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 +269,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 +290,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 +314,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 +323,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 +371,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 +397,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 if s.name == getIdent(":state"): @@ -419,7 +421,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: @@ -444,7 +446,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 @@ -465,17 +467,16 @@ type processed: IntSet envVars: Table[int, PNode] inContainer: int - features: set[Feature] proc initLiftingPass(fn: PSym): LiftingPass = result.processed = initIntSet() 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: @@ -487,7 +488,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 = @@ -506,22 +507,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) @@ -531,7 +532,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: @@ -539,7 +540,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 @@ -550,7 +551,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)) @@ -558,7 +559,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 = @@ -566,10 +567,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: @@ -577,7 +578,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: @@ -586,8 +587,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 = @@ -597,11 +598,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 @@ -609,8 +610,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 @@ -620,7 +621,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: @@ -633,7 +635,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) @@ -642,16 +645,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 @@ -665,7 +668,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)) @@ -674,9 +677,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; @@ -684,25 +687,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) @@ -719,8 +722,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; let oldInContainer = c.inContainer c.inContainer = 0 var body = liftCapturedVars(s.getBody, s, d, c) - if oldIterTransf in c.features: - body = wrapIterBody(body, s) + if oldIterTransf in d.graph.config.features: + body = wrapIterBody(d.graph, body, s) if c.envvars.getOrDefault(s.id).isNil: s.ast.sons[bodyPos] = body else: @@ -730,9 +733,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, @@ -763,9 +766,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass; if n[1].kind == nkClosure: result = n[1] else: if owner.isIterator: - if oldIterTransf in c.features and n.kind == nkYieldStmt: + if oldIterTransf in d.graph.config.features and n.kind == nkYieldStmt: return transformYield(n, owner, d, c) - elif oldIterTransf in c.features and n.kind == nkReturnStmt: + elif oldIterTransf in d.graph.config.features and n.kind == nkReturnStmt: return transformReturn(n, owner, d, c) elif nfLL in n.flags: # special case 'when nimVm' due to bug #3636: @@ -798,8 +801,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 @@ -808,11 +811,11 @@ 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*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var bool): PNode = +proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode = # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs # the transformation even when compiling to JS ... @@ -820,27 +823,26 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b 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) d.somethingToDo = true if d.somethingToDo: var c = initLiftingPass(fn) - c.features = features result = liftCapturedVars(body, fn, d, c) if c.envvars.getOrDefault(fn.id) != nil: result = newTree(nkStmtList, rawClosureCreation(fn, d, c), result) - if oldIterTransf in features: - result = wrapIterBody(result, fn) + if oldIterTransf in g.config.features: + result = wrapIterBody(g, result, fn) else: result = body #if fn.name.s == "get2": @@ -848,15 +850,12 @@ proc liftLambdas*(features: set[Feature], fn: PSym, body: PNode; tooEarly: var b # 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: # @@ -885,10 +884,10 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode = break ... """ - 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] @@ -901,7 +900,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 @@ -910,7 +909,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: @@ -920,7 +919,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 @@ -935,7 +934,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) diff --git a/compiler/lexer.nim b/compiler/lexer.nim index a65587390..591561987 100644 --- a/compiler/lexer.nim +++ b/compiler/lexer.nim @@ -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() diff --git a/compiler/liftlocals.nim b/compiler/liftlocals.nim index 3610a1486..4603d357b 100644 --- a/compiler/liftlocals.nim +++ b/compiler/liftlocals.nim @@ -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) diff --git a/compiler/lookups.nim b/compiler/lookups.nim index e0d6e0098..b6d63d0bd 100644 --- a/compiler/lookups.nim +++ b/compiler/lookups.nim @@ -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) diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim index 8510bf7ee..13336f00e 100644 --- a/compiler/lowerings.nim +++ b/compiler/lowerings.nim @@ -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 diff --git a/compiler/magicsys.nim b/compiler/magicsys.nim index 6a9d69082..b5577d961 100644 --- a/compiler/magicsys.nim +++ b/compiler/magicsys.nim @@ -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) - -var - intTypeCache: array[-5..64, PType] + internalError(g.config, "wanted: " & $kind & " got: " & $result.kind) + if result == nil: internalError(g.config, "type not found: " & $kind) -proc resetSysTypes* = - systemModule = nil - initStrTable(compilerprocs) - initStrTable(exposed) - for i in low(gSysTypes)..high(gSysTypes): - gSysTypes[i] = nil +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 - for i in low(intTypeCache)..high(intTypeCache): - intTypeCache[i] = nil + for i in low(g.intTypeCache)..high(g.intTypeCache): + g.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") + result.typ = getSysType(g, result.info, tyInt64) + else: + internalError(g.config, result.info, "invalid int size") -proc getCompilerProc*(name: string): PSym = +proc getCompilerProc*(g: ModuleGraph; 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 + 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 registerCompilerProc*(s: PSym) = - strTableAdd(compilerprocs, s) +proc registerCompilerProc*(g: ModuleGraph; s: PSym) = + strTableAdd(g.compilerprocs, s) -proc registerNimScriptSymbol*(s: PSym) = +proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) = # Nimscript symbols must be al unique: - let conflict = strTableGet(exposed, s.name) + let conflict = strTableGet(g.exposed, s.name) if conflict == nil: - strTableAdd(exposed, s) + strTableAdd(g.exposed, s) else: - localError(s.info, "symbol conflicts with other .exportNims symbol at: " & - $conflict.info) - -proc getNimScriptSymbol*(name: string): PSym = - strTableGet(exposed, getIdent(name)) + localError(g.config, s.info, + "symbol conflicts with other .exportNims symbol at: " & $conflict.info) -proc resetNimScriptSymbols*() = initStrTable(exposed) +proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym = + strTableGet(g.exposed, getIdent(name)) -initStrTable(compilerprocs) -initStrTable(exposed) +proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed) diff --git a/compiler/main.nim b/compiler/main.nim index f23a3a88e..e3f00db9e 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -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()) diff --git a/compiler/modulegraphs.nim b/compiler/modulegraphs.nim index 6c14a46e8..460d0b4a5 100644 --- a/compiler/modulegraphs.nim +++ b/compiler/modulegraphs.nim @@ -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: diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 1318b67a7..daa55c2ba 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -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) diff --git a/compiler/modules.nim b/compiler/modules.nim index 7fe2336dd..5d1eba1f2 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -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" diff --git a/compiler/msgs.nim b/compiler/msgs.nim index b6cd05e06..533d3a57f 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -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 - 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 +# MsgConfig* = ref object of RootObj 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) diff --git a/compiler/nim.nim b/compiler/nim.nim index 280782330..d3e00017f 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -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)) diff --git a/compiler/nimblecmd.nim b/compiler/nimblecmd.nim index 0f9e03352..8305b01f5 100644 --- a/compiler/nimblecmd.nim +++ b/compiler/nimblecmd.nim @@ -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 diff --git a/compiler/nimconf.nim b/compiler/nimconf.nim index dc8d082b3..6cb5bab0f 100644 --- a/compiler/nimconf.nim +++ b/compiler/nimconf.nim @@ -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) diff --git a/compiler/nimfix/nimfix.nim b/compiler/nimfix/nimfix.nim index 2ef375b00..c3e29f9a1 100644 --- a/compiler/nimfix/nimfix.nim +++ b/compiler/nimfix/nimfix.nim @@ -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 diff --git a/compiler/nimfix/pretty.nim b/compiler/nimfix/pretty.nim index 7af2a86dc..96429ad53 100644 --- a/compiler/nimfix/pretty.nim +++ b/compiler/nimfix/pretty.nim @@ -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) diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim index 8ec4d3c0d..6cb675ed8 100644 --- a/compiler/nimsets.nim +++ b/compiler/nimsets.nim @@ -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) - diff --git a/compiler/nversion.nim b/compiler/nversion.nim index 85265a7c0..caa818d79 100644 --- a/compiler/nversion.nim +++ b/compiler/nversion.nim @@ -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. diff --git a/compiler/options.nim b/compiler/options.nim index 0ce2f95ce..8fe3cf054 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -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] @@ -113,74 +119,177 @@ type notnil, oldIterTransf + 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 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]) -proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} -proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc -template preciseStack*(): bool = gPreciseStack +proc cppDefine*(c: ConfigRef; define: string) = + c.cppDefines.incl define -template compilationCachePresent*: untyped = - gSymbolFiles in {enabledSf, writeOnlySf} +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" @@ -195,82 +304,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 @@ -282,12 +371,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 @@ -298,114 +387,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 @@ -415,16 +479,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): @@ -449,11 +513,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 diff --git a/compiler/packagehandling.nim b/compiler/packagehandling.nim index 758411e39..2efab58b0 100644 --- a/compiler/packagehandling.nim +++ b/compiler/packagehandling.nim @@ -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: diff --git a/compiler/parampatterns.nim b/compiler/parampatterns.nim index 02c48c16d..944aec048 100644 --- a/compiler/parampatterns.nim +++ b/compiler/parampatterns.nim @@ -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 diff --git a/compiler/parser.nim b/compiler/parser.nim index 0a3815f13..fbc57ebb6 100644 --- a/compiler/parser.nim +++ b/compiler/parser.nim @@ -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: diff --git a/compiler/passaux.nim b/compiler/passaux.nim index 2065d5893..568fb4c23 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -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) diff --git a/compiler/passes.nim b/compiler/passes.nim index b104cd132..8f9f57f3d 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -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 diff --git a/compiler/patterns.nim b/compiler/patterns.nim index 31b76743e..5409a4811 100644 --- a/compiler/patterns.nim +++ b/compiler/patterns.nim @@ -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 diff --git a/compiler/plugins/itersgen.nim b/compiler/plugins/itersgen.nim index dbc47e11e..ebb65dd4a 100644 --- a/compiler/plugins/itersgen.nim +++ b/compiler/plugins/itersgen.nim @@ -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) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 0b8bcd374..de98a5e42 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -12,7 +12,7 @@ import os, platform, condsyms, ast, astalgo, idents, semdata, msgs, renderer, wordrecg, ropes, options, strutils, extccomp, math, magicsys, trees, - rodread, types, lookups + rodread, types, lookups, configuration const FirstCallConv* = wNimcall @@ -84,8 +84,12 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode = proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) # implementation -proc invalidPragma*(n: PNode) = - localError(n.info, errInvalidPragmaX, renderTree(n, {renderNoComments})) +const + errStringLiteralExpected = "string literal expected" + errIntLiteralExpected = "integer literal expected" + +proc invalidPragma*(c: PContext; n: PNode) = + localError(c.config, n.info, "invalid pragma: " % renderTree(n, {renderNoComments})) proc pragmaAsm*(c: PContext, n: PNode): char = result = '\0' @@ -96,12 +100,12 @@ proc pragmaAsm*(c: PContext, n: PNode): char = case whichKeyword(it.sons[0].ident) of wSubsChar: if it.sons[1].kind == nkCharLit: result = chr(int(it.sons[1].intVal)) - else: invalidPragma(it) - else: invalidPragma(it) + else: invalidPragma(c, it) + else: invalidPragma(c, it) else: - invalidPragma(it) + invalidPragma(c, it) -proc setExternName(s: PSym, extname: string, info: TLineInfo) = +proc setExternName(c: PContext; s: PSym, extname: string, info: TLineInfo) = # special cases to improve performance: if extname == "$1": s.loc.r = rope(s.name.s) @@ -111,73 +115,73 @@ proc setExternName(s: PSym, extname: string, info: TLineInfo) = try: s.loc.r = rope(extname % s.name.s) except ValueError: - localError(info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") - if gCmd == cmdPretty and '$' notin extname: + localError(c.config, info, "invalid extern name: '" & extname & "'. (Forgot to escape '$'?)") + if c.config.cmd == cmdPretty and '$' notin extname: # note that '{.importc.}' is transformed into '{.importc: "$1".}' s.loc.flags.incl(lfFullExternalName) -proc makeExternImport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc makeExternImport(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) -proc makeExternExport(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc makeExternExport(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfExportc) -proc processImportCompilerProc(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportCompilerProc(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) excl(s.flags, sfForward) incl(s.loc.flags, lfImportCompilerProc) -proc processImportCpp(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportCpp(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfInfixCall) excl(s.flags, sfForward) - if gCmd == cmdCompileToC: + if c.config.cmd == cmdCompileToC: let m = s.getModule() incl(m.flags, sfCompileToCpp) extccomp.gMixedMode = true -proc processImportObjC(s: PSym, extname: string, info: TLineInfo) = - setExternName(s, extname, info) +proc processImportObjC(c: PContext; s: PSym, extname: string, info: TLineInfo) = + setExternName(c, s, extname, info) incl(s.flags, sfImportc) incl(s.flags, sfNamedParamCall) excl(s.flags, sfForward) let m = s.getModule() incl(m.flags, sfCompileToObjC) -proc newEmptyStrNode(n: PNode): PNode {.noinline.} = - result = newNodeIT(nkStrLit, n.info, getSysType(tyString)) +proc newEmptyStrNode(c: PContext; n: PNode): PNode {.noinline.} = + result = newNodeIT(nkStrLit, n.info, getSysType(c.graph, n.info, tyString)) result.strVal = "" proc getStrLitNode(c: PContext, n: PNode): PNode = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) else: n.sons[1] = c.semConstExpr(c, n.sons[1]) case n.sons[1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: result = n.sons[1] else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) proc expectStrLit(c: PContext, n: PNode): string = result = getStrLitNode(c, n).strVal proc expectIntLit(c: PContext, n: PNode): int = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errIntLiteralExpected) + localError(c.config, n.info, errIntLiteralExpected) else: n.sons[1] = c.semConstExpr(c, n.sons[1]) case n.sons[1].kind of nkIntLit..nkInt64Lit: result = int(n.sons[1].intVal) - else: localError(n.info, errIntLiteralExpected) + else: localError(c.config, n.info, errIntLiteralExpected) proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string = if n.kind in nkPragmaCallKinds: result = expectStrLit(c, n) @@ -190,7 +194,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = #if sfSystemModule notin c.module.flags: # liMessage(n.info, errMagicOnlyInSystem) if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) return var v: string if n.sons[1].kind == nkIdent: v = n.sons[1].ident.s @@ -199,7 +203,7 @@ proc processMagic(c: PContext, n: PNode, s: PSym) = if substr($m, 1) == v: s.magic = m break - if s.magic == mNone: message(n.info, warnUnknownMagic, v) + if s.magic == mNone: message(c.config, n.info, warnUnknownMagic, v) proc wordToCallConv(sw: TSpecialWord): TCallingConvention = # this assumes that the order of special words and calling conventions is @@ -211,11 +215,11 @@ proc isTurnedOn(c: PContext, n: PNode): bool = let x = c.semConstBoolExpr(c, n.sons[1]) n.sons[1] = x if x.kind == nkIntLit: return x.intVal != 0 - localError(n.info, errOnOrOffExpected) + localError(c.config, n.info, "'on' or 'off' expected") proc onOff(c: PContext, n: PNode, op: TOptions) = - if isTurnedOn(c, n): gOptions = gOptions + op - else: gOptions = gOptions - op + if isTurnedOn(c, n): c.config.options = c.config.options + op + else: c.config.options = c.config.options - op proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) = if isTurnedOn(c, n): incl(c.module.flags, flag) @@ -227,9 +231,9 @@ proc processCallConv(c: PContext, n: PNode) = case sw of FirstCallConv..LastCallConv: c.optionStack[^1].defaultCC = wordToCallConv(sw) - else: localError(n.info, errCallConvExpected) + else: localError(c.config, n.info, "calling convention expected") else: - localError(n.info, errCallConvExpected) + localError(c.config, n.info, "calling convention expected") proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = for it in c.libs: @@ -240,13 +244,13 @@ proc getLib(c: PContext, kind: TLibKind, path: PNode): PLib = result.path = path c.libs.add result if path.kind in {nkStrLit..nkTripleStrLit}: - result.isOverriden = options.isDynlibOverride(path.strVal) + result.isOverriden = options.isDynlibOverride(c.config, path.strVal) proc expectDynlibNode(c: PContext, n: PNode): PNode = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) # error correction: - result = newEmptyStrNode(n) + result = newEmptyStrNode(c, n) else: # For the OpenGL wrapper we support: # {.dynlib: myGetProcAddr(...).} @@ -254,8 +258,8 @@ proc expectDynlibNode(c: PContext, n: PNode): PNode = if result.kind == nkSym and result.sym.kind == skConst: result = result.sym.ast # look it up if result.typ == nil or result.typ.kind notin {tyPointer, tyString, tyProc}: - localError(n.info, errStringLiteralExpected) - result = newEmptyStrNode(n) + localError(c.config, n.info, errStringLiteralExpected) + result = newEmptyStrNode(c, n) proc processDynLib(c: PContext, n: PNode, sym: PSym) = if (sym == nil) or (sym.kind == skModule): @@ -278,39 +282,37 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds) and (sonsLen(n) == 2) and - (n.sons[0].kind == nkBracketExpr) and - (n.sons[0].sons.len == 2) and - (n.sons[0].sons[1].kind == nkIdent) and - (n.sons[0].sons[0].kind == nkIdent): - #and (n.sons[1].kind == nkIdent): + if n.kind in nkPragmaCallKinds and len(n) == 2 and + n[0].kind == nkBracketExpr and + n[0].len == 2 and + n[0][1].kind == nkIdent and n[0][0].kind == nkIdent: var nk: TNoteKind - case whichKeyword(n.sons[0].sons[0].ident) + case whichKeyword(n[0][0].ident) of wHint: - var x = findStr(msgs.HintsToStr, n.sons[0].sons[1].ident.s) + var x = findStr(HintsToStr, n[0][1].ident.s) if x >= 0: nk = TNoteKind(x + ord(hintMin)) - else: invalidPragma(n); return + else: invalidPragma(c, n); return of wWarning: - var x = findStr(msgs.WarningsToStr, n.sons[0].sons[1].ident.s) + var x = findStr(WarningsToStr, n[0][1].ident.s) if x >= 0: nk = TNoteKind(x + ord(warnMin)) - else: invalidPragma(n); return + else: invalidPragma(c, n); return else: - invalidPragma(n) + invalidPragma(c, n) return - let x = c.semConstBoolExpr(c, n.sons[1]) + let x = c.semConstBoolExpr(c, n[1]) n.sons[1] = x - if x.kind == nkIntLit and x.intVal != 0: incl(gNotes, nk) - else: excl(gNotes, nk) + if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk) + else: excl(c.config.notes, nk) else: - invalidPragma(n) + invalidPragma(c, n) proc processOption(c: PContext, n: PNode): bool = if n.kind notin nkPragmaCallKinds or n.len != 2: result = true elif n.sons[0].kind == nkBracketExpr: processNote(c, n) elif n.sons[0].kind != nkIdent: result = true else: - var sw = whichKeyword(n.sons[0].ident) + let sw = whichKeyword(n.sons[0].ident) case sw of wChecks: onOff(c, n, ChecksOptions) of wObjChecks: onOff(c, n, {optObjCheck}) @@ -337,32 +339,32 @@ proc processOption(c: PContext, n: PNode): bool = of wDynlib: processDynLib(c, n, nil) of wOptimization: if n.sons[1].kind != nkIdent: - invalidPragma(n) + invalidPragma(c, n) else: case n.sons[1].ident.s.normalize of "speed": - incl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) + incl(c.config.options, optOptimizeSpeed) + excl(c.config.options, optOptimizeSize) of "size": - excl(gOptions, optOptimizeSpeed) - incl(gOptions, optOptimizeSize) + excl(c.config.options, optOptimizeSpeed) + incl(c.config.options, optOptimizeSize) of "none": - excl(gOptions, optOptimizeSpeed) - excl(gOptions, optOptimizeSize) - else: localError(n.info, errNoneSpeedOrSizeExpected) + excl(c.config.options, optOptimizeSpeed) + excl(c.config.options, optOptimizeSize) + else: localError(c.config, n.info, "'none', 'speed' or 'size' expected") of wImplicitStatic: onOff(c, n, {optImplicitStatic}) of wPatterns: onOff(c, n, {optPatterns}) else: result = true proc processPush(c: PContext, n: PNode, start: int) = if n.sons[start-1].kind in nkPragmaCallKinds: - localError(n.info, errGenerated, "'push' can't have arguments") - var x = newOptionEntry() + localError(c.config, n.info, "'push' cannot have arguments") + var x = newOptionEntry(c.config) var y = c.optionStack[^1] - x.options = gOptions + x.options = c.config.options x.defaultCC = y.defaultCC x.dynlib = y.dynlib - x.notes = gNotes + x.notes = c.config.notes c.optionStack.add(x) for i in countup(start, sonsLen(n) - 1): if processOption(c, n.sons[i]): @@ -370,29 +372,29 @@ proc processPush(c: PContext, n: PNode, start: int) = if x.otherPragmas.isNil: x.otherPragmas = newNodeI(nkPragma, n.info) x.otherPragmas.add n.sons[i] - #localError(n.info, errOptionExpected) + #localError(c.config, n.info, errOptionExpected) proc processPop(c: PContext, n: PNode) = if c.optionStack.len <= 1: - localError(n.info, errAtPopWithoutPush) + localError(c.config, n.info, "{.pop.} without a corresponding {.push.}") else: - gOptions = c.optionStack[^1].options - gNotes = c.optionStack[^1].notes + c.config.options = c.optionStack[^1].options + c.config.notes = c.optionStack[^1].notes c.optionStack.setLen(c.optionStack.len - 1) proc processDefine(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent): - defineSymbol(n.sons[1].ident.s) - message(n.info, warnDeprecated, "define") + if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): + defineSymbol(c.config.symbols, n[1].ident.s) + message(c.config, n.info, warnDeprecated, "define") else: - invalidPragma(n) + invalidPragma(c, n) proc processUndef(c: PContext, n: PNode) = - if (n.kind in nkPragmaCallKinds and n.len == 2) and (n.sons[1].kind == nkIdent): - undefSymbol(n.sons[1].ident.s) - message(n.info, warnDeprecated, "undef") + if (n.kind in nkPragmaCallKinds and n.len == 2) and (n[1].kind == nkIdent): + undefSymbol(c.config.symbols, n[1].ident.s) + message(c.config, n.info, warnDeprecated, "undef") else: - invalidPragma(n) + invalidPragma(c, n) type TLinkFeature = enum @@ -406,18 +408,18 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string = if not fileExists(result): if isAbsolute(s): result = s else: - result = findFile(s) + result = findFile(c.config, s) if result.len == 0: result = s proc processCompile(c: PContext, n: PNode) = proc getStrLit(c: PContext, n: PNode; i: int): string = - n.sons[i] = c.semConstExpr(c, n.sons[i]) - case n.sons[i].kind + n.sons[i] = c.semConstExpr(c, n[i]) + case n[i].kind of nkStrLit, nkRStrLit, nkTripleStrLit: - shallowCopy(result, n.sons[i].strVal) + shallowCopy(result, n[i].strVal) else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) result = "" let it = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] else: n @@ -428,26 +430,27 @@ proc processCompile(c: PContext, n: PNode) = for f in os.walkFiles(found): let nameOnly = extractFilename(f) var cf = Cfile(cname: f, - obj: completeCFilePath(dest % nameOnly), + obj: completeCFilePath(c.config, dest % nameOnly), flags: {CfileFlag.External}) - extccomp.addExternalFileToCompile(cf) + extccomp.addExternalFileToCompile(c.config, cf) else: let s = expectStrLit(c, n) var found = parentDir(n.info.toFullPath) / s if not fileExists(found): if isAbsolute(s): found = s else: - found = findFile(s) + found = findFile(c.config, s) if found.len == 0: found = s - extccomp.addExternalFileToCompile(found) + extccomp.addExternalFileToCompile(c.config, found) proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = let found = relativeFile(c, n, CC[cCompiler].objExt) case feature - of linkNormal: extccomp.addExternalFileToLink(found) + of linkNormal: extccomp.addExternalFileToLink(c.config, found) of linkSys: - extccomp.addExternalFileToLink(libpath / completeCFilePath(found, false)) - else: internalError(n.info, "processCommonLink") + extccomp.addExternalFileToLink(c.config, + c.config.libpath / completeCFilePath(c.config, found, false)) + else: internalError(c.config, n.info, "processCommonLink") proc pragmaBreakpoint(c: PContext, n: PNode) = discard getOptionalStr(c, n, "") @@ -456,7 +459,7 @@ proc pragmaWatchpoint(c: PContext, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: n.sons[1] = c.semExpr(c, n.sons[1]) else: - invalidPragma(n) + invalidPragma(c, n) proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = case n.sons[1].kind @@ -464,7 +467,7 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = result = newNode(if n.kind == nkAsmStmt: nkAsmStmt else: nkArgList, n.info) var str = n.sons[1].strVal if str == "": - localError(n.info, errEmptyAsm) + localError(con.config, n.info, "empty 'asm' statement") return # now parse the string literal and substitute symbols: var a = 0 @@ -490,12 +493,12 @@ proc semAsmOrEmit*(con: PContext, n: PNode, marker: char): PNode = if c < 0: break a = c + 1 else: - illFormedAstLocal(n) + illFormedAstLocal(n, con.config) result = newNode(nkAsmStmt, n.info) proc pragmaEmit(c: PContext, n: PNode) = if n.kind notin nkPragmaCallKinds or n.len != 2: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) else: let n1 = n[1] if n1.kind == nkBracket: @@ -509,20 +512,20 @@ proc pragmaEmit(c: PContext, n: PNode) = of nkStrLit, nkRStrLit, nkTripleStrLit: n.sons[1] = semAsmOrEmit(c, n, '`') else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) -proc noVal(n: PNode) = - if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(n) +proc noVal(c: PContext; n: PNode) = + if n.kind in nkPragmaCallKinds and n.len > 1: invalidPragma(c, n) proc pragmaUnroll(c: PContext, n: PNode) = if c.p.nestedLoopCounter <= 0: - invalidPragma(n) + invalidPragma(c, n) elif n.kind in nkPragmaCallKinds and n.len == 2: var unrollFactor = expectIntLit(c, n) if unrollFactor <% 32: n.sons[1] = newIntNode(nkIntLit, unrollFactor) else: - invalidPragma(n) + invalidPragma(c, n) proc pragmaLine(c: PContext, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: @@ -535,26 +538,26 @@ proc pragmaLine(c: PContext, n: PNode) = if x.kind == nkExprColonExpr: x = x.sons[1] if y.kind == nkExprColonExpr: y = y.sons[1] if x.kind != nkStrLit: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) elif y.kind != nkIntLit: - localError(n.info, errIntLiteralExpected) + localError(c.config, n.info, errIntLiteralExpected) else: # XXX this produces weird paths which are not properly resolved: - n.info.fileIndex = msgs.fileInfoIdx(x.strVal) + n.info.fileIndex = msgs.fileInfoIdx(c.config, x.strVal) n.info.line = uint16(y.intVal) else: - localError(n.info, errXExpected, "tuple") + localError(c.config, n.info, "tuple expected") else: # sensible default: n.info = getInfoContext(-1) proc processPragma(c: PContext, n: PNode, i: int) = let it = n[i] - if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(n) - elif it[0].kind != nkIdent: invalidPragma(n) - elif it[1].kind != nkIdent: invalidPragma(n) + if it.kind notin nkPragmaCallKinds and it.len == 2: invalidPragma(c, n) + elif it[0].kind != nkIdent: invalidPragma(c, n) + elif it[1].kind != nkIdent: invalidPragma(c, n) - var userPragma = newSym(skTemplate, it[1].ident, nil, it.info) + var userPragma = newSym(skTemplate, it[1].ident, nil, it.info, c.config.options) userPragma.ast = newNode(nkPragma, n.info, n.sons[i+1..^1]) strTableAdd(c.userPragmas, userPragma) @@ -562,7 +565,7 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = proc processExc(c: PContext, x: PNode) = var t = skipTypes(c.semTypeNode(c, x, nil), skipPtrs) if t.kind != tyObject: - localError(x.info, errGenerated, "invalid type for raises/tags list") + localError(c.config, x.info, errGenerated, "invalid type for raises/tags list") x.typ = t if n.kind in nkPragmaCallKinds and n.len == 2: @@ -572,51 +575,51 @@ proc pragmaRaisesOrTags(c: PContext, n: PNode) = else: for e in items(it): processExc(c, e) else: - invalidPragma(n) + invalidPragma(c, n) proc pragmaLockStmt(c: PContext; it: PNode) = if it.kind notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it) + invalidPragma(c, it) else: let n = it[1] if n.kind != nkBracket: - localError(n.info, errGenerated, "locks pragma takes a list of expressions") + localError(c.config, n.info, errGenerated, "locks pragma takes a list of expressions") else: for i in 0 ..< n.len: n.sons[i] = c.semExpr(c, n.sons[i]) proc pragmaLocks(c: PContext, it: PNode): TLockLevel = if it.kind notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it) + invalidPragma(c, it) else: case it[1].kind of nkStrLit, nkRStrLit, nkTripleStrLit: if it[1].strVal == "unknown": result = UnknownLockLevel else: - localError(it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") + localError(c.config, it[1].info, "invalid string literal for locks pragma (only allowed string is \"unknown\")") else: let x = expectIntLit(c, it) if x < 0 or x > MaxLockLevel: - localError(it[1].info, "integer must be within 0.." & $MaxLockLevel) + localError(c.config, it[1].info, "integer must be within 0.." & $MaxLockLevel) else: result = TLockLevel(x) -proc typeBorrow(sym: PSym, n: PNode) = +proc typeBorrow(c: PContext; sym: PSym, n: PNode) = if n.kind in nkPragmaCallKinds and n.len == 2: let it = n.sons[1] if it.kind != nkAccQuoted: - localError(n.info, "a type can only borrow `.` for now") + localError(c.config, n.info, "a type can only borrow `.` for now") incl(sym.typ.flags, tfBorrowDot) -proc markCompilerProc(s: PSym) = +proc markCompilerProc(c: PContext; s: PSym) = # minor hack ahead: FlowVar is the only generic .compilerProc type which # should not have an external name set: if s.kind != skType or s.name.s != "FlowVar": - makeExternExport(s, "$1", s.info) + makeExternExport(c, s, "$1", s.info) incl(s.flags, sfCompilerProc) incl(s.flags, sfUsed) - registerCompilerProc(s) + registerCompilerProc(c.graph, s) proc deprecatedStmt(c: PContext; outerPragma: PNode) = let pragma = outerPragma[1] @@ -625,24 +628,24 @@ proc deprecatedStmt(c: PContext; outerPragma: PNode) = c.module.constraint = getStrLitNode(c, outerPragma) return if pragma.kind != nkBracket: - localError(pragma.info, "list of key:value pairs expected"); return + localError(c.config, pragma.info, "list of key:value pairs expected"); return for n in pragma: if n.kind in nkPragmaCallKinds and n.len == 2: let dest = qualifiedLookUp(c, n[1], {checkUndeclared}) if dest == nil or dest.kind in routineKinds: - localError(n.info, warnUser, "the .deprecated pragma is unreliable for routines") - let src = considerQuotedIdent(n[0]) - let alias = newSym(skAlias, src, dest, n[0].info) + localError(c.config, n.info, warnUser, "the .deprecated pragma is unreliable for routines") + let src = considerQuotedIdent(c.config, n[0]) + let alias = newSym(skAlias, src, dest, n[0].info, c.config.options) incl(alias.flags, sfExported) - if sfCompilerProc in dest.flags: markCompilerProc(alias) + if sfCompilerProc in dest.flags: markCompilerProc(c, alias) addInterfaceDecl(c, alias) n.sons[1] = newSymNode(dest) else: - localError(n.info, "key:value pair expected") + localError(c.config, n.info, "key:value pair expected") proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = if it.kind notin nkPragmaCallKinds or it.len != 2: - invalidPragma(it); return + invalidPragma(c, it); return let n = it[1] if n.kind == nkSym: result = n.sym @@ -654,7 +657,8 @@ proc pragmaGuard(c: PContext; it: PNode; kind: TSymKind): PSym = # We return a dummy symbol; later passes over the type will repair it. # Generic instantiation needs to know about this too. But we're lazy # and perform the lookup on demand instead. - result = newSym(skUnknown, considerQuotedIdent(n), nil, n.info) + result = newSym(skUnknown, considerQuotedIdent(c.config, n), nil, n.info, + c.config.options) else: result = qualifiedLookUp(c, n, {checkUndeclared}) @@ -667,12 +671,12 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = elif n.kind in nkPragmaCallKinds + {nkIdent}: result = n else: - invalidPragma(n) + invalidPragma(c, n) return n let r = c.semOverloadedCall(c, result, n, {skTemplate}, {}) if r.isNil or sfCustomPragma notin r[0].sym.flags: - invalidPragma(n) + invalidPragma(c, n) else: result = r if n.kind == nkIdent: @@ -682,7 +686,7 @@ proc semCustomPragma(c: PContext, n: PNode): PNode = proc processExperimental(c: PContext; n: PNode; s: PSym) = if not isTopLevel(c): - localError(n.info, "'experimental' pragma only valid as toplevel statement") + localError(c.config, n.info, "'experimental' pragma only valid as toplevel statement") if n.kind notin nkPragmaCallKinds or n.len != 2: c.features.incl oldExperimentalFeatures else: @@ -692,9 +696,9 @@ proc processExperimental(c: PContext; n: PNode; s: PSym) = try: c.features.incl parseEnum[Feature](n[1].strVal) except ValueError: - localError(n[1].info, "unknown experimental feature") + localError(c.config, n[1].info, "unknown experimental feature") else: - localError(n.info, errStringLiteralExpected) + localError(c.config, n.info, errStringLiteralExpected) proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, validPragmas: TSpecialWords): bool = @@ -706,13 +710,13 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, elif key.kind notin nkIdentKinds: n.sons[i] = semCustomPragma(c, it) return - let ident = considerQuotedIdent(key) + let ident = considerQuotedIdent(c.config, key) var userPragma = strTableGet(c.userPragmas, ident) if userPragma != nil: # number of pragmas increase/decrease with user pragma expansion inc c.instCounter if c.instCounter > 100: - globalError(it.info, errRecursiveDependencyX, userPragma.name.s) + globalError(c.config, it.info, "recursive dependency: " & userPragma.name.s) pragma(c, sym, userPragma.ast, validPragmas) n.sons[i..i] = userPragma.ast.sons # expand user pragma with its content @@ -723,78 +727,78 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, if k in validPragmas: case k of wExportc: - makeExternExport(sym, getOptionalStr(c, it, "$1"), it.info) + makeExternExport(c, sym, getOptionalStr(c, it, "$1"), it.info) incl(sym.flags, sfUsed) # avoid wrong hints of wImportc: let name = getOptionalStr(c, it, "$1") - cppDefine(c.graph.config, name) - makeExternImport(sym, name, it.info) + cppDefine(c.config, name) + makeExternImport(c, sym, name, it.info) of wImportCompilerProc: let name = getOptionalStr(c, it, "$1") - cppDefine(c.graph.config, name) - processImportCompilerProc(sym, name, it.info) - of wExtern: setExternName(sym, expectStrLit(c, it), it.info) + cppDefine(c.config, name) + processImportCompilerProc(c, sym, name, it.info) + of wExtern: setExternName(c, sym, expectStrLit(c, it), it.info) of wImmediate: if sym.kind in {skTemplate, skMacro}: incl(sym.flags, sfImmediate) incl(sym.flags, sfAllUntyped) - message(n.info, warnDeprecated, "use 'untyped' parameters instead; immediate") - else: invalidPragma(it) + message(c.config, n.info, warnDeprecated, "use 'untyped' parameters instead; immediate") + else: invalidPragma(c, it) of wDirty: if sym.kind == skTemplate: incl(sym.flags, sfDirty) - else: invalidPragma(it) + else: invalidPragma(c, it) of wImportCpp: - processImportCpp(sym, getOptionalStr(c, it, "$1"), it.info) + processImportCpp(c, sym, getOptionalStr(c, it, "$1"), it.info) of wImportObjC: - processImportObjC(sym, getOptionalStr(c, it, "$1"), it.info) + processImportObjC(c, sym, getOptionalStr(c, it, "$1"), it.info) of wAlign: - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) var align = expectIntLit(c, it) if (not isPowerOfTwo(align) and align != 0) or align >% high(int16): - localError(it.info, errPowerOfTwoExpected) + localError(c.config, it.info, "power of two expected") else: sym.typ.align = align.int16 of wSize: - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) var size = expectIntLit(c, it) if not isPowerOfTwo(size) or size <= 0 or size > 8: - localError(it.info, errPowerOfTwoExpected) + localError(c.config, it.info, "power of two expected") else: sym.typ.size = size of wNodecl: - noVal(it) + noVal(c, it) incl(sym.loc.flags, lfNoDecl) of wPure, wAsmNoStackFrame: - noVal(it) + noVal(c, it) if sym != nil: - if k == wPure and sym.kind in routineKinds: invalidPragma(it) + if k == wPure and sym.kind in routineKinds: invalidPragma(c, it) else: incl(sym.flags, sfPure) of wVolatile: - noVal(it) + noVal(c, it) incl(sym.flags, sfVolatile) of wRegister: - noVal(it) + noVal(c, it) incl(sym.flags, sfRegister) of wThreadVar: - noVal(it) + noVal(c, it) incl(sym.flags, {sfThread, sfGlobal}) of wDeadCodeElimUnused: discard # deprecated, dead code elim always on of wNoForward: pragmaNoForward(c, it) of wReorder: pragmaNoForward(c, it, sfReorder) of wMagic: processMagic(c, it, sym) of wCompileTime: - noVal(it) + noVal(c, it) incl(sym.flags, sfCompileTime) incl(sym.loc.flags, lfNoDecl) of wGlobal: - noVal(it) + noVal(c, it) incl(sym.flags, sfGlobal) incl(sym.flags, sfPure) of wMerge: # only supported for backwards compat, doesn't do anything anymore - noVal(it) + noVal(c, it) of wConstructor: - noVal(it) + noVal(c, it) incl(sym.flags, sfConstructor) of wHeader: var lib = getLib(c, libHeader, getStrLitNode(c, it)) @@ -807,25 +811,26 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wOverride: sym.flags.incl sfOverriden of wNosideeffect: - noVal(it) + noVal(c, it) incl(sym.flags, sfNoSideEffect) if sym.typ != nil: incl(sym.typ.flags, tfNoSideEffect) of wSideeffect: - noVal(it) + noVal(c, it) incl(sym.flags, sfSideEffect) of wNoreturn: - noVal(it) + noVal(c, it) incl(sym.flags, sfNoReturn) if sym.typ[0] != nil: - localError(sym.ast[paramsPos][0].info, errNoReturnWithReturnTypeNotAllowed) + localError(c.config, sym.ast[paramsPos][0].info, + ".noreturn with return type not allowed") of wDynlib: processDynLib(c, it, sym) of wCompilerProc, wCore: - noVal(it) # compilerproc may not get a string! + noVal(c, it) # compilerproc may not get a string! cppDefine(c.graph.config, sym.name.s) - if sfFromGeneric notin sym.flags: markCompilerProc(sym) + if sfFromGeneric notin sym.flags: markCompilerProc(c, sym) of wProcVar: - noVal(it) + noVal(c, it) incl(sym.flags, sfProcvar) of wExplain: sym.flags.incl sfExplain @@ -837,74 +842,74 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, elif sym != nil: incl(sym.flags, sfDeprecated) else: incl(c.module.flags, sfDeprecated) of wVarargs: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfVarargs) of wBorrow: if sym.kind == skType: - typeBorrow(sym, it) + typeBorrow(c, sym, it) else: - noVal(it) + noVal(c, it) incl(sym.flags, sfBorrow) of wFinal: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfFinal) of wInheritable: - noVal(it) - if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(it) + noVal(c, it) + if sym.typ == nil or tfFinal in sym.typ.flags: invalidPragma(c, it) else: incl(sym.typ.flags, tfInheritable) of wPackage: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.flags, sfForward) of wAcyclic: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfAcyclic) of wShallow: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfShallow) of wThread: - noVal(it) + noVal(c, it) incl(sym.flags, sfThread) incl(sym.flags, sfProcvar) if sym.typ != nil: incl(sym.typ.flags, tfThread) if sym.typ.callConv == ccClosure: sym.typ.callConv = ccDefault of wGcSafe: - noVal(it) + noVal(c, it) if sym != nil: if sym.kind != skType: incl(sym.flags, sfThread) if sym.typ != nil: incl(sym.typ.flags, tfGcSafe) - else: invalidPragma(it) + else: invalidPragma(c, it) else: discard "no checking if used as a code block" of wPacked: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfPacked) - of wHint: message(it.info, hintUser, expectStrLit(c, it)) - of wWarning: message(it.info, warnUser, expectStrLit(c, it)) + of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it)) + of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it)) of wError: if sym != nil and sym.isRoutine: # This is subtle but correct: the error *statement* is only # allowed for top level statements. Seems to be easier than # distinguishing properly between # ``proc p() {.error}`` and ``proc p() = {.error: "msg".}`` - noVal(it) + noVal(c, it) incl(sym.flags, sfError) else: - localError(it.info, errUser, expectStrLit(c, it)) - of wFatal: fatal(it.info, errUser, expectStrLit(c, it)) + localError(c.config, it.info, errUser, expectStrLit(c, it)) + of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it)) of wDefine: processDefine(c, it) of wUndef: processUndef(c, it) of wCompile: processCompile(c, it) of wLink: processCommonLink(c, it, linkNormal) of wLinksys: processCommonLink(c, it, linkSys) - of wPassl: extccomp.addLinkOption(expectStrLit(c, it)) - of wPassc: extccomp.addCompileOption(expectStrLit(c, it)) + of wPassl: extccomp.addLinkOption(c.config, expectStrLit(c, it)) + of wPassc: extccomp.addCompileOption(c.config, expectStrLit(c, it)) of wBreakpoint: pragmaBreakpoint(c, it) of wWatchPoint: pragmaWatchpoint(c, it) of wPush: @@ -918,10 +923,10 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, processPragma(c, n, i) result = true of wDiscardable: - noVal(it) + noVal(c, it) if sym != nil: incl(sym.flags, sfDiscardable) of wNoInit: - noVal(it) + noVal(c, it) if sym != nil: incl(sym.flags, sfNoInit) of wCodegenDecl: processCodegenDecl(c, it, sym) of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks, @@ -932,106 +937,106 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, wPatterns: if processOption(c, it): # calling conventions (boring...): - localError(it.info, errOptionExpected) + localError(c.config, it.info, "option expected") of FirstCallConv..LastCallConv: assert(sym != nil) - if sym.typ == nil: invalidPragma(it) + if sym.typ == nil: invalidPragma(c, it) else: sym.typ.callConv = wordToCallConv(k) of wEmit: pragmaEmit(c, it) of wUnroll: pragmaUnroll(c, it) - of wLinearScanEnd, wComputedGoto: noVal(it) + of wLinearScanEnd, wComputedGoto: noVal(c, it) of wEffects: # is later processed in effect analysis: - noVal(it) + noVal(c, it) of wIncompleteStruct: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfIncompleteStruct) of wUnchecked: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfUncheckedArray) of wUnion: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfUnion) of wRequiresInit: - noVal(it) - if sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfNeedsInit) of wByRef: - noVal(it) + noVal(c, it) if sym == nil or sym.typ == nil: - if processOption(c, it): localError(it.info, errOptionExpected) + if processOption(c, it): localError(c.config, it.info, "option expected") else: incl(sym.typ.flags, tfByRef) of wByCopy: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.kind != skType or sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfByCopy) of wPartial: - noVal(it) - if sym.kind != skType or sym.typ == nil: invalidPragma(it) + noVal(c, it) + if sym.kind != skType or sym.typ == nil: invalidPragma(c, it) else: incl(sym.typ.flags, tfPartial) of wInject, wGensym: # We check for errors, but do nothing with these pragmas otherwise # as they are handled directly in 'evalTemplate'. - noVal(it) - if sym == nil: invalidPragma(it) + noVal(c, it) + if sym == nil: invalidPragma(c, it) of wLine: pragmaLine(c, it) of wRaises, wTags: pragmaRaisesOrTags(c, it) of wLocks: if sym == nil: pragmaLockStmt(c, it) - elif sym.typ == nil: invalidPragma(it) + elif sym.typ == nil: invalidPragma(c, it) else: sym.typ.lockLevel = pragmaLocks(c, it) of wBitsize: if sym == nil or sym.kind != skField: - invalidPragma(it) + invalidPragma(c, it) else: sym.bitsize = expectIntLit(c, it) of wGuard: if sym == nil or sym.kind notin {skVar, skLet, skField}: - invalidPragma(it) + invalidPragma(c, it) else: sym.guard = pragmaGuard(c, it, sym.kind) of wGoto: if sym == nil or sym.kind notin {skVar, skLet}: - invalidPragma(it) + invalidPragma(c, it) else: sym.flags.incl sfGoto of wExportNims: - if sym == nil: invalidPragma(it) - else: magicsys.registerNimScriptSymbol(sym) + if sym == nil: invalidPragma(c, it) + else: magicsys.registerNimScriptSymbol(c.graph, sym) of wInjectStmt: if it.kind notin nkPragmaCallKinds or it.len != 2: - localError(it.info, errExprExpected) + localError(c.config, it.info, "expression expected") else: it.sons[1] = c.semExpr(c, it.sons[1]) of wExperimental: processExperimental(c, it, sym) of wThis: if it.kind in nkPragmaCallKinds and it.len == 2: - c.selfName = considerQuotedIdent(it[1]) + c.selfName = considerQuotedIdent(c.config, it[1]) elif it.kind == nkIdent or it.len == 1: c.selfName = getIdent("self") else: - localError(it.info, "'this' pragma is allowed to have zero or one arguments") + localError(c.config, it.info, "'this' pragma is allowed to have zero or one arguments") of wNoRewrite: - noVal(it) + noVal(c, it) of wBase: - noVal(it) + noVal(c, it) sym.flags.incl sfBase of wIntDefine: sym.magic = mIntDefine of wStrDefine: sym.magic = mStrDefine of wUsed: - noVal(it) - if sym == nil: invalidPragma(it) + noVal(c, it) + if sym == nil: invalidPragma(c, it) else: sym.flags.incl sfUsed of wLiftLocals: discard - else: invalidPragma(it) + else: invalidPragma(c, it) else: n.sons[i] = semCustomPragma(c, it) @@ -1046,12 +1051,12 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode, var i = 0 while i < o.len(): if singlePragma(c, sym, o, i, validPragmas): - internalError(n.info, "implicitPragmas") + internalError(c.config, n.info, "implicitPragmas") inc i popInfoContext() if lfExportLib in sym.loc.flags and sfExportc notin sym.flags: - localError(n.info, errDynlibRequiresExportc) + localError(c.config, n.info, ".dynlib requires .exportc") var lib = c.optionStack[^1].dynlib if {lfDynamicLib, lfHeader} * sym.loc.flags == {} and sfImportc in sym.flags and lib != nil: @@ -1063,7 +1068,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = if n == nil or n.sons == nil: return false - for p in n.sons: + for p in n: var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p if key.kind == nkIdent and whichKeyword(key.ident) == pragma: return true diff --git a/compiler/procfind.nim b/compiler/procfind.nim index f7d86aaef..042947e72 100644 --- a/compiler/procfind.nim +++ b/compiler/procfind.nim @@ -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 diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 0c861bdb8..259d0211f 100644 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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 = @@ -1432,11 +1434,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: @@ -1454,7 +1456,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]) @@ -1464,16 +1466,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) = diff --git a/compiler/reorder.nim b/compiler/reorder.nim index 2542a08ea..d50be1d99 100644 --- a/compiler/reorder.nim +++ b/compiler/reorder.nim @@ -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) diff --git a/compiler/rodread.nim b/compiler/rodread.nim index f55c3279c..52e7a924c 100644 --- a/compiler/rodread.nim +++ b/compiler/rodread.nim @@ -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': diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 0ae687268..4686baf2b 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -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) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 6ef42f15e..30e5e4803 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -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") diff --git a/compiler/sem.nim b/compiler/sem.nim index d8e5b7f20..c5c3dd99b 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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) diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index 5c7b91f6d..f0fde195c 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -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) diff --git a/compiler/semcall.nim b/compiler/semcall.nim index aa53fda3b..e9a31d3d6 100644 --- a/compiler/semcall.nim +++ b/compiler/semcall.nim @@ -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 diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 62be471f7..12ac19ca3 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -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 diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 79010bfde..92b9c365a 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -10,12 +10,24 @@ # this module does the semantic checking for expressions # included from sem.nim +const + errExprXHasNoType = "expression '$1' has no type (or is ambiguous)" + errXExpectsTypeOrValue = "'$1' expects a type or value" + errVarForOutParamNeededX = "for a 'var' type a variable needs to be passed; but '$1' is immutable" + errXStackEscape = "address of '$1' may not escape its stack frame" + errExprHasNoAddress = "expression has no address; maybe use 'unsafeAddr'" + errCannotInterpretNodeX = "cannot evaluate '$1'" + errNamedExprExpected = "named expression expected" + errNamedExprNotAllowed = "named expression not allowed here" + errFieldInitTwice = "field initialized twice: '$1'" + errUndeclaredFieldX = "undeclared field: '$1'" + proc semTemplateExpr(c: PContext, n: PNode, s: PSym, flags: TExprFlags = {}): PNode = - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) pushInfoContext(n.info) - result = evalTemplate(n, s, getCurrOwner(c), efFromHlo in flags) + result = evalTemplate(n, s, getCurrOwner(c), c.config, efFromHlo in flags) if efNoSemCheck notin flags: result = semAfterMacroCall(c, n, result, s, flags) popInfoContext() @@ -31,12 +43,12 @@ proc semOperand(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.typ != nil: # XXX tyGenericInst here? if result.typ.kind == tyProc and tfUnresolved in result.typ.flags: - localError(n.info, errProcHasNoConcreteType, n.renderTree) + localError(c.config, n.info, errProcHasNoConcreteType % n.renderTree) if result.typ.kind in {tyVar, tyLent}: result = newDeref(result) elif {efWantStmt, efAllowStmt} * flags != {}: result.typ = newTypeS(tyVoid, c) else: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) @@ -47,7 +59,7 @@ proc semExprWithType(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = #raiseRecoverableError("") result = errorNode(c, n) if result.typ == nil or result.typ == enforceVoidContext: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) else: @@ -59,17 +71,17 @@ proc semExprNoDeref(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # do not produce another redundant error message: result = errorNode(c, n) if result.typ == nil: - localError(n.info, errExprXHasNoType, + localError(c.config, n.info, errExprXHasNoType % renderTree(result, {renderNoComments})) result.typ = errorType(c) proc semSymGenericInstantiation(c: PContext, n: PNode, s: PSym): PNode = result = symChoice(c, n, s, scClosed) -proc inlineConst(n: PNode, s: PSym): PNode {.inline.} = +proc inlineConst(c: PContext, n: PNode, s: PSym): PNode {.inline.} = result = copyTree(s.ast) if result.isNil: - localError(n.info, "constant of type '" & typeToString(s.typ) & "' has no value") + localError(c.config, n.info, "constant of type '" & typeToString(s.typ) & "' has no value") result = newSymNode(s) else: result.typ = s.typ @@ -172,7 +184,7 @@ proc maybeLiftType(t: var PType, c: PContext, info: TLineInfo) = proc semConv(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(n.info, errConvNeedsOneArg) + localError(c.config, n.info, "a type conversion takes exactly one argument") return n result = newNodeI(nkConv, n.info) @@ -192,7 +204,7 @@ proc semConv(c: PContext, n: PNode): PNode = # special case to make MyObject(x = 3) produce a nicer error message: if n[1].kind == nkExprEqExpr and targetType.skipTypes(abstractPtrs).kind == tyObject: - localError(n.info, "object contruction uses ':', not '='") + localError(c.config, n.info, "object contruction uses ':', not '='") var op = semExprWithType(c, n.sons[1]) if targetType.isMetaType: let final = inferWithMetatype(c, targetType, op, true) @@ -215,18 +227,18 @@ proc semConv(c: PContext, n: PNode): PNode = elif op.kind in {nkPar, nkTupleConstr} and targetType.kind == tyTuple: op = fitNode(c, targetType, op, result.info) of convNotNeedeed: - message(n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) + message(c.config, n.info, hintConvFromXtoItselfNotNeeded, result.typ.typeToString) of convNotLegal: result = fitNode(c, result.typ, result.sons[1], result.info) if result == nil: - localError(n.info, errGenerated, msgKindToString(errIllegalConvFromXtoY)% + localError(c.config, n.info, "illegal conversion from '$1' to '$2'" % [op.typ.typeToString, result.typ.typeToString]) else: for i in countup(0, sonsLen(op) - 1): let it = op.sons[i] let status = checkConvertible(c, result.typ, it.typ) if status in {convOK, convNotNeedeed}: - markUsed(n.info, it.sym, c.graph.usageSym) + markUsed(c.config, n.info, it.sym, c.graph.usageSym) styleCheckUse(n.info, it.sym) markIndirect(c, it.sym) return it @@ -234,16 +246,16 @@ proc semConv(c: PContext, n: PNode): PNode = proc semCast(c: PContext, n: PNode): PNode = ## Semantically analyze a casting ("cast[type](param)") - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) let targetType = semTypeNode(c, n.sons[0], nil) let castedExpr = semExprWithType(c, n.sons[1]) if tfHasMeta in targetType.flags: - localError(n.sons[0].info, errCastToANonConcreteType, $targetType) + localError(c.config, n.sons[0].info, "cannot cast to a non concrete type: '$1'" % $targetType) if not isCastable(targetType, castedExpr.typ): let tar = $targetType let alt = typeToString(targetType, preferDesc) let msg = if tar != alt: tar & "=" & alt else: tar - localError(n.info, errExprCannotBeCastToX, msg) + localError(c.config, n.info, "expression cannot be cast to " & msg) result = newNodeI(nkCast, n.info) result.typ = targetType addSon(result, copyTree(n.sons[0])) @@ -253,13 +265,13 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = const opToStr: array[mLow..mHigh, string] = ["low", "high"] if sonsLen(n) != 2: - localError(n.info, errXExpectsTypeOrValue, opToStr[m]) + localError(c.config, n.info, errXExpectsTypeOrValue % opToStr[m]) else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) var typ = skipTypes(n.sons[1].typ, abstractVarRange + {tyTypeDesc}) case typ.kind of tySequence, tyString, tyCString, tyOpenArray, tyVarargs: - n.typ = getSysType(tyInt) + n.typ = getSysType(c.graph, n.info, tyInt) of tyArray: n.typ = typ.sons[0] # indextype of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32: @@ -271,20 +283,20 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode = # that could easily turn into an infinite recursion in semtypinst n.typ = makeTypeFromExpr(c, n.copyTree) else: - localError(n.info, errInvalidArgForX, opToStr[m]) + localError(c.config, n.info, "invalid argument for: " & opToStr[m]) result = n proc semSizeof(c: PContext, n: PNode): PNode = if sonsLen(n) != 2: - localError(n.info, errXExpectsTypeOrValue, "sizeof") + localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof") else: n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType}) #restoreOldStyleType(n.sons[1]) - n.typ = getSysType(tyInt) + n.typ = getSysType(c.graph, n.info, tyInt) result = n proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = - internalAssert n.sonsLen == 3 and + internalAssert c.config, n.sonsLen == 3 and n[1].typ != nil and n[1].typ.kind == tyTypeDesc and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} @@ -315,10 +327,10 @@ proc isOpImpl(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semIs(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) != 3: - localError(n.info, errXExpectsTwoArguments, "is") + localError(c.config, n.info, "'is' operator takes 2 arguments") result = n - n.typ = getSysType(tyBool) + n.typ = getSysType(c.graph, n.info, tyBool) n.sons[1] = semExprWithType(c, n[1], {efDetermineType, efWantIterator}) if n[2].kind notin {nkStrLit..nkTripleStrLit}: @@ -340,8 +352,8 @@ proc semOpAux(c: PContext, n: PNode) = for i in countup(1, n.sonsLen-1): var a = n.sons[i] if a.kind == nkExprEqExpr and sonsLen(a) == 2: - var info = a.sons[0].info - a.sons[0] = newIdentNode(considerQuotedIdent(a.sons[0], a), info) + let info = a.sons[0].info + a.sons[0] = newIdentNode(considerQuotedIdent(c.config, a.sons[0], a), info) a.sons[1] = semExprWithType(c, a.sons[1], flags) a.typ = a.sons[1].typ else: @@ -358,34 +370,34 @@ proc overloadedCallOpr(c: PContext, n: PNode): PNode = for i in countup(0, sonsLen(n) - 1): addSon(result, n.sons[i]) result = semExpr(c, result) -proc changeType(n: PNode, newType: PType, check: bool) = +proc changeType(c: PContext; n: PNode, newType: PType, check: bool) = case n.kind of nkCurly, nkBracket: for i in countup(0, sonsLen(n) - 1): - changeType(n.sons[i], elemType(newType), check) + changeType(c, n.sons[i], elemType(newType), check) of nkPar, nkTupleConstr: let tup = newType.skipTypes({tyGenericInst, tyAlias, tySink}) if tup.kind != tyTuple: if tup.kind == tyObject: return - globalError(n.info, "no tuple type for constructor") + globalError(c.config, n.info, "no tuple type for constructor") elif sonsLen(n) > 0 and n.sons[0].kind == nkExprColonExpr: # named tuple? for i in countup(0, sonsLen(n) - 1): var m = n.sons[i].sons[0] if m.kind != nkSym: - globalError(m.info, "invalid tuple constructor") + globalError(c.config, m.info, "invalid tuple constructor") return if tup.n != nil: var f = getSymFromList(tup.n, m.sym.name) if f == nil: - globalError(m.info, "unknown identifier: " & m.sym.name.s) + globalError(c.config, m.info, "unknown identifier: " & m.sym.name.s) return - changeType(n.sons[i].sons[1], f.typ, check) + changeType(c, n.sons[i].sons[1], f.typ, check) else: - changeType(n.sons[i].sons[1], tup.sons[i], check) + changeType(c, n.sons[i].sons[1], tup.sons[i], check) else: for i in countup(0, sonsLen(n) - 1): - changeType(n.sons[i], tup.sons[i], check) + changeType(c, n.sons[i], tup.sons[i], check) when false: var m = n.sons[i] var a = newNodeIT(nkExprColonExpr, m.info, newType.sons[i]) @@ -396,7 +408,7 @@ proc changeType(n: PNode, newType: PType, check: bool) = if check and n.kind != nkUInt64Lit: let value = n.intVal if value < firstOrd(newType) or value > lastOrd(newType): - localError(n.info, errGenerated, "cannot convert " & $value & + localError(c.config, n.info, "cannot convert " & $value & " to " & typeToString(newType)) else: discard n.typ = newType @@ -421,7 +433,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = else: var x = n.sons[0] var lastIndex: BiggestInt = 0 - var indexType = getSysType(tyInt) + var indexType = getSysType(c.graph, n.info, tyInt) if x.kind == nkExprColonExpr and sonsLen(x) == 2: var idx = semConstExpr(c, x.sons[0]) lastIndex = getOrdValue(idx) @@ -438,7 +450,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var idx = semConstExpr(c, x.sons[0]) idx = fitNode(c, indexType, idx, x.info) if lastIndex+1 != getOrdValue(idx): - localError(x.info, errInvalidOrderInArrayConstructor) + localError(c.config, x.info, "invalid order in array constructor") x = x.sons[1] let xx = semExprWithType(c, x, flags*{efAllowDestructor}) @@ -462,22 +474,22 @@ proc fixAbstractType(c: PContext, n: PNode) = {tyNil, tyTuple, tySet} or it[1].isArrayConstr: var s = skipTypes(it.typ, abstractVar) if s.kind != tyExpr: - changeType(it.sons[1], s, check=true) + changeType(c, it.sons[1], s, check=true) n.sons[i] = it.sons[1] proc isAssignable(c: PContext, n: PNode; isUnsafeAddr=false): TAssignableResult = result = parampatterns.isAssignable(c.p.owner, n, isUnsafeAddr) proc newHiddenAddrTaken(c: PContext, n: PNode): PNode = - if n.kind == nkHiddenDeref and not (gCmd == cmdCompileToCpp or + if n.kind == nkHiddenDeref and not (c.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags): - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) result = n.sons[0] else: result = newNodeIT(nkHiddenAddr, n.info, makeVarType(c, n.typ)) addSon(result, n) if isAssignable(c, n) notin {arLValue, arLocalLValue}: - localError(n.info, errVarForOutParamNeededX, renderNotLValue(n)) + localError(c.config, n.info, errVarForOutParamNeededX % renderNotLValue(n)) proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = n @@ -489,15 +501,15 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = incl(n.sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) of nkDotExpr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) if n.sons[1].kind != nkSym: - internalError(n.info, "analyseIfAddressTaken") + internalError(c.config, n.info, "analyseIfAddressTaken") return if skipTypes(n.sons[1].sym.typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: incl(n.sons[1].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) of nkBracketExpr: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) if skipTypes(n.sons[0].typ, abstractInst-{tyTypeDesc}).kind notin {tyVar, tyLent}: if n.sons[0].kind == nkSym: incl(n.sons[0].sym.flags, sfAddrTaken) result = newHiddenAddrTaken(c, n) @@ -505,7 +517,7 @@ proc analyseIfAddressTaken(c: PContext, n: PNode): PNode = result = newHiddenAddrTaken(c, n) proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) const FakeVarParams = {mNew, mNewFinalize, mInc, ast.mDec, mIncl, mExcl, mSetLengthStr, mSetLengthSeq, mAppendStrCh, mAppendStrStr, mSwap, @@ -524,14 +536,14 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) = let it = n[i] if isAssignable(c, it) notin {arLValue, arLocalLValue}: if it.kind != nkHiddenAddr: - localError(it.info, errVarForOutParamNeededX, $it) + localError(c.config, it.info, errVarForOutParamNeededX % $it) # bug #5113: disallow newSeq(result) where result is a 'var T': if n[0].sym.magic in {mNew, mNewFinalize, mNewSeq}: var arg = n[1] #.skipAddr if arg.kind == nkHiddenDeref: arg = arg[0] if arg.kind == nkSym and arg.sym.kind == skResult and arg.typ.skipTypes(abstractInst).kind in {tyVar, tyLent}: - localError(n.info, errXStackEscape, renderTree(n[1], {renderNoComments})) + localError(c.config, n.info, errXStackEscape % renderTree(n[1], {renderNoComments})) return for i in countup(1, sonsLen(n) - 1): @@ -560,14 +572,14 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = call.add(n.sons[0]) var allConst = true for i in 1 ..< n.len: - var a = getConstExpr(c.module, n.sons[i]) + var a = getConstExpr(c.module, n.sons[i], c.graph) if a == nil: allConst = false a = n.sons[i] if a.kind == nkHiddenStdConv: a = a.sons[1] call.add(a) if allConst: - result = semfold.getConstExpr(c.module, call) + result = semfold.getConstExpr(c.module, call, c.graph) if result.isNil: result = n else: return result @@ -589,7 +601,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and {sfForward, sfImportc} * callee.flags == {} and n.typ != nil: if sfCompileTime notin callee.flags and - optImplicitStatic notin gOptions: return + optImplicitStatic notin c.config.options: return if callee.magic notin ctfeWhitelist: return if callee.kind notin {skProc, skFunc, skConverter} or callee.isGenericRoutine: @@ -600,17 +612,17 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = var call = newNodeIT(nkCall, n.info, n.typ) call.add(n.sons[0]) for i in 1 ..< n.len: - let a = getConstExpr(c.module, n.sons[i]) + let a = getConstExpr(c.module, n.sons[i], c.graph) if a == nil: return n call.add(a) #echo "NOW evaluating at compile time: ", call.renderTree if sfCompileTime in callee.flags: - result = evalStaticExpr(c.module, c.cache, c.graph.config, call, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph, call, c.p.owner) if result.isNil: - localError(n.info, errCannotInterpretNodeX, renderTree(call)) + localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call)) else: result = fixupTypeAfterEval(c, result, n) else: - result = evalConstExpr(c.module, c.cache, c.graph.config, call) + result = evalConstExpr(c.module, c.cache, c.graph, call) if result.isNil: result = n else: result = fixupTypeAfterEval(c, result, n) #if result != n: @@ -619,9 +631,9 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode = let a = semExpr(c, n.sons[0]) if a.findUnresolvedStatic != nil: return a - result = evalStaticExpr(c.module, c.cache, c.graph.config, a, c.p.owner) + result = evalStaticExpr(c.module, c.cache, c.graph, a, c.p.owner) if result.isNil: - localError(n.info, errCannotInterpretNodeX, renderTree(n)) + localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n)) result = emptyNode else: result = fixupTypeAfterEval(c, result, a) @@ -641,14 +653,14 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode, if result != nil: if result.sons[0].kind != nkSym: - internalError("semOverloadedCallAnalyseEffects") + internalError(c.config, "semOverloadedCallAnalyseEffects") return let callee = result.sons[0].sym case callee.kind of skMacro, skTemplate: discard else: if callee.kind == skIterator and callee.id == c.p.owner.id: - localError(n.info, errRecursiveDependencyX, callee.name.s) + localError(c.config, n.info, errRecursiveDependencyX % callee.name.s) # error correction, prevents endless for loop elimination in transf. # See bug #2051: result.sons[0] = newSymNode(errorSym(c, n)) @@ -696,10 +708,10 @@ proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode = proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = result = nil - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) var prc = n.sons[0] if n.sons[0].kind == nkDotExpr: - checkSonsLen(n.sons[0], 2) + checkSonsLen(n.sons[0], 2, c.config) let n0 = semFieldAccess(c, n.sons[0]) if n0.kind == nkDotCall: # it is a static call! @@ -732,11 +744,11 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = if m.state != csMatch: if errorOutputs == {}: # speed up error generation: - globalError(n.info, errTypeMismatch, "") + globalError(c.config, n.info, "type mismatch") return emptyNode else: var hasErrorType = false - var msg = msgKindToString(errTypeMismatch) + var msg = "type mismatch: got <" for i in countup(1, sonsLen(n) - 1): if i > 1: add(msg, ", ") let nt = n.sons[i].typ @@ -745,9 +757,9 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = hasErrorType = true break if not hasErrorType: - add(msg, ">\n" & msgKindToString(errButExpected) & "\n" & + add(msg, ">\nbut expected one of: \n" & typeToString(n.sons[0].typ)) - localError(n.info, errGenerated, msg) + localError(c.config, n.info, msg) return errorNode(c, n) result = nil else: @@ -790,11 +802,11 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode = proc buildEchoStmt(c: PContext, n: PNode): PNode = # we MUST not check 'n' for semantics again here! But for now we give up: result = newNodeI(nkCall, n.info) - var e = strTableGet(magicsys.systemModule.tab, getIdent"echo") + var e = strTableGet(c.graph.systemModule.tab, getIdent"echo") if e != nil: add(result, newSymNode(e)) else: - localError(n.info, errSystemNeeds, "echo") + localError(c.config, n.info, "system needs: echo") add(result, errorNode(c, n)) add(result, n) result = semExpr(c, result) @@ -838,8 +850,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, result = lookupInRecordAndBuildCheck(c, n, r.sons[i], field, check) if result != nil: return of nkRecCase: - checkMinSonsLen(r, 2) - if (r.sons[0].kind != nkSym): illFormedAst(r) + checkMinSonsLen(r, 2, c.config) + if (r.sons[0].kind != nkSym): illFormedAst(r, c.config) result = lookupInRecordAndBuildCheck(c, n, r.sons[0], field, check) if result != nil: return let setType = createSetType(c, r.sons[0].typ) @@ -857,8 +869,8 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, addSon(check, ast.emptyNode) # make space for access node s = newNodeIT(nkCurly, n.info, setType) for j in countup(0, sonsLen(it) - 2): addSon(s, copyTree(it.sons[j])) - var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(inExpr, newSymNode(opContains, n.info)) + var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(inExpr, newSymNode(c.graph.opContains, n.info)) addSon(inExpr, s) addSon(inExpr, copyTree(r.sons[0])) addSon(check, inExpr) @@ -870,19 +882,19 @@ proc lookupInRecordAndBuildCheck(c: PContext, n, r: PNode, field: PIdent, if check == nil: check = newNodeI(nkCheckedFieldExpr, n.info) addSon(check, ast.emptyNode) # make space for access node - var inExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(inExpr, newSymNode(opContains, n.info)) + var inExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(inExpr, newSymNode(c.graph.opContains, n.info)) addSon(inExpr, s) addSon(inExpr, copyTree(r.sons[0])) - var notExpr = newNodeIT(nkCall, n.info, getSysType(tyBool)) - addSon(notExpr, newSymNode(opNot, n.info)) + var notExpr = newNodeIT(nkCall, n.info, getSysType(c.graph, n.info, tyBool)) + addSon(notExpr, newSymNode(c.graph.opNot, n.info)) addSon(notExpr, inExpr) addSon(check, notExpr) return - else: illFormedAst(it) + else: illFormedAst(it, c.config) of nkSym: if r.sym.name.id == field.id: result = r.sym - else: illFormedAst(n) + else: illFormedAst(n, c.config) const tyTypeParamsHolders = {tyGenericInst, tyCompositeTypeClass} @@ -937,12 +949,12 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = let s = getGenSym(c, sym) case s.kind of skConst: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) case skipTypes(s.typ, abstractInst-{tyTypeDesc}).kind of tyNil, tyChar, tyInt..tyInt64, tyFloat..tyFloat128, tyTuple, tySet, tyUInt..tyUInt64: - if s.magic == mNone: result = inlineConst(n, s) + if s.magic == mNone: result = inlineConst(c, n, s) else: result = newSymNode(s, n.info) of tyArray, tySequence: # Consider:: @@ -955,14 +967,14 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # It is clear that ``[]`` means two totally different things. Thus, we # copy `x`'s AST into each context, so that the type fixup phase can # deal with two different ``[]``. - if s.ast.len == 0: result = inlineConst(n, s) + if s.ast.len == 0: result = inlineConst(c, n, s) else: result = newSymNode(s, n.info) else: result = newSymNode(s, n.info) of skMacro: if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or (n.kind notin nkCallKinds and s.requiredParams > 0): - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = symChoice(c, n, s, scClosed) else: @@ -971,13 +983,13 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if efNoEvaluateGeneric in flags and s.ast[genericParamsPos].len > 0 or (n.kind notin nkCallKinds and s.requiredParams > 0) or sfCustomPragma in sym.flags: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = symChoice(c, n, s, scClosed) else: result = semTemplateExpr(c, n, s, flags) of skParam: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ != nil and s.typ.kind == tyStatic and s.typ.n != nil: # XXX see the hack in sigmatch.nim ... @@ -987,19 +999,19 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = # gensym'ed parameters that nevertheless have been forward declared # need a special fixup: let realParam = c.p.owner.typ.n[s.position+1] - internalAssert realParam.kind == nkSym and realParam.sym.kind == skParam + internalAssert c.config, realParam.kind == nkSym and realParam.sym.kind == skParam return newSymNode(c.p.owner.typ.n[s.position+1].sym, n.info) elif c.p.owner.kind == skMacro: # gensym'ed macro parameters need a similar hack (see bug #1944): var u = searchInScopes(c, s.name) - internalAssert u != nil and u.kind == skParam and u.owner == s.owner + internalAssert c.config, u != nil and u.kind == skParam and u.owner == s.owner return newSymNode(u, n.info) result = newSymNode(s, n.info) of skVar, skLet, skResult, skForVar: if s.magic == mNimvm: - localError(n.info, "illegal context for 'nimvm' magic") + localError(c.config, n.info, "illegal context for 'nimvm' magic") - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) # We cannot check for access to outer vars for example because it's still @@ -1017,7 +1029,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = n.typ = s.typ return n of skType: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) if s.typ.kind == tyStatic and s.typ.n != nil: return s.typ.n @@ -1039,7 +1051,7 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if f != nil and fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? doAssert f == s - markUsed(n.info, f, c.graph.usageSym) + markUsed(c.config, n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) result = newNodeIT(nkDotExpr, n.info, f.typ) result.add makeDeref(newSymNode(p.selfSym)) @@ -1052,23 +1064,23 @@ proc semSym(c: PContext, n: PNode, sym: PSym, flags: TExprFlags): PNode = if ty.sons[0] == nil: break ty = skipTypes(ty.sons[0], skipPtrs) # old code, not sure if it's live code: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) else: - markUsed(n.info, s, c.graph.usageSym) + markUsed(c.config, n.info, s, c.graph.usageSym) styleCheckUse(n.info, s) result = newSymNode(s, n.info) proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = ## returns nil if it's not a built-in field access - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) # tests/bind/tbindoverload.nim wants an early exit here, but seems to # work without now. template/tsymchoicefield doesn't like an early exit # here at all! #if isSymChoice(n.sons[1]): return when defined(nimsuggest): - if gCmd == cmdIdeTools: + if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if exactEquals(gTrackPos, n[1].info): suggestExprNoCheck(c, n) @@ -1078,14 +1090,14 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = symChoice(c, n, s, scClosed) if result.kind == nkSym: result = semSym(c, n, s, flags) else: - markUsed(n.sons[1].info, s, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, s, c.graph.usageSym) result = semSym(c, n, s, flags) styleCheckUse(n.sons[1].info, s) return n.sons[0] = semExprWithType(c, n.sons[0], flags+{efDetermineType}) #restoreOldStyleType(n.sons[0]) - var i = considerQuotedIdent(n.sons[1], n) + var i = considerQuotedIdent(c.config, n.sons[1], n) var ty = n.sons[0].typ var f: PSym = nil result = nil @@ -1142,7 +1154,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newSymNode(f) result.info = n.info result.typ = ty - markUsed(n.info, f, c.graph.usageSym) + markUsed(c.config, n.info, f, c.graph.usageSym) styleCheckUse(n.info, f) return of tyObject, tyTuple: @@ -1173,7 +1185,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = if f != nil: if fieldVisible(c, f): # is the access to a public field or in the same module or in a friend? - markUsed(n.sons[1].info, f, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) # we now have the correct field @@ -1187,7 +1199,7 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = elif ty.kind == tyTuple and ty.n != nil: f = getSymFromList(ty.n, i) if f != nil: - markUsed(n.sons[1].info, f, c.graph.usageSym) + markUsed(c.config, n.sons[1].info, f, c.graph.usageSym) styleCheckUse(n.sons[1].info, f) n.sons[0] = makeDeref(n.sons[0]) n.sons[1] = newSymNode(f) @@ -1205,7 +1217,7 @@ proc dotTransformation(c: PContext, n: PNode): PNode = addSon(result, n.sons[1]) addSon(result, copyTree(n[0])) else: - var i = considerQuotedIdent(n.sons[1], n) + var i = considerQuotedIdent(c.config, n.sons[1], n) result = newNodeI(nkDotCall, n.info) result.flags.incl nfDotField addSon(result, newIdentNode(i, n[1].info)) @@ -1224,7 +1236,7 @@ proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode = for i in 0 .. n.len-1: result.add(n[i]) proc semDeref(c: PContext, n: PNode): PNode = - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) n.sons[0] = semExprWithType(c, n.sons[0]) result = n var t = skipTypes(n.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyAlias, tySink}) @@ -1242,7 +1254,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newNodeIT(nkDerefExpr, x.info, x.typ) result.add(x[0]) return - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) # make sure we don't evaluate generic macros/templates n.sons[0] = semExprWithType(c, n.sons[0], {efNoEvaluateGeneric}) @@ -1256,7 +1268,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = for i in countup(1, sonsLen(n) - 1): n.sons[i] = semExprWithType(c, n.sons[i], flags*{efInTypeof, efDetermineType}) - var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(tyInt) + var indexType = if arr.kind == tyArray: arr.sons[0] else: getSysType(c.graph, n.info, tyInt) var arg = indexTypesMatch(c, indexType, n.sons[1].typ, n.sons[1]) if arg != nil: n.sons[1] = arg @@ -1279,7 +1291,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode = {tyInt..tyInt64}: var idx = getOrdValue(n.sons[1]) if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)] - else: localError(n.info, errInvalidIndexValueForTuple) + else: localError(c.config, n.info, "invalid index value for tuple subscript") result = n else: result = nil @@ -1319,7 +1331,7 @@ proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semExpr(c, buildOverloadedSubscripts(n, getIdent"[]")) proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = - var id = considerQuotedIdent(a[1], a) + var id = considerQuotedIdent(c.config, a[1], a) var setterId = newIdentNode(getIdent(id.s & '='), n.info) # a[0] is already checked for semantics, that does ``builtinFieldAccess`` # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for @@ -1342,10 +1354,10 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let root = exprRoot(n) if root != nil and root.owner == c.p.owner: if root.kind in {skLet, skVar, skTemp} and sfGlobal notin root.flags: - localError(n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [ + localError(c.config, n.info, "'$1' escapes its stack frame; context: '$2'; see $3/var_t_return.html" % [ root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) elif root.kind == skParam and root.position != 0: - localError(n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [ + localError(c.config, n.info, "'$1' is not the first parameter; context: '$2'; see $3/var_t_return.html" % [ root.name.s, renderTree(n, {renderNoComments}), explanationsBaseUrl]) case n.kind of nkHiddenAddr, nkAddr: return n @@ -1356,9 +1368,9 @@ proc takeImplicitAddr(c: PContext, n: PNode; isLent: bool): PNode = let valid = isAssignable(c, n) if valid != arLValue: if valid == arLocalLValue: - localError(n.info, errXStackEscape, renderTree(n, {renderNoComments})) + localError(c.config, n.info, errXStackEscape % renderTree(n, {renderNoComments})) elif not isLent: - localError(n.info, errExprHasNoAddress) + localError(c.config, n.info, errExprHasNoAddress) result = newNodeIT(nkHiddenAddr, n.info, makePtrType(c, n.typ)) result.add(n) @@ -1375,7 +1387,7 @@ template resultTypeIsInferrable(typ: PType): untyped = typ.isMetaType and typ.kind != tyTypeDesc proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) var a = n.sons[0] case a.kind of nkDotExpr: @@ -1428,7 +1440,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = isAssignable(c, a) == arNone) or skipTypes(le, abstractVar).kind in {tyOpenArray, tyVarargs}: # Direct assignment to a discriminant is allowed! - localError(a.info, errXCannotBeAssignedTo, + localError(c.config, a.info, errXCannotBeAssignedTo % renderTree(a, {renderNoComments})) else: let @@ -1444,12 +1456,12 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = if rhsTyp.kind in tyUserTypeClasses and rhsTyp.isResolvedUserTypeClass: rhsTyp = rhsTyp.lastSon if cmpTypes(c, lhs.typ, rhsTyp) in {isGeneric, isEqual}: - internalAssert c.p.resultSym != nil + internalAssert c.config, c.p.resultSym != nil lhs.typ = rhsTyp c.p.resultSym.typ = rhsTyp c.p.owner.typ.sons[0] = rhsTyp else: - typeMismatch(n.info, lhs.typ, rhsTyp) + typeMismatch(c.config, n.info, lhs.typ, rhsTyp) n.sons[1] = fitNode(c, le, rhs, n.info) if destructor notin c.features: @@ -1465,7 +1477,7 @@ proc semAsgn(c: PContext, n: PNode; mode=asgnNormal): PNode = proc semReturn(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if c.p.owner.kind in {skConverter, skMethod, skProc, skFunc, skMacro} or ( c.p.owner.kind == skIterator and c.p.owner.typ.callConv == ccClosure): if n.sons[0].kind != nkEmpty: @@ -1479,9 +1491,9 @@ proc semReturn(c: PContext, n: PNode): PNode = if n[0][1].kind == nkSym and n[0][1].sym == c.p.resultSym: n.sons[0] = ast.emptyNode else: - localError(n.info, errNoReturnTypeDeclared) + localError(c.config, n.info, errNoReturnTypeDeclared) else: - localError(n.info, errXNotAllowedHere, "\'return\'") + localError(c.config, n.info, "'return' not allowed here") proc semProcBody(c: PContext, n: PNode): PNode = openScope(c) @@ -1496,7 +1508,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = # nil # # comment # are not expressions: - fixNilType(result) + fixNilType(c, result) else: var a = newNodeI(nkAsgn, n.info, 2) a.sons[0] = newSymNode(c.p.resultSym) @@ -1512,7 +1524,7 @@ proc semProcBody(c: PContext, n: PNode): PNode = c.p.resultSym.typ = errorType(c) c.p.owner.typ.sons[0] = nil else: - localError(c.p.resultSym.info, errCannotInferReturnType) + localError(c.config, c.p.resultSym.info, errCannotInferReturnType) closeScope(c) @@ -1536,16 +1548,16 @@ proc semYieldVarResult(c: PContext, n: PNode, restype: PType) = var a = n.sons[0].sons[1] a.sons[i] = takeImplicitAddr(c, a.sons[i], false) else: - localError(n.sons[0].info, errXExpected, "tuple constructor") + localError(c.config, n.sons[0].info, errXExpected, "tuple constructor") else: discard proc semYield(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if c.p.owner == nil or c.p.owner.kind != skIterator: - localError(n.info, errYieldNotAllowedHere) + localError(c.config, n.info, errYieldNotAllowedHere) elif oldIterTransf in c.features and c.p.inTryStmt > 0 and c.p.owner.typ.callConv != ccInline: - localError(n.info, errYieldNotAllowedInTryStmt) + localError(c.config, n.info, errYieldNotAllowedInTryStmt) elif n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) # check for type compatibility: var iterType = c.p.owner.typ @@ -1553,7 +1565,7 @@ proc semYield(c: PContext, n: PNode): PNode = if restype != nil: if restype.kind != tyExpr: n.sons[0] = fitNode(c, restype, n.sons[0], n.info) - if n.sons[0].typ == nil: internalError(n.info, "semYield") + if n.sons[0].typ == nil: internalError(c.config, n.info, "semYield") if resultTypeIsInferrable(restype): let inferred = n.sons[0].typ @@ -1561,9 +1573,9 @@ proc semYield(c: PContext, n: PNode): PNode = semYieldVarResult(c, n, restype) else: - localError(n.info, errCannotReturnExpr) + localError(c.config, n.info, errCannotReturnExpr) elif c.p.owner.typ.sons[0] != nil: - localError(n.info, errGenerated, "yield statement must yield a value") + localError(c.config, n.info, errGenerated, "yield statement must yield a value") proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym = if onlyCurrentScope: @@ -1578,37 +1590,37 @@ proc lookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = of nkDotExpr: result = nil if onlyCurrentScope: return - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) var m = lookUpForDefined(c, n.sons[0], onlyCurrentScope) if m != nil and m.kind == skModule: - let ident = considerQuotedIdent(n[1], n) + let ident = considerQuotedIdent(c.config, n[1], n) if m == c.module: result = strTableGet(c.topLevelScope.symbols, ident) else: result = strTableGet(m.tab, ident) of nkAccQuoted: - result = lookUpForDefined(c, considerQuotedIdent(n), onlyCurrentScope) + result = lookUpForDefined(c, considerQuotedIdent(c.config, n), onlyCurrentScope) of nkSym: result = n.sym of nkOpenSymChoice, nkClosedSymChoice: result = n.sons[0].sym else: - localError(n.info, errIdentifierExpected, renderTree(n)) + localError(c.config, n.info, "identifier expected, but got: " & renderTree(n)) result = nil proc semDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PNode = - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) # we replace this node by a 'true' or 'false' node: result = newIntNode(nkIntLit, 0) - if not onlyCurrentScope and considerQuotedIdent(n[0], n).s == "defined": + if not onlyCurrentScope and considerQuotedIdent(c.config, n[0], n).s == "defined": if n.sons[1].kind != nkIdent: - localError(n.info, "obsolete usage of 'defined', use 'declared' instead") - elif condsyms.isDefined(n.sons[1].ident): + localError(c.config, n.info, "obsolete usage of 'defined', use 'declared' instead") + elif isDefined(c.config, n.sons[1].ident.s): result.intVal = 1 elif lookUpForDefined(c, n.sons[1], onlyCurrentScope) != nil: result.intVal = 1 result.info = n.info - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, n.info, tyBool) proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = ## The argument to the proc should be nkCall(...) or similar @@ -1620,12 +1632,12 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym = return errorSym(c, n[0]) if expandedSym.kind notin {skMacro, skTemplate}: - localError(n.info, errXisNoMacroOrTemplate, expandedSym.name.s) + localError(c.config, n.info, "'$1' is not a macro or template" % expandedSym.name.s) return errorSym(c, n[0]) result = expandedSym else: - localError(n.info, errXisNoMacroOrTemplate, n.renderTree) + localError(c.config, n.info, "'$1' is not a macro or template" % n.renderTree) result = errorSym(c, n) proc expectString(c: PContext, n: PNode): string = @@ -1633,11 +1645,7 @@ proc expectString(c: PContext, n: PNode): string = if n.kind in nkStrKinds: return n.strVal else: - localError(n.info, errStringLiteralExpected) - -proc getMagicSym(magic: TMagic): PSym = - result = newSym(skProc, getIdent($magic), systemModule, gCodegenLineInfo) - result.magic = magic + localError(c.config, n.info, errStringLiteralExpected) proc newAnonSym(c: PContext; kind: TSymKind, info: TLineInfo): PSym = result = newSym(kind, c.cache.idAnon, getCurrOwner(c), info) @@ -1651,7 +1659,7 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = if expandedSym.kind == skError: return n macroCall.sons[0] = newSymNode(expandedSym, macroCall.info) - markUsed(n.info, expandedSym, c.graph.usageSym) + markUsed(c.config, n.info, expandedSym, c.graph.usageSym) styleCheckUse(n.info, expandedSym) if isCallExpr(macroCall): @@ -1670,26 +1678,25 @@ proc semExpandToAst(c: PContext, n: PNode): PNode = inc cands symx = nextOverloadIter(o, c, headSymbol) if cands == 0: - localError(n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments") + localError(c.config, n.info, "expected a template that takes " & $(macroCall.len-1) & " arguments") elif cands >= 2: - localError(n.info, "ambiguous symbol in 'getAst' context: " & $macroCall) + localError(c.config, n.info, "ambiguous symbol in 'getAst' context: " & $macroCall) else: let info = macroCall.sons[0].info macroCall.sons[0] = newSymNode(cand, info) - markUsed(info, cand, c.graph.usageSym) + markUsed(c.config, info, cand, c.graph.usageSym) styleCheckUse(info, cand) # we just perform overloading resolution here: #n.sons[1] = semOverloadedCall(c, macroCall, macroCall, {skTemplate, skMacro}) else: - localError(n.info, "getAst takes a call, but got " & n.renderTree) + localError(c.config, n.info, "getAst takes a call, but got " & n.renderTree) # Preserve the magic symbol in order to be handled in evals.nim - internalAssert n.sons[0].sym.magic == mExpandToAst + internalAssert c.config, n.sons[0].sym.magic == mExpandToAst #n.typ = getSysSym("NimNode").typ # expandedSym.getReturnType if n.kind == nkStmtList and n.len == 1: result = n[0] else: result = n - result.typ = if getCompilerProc("NimNode") != nil: sysTypeFromName"NimNode" - else: sysTypeFromName"PNimrodNode" + result.typ = sysTypeFromName(c.graph, n.info, "NimNode") proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, flags: TExprFlags = {}): PNode = @@ -1699,7 +1706,7 @@ proc semExpandToAst(c: PContext, n: PNode, magicSym: PSym, else: result = semDirectOp(c, n, flags) -proc processQuotations(n: var PNode, op: string, +proc processQuotations(c: PContext; n: var PNode, op: string, quotes: var seq[PNode], ids: var seq[PNode]) = template returnQuote(q) = @@ -1709,7 +1716,7 @@ proc processQuotations(n: var PNode, op: string, return if n.kind == nkPrefix: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) if n[0].kind == nkIdent: var examinedOp = n[0].ident.s if examinedOp == op: @@ -1720,10 +1727,10 @@ proc processQuotations(n: var PNode, op: string, returnQuote n[0] for i in 0 ..< n.safeLen: - processQuotations(n.sons[i], op, quotes, ids) + processQuotations(c, n.sons[i], op, quotes, ids) proc semQuoteAst(c: PContext, n: PNode): PNode = - internalAssert n.len == 2 or n.len == 3 + internalAssert c.config, n.len == 2 or n.len == 3 # We transform the do block into a template with a param for # each interpolation. We'll pass this template to getAst. var @@ -1736,9 +1743,9 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = # this will store the generated param names if quotedBlock.kind != nkStmtList: - localError(n.info, errXExpected, "block") + localError(c.config, n.info, errXExpected, "block") - processQuotations(quotedBlock, op, quotes, ids) + processQuotations(c, quotedBlock, op, quotes, ids) var dummyTemplate = newProcNode( nkTemplateDef, quotedBlock.info, quotedBlock, @@ -1746,27 +1753,27 @@ proc semQuoteAst(c: PContext, n: PNode): PNode = if ids.len > 0: dummyTemplate.sons[paramsPos] = newNodeI(nkFormalParams, n.info) - dummyTemplate[paramsPos].add getSysSym("typed").newSymNode # return type - ids.add getSysSym("untyped").newSymNode # params type + dummyTemplate[paramsPos].add getSysSym(c.graph, n.info, "typed").newSymNode # return type + ids.add getSysSym(c.graph, n.info, "untyped").newSymNode # params type ids.add emptyNode # no default value dummyTemplate[paramsPos].add newNode(nkIdentDefs, n.info, ids) var tmpl = semTemplateDef(c, dummyTemplate) quotes[0] = tmpl[namePos] result = newNode(nkCall, n.info, @[ - getMagicSym(mExpandToAst).newSymNode, + createMagic(c.graph, "getAst", mExpandToAst).newSymNode, newNode(nkCall, n.info, quotes)]) result = semExpandToAst(c, result) proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # watch out, hacks ahead: - let oldErrorCount = msgs.gErrorCounter - let oldErrorMax = msgs.gErrorMax + let oldErrorCount = c.config.errorCounter + let oldErrorMax = c.config.errorMax let oldCompilesId = c.compilesContextId inc c.compilesContextIdGenerator c.compilesContextId = c.compilesContextIdGenerator # do not halt after first error: - msgs.gErrorMax = high(int) + c.config.errorMax = high(int) # open a scope for temporary symbol inclusions: let oldScope = c.currentScope @@ -1786,7 +1793,7 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var err: string try: result = semExpr(c, n, flags) - if msgs.gErrorCounter != oldErrorCount: result = nil + if c.config.errorCounter != oldErrorCount: result = nil except ERecoverableError: discard # undo symbol table changes (as far as it's possible): @@ -1801,8 +1808,8 @@ proc tryExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = setLen(c.graph.owners, oldOwnerLen) c.currentScope = oldScope errorOutputs = oldErrorOutputs - msgs.gErrorCounter = oldErrorCount - msgs.gErrorMax = oldErrorMax + c.config.errorCounter = oldErrorCount + c.config.errorMax = oldErrorMax proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = # we replace this node by a 'true' or 'false' node: @@ -1810,7 +1817,7 @@ proc semCompiles(c: PContext, n: PNode, flags: TExprFlags): PNode = result = newIntNode(nkIntLit, ord(tryExpr(c, n[1], flags) != nil)) result.info = n.info - result.typ = getSysType(tyBool) + result.typ = getSysType(c.graph, n.info, tyBool) proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = if sonsLen(n) == 3: @@ -1825,15 +1832,15 @@ proc semShallowCopy(c: PContext, n: PNode, flags: TExprFlags): PNode = proc createFlowVar(c: PContext; t: PType; info: TLineInfo): PType = result = newType(tyGenericInvocation, c.module) - addSonSkipIntLit(result, magicsys.getCompilerProc("FlowVar").typ) + addSonSkipIntLit(result, magicsys.getCompilerProc(c.graph, "FlowVar").typ) addSonSkipIntLit(result, t) result = instGenericContainer(c, info, result, allowMetaTypes = false) proc instantiateCreateFlowVarCall(c: PContext; t: PType; info: TLineInfo): PSym = - let sym = magicsys.getCompilerProc("nimCreateFlowVar") + let sym = magicsys.getCompilerProc(c.graph, "nimCreateFlowVar") if sym == nil: - localError(info, errSystemNeeds, "nimCreateFlowVar") + localError(c.config, info, "system needs: nimCreateFlowVar") var bindings: TIdTable initIdTable(bindings) bindings.idTablePut(sym.ast[genericParamsPos].sons[0].typ, t) @@ -1862,10 +1869,10 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = result = n case s.magic # magics that need special treatment of mAddr: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) result = semAddr(c, n.sons[1], s.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) @@ -1882,12 +1889,12 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = of mExpandToAst: result = semExpandToAst(c, n, s, flags) of mQuoteAst: result = semQuoteAst(c, n) of mAstToStr: - checkSonsLen(n, 2) - result = newStrNodeT(renderTree(n[1], {renderNoComments}), n) - result.typ = getSysType(tyString) + checkSonsLen(n, 2, c.config) + result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, c.graph) + result.typ = getSysType(c.graph, n.info, tyString) of mParallel: if parallel notin c.features: - localError(n.info, "use the {.experimental.} pragma to enable 'parallel'") + localError(c.config, n.info, "use the {.experimental.} pragma to enable 'parallel'") result = setMs(n, s) var x = n.lastSon if x.kind == nkDo: x = x.sons[bodyPos] @@ -1928,7 +1935,7 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode = if callee.magic != mNone: result = magicsAfterOverloadResolution(c, result, flags) of mRunnableExamples: - if gCmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: + if c.config.cmd == cmdDoc and n.len >= 2 and n.lastSon.kind == nkStmtList: if sfMainModule in c.module.flags: let inp = toFullPath(c.module.info) if c.runnableExamples == nil: @@ -1973,7 +1980,7 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = var it = n.sons[i] case it.kind of nkElifBranch, nkElifExpr: - checkSonsLen(it, 2) + checkSonsLen(it, 2, c.config) if whenNimvm: if semCheck: it.sons[1] = semExpr(c, it.sons[1]) @@ -1988,14 +1995,14 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = elif e.intVal != 0 and result == nil: setResult(it.sons[1]) of nkElse, nkElseExpr: - checkSonsLen(it, 1) + checkSonsLen(it, 1, c.config) if result == nil or whenNimvm: if semCheck: it.sons[0] = semExpr(c, it.sons[0]) typ = commonType(typ, it.sons[0].typ) if result == nil: result = it.sons[0] - else: illFormedAst(n) + else: illFormedAst(n, c.config) if result == nil: result = newNodeI(nkEmpty, n.info) if whenNimvm: result.typ = typ @@ -2014,7 +2021,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = var typ: PType = nil for i in countup(0, sonsLen(n) - 1): if isRange(n.sons[i]): - checkSonsLen(n.sons[i], 3) + checkSonsLen(n.sons[i], 3, c.config) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1]) n.sons[i].sons[2] = semExprWithType(c, n.sons[i].sons[2]) if typ == nil: @@ -2031,7 +2038,7 @@ proc semSetConstr(c: PContext, n: PNode): PNode = if typ == nil: typ = skipTypes(n.sons[i].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal, tyAlias, tySink}) if not isOrdinalType(typ): - localError(n.info, errOrdinalTypeExpected) + localError(c.config, n.info, errOrdinalTypeExpected) typ = makeRangeType(c, 0, MaxSetElements-1, n.info) elif lengthOrd(typ) > MaxSetElements: typ = makeRangeType(c, 0, MaxSetElements-1, n.info) @@ -2069,14 +2076,14 @@ proc semTableConstr(c: PContext, n: PNode): PNode = lastKey = i+1 - if lastKey != n.len: illFormedAst(n) + if lastKey != n.len: illFormedAst(n, c.config) result = semExpr(c, result) type TParKind = enum paNone, paSingle, paTupleFields, paTuplePositions -proc checkPar(n: PNode): TParKind = +proc checkPar(c: PContext; n: PNode): TParKind = var length = sonsLen(n) if length == 0: result = paTuplePositions # () @@ -2091,11 +2098,11 @@ proc checkPar(n: PNode): TParKind = if result == paTupleFields: if (n.sons[i].kind != nkExprColonExpr) or not (n.sons[i].sons[0].kind in {nkSym, nkIdent}): - localError(n.sons[i].info, errNamedExprExpected) + localError(c.config, n.sons[i].info, errNamedExprExpected) return paNone else: if n.sons[i].kind == nkExprColonExpr: - localError(n.sons[i].info, errNamedExprNotAllowed) + localError(c.config, n.sons[i].info, errNamedExprNotAllowed) return paNone proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = @@ -2105,12 +2112,12 @@ proc semTupleFieldsConstr(c: PContext, n: PNode, flags: TExprFlags): PNode = var ids = initIntSet() for i in countup(0, sonsLen(n) - 1): if n[i].kind != nkExprColonExpr or n[i][0].kind notin {nkSym, nkIdent}: - illFormedAst(n.sons[i]) + illFormedAst(n.sons[i], c.config) var id: PIdent if n.sons[i].sons[0].kind == nkIdent: id = n.sons[i].sons[0].ident else: id = n.sons[i].sons[0].sym.name if containsOrIncl(ids, id.id): - localError(n.sons[i].info, errFieldInitTwice, id.s) + localError(c.config, n.sons[i].info, errFieldInitTwice % id.s) n.sons[i].sons[1] = semExprWithType(c, n.sons[i].sons[1], flags*{efAllowDestructor}) var f = newSymS(skField, n.sons[i].sons[0], c) @@ -2144,14 +2151,14 @@ include semobjconstr proc semBlock(c: PContext, n: PNode): PNode = result = n inc(c.p.nestedBlockCounter) - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) # BUGFIX: label is in the scope of block! if n.sons[0].kind != nkEmpty: var labl = newSymG(skLabel, n.sons[0], c) if sfGenSym notin labl.flags: addDecl(c, labl) n.sons[0] = newSymNode(labl, n.sons[0].info) - suggestSym(n.sons[0].info, labl, c.graph.usageSym) + suggestSym(c.config, n.sons[0].info, labl, c.graph.usageSym) styleCheckDef(labl) n.sons[1] = semExpr(c, n.sons[1]) n.typ = n.sons[1].typ @@ -2163,9 +2170,9 @@ proc semBlock(c: PContext, n: PNode): PNode = proc semExportExcept(c: PContext, n: PNode): PNode = let moduleName = semExpr(c, n[0]) if moduleName.kind != nkSym or moduleName.sym.kind != skModule: - localError(n.info, "The export/except syntax expects a module name") - return - let exceptSet = readExceptSet(n) + localError(c.config, n.info, "The export/except syntax expects a module name") + return n + let exceptSet = readExceptSet(c, n) let exported = moduleName.sym strTableAdd(c.module.tab, exported) var i: TTabIter @@ -2184,7 +2191,7 @@ proc semExport(c: PContext, n: PNode): PNode = var o: TOverloadIter var s = initOverloadIter(o, c, a) if s == nil: - localError(a.info, errGenerated, "cannot export: " & renderTree(a)) + localError(c.config, a.info, errGenerated, "cannot export: " & renderTree(a)) elif s.kind == skModule: # forward everything from that module: strTableAdd(c.module.tab, s) @@ -2218,7 +2225,7 @@ proc shouldBeBracketExpr(n: PNode): bool = proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result = n - if gCmd == cmdIdeTools: suggestExpr(c, n) + if c.config.cmd == cmdIdeTools: suggestExpr(c, n) if nfSem in n.flags: return case n.kind of nkIdent, nkAccQuoted: @@ -2237,7 +2244,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = if result.kind == nkSym: markIndirect(c, result.sym) # if isGenericRoutine(result.sym): - # localError(n.info, errInstantiateXExplicitly, s.name.s) + # localError(c.config, n.info, errInstantiateXExplicitly, s.name.s) of nkSym: # because of the changed symbol binding, this does not mean that we # don't have to check the symbol for semantics here again! @@ -2245,46 +2252,46 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkEmpty, nkNone, nkCommentStmt, nkType: discard of nkNilLit: - if result.typ == nil: result.typ = getSysType(tyNil) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyNil) of nkIntLit: - if result.typ == nil: setIntLitType(result) + if result.typ == nil: setIntLitType(c.graph, result) of nkInt8Lit: - if result.typ == nil: result.typ = getSysType(tyInt8) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt8) of nkInt16Lit: - if result.typ == nil: result.typ = getSysType(tyInt16) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt16) of nkInt32Lit: - if result.typ == nil: result.typ = getSysType(tyInt32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt32) of nkInt64Lit: - if result.typ == nil: result.typ = getSysType(tyInt64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyInt64) of nkUIntLit: - if result.typ == nil: result.typ = getSysType(tyUInt) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt) of nkUInt8Lit: - if result.typ == nil: result.typ = getSysType(tyUInt8) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt8) of nkUInt16Lit: - if result.typ == nil: result.typ = getSysType(tyUInt16) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt16) of nkUInt32Lit: - if result.typ == nil: result.typ = getSysType(tyUInt32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt32) of nkUInt64Lit: - if result.typ == nil: result.typ = getSysType(tyUInt64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyUInt64) #of nkFloatLit: # if result.typ == nil: result.typ = getFloatLitType(result) of nkFloat32Lit: - if result.typ == nil: result.typ = getSysType(tyFloat32) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat32) of nkFloat64Lit, nkFloatLit: - if result.typ == nil: result.typ = getSysType(tyFloat64) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat64) of nkFloat128Lit: - if result.typ == nil: result.typ = getSysType(tyFloat128) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyFloat128) of nkStrLit..nkTripleStrLit: - if result.typ == nil: result.typ = getSysType(tyString) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyString) of nkCharLit: - if result.typ == nil: result.typ = getSysType(tyChar) + if result.typ == nil: result.typ = getSysType(c.graph, n.info, tyChar) of nkDotExpr: result = semFieldAccess(c, n, flags) if result.kind == nkDotCall: result.kind = nkCall result = semExpr(c, result, flags) of nkBind: - message(n.info, warnDeprecated, "bind") + message(c.config, n.info, warnDeprecated, "bind") result = semExpr(c, n.sons[0], flags) of nkTypeOfExpr, nkTupleTy, nkTupleClassTy, nkRefTy..nkEnumTy, nkStaticTy: if c.matchedConcept != nil and n.len == 1: @@ -2297,13 +2304,13 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = result.typ = makeTypeDesc(c, typ) of nkCall, nkInfix, nkPrefix, nkPostfix, nkCommand, nkCallStrLit: # check if it is an expression macro: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) #when defined(nimsuggest): # if gIdeCmd == ideCon and gTrackPos == n.info: suggestExprNoCheck(c, n) let mode = if nfDotField in n.flags: {} else: {checkUndeclared} var s = qualifiedLookUp(c, n.sons[0], mode) if s != nil: - #if gCmd == cmdPretty and n.sons[0].kind == nkDotExpr: + #if c.config.cmd == cmdPretty and n.sons[0].kind == nkDotExpr: # pretty.checkUse(n.sons[0].sons[1].info, s) case s.kind of skMacro: @@ -2353,7 +2360,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = else: result = semExpr(c, result, flags) of nkBracketExpr: - checkMinSonsLen(n, 1) + checkMinSonsLen(n, 1, c.config) result = semArrayAccess(c, n, flags) of nkCurlyExpr: result = semExpr(c, buildOverloadedSubscripts(n, getIdent"{}"), flags) @@ -2361,7 +2368,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = var expr = n[0] pragma = n[1] - pragmaName = considerQuotedIdent(pragma[0]) + pragmaName = considerQuotedIdent(c.config, pragma[0]) flags = flags case whichKeyword(pragmaName) @@ -2369,11 +2376,11 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = flags.incl efExplain else: # what other pragmas are allowed for expressions? `likely`, `unlikely` - invalidPragma(n) + invalidPragma(c, n) result = semExpr(c, n[0], flags) of nkPar, nkTupleConstr: - case checkPar(n) + case checkPar(c, n) of paNone: result = errorNode(c, n) of paTuplePositions: var tupexp = semTuplePositionsConstr(c, n, flags) @@ -2392,24 +2399,24 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkDerefExpr: result = semDeref(c, n) of nkAddr: result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) result = semAddr(c, n.sons[0]) of nkHiddenAddr, nkHiddenDeref: - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) n.sons[0] = semExpr(c, n.sons[0], flags) of nkCast: result = semCast(c, n) of nkIfExpr, nkIfStmt: result = semIf(c, n) of nkHiddenStdConv, nkHiddenSubConv, nkConv, nkHiddenCallConv: - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) considerGenSyms(c, n) of nkStringToCString, nkCStringToString, nkObjDownConv, nkObjUpConv: - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) considerGenSyms(c, n) of nkChckRangeF, nkChckRange64, nkChckRange: - checkSonsLen(n, 3) + checkSonsLen(n, 3, c.config) considerGenSyms(c, n) of nkCheckedFieldExpr: - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) considerGenSyms(c, n) of nkTableConstr: result = semTableConstr(c, n) @@ -2453,22 +2460,22 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = # # works: if c.currentScope.depthLevel > 2 + c.compilesContextId: - localError(n.info, errXOnlyAtModuleScope, "import") + localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImport(c, n) of nkImportExceptStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "import") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "import") result = evalImportExcept(c, n) of nkFromStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "from") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "from") result = evalFrom(c, n) of nkIncludeStmt: - #if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "include") + #if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "include") result = evalInclude(c, n) of nkExportStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export") result = semExport(c, n) of nkExportExceptStmt: - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "export") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "export") result = semExportExcept(c, n) of nkPragmaBlock: result = semPragmaBlock(c, n) @@ -2477,14 +2484,14 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = of nkDefer: n.sons[0] = semExpr(c, n.sons[0]) if not n.sons[0].typ.isEmptyType and not implicitlyDiscardable(n.sons[0]): - localError(n.info, errGenerated, "'defer' takes a 'void' expression") - #localError(n.info, errGenerated, "'defer' not allowed in this context") + localError(c.config, n.info, "'defer' takes a 'void' expression") + #localError(c.config, n.info, errGenerated, "'defer' not allowed in this context") of nkGotoState, nkState: - if n.len != 1 and n.len != 2: illFormedAst(n) + if n.len != 1 and n.len != 2: illFormedAst(n, c.config) for i in 0 ..< n.len: n.sons[i] = semExpr(c, n.sons[i]) of nkComesFrom: discard "ignore the comes from information for now" else: - localError(n.info, errInvalidExpressionX, + localError(c.config, n.info, "invalid expression: " & renderTree(n, {renderNoComments})) if result != nil: incl(result.flags, nfSem) diff --git a/compiler/semfields.nim b/compiler/semfields.nim index c5bc07d77..16d79c559 100644 --- a/compiler/semfields.nim +++ b/compiler/semfields.nim @@ -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 diff --git a/compiler/semfold.nim b/compiler/semfold.nim index c4d79a4a3..daf9ce983 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -13,54 +13,83 @@ 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 +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(g, result) + else: + result.typ = n.typ + # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... + #setIntLitType(result) + of tyChar: + result = newIntNode(nkCharLit, intVal) + result.typ = n.typ + else: + result = newIntNode(nkIntLit, intVal) + result.typ = n.typ + result.info = n.info + +proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode = + result = newFloatNode(nkFloatLit, floatVal) + if skipTypes(n.typ, abstractVarRange).kind == tyFloat: + result.typ = getFloatLitType(g, result) + else: + result.typ = n.typ + result.info = n.info + +proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode = + result = newStrNode(nkStrLit, strVal) + result.typ = n.typ + result.info = n.info + +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): 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 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): PNode = +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) + result = newIntNodeT(res, n, g) -proc foldSub*(a, b: BiggestInt, n: PNode): PNode = +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) + result = newIntNodeT(res, n, g) -proc foldAbs*(a: BiggestInt, n: PNode): PNode = +proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode = if a != firstOrd(n.typ): - result = newIntNodeT(a, n) - -proc foldMod*(a, b: BiggestInt, n: PNode): PNode = + 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) + result = newIntNodeT(a mod b, n, g) -proc foldModU*(a, b: BiggestInt, n: PNode): PNode = +proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = if b != 0'i64: - result = newIntNodeT(a %% b, n) + result = newIntNodeT(a %% b, n, g) -proc foldDiv*(a, b: BiggestInt, n: PNode): PNode = +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) + result = newIntNodeT(a div b, n, g) -proc foldDivU*(a, b: BiggestInt, n: PNode): PNode = +proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = if b != 0'i64: - result = newIntNodeT(a /% b, n) + result = newIntNodeT(a /% b, n, g) -proc foldMul*(a, b: BiggestInt, n: PNode): PNode = +proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = let res = a *% b let floatProd = toBiggestFloat(a) * toBiggestFloat(b) let resAsFloat = toBiggestFloat(res) @@ -68,7 +97,7 @@ proc foldMul*(a, b: BiggestInt, n: PNode): PNode = # 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) + 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). @@ -79,44 +108,9 @@ proc foldMul*(a, b: BiggestInt, n: PNode): PNode = # 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 = - 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) - else: - result.typ = n.typ - # hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ... - #setIntLitType(result) - of tyChar: - result = newIntNode(nkCharLit, intVal) - result.typ = n.typ - else: - result = newIntNode(nkIntLit, intVal) - result.typ = n.typ - result.info = n.info - -proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode = - result = newFloatNode(nkFloatLit, floatVal) - if skipTypes(n.typ, abstractVarRange).kind == tyFloat: - result.typ = getFloatLitType(result) - else: - result.typ = n.typ - result.info = n.info - -proc newStrNodeT(strVal: string, n: PNode): PNode = - result = newStrNode(nkStrLit, strVal) - result.typ = n.typ - result.info = n.info + return newIntNodeT(res, n, g) -proc ordinalValToString*(a: PNode): string = +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) - -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) + result = evalOp(s.magic, n, a, b, c, g) + +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 diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 16da06952..8f06e748e 100644 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -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): diff --git a/compiler/seminst.nim b/compiler/seminst.nim index 0513e2395..a5f0ca7d8 100644 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -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, c.features, 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 diff --git a/compiler/semmacrosanity.nim b/compiler/semmacrosanity.nim index f6df67441..02c56c035 100644 --- a/compiler/semmacrosanity.nim +++ b/compiler/semmacrosanity.nim @@ -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 diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index e6e29b4d3..8515e971d 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -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) diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim index cfa0fbd05..1e0802953 100644 --- a/compiler/semobjconstr.nim +++ b/compiler/semobjconstr.nim @@ -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 - diff --git a/compiler/semparallel.nim b/compiler/semparallel.nim index e12fd84bb..ea5aab628 100644 --- a/compiler/semparallel.nim +++ b/compiler/semparallel.nim @@ -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) diff --git a/compiler/sempass2.nim b/compiler/sempass2.nim index d2a10f714..b66d7d9f2 100644 --- a/compiler/sempass2.nim +++ b/compiler/sempass2.nim @@ -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) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 9f00e877f..3687e50e9 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -10,51 +10,77 @@ ## this module does the semantic checking of statements # included from sem.nim -var enforceVoidContext = PType(kind: tyStmt) +const + 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" + errInvalidControlFlowX = "invalid control flow: $1" + errSelectorMustBeOfCertainTypes = "selector must be of an ordinal type, float or string" + errExprCannotBeRaised = "only a 'ref object' can be raised" + errBreakOnlyInLoop = "'break' only allowed in loop construct" + 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" + 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." + 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'" + errProcHasNoConcreteType = "'$1' doesn't have a concrete type, due to unspecified generic parameters." + errLetNeedsInit = "'let' symbol requires an initialization" + errThreadvarCannotInit = "a thread var cannot be initialized explicitly; this would only run for the main thread" + errImplOfXexpected = "implementation of '$1' expected" + errRecursiveDependencyX = "recursive dependency: '$1'" + errPragmaOnlyInHeaderOfProcX = "pragmas are only allowed in the header of a proc; redefinition of $1" + +var enforceVoidContext = PType(kind: tyStmt) # XXX global variable here proc semDiscard(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: n.sons[0] = semExprWithType(c, n.sons[0]) if isEmptyType(n.sons[0].typ) or n.sons[0].typ.kind == tyNone or n.sons[0].kind == nkTypeOfExpr: - localError(n.info, errInvalidDiscard) + localError(c.config, n.info, errInvalidDiscard) proc semBreakOrContinue(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n.sons[0].kind != nkEmpty: if n.kind != nkContinueStmt: var s: PSym case n.sons[0].kind of nkIdent: s = lookUp(c, n.sons[0]) of nkSym: s = n.sons[0].sym - else: illFormedAst(n) + else: illFormedAst(n, c.config) s = getGenSym(c, s) if s.kind == skLabel and s.owner.id == c.p.owner.id: var x = newSymNode(s) x.info = n.info incl(s.flags, sfUsed) n.sons[0] = x - suggestSym(x.info, s, c.graph.usageSym) + suggestSym(c.config, x.info, s, c.graph.usageSym) styleCheckUse(x.info, s) else: - localError(n.info, errInvalidControlFlowX, s.name.s) + localError(c.config, n.info, errInvalidControlFlowX % s.name.s) else: - localError(n.info, errGenerated, "'continue' cannot have a label") + localError(c.config, n.info, errGenerated, "'continue' cannot have a label") elif (c.p.nestedLoopCounter <= 0) and (c.p.nestedBlockCounter <= 0): - localError(n.info, errInvalidControlFlowX, + localError(c.config, n.info, errInvalidControlFlowX % renderTree(n, {renderNoComments})) -proc semAsm(con: PContext, n: PNode): PNode = - checkSonsLen(n, 2) - var marker = pragmaAsm(con, n.sons[0]) +proc semAsm(c: PContext, n: PNode): PNode = + checkSonsLen(n, 2, c.config) + var marker = pragmaAsm(c, n.sons[0]) if marker == '\0': marker = '`' # default marker - result = semAsmOrEmit(con, n, marker) + result = semAsmOrEmit(c, n, marker) proc semWhile(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 2) + checkSonsLen(n, 2, c.config) openScope(c) n.sons[0] = forceBool(c, semExprWithType(c, n.sons[0])) inc(c.p.nestedLoopCounter) @@ -95,13 +121,13 @@ proc implicitlyDiscardable(n: PNode): bool = result = isCallExpr(n) and n.sons[0].kind == nkSym and sfDiscardable in n.sons[0].sym.flags -proc fixNilType(n: PNode) = +proc fixNilType(c: PContext; n: PNode) = if isAtom(n): if n.kind != nkNilLit and n.typ != nil: - localError(n.info, errDiscardValueX, n.typ.typeToString) + localError(c.config, n.info, errDiscardValueX % n.typ.typeToString) elif n.kind in {nkStmtList, nkStmtListExpr}: n.kind = nkStmtList - for it in n: fixNilType(it) + for it in n: fixNilType(c, it) n.typ = nil proc discardCheck(c: PContext, result: PNode) = @@ -113,7 +139,7 @@ proc discardCheck(c: PContext, result: PNode) = while n.kind in skipForDiscardable: n = n.lastSon n.typ = nil - elif result.typ.kind != tyError and gCmd != cmdInteractive: + elif result.typ.kind != tyError and c.config.cmd != cmdInteractive: var n = result while n.kind in skipForDiscardable: n = n.lastSon var s = "expression '" & $n & "' is of type '" & @@ -123,7 +149,7 @@ proc discardCheck(c: PContext, result: PNode) = s.add "; start of expression here: " & $result.info if result.typ.kind == tyProc: s.add "; for a function call use ()" - localError(n.info, s) + localError(c.config, n.info, s) proc semIf(c: PContext, n: PNode): PNode = result = n @@ -142,7 +168,7 @@ proc semIf(c: PContext, n: PNode): PNode = hasElse = true it.sons[0] = semExprBranchScope(c, it.sons[0]) typ = commonType(typ, it.sons[0]) - else: illFormedAst(it) + else: illFormedAst(it, c.config) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for it in n: discardCheck(c, it.lastSon) result.kind = nkIfStmt @@ -158,7 +184,7 @@ proc semIf(c: PContext, n: PNode): PNode = proc semCase(c: PContext, n: PNode): PNode = result = n - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) openScope(c) n.sons[0] = semExprWithType(c, n.sons[0]) var chckCovered = false @@ -172,23 +198,23 @@ proc semCase(c: PContext, n: PNode): PNode = of tyFloat..tyFloat128, tyString, tyError: discard else: - localError(n.info, errSelectorMustBeOfCertainTypes) + localError(c.config, n.info, errSelectorMustBeOfCertainTypes) return for i in countup(1, sonsLen(n) - 1): var x = n.sons[i] when defined(nimsuggest): - if gIdeCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: + if c.config.ideCmd == ideSug and exactEquals(gTrackPos, x.info) and caseTyp.kind == tyEnum: suggestEnum(c, x, caseTyp) case x.kind of nkOfBranch: - checkMinSonsLen(x, 2) + checkMinSonsLen(x, 2, c.config) semCaseBranch(c, n, x, i, covered) var last = sonsLen(x)-1 x.sons[last] = semExprBranchScope(c, x.sons[last]) typ = commonType(typ, x.sons[last]) of nkElifBranch: chckCovered = false - checkSonsLen(x, 2) + checkSonsLen(x, 2, c.config) when newScopeForIf: openScope(c) x.sons[0] = forceBool(c, semExprWithType(c, x.sons[0])) when not newScopeForIf: openScope(c) @@ -197,17 +223,17 @@ proc semCase(c: PContext, n: PNode): PNode = closeScope(c) of nkElse: chckCovered = false - checkSonsLen(x, 1) + checkSonsLen(x, 1, c.config) x.sons[0] = semExprBranchScope(c, x.sons[0]) typ = commonType(typ, x.sons[0]) hasElse = true else: - illFormedAst(x) + illFormedAst(x, c.config) if chckCovered: if covered == toCover(n.sons[0].typ): hasElse = true else: - localError(n.info, errNotAllCasesCovered) + localError(c.config, n.info, "not all cases are covered") closeScope(c) if isEmptyType(typ) or typ.kind in {tyNil, tyExpr} or not hasElse: for i in 1..n.len-1: discardCheck(c, n.sons[i].lastSon) @@ -229,19 +255,19 @@ proc semTry(c: PContext, n: PNode): PNode = # returns true if exception type is imported type let typ = semTypeNode(c, typeNode, nil).toObject() var is_imported = false - if isImportedException(typ): + if isImportedException(typ, c.config): is_imported = true elif not isException(typ): - localError(typeNode.info, errExprCannotBeRaised) + localError(c.config, typeNode.info, errExprCannotBeRaised) if containsOrIncl(check, typ.id): - localError(typeNode.info, errExceptionAlreadyHandled) + localError(c.config, typeNode.info, errExceptionAlreadyHandled) typeNode = newNodeIT(nkType, typeNode.info, typ) is_imported result = n inc c.p.inTryStmt - checkMinSonsLen(n, 2) + checkMinSonsLen(n, 2, c.config) var typ = commonTypeBegin n[0] = semExprBranchScope(c, n[0]) @@ -250,7 +276,7 @@ proc semTry(c: PContext, n: PNode): PNode = var last = sonsLen(n) - 1 for i in countup(1, last): let a = n.sons[i] - checkMinSonsLen(a, 1) + checkMinSonsLen(a, 1, c.config) openScope(c) if a.kind == nkExceptBranch: @@ -277,10 +303,10 @@ proc semTry(c: PContext, n: PNode): PNode = else: is_native = true if is_native and is_imported: - localError(a[0].info, "Mix of imported and native exception types is not allowed in one except branch") + localError(c.config, a[0].info, "Mix of imported and native exception types is not allowed in one except branch") elif a.kind != nkFinally: - illFormedAst(n) + illFormedAst(n, c.config) # last child of an nkExcept/nkFinally branch is a statement: a[^1] = semExprBranchScope(c, a[^1]) @@ -312,10 +338,10 @@ proc fitRemoveHiddenConv(c: PContext, typ: PType, n: PNode): PNode = result.info = n.info result.typ = typ else: - changeType(r1, typ, check=true) + changeType(c, r1, typ, check=true) result = r1 elif not sameType(result.typ, typ): - changeType(result, typ, check=false) + changeType(c, result, typ, check=false) proc findShadowedVar(c: PContext, v: PSym): PSym = for scope in walkScopes(c.currentScope.parent): @@ -339,16 +365,16 @@ proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym = result = semIdentWithPragma(c, kind, n, {}) if result.owner.kind == skModule: incl(result.flags, sfGlobal) - suggestSym(n.info, result, c.graph.usageSym) + suggestSym(c.config, n.info, result, c.graph.usageSym) styleCheckDef(result) -proc checkNilable(v: PSym) = +proc checkNilable(c: PContext; v: PSym) = if {sfGlobal, sfImportC} * v.flags == {sfGlobal} and {tfNotNil, tfNeedsInit} * v.typ.flags != {}: if v.ast.isNil: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) elif tfNotNil in v.typ.flags and tfNotNil notin v.ast.typ.flags: - message(v.info, warnProveInit, v.name.s) + message(c.config, v.info, warnProveInit, v.name.s) include semasgn @@ -369,13 +395,13 @@ proc isDiscardUnderscore(v: PSym): bool = proc semUsing(c: PContext; n: PNode): PNode = result = ast.emptyNode - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "using") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "using") for i in countup(0, sonsLen(n)-1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a) - checkMinSonsLen(a, 3) + if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var length = sonsLen(a) if a.sons[length-2].kind != nkEmpty: let typ = semTypeNode(c, a.sons[length-2], nil) @@ -384,10 +410,10 @@ proc semUsing(c: PContext; n: PNode): PNode = v.typ = typ strTableIncl(c.signatures, v) else: - localError(a.info, "'using' section must have a type") + localError(c.config, a.info, "'using' section must have a type") var def: PNode if a.sons[length-1].kind != nkEmpty: - localError(a.info, "'using' sections cannot contain assignments") + localError(c.config, a.info, "'using' sections cannot contain assignments") proc hasEmpty(typ: PType): bool = if typ.kind in {tySequence, tyArray, tySet}: @@ -416,7 +442,7 @@ proc makeDeref(n: PNode): PNode = proc fillPartialObject(c: PContext; n: PNode; typ: PType) = if n.len == 2: let x = semExprWithType(c, n[0]) - let y = considerQuotedIdent(n[1]) + let y = considerQuotedIdent(c.config, n[1]) let obj = x.typ.skipTypes(abstractPtrs) if obj.kind == tyObject and tfPartial in obj.flags: let field = newSym(skField, getIdent(y.s), obj.sym, n[1].info) @@ -427,14 +453,14 @@ proc fillPartialObject(c: PContext; n: PNode; typ: PType) = n.sons[1] = newSymNode(field) n.typ = field.typ else: - localError(n.info, "implicit object field construction " & + localError(c.config, n.info, "implicit object field construction " & "requires a .partial object, but got " & typeToString(obj)) else: - localError(n.info, "nkDotNode requires 2 children") + localError(c.config, n.info, "nkDotNode requires 2 children") -proc setVarType(v: PSym, typ: PType) = +proc setVarType(c: PContext; v: PSym, typ: PType) = if v.typ != nil and not sameTypeOrNil(v.typ, typ): - localError(v.info, "inconsistent typing for reintroduced symbol '" & + localError(c.config, v.info, "inconsistent typing for reintroduced symbol '" & v.name.s & "': previous type was: " & typeToString(v.typ) & "; new type is: " & typeToString(typ)) v.typ = typ @@ -445,10 +471,10 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = var hasCompileTime = false for i in countup(0, sonsLen(n)-1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a) - checkMinSonsLen(a, 3) + if a.kind notin {nkIdentDefs, nkVarTuple, nkConstDef}: illFormedAst(a, c.config) + checkMinSonsLen(a, 3, c.config) var length = sonsLen(a) var typ: PType if a.sons[length-2].kind != nkEmpty: @@ -460,7 +486,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = def = semExprWithType(c, a.sons[length-1], {efAllowDestructor}) if def.typ.kind == tyTypeDesc and c.p.owner.kind != skMacro: # prevent the all too common 'var x = int' bug: - localError(def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?") + localError(c.config, def.info, "'typedesc' metatype is not valid here; typed '=' instead of ':'?") def.typ = errorType(c) if typ != nil: if typ.isMetaType: @@ -476,23 +502,23 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if typ.kind in tyUserTypeClasses and typ.isResolvedUserTypeClass: typ = typ.lastSon if hasEmpty(typ): - localError(def.info, errCannotInferTypeOfTheLiteral, + localError(c.config, def.info, errCannotInferTypeOfTheLiteral % ($typ.kind).substr(2).toLowerAscii) elif typ.kind == tyProc and tfUnresolved in typ.flags: - localError(def.info, errProcHasNoConcreteType, def.renderTree) + localError(c.config, def.info, errProcHasNoConcreteType % def.renderTree) else: - if symkind == skLet: localError(a.info, errLetNeedsInit) + if symkind == skLet: localError(c.config, a.info, errLetNeedsInit) # this can only happen for errornous var statements: if typ == nil: continue - typeAllowedCheck(a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) + typeAllowedCheck(c.config, a.info, typ, symkind, if c.matchedConcept != nil: {taConcept} else: {}) liftTypeBoundOps(c, typ, a.info) var tup = skipTypes(typ, {tyGenericInst, tyAlias, tySink}) if a.kind == nkVarTuple: if tup.kind != tyTuple: - localError(a.info, errXExpected, "tuple") + localError(c.config, a.info, errXExpected, "tuple") elif length-2 != sonsLen(tup): - localError(a.info, errWrongNumberOfVariables) + localError(c.config, a.info, errWrongNumberOfVariables) b = newNodeI(nkVarTuple, a.info) newSons(b, length) b.sons[length-2] = a.sons[length-2] # keep type desc for doc generator @@ -500,7 +526,7 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = addToVarSection(c, result, n, b) elif tup.kind == tyTuple and def.kind in {nkPar, nkTupleConstr} and a.kind == nkIdentDefs and a.len > 3: - message(a.info, warnEachIdentIsTuple) + message(c.config, a.info, warnEachIdentIsTuple) for j in countup(0, length-3): if a[j].kind == nkDotExpr: @@ -518,19 +544,19 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = if shadowed != nil: shadowed.flags.incl(sfShadowed) if shadowed.kind == skResult and sfGenSym notin v.flags: - message(a.info, warnResultShadowed) + message(c.config, a.info, warnResultShadowed) # a shadowed variable is an error unless it appears on the right # side of the '=': - if warnShadowIdent in gNotes and not identWithin(def, v.name): - message(a.info, warnShadowIdent, v.name.s) + if warnShadowIdent in c.config.notes and not identWithin(def, v.name): + message(c.config, a.info, warnShadowIdent, v.name.s) if a.kind != nkVarTuple: if def.kind != nkEmpty: # this is needed for the evaluation pass and for the guard checking: v.ast = def - if sfThread in v.flags: localError(def.info, errThreadvarCannotInit) - setVarType(v, typ) + if sfThread in v.flags: localError(c.config, def.info, errThreadvarCannotInit) + setVarType(c, v, typ) b = newNodeI(nkIdentDefs, a.info) - if importantComments(): + if importantComments(c.config): # keep documentation information: b.comment = a.comment addSon(b, newSymNode(v)) @@ -540,29 +566,29 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = else: if def.kind in {nkPar, nkTupleConstr}: v.ast = def[j] # bug #7663, for 'nim check' this can be a non-tuple: - if tup.kind == tyTuple: setVarType(v, tup.sons[j]) + if tup.kind == tyTuple: setVarType(c, v, tup.sons[j]) else: v.typ = tup b.sons[j] = newSymNode(v) - checkNilable(v) + checkNilable(c, v) if sfCompileTime in v.flags: hasCompileTime = true if hasCompileTime: - vm.setupCompileTimeVar(c.module, c.cache, c.graph.config, result) + vm.setupCompileTimeVar(c.module, c.cache, c.graph, result) proc semConst(c: PContext, n: PNode): PNode = result = copyNode(n) for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] - if gCmd == cmdIdeTools: suggestStmt(c, a) + if c.config.cmd == cmdIdeTools: suggestStmt(c, a) if a.kind == nkCommentStmt: continue - if (a.kind != nkConstDef): illFormedAst(a) - checkSonsLen(a, 3) + if a.kind != nkConstDef: illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) var v = semIdentDef(c, a.sons[0], skConst) var typ: PType = nil if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil) var def = semConstExpr(c, a.sons[2]) if def == nil: - localError(a.sons[2].info, errConstExprExpected) + localError(c.config, a.sons[2].info, errConstExprExpected) continue # check type compatibility between def.typ and typ: if typ != nil: @@ -570,16 +596,16 @@ proc semConst(c: PContext, n: PNode): PNode = else: typ = def.typ if typ == nil: - localError(a.sons[2].info, errConstExprExpected) + localError(c.config, a.sons[2].info, errConstExprExpected) continue if typeAllowed(typ, skConst) != nil and def.kind != nkNilLit: - localError(a.info, "invalid type for const: " & typeToString(typ)) + localError(c.config, a.info, "invalid type for const: " & typeToString(typ)) continue - setVarType(v, typ) + setVarType(c, v, typ) v.ast = def # no need to copy if sfGenSym notin v.flags: addInterfaceDecl(c, v) var b = newNodeI(nkConstDef, a.info) - if importantComments(): b.comment = a.comment + if importantComments(c.config): b.comment = a.comment addSon(b, newSymNode(v)) addSon(b, a.sons[1]) addSon(b, copyTree(def)) @@ -588,12 +614,12 @@ proc semConst(c: PContext, n: PNode): PNode = include semfields proc addForVarDecl(c: PContext, v: PSym) = - if warnShadowIdent in gNotes: + if warnShadowIdent in c.config.notes: let shadowed = findShadowedVar(c, v) if shadowed != nil: # XXX should we do this here? #shadowed.flags.incl(sfShadowed) - message(v.info, warnShadowIdent, v.name.s) + message(c.config, v.info, warnShadowIdent, v.name.s) addDecl(c, v) proc symForVar(c: PContext, n: PNode): PSym = @@ -619,9 +645,9 @@ proc semForVars(c: PContext, n: PNode): PNode = n.sons[0] = newSymNode(v) if sfGenSym notin v.flags: addForVarDecl(c, v) else: - localError(n.info, errWrongNumberOfVariables) + localError(c.config, n.info, errWrongNumberOfVariables) elif length-2 != sonsLen(iter): - localError(n.info, errWrongNumberOfVariables) + localError(c.config, n.info, errWrongNumberOfVariables) else: for i in countup(0, length - 3): var v = symForVar(c, n.sons[i]) @@ -658,7 +684,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = # n := for a, b, c in m(x, y, z): Y # to # m(n) - let forLoopStmt = magicsys.getCompilerProc("ForLoopStmt") + let forLoopStmt = magicsys.getCompilerProc(c.graph, "ForLoopStmt") if forLoopStmt == nil: return let headSymbol = iterExpr[0] @@ -671,7 +697,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = if match == nil: match = symx else: - localError(n.info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [ + localError(c.config, n.info, errAmbiguousCallXYZ % [ getProcHeader(match), getProcHeader(symx), $iterExpr]) symx = nextOverloadIter(o, c, headSymbol) @@ -685,7 +711,7 @@ proc handleForLoopMacro(c: PContext; n: PNode): PNode = else: result = nil proc semFor(c: PContext, n: PNode): PNode = - checkMinSonsLen(n, 3) + checkMinSonsLen(n, 3, c.config) var length = sonsLen(n) result = handleForLoopMacro(c, n) if result != nil: return result @@ -715,7 +741,7 @@ proc semFor(c: PContext, n: PNode): PNode = elif length == 4: n.sons[length-2] = implicitIterator(c, "pairs", n.sons[length-2]) else: - localError(n.sons[length-2].info, errIteratorExpected) + localError(c.config, n.sons[length-2].info, "iterator within for loop context expected") result = semForVars(c, n) else: result = semForVars(c, n) @@ -726,31 +752,31 @@ proc semFor(c: PContext, n: PNode): PNode = proc semRaise(c: PContext, n: PNode): PNode = result = n - checkSonsLen(n, 1) + checkSonsLen(n, 1, c.config) if n[0].kind != nkEmpty: n[0] = semExprWithType(c, n[0]) let typ = n[0].typ - if not isImportedException(typ): + if not isImportedException(typ, c.config): if typ.kind != tyRef or typ.lastSon.kind != tyObject: - localError(n.info, errExprCannotBeRaised) + localError(c.config, n.info, errExprCannotBeRaised) if not isException(typ.lastSon): - localError(n.info, "raised object of type $1 does not inherit from Exception", + localError(c.config, n.info, "raised object of type $1 does not inherit from Exception", [typeToString(typ)]) proc addGenericParamListToScope(c: PContext, n: PNode) = - if n.kind != nkGenericParams: illFormedAst(n) + if n.kind != nkGenericParams: illFormedAst(n, c.config) for i in countup(0, sonsLen(n)-1): var a = n.sons[i] if a.kind == nkSym: addDecl(c, a.sym) - else: illFormedAst(a) + else: illFormedAst(a, c.config) -proc typeSectionTypeName(n: PNode): PNode = +proc typeSectionTypeName(c: PContext; n: PNode): PNode = if n.kind == nkPragmaExpr: - if n.len == 0: illFormedAst(n) + if n.len == 0: illFormedAst(n, c.config) result = n.sons[0] else: result = n - if result.kind != nkSym: illFormedAst(n) + if result.kind != nkSym: illFormedAst(n, c.config) proc typeSectionLeftSidePass(c: PContext, n: PNode) = @@ -759,21 +785,21 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] when defined(nimsuggest): - if gCmd == cmdIdeTools: + if c.config.cmd == cmdIdeTools: inc c.inTypeContext suggestStmt(c, a) dec c.inTypeContext 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) let name = a.sons[0] var s: PSym if name.kind == nkDotExpr and a[2].kind == nkObjectTy: - let pkgName = considerQuotedIdent(name[0]) - let typName = considerQuotedIdent(name[1]) + let pkgName = considerQuotedIdent(c.config, name[0]) + let typName = considerQuotedIdent(c.config, name[1]) let pkg = c.graph.packageSyms.strTableGet(pkgName) if pkg.isNil or pkg.kind != skPackage: - localError(name.info, "unknown package name: " & pkgName.s) + localError(c.config, name.info, "unknown package name: " & pkgName.s) else: let typsym = pkg.tab.strTableGet(typName) if typsym.isNil: @@ -787,7 +813,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = s = typsym addInterfaceDecl(c, s) else: - localError(name.info, typsym.name.s & " is not a type that can be forwarded") + localError(c.config, name.info, typsym.name.s & " is not a type that can be forwarded") s = typsym else: s = semIdentDef(c, name, skType) @@ -799,7 +825,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = # check if the symbol already exists: let pkg = c.module.owner if not isTopLevel(c) or pkg.isNil: - localError(name.info, "only top level types in a package can be 'package'") + localError(c.config, name.info, "only top level types in a package can be 'package'") else: let typsym = pkg.tab.strTableGet(s.name) if typsym != nil: @@ -807,7 +833,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = typeCompleted(typsym) typsym.info = s.info else: - localError(name.info, "cannot complete type '" & s.name.s & "' twice; " & + localError(c.config, name.info, "cannot complete type '" & s.name.s & "' twice; " & "previous type completion was here: " & $typsym.info) s = typsym # add it here, so that recursive types are possible: @@ -818,14 +844,12 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) = else: a.sons[0] = newSymNode(s) -proc checkCovariantParamsUsages(genericType: PType) = +proc checkCovariantParamsUsages(c: PContext; genericType: PType) = var body = genericType[^1] - proc traverseSubTypes(t: PType): bool = - template error(msg) = localError(genericType.sym.info, msg) - + proc traverseSubTypes(c: PContext; t: PType): bool = + template error(msg) = localError(c.config, genericType.sym.info, msg) result = false - template subresult(r) = let sub = r result = result or sub @@ -834,24 +858,19 @@ proc checkCovariantParamsUsages(genericType: PType) = of tyGenericParam: t.flags.incl tfWeakCovariant return true - of tyObject: for field in t.n: - subresult traverseSubTypes(field.typ) - + subresult traverseSubTypes(c, field.typ) of tyArray: - return traverseSubTypes(t[1]) - + return traverseSubTypes(c, t[1]) of tyProc: for subType in t.sons: if subType != nil: - subresult traverseSubTypes(subType) + subresult traverseSubTypes(c, subType) if result: error("non-invariant type param used in a proc type: " & $t) - of tySequence: - return traverseSubTypes(t[0]) - + return traverseSubTypes(c, t[0]) of tyGenericInvocation: let targetBody = t[0] for i in 1 ..< t.len: @@ -872,43 +891,35 @@ proc checkCovariantParamsUsages(genericType: PType) = "' used in a non-contravariant position") result = true else: - subresult traverseSubTypes(param) - + subresult traverseSubTypes(c, param) of tyAnd, tyOr, tyNot, tyStatic, tyBuiltInTypeClass, tyCompositeTypeClass: error("non-invariant type parameters cannot be used with types such '" & $t & "'") - of tyUserTypeClass, tyUserTypeClassInst: error("non-invariant type parameters are not supported in concepts") - of tyTuple: for fieldType in t.sons: - subresult traverseSubTypes(fieldType) - + subresult traverseSubTypes(c, fieldType) of tyPtr, tyRef, tyVar, tyLent: if t.base.kind == tyGenericParam: return true - return traverseSubTypes(t.base) - + return traverseSubTypes(c, t.base) of tyDistinct, tyAlias, tySink: - return traverseSubTypes(t.lastSon) - + return traverseSubTypes(c, t.lastSon) of tyGenericInst: - internalAssert false - + internalAssert c.config, false else: discard - - discard traverseSubTypes(body) + discard traverseSubTypes(c, body) proc typeSectionRightSidePass(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 != nkTypeDef): illFormedAst(a) - checkSonsLen(a, 3) - let name = typeSectionTypeName(a.sons[0]) + if a.kind != nkTypeDef: illFormedAst(a, c.config) + checkSonsLen(a, 3, c.config) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym if s.magic == mNone and a.sons[2].kind == nkEmpty: - localError(a.info, errImplOfXexpected, s.name.s) + localError(c.config, a.info, errImplOfXexpected % s.name.s) if s.magic != mNone: processMagicType(c, s) if a.sons[1].kind != nkEmpty: # We have a generic type declaration here. In generic types, @@ -939,7 +950,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = body.size = -1 # could not be computed properly s.typ.sons[sonsLen(s.typ) - 1] = body if tfCovariant in s.typ.flags: - checkCovariantParamsUsages(s.typ) + checkCovariantParamsUsages(c, s.typ) # XXX: This is a temporary limitation: # The codegen currently produces various failures with # generic imported types that have fields, but we need @@ -974,8 +985,8 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = # give anonymous object a dummy symbol: var st = s.typ if st.kind == tyGenericBody: st = st.lastSon - internalAssert st.kind in {tyPtr, tyRef} - internalAssert st.lastSon.sym == nil + internalAssert c.config, st.kind in {tyPtr, tyRef} + internalAssert c.config, st.lastSon.sym == nil incl st.flags, tfRefsAnonObj let obj = newSym(skType, getIdent(s.name.s & ":ObjectType"), getCurrOwner(c), s.info) @@ -983,17 +994,17 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) = st.lastSon.sym = obj -proc checkForMetaFields(n: PNode) = +proc checkForMetaFields(c: PContext; n: PNode) = template checkMeta(t) = if t != nil and t.isMetaType and tfGenericTypeParam notin t.flags: - localError(n.info, errTIsNotAConcreteType, t.typeToString) + localError(c.config, n.info, errTIsNotAConcreteType % t.typeToString) if n.isNil: return case n.kind of nkRecList, nkRecCase: - for s in n: checkForMetaFields(s) + for s in n: checkForMetaFields(c, s) of nkOfBranch, nkElse: - checkForMetaFields(n.lastSon) + checkForMetaFields(c, n.lastSon) of nkSym: let t = n.sym.typ case t.kind @@ -1005,13 +1016,13 @@ proc checkForMetaFields(n: PNode) = else: checkMeta(t) else: - internalAssert false + internalAssert c.config, false proc typeSectionFinalPass(c: PContext, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue - let name = typeSectionTypeName(a.sons[0]) + let name = typeSectionTypeName(c, a.sons[0]) var s = name.sym # compute the type's size and check for illegal recursions: if a.sons[1].kind == nkEmpty: @@ -1031,9 +1042,9 @@ proc typeSectionFinalPass(c: PContext, n: PNode) = assert s.typ != nil assignType(s.typ, t) s.typ.id = t.id # same id - checkConstructedType(s.info, s.typ) + checkConstructedType(c.config, s.info, s.typ) if s.typ.kind in {tyObject, tyTuple} and not s.typ.n.isNil: - checkForMetaFields(s.typ.n) + checkForMetaFields(c, s.typ.n) instAllTypeBoundOp(c, n.info) @@ -1042,10 +1053,10 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = case n.kind of nkIncludeStmt: for i in 0..<n.len: - var f = checkModuleName(n.sons[i]) + var f = checkModuleName(c.config, n.sons[i]) if f != InvalidFileIDX: if containsOrIncl(c.includedFiles, f.int): - localError(n.info, errRecursiveDependencyX, f.toFilename) + localError(c.config, n.info, errRecursiveDependencyX % f.toFilename) else: let code = gIncludeFile(c.graph, c.module, f, c.cache) gatherStmts c, code, result @@ -1101,12 +1112,12 @@ proc semParamList(c: PContext, n, genericParams: PNode, s: PSym) = s.typ = semProcTypeNode(c, n, genericParams, nil, s.kind) if s.kind notin {skMacro, skTemplate}: if s.typ.sons[0] != nil and s.typ.sons[0].kind == tyStmt: - localError(n.info, errGenerated, "invalid return type: 'stmt'") + localError(c.config, n.info, "invalid return type: 'stmt'") proc addParams(c: PContext, n: PNode, kind: TSymKind) = for i in countup(1, sonsLen(n)-1): if n.sons[i].kind == nkSym: addParamOrResult(c, n.sons[i].sym, kind) - else: illFormedAst(n) + else: illFormedAst(n, c.config) proc semBorrow(c: PContext, n: PNode, s: PSym) = # search for the correct alias: @@ -1115,7 +1126,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) = # store the alias: n.sons[bodyPos] = newSymNode(b) else: - localError(n.info, errNoSymbolToBorrowFromFound) + localError(c.config, n.info, errNoSymbolToBorrowFromFound) proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = if t != nil: @@ -1138,7 +1149,7 @@ proc lookupMacro(c: PContext, n: PNode): PSym = result = n.sym if result.kind notin {skMacro, skTemplate}: result = nil else: - result = searchInScopes(c, considerQuotedIdent(n), {skMacro, skTemplate}) + result = searchInScopes(c, considerQuotedIdent(c.config, n), {skMacro, skTemplate}) proc semProcAnnotation(c: PContext, prc: PNode; validPragmas: TSpecialWords): PNode = @@ -1150,11 +1161,11 @@ proc semProcAnnotation(c: PContext, prc: PNode; let m = lookupMacro(c, key) if m == nil: if key.kind == nkIdent and key.ident.id == ord(wDelegator): - if considerQuotedIdent(prc.sons[namePos]).s == "()": + if considerQuotedIdent(c.config, prc.sons[namePos]).s == "()": prc.sons[namePos] = newIdentNode(c.cache.idDelegator, prc.info) prc.sons[pragmasPos] = copyExcept(n, i) else: - localError(prc.info, errOnlyACallOpCanBeDelegator) + localError(c.config, prc.info, "only a call operator can be a delegator") continue elif sfCustomPragma in m.flags: continue # semantic check for custom pragma happens later in semProcAux @@ -1199,7 +1210,7 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = result = semProcAnnotation(c, n, lambdaPragmas) if result != nil: return result result = n - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) var s: PSym if n[namePos].kind != nkSym: s = newSym(skProc, c.cache.idAnon, getCurrOwner(c), n.info) @@ -1225,10 +1236,10 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = s.typ = newProcType(c, n.info) if n.sons[pragmasPos].kind != nkEmpty: pragma(c, s, n.sons[pragmasPos], lambdaPragmas) - s.options = gOptions + s.options = c.config.options if n.sons[bodyPos].kind != nkEmpty: if sfImportc in s.flags: - localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) + localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) #if efDetermineType notin flags: # XXX not good enough; see tnamedparamanonproc.nim if gp.len == 0 or (gp.len == 1 and tfRetType in gp[0].typ.flags): @@ -1236,13 +1247,13 @@ proc semLambda(c: PContext, n: PNode, flags: TExprFlags): PNode = addResult(c, s.typ.sons[0], n.info, skProc) addResultNode(c, n) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) - n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s) + n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s) popProcCon(c) elif efOperand notin flags: - localError(n.info, errGenericLambdaNotAllowed) + localError(c.config, n.info, errGenericLambdaNotAllowed) sideEffectsCheck(c, s) else: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected % s.name.s) closeScope(c) # close scope for parameters popOwner(c) result.typ = s.typ @@ -1267,7 +1278,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = for i in 1..<params.len: if params[i].typ.kind in {tyTypeDesc, tyGenericParam, tyFromExpr}+tyTypeClasses: - localError(params[i].info, "cannot infer type of parameter: " & + localError(c.config, params[i].info, "cannot infer type of parameter: " & params[i].sym.name.s) #params[i].sym.owner = s openScope(c) @@ -1277,7 +1288,7 @@ proc semInferredLambda(c: PContext, pt: TIdTable, n: PNode): PNode = addResult(c, n.typ.sons[0], n.info, skProc) addResultNode(c, n) let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) - n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s) + n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s) popProcCon(c) popOwner(c) closeScope(c) @@ -1323,11 +1334,11 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if obj.destructor.isNil: obj.destructor = s else: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) noError = true if not noError and sfSystemModule notin s.owner.flags: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "signature for '" & s.name.s & "' must be proc[T: object](x: var T)") incl(s.flags, sfUsed) of "deepcopy", "=deepcopy": @@ -1344,13 +1355,13 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if t.kind in {tyObject, tyDistinct, tyEnum}: if t.deepCopy.isNil: t.deepCopy = s else: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "cannot bind another 'deepCopy' to: " & typeToString(t)) else: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "cannot bind 'deepCopy' to: " & typeToString(t)) else: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "signature for 'deepCopy' must be proc[T: ptr|ref](x: T): T") incl(s.flags, sfUsed) of "=", "=sink": @@ -1375,15 +1386,15 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if opr[].isNil: opr[] = s else: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "cannot bind another '" & s.name.s & "' to: " & typeToString(obj)) return if sfSystemModule notin s.owner.flags: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "signature for '" & s.name.s & "' must be proc[T: object](x: var T; y: T)") else: if sfOverriden in s.flags: - localError(n.info, errGenerated, + localError(c.config, n.info, errGenerated, "'destroy' or 'deepCopy' expected for 'override'") proc cursorInProcAux(n: PNode): bool = @@ -1426,7 +1437,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = foundObj = true x.methods.safeAdd((col,s)) if not foundObj: - message(n.info, warnDeprecated, "generic method not attachable to object type") + message(c.config, n.info, warnDeprecated, "generic method not attachable to object type") else: # why check for the body? bug #2400 has none. Checking for sfForward makes # no sense either. @@ -1434,7 +1445,7 @@ proc semMethodPrototype(c: PContext; s: PSym; n: PNode) = if hasObjParam(s): methodDef(c.graph, s, fromCache=false) else: - localError(n.info, errXNeedsParamObjectType, "method") + localError(c.config, n.info, "'method' needs a parameter that has an object type") proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords, @@ -1442,7 +1453,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, result = semProcAnnotation(c, n, validPragmas) if result != nil: return result result = n - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) var s: PSym var typeIsDetermined = false var isAnon = false @@ -1531,10 +1542,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, # XXX This needs more checks eventually, for example that external # linking names do agree: if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags: - localError(n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX, - "'" & proto.name.s & "' from " & $proto.info) + localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % + ("'" & proto.name.s & "' from " & $proto.info)) if sfForward notin proto.flags: - wrongRedefinition(n.info, proto.name.s) + wrongRedefinition(c, n.info, proto.name.s) excl(proto.flags, sfForward) closeScope(c) # close scope with wrong parameter symbols openScope(c) # open scope for old (correct) parameter symbols @@ -1547,32 +1558,32 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, n.sons[genericParamsPos] = proto.ast.sons[genericParamsPos] n.sons[paramsPos] = proto.ast.sons[paramsPos] n.sons[pragmasPos] = proto.ast.sons[pragmasPos] - if n.sons[namePos].kind != nkSym: internalError(n.info, "semProcAux") + if n.sons[namePos].kind != nkSym: internalError(c.config, n.info, "semProcAux") n.sons[namePos].sym = proto - if importantComments() and not isNil(proto.ast.comment): + if importantComments(c.config) and not isNil(proto.ast.comment): n.comment = proto.ast.comment proto.ast = n # needed for code generation popOwner(c) pushOwner(c, s) - s.options = gOptions + s.options = c.config.options if sfOverriden in s.flags or s.name.s[0] == '=': semOverride(c, s, n) if s.name.s[0] in {'.', '('}: if s.name.s in [".", ".()", ".="] and {destructor, dotOperators} * c.features == {}: - localError(n.info, "the overloaded " & s.name.s & + localError(c.config, n.info, "the overloaded " & s.name.s & " operator has to be enabled with {.experimental: \"dotOperators\".}") elif s.name.s == "()" and callOperator notin c.features: - localError(n.info, "the overloaded " & s.name.s & + localError(c.config, n.info, "the overloaded " & s.name.s & " operator has to be enabled with {.experimental: \"callOperator\".}") if n.sons[bodyPos].kind != nkEmpty: # for DLL generation it is annoying to check for sfImportc! if sfBorrow in s.flags: - localError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s) + localError(c.config, n.sons[bodyPos].info, errImplOfXNotAllowed % s.name.s) let usePseudoGenerics = kind in {skMacro, skTemplate} # Macros and Templates can have generic parameters, but they are # only used for overload resolution (there is no instantiation of # the symbol, so we must process the body now) - if not usePseudoGenerics and gIdeCmd in {ideSug, ideCon} and not + if not usePseudoGenerics and c.config.ideCmd in {ideSug, ideCon} and not cursorInProc(n.sons[bodyPos]): discard "speed up nimsuggest" if s.kind == skMethod: semMethodPrototype(c, s, n) @@ -1590,7 +1601,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, let semBody = hloBody(c, semProcBody(c, n.sons[bodyPos])) # unfortunately we cannot skip this step when in 'system.compiles' # context as it may even be evaluated in 'system.compiles': - n.sons[bodyPos] = transformBody(c.module, c.features, semBody, s) + n.sons[bodyPos] = transformBody(c.graph, c.module, semBody, s) else: if s.typ.sons[0] != nil and kind != skIterator: addDecl(c, newSym(skUnknown, getIdent"result", nil, n.info)) @@ -1606,7 +1617,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, popProcCon(c) else: if s.kind == skMethod: semMethodPrototype(c, s, n) - if proto != nil: localError(n.info, errImplOfXexpected, proto.name.s) + if proto != nil: localError(c.config, n.info, errImplOfXexpected % proto.name.s) if {sfImportc, sfBorrow} * s.flags == {} and s.magic == mNone: incl(s.flags, sfForward) elif sfBorrow in s.flags: semBorrow(c, n, s) @@ -1621,7 +1632,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, result.typ = s.typ if isTopLevel(c) and s.kind != skIterator and s.typ.callConv == ccClosure: - localError(s.info, "'.closure' calling convention for top level routines is invalid") + localError(c.config, s.info, "'.closure' calling convention for top level routines is invalid") proc determineType(c: PContext, s: PSym) = if s.typ != nil: return @@ -1644,9 +1655,9 @@ proc semIterator(c: PContext, n: PNode): PNode = var s = result.sons[namePos].sym var t = s.typ if t.sons[0] == nil and s.typ.callConv != ccClosure: - localError(n.info, errXNeedsReturnType, "iterator") + localError(c.config, n.info, "iterator needs a return type") if isAnon and s.typ.callConv == ccInline: - localError(n.info, "inline iterators are not first-class / cannot be assigned to variables") + localError(c.config, n.info, "inline iterators are not first-class / cannot be assigned to variables") # iterators are either 'inline' or 'closure'; for backwards compatibility, # we require first class iterators to be marked with 'closure' explicitly # -- at least for 0.9.2. @@ -1655,7 +1666,7 @@ proc semIterator(c: PContext, n: PNode): PNode = else: s.typ.callConv = ccInline if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected % s.name.s) proc semProc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skProc, procPragmas) @@ -1664,7 +1675,7 @@ proc semFunc(c: PContext, n: PNode): PNode = result = semProcAux(c, n, skFunc, procPragmas) proc semMethod(c: PContext, n: PNode): PNode = - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "method") + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "method") result = semProcAux(c, n, skMethod, methodPragmas) # macros can transform converters to nothing: if namePos >= result.safeLen: return result @@ -1685,8 +1696,8 @@ proc semMethod(c: PContext, n: PNode): PNode = else: disp.ast[resultPos].sym.typ = ret proc semConverterDef(c: PContext, n: PNode): PNode = - if not isTopLevel(c): localError(n.info, errXOnlyAtModuleScope, "converter") - checkSonsLen(n, bodyPos + 1) + if not isTopLevel(c): localError(c.config, n.info, errXOnlyAtModuleScope % "converter") + checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skConverter, converterPragmas) # macros can transform converters to nothing: if namePos >= result.safeLen: return result @@ -1696,12 +1707,12 @@ proc semConverterDef(c: PContext, n: PNode): PNode = if result.kind != nkConverterDef: return var s = result.sons[namePos].sym var t = s.typ - if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "converter") - if sonsLen(t) != 2: localError(n.info, errXRequiresOneArgument, "converter") + if t.sons[0] == nil: localError(c.config, n.info, errXNeedsReturnType % "converter") + if sonsLen(t) != 2: localError(c.config, n.info, "a converter takes exactly one argument") addConverter(c, s) proc semMacroDef(c: PContext, n: PNode): PNode = - checkSonsLen(n, bodyPos + 1) + checkSonsLen(n, bodyPos + 1, c.config) result = semProcAux(c, n, skMacro, macroPragmas) # macros can transform macros to nothing: if namePos >= result.safeLen: return result @@ -1716,18 +1727,18 @@ proc semMacroDef(c: PContext, n: PNode): PNode = let param = t.n.sons[i].sym if param.typ.kind != tyExpr: allUntyped = false if allUntyped: incl(s.flags, sfAllUntyped) - if t.sons[0] == nil: localError(n.info, errXNeedsReturnType, "macro") + if t.sons[0] == nil: localError(c.config, n.info, "macro needs a return type") if n.sons[bodyPos].kind == nkEmpty: - localError(n.info, errImplOfXexpected, s.name.s) + localError(c.config, n.info, errImplOfXexpected % s.name.s) proc evalInclude(c: PContext, n: PNode): PNode = result = newNodeI(nkStmtList, n.info) addSon(result, n) for i in countup(0, sonsLen(n) - 1): - var f = checkModuleName(n.sons[i]) + var f = checkModuleName(c.config, n.sons[i]) if f != InvalidFileIDX: if containsOrIncl(c.includedFiles, f.int): - localError(n.info, errRecursiveDependencyX, f.toFilename) + localError(c.config, n.info, errRecursiveDependencyX % f.toFilename) else: addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache))) excl(c.includedFiles, f.int) @@ -1758,7 +1769,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode = let a = semStmt(c, n.sons[0]) dec c.inStaticContext n.sons[0] = a - evalStaticStmt(c.module, c.cache, c.graph.config, a, c.p.owner) + evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner) result = newNodeI(nkDiscardStmt, n.info, 1) result.sons[0] = emptyNode @@ -1779,7 +1790,7 @@ proc inferConceptStaticParam(c: PContext, inferred, n: PNode) = var typ = inferred.typ let res = semConstExpr(c, n) if not sameType(res.typ, typ.base): - localError(n.info, + localError(c.config, n.info, "cannot infer the concept parameter '%s', due to a type mismatch. " & "attempt to equate '%s' and '%s'.", [inferred.renderTree, $res.typ, $typ.base]) @@ -1820,7 +1831,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = let verdict = semConstExpr(c, n[i]) if verdict.intVal == 0: - localError(result.info, "concept predicate failed") + localError(c.config, result.info, "concept predicate failed") of tyUnknown: continue else: discard if n.sons[i].typ == enforceVoidContext: #or usesResult(n.sons[i]): @@ -1841,7 +1852,7 @@ proc semStmtList(c: PContext, n: PNode, flags: TExprFlags): PNode = case n.sons[j].kind of nkPragma, nkCommentStmt, nkNilLit, nkEmpty, nkBlockExpr, nkBlockStmt, nkState: discard - else: localError(n.sons[j].info, errStmtInvalidAfterReturn) + else: localError(c.config, n.sons[j].info, "unreachable statement after 'return'") else: discard if result.len == 1 and diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim index 454dadec0..352bc5c6b 100644 --- a/compiler/semtempl.nim +++ b/compiler/semtempl.nim @@ -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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 537319d66..8b5c26f99 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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 diff --git a/compiler/semtypinst.nim b/compiler/semtypinst.nim index c97c1186e..61d92bb19 100644 --- a/compiler/semtypinst.nim +++ b/compiler/semtypinst.nim @@ -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) diff --git a/compiler/service.nim b/compiler/service.nim index 6ec9b9046..f1a988ae5 100644 --- a/compiler/service.nim +++ b/compiler/service.nim @@ -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() diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 55d83d990..41cac2a4a 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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: diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 555ec9867..23aecfa71 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -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) diff --git a/compiler/syntaxes.nim b/compiler/syntaxes.nim index 974df50fb..4bc153e46 100644 --- a/compiler/syntaxes.nim +++ b/compiler/syntaxes.nim @@ -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) diff --git a/compiler/transf.nim b/compiler/transf.nim index 75c7f2b6c..c2add13ff 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -19,9 +19,10 @@ # * transforms 'defer' into a 'try finally' statement import - intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os, lookups, + intsets, strutils, options, ast, astalgo, trees, treetab, msgs, lookups, idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread, - lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters + lambdalifting, sempass2, lowerings, destroyer, liftlocals, closureiters, + 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,48 +970,50 @@ template liftDefer(c, root) = if c.deferDetected: liftDeferAux(root) -proc transformBody*(module: PSym, features: set[Feature], n: PNode, prc: PSym): PNode = - result = n - if nfTransf notin n.flags and prc.kind notin {skTemplate}: - var c = openTransf(module, "") - result = liftLambdas(features, prc, result, c.tooEarly) +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(g, module, "") + result = liftLambdas(g, prc, n, c.tooEarly) + #result = n result = processTransf(c, result, prc) liftDefer(c, result) - - when useEffectSystem: trackProc(prc, result) - result = liftLocalsIfRequested(prc, result) + #result = liftLambdas(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) - if prc.isIterator and oldIterTransf notin features: - result = transformClosureIterator(prc, result) + if prc.isIterator and oldIterTransf notin g.config.features: + result = g.transformClosureIterator(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) diff --git a/compiler/types.nim b/compiler/types.nim index b9b6ab33c..b5f4fbf54 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -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) diff --git a/compiler/typesrenderer.nim b/compiler/typesrenderer.nim index 4a9b8d1a9..4d75d5d05 100644 --- a/compiler/typesrenderer.nim +++ b/compiler/typesrenderer.nim @@ -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`. diff --git a/compiler/vm.nim b/compiler/vm.nim index 27135d2e7..dcb4cefd7 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -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 ouf 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 diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index b0a559d2c..e10a62006 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -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 diff --git a/compiler/vmdeps.nim b/compiler/vmdeps.nim index ba37237e8..2c92348a6 100644 --- a/compiler/vmdeps.nim +++ b/compiler/vmdeps.nim @@ -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) diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 7f91e63db..7ac3b5cf7 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -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 diff --git a/compiler/vmmarshal.nim b/compiler/vmmarshal.nim index d76909443..f38be7c29 100644 --- a/compiler/vmmarshal.nim +++ b/compiler/vmmarshal.nim @@ -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) diff --git a/compiler/vmops.nim b/compiler/vmops.nim index 7f8bf06c1..617295b0d 100644 --- a/compiler/vmops.nim +++ b/compiler/vmops.nim @@ -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 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) {.nimcall.} = - setResult a, gProjectPath + proc getProjectPathWrapper(a: VmArgs) = + setResult a, c.config.projectPath -proc registerAdditionalOps*(c: PCtx) = wrap1f_math(sqrt) wrap1f_math(ln) wrap1f_math(log10) diff --git a/compiler/writetracking.nim b/compiler/writetracking.nim index e03d6fb59..c0f7b7b20 100644 --- a/compiler/writetracking.nim +++ b/compiler/writetracking.nim @@ -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) |