mirror of
https://github.com/nim-lang/Nim.git
synced 2026-05-15 17:54:26 +00:00
Merge branch 'devel' of https://github.com/nim-lang/Nim into fix_2753
This commit is contained in:
@@ -74,6 +74,7 @@
|
||||
deprecated.
|
||||
- The `terminal` module now exports additional procs for generating ANSI color
|
||||
codes as strings.
|
||||
- Added the parameter ``val`` for the ``CritBitTree[int].inc`` proc.
|
||||
|
||||
### Language additions
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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, ~" ")
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
proc int64Literal(i: BiggestInt): Rope =
|
||||
if i > low(int64):
|
||||
result = rfmt(nil, "IL64($1)", rope(i))
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
@@ -26,12 +26,12 @@ proc intLiteral(i: BiggestInt): Rope =
|
||||
# Nim has the same bug for the same reasons :-)
|
||||
result = ~"(-2147483647 -1)"
|
||||
elif i > low(int64):
|
||||
result = rfmt(nil, "IL64($1)", rope(i))
|
||||
result = "IL64($1)" % [rope(i)]
|
||||
else:
|
||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||
|
||||
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
|
||||
if ty == nil: internalError(p.config, n.info, "genLiteral: ty is nil")
|
||||
case n.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case skipTypes(ty, abstractVarRange).kind
|
||||
@@ -76,7 +76,7 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||
of nkFloat32Lit:
|
||||
result = rope(n.floatVal.toStrMaxPrecision("f"))
|
||||
else:
|
||||
internalError(n.info, "genLiteral(" & $n.kind & ')')
|
||||
internalError(p.config, n.info, "genLiteral(" & $n.kind & ')')
|
||||
result = nil
|
||||
|
||||
proc genLiteral(p: BProc, n: PNode): Rope =
|
||||
@@ -145,7 +145,7 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||
of tyVar, tyLent: result = OnUnknown
|
||||
of tyPtr: result = OnStack
|
||||
of tyRef: result = OnHeap
|
||||
else: internalError(n.info, "getStorageLoc")
|
||||
else: doAssert(false, "getStorageLoc")
|
||||
of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
|
||||
result = getStorageLoc(n.sons[0])
|
||||
else: result = OnUnknown
|
||||
@@ -164,7 +164,7 @@ proc canMove(n: PNode): bool =
|
||||
# result = false
|
||||
|
||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
if dest.storage == OnStack or not usesNativeGC():
|
||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||
elif dest.storage == OnHeap:
|
||||
# location is on heap
|
||||
@@ -256,7 +256,7 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
# (for objects, etc.):
|
||||
if needToCopy notin flags or
|
||||
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
|
||||
if dest.storage == OnStack or not usesNativeGC():
|
||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
||||
useStringh(p.module)
|
||||
linefmt(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
@@ -290,7 +290,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode):
|
||||
genRefAssign(p, dest, src, flags)
|
||||
else:
|
||||
if dest.storage == OnStack or not usesNativeGC():
|
||||
if dest.storage == OnStack or not usesNativeGC(p.config):
|
||||
linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc)
|
||||
elif dest.storage == OnHeap:
|
||||
# we use a temporary to care for the dreaded self assignment:
|
||||
@@ -326,7 +326,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
elif needsComplexAssignment(ty):
|
||||
if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
|
||||
discard getTypeDesc(p.module, ty)
|
||||
internalAssert ty.n != nil
|
||||
internalAssert p.config, ty.n != nil
|
||||
genOptAsgnObject(p, dest, src, flags, ty.n, ty)
|
||||
else:
|
||||
genGenericAsgn(p, dest, src, flags)
|
||||
@@ -363,7 +363,7 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
of tyPtr, tyPointer, tyChar, tyBool, tyEnum, tyCString,
|
||||
tyInt..tyUInt64, tyRange, tyVar, tyLent:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||
else: internalError("genAssignment: " & $ty.kind)
|
||||
else: internalError(p.config, "genAssignment: " & $ty.kind)
|
||||
|
||||
if optMemTracker in p.options and dest.storage in {OnHeap, OnUnknown}:
|
||||
#writeStackTrace()
|
||||
@@ -409,7 +409,7 @@ proc genDeepCopy(p: BProc; dest, src: TLoc) =
|
||||
of tyPointer, tyChar, tyBool, tyEnum, tyCString,
|
||||
tyInt..tyUInt64, tyRange, tyVar, tyLent:
|
||||
linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
|
||||
else: internalError("genDeepCopy: " & $ty.kind)
|
||||
else: internalError(p.config, "genDeepCopy: " & $ty.kind)
|
||||
|
||||
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
|
||||
if d.k != locNone:
|
||||
@@ -450,14 +450,14 @@ proc putIntoDest(p: BProc, d: var TLoc, n: PNode, r: Rope; s=OnUnknown) =
|
||||
|
||||
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
var a, b: TLoc
|
||||
if d.k != locNone: internalError(e.info, "binaryStmt")
|
||||
if d.k != locNone: internalError(p.config, e.info, "binaryStmt")
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b))
|
||||
|
||||
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
|
||||
var a: TLoc
|
||||
if d.k != locNone: internalError(e.info, "unaryStmt")
|
||||
if d.k != locNone: internalError(p.config, e.info, "unaryStmt")
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
lineCg(p, cpsStmts, frmt, [rdLoc(a)])
|
||||
|
||||
@@ -701,7 +701,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
|
||||
of tyPtr:
|
||||
d.storage = OnUnknown # BUGFIX!
|
||||
else:
|
||||
internalError(e.info, "genDeref " & $typ.kind)
|
||||
internalError(p.config, e.info, "genDeref " & $typ.kind)
|
||||
elif p.module.compileToCpp:
|
||||
if typ.kind == tyVar and tfVarIsPtr notin typ.flags and
|
||||
e.kind == nkHiddenDeref:
|
||||
@@ -736,7 +736,7 @@ template inheritLocation(d: var TLoc, a: TLoc) =
|
||||
|
||||
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc) =
|
||||
initLocExpr(p, e.sons[0], a)
|
||||
if e.sons[1].kind != nkSym: internalError(e.info, "genRecordFieldAux")
|
||||
if e.sons[1].kind != nkSym: internalError(p.config, e.info, "genRecordFieldAux")
|
||||
d.inheritLocation(a)
|
||||
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
|
||||
|
||||
@@ -752,7 +752,7 @@ proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
|
||||
var r = rdLoc(a)
|
||||
case e.sons[1].kind
|
||||
of nkIntLit..nkUInt64Lit: i = int(e.sons[1].intVal)
|
||||
else: internalError(e.info, "genTupleElem")
|
||||
else: internalError(p.config, e.info, "genTupleElem")
|
||||
addf(r, ".Field$1", [rope(i)])
|
||||
putIntoDest(p, d, e, r, a.storage)
|
||||
|
||||
@@ -769,7 +769,7 @@ proc lookupFieldAgain(p: BProc, ty: PType; field: PSym; r: var Rope;
|
||||
break
|
||||
if not p.module.compileToCpp: add(r, ".Sup")
|
||||
ty = ty.sons[0]
|
||||
if result == nil: internalError(field.info, "genCheckedRecordField")
|
||||
if result == nil: internalError(p.config, field.info, "genCheckedRecordField")
|
||||
|
||||
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
@@ -786,7 +786,7 @@ proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
var rtyp: PType
|
||||
let field = lookupFieldAgain(p, ty, f, r, addr rtyp)
|
||||
if field.loc.r == nil and rtyp != nil: fillObjectFields(p.module, rtyp)
|
||||
if field.loc.r == nil: internalError(e.info, "genRecordField 3 " & typeToString(ty))
|
||||
if field.loc.r == nil: internalError(p.config, e.info, "genRecordField 3 " & typeToString(ty))
|
||||
addf(r, ".$1", [field.loc.r])
|
||||
putIntoDest(p, d, e, r, a.storage)
|
||||
|
||||
@@ -832,9 +832,9 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||
let field = lookupFieldAgain(p, ty, f, r)
|
||||
if field.loc.r == nil: fillObjectFields(p.module, ty)
|
||||
if field.loc.r == nil:
|
||||
internalError(e.info, "genCheckedRecordField") # generate the checks:
|
||||
internalError(p.config, e.info, "genCheckedRecordField") # generate the checks:
|
||||
genFieldCheck(p, e, r, field)
|
||||
add(r, rfmt(nil, ".$1", field.loc.r))
|
||||
add(r, ropecg(p.module, ".$1", field.loc.r))
|
||||
putIntoDest(p, d, e.sons[0], r, a.storage)
|
||||
else:
|
||||
genRecordField(p, e.sons[0], d)
|
||||
@@ -859,10 +859,10 @@ proc genArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
else:
|
||||
let idx = getOrdValue(y)
|
||||
if idx < firstOrd(ty) or idx > lastOrd(ty):
|
||||
localError(x.info, errIndexOutOfBounds)
|
||||
localError(p.config, x.info, "index out of bounds")
|
||||
d.inheritLocation(a)
|
||||
putIntoDest(p, d, n,
|
||||
rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
|
||||
ropecg(p.module, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first), a.storage)
|
||||
|
||||
proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
@@ -871,7 +871,7 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
var ty = skipTypes(a.t, abstractVarRange)
|
||||
inheritLocation(d, a)
|
||||
putIntoDest(p, d, n,
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
|
||||
proc genIndexCheck(p: BProc; arr, idx: TLoc) =
|
||||
let ty = skipTypes(arr.t, abstractVarRange)
|
||||
@@ -899,7 +899,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
|
||||
inheritLocation(d, a)
|
||||
putIntoDest(p, d, n,
|
||||
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
ropecg(p.module, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
|
||||
proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
@@ -919,9 +919,9 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) =
|
||||
rdLoc(b), rdLoc(a), lenField(p))
|
||||
if d.k == locNone: d.storage = OnHeap
|
||||
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
|
||||
a.r = rfmt(nil, "(*$1)", a.r)
|
||||
a.r = ropecg(p.module, "(*$1)", a.r)
|
||||
putIntoDest(p, d, n,
|
||||
rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
ropecg(p.module, "$1->data[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
|
||||
|
||||
proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
var ty = skipTypes(n.sons[0].typ, abstractVarRange + tyUserTypeClasses)
|
||||
@@ -932,7 +932,7 @@ proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
|
||||
of tySequence, tyString: genSeqElem(p, n, n.sons[0], n.sons[1], d)
|
||||
of tyCString: genCStringElem(p, n, n.sons[0], n.sons[1], d)
|
||||
of tyTuple: genTupleElem(p, n, d)
|
||||
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
|
||||
|
||||
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
# how to generate code?
|
||||
@@ -977,7 +977,7 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
proc genEcho(p: BProc, n: PNode) =
|
||||
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
|
||||
# is threadsafe.
|
||||
internalAssert n.kind == nkBracket
|
||||
internalAssert p.config, n.kind == nkBracket
|
||||
if platform.targetOS == osGenode:
|
||||
# bypass libc and print directly to the Genode LOG session
|
||||
var args: Rope = nil
|
||||
@@ -1003,8 +1003,8 @@ proc genEcho(p: BProc, n: PNode) =
|
||||
makeCString(repeat("%s", n.len) & tnl), args)
|
||||
linefmt(p, cpsStmts, "fflush(stdout);$n")
|
||||
|
||||
proc gcUsage(n: PNode) =
|
||||
if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
|
||||
proc gcUsage(conf: ConfigRef; n: PNode) =
|
||||
if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree)
|
||||
|
||||
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||
# <Nim code>
|
||||
@@ -1033,20 +1033,20 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e.sons[i + 1], a)
|
||||
if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar:
|
||||
inc(L)
|
||||
add(appends, rfmt(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
|
||||
add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a)))
|
||||
else:
|
||||
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
|
||||
inc(L, len(e.sons[i + 1].strVal))
|
||||
else:
|
||||
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
|
||||
add(appends, rfmt(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
||||
add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a)))
|
||||
linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L))
|
||||
add(p.s(cpsStmts), appends)
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
else:
|
||||
genAssignment(p, d, tmp, {}) # no need for deep copying
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
# <Nim code>
|
||||
@@ -1071,19 +1071,19 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLocExpr(p, e.sons[i + 2], a)
|
||||
if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar:
|
||||
inc(L)
|
||||
add(appends, rfmt(p.module, "#appendChar($1, $2);$n",
|
||||
add(appends, ropecg(p.module, "#appendChar($1, $2);$n",
|
||||
rdLoc(dest), rdLoc(a)))
|
||||
else:
|
||||
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
|
||||
inc(L, len(e.sons[i + 2].strVal))
|
||||
else:
|
||||
addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)])
|
||||
add(appends, rfmt(p.module, "#appendString($1, $2);$n",
|
||||
add(appends, ropecg(p.module, "#appendString($1, $2);$n",
|
||||
rdLoc(dest), rdLoc(a)))
|
||||
linefmt(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
|
||||
rdLoc(dest), lens, rope(L))
|
||||
add(p.s(cpsStmts), appends)
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
# seq &= x -->
|
||||
@@ -1106,9 +1106,9 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
initLoc(dest, locExpr, e.sons[2], OnHeap)
|
||||
getIntTemp(p, tmpL)
|
||||
lineCg(p, cpsStmts, "$1 = $2->$3++;$n", tmpL.r, rdLoc(a), lenField(p))
|
||||
dest.r = rfmt(nil, "$1->data[$2]", rdLoc(a), tmpL.r)
|
||||
dest.r = ropecg(p.module, "$1->data[$2]", rdLoc(a), tmpL.r)
|
||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genReset(p: BProc, n: PNode) =
|
||||
var a: TLoc
|
||||
@@ -1131,7 +1131,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||
let args = [getTypeDesc(p.module, typ),
|
||||
genTypeInfo(p.module, typ, a.lode.info),
|
||||
sizeExpr]
|
||||
if a.storage == OnHeap and usesNativeGC():
|
||||
if a.storage == OnHeap and usesNativeGC(p.config):
|
||||
# use newObjRC1 as an optimization
|
||||
if canFormAcycle(a.t):
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc)
|
||||
@@ -1154,7 +1154,7 @@ proc genNew(p: BProc, e: PNode) =
|
||||
rawGenNew(p, a, se.rdLoc)
|
||||
else:
|
||||
rawGenNew(p, a, nil)
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
||||
let seqtype = skipTypes(dest.t, abstractVarRange)
|
||||
@@ -1162,7 +1162,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope) =
|
||||
genTypeInfo(p.module, seqtype, dest.lode.info), length]
|
||||
var call: TLoc
|
||||
initLoc(call, locExpr, dest.lode, OnHeap)
|
||||
if dest.storage == OnHeap and usesNativeGC():
|
||||
if dest.storage == OnHeap and usesNativeGC(p.config):
|
||||
if canFormAcycle(dest.t):
|
||||
linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc)
|
||||
else:
|
||||
@@ -1178,7 +1178,7 @@ proc genNewSeq(p: BProc, e: PNode) =
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
genNewSeqAux(p, a, b.rdLoc)
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
let seqtype = skipTypes(e.typ, abstractVarRange)
|
||||
@@ -1188,7 +1188,7 @@ proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) =
|
||||
"($1)#nimNewSeqOfCap($2, $3)", [
|
||||
getTypeDesc(p.module, seqtype),
|
||||
genTypeInfo(p.module, seqtype, e.info), a.rdLoc]))
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genConstExpr(p: BProc, n: PNode): Rope
|
||||
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
|
||||
@@ -1230,7 +1230,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
rawGenNew(p, tmp, nil)
|
||||
t = t.lastSon.skipTypes(abstractInst)
|
||||
r = "(*$1)" % [r]
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
else:
|
||||
constructLoc(p, tmp)
|
||||
else:
|
||||
@@ -1244,7 +1244,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
tmp2.r = r
|
||||
let field = lookupFieldAgain(p, ty, it.sons[0].sym, tmp2.r)
|
||||
if field.loc.r == nil: fillObjectFields(p.module, ty)
|
||||
if field.loc.r == nil: internalError(e.info, "genObjConstr")
|
||||
if field.loc.r == nil: internalError(p.config, e.info, "genObjConstr")
|
||||
if it.len == 3 and optFieldCheck in p.options:
|
||||
genFieldCheck(p, it.sons[2], r, field)
|
||||
add(tmp2.r, ".")
|
||||
@@ -1280,10 +1280,10 @@ proc genSeqConstr(p: BProc, n: PNode, d: var TLoc) =
|
||||
genNewSeqAux(p, dest[], intLiteral(sonsLen(n)))
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
initLoc(arr, locExpr, n[i], OnHeap)
|
||||
arr.r = rfmt(nil, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
|
||||
arr.r = ropecg(p.module, "$1->data[$2]", rdLoc(dest[]), intLiteral(i))
|
||||
arr.storage = OnHeap # we know that sequences are on the heap
|
||||
expr(p, n[i], arr)
|
||||
gcUsage(n)
|
||||
gcUsage(p.config, n)
|
||||
if doesAlias:
|
||||
if d.k == locNone:
|
||||
d = tmp
|
||||
@@ -1306,21 +1306,21 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
|
||||
if L < 10:
|
||||
for i in countup(0, L - 1):
|
||||
initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
|
||||
elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), intLiteral(i))
|
||||
elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), intLiteral(i))
|
||||
elem.storage = OnHeap # we know that sequences are on the heap
|
||||
initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
|
||||
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), intLiteral(i))
|
||||
arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), intLiteral(i))
|
||||
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
||||
else:
|
||||
var i: TLoc
|
||||
getTemp(p, getSysType(tyInt), i)
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i)
|
||||
let oldCode = p.s(cpsStmts)
|
||||
linefmt(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", i.r, L.rope)
|
||||
initLoc(elem, locExpr, lodeTyp elemType(skipTypes(n.typ, abstractInst)), OnHeap)
|
||||
elem.r = rfmt(nil, "$1->data[$2]", rdLoc(d), rdLoc(i))
|
||||
elem.r = ropecg(p.module, "$1->data[$2]", rdLoc(d), rdLoc(i))
|
||||
elem.storage = OnHeap # we know that sequences are on the heap
|
||||
initLoc(arr, locExpr, lodeTyp elemType(skipTypes(n.sons[1].typ, abstractInst)), a.storage)
|
||||
arr.r = rfmt(nil, "$1[$2]", rdLoc(a), rdLoc(i))
|
||||
arr.r = ropecg(p.module, "$1[$2]", rdLoc(a), rdLoc(i))
|
||||
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
|
||||
@@ -1342,7 +1342,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
genAssignment(p, a, b, {}) # set the object type:
|
||||
bt = skipTypes(refType.lastSon, abstractRange)
|
||||
genObjectInit(p, cpsStmts, bt, a, false)
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
||||
# unfortunately 'genTypeInfo' sets tfObjHasKids as a side effect, so we
|
||||
@@ -1356,10 +1356,10 @@ proc genOfHelper(p: BProc; dest: PType; a: Rope; info: TLineInfo): Rope =
|
||||
inc p.module.labels
|
||||
let cache = "Nim_OfCheck_CACHE" & p.module.labels.rope
|
||||
addf(p.module.s[cfsVars], "static TNimType* $#[2];$n", [cache])
|
||||
result = rfmt(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
|
||||
result = ropecg(p.module, "#isObjWithCache($#.m_type, $#, $#)", a, ti, cache)
|
||||
when false:
|
||||
# former version:
|
||||
result = rfmt(p.module, "#isObj($1.m_type, $2)",
|
||||
result = ropecg(p.module, "#isObj($1.m_type, $2)",
|
||||
a, genTypeInfo(p.module, dest, info))
|
||||
|
||||
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
@@ -1372,7 +1372,7 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
while t.kind in {tyVar, tyLent, tyPtr, tyRef}:
|
||||
if t.kind notin {tyVar, tyLent}: nilCheck = r
|
||||
if t.kind notin {tyVar, tyLent} or not p.module.compileToCpp:
|
||||
r = rfmt(nil, "(*$1)", r)
|
||||
r = ropecg(p.module, "(*$1)", r)
|
||||
t = skipTypes(t.lastSon, typedescInst)
|
||||
discard getTypeDesc(p.module, t)
|
||||
if not p.module.compileToCpp:
|
||||
@@ -1380,12 +1380,12 @@ proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
|
||||
add(r, ~".Sup")
|
||||
t = skipTypes(t.sons[0], skipPtrs)
|
||||
if isObjLackingTypeField(t):
|
||||
globalError(x.info, errGenerated,
|
||||
globalError(p.config, x.info,
|
||||
"no 'of' operator available for pure objects")
|
||||
if nilCheck != nil:
|
||||
r = rfmt(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
|
||||
r = ropecg(p.module, "(($1) && ($2))", nilCheck, genOfHelper(p, dest, r, x.info))
|
||||
else:
|
||||
r = rfmt(p.module, "($1)", genOfHelper(p, dest, r, x.info))
|
||||
r = ropecg(p.module, "($1)", genOfHelper(p, dest, r, x.info))
|
||||
putIntoDest(p, d, x, r, a.storage)
|
||||
|
||||
proc genOf(p: BProc, n: PNode, d: var TLoc) =
|
||||
@@ -1425,7 +1425,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
of tyArray:
|
||||
putIntoDest(p, b, e,
|
||||
"$1, $2" % [rdLoc(a), rope(lengthOrd(a.t))], a.storage)
|
||||
else: internalError(e.sons[0].info, "genRepr()")
|
||||
else: internalError(p.config, e.sons[0].info, "genRepr()")
|
||||
putIntoDest(p, d, e,
|
||||
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
|
||||
genTypeInfo(p.module, elemType(t), e.info)]), a.storage)
|
||||
@@ -1434,12 +1434,12 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
ropecg(p.module, "#reprAny($1, $2)", [
|
||||
rdLoc(a), genTypeInfo(p.module, t, e.info)]), a.storage)
|
||||
of tyEmpty, tyVoid:
|
||||
localError(e.info, "'repr' doesn't support 'void' type")
|
||||
localError(p.config, e.info, "'repr' doesn't support 'void' type")
|
||||
else:
|
||||
putIntoDest(p, d, e, ropecg(p.module, "#reprAny($1, $2)",
|
||||
[addrLoc(a), genTypeInfo(p.module, t, e.info)]),
|
||||
a.storage)
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
|
||||
let t = e.sons[1].typ
|
||||
@@ -1451,7 +1451,7 @@ proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
|
||||
a.r = ropecg(p.module, frmt, [rdLoc(a)])
|
||||
if d.k == locNone: getTemp(p, n.typ, d)
|
||||
genAssignment(p, d, a, {})
|
||||
gcUsage(n)
|
||||
gcUsage(p.config, n)
|
||||
|
||||
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
var a = e.sons[1]
|
||||
@@ -1493,7 +1493,7 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
# YYY: length(sideeffect) is optimized away incorrectly?
|
||||
if op == mHigh: putIntoDest(p, d, e, rope(lastOrd(typ)))
|
||||
else: putIntoDest(p, d, e, rope(lengthOrd(typ)))
|
||||
else: internalError(e.info, "genArrayLen()")
|
||||
else: internalError(p.config, e.info, "genArrayLen()")
|
||||
|
||||
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a, b: TLoc
|
||||
@@ -1511,11 +1511,11 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
|
||||
lineCg(p, cpsStmts, setLenPattern, [
|
||||
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
|
||||
genTypeInfo(p.module, t.skipTypes(abstractInst), e.info)])
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
|
||||
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
|
||||
gcUsage(e)
|
||||
gcUsage(p.config, e)
|
||||
|
||||
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
|
||||
# swap(a, b) -->
|
||||
@@ -1541,7 +1541,7 @@ proc rdSetElemLoc(a: TLoc, setType: PType): Rope =
|
||||
proc fewCmps(s: PNode): bool =
|
||||
# this function estimates whether it is better to emit code
|
||||
# for constructing the set or generating a bunch of comparisons directly
|
||||
if s.kind != nkCurly: internalError(s.info, "fewCmps")
|
||||
if s.kind != nkCurly: return false
|
||||
if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
|
||||
result = false # it is better to emit the set generation code
|
||||
elif elemType(s.typ).kind in {tyInt, tyInt16..tyInt64}:
|
||||
@@ -1637,17 +1637,17 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)")
|
||||
of mInSet:
|
||||
genInOp(p, e, d)
|
||||
else: internalError(e.info, "genSetOp()")
|
||||
else: internalError(p.config, e.info, "genSetOp()")
|
||||
else:
|
||||
case op
|
||||
of mIncl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] |=(1U<<($2&7U));$n")
|
||||
of mExcl: binaryStmtInExcl(p, e, d, "$1[(NU)($2)>>3] &= ~(1U<<($2&7U));$n")
|
||||
of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')')
|
||||
of mLtSet, mLeSet:
|
||||
getTemp(p, getSysType(tyInt), i) # our counter
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
if d.k == locNone: getTemp(p, getSysType(tyBool), d)
|
||||
if d.k == locNone: getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyBool), d)
|
||||
lineF(p, cpsStmts, lookupOpr[op],
|
||||
[rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
|
||||
of mEqSet:
|
||||
@@ -1655,7 +1655,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
|
||||
of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
|
||||
# we inline the simple for loop for better code generation:
|
||||
getTemp(p, getSysType(tyInt), i) # our counter
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), i) # our counter
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
if d.k == locNone: getTemp(p, a.t, d)
|
||||
@@ -1665,7 +1665,7 @@ proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
rdLoc(i), rope(size), rdLoc(d), rdLoc(a), rdLoc(b),
|
||||
rope(lookupOpr[op])])
|
||||
of mInSet: genInOp(p, e, d)
|
||||
else: internalError(e.info, "genSetOp")
|
||||
else: internalError(p.config, e.info, "genSetOp")
|
||||
|
||||
proc genOrd(p: BProc, e: PNode, d: var TLoc) =
|
||||
unaryExprChar(p, e, d, "$1")
|
||||
@@ -1753,7 +1753,7 @@ proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
|
||||
putIntoDest(p, d, n,
|
||||
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]),
|
||||
a.storage)
|
||||
gcUsage(n)
|
||||
gcUsage(p.config, n)
|
||||
|
||||
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
||||
var x: TLoc
|
||||
@@ -1762,11 +1762,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
|
||||
if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "":
|
||||
initLocExpr(p, e.sons[2], x)
|
||||
putIntoDest(p, d, e,
|
||||
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "":
|
||||
initLocExpr(p, e.sons[1], x)
|
||||
putIntoDest(p, d, e,
|
||||
rfmt(nil, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p)))
|
||||
else:
|
||||
binaryExpr(p, e, d, "#eqStrings($1, $2)")
|
||||
|
||||
@@ -1778,7 +1778,7 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
assert(e.sons[2].typ != nil)
|
||||
initLocExpr(p, e.sons[1], a)
|
||||
initLocExpr(p, e.sons[2], b)
|
||||
putIntoDest(p, d, e, rfmt(nil, "(($4)($2) $1 ($4)($3))",
|
||||
putIntoDest(p, d, e, ropecg(p.module, "(($4)($2) $1 ($4)($3))",
|
||||
rope(opr[m]), rdLoc(a), rdLoc(b),
|
||||
getSimpleTypeDesc(p.module, e[1].typ)))
|
||||
if optNaNCheck in p.options:
|
||||
@@ -1887,12 +1887,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
of mEcho: genEcho(p, e[1].skipConv)
|
||||
of mArrToSeq: genArrToSeq(p, e, d)
|
||||
of mNLen..mNError, mSlurp..mQuoteAst:
|
||||
localError(e.info, errXMustBeCompileTime, e.sons[0].sym.name.s)
|
||||
localError(p.config, e.info, strutils.`%`(errXMustBeCompileTime, e.sons[0].sym.name.s))
|
||||
of mSpawn:
|
||||
let n = lowerings.wrapProcForSpawn(p.module.module, e, e.typ, nil, nil)
|
||||
let n = lowerings.wrapProcForSpawn(p.module.g.graph, p.module.module, e, e.typ, nil, nil)
|
||||
expr(p, n, d)
|
||||
of mParallel:
|
||||
let n = semparallel.liftParallel(p.module.module, e)
|
||||
let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
|
||||
expr(p, n, d)
|
||||
of mDeepCopy:
|
||||
var a, b: TLoc
|
||||
@@ -1904,7 +1904,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
|
||||
else:
|
||||
when defined(debugMagics):
|
||||
echo p.prc.name.s, " ", p.prc.id, " ", p.prc.flags, " ", p.prc.ast[genericParamsPos].kind
|
||||
internalError(e.info, "genMagicExpr: " & $op)
|
||||
internalError(p.config, e.info, "genMagicExpr: " & $op)
|
||||
|
||||
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
# example: { a..b, c, d, e, f..g }
|
||||
@@ -1924,7 +1924,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
[rdLoc(d), getTypeDesc(p.module, e.typ)])
|
||||
for it in e.sons:
|
||||
if it.kind == nkRange:
|
||||
getTemp(p, getSysType(tyInt), idx) # our counter
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
initLocExpr(p, it.sons[1], b)
|
||||
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
|
||||
@@ -1940,7 +1940,7 @@ proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
|
||||
lineF(p, cpsStmts, "$1 = 0;$n", [rdLoc(d)])
|
||||
for it in e.sons:
|
||||
if it.kind == nkRange:
|
||||
getTemp(p, getSysType(tyInt), idx) # our counter
|
||||
getTemp(p, getSysType(p.module.g.graph, unknownLineInfo(), tyInt), idx) # our counter
|
||||
initLocExpr(p, it.sons[0], a)
|
||||
initLocExpr(p, it.sons[1], b)
|
||||
lineF(p, cpsStmts, "for ($1 = $3; $1 <= $4; $1++) $n" &
|
||||
@@ -1984,7 +1984,7 @@ proc genClosure(p: BProc, n: PNode, d: var TLoc) =
|
||||
initLocExpr(p, n.sons[0], a)
|
||||
initLocExpr(p, n.sons[1], b)
|
||||
if n.sons[0].skipConv.kind == nkClosure:
|
||||
internalError(n.info, "closure to closure created")
|
||||
internalError(p.config, n.info, "closure to closure created")
|
||||
# tasyncawait.nim breaks with this optimization:
|
||||
when false:
|
||||
if d.k != locNone:
|
||||
@@ -2025,7 +2025,7 @@ template genStmtListExprImpl(exprOrStmt) {.dirty.} =
|
||||
let theMacro = it[0].sym
|
||||
add p.s(cpsStmts), initFrameNoDebug(p, frameName,
|
||||
makeCString theMacro.name.s,
|
||||
theMacro.info.quotedFilename, it.info.line.int)
|
||||
quotedFilename(p.config, theMacro.info), it.info.line.int)
|
||||
else:
|
||||
genStmts(p, it)
|
||||
if n.len > 0: exprOrStmt
|
||||
@@ -2146,11 +2146,11 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
#if sym.kind == skIterator:
|
||||
# echo renderTree(sym.getBody, {renderIds})
|
||||
if sfCompileTime in sym.flags:
|
||||
localError(n.info, "request to generate code for .compileTime proc: " &
|
||||
localError(p.config, n.info, "request to generate code for .compileTime proc: " &
|
||||
sym.name.s)
|
||||
genProc(p.module, sym)
|
||||
if sym.loc.r == nil or sym.loc.lode == nil:
|
||||
internalError(n.info, "expr: proc not init " & sym.name.s)
|
||||
internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skConst:
|
||||
if isSimpleConst(sym.typ):
|
||||
@@ -2168,10 +2168,10 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
#echo renderTree(p.prc.ast, {renderIds})
|
||||
internalError n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
||||
internalError p.config, n.info, "expr: var not init " & sym.name.s & "_" & $sym.id
|
||||
if sfThread in sym.flags:
|
||||
accessThreadLocalVar(p, sym)
|
||||
if emulatedThreadVars():
|
||||
if emulatedThreadVars(p.config):
|
||||
putIntoDest(p, d, sym.loc.lode, "NimTV_->" & sym.loc.r)
|
||||
else:
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
@@ -2181,16 +2181,16 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
#echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
#echo renderTree(p.prc.ast, {renderIds})
|
||||
internalError(n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
|
||||
internalError(p.config, n.info, "expr: temp not init " & sym.name.s & "_" & $sym.id)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of skParam:
|
||||
if sym.loc.r == nil or sym.loc.t == nil:
|
||||
# echo "FAILED FOR PRCO ", p.prc.name.s
|
||||
# debug p.prc.typ.n
|
||||
# echo renderTree(p.prc.ast, {renderIds})
|
||||
internalError(n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||
internalError(p.config, n.info, "expr: param not init " & sym.name.s & "_" & $sym.id)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
else: internalError(n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||
else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
|
||||
of nkNilLit:
|
||||
if not isEmptyType(n.typ):
|
||||
putIntoDest(p, d, n, genLiteral(p, n))
|
||||
@@ -2259,7 +2259,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
var sym = n.sons[namePos].sym
|
||||
genProc(p.module, sym)
|
||||
if sym.loc.r == nil or sym.loc.lode == nil:
|
||||
internalError(n.info, "expr: proc not init " & sym.name.s)
|
||||
internalError(p.config, n.info, "expr: proc not init " & sym.name.s)
|
||||
putLocIntoDest(p, d, sym.loc)
|
||||
of nkClosure: genClosure(p, n, d)
|
||||
|
||||
@@ -2267,7 +2267,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
of nkWhileStmt: genWhileStmt(p, n)
|
||||
of nkVarSection, nkLetSection: genVarStmt(p, n)
|
||||
of nkConstSection: discard # consts generated lazily on use
|
||||
of nkForStmt: internalError(n.info, "for statement not eliminated")
|
||||
of nkForStmt: internalError(p.config, n.info, "for statement not eliminated")
|
||||
of nkCaseStmt: genCase(p, n, d)
|
||||
of nkReturnStmt: genReturnStmt(p, n)
|
||||
of nkBreakStmt: genBreakStmt(p, n)
|
||||
@@ -2295,7 +2295,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
initLocExpr(p, ex, a)
|
||||
of nkAsmStmt: genAsmStmt(p, n)
|
||||
of nkTryStmt:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
|
||||
genTryCpp(p, n, d)
|
||||
else:
|
||||
genTry(p, n, d)
|
||||
@@ -2327,7 +2327,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
|
||||
of nkState: genState(p, n)
|
||||
of nkGotoState: genGotoState(p, n)
|
||||
of nkBreakState: genBreakState(p, n)
|
||||
else: internalError(n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||
else: internalError(p.config, n.info, "expr(" & $n.kind & "); unknown node kind")
|
||||
|
||||
proc genNamedConstExpr(p: BProc, n: PNode): Rope =
|
||||
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
|
||||
@@ -2363,7 +2363,7 @@ proc getDefaultValue(p: BProc; typ: PType; info: TLineInfo): Rope =
|
||||
if mapType(t) == ctArray: result = rope"{}"
|
||||
else: result = rope"0"
|
||||
else:
|
||||
globalError(info, "cannot create null element for: " & $t.kind)
|
||||
globalError(p.config, info, "cannot create null element for: " & $t.kind)
|
||||
|
||||
proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; count: var int) =
|
||||
case obj.kind
|
||||
@@ -2389,7 +2389,7 @@ proc getNullValueAux(p: BProc; t: PType; obj, cons: PNode, result: var Rope; cou
|
||||
# not found, produce default value:
|
||||
result.add getDefaultValue(p, field.typ, cons.info)
|
||||
else:
|
||||
localError(cons.info, "cannot create null element for: " & $obj)
|
||||
localError(p.config, cons.info, "cannot create null element for: " & $obj)
|
||||
|
||||
proc getNullValueAuxT(p: BProc; orig, t: PType; obj, cons: PNode, result: var Rope; count: var int) =
|
||||
var base = t.sons[0]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -16,7 +16,7 @@ const
|
||||
# above X strings a hash-switch for strings is generated
|
||||
|
||||
proc registerGcRoot(p: BProc, v: PSym) =
|
||||
if gSelectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
|
||||
if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and
|
||||
containsGarbageCollectedRef(v.loc.t):
|
||||
# we register a specialized marked proc here; this has the advantage
|
||||
# that it works out of the box for thread local storage then :-)
|
||||
@@ -43,13 +43,13 @@ proc inExceptBlockLen(p: BProc): int =
|
||||
|
||||
proc genVarTuple(p: BProc, n: PNode) =
|
||||
var tup, field: TLoc
|
||||
if n.kind != nkVarTuple: internalError(n.info, "genVarTuple")
|
||||
if n.kind != nkVarTuple: internalError(p.config, n.info, "genVarTuple")
|
||||
var L = sonsLen(n)
|
||||
|
||||
# if we have a something that's been captured, use the lowering instead:
|
||||
for i in countup(0, L-3):
|
||||
if n[i].kind != nkSym:
|
||||
genStmts(p, lowerTupleUnpacking(n, p.prc))
|
||||
genStmts(p, lowerTupleUnpacking(p.module.g.graph, n, p.prc))
|
||||
return
|
||||
|
||||
genLineDir(p, n)
|
||||
@@ -70,7 +70,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
if t.kind == tyTuple:
|
||||
field.r = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||
else:
|
||||
if t.n.sons[i].kind != nkSym: internalError(n.info, "genVarTuple")
|
||||
if t.n.sons[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
|
||||
field.r = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n.sons[i].sym, t)]
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
|
||||
@@ -125,7 +125,7 @@ proc endBlock(p: BProc, blockEnd: Rope) =
|
||||
proc endBlock(p: BProc) =
|
||||
let topBlock = p.blocks.len - 1
|
||||
var blockEnd = if p.blocks[topBlock].label != nil:
|
||||
rfmt(nil, "} $1: ;$n", p.blocks[topBlock].label)
|
||||
ropecg(p.module, "} $1: ;$n", p.blocks[topBlock].label)
|
||||
else:
|
||||
~"}$n"
|
||||
let frameLen = p.blocks[topBlock].frameLen
|
||||
@@ -149,7 +149,7 @@ template preserveBreakIdx(body: untyped): untyped =
|
||||
p.breakIdx = oldBreakIdx
|
||||
|
||||
proc genState(p: BProc, n: PNode) =
|
||||
internalAssert n.len == 1
|
||||
internalAssert p.config, n.len == 1
|
||||
let n0 = n[0]
|
||||
if n0.kind == nkIntLit:
|
||||
let idx = n.sons[0].intVal
|
||||
@@ -191,7 +191,7 @@ proc genBreakState(p: BProc, n: PNode) =
|
||||
|
||||
proc genGotoVar(p: BProc; value: PNode) =
|
||||
if value.kind notin {nkCharLit..nkUInt64Lit}:
|
||||
localError(value.info, "'goto' target must be a literal value")
|
||||
localError(p.config, value.info, "'goto' target must be a literal value")
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
||||
|
||||
@@ -325,7 +325,7 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
startBlock(p)
|
||||
expr(p, it.sons[0], d)
|
||||
endBlock(p)
|
||||
else: internalError(n.info, "genIf()")
|
||||
else: internalError(p.config, n.info, "genIf()")
|
||||
if sonsLen(n) > 1: fixLabel(p, lend)
|
||||
|
||||
|
||||
@@ -337,7 +337,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
|
||||
for i in countup(1, howManyTrys):
|
||||
let tryStmt = p.nestedTryStmts.pop
|
||||
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
|
||||
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
|
||||
# Pop safe points generated by try
|
||||
if not tryStmt.inExcept:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n")
|
||||
@@ -356,7 +356,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
for i in countdown(howManyTrys-1, 0):
|
||||
p.nestedTryStmts.add(stack[i])
|
||||
|
||||
if not p.module.compileToCpp or optNoCppExceptions in gGlobalOptions:
|
||||
if not p.module.compileToCpp or optNoCppExceptions in p.config.globalOptions:
|
||||
# Pop exceptions that was handled by the
|
||||
# except-blocks we are in
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
@@ -383,7 +383,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
let it = caseStmt.sons[i]
|
||||
for j in 0 .. it.len-2:
|
||||
if it.sons[j].kind == nkRange:
|
||||
localError(it.info, "range notation not available for computed goto")
|
||||
localError(p.config, it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
|
||||
@@ -398,19 +398,19 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
let it = n.sons[i]
|
||||
if it.kind == nkCaseStmt:
|
||||
if lastSon(it).kind != nkOfBranch:
|
||||
localError(it.info,
|
||||
localError(p.config, it.info,
|
||||
"case statement must be exhaustive for computed goto"); return
|
||||
casePos = i
|
||||
let aSize = lengthOrd(it.sons[0].typ)
|
||||
if aSize > 10_000:
|
||||
localError(it.info,
|
||||
localError(p.config, it.info,
|
||||
"case statement has too many cases for computed goto"); return
|
||||
arraySize = aSize.int
|
||||
if firstOrd(it.sons[0].typ) != 0:
|
||||
localError(it.info,
|
||||
localError(p.config, it.info,
|
||||
"case statement has to start at 0 for computed goto"); return
|
||||
if casePos < 0:
|
||||
localError(n.info, "no case statement found for computed goto"); return
|
||||
localError(p.config, n.info, "no case statement found for computed goto"); return
|
||||
var id = p.labels+1
|
||||
inc p.labels, arraySize+1
|
||||
let tmp = "TMP$1_" % [id.rope]
|
||||
@@ -444,7 +444,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
let it = caseStmt.sons[i]
|
||||
for j in 0 .. it.len-2:
|
||||
if it.sons[j].kind == nkRange:
|
||||
localError(it.info, "range notation not available for computed goto")
|
||||
localError(p.config, it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it.sons[j])
|
||||
lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
|
||||
@@ -548,7 +548,7 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||
# an unnamed 'break' can only break a loop after 'transf' pass:
|
||||
while idx >= 0 and not p.blocks[idx].isLoop: dec idx
|
||||
if idx < 0 or not p.blocks[idx].isLoop:
|
||||
internalError(t.info, "no loop to break")
|
||||
internalError(p.config, t.info, "no loop to break")
|
||||
let label = assignLabel(p.blocks[idx])
|
||||
blockLeaveActions(p,
|
||||
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
|
||||
@@ -571,7 +571,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
var e = rdLoc(a)
|
||||
var typ = skipTypes(t[0].typ, abstractPtrs)
|
||||
genLineDir(p, t)
|
||||
if isImportedException(typ):
|
||||
if isImportedException(typ, p.config):
|
||||
lineF(p, cpsStmts, "throw $1;$n", [e])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "#raiseException((#Exception*)$1, $2);$n",
|
||||
@@ -579,7 +579,7 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
# reraise the last exception:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin gGlobalOptions:
|
||||
if p.module.compileToCpp and optNoCppExceptions notin p.config.globalOptions:
|
||||
line(p, cpsStmts, ~"throw;$n")
|
||||
else:
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n")
|
||||
@@ -876,17 +876,14 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
|
||||
p.module.includeHeader("<setjmp.h>")
|
||||
genLineDir(p, t)
|
||||
var safePoint = getTempName(p.module)
|
||||
if getCompilerProc("Exception") != nil:
|
||||
discard cgsym(p.module, "Exception")
|
||||
else:
|
||||
discard cgsym(p.module, "E_Base")
|
||||
discard cgsym(p.module, "Exception")
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", safePoint)
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", safePoint)
|
||||
if isDefined("nimStdSetjmp"):
|
||||
if isDefined(p.config, "nimStdSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
elif isDefined("nimSigSetjmp"):
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", safePoint)
|
||||
elif isDefined("nimRawSetjmp"):
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", safePoint)
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", safePoint)
|
||||
@@ -1013,7 +1010,7 @@ proc genEmit(p: BProc, t: PNode) =
|
||||
if p.prc == nil:
|
||||
# top level emit pragma?
|
||||
let section = determineSection(t[1])
|
||||
genCLineDir(p.module.s[section], t.info)
|
||||
genCLineDir(p.module.s[section], t.info, p.config)
|
||||
add(p.module.s[section], s)
|
||||
else:
|
||||
genLineDir(p, t)
|
||||
@@ -1139,4 +1136,4 @@ proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) =
|
||||
proc genStmts(p: BProc, t: PNode) =
|
||||
var a: TLoc
|
||||
expr(p, t, a)
|
||||
internalAssert a.k in {locNone, locTemp, locLocalVar}
|
||||
internalAssert p.config, a.k in {locNone, locTemp, locLocalVar}
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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() =
|
||||
|
||||
@@ -19,6 +19,7 @@ import
|
||||
import strutils except `%` # collides with ropes.`%`
|
||||
|
||||
from modulegraphs import ModuleGraph
|
||||
from configuration import warnGcMem, errXMustBeCompileTime, hintDependency, errGenerated
|
||||
import dynlib
|
||||
|
||||
when not declared(dynlib.libCandidates):
|
||||
@@ -92,6 +93,7 @@ proc useHeader(m: BModule, sym: PSym) =
|
||||
proc cgsym(m: BModule, name: string): Rope
|
||||
|
||||
proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
assert m != nil
|
||||
var i = 0
|
||||
var length = len(frmt)
|
||||
result = nil
|
||||
@@ -115,15 +117,15 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
if i >= length or not (frmt[i] in {'0'..'9'}): break
|
||||
num = j
|
||||
if j > high(args) + 1:
|
||||
internalError("ropes: invalid format string $" & $j)
|
||||
internalError(m.config, "ropes: invalid format string $" & $j)
|
||||
add(result, args[j-1])
|
||||
of 'n':
|
||||
if optLineDir notin gOptions: add(result, rnl)
|
||||
if optLineDir notin m.config.options: add(result, rnl)
|
||||
inc(i)
|
||||
of 'N':
|
||||
add(result, rnl)
|
||||
inc(i)
|
||||
else: internalError("ropes: invalid format string $" & frmt[i])
|
||||
else: internalError(m.config, "ropes: invalid format string $" & frmt[i])
|
||||
elif frmt[i] == '#' and frmt[i+1] in IdentStartChars:
|
||||
inc(i)
|
||||
var j = i
|
||||
@@ -145,15 +147,10 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
if i - 1 >= start:
|
||||
add(result, substr(frmt, start, i - 1))
|
||||
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
||||
ropecg(m, fmt, args)
|
||||
|
||||
var indent = "\t".rope
|
||||
|
||||
proc indentLine(p: BProc, r: Rope): Rope =
|
||||
result = r
|
||||
for i in countup(0, p.blocks.len-1):
|
||||
prepend(result, indent)
|
||||
prepend(result, "\t".rope)
|
||||
|
||||
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
@@ -189,14 +186,14 @@ proc safeLineNm(info: TLineInfo): int =
|
||||
result = toLinenumber(info)
|
||||
if result < 0: result = 0 # negative numbers are not allowed in #line
|
||||
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int) =
|
||||
proc genCLineDir(r: var Rope, filename: string, line: int; conf: ConfigRef) =
|
||||
assert line >= 0
|
||||
if optLineDir in gOptions:
|
||||
if optLineDir in conf.options:
|
||||
addf(r, "$N#line $2 $1$N",
|
||||
[rope(makeSingleLineCString(filename)), rope(line)])
|
||||
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo) =
|
||||
genCLineDir(r, info.toFullPath, info.safeLineNm)
|
||||
proc genCLineDir(r: var Rope, info: TLineInfo; conf: ConfigRef) =
|
||||
genCLineDir(r, info.toFullPath, info.safeLineNm, conf)
|
||||
|
||||
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
|
||||
if p.lastLineInfo.line != info.line or
|
||||
@@ -213,9 +210,9 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
tt = tt.sons[1]
|
||||
let line = tt.info.safeLineNm
|
||||
|
||||
if optEmbedOrigSrc in gGlobalOptions:
|
||||
add(p.s(cpsStmts), ~"//" & tt.info.sourceLine & rnl)
|
||||
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line)
|
||||
if optEmbedOrigSrc in p.config.globalOptions:
|
||||
add(p.s(cpsStmts), ~"//" & sourceLine(p.config, tt.info) & rnl)
|
||||
genCLineDir(p.s(cpsStmts), tt.info.toFullPath, line, p.config)
|
||||
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
|
||||
(p.prc == nil or sfPure notin p.prc.flags):
|
||||
if freshLineInfo(p, tt.info):
|
||||
@@ -226,17 +223,17 @@ proc genLineDir(p: BProc, t: PNode) =
|
||||
(p.prc == nil or sfPure notin p.prc.flags) and tt.info.fileIndex != InvalidFileIDX:
|
||||
if freshLineInfo(p, tt.info):
|
||||
linefmt(p, cpsStmts, "nimln_($1, $2);$n",
|
||||
line.rope, tt.info.quotedFilename)
|
||||
line.rope, quotedFilename(p.config, tt.info))
|
||||
|
||||
proc postStmtActions(p: BProc) {.inline.} =
|
||||
add(p.s(cpsStmts), p.module.injectStmt)
|
||||
|
||||
proc accessThreadLocalVar(p: BProc, s: PSym)
|
||||
proc emulatedThreadVars(): bool {.inline.}
|
||||
proc emulatedThreadVars(conf: ConfigRef): bool {.inline.}
|
||||
proc genProc(m: BModule, prc: PSym)
|
||||
|
||||
template compileToCpp(m: BModule): untyped =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||
m.config.cmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||
|
||||
proc getTempName(m: BModule): Rope =
|
||||
result = m.tmpBase & rope(m.labels)
|
||||
@@ -265,7 +262,7 @@ proc rdCharLoc(a: TLoc): Rope =
|
||||
|
||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
takeAddr: bool) =
|
||||
if p.module.compileToCpp and t.isException and not isDefined("noCppExceptions"):
|
||||
if p.module.compileToCpp and t.isException and not isDefined(p.config, "noCppExceptions"):
|
||||
# init vtable in Exception object for polymorphic exceptions
|
||||
includeHeader(p.module, "<new>")
|
||||
linefmt(p, section, "new ($1) $2;$n", rdLoc(a), getTypeDesc(p.module, t))
|
||||
@@ -373,7 +370,7 @@ proc getIntTemp(p: BProc, result: var TLoc) =
|
||||
linefmt(p, cpsLocals, "NI $1;$n", result.r)
|
||||
result.k = locTemp
|
||||
result.storage = OnStack
|
||||
result.lode = lodeTyp getSysType(tyInt)
|
||||
result.lode = lodeTyp getSysType(p.module.g.graph, unknownLineInfo(), tyInt)
|
||||
result.flags = {}
|
||||
|
||||
proc initGCFrame(p: BProc): Rope =
|
||||
@@ -417,7 +414,7 @@ proc assignLocalVar(p: BProc, n: PNode) =
|
||||
#assert(s.loc.k == locNone) # not yet assigned
|
||||
# this need not be fulfilled for inline procs; they are regenerated
|
||||
# for each module that uses them!
|
||||
let nl = if optLineDir in gOptions: "" else: tnl
|
||||
let nl = if optLineDir in p.config.options: "" else: tnl
|
||||
let decl = localVarDecl(p, n) & ";" & nl
|
||||
line(p, cpsLocals, decl)
|
||||
localDebugInfo(p, n.sym)
|
||||
@@ -511,24 +508,24 @@ proc initFrame(p: BProc, procname, filename: Rope): Rope =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
if p.maxFrameLen > 0:
|
||||
discard cgsym(p.module, "VarSlot")
|
||||
result = rfmt(nil, "\tnimfrs_($1, $2, $3, $4);$n",
|
||||
result = ropecg(p.module, "\tnimfrs_($1, $2, $3, $4);$n",
|
||||
procname, filename, p.maxFrameLen.rope,
|
||||
p.blocks[0].frameLen.rope)
|
||||
else:
|
||||
result = rfmt(nil, "\tnimfr_($1, $2);$n", procname, filename)
|
||||
result = ropecg(p.module, "\tnimfr_($1, $2);$n", procname, filename)
|
||||
|
||||
proc initFrameNoDebug(p: BProc; frame, procname, filename: Rope; line: int): Rope =
|
||||
discard cgsym(p.module, "nimFrame")
|
||||
addf(p.blocks[0].sections[cpsLocals], "TFrame $1;$n", [frame])
|
||||
result = rfmt(nil, "\t$1.procname = $2; $1.filename = $3; " &
|
||||
result = ropecg(p.module, "\t$1.procname = $2; $1.filename = $3; " &
|
||||
" $1.line = $4; $1.len = -1; nimFrame(&$1);$n",
|
||||
frame, procname, filename, rope(line))
|
||||
|
||||
proc deinitFrameNoDebug(p: BProc; frame: Rope): Rope =
|
||||
result = rfmt(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
|
||||
result = ropecg(p.module, "\t#popFrameOfAddr(&$1);$n", frame)
|
||||
|
||||
proc deinitFrame(p: BProc): Rope =
|
||||
result = rfmt(p.module, "\t#popFrame();$n")
|
||||
result = ropecg(p.module, "\t#popFrame();$n")
|
||||
|
||||
include ccgexprs
|
||||
|
||||
@@ -551,7 +548,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
if lib.path.kind in {nkStrLit..nkTripleStrLit}:
|
||||
var s: TStringSeq = @[]
|
||||
libCandidates(lib.path.strVal, s)
|
||||
rawMessage(hintDependency, lib.path.strVal)
|
||||
rawMessage(m.config, hintDependency, lib.path.strVal)
|
||||
var loadlib: Rope = nil
|
||||
for i in countup(0, high(s)):
|
||||
inc(m.labels)
|
||||
@@ -575,7 +572,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||
"if (!($1 = #nimLoadLibrary($2))) #nimLoadLibraryError($2);$n",
|
||||
[tmp, rdLoc(dest)])
|
||||
|
||||
if lib.name == nil: internalError("loadDynamicLib")
|
||||
if lib.name == nil: internalError(m.config, "loadDynamicLib")
|
||||
|
||||
proc mangleDynLibProc(sym: PSym): Rope =
|
||||
if sfCompilerProc in sym.flags:
|
||||
@@ -606,14 +603,14 @@ proc symInDynamicLib(m: BModule, sym: PSym) =
|
||||
[tmp, getTypeDesc(m, sym.typ), params, makeCString($extname)]
|
||||
var last = lastSon(n)
|
||||
if last.kind == nkHiddenStdConv: last = last.sons[1]
|
||||
internalAssert(last.kind == nkStrLit)
|
||||
internalAssert(m.config, last.kind == nkStrLit)
|
||||
let idx = last.strVal
|
||||
if idx.len == 0:
|
||||
add(m.initProc.s(cpsStmts), load)
|
||||
elif idx.len == 1 and idx[0] in {'0'..'9'}:
|
||||
add(m.extensionLoaders[idx[0]], load)
|
||||
else:
|
||||
internalError(sym.info, "wrong index: " & idx)
|
||||
internalError(m.config, sym.info, "wrong index: " & idx)
|
||||
else:
|
||||
appcg(m, m.s[cfsDynLibInit],
|
||||
"\t$1 = ($2) #nimGetProcAddr($3, $4);$n",
|
||||
@@ -639,18 +636,18 @@ proc symInDynamicLibPartial(m: BModule, sym: PSym) =
|
||||
sym.typ.sym = nil # generate a new name
|
||||
|
||||
proc cgsym(m: BModule, name: string): Rope =
|
||||
let sym = magicsys.getCompilerProc(name)
|
||||
let sym = magicsys.getCompilerProc(m.g.graph, name)
|
||||
if sym != nil:
|
||||
case sym.kind
|
||||
of skProc, skFunc, skMethod, skConverter, skIterator: genProc(m, sym)
|
||||
of skVar, skResult, skLet: genVarPrototype(m, newSymNode sym)
|
||||
of skType: discard getTypeDesc(m, sym.typ)
|
||||
else: internalError("cgsym: " & name & ": " & $sym.kind)
|
||||
else: internalError(m.config, "cgsym: " & name & ": " & $sym.kind)
|
||||
else:
|
||||
# we used to exclude the system module from this check, but for DLL
|
||||
# generation support this sloppyness leads to hard to detect bugs, so
|
||||
# we're picky here for the system module too:
|
||||
rawMessage(errSystemNeeds, name)
|
||||
rawMessage(m.config, errGenerated, "system module needs: " & name)
|
||||
result = sym.loc.r
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
@@ -687,7 +684,7 @@ proc closureSetup(p: BProc, prc: PSym) =
|
||||
# prc.ast[paramsPos].last contains the type we're after:
|
||||
var ls = lastSon(prc.ast[paramsPos])
|
||||
if ls.kind != nkSym:
|
||||
internalError(prc.info, "closure generation failed")
|
||||
internalError(p.config, prc.info, "closure generation failed")
|
||||
var env = ls.sym
|
||||
#echo "created environment: ", env.id, " for ", prc.name.s
|
||||
assignLocalVar(p, ls)
|
||||
@@ -727,7 +724,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
assert(prc.ast != nil)
|
||||
if sfPure notin prc.flags and prc.typ.sons[0] != nil:
|
||||
if resultPos >= prc.ast.len:
|
||||
internalError(prc.info, "proc has no result symbol")
|
||||
internalError(m.config, prc.info, "proc has no result symbol")
|
||||
let resNode = prc.ast.sons[resultPos]
|
||||
let res = resNode.sym # get result symbol
|
||||
if not isInvalidReturnType(prc.typ.sons[0]):
|
||||
@@ -742,7 +739,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
assignLocalVar(p, resNode)
|
||||
assert(res.loc.r != nil)
|
||||
initLocalVar(p, res, immediateAsgn=false)
|
||||
returnStmt = rfmt(nil, "\treturn $1;$n", rdLoc(res.loc))
|
||||
returnStmt = ropecg(p.module, "\treturn $1;$n", rdLoc(res.loc))
|
||||
else:
|
||||
fillResult(resNode)
|
||||
assignParam(p, res)
|
||||
@@ -764,15 +761,15 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
if sfPure in prc.flags:
|
||||
if hasDeclspec in extccomp.CC[extccomp.cCompiler].props:
|
||||
header = "__declspec(naked) " & header
|
||||
generatedProc = rfmt(nil, "$N$1 {$n$2$3$4}$N$N",
|
||||
generatedProc = ropecg(p.module, "$N$1 {$n$2$3$4}$N$N",
|
||||
header, p.s(cpsLocals), p.s(cpsInit), p.s(cpsStmts))
|
||||
else:
|
||||
generatedProc = rfmt(nil, "$N$1 {$N", header)
|
||||
generatedProc = ropecg(p.module, "$N$1 {$N", header)
|
||||
add(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
var procname = makeCString(prc.name.s)
|
||||
add(generatedProc, initFrame(p, procname, prc.info.quotedFilename))
|
||||
add(generatedProc, initFrame(p, procname, quotedFilename(p.config, prc.info)))
|
||||
else:
|
||||
add(generatedProc, p.s(cpsLocals))
|
||||
if optProfiler in prc.options:
|
||||
@@ -791,10 +788,10 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
proc requiresExternC(m: BModule; sym: PSym): bool {.inline.} =
|
||||
result = (sfCompileToCpp in m.module.flags and
|
||||
sfCompileToCpp notin sym.getModule().flags and
|
||||
gCmd != cmdCompileToCpp) or (
|
||||
m.config.cmd != cmdCompileToCpp) or (
|
||||
sym.flags * {sfImportc, sfInfixCall, sfCompilerProc} == {sfImportc} and
|
||||
sym.magic == mNone and
|
||||
gCmd == cmdCompileToCpp)
|
||||
m.config.cmd == cmdCompileToCpp)
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
@@ -802,7 +799,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
if lfDynamicLib in sym.loc.flags:
|
||||
if getModule(sym).id != m.module.id and
|
||||
not containsOrIncl(m.declaredThings, sym.id):
|
||||
add(m.s[cfsVars], rfmt(nil, "extern $1 $2;$n",
|
||||
add(m.s[cfsVars], ropecg(m, "extern $1 $2;$n",
|
||||
getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)))
|
||||
elif not containsOrIncl(m.declaredProtos, sym.id):
|
||||
var header = genProcHeader(m, sym)
|
||||
@@ -814,7 +811,7 @@ proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
header.add(" __attribute__((naked))")
|
||||
if sfNoReturn in sym.flags and hasAttribute in CC[cCompiler].props:
|
||||
header.add(" __attribute__((noreturn))")
|
||||
add(m.s[cfsProcHeaders], rfmt(nil, "$1;$n", header))
|
||||
add(m.s[cfsProcHeaders], ropecg(m, "$1;$n", header))
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
if lfImportCompilerProc in prc.loc.flags:
|
||||
@@ -920,14 +917,14 @@ proc genVarPrototype(m: BModule, n: PNode) =
|
||||
if sfVolatile in sym.flags: add(m.s[cfsVars], " volatile")
|
||||
addf(m.s[cfsVars], " $1;$n", [sym.loc.r])
|
||||
|
||||
proc addIntTypes(result: var Rope) {.inline.} =
|
||||
proc addIntTypes(result: var Rope; conf: ConfigRef) {.inline.} =
|
||||
addf(result, "#define NIM_NEW_MANGLING_RULES" & tnl &
|
||||
"#define NIM_INTBITS $1" & tnl, [
|
||||
platform.CPU[targetCPU].intSize.rope])
|
||||
if useNimNamespace : result.add("#define USE_NIM_NAMESPACE" & tnl)
|
||||
if optUseNimNamespace in conf.globalOptions: result.add("#define USE_NIM_NAMESPACE" & tnl)
|
||||
|
||||
proc getCopyright(cfile: Cfile): Rope =
|
||||
if optCompileOnly in gGlobalOptions:
|
||||
proc getCopyright(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
if optCompileOnly in conf.globalOptions:
|
||||
result = ("/* Generated by Nim Compiler v$1 */$N" &
|
||||
"/* (c) " & copyrightYear & " Andreas Rumpf */$N" &
|
||||
"/* The generated code is subject to the original license. */$N") %
|
||||
@@ -942,11 +939,11 @@ proc getCopyright(cfile: Cfile): Rope =
|
||||
rope(platform.OS[targetOS].name),
|
||||
rope(platform.CPU[targetCPU].name),
|
||||
rope(extccomp.CC[extccomp.cCompiler].name),
|
||||
rope(getCompileCFileCmd(cfile))]
|
||||
rope(getCompileCFileCmd(conf, cfile))]
|
||||
|
||||
proc getFileHeader(cfile: Cfile): Rope =
|
||||
result = getCopyright(cfile)
|
||||
addIntTypes(result)
|
||||
proc getFileHeader(conf: ConfigRef; cfile: Cfile): Rope =
|
||||
result = getCopyright(conf, cfile)
|
||||
addIntTypes(result, conf)
|
||||
|
||||
proc genFilenames(m: BModule): Rope =
|
||||
discard cgsym(m, "dbgRegisterFilename")
|
||||
@@ -1051,8 +1048,8 @@ proc genMainProc(m: BModule) =
|
||||
|
||||
var nimMain, otherMain: FormatStr
|
||||
if platform.targetOS == osWindows and
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in gGlobalOptions:
|
||||
m.config.globalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in m.config.globalOptions:
|
||||
nimMain = WinNimMain
|
||||
otherMain = WinCMain
|
||||
else:
|
||||
@@ -1062,7 +1059,7 @@ proc genMainProc(m: BModule) =
|
||||
elif platform.targetOS == osGenode:
|
||||
nimMain = GenodeNimMain
|
||||
otherMain = ComponentConstruct
|
||||
elif optGenDynLib in gGlobalOptions:
|
||||
elif optGenDynLib in m.config.globalOptions:
|
||||
nimMain = PosixNimDllMain
|
||||
otherMain = PosixCDllMain
|
||||
elif platform.targetOS == osStandalone:
|
||||
@@ -1072,16 +1069,16 @@ proc genMainProc(m: BModule) =
|
||||
nimMain = PosixNimMain
|
||||
otherMain = PosixCMain
|
||||
if m.g.breakpoints != nil: discard cgsym(m, "dbgRegisterBreakpoint")
|
||||
if optEndb in gOptions:
|
||||
if optEndb in m.config.options:
|
||||
m.g.breakpoints.add(m.genFilenames)
|
||||
|
||||
let initStackBottomCall =
|
||||
if platform.targetOS == osStandalone or gSelectedGC == gcNone: "".rope
|
||||
if platform.targetOS == osStandalone or m.config.selectedGC == gcNone: "".rope
|
||||
else: ropecg(m, "\t#initStackBottomWith((void *)&inner);$N")
|
||||
inc(m.labels)
|
||||
appcg(m, m.s[cfsProcs], PreMainBody, [
|
||||
m.g.mainDatInit, m.g.breakpoints, m.g.otherModsInit,
|
||||
if emulatedThreadVars() and platform.targetOS != osStandalone:
|
||||
if emulatedThreadVars(m.config) and platform.targetOS != osStandalone:
|
||||
ropecg(m, "\t#initThreadVarsEmulation();$N")
|
||||
else:
|
||||
"".rope,
|
||||
@@ -1089,12 +1086,12 @@ proc genMainProc(m: BModule) =
|
||||
|
||||
appcg(m, m.s[cfsProcs], nimMain,
|
||||
[m.g.mainModInit, initStackBottomCall, rope(m.labels)])
|
||||
if optNoMain notin gGlobalOptions:
|
||||
if useNimNamespace:
|
||||
if optNoMain notin m.config.globalOptions:
|
||||
if optUseNimNamespace in m.config.globalOptions:
|
||||
m.s[cfsProcs].add closeNamespaceNim() & "using namespace Nim;" & tnl
|
||||
|
||||
appcg(m, m.s[cfsProcs], otherMain, [])
|
||||
if useNimNamespace: m.s[cfsProcs].add openNamespaceNim()
|
||||
if optUseNimNamespace in m.config.globalOptions: m.s[cfsProcs].add openNamespaceNim()
|
||||
|
||||
proc getSomeInitName(m: PSym, suffix: string): Rope =
|
||||
assert m.kind == skModule
|
||||
@@ -1118,8 +1115,8 @@ proc registerModuleToMain(g: BModuleList; m: PSym) =
|
||||
var
|
||||
init = m.getInitName
|
||||
datInit = m.getDatInitName
|
||||
addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [init])
|
||||
addf(g.mainModProcs, "NIM_EXTERNC N_NOINLINE(void, $1)(void);$N", [datInit])
|
||||
addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [init])
|
||||
addf(g.mainModProcs, "N_LIB_PRIVATE N_NIMCALL(void, $1)(void);$N", [datInit])
|
||||
if sfSystemModule notin m.flags:
|
||||
addf(g.mainDatInit, "\t$1();$N", [datInit])
|
||||
let initCall = "\t$1();$N" % [init]
|
||||
@@ -1130,7 +1127,7 @@ proc registerModuleToMain(g: BModuleList; m: PSym) =
|
||||
|
||||
proc genInitCode(m: BModule) =
|
||||
var initname = getInitName(m.module)
|
||||
var prc = "NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N" % [initname]
|
||||
var prc = "N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N" % [initname]
|
||||
if m.typeNodes > 0:
|
||||
appcg(m, m.s[cfsTypeInit1], "static #TNimNode $1[$2];$n",
|
||||
[m.typeNodesName, rope(m.typeNodes)])
|
||||
@@ -1140,11 +1137,11 @@ proc genInitCode(m: BModule) =
|
||||
|
||||
add(prc, initGCFrame(m.initProc))
|
||||
|
||||
add(prc, genSectionStart(cpsLocals))
|
||||
add(prc, genSectionStart(cpsLocals, m.config))
|
||||
add(prc, m.preInitProc.s(cpsLocals))
|
||||
add(prc, m.initProc.s(cpsLocals))
|
||||
add(prc, m.postInitProc.s(cpsLocals))
|
||||
add(prc, genSectionEnd(cpsLocals))
|
||||
add(prc, genSectionEnd(cpsLocals, m.config))
|
||||
|
||||
if optStackTrace in m.initProc.options and frameDeclared notin m.flags:
|
||||
# BUT: the generated init code might depend on a current frame, so
|
||||
@@ -1152,33 +1149,33 @@ proc genInitCode(m: BModule) =
|
||||
incl m.flags, frameDeclared
|
||||
if preventStackTrace notin m.flags:
|
||||
var procname = makeCString(m.module.name.s)
|
||||
add(prc, initFrame(m.initProc, procname, m.module.info.quotedFilename))
|
||||
add(prc, initFrame(m.initProc, procname, quotedFilename(m.config, m.module.info)))
|
||||
else:
|
||||
add(prc, ~"\tTFrame FR_; FR_.len = 0;$N")
|
||||
|
||||
add(prc, genSectionStart(cpsInit))
|
||||
add(prc, genSectionStart(cpsInit, m.config))
|
||||
add(prc, m.preInitProc.s(cpsInit))
|
||||
add(prc, m.initProc.s(cpsInit))
|
||||
add(prc, m.postInitProc.s(cpsInit))
|
||||
add(prc, genSectionEnd(cpsInit))
|
||||
add(prc, genSectionEnd(cpsInit, m.config))
|
||||
|
||||
add(prc, genSectionStart(cpsStmts))
|
||||
add(prc, genSectionStart(cpsStmts, m.config))
|
||||
add(prc, m.preInitProc.s(cpsStmts))
|
||||
add(prc, m.initProc.s(cpsStmts))
|
||||
add(prc, m.postInitProc.s(cpsStmts))
|
||||
add(prc, genSectionEnd(cpsStmts))
|
||||
add(prc, genSectionEnd(cpsStmts, m.config))
|
||||
if optStackTrace in m.initProc.options and preventStackTrace notin m.flags:
|
||||
add(prc, deinitFrame(m.initProc))
|
||||
add(prc, deinitGCFrame(m.initProc))
|
||||
addf(prc, "}$N$N", [])
|
||||
|
||||
prc.addf("NIM_EXTERNC N_NOINLINE(void, $1)(void) {$N",
|
||||
prc.addf("N_LIB_PRIVATE N_NIMCALL(void, $1)(void) {$N",
|
||||
[getDatInitName(m.module)])
|
||||
|
||||
for i in cfsTypeInit1..cfsDynLibInit:
|
||||
add(prc, genSectionStart(i))
|
||||
add(prc, genSectionStart(i, m.config))
|
||||
add(prc, m.s[i])
|
||||
add(prc, genSectionEnd(i))
|
||||
add(prc, genSectionEnd(i, m.config))
|
||||
|
||||
addf(prc, "}$N$N", [])
|
||||
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
|
||||
@@ -1193,18 +1190,19 @@ proc genInitCode(m: BModule) =
|
||||
add(m.s[cfsInitProc], ex)
|
||||
|
||||
proc genModule(m: BModule, cfile: Cfile): Rope =
|
||||
result = getFileHeader(cfile)
|
||||
result = getFileHeader(m.config, cfile)
|
||||
result.add(genMergeInfo(m))
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
generateHeaders(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
add(result, genSectionStart(i))
|
||||
add(result, genSectionStart(i, m.config))
|
||||
add(result, m.s[i])
|
||||
add(result, genSectionEnd(i))
|
||||
if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
|
||||
add(result, genSectionEnd(i, m.config))
|
||||
if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders:
|
||||
result.add openNamespaceNim()
|
||||
add(result, m.s[cfsInitProc])
|
||||
if useNimNamespace: result.add closeNamespaceNim()
|
||||
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
|
||||
|
||||
proc newPreInitProc(m: BModule): BProc =
|
||||
result = newProc(nil, m)
|
||||
@@ -1217,10 +1215,12 @@ proc newPostInitProc(m: BModule): BProc =
|
||||
result.labels = 200_000
|
||||
|
||||
proc initProcOptions(m: BModule): TOptions =
|
||||
if sfSystemModule in m.module.flags: gOptions-{optStackTrace} else: gOptions
|
||||
let opts = m.config.options
|
||||
if sfSystemModule in m.module.flags: opts-{optStackTrace} else: opts
|
||||
|
||||
proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||
new(result)
|
||||
result.g = g
|
||||
result.tmpBase = rope("TM" & $hashOwner(module) & "_")
|
||||
result.headerFiles = @[]
|
||||
result.declaredThings = initIntSet()
|
||||
@@ -1241,14 +1241,13 @@ proc rawNewModule(g: BModuleList; module: PSym, filename: string): BModule =
|
||||
result.forwardedProcs = @[]
|
||||
result.typeNodesName = getTempName(result)
|
||||
result.nimTypesName = getTempName(result)
|
||||
result.g = g
|
||||
# no line tracing for the init sections of the system module so that we
|
||||
# don't generate a TFrame which can confuse the stack botton initialization:
|
||||
if sfSystemModule in module.flags:
|
||||
incl result.flags, preventStackTrace
|
||||
excl(result.preInitProc.options, optStackTrace)
|
||||
excl(result.postInitProc.options, optStackTrace)
|
||||
let ndiName = if optCDebug in gGlobalOptions: changeFileExt(completeCFilePath(filename), "ndi")
|
||||
let ndiName = if optCDebug in g.config.globalOptions: changeFileExt(completeCFilePath(g.config, filename), "ndi")
|
||||
else: ""
|
||||
open(result.ndi, ndiName)
|
||||
|
||||
@@ -1309,18 +1308,19 @@ proc newModule(g: BModuleList; module: PSym): BModule =
|
||||
growCache g.modules, module.position
|
||||
g.modules[module.position] = result
|
||||
|
||||
template injectG(config) {.dirty.} =
|
||||
template injectG() {.dirty.} =
|
||||
if graph.backend == nil:
|
||||
graph.backend = newModuleList(config)
|
||||
graph.backend = newModuleList(graph)
|
||||
let g = BModuleList(graph.backend)
|
||||
|
||||
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
||||
injectG(graph.config)
|
||||
injectG()
|
||||
result = newModule(g, module)
|
||||
if optGenIndex in gGlobalOptions and g.generatedHeader == nil:
|
||||
let f = if graph.config.headerFile.len > 0: graph.config.headerFile else: gProjectFull
|
||||
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
|
||||
let f = if graph.config.headerFile.len > 0: graph.config.headerFile
|
||||
else: graph.config.projectFull
|
||||
g.generatedHeader = rawNewModule(g, module,
|
||||
changeFileExt(completeCFilePath(f), hExt))
|
||||
changeFileExt(completeCFilePath(graph.config, f), hExt))
|
||||
incl g.generatedHeader.flags, isHeaderFile
|
||||
|
||||
proc writeHeader(m: BModule) =
|
||||
@@ -1331,43 +1331,44 @@ proc writeHeader(m: BModule) =
|
||||
|
||||
var guard = "__$1__" % [m.filename.splitFile.name.rope]
|
||||
result.addf("#ifndef $1$n#define $1$n", [guard])
|
||||
addIntTypes(result)
|
||||
addIntTypes(result, m.config)
|
||||
generateHeaders(m)
|
||||
|
||||
generateThreadLocalStorage(m)
|
||||
for i in countup(cfsHeaders, cfsProcs):
|
||||
add(result, genSectionStart(i))
|
||||
add(result, genSectionStart(i, m.config))
|
||||
add(result, m.s[i])
|
||||
add(result, genSectionEnd(i))
|
||||
if useNimNamespace and i == cfsHeaders: result.add openNamespaceNim()
|
||||
add(result, genSectionEnd(i, m.config))
|
||||
if optUseNimNamespace in m.config.globalOptions and i == cfsHeaders: result.add openNamespaceNim()
|
||||
add(result, m.s[cfsInitProc])
|
||||
|
||||
if optGenDynLib in gGlobalOptions:
|
||||
if optGenDynLib in m.config.globalOptions:
|
||||
result.add("N_LIB_IMPORT ")
|
||||
result.addf("N_CDECL(void, NimMain)(void);$n", [])
|
||||
if useNimNamespace: result.add closeNamespaceNim()
|
||||
if optUseNimNamespace in m.config.globalOptions: result.add closeNamespaceNim()
|
||||
result.addf("#endif /* $1 */$n", [guard])
|
||||
writeRope(result, m.filename)
|
||||
|
||||
proc getCFile(m: BModule): string =
|
||||
let ext =
|
||||
if m.compileToCpp: ".cpp"
|
||||
elif gCmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
|
||||
elif m.config.cmd == cmdCompileToOC or sfCompileToObjC in m.module.flags: ".m"
|
||||
else: ".c"
|
||||
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext)
|
||||
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
|
||||
|
||||
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
|
||||
injectG(graph.config)
|
||||
injectG()
|
||||
var m = newModule(g, module)
|
||||
readMergeInfo(getCFile(m), m)
|
||||
result = m
|
||||
|
||||
proc myProcess(b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
if b == nil: return
|
||||
var m = BModule(b)
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
m.initProc.options = initProcOptions(m)
|
||||
softRnl = if optLineDir in gOptions: noRnl else: rnl
|
||||
softRnl = if optLineDir in m.config.options: noRnl else: rnl
|
||||
genStmts(m.initProc, n)
|
||||
|
||||
proc finishModule(m: BModule) =
|
||||
@@ -1377,18 +1378,18 @@ proc finishModule(m: BModule) =
|
||||
# a ``for`` loop here
|
||||
var prc = m.forwardedProcs[i]
|
||||
if sfForward in prc.flags:
|
||||
internalError(prc.info, "still forwarded: " & prc.name.s)
|
||||
internalError(m.config, prc.info, "still forwarded: " & prc.name.s)
|
||||
genProcNoForward(m, prc)
|
||||
inc(i)
|
||||
assert(m.g.forwardedProcsCounter >= i)
|
||||
dec(m.g.forwardedProcsCounter, i)
|
||||
setLen(m.forwardedProcs, 0)
|
||||
|
||||
proc shouldRecompile(code: Rope, cfile: Cfile): bool =
|
||||
proc shouldRecompile(m: BModule; code: Rope, cfile: Cfile): bool =
|
||||
result = true
|
||||
if optForceFullMake notin gGlobalOptions:
|
||||
if optForceFullMake notin m.config.globalOptions:
|
||||
if not equalsFile(code, cfile.cname):
|
||||
if isDefined("nimdiff"):
|
||||
if isDefined(m.config, "nimdiff"):
|
||||
if fileExists(cfile.cname):
|
||||
copyFile(cfile.cname, cfile.cname & ".backup")
|
||||
echo "diff ", cfile.cname, ".backup ", cfile.cname
|
||||
@@ -1411,7 +1412,7 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
# generate code for the init statements of the module:
|
||||
let cfile = getCFile(m)
|
||||
|
||||
if m.rd == nil or optForceFullMake in gGlobalOptions:
|
||||
if m.rd == nil or optForceFullMake in m.config.globalOptions:
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
if sfMainModule in m.module.flags:
|
||||
@@ -1419,35 +1420,35 @@ proc writeModule(m: BModule, pending: bool) =
|
||||
add(m.s[cfsProcHeaders], m.g.mainModProcs)
|
||||
generateThreadVarsSize(m)
|
||||
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
var code = genModule(m, cf)
|
||||
when hasTinyCBackend:
|
||||
if gCmd == cmdRun:
|
||||
if conf.cmd == cmdRun:
|
||||
tccgen.compileCCode($code)
|
||||
return
|
||||
|
||||
if not shouldRecompile(code, cf): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(cf)
|
||||
if not shouldRecompile(m, code, cf): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(m.config, cf)
|
||||
elif pending and mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||
let cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
||||
let cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
mergeFiles(cfile, m)
|
||||
genInitCode(m)
|
||||
finishTypeDescriptions(m)
|
||||
var code = genModule(m, cf)
|
||||
writeRope(code, cfile)
|
||||
addFileToCompile(cf)
|
||||
addFileToCompile(m.config, cf)
|
||||
else:
|
||||
# Consider: first compilation compiles ``system.nim`` and produces
|
||||
# ``system.c`` but then compilation fails due to an error. This means
|
||||
# that ``system.o`` is missing, so we need to call the C compiler for it:
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
if not existsFile(cf.obj): cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(cf)
|
||||
addFileToCompile(m.config, cf)
|
||||
close(m.ndi)
|
||||
|
||||
proc updateCachedModule(m: BModule) =
|
||||
let cfile = getCFile(m)
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(toObjFile(cfile)), flags: {})
|
||||
var cf = Cfile(cname: cfile, obj: completeCFilePath(m.config, toObjFile(m.config, cfile)), flags: {})
|
||||
|
||||
if mergeRequired(m) and sfMainModule notin m.module.flags:
|
||||
mergeFiles(cfile, m)
|
||||
@@ -1458,12 +1459,13 @@ proc updateCachedModule(m: BModule) =
|
||||
writeRope(code, cfile)
|
||||
else:
|
||||
cf.flags = {CfileFlag.Cached}
|
||||
addFileToCompile(cf)
|
||||
addFileToCompile(m.config, cf)
|
||||
|
||||
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
|
||||
result = n
|
||||
if b == nil or passes.skipCodegen(n): return
|
||||
if b == nil: return
|
||||
var m = BModule(b)
|
||||
if passes.skipCodegen(m.config, n): return
|
||||
# if the module is cached, we don't regenerate the main proc
|
||||
# nor the dispatchers? But if the dispatchers changed?
|
||||
# XXX emit the dispatchers into its own .c file?
|
||||
@@ -1497,7 +1499,7 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
|
||||
m.updateCachedModule
|
||||
else:
|
||||
m.writeModule(pending=true)
|
||||
writeMapping(g.mapping)
|
||||
writeMapping(config, g.mapping)
|
||||
if g.generatedHeader != nil: writeHeader(g.generatedHeader)
|
||||
|
||||
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
import
|
||||
intsets, options, ast, astalgo, msgs, idents, renderer, types, magicsys,
|
||||
sempass2, strutils, modulegraphs
|
||||
sempass2, strutils, modulegraphs, configuration
|
||||
|
||||
proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
proc genConv(n: PNode, d: PType, downcast: bool; conf: ConfigRef): PNode =
|
||||
var dest = skipTypes(d, abstractPtrs)
|
||||
var source = skipTypes(n.typ, abstractPtrs)
|
||||
if (source.kind == tyObject) and (dest.kind == tyObject):
|
||||
@@ -24,12 +24,12 @@ proc genConv(n: PNode, d: PType, downcast: bool): PNode =
|
||||
elif diff < 0:
|
||||
result = newNodeIT(nkObjUpConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if downcast: internalError(n.info, "cgmeth.genConv: no upcast allowed")
|
||||
if downcast: internalError(conf, n.info, "cgmeth.genConv: no upcast allowed")
|
||||
elif diff > 0:
|
||||
result = newNodeIT(nkObjDownConv, n.info, d)
|
||||
addSon(result, n)
|
||||
if not downcast:
|
||||
internalError(n.info, "cgmeth.genConv: no downcast allowed")
|
||||
internalError(conf, n.info, "cgmeth.genConv: no downcast allowed")
|
||||
else:
|
||||
result = n
|
||||
else:
|
||||
@@ -42,7 +42,7 @@ proc getDispatcher*(s: PSym): PSym =
|
||||
let disp = dispn.sym
|
||||
if sfDispatcher in disp.flags: result = disp
|
||||
|
||||
proc methodCall*(n: PNode): PNode =
|
||||
proc methodCall*(n: PNode; conf: ConfigRef): PNode =
|
||||
result = n
|
||||
# replace ordinary method by dispatcher method:
|
||||
let disp = getDispatcher(result.sons[0].sym)
|
||||
@@ -50,9 +50,9 @@ proc methodCall*(n: PNode): PNode =
|
||||
result.sons[0].sym = disp
|
||||
# change the arguments to up/downcasts to fit the dispatcher's parameters:
|
||||
for i in countup(1, sonsLen(result)-1):
|
||||
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true)
|
||||
result.sons[i] = genConv(result.sons[i], disp.typ.sons[i], true, conf)
|
||||
else:
|
||||
localError(n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
|
||||
localError(conf, n.info, "'" & $result.sons[0] & "' lacks a dispatcher")
|
||||
|
||||
type
|
||||
MethodResult = enum No, Invalid, Yes
|
||||
@@ -130,7 +130,7 @@ proc createDispatcher(s: PSym): PSym =
|
||||
attachDispatcher(disp, newSymNode(disp))
|
||||
return disp
|
||||
|
||||
proc fixupDispatcher(meth, disp: PSym) =
|
||||
proc fixupDispatcher(meth, disp: PSym; conf: ConfigRef) =
|
||||
# We may have constructed the dispatcher from a method prototype
|
||||
# and need to augment the incomplete dispatcher with information
|
||||
# from later definitions, particularly the resultPos slot. Also,
|
||||
@@ -149,7 +149,7 @@ proc fixupDispatcher(meth, disp: PSym) =
|
||||
disp.typ.lockLevel = meth.typ.lockLevel
|
||||
elif meth.typ.lockLevel != UnspecifiedLockLevel and
|
||||
meth.typ.lockLevel != disp.typ.lockLevel:
|
||||
message(meth.info, warnLockLevel,
|
||||
message(conf, meth.info, warnLockLevel,
|
||||
"method has lock level $1, but another method has $2" %
|
||||
[$meth.typ.lockLevel, $disp.typ.lockLevel])
|
||||
# XXX The following code silences a duplicate warning in
|
||||
@@ -166,13 +166,13 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
|
||||
of Yes:
|
||||
add(g.methods[i].methods, s)
|
||||
attachDispatcher(s, lastSon(disp.ast))
|
||||
fixupDispatcher(s, disp)
|
||||
fixupDispatcher(s, disp, g.config)
|
||||
#echo "fixup ", disp.name.s, " ", disp.id
|
||||
when useEffectSystem: checkMethodEffects(disp, s)
|
||||
when useEffectSystem: checkMethodEffects(g, disp, s)
|
||||
if {sfBase, sfFromGeneric} * s.flags == {sfBase} and
|
||||
g.methods[i].methods[0] != s:
|
||||
# already exists due to forwarding definition?
|
||||
localError(s.info, "method is not a base")
|
||||
localError(g.config, s.info, "method is not a base")
|
||||
return
|
||||
of No: discard
|
||||
of Invalid:
|
||||
@@ -183,10 +183,10 @@ proc methodDef*(g: ModuleGraph; s: PSym, fromCache: bool) =
|
||||
#if fromCache:
|
||||
# internalError(s.info, "no method dispatcher found")
|
||||
if witness != nil:
|
||||
localError(s.info, "invalid declaration order; cannot attach '" & s.name.s &
|
||||
localError(g.config, s.info, "invalid declaration order; cannot attach '" & s.name.s &
|
||||
"' to method defined here: " & $witness.info)
|
||||
elif sfBase notin s.flags:
|
||||
message(s.info, warnUseBase)
|
||||
message(g.config, s.info, warnUseBase)
|
||||
|
||||
proc relevantCol(methods: TSymSeq, col: int): bool =
|
||||
# returns true iff the position is relevant
|
||||
@@ -225,32 +225,33 @@ proc sortBucket(a: var TSymSeq, relevantCols: IntSet) =
|
||||
a[j] = v
|
||||
if h == 1: break
|
||||
|
||||
proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
proc genDispatcher(g: ModuleGraph; methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
var base = lastSon(methods[0].ast).sym
|
||||
result = base
|
||||
var paramLen = sonsLen(base.typ)
|
||||
var nilchecks = newNodeI(nkStmtList, base.info)
|
||||
var disp = newNodeI(nkIfStmt, base.info)
|
||||
var ands = getSysSym("and")
|
||||
var iss = getSysSym("of")
|
||||
var ands = getSysSym(g, unknownLineInfo(), "and")
|
||||
var iss = getSysSym(g, unknownLineInfo(), "of")
|
||||
let boolType = getSysType(g, unknownLineInfo(), tyBool)
|
||||
for col in countup(1, paramLen - 1):
|
||||
if contains(relevantCols, col):
|
||||
let param = base.typ.n.sons[col].sym
|
||||
if param.typ.skipTypes(abstractInst).kind in {tyRef, tyPtr}:
|
||||
addSon(nilchecks, newTree(nkCall,
|
||||
newSymNode(getCompilerProc"chckNilDisp"), newSymNode(param)))
|
||||
newSymNode(getCompilerProc(g, "chckNilDisp")), newSymNode(param)))
|
||||
for meth in countup(0, high(methods)):
|
||||
var curr = methods[meth] # generate condition:
|
||||
var cond: PNode = nil
|
||||
for col in countup(1, paramLen - 1):
|
||||
if contains(relevantCols, col):
|
||||
var isn = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
var isn = newNodeIT(nkCall, base.info, boolType)
|
||||
addSon(isn, newSymNode(iss))
|
||||
let param = base.typ.n.sons[col].sym
|
||||
addSon(isn, newSymNode(param))
|
||||
addSon(isn, newNodeIT(nkType, base.info, curr.typ.sons[col]))
|
||||
if cond != nil:
|
||||
var a = newNodeIT(nkCall, base.info, getSysType(tyBool))
|
||||
var a = newNodeIT(nkCall, base.info, boolType)
|
||||
addSon(a, newSymNode(ands))
|
||||
addSon(a, cond)
|
||||
addSon(a, isn)
|
||||
@@ -262,7 +263,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: IntSet): PSym =
|
||||
addSon(call, newSymNode(curr))
|
||||
for col in countup(1, paramLen - 1):
|
||||
addSon(call, genConv(newSymNode(base.typ.n.sons[col].sym),
|
||||
curr.typ.sons[col], false))
|
||||
curr.typ.sons[col], false, g.config))
|
||||
var ret: PNode
|
||||
if retTyp != nil:
|
||||
var a = newNodeI(nkFastAsgn, base.info)
|
||||
@@ -290,4 +291,4 @@ proc generateMethodDispatchers*(g: ModuleGraph): PNode =
|
||||
if relevantCol(g.methods[bucket].methods, col): incl(relevantCols, col)
|
||||
sortBucket(g.methods[bucket].methods, relevantCols)
|
||||
addSon(result,
|
||||
newSymNode(genDispatcher(g.methods[bucket].methods, relevantCols)))
|
||||
newSymNode(genDispatcher(g, g.methods[bucket].methods, relevantCols)))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,77 +12,30 @@
|
||||
import
|
||||
strtabs, platform, strutils, idents
|
||||
|
||||
# We need to use a StringTableRef here as defined symbols are always guaranteed
|
||||
# to be style insensitive. Otherwise hell would break lose.
|
||||
var gSymbols: StringTableRef
|
||||
|
||||
const
|
||||
catNone = "false"
|
||||
|
||||
proc defineSymbol*(symbol: string, value: string = "true") =
|
||||
gSymbols[symbol] = value
|
||||
proc defineSymbol*(symbols: StringTableRef; symbol: string, value: string = "true") =
|
||||
symbols[symbol] = value
|
||||
|
||||
proc undefSymbol*(symbol: string) =
|
||||
gSymbols[symbol] = catNone
|
||||
proc undefSymbol*(symbols: StringTableRef; symbol: string) =
|
||||
symbols[symbol] = catNone
|
||||
|
||||
proc isDefined*(symbol: string): bool =
|
||||
if gSymbols.hasKey(symbol):
|
||||
result = gSymbols[symbol] != catNone
|
||||
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
|
||||
result = true
|
||||
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
|
||||
result = true
|
||||
else:
|
||||
case symbol.normalize
|
||||
of "x86": result = targetCPU == cpuI386
|
||||
of "itanium": result = targetCPU == cpuIa64
|
||||
of "x8664": result = targetCPU == cpuAmd64
|
||||
of "posix", "unix":
|
||||
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
|
||||
osAndroid}
|
||||
of "linux":
|
||||
result = targetOS in {osLinux, osAndroid}
|
||||
of "bsd":
|
||||
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
|
||||
of "emulatedthreadvars":
|
||||
result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
|
||||
of "msdos": result = targetOS == osDos
|
||||
of "mswindows", "win32": result = targetOS == osWindows
|
||||
of "macintosh": result = targetOS in {osMacos, osMacosx}
|
||||
of "sunos": result = targetOS == osSolaris
|
||||
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
|
||||
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
|
||||
of "cpu8": result = CPU[targetCPU].bit == 8
|
||||
of "cpu16": result = CPU[targetCPU].bit == 16
|
||||
of "cpu32": result = CPU[targetCPU].bit == 32
|
||||
of "cpu64": result = CPU[targetCPU].bit == 64
|
||||
of "nimrawsetjmp":
|
||||
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
|
||||
osDragonfly, osMacosx}
|
||||
else: discard
|
||||
#proc lookupSymbol*(symbols: StringTableRef; symbol: string): string =
|
||||
# result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||
|
||||
proc isDefined*(symbol: PIdent): bool = isDefined(symbol.s)
|
||||
|
||||
proc lookupSymbol*(symbol: string): string =
|
||||
result = if isDefined(symbol): gSymbols[symbol] else: nil
|
||||
|
||||
proc lookupSymbol*(symbol: PIdent): string = lookupSymbol(symbol.s)
|
||||
|
||||
iterator definedSymbolNames*: string =
|
||||
for key, val in pairs(gSymbols):
|
||||
iterator definedSymbolNames*(symbols: StringTableRef): string =
|
||||
for key, val in pairs(symbols):
|
||||
if val != catNone: yield key
|
||||
|
||||
proc countDefinedSymbols*(): int =
|
||||
proc countDefinedSymbols*(symbols: StringTableRef): int =
|
||||
result = 0
|
||||
for key, val in pairs(gSymbols):
|
||||
for key, val in pairs(symbols):
|
||||
if val != catNone: inc(result)
|
||||
|
||||
proc initDefines*() =
|
||||
gSymbols = newStringTable(modeStyleInsensitive)
|
||||
proc initDefines*(symbols: StringTableRef) =
|
||||
# for bootstrapping purposes and old code:
|
||||
template defineSymbol(s) = symbols.defineSymbol(s)
|
||||
defineSymbol("nimhygiene")
|
||||
defineSymbol("niminheritable")
|
||||
defineSymbol("nimmixin")
|
||||
|
||||
360
compiler/configuration.nim
Normal file
360
compiler/configuration.nim
Normal file
@@ -0,0 +1,360 @@
|
||||
#
|
||||
#
|
||||
# The Nim Compiler
|
||||
# (c) Copyright 2018 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## This module contains the rather excessive configuration object that
|
||||
## needs to be passed around to everything so that the compiler becomes
|
||||
## more useful as a library.
|
||||
|
||||
import tables
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile,
|
||||
errXExpected,
|
||||
errGridTableNotImplemented,
|
||||
errGeneralParseError,
|
||||
errNewSectionExpected,
|
||||
errInvalidDirectiveX,
|
||||
errGenerated,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
warnDeprecated, warnConfigDeprecated,
|
||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnTypelessParam,
|
||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintExecuting, hintLinking, hintDependency,
|
||||
hintSource, hintPerformance, hintStackTrace, hintGCStats,
|
||||
hintUser, hintUserRaw
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
errUnknown: "unknown error",
|
||||
errInternal: "internal error: $1",
|
||||
errIllFormedAstX: "illformed AST: $1",
|
||||
errCannotOpenFile: "cannot open '$1'",
|
||||
errXExpected: "'$1' expected",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
errNewSectionExpected: "new section expected",
|
||||
errInvalidDirectiveX: "invalid directive: '$1'",
|
||||
errGenerated: "$1",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open '$1'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
warnXIsNeverRead: "'$1' is never read",
|
||||
warnXmightNotBeenInit: "'$1' might not have been initialized",
|
||||
warnDeprecated: "$1 is deprecated",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated",
|
||||
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
|
||||
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
|
||||
warnRedefinitionOfLabel: "redefinition of label '$1'",
|
||||
warnUnknownSubstitutionX: "unknown substitution '$1'",
|
||||
warnLanguageXNotSupported: "language '$1' not supported",
|
||||
warnFieldXNotSupported: "field '$1' not supported",
|
||||
warnCommentXIgnored: "comment '$1' ignored",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||
warnWriteToForeignHeap: "write to foreign heap",
|
||||
warnUnsafeCode: "unsafe code: '$1'",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple",
|
||||
warnShadowIdent: "shadowed identifier: '$1'",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
|
||||
warnProveField: "cannot prove that field '$1' is accessible",
|
||||
warnProveIndex: "cannot prove index '$1' is valid",
|
||||
warnGcUnsafe: "not GC-safe: '$1'",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized",
|
||||
warnGcMem: "'$1' uses GC'ed memory",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
|
||||
warnLockLevel: "$1",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
||||
hintExprAlwaysX: "expression evaluates always to '$1'",
|
||||
hintQuitCalled: "quit() called",
|
||||
hintProcessing: "$1",
|
||||
hintCodeBegin: "generated code listing:",
|
||||
hintCodeEnd: "end of listing",
|
||||
hintConf: "used config file '$1'",
|
||||
hintPath: "added path: '$1'",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1'",
|
||||
hintName: "name should be: '$1'",
|
||||
hintPattern: "$1",
|
||||
hintExecuting: "$1",
|
||||
hintLinking: "",
|
||||
hintDependency: "$1",
|
||||
hintSource: "$1",
|
||||
hintPerformance: "$1",
|
||||
hintStackTrace: "$1",
|
||||
hintGCStats: "$1",
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1"]
|
||||
|
||||
const
|
||||
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored",
|
||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "User"]
|
||||
|
||||
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "Performance", "StackTrace", "GCStats",
|
||||
"User", "UserRaw"]
|
||||
|
||||
const
|
||||
fatalMin* = errUnknown
|
||||
fatalMax* = errInternal
|
||||
errMin* = errUnknown
|
||||
errMax* = errUser
|
||||
warnMin* = warnCannotOpenFile
|
||||
warnMax* = pred(hintSuccess)
|
||||
hintMin* = hintSuccess
|
||||
hintMax* = high(TMsgKind)
|
||||
|
||||
static:
|
||||
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
|
||||
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
|
||||
|
||||
type
|
||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
const
|
||||
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintSuccessX, hintPath, hintConf,
|
||||
hintProcessing, hintPattern,
|
||||
hintDependency,
|
||||
hintExecuting, hintLinking,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintPath,
|
||||
hintDependency,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
|
||||
{low(TNoteKind)..high(TNoteKind)}]
|
||||
|
||||
const
|
||||
errXMustBeCompileTime* = "'$1' can only be used in compile-time context"
|
||||
errArgsNeedRunOption* = "arguments can only be given if the '--run' option is selected"
|
||||
|
||||
#[
|
||||
errStringLiteralExpected: "string literal expected",
|
||||
errIntLiteralExpected: "integer literal expected",
|
||||
errIdentifierExpected: "identifier expected, but found '$1'",
|
||||
errNewlineExpected: "newline expected, but found '$1'",
|
||||
errInvalidModuleName: "invalid module name: '$1'",
|
||||
errOnOrOffExpected: "'on' or 'off' expected",
|
||||
errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
|
||||
errInvalidPragma: "invalid pragma",
|
||||
errUnknownPragma: "unknown pragma: '$1'",
|
||||
errAtPopWithoutPush: "'pop' without a 'push' pragma",
|
||||
errEmptyAsm: "empty asm statement",
|
||||
errInvalidIndentation: "invalid indentation",
|
||||
|
||||
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
|
||||
errAttemptToRedefine: ,
|
||||
errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
|
||||
errStmtExpected: "statement expected",
|
||||
errInvalidLabel: "'$1' is no label",
|
||||
errInvalidCmdLineOption: "invalid command line option: '$1'",
|
||||
errCmdLineArgExpected: "argument for command line option expected: '$1'",
|
||||
errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
|
||||
errInvalidVarSubstitution: "invalid variable substitution in '$1'",
|
||||
errUnknownVar: "unknown variable: '$1'",
|
||||
errUnknownCcompiler: "unknown C compiler: '$1'",
|
||||
errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
|
||||
errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
|
||||
errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
|
||||
,
|
||||
errInvalidMultipleAsgn: "multiple assignment is not allowed",
|
||||
errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
|
||||
errUndeclaredField: "undeclared field: '$1'",
|
||||
errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
|
||||
errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
|
||||
errTypeExpected: "type expected",
|
||||
errSystemNeeds: "system module needs '$1'",
|
||||
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
|
||||
errNotOverloadable: ,
|
||||
errInvalidArgForX: "invalid argument for '$1'",
|
||||
errStmtHasNoEffect: "statement has no effect",
|
||||
,
|
||||
errXExpectsArrayType: "'$1' expects an array type",
|
||||
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
|
||||
errExprXAmbiguous: "expression '$1' ambiguous in this context",
|
||||
errConstantDivisionByZero: ,
|
||||
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
|
||||
errOverOrUnderflow: ,
|
||||
errCannotEvalXBecauseIncompletelyDefined: ,
|
||||
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
|
||||
errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
|
||||
errNilAccess: "attempt to access a nil address",
|
||||
errIndexOutOfBounds: "index out of bounds",
|
||||
errIndexTypesDoNotMatch: "index types do not match",
|
||||
errBracketsInvalidForType: "'[]' operator invalid for this type",
|
||||
errValueOutOfSetBounds: "value out of set bounds",
|
||||
errFieldNotInit: "field '$1' not initialized",
|
||||
errExprXCannotBeCalled: "expression '$1' cannot be called",
|
||||
errExprHasNoType: "expression has no type",
|
||||
errExprXHasNoType:,
|
||||
errCastNotInSafeMode: "'cast' not allowed in safe mode",
|
||||
errExprCannotBeCastToX: ,
|
||||
errCommaOrParRiExpected: "',' or ')' expected",
|
||||
errCurlyLeOrParLeExpected: "'{' or '(' expected",
|
||||
errSectionExpected: "section ('type', 'proc', etc.) expected",
|
||||
errRangeExpected: "range expected",
|
||||
errMagicOnlyInSystem: "'magic' only allowed in system module",
|
||||
errPowerOfTwoExpected: "power of two expected",
|
||||
errStringMayNotBeEmpty: "string literal may not be empty",
|
||||
errCallConvExpected: "calling convention expected",
|
||||
errProcOnlyOneCallConv: "a proc can only have one calling convention",
|
||||
errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
|
||||
errExprMustBeBool: "expression must be of type 'bool'",
|
||||
errConstExprExpected: "constant expression expected",
|
||||
errDuplicateCaseLabel: "duplicate case label",
|
||||
errRangeIsEmpty: "range is empty",
|
||||
,
|
||||
errSelectorMustBeOrdinal: "selector must be of an ordinal type",
|
||||
errOrdXMustNotBeNegative: "ord($1) must not be negative",
|
||||
errLenXinvalid: "len($1) must be less than 32768",
|
||||
errTypeXhasUnknownSize: "type '$1' has unknown size",
|
||||
errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
|
||||
errConstNeedsValue: "a constant needs a value",
|
||||
errResultCannotBeOpenArray: "the result type cannot be on open array",
|
||||
errSizeTooBig: "computing the type's size produced an overflow",
|
||||
errInheritanceOnlyWithEnums: "inheritance only works with an enum",
|
||||
errIllegalRecursionInTypeX:,
|
||||
errCannotInstantiateX: "cannot instantiate: '$1'",
|
||||
errTypeMismatch: "type mismatch: got <",
|
||||
errButExpected: "but expected one of: ",
|
||||
errButExpectedX: "but expected '$1'",
|
||||
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
|
||||
errWrongNumberOfArguments: "wrong number of arguments",
|
||||
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
||||
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
||||
errXCannotBePassedToProcVar: ,
|
||||
,
|
||||
errImplOfXexpected: ,
|
||||
|
||||
errIllegalConvFromXtoY: ,
|
||||
errCannotBindXTwice: "cannot bind parameter '$1' twice",
|
||||
errInvalidOrderInArrayConstructor: ,
|
||||
errInvalidOrderInEnumX: "invalid order in enum '$1'",
|
||||
errEnumXHasHoles: "enum '$1' has holes",
|
||||
errExceptExpected: "'except' or 'finally' expected",
|
||||
errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
|
||||
errOptionExpected: ,
|
||||
errXisNoLabel: "'$1' is not a label",
|
||||
errNotAllCasesCovered: "not all cases are covered",
|
||||
errUnknownSubstitionVar: "unknown substitution variable: '$1'",
|
||||
errComplexStmtRequiresInd: "complex statement requires indentation",
|
||||
errXisNotCallable: "'$1' is not callable",
|
||||
errNoPragmasAllowedForX: "no pragmas allowed for $1",
|
||||
,
|
||||
errInvalidParamKindX: "invalid param kind: '$1'",
|
||||
errDefaultArgumentInvalid: "default argument invalid",
|
||||
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
|
||||
errNoReturnTypeForX: "no return type allowed for $1",
|
||||
errConvNeedsOneArg: "a type conversion needs exactly one argument",
|
||||
errInvalidPragmaX: ,
|
||||
errXNotAllowedHere: "$1 not allowed here",
|
||||
errXisNoType: "invalid type: '$1'",
|
||||
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
|
||||
errInvalidExpression: "invalid expression",
|
||||
errInvalidExpressionX: "invalid expression: '$1'",
|
||||
errEnumHasNoValueX: "enum has no value '$1'",
|
||||
,
|
||||
errNoCommand: "no command given",
|
||||
errInvalidCommandX: "invalid command: '$1'",
|
||||
errXNeedsParamObjectType: ,
|
||||
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
|
||||
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
|
||||
errInstantiationFrom: "template/generic instantiation from here",
|
||||
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
|
||||
errCommandExpectsFilename: "command expects a filename argument",
|
||||
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
|
||||
errXExpected: "'$1' expected",
|
||||
,
|
||||
errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
|
||||
errInvalidSectionStart: "invalid section start",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
errNewSectionExpected: "new section expected",
|
||||
errWhitespaceExpected: "whitespace expected, got '$1'",
|
||||
errXisNoValidIndexFile: "'$1' is no valid index file",
|
||||
errCannotRenderX: "cannot render reStructuredText element '$1'",
|
||||
errVarVarTypeNotAllowed: ,
|
||||
errInstantiateXExplicitly: "instantiate '$1' explicitly",
|
||||
errOnlyACallOpCanBeDelegator: ,
|
||||
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
||||
"because the parameter '$1' has a generic type",
|
||||
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
|
||||
"A destructor must be associated will all instantiations of a generic type",
|
||||
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
|
||||
"templates, macros and other inline iterators",
|
||||
errXExpectsTwoArguments: "'$1' expects two arguments",
|
||||
errXExpectsObjectTypes: "'$1' expects object types",
|
||||
errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
|
||||
errTooManyIterations: "interpretation requires too many iterations; " &
|
||||
"if you are sure this is not a bug in your code edit " &
|
||||
"compiler/vmdef.MaxLoopIterations and rebuild the compiler",
|
||||
errFieldXNotFound: "field '$1' cannot be found",
|
||||
errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
|
||||
errAssertionFailed: "assertion failed",
|
||||
errCannotGenerateCodeForX: "cannot generate code for '$1'",
|
||||
errXRequiresOneArgument: "$1 requires one parameter",
|
||||
errUnhandledExceptionX: "unhandled exception: $1",
|
||||
errCyclicTree: "macro returned a cyclic abstract syntax tree",
|
||||
errXisNoMacroOrTemplate: "'$1' is no macro or template",
|
||||
errXhasSideEffects: "'$1' can have side effects",
|
||||
errWrongSymbolX:,
|
||||
errIllegalCaptureX: "illegal capture '$1'",
|
||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||
,
|
||||
]#
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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``.
|
||||
|
||||
@@ -16,7 +16,7 @@ import
|
||||
wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast,
|
||||
packages/docutils/rst, packages/docutils/rstgen, times,
|
||||
packages/docutils/highlite, sempass2, json, xmltree, cgi,
|
||||
typesrenderer, astalgo, modulepaths
|
||||
typesrenderer, astalgo, modulepaths, configuration
|
||||
|
||||
type
|
||||
TSections = array[TSymKind, Rope]
|
||||
@@ -29,6 +29,7 @@ type
|
||||
jArray: JsonNode
|
||||
types: TStrTable
|
||||
isPureRst: bool
|
||||
conf*: ConfigRef
|
||||
|
||||
PDoc* = ref TDocumentor ## Alias to type less.
|
||||
|
||||
@@ -53,42 +54,47 @@ proc attachToType(d: PDoc; p: PSym): PSym =
|
||||
if params.len > 0: check(0)
|
||||
for i in 2..<params.len: check(i)
|
||||
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.MsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
var k: msgs.TMsgKind
|
||||
case msgKind
|
||||
of meCannotOpenFile: k = errCannotOpenFile
|
||||
of meExpected: k = errXExpected
|
||||
of meGridTableNotImplemented: k = errGridTableNotImplemented
|
||||
of meNewSectionExpected: k = errNewSectionExpected
|
||||
of meGeneralParseError: k = errGeneralParseError
|
||||
of meInvalidDirective: k = errInvalidDirectiveX
|
||||
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||
globalError(newLineInfo(filename, line, col), k, arg)
|
||||
template declareClosures =
|
||||
proc compilerMsgHandler(filename: string, line, col: int,
|
||||
msgKind: rst.MsgKind, arg: string) {.procvar.} =
|
||||
# translate msg kind:
|
||||
var k: TMsgKind
|
||||
case msgKind
|
||||
of meCannotOpenFile: k = errCannotOpenFile
|
||||
of meExpected: k = errXExpected
|
||||
of meGridTableNotImplemented: k = errGridTableNotImplemented
|
||||
of meNewSectionExpected: k = errNewSectionExpected
|
||||
of meGeneralParseError: k = errGeneralParseError
|
||||
of meInvalidDirective: k = errInvalidDirectiveX
|
||||
of mwRedefinitionOfLabel: k = warnRedefinitionOfLabel
|
||||
of mwUnknownSubstitution: k = warnUnknownSubstitutionX
|
||||
of mwUnsupportedLanguage: k = warnLanguageXNotSupported
|
||||
of mwUnsupportedField: k = warnFieldXNotSupported
|
||||
globalError(conf, newLineInfo(conf, filename, line, col), k, arg)
|
||||
|
||||
proc docgenFindFile(s: string): string {.procvar.} =
|
||||
result = options.findFile(s)
|
||||
if result.len == 0:
|
||||
result = getCurrentDir() / s
|
||||
if not existsFile(result): result = ""
|
||||
proc docgenFindFile(s: string): string {.procvar.} =
|
||||
result = options.findFile(conf, s)
|
||||
if result.len == 0:
|
||||
result = getCurrentDir() / s
|
||||
if not existsFile(result): result = ""
|
||||
|
||||
proc parseRst(text, filename: string,
|
||||
line, column: int, hasToc: var bool,
|
||||
rstOptions: RstParseOptions): PRstNode =
|
||||
rstOptions: RstParseOptions;
|
||||
conf: ConfigRef): PRstNode =
|
||||
declareClosures()
|
||||
result = rstParse(text, filename, line, column, hasToc, rstOptions,
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
proc newDocumentor*(filename: string, conf: ConfigRef): PDoc =
|
||||
declareClosures()
|
||||
new(result)
|
||||
initRstGenerator(result[], (if gCmd != cmdRst2tex: outHtml else: outLatex),
|
||||
options.gConfigVars, filename, {roSupportRawDirective},
|
||||
result.conf = conf
|
||||
initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex),
|
||||
conf.configVars, filename, {roSupportRawDirective},
|
||||
docgenFindFile, compilerMsgHandler)
|
||||
|
||||
if config.hasKey("doc.googleAnalytics"):
|
||||
if conf.configVars.hasKey("doc.googleAnalytics"):
|
||||
result.analytics = """
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
@@ -100,7 +106,7 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
""" % [config.getOrDefault"doc.googleAnalytics"]
|
||||
""" % [conf.configVars.getOrDefault"doc.googleAnalytics"]
|
||||
else:
|
||||
result.analytics = ""
|
||||
|
||||
@@ -109,10 +115,10 @@ proc newDocumentor*(filename: string, config: StringTableRef): PDoc =
|
||||
result.jArray = newJArray()
|
||||
initStrTable result.types
|
||||
result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) =
|
||||
localError(newLineInfo(d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
|
||||
localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute")
|
||||
|
||||
proc dispA(dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if gCmd != cmdRst2tex: addf(dest, xml, args)
|
||||
proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) =
|
||||
if conf.cmd != cmdRst2tex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
@@ -121,7 +127,8 @@ proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
return i
|
||||
result = -1
|
||||
|
||||
proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
|
||||
proc ropeFormatNamedVars(conf: ConfigRef; frmt: FormatStr,
|
||||
varnames: openArray[string],
|
||||
varvalues: openArray[Rope]): Rope =
|
||||
var i = 0
|
||||
var L = len(frmt)
|
||||
@@ -144,7 +151,8 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if (i > L + 0 - 1) or not (frmt[i] in {'0'..'9'}): break
|
||||
if j > high(varvalues) + 1: internalError("ropeFormatNamedVars")
|
||||
if j > high(varvalues) + 1:
|
||||
rawMessage(conf, errGenerated, "Invalid format string; too many $s: " & frmt)
|
||||
num = j
|
||||
add(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
@@ -155,20 +163,23 @@ proc ropeFormatNamedVars(frmt: FormatStr, varnames: openArray[string],
|
||||
if not (frmt[i] in {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}): break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0': rawMessage(errTokenExpected, "}")
|
||||
while i < frmt.len and frmt[i] != '}':
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
inc(i) # skip }
|
||||
# search for the variable:
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if i >= frmt.len:
|
||||
rawMessage(conf, errGenerated, "expected closing '}'")
|
||||
else:
|
||||
inc(i) # skip }
|
||||
# search for the variable:
|
||||
let idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else: rawMessage(errUnknownSubstitionVar, id)
|
||||
else: internalError("ropeFormatNamedVars")
|
||||
else: rawMessage(conf, errGenerated, "unknown substition variable: " & id)
|
||||
else:
|
||||
add(result, "$")
|
||||
var start = i
|
||||
while i < L:
|
||||
if frmt[i] != '$': inc(i)
|
||||
@@ -181,7 +192,7 @@ proc genComment(d: PDoc, n: PNode): string =
|
||||
if n.comment != nil:
|
||||
renderRstToOut(d[], parseRst(n.comment, toFilename(n.info),
|
||||
toLinenumber(n.info), toColumn(n.info),
|
||||
dummyHasToc, d.options), result)
|
||||
dummyHasToc, d.options, d.conf), result)
|
||||
|
||||
proc genRecComment(d: PDoc, n: PNode): Rope =
|
||||
if n == nil: return nil
|
||||
@@ -220,37 +231,37 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
|
||||
of tkEof:
|
||||
break
|
||||
of tkComment:
|
||||
dispA(result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
dispA(d.conf, result, "<span class=\"Comment\">$1</span>", "\\spanComment{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tokKeywordLow..tokKeywordHigh:
|
||||
dispA(result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
dispA(d.conf, result, "<span class=\"Keyword\">$1</span>", "\\spanKeyword{$1}",
|
||||
[rope(literal)])
|
||||
of tkOpr:
|
||||
dispA(result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
dispA(d.conf, result, "<span class=\"Operator\">$1</span>", "\\spanOperator{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkStrLit..tkTripleStrLit:
|
||||
dispA(result, "<span class=\"StringLit\">$1</span>",
|
||||
dispA(d.conf, result, "<span class=\"StringLit\">$1</span>",
|
||||
"\\spanStringLit{$1}", [rope(esc(d.target, literal))])
|
||||
of tkCharLit:
|
||||
dispA(result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
dispA(d.conf, result, "<span class=\"CharLit\">$1</span>", "\\spanCharLit{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkIntLit..tkUInt64Lit:
|
||||
dispA(result, "<span class=\"DecNumber\">$1</span>",
|
||||
dispA(d.conf, result, "<span class=\"DecNumber\">$1</span>",
|
||||
"\\spanDecNumber{$1}", [rope(esc(d.target, literal))])
|
||||
of tkFloatLit..tkFloat128Lit:
|
||||
dispA(result, "<span class=\"FloatNumber\">$1</span>",
|
||||
dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>",
|
||||
"\\spanFloatNumber{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSymbol:
|
||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||
dispA(d.conf, result, "<span class=\"Identifier\">$1</span>",
|
||||
"\\spanIdentifier{$1}", [rope(esc(d.target, literal))])
|
||||
of tkSpaces, tkInvalid:
|
||||
add(result, literal)
|
||||
of tkCurlyDotLe:
|
||||
dispA(result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
|
||||
dispA(d.conf, result, """<span class="Other pragmabegin">$1</span><div class="pragma">""",
|
||||
"\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkCurlyDotRi:
|
||||
dispA(result, "</div><span class=\"Other pragmaend\">$1</span>",
|
||||
dispA(d.conf, result, "</div><span class=\"Other pragmaend\">$1</span>",
|
||||
"\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||
@@ -259,7 +270,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe
|
||||
tkAccent, tkColonColon,
|
||||
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr,
|
||||
tkBracketLeColon:
|
||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
dispA(d.conf, result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||
[rope(esc(d.target, literal))])
|
||||
|
||||
proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
|
||||
@@ -267,7 +278,7 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) =
|
||||
of nkCallKinds:
|
||||
if n[0].kind == nkSym and n[0].sym.magic == mRunnableExamples and
|
||||
n.len >= 2 and n.lastSon.kind == nkStmtList:
|
||||
dispA(dest, "\n<strong class=\"examples_text\">$1</strong>\n",
|
||||
dispA(d.conf, dest, "\n<strong class=\"examples_text\">$1</strong>\n",
|
||||
"\n\\textbf{$1}\n", [rope"Examples:"])
|
||||
inc d.listingCounter
|
||||
let id = $d.listingCounter
|
||||
@@ -336,7 +347,6 @@ proc getName(d: PDoc, n: PNode, splitAfter = -1): string =
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getName(d, n[0], splitAfter)
|
||||
else:
|
||||
internalError(n.info, "getName()")
|
||||
result = ""
|
||||
|
||||
proc getNameIdent(n: PNode): PIdent =
|
||||
@@ -366,7 +376,6 @@ proc getRstName(n: PNode): PRstNode =
|
||||
of nkOpenSymChoice, nkClosedSymChoice:
|
||||
result = getRstName(n[0])
|
||||
else:
|
||||
internalError(n.info, "getRstName()")
|
||||
result = nil
|
||||
|
||||
proc newUniquePlainSymbol(d: PDoc, original: string): string =
|
||||
@@ -490,22 +499,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
symbolOrIdEncRope = encodeUrl(symbolOrId).rope
|
||||
|
||||
var seeSrcRope: Rope = nil
|
||||
let docItemSeeSrc = getConfigVar("doc.item.seesrc")
|
||||
let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc")
|
||||
if docItemSeeSrc.len > 0:
|
||||
let cwd = getCurrentDir().canonicalizePath()
|
||||
let cwd = canonicalizePath(d.conf, getCurrentDir())
|
||||
var path = n.info.toFullPath
|
||||
if path.startsWith(cwd):
|
||||
path = path[cwd.len+1 .. ^1].replace('\\', '/')
|
||||
let gitUrl = getConfigVar("git.url")
|
||||
let gitUrl = getConfigVar(d.conf, "git.url")
|
||||
if gitUrl.len > 0:
|
||||
var commit = getConfigVar("git.commit")
|
||||
var commit = getConfigVar(d.conf, "git.commit")
|
||||
if commit.len == 0: commit = "master"
|
||||
dispA(seeSrcRope, "$1", "", [ropeFormatNamedVars(docItemSeeSrc,
|
||||
dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc,
|
||||
["path", "line", "url", "commit"], [rope path,
|
||||
rope($n.info.line), rope gitUrl,
|
||||
rope commit])])
|
||||
|
||||
add(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||
add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "seeSrc"],
|
||||
[nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope,
|
||||
@@ -516,7 +525,7 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||
let att = attachToType(d, nameNode.sym)
|
||||
if att != nil:
|
||||
attype = rope esc(d.target, att.name.s)
|
||||
add(d.toc[k], ropeFormatNamedVars(getConfigVar("doc.item.toc"),
|
||||
add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"),
|
||||
["name", "header", "desc", "itemID", "header_plain", "itemSym",
|
||||
"itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"],
|
||||
[rope(getName(d, nameNode, d.splitAfter)), result, comm,
|
||||
@@ -569,9 +578,9 @@ proc traceDeps(d: PDoc, it: PNode) =
|
||||
traceDeps(d, a)
|
||||
else:
|
||||
if d.section[k] != nil: add(d.section[k], ", ")
|
||||
dispA(d.section[k],
|
||||
dispA(d.conf, d.section[k],
|
||||
"<a class=\"reference external\" href=\"$1.html\">$1</a>",
|
||||
"$1", [rope(getModuleName(it))])
|
||||
"$1", [rope(getModuleName(d.conf, it))])
|
||||
|
||||
proc generateDoc*(d: PDoc, n: PNode) =
|
||||
case n.kind
|
||||
@@ -704,10 +713,10 @@ proc genSection(d: PDoc, kind: TSymKind) =
|
||||
]
|
||||
if d.section[kind] == nil: return
|
||||
var title = sectionNames[kind].rope
|
||||
d.section[kind] = ropeFormatNamedVars(getConfigVar("doc.section"), [
|
||||
d.section[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).rope, title, rope(ord(kind) + 50), d.section[kind]])
|
||||
d.toc[kind] = ropeFormatNamedVars(getConfigVar("doc.section.toc"), [
|
||||
d.toc[kind] = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.section.toc"), [
|
||||
"sectionid", "sectionTitle", "sectionTitleID", "content"], [
|
||||
ord(kind).rope, title, rope(ord(kind) + 50), d.toc[kind]])
|
||||
|
||||
@@ -723,7 +732,7 @@ proc genOutFile(d: PDoc): Rope =
|
||||
genSection(d, i)
|
||||
add(toc, d.toc[i])
|
||||
if toc != nil:
|
||||
toc = ropeFormatNamedVars(getConfigVar("doc.toc"), ["content"], [toc])
|
||||
toc = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.toc"), ["content"], [toc])
|
||||
for i in countup(low(TSymKind), high(TSymKind)): add(code, d.section[i])
|
||||
|
||||
# Extract the title. Non API modules generate an entry in the index table.
|
||||
@@ -737,13 +746,13 @@ proc genOutFile(d: PDoc): Rope =
|
||||
let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group"
|
||||
elif d.hasToc: "doc.body_toc"
|
||||
else: "doc.body_no_toc"
|
||||
content = ropeFormatNamedVars(getConfigVar(bodyname), ["title",
|
||||
content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time", "content"],
|
||||
[title.rope, toc, d.modDesc, rope(getDateStr()),
|
||||
rope(getClockStr()), code])
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
if optCompileOnly notin d.conf.globalOptions:
|
||||
# XXX what is this hack doing here? 'optCompileOnly' means raw output!?
|
||||
code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version", "analytics"],
|
||||
[title.rope, toc, d.modDesc, rope(getDateStr()),
|
||||
@@ -754,60 +763,60 @@ proc genOutFile(d: PDoc): Rope =
|
||||
result = code
|
||||
|
||||
proc generateIndex*(d: PDoc) =
|
||||
if optGenIndex in gGlobalOptions:
|
||||
writeIndexFile(d[], splitFile(options.outFile).dir /
|
||||
if optGenIndex in d.conf.globalOptions:
|
||||
writeIndexFile(d[], splitFile(d.conf.outFile).dir /
|
||||
splitFile(d.filename).name & IndexExt)
|
||||
|
||||
proc getOutFile2(filename, ext, dir: string): string =
|
||||
if gWholeProject:
|
||||
let d = if options.outFile != "": options.outFile else: dir
|
||||
proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string =
|
||||
if optWholeProject in conf.globalOptions:
|
||||
let d = if conf.outFile != "": conf.outFile else: dir
|
||||
createDir(d)
|
||||
result = d / changeFileExt(filename, ext)
|
||||
else:
|
||||
result = getOutFile(filename, ext)
|
||||
result = getOutFile(conf, filename, ext)
|
||||
|
||||
proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||
var content = genOutFile(d)
|
||||
if optStdout in gGlobalOptions:
|
||||
if optStdout in d.conf.globalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
writeRope(content, getOutFile2(filename, outExt, "htmldocs"), useWarning)
|
||||
writeRope(content, getOutFile2(d.conf, filename, outExt, "htmldocs"), useWarning)
|
||||
|
||||
proc writeOutputJson*(d: PDoc, filename, outExt: string,
|
||||
useWarning = false) =
|
||||
let content = %*{"orig": d.filename,
|
||||
"nimble": getPackageName(d.filename),
|
||||
"nimble": getPackageName(d.conf, d.filename),
|
||||
"entries": d.jArray}
|
||||
if optStdout in gGlobalOptions:
|
||||
if optStdout in d.conf.globalOptions:
|
||||
write(stdout, $content)
|
||||
else:
|
||||
var f: File
|
||||
if open(f, getOutFile2(splitFile(filename).name,
|
||||
if open(f, getOutFile2(d.conf, splitFile(filename).name,
|
||||
outExt, "jsondocs"), fmWrite):
|
||||
write(f, $content)
|
||||
close(f)
|
||||
else:
|
||||
discard "fixme: error report"
|
||||
|
||||
proc commandDoc*() =
|
||||
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
|
||||
proc commandDoc*(conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
var d = newDocumentor(conf.projectFull, conf)
|
||||
d.hasToc = true
|
||||
generateDoc(d, ast)
|
||||
writeOutput(d, gProjectFull, HtmlExt)
|
||||
writeOutput(d, conf.projectFull, HtmlExt)
|
||||
generateIndex(d)
|
||||
|
||||
proc commandRstAux(filename, outExt: string) =
|
||||
proc commandRstAux(conf: ConfigRef; filename, outExt: string) =
|
||||
var filen = addFileExt(filename, "txt")
|
||||
var d = newDocumentor(filen, options.gConfigVars)
|
||||
var d = newDocumentor(filen, conf)
|
||||
d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string;
|
||||
status: int; content: string) =
|
||||
var outp: string
|
||||
if filename.len == 0:
|
||||
inc(d.id)
|
||||
let nameOnly = splitFile(d.filename).name
|
||||
let subdir = getNimcacheDir() / nameOnly
|
||||
let subdir = getNimcacheDir(conf) / nameOnly
|
||||
createDir(subdir)
|
||||
outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim")
|
||||
elif isAbsolute(filename):
|
||||
@@ -817,13 +826,13 @@ proc commandRstAux(filename, outExt: string) =
|
||||
outp = splitFile(d.filename).dir / filename
|
||||
writeFile(outp, content)
|
||||
let cmd = cmd % quoteShell(outp)
|
||||
rawMessage(hintExecuting, cmd)
|
||||
rawMessage(conf, hintExecuting, cmd)
|
||||
if execShellCmd(cmd) != status:
|
||||
rawMessage(errExecutionOfProgramFailed, cmd)
|
||||
rawMessage(conf, errGenerated, "executing of external program failed: " & cmd)
|
||||
|
||||
d.isPureRst = true
|
||||
var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc,
|
||||
{roSupportRawDirective})
|
||||
{roSupportRawDirective}, conf)
|
||||
var modDesc = newStringOfCap(30_000)
|
||||
#d.modDesc = newMutableRope(30_000)
|
||||
renderRstToOut(d[], rst, modDesc)
|
||||
@@ -832,50 +841,50 @@ proc commandRstAux(filename, outExt: string) =
|
||||
writeOutput(d, filename, outExt)
|
||||
generateIndex(d)
|
||||
|
||||
proc commandRst2Html*() =
|
||||
commandRstAux(gProjectFull, HtmlExt)
|
||||
proc commandRst2Html*(conf: ConfigRef) =
|
||||
commandRstAux(conf, conf.projectFull, HtmlExt)
|
||||
|
||||
proc commandRst2TeX*() =
|
||||
proc commandRst2TeX*(conf: ConfigRef) =
|
||||
splitter = "\\-"
|
||||
commandRstAux(gProjectFull, TexExt)
|
||||
commandRstAux(conf, conf.projectFull, TexExt)
|
||||
|
||||
proc commandJson*() =
|
||||
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
|
||||
proc commandJson*(conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
var d = newDocumentor(conf.projectFull, conf)
|
||||
d.hasToc = true
|
||||
generateJson(d, ast)
|
||||
let json = d.jArray
|
||||
let content = rope(pretty(json))
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
if optStdout in d.conf.globalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
#echo getOutFile(gProjectFull, JsonExt)
|
||||
writeRope(content, getOutFile(gProjectFull, JsonExt), useWarning = false)
|
||||
writeRope(content, getOutFile(conf, conf.projectFull, JsonExt), useWarning = false)
|
||||
|
||||
proc commandTags*() =
|
||||
var ast = parseFile(gProjectMainIdx.FileIndex, newIdentCache(), newConfigRef())
|
||||
proc commandTags*(conf: ConfigRef) =
|
||||
var ast = parseFile(conf.projectMainIdx.FileIndex, newIdentCache(), conf)
|
||||
if ast == nil: return
|
||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||
var d = newDocumentor(conf.projectFull, conf)
|
||||
d.hasToc = true
|
||||
var
|
||||
content: Rope
|
||||
generateTags(d, ast, content)
|
||||
|
||||
if optStdout in gGlobalOptions:
|
||||
if optStdout in d.conf.globalOptions:
|
||||
writeRope(stdout, content)
|
||||
else:
|
||||
#echo getOutFile(gProjectFull, TagsExt)
|
||||
writeRope(content, getOutFile(gProjectFull, TagsExt), useWarning = false)
|
||||
writeRope(content, getOutFile(conf, conf.projectFull, TagsExt), useWarning = false)
|
||||
|
||||
proc commandBuildIndex*() =
|
||||
var content = mergeIndexes(gProjectFull).rope
|
||||
proc commandBuildIndex*(conf: ConfigRef) =
|
||||
var content = mergeIndexes(conf.projectFull).rope
|
||||
|
||||
let code = ropeFormatNamedVars(getConfigVar("doc.file"), ["title",
|
||||
let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title",
|
||||
"tableofcontents", "moduledesc", "date", "time",
|
||||
"content", "author", "version", "analytics"],
|
||||
["Index".rope, nil, nil, rope(getDateStr()),
|
||||
rope(getClockStr()), content, nil, nil, nil])
|
||||
# no analytics because context is not available
|
||||
writeRope(code, getOutFile("theindex", HtmlExt))
|
||||
writeRope(code, getOutFile(conf, "theindex", HtmlExt))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
import
|
||||
ropes, os, strutils, osproc, platform, condsyms, options, msgs,
|
||||
std / sha1, streams
|
||||
configuration, std / sha1, streams
|
||||
|
||||
#from debuginfo import writeDebugInfo
|
||||
|
||||
@@ -193,9 +193,9 @@ compiler bcc:
|
||||
pic: "",
|
||||
asmStmtFrmt: "__asm{$n$1$n}$n",
|
||||
structStmtFmt: "$1 $2",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard,
|
||||
hasAttribute})
|
||||
|
||||
|
||||
|
||||
# Digital Mars C Compiler
|
||||
compiler dmc:
|
||||
@@ -376,80 +376,81 @@ proc nameToCC*(name: string): TSystemCC =
|
||||
return i
|
||||
result = ccNone
|
||||
|
||||
proc getConfigVar(c: TSystemCC, suffix: string): string =
|
||||
proc getConfigVar(conf: ConfigRef; c: TSystemCC, suffix: string): string =
|
||||
# use ``cpu.os.cc`` for cross compilation, unless ``--compileOnly`` is given
|
||||
# for niminst support
|
||||
let fullSuffix =
|
||||
if gCmd == cmdCompileToCpp:
|
||||
if conf.cmd == cmdCompileToCpp:
|
||||
".cpp" & suffix
|
||||
elif gCmd == cmdCompileToOC:
|
||||
elif conf.cmd == cmdCompileToOC:
|
||||
".objc" & suffix
|
||||
elif gCmd == cmdCompileToJS:
|
||||
elif conf.cmd == cmdCompileToJS:
|
||||
".js" & suffix
|
||||
else:
|
||||
suffix
|
||||
|
||||
if (platform.hostOS != targetOS or platform.hostCPU != targetCPU) and
|
||||
optCompileOnly notin gGlobalOptions:
|
||||
optCompileOnly notin conf.globalOptions:
|
||||
let fullCCname = platform.CPU[targetCPU].name & '.' &
|
||||
platform.OS[targetOS].name & '.' &
|
||||
CC[c].name & fullSuffix
|
||||
result = getConfigVar(fullCCname)
|
||||
result = getConfigVar(conf, fullCCname)
|
||||
if result.len == 0:
|
||||
# not overriden for this cross compilation setting?
|
||||
result = getConfigVar(CC[c].name & fullSuffix)
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
else:
|
||||
result = getConfigVar(CC[c].name & fullSuffix)
|
||||
result = getConfigVar(conf, CC[c].name & fullSuffix)
|
||||
|
||||
proc setCC*(ccname: string) =
|
||||
proc setCC*(conf: ConfigRef; ccname: string; info: TLineInfo) =
|
||||
cCompiler = nameToCC(ccname)
|
||||
if cCompiler == ccNone: rawMessage(errUnknownCcompiler, ccname)
|
||||
compileOptions = getConfigVar(cCompiler, ".options.always")
|
||||
if cCompiler == ccNone:
|
||||
localError(conf, info, "unknown C compiler: '$1'" % ccname)
|
||||
compileOptions = getConfigVar(conf, cCompiler, ".options.always")
|
||||
linkOptions = ""
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
|
||||
defineSymbol(conf.symbols, CC[cCompiler].name)
|
||||
|
||||
proc addOpt(dest: var string, src: string) =
|
||||
if len(dest) == 0 or dest[len(dest)-1] != ' ': add(dest, " ")
|
||||
add(dest, src)
|
||||
|
||||
proc addLinkOption*(option: string) =
|
||||
proc addLinkOption*(conf: ConfigRef; option: string) =
|
||||
addOpt(linkOptions, option)
|
||||
|
||||
proc addCompileOption*(option: string) =
|
||||
proc addCompileOption*(conf: ConfigRef; option: string) =
|
||||
if strutils.find(compileOptions, option, 0) < 0:
|
||||
addOpt(compileOptions, option)
|
||||
|
||||
proc addLinkOptionCmd*(option: string) =
|
||||
proc addLinkOptionCmd*(conf: ConfigRef; option: string) =
|
||||
addOpt(linkOptionsCmd, option)
|
||||
|
||||
proc addCompileOptionCmd*(option: string) =
|
||||
proc addCompileOptionCmd*(conf: ConfigRef; option: string) =
|
||||
compileOptionsCmd.add(option)
|
||||
|
||||
proc initVars*() =
|
||||
proc initVars*(conf: ConfigRef) =
|
||||
# we need to define the symbol here, because ``CC`` may have never been set!
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(CC[i].name)
|
||||
defineSymbol(CC[cCompiler].name)
|
||||
addCompileOption(getConfigVar(cCompiler, ".options.always"))
|
||||
for i in countup(low(CC), high(CC)): undefSymbol(conf.symbols, CC[i].name)
|
||||
defineSymbol(conf.symbols, CC[cCompiler].name)
|
||||
addCompileOption(conf, getConfigVar(conf, cCompiler, ".options.always"))
|
||||
#addLinkOption(getConfigVar(cCompiler, ".options.linker"))
|
||||
if len(ccompilerpath) == 0:
|
||||
ccompilerpath = getConfigVar(cCompiler, ".path")
|
||||
ccompilerpath = getConfigVar(conf, cCompiler, ".path")
|
||||
|
||||
proc completeCFilePath*(cfile: string, createSubDir: bool = true): string =
|
||||
result = completeGeneratedFilePath(cfile, createSubDir)
|
||||
proc completeCFilePath*(conf: ConfigRef; cfile: string, createSubDir: bool = true): string =
|
||||
result = completeGeneratedFilePath(conf, cfile, createSubDir)
|
||||
|
||||
proc toObjFile*(filename: string): string =
|
||||
proc toObjFile*(conf: ConfigRef; filename: string): string =
|
||||
# Object file for compilation
|
||||
#if filename.endsWith(".cpp"):
|
||||
# result = changeFileExt(filename, "cpp." & CC[cCompiler].objExt)
|
||||
#else:
|
||||
result = changeFileExt(filename, CC[cCompiler].objExt)
|
||||
|
||||
proc addFileToCompile*(cf: Cfile) =
|
||||
proc addFileToCompile*(conf: ConfigRef; cf: Cfile) =
|
||||
toCompile.add(cf)
|
||||
|
||||
proc resetCompilationLists* =
|
||||
proc resetCompilationLists*(conf: ConfigRef) =
|
||||
toCompile.setLen 0
|
||||
## XXX: we must associate these with their originating module
|
||||
# when the module is loaded/unloaded it adds/removes its items
|
||||
@@ -457,109 +458,112 @@ proc resetCompilationLists* =
|
||||
# Maybe we can do that in checkDep on the other hand?
|
||||
externalToLink.setLen 0
|
||||
|
||||
proc addExternalFileToLink*(filename: string) =
|
||||
proc addExternalFileToLink*(conf: ConfigRef; filename: string) =
|
||||
externalToLink.insert(filename, 0)
|
||||
|
||||
proc execWithEcho(cmd: string, msg = hintExecuting): int =
|
||||
rawMessage(msg, cmd)
|
||||
proc execWithEcho(conf: ConfigRef; cmd: string, msg = hintExecuting): int =
|
||||
rawMessage(conf, msg, cmd)
|
||||
result = execCmd(cmd)
|
||||
|
||||
proc execExternalProgram*(cmd: string, msg = hintExecuting) =
|
||||
if execWithEcho(cmd, msg) != 0:
|
||||
rawMessage(errExecutionOfProgramFailed, cmd)
|
||||
proc execExternalProgram*(conf: ConfigRef; cmd: string, msg = hintExecuting) =
|
||||
if execWithEcho(conf, cmd, msg) != 0:
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
cmd)
|
||||
|
||||
proc generateScript(projectFile: string, script: Rope) =
|
||||
proc generateScript(conf: ConfigRef; projectFile: string, script: Rope) =
|
||||
let (dir, name, ext) = splitFile(projectFile)
|
||||
writeRope(script, getNimcacheDir() / addFileExt("compile_" & name,
|
||||
writeRope(script, getNimcacheDir(conf) / addFileExt("compile_" & name,
|
||||
platform.OS[targetOS].scriptExt))
|
||||
copyFile(libpath / "nimbase.h", getNimcacheDir() / "nimbase.h")
|
||||
copyFile(conf.libpath / "nimbase.h", getNimcacheDir(conf) / "nimbase.h")
|
||||
|
||||
proc getOptSpeed(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.speed")
|
||||
proc getOptSpeed(conf: ConfigRef; c: TSystemCC): string =
|
||||
result = getConfigVar(conf, c, ".options.speed")
|
||||
if result == "":
|
||||
result = CC[c].optSpeed # use default settings from this file
|
||||
|
||||
proc getDebug(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.debug")
|
||||
proc getDebug(conf: ConfigRef; c: TSystemCC): string =
|
||||
result = getConfigVar(conf, c, ".options.debug")
|
||||
if result == "":
|
||||
result = CC[c].debug # use default settings from this file
|
||||
|
||||
proc getOptSize(c: TSystemCC): string =
|
||||
result = getConfigVar(c, ".options.size")
|
||||
proc getOptSize(conf: ConfigRef; c: TSystemCC): string =
|
||||
result = getConfigVar(conf, c, ".options.size")
|
||||
if result == "":
|
||||
result = CC[c].optSize # use default settings from this file
|
||||
|
||||
proc noAbsolutePaths: bool {.inline.} =
|
||||
proc noAbsolutePaths(conf: ConfigRef): bool {.inline.} =
|
||||
# We used to check current OS != specified OS, but this makes no sense
|
||||
# really: Cross compilation from Linux to Linux for example is entirely
|
||||
# reasonable.
|
||||
# `optGenMapping` is included here for niminst.
|
||||
result = gGlobalOptions * {optGenScript, optGenMapping} != {}
|
||||
result = conf.globalOptions * {optGenScript, optGenMapping} != {}
|
||||
|
||||
proc cFileSpecificOptions(cfilename: string): string =
|
||||
proc cFileSpecificOptions(conf: ConfigRef; cfilename: string): string =
|
||||
result = compileOptions
|
||||
for option in compileOptionsCmd:
|
||||
if strutils.find(result, option, 0) < 0:
|
||||
addOpt(result, option)
|
||||
|
||||
var trunk = splitFile(cfilename).name
|
||||
if optCDebug in gGlobalOptions:
|
||||
var key = trunk & ".debug"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getDebug(cCompiler))
|
||||
if optOptimizeSpeed in gOptions:
|
||||
var key = trunk & ".speed"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getOptSpeed(cCompiler))
|
||||
elif optOptimizeSize in gOptions:
|
||||
var key = trunk & ".size"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
else: addOpt(result, getOptSize(cCompiler))
|
||||
var key = trunk & ".always"
|
||||
if existsConfigVar(key): addOpt(result, getConfigVar(key))
|
||||
let trunk = splitFile(cfilename).name
|
||||
if optCDebug in conf.globalOptions:
|
||||
let key = trunk & ".debug"
|
||||
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||
else: addOpt(result, getDebug(conf, cCompiler))
|
||||
if optOptimizeSpeed in conf.options:
|
||||
let key = trunk & ".speed"
|
||||
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||
else: addOpt(result, getOptSpeed(conf, cCompiler))
|
||||
elif optOptimizeSize in conf.options:
|
||||
let key = trunk & ".size"
|
||||
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||
else: addOpt(result, getOptSize(conf, cCompiler))
|
||||
let key = trunk & ".always"
|
||||
if existsConfigVar(conf, key): addOpt(result, getConfigVar(conf, key))
|
||||
|
||||
proc getCompileOptions: string =
|
||||
result = cFileSpecificOptions("__dummy__")
|
||||
proc getCompileOptions(conf: ConfigRef): string =
|
||||
result = cFileSpecificOptions(conf, "__dummy__")
|
||||
|
||||
proc getLinkOptions: string =
|
||||
proc getLinkOptions(conf: ConfigRef): string =
|
||||
result = linkOptions & " " & linkOptionsCmd & " "
|
||||
for linkedLib in items(cLinkedLibs):
|
||||
result.add(CC[cCompiler].linkLibCmd % linkedLib.quoteShell)
|
||||
for libDir in items(cLibs):
|
||||
result.add(join([CC[cCompiler].linkDirCmd, libDir.quoteShell]))
|
||||
|
||||
proc needsExeExt(): bool {.inline.} =
|
||||
result = (optGenScript in gGlobalOptions and targetOS == osWindows) or
|
||||
proc needsExeExt(conf: ConfigRef): bool {.inline.} =
|
||||
result = (optGenScript in conf.globalOptions and targetOS == osWindows) or
|
||||
(platform.hostOS == osWindows)
|
||||
|
||||
proc getCompilerExe(compiler: TSystemCC; cfile: string): string =
|
||||
result = if gCmd == cmdCompileToCpp and not cfile.endsWith(".c"):
|
||||
proc getCompilerExe(conf: ConfigRef; compiler: TSystemCC; cfile: string): string =
|
||||
result = if conf.cmd == cmdCompileToCpp and not cfile.endsWith(".c"):
|
||||
CC[compiler].cppCompiler
|
||||
else:
|
||||
CC[compiler].compilerExe
|
||||
if result.len == 0:
|
||||
rawMessage(errCompilerDoesntSupportTarget, CC[compiler].name)
|
||||
rawMessage(conf, errGenerated,
|
||||
"Compiler '$1' doesn't support the requested target" %
|
||||
CC[compiler].name)
|
||||
|
||||
proc getLinkerExe(compiler: TSystemCC): string =
|
||||
proc getLinkerExe(conf: ConfigRef; compiler: TSystemCC): string =
|
||||
result = if CC[compiler].linkerExe.len > 0: CC[compiler].linkerExe
|
||||
elif gMixedMode and gCmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
else: compiler.getCompilerExe("")
|
||||
elif gMixedMode and conf.cmd != cmdCompileToCpp: CC[compiler].cppCompiler
|
||||
else: getCompilerExe(conf, compiler, "")
|
||||
|
||||
proc getCompileCFileCmd*(cfile: Cfile): string =
|
||||
proc getCompileCFileCmd*(conf: ConfigRef; cfile: Cfile): string =
|
||||
var c = cCompiler
|
||||
var options = cFileSpecificOptions(cfile.cname)
|
||||
var exe = getConfigVar(c, ".exe")
|
||||
if exe.len == 0: exe = c.getCompilerExe(cfile.cname)
|
||||
var options = cFileSpecificOptions(conf, cfile.cname)
|
||||
var exe = getConfigVar(conf, c, ".exe")
|
||||
if exe.len == 0: exe = getCompilerExe(conf, c, cfile.cname)
|
||||
|
||||
if needsExeExt(): exe = addFileExt(exe, "exe")
|
||||
if optGenDynLib in gGlobalOptions and
|
||||
if needsExeExt(conf): exe = addFileExt(exe, "exe")
|
||||
if optGenDynLib in conf.globalOptions and
|
||||
ospNeedsPIC in platform.OS[targetOS].props:
|
||||
add(options, ' ' & CC[c].pic)
|
||||
|
||||
var includeCmd, compilePattern: string
|
||||
if not noAbsolutePaths():
|
||||
if not noAbsolutePaths(conf):
|
||||
# compute include paths:
|
||||
includeCmd = CC[c].includeCmd & quoteShell(libpath)
|
||||
includeCmd = CC[c].includeCmd & quoteShell(conf.libpath)
|
||||
|
||||
for includeDir in items(cIncludes):
|
||||
includeCmd.add(join([CC[c].includeCmd, includeDir.quoteShell]))
|
||||
@@ -567,18 +571,18 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
|
||||
compilePattern = joinPath(ccompilerpath, exe)
|
||||
else:
|
||||
includeCmd = ""
|
||||
compilePattern = c.getCompilerExe(cfile.cname)
|
||||
compilePattern = getCompilerExe(conf, c, cfile.cname)
|
||||
|
||||
var cf = if noAbsolutePaths(): extractFilename(cfile.cname)
|
||||
var cf = if noAbsolutePaths(conf): extractFilename(cfile.cname)
|
||||
else: cfile.cname
|
||||
|
||||
var objfile =
|
||||
if cfile.obj.len == 0:
|
||||
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths():
|
||||
toObjFile(cf)
|
||||
if not cfile.flags.contains(CfileFlag.External) or noAbsolutePaths(conf):
|
||||
toObjFile(conf, cf)
|
||||
else:
|
||||
completeCFilePath(toObjFile(cf))
|
||||
elif noAbsolutePaths():
|
||||
completeCFilePath(conf, toObjFile(conf, cf))
|
||||
elif noAbsolutePaths(conf):
|
||||
extractFilename(cfile.obj)
|
||||
else:
|
||||
cfile.obj
|
||||
@@ -587,30 +591,30 @@ proc getCompileCFileCmd*(cfile: Cfile): string =
|
||||
cf = quoteShell(cf)
|
||||
result = quoteShell(compilePattern % [
|
||||
"file", cf, "objfile", objfile, "options", options,
|
||||
"include", includeCmd, "nim", getPrefixDir(),
|
||||
"nim", getPrefixDir(), "lib", libpath])
|
||||
"include", includeCmd, "nim", getPrefixDir(conf),
|
||||
"nim", getPrefixDir(conf), "lib", conf.libpath])
|
||||
add(result, ' ')
|
||||
addf(result, CC[c].compileTmpl, [
|
||||
"file", cf, "objfile", objfile,
|
||||
"options", options, "include", includeCmd,
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
"nim", quoteShell(getPrefixDir(conf)),
|
||||
"nim", quoteShell(getPrefixDir(conf)),
|
||||
"lib", quoteShell(conf.libpath)])
|
||||
|
||||
proc footprint(cfile: Cfile): SecureHash =
|
||||
proc footprint(conf: ConfigRef; cfile: Cfile): SecureHash =
|
||||
result = secureHash(
|
||||
$secureHashFile(cfile.cname) &
|
||||
platform.OS[targetOS].name &
|
||||
platform.CPU[targetCPU].name &
|
||||
extccomp.CC[extccomp.cCompiler].name &
|
||||
getCompileCFileCmd(cfile))
|
||||
getCompileCFileCmd(conf, cfile))
|
||||
|
||||
proc externalFileChanged(cfile: Cfile): bool =
|
||||
if gCmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||
proc externalFileChanged(conf: ConfigRef; cfile: Cfile): bool =
|
||||
if conf.cmd notin {cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdCompileToLLVM}:
|
||||
return false
|
||||
|
||||
var hashFile = toGeneratedFile(cfile.cname.withPackageName, "sha1")
|
||||
var currentHash = footprint(cfile)
|
||||
var hashFile = toGeneratedFile(conf, conf.withPackageName(cfile.cname), "sha1")
|
||||
var currentHash = footprint(conf, cfile)
|
||||
var f: File
|
||||
if open(f, hashFile, fmRead):
|
||||
let oldHash = parseSecureHash(f.readLine())
|
||||
@@ -623,133 +627,137 @@ proc externalFileChanged(cfile: Cfile): bool =
|
||||
f.writeLine($currentHash)
|
||||
close(f)
|
||||
|
||||
proc addExternalFileToCompile*(c: var Cfile) =
|
||||
if optForceFullMake notin gGlobalOptions and not externalFileChanged(c):
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; c: var Cfile) =
|
||||
if optForceFullMake notin conf.globalOptions and not externalFileChanged(conf, c):
|
||||
c.flags.incl CfileFlag.Cached
|
||||
toCompile.add(c)
|
||||
|
||||
proc addExternalFileToCompile*(filename: string) =
|
||||
proc addExternalFileToCompile*(conf: ConfigRef; filename: string) =
|
||||
var c = Cfile(cname: filename,
|
||||
obj: toObjFile(completeCFilePath(changeFileExt(filename, ""), false)),
|
||||
obj: toObjFile(conf, completeCFilePath(conf, changeFileExt(filename, ""), false)),
|
||||
flags: {CfileFlag.External})
|
||||
addExternalFileToCompile(c)
|
||||
addExternalFileToCompile(conf, c)
|
||||
|
||||
proc compileCFile(list: CFileList, script: var Rope, cmds: var TStringSeq,
|
||||
proc compileCFile(conf: ConfigRef; list: CFileList, script: var Rope, cmds: var TStringSeq,
|
||||
prettyCmds: var TStringSeq) =
|
||||
for it in list:
|
||||
# call the C compiler for the .c file:
|
||||
if it.flags.contains(CfileFlag.Cached): continue
|
||||
var compileCmd = getCompileCFileCmd(it)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
var compileCmd = getCompileCFileCmd(conf, it)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
add(cmds, compileCmd)
|
||||
let (_, name, _) = splitFile(it.cname)
|
||||
add(prettyCmds, "CC: " & name)
|
||||
if optGenScript in gGlobalOptions:
|
||||
if optGenScript in conf.globalOptions:
|
||||
add(script, compileCmd)
|
||||
add(script, tnl)
|
||||
|
||||
proc getLinkCmd(projectfile, objfiles: string): string =
|
||||
if optGenStaticLib in gGlobalOptions:
|
||||
proc getLinkCmd(conf: ConfigRef; projectfile, objfiles: string): string =
|
||||
if optGenStaticLib in conf.globalOptions:
|
||||
var libname: string
|
||||
if options.outFile.len > 0:
|
||||
libname = options.outFile.expandTilde
|
||||
if conf.outFile.len > 0:
|
||||
libname = conf.outFile.expandTilde
|
||||
if not libname.isAbsolute():
|
||||
libname = getCurrentDir() / libname
|
||||
else:
|
||||
libname = (libNameTmpl() % splitFile(gProjectName).name)
|
||||
libname = (libNameTmpl() % splitFile(conf.projectName).name)
|
||||
result = CC[cCompiler].buildLib % ["libfile", libname,
|
||||
"objfiles", objfiles]
|
||||
else:
|
||||
var linkerExe = getConfigVar(cCompiler, ".linkerexe")
|
||||
if len(linkerExe) == 0: linkerExe = cCompiler.getLinkerExe
|
||||
var linkerExe = getConfigVar(conf, cCompiler, ".linkerexe")
|
||||
if len(linkerExe) == 0: linkerExe = getLinkerExe(conf, cCompiler)
|
||||
# bug #6452: We must not use ``quoteShell`` here for ``linkerExe``
|
||||
if needsExeExt(): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(): result = linkerExe
|
||||
if needsExeExt(conf): linkerExe = addFileExt(linkerExe, "exe")
|
||||
if noAbsolutePaths(conf): result = linkerExe
|
||||
else: result = joinPath(ccompilerpath, linkerExe)
|
||||
let buildgui = if optGenGuiApp in gGlobalOptions: CC[cCompiler].buildGui
|
||||
let buildgui = if optGenGuiApp in conf.globalOptions: CC[cCompiler].buildGui
|
||||
else: ""
|
||||
var exefile, builddll: string
|
||||
if optGenDynLib in gGlobalOptions:
|
||||
if optGenDynLib in conf.globalOptions:
|
||||
exefile = platform.OS[targetOS].dllFrmt % splitFile(projectfile).name
|
||||
builddll = CC[cCompiler].buildDll
|
||||
else:
|
||||
exefile = splitFile(projectfile).name & platform.OS[targetOS].exeExt
|
||||
builddll = ""
|
||||
if options.outFile.len > 0:
|
||||
exefile = options.outFile.expandTilde
|
||||
if conf.outFile.len > 0:
|
||||
exefile = conf.outFile.expandTilde
|
||||
if not exefile.isAbsolute():
|
||||
exefile = getCurrentDir() / exefile
|
||||
if not noAbsolutePaths():
|
||||
if not noAbsolutePaths(conf):
|
||||
if not exefile.isAbsolute():
|
||||
exefile = joinPath(splitFile(projectfile).dir, exefile)
|
||||
when false:
|
||||
if optCDebug in gGlobalOptions:
|
||||
if optCDebug in conf.globalOptions:
|
||||
writeDebugInfo(exefile.changeFileExt("ndb"))
|
||||
exefile = quoteShell(exefile)
|
||||
let linkOptions = getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")
|
||||
var linkTmpl = getConfigVar(cCompiler, ".linkTmpl")
|
||||
let linkOptions = getLinkOptions(conf) & " " &
|
||||
getConfigVar(conf, cCompiler, ".options.linker")
|
||||
var linkTmpl = getConfigVar(conf, cCompiler, ".linkTmpl")
|
||||
if linkTmpl.len == 0:
|
||||
linkTmpl = CC[cCompiler].linkTmpl
|
||||
result = quoteShell(result % ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions, "objfiles", objfiles,
|
||||
"exefile", exefile, "nim", getPrefixDir(), "lib", libpath])
|
||||
"exefile", exefile, "nim", getPrefixDir(conf), "lib", conf.libpath])
|
||||
result.add ' '
|
||||
addf(result, linkTmpl, ["builddll", builddll,
|
||||
"buildgui", buildgui, "options", linkOptions,
|
||||
"objfiles", objfiles, "exefile", exefile,
|
||||
"nim", quoteShell(getPrefixDir()),
|
||||
"lib", quoteShell(libpath)])
|
||||
"nim", quoteShell(getPrefixDir(conf)),
|
||||
"lib", quoteShell(conf.libpath)])
|
||||
|
||||
template tryExceptOSErrorMessage(errorPrefix: string = "", body: untyped): typed =
|
||||
template tryExceptOSErrorMessage(conf: ConfigRef; errorPrefix: string = "", body: untyped): typed =
|
||||
try:
|
||||
body
|
||||
except OSError:
|
||||
let ose = (ref OSError)(getCurrentException())
|
||||
if errorPrefix.len > 0:
|
||||
rawMessage(errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
|
||||
rawMessage(conf, errGenerated, errorPrefix & " " & ose.msg & " " & $ose.errorCode)
|
||||
else:
|
||||
rawMessage(errExecutionOfProgramFailed, ose.msg & " " & $ose.errorCode)
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
(ose.msg & " " & $ose.errorCode))
|
||||
raise
|
||||
|
||||
proc execLinkCmd(linkCmd: string) =
|
||||
tryExceptOSErrorMessage("invocation of external linker program failed."):
|
||||
execExternalProgram(linkCmd,
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 1: hintExecuting else: hintLinking)
|
||||
proc execLinkCmd(conf: ConfigRef; linkCmd: string) =
|
||||
tryExceptOSErrorMessage(conf, "invocation of external linker program failed."):
|
||||
execExternalProgram(conf, linkCmd,
|
||||
if optListCmd in conf.globalOptions or conf.verbosity > 1: hintExecuting else: hintLinking)
|
||||
|
||||
proc execCmdsInParallel(cmds: seq[string]; prettyCb: proc (idx: int)) =
|
||||
proc execCmdsInParallel(conf: ConfigRef; cmds: seq[string]; prettyCb: proc (idx: int)) =
|
||||
let runCb = proc (idx: int, p: Process) =
|
||||
let exitCode = p.peekExitCode
|
||||
if exitCode != 0:
|
||||
rawMessage(errGenerated, "execution of an external compiler program '" &
|
||||
rawMessage(conf, errGenerated, "execution of an external compiler program '" &
|
||||
cmds[idx] & "' failed with exit code: " & $exitCode & "\n\n" &
|
||||
p.outputStream.readAll.strip)
|
||||
if gNumberOfProcessors == 0: gNumberOfProcessors = countProcessors()
|
||||
if conf.numberOfProcessors == 0: conf.numberOfProcessors = countProcessors()
|
||||
var res = 0
|
||||
if gNumberOfProcessors <= 1:
|
||||
if conf.numberOfProcessors <= 1:
|
||||
for i in countup(0, high(cmds)):
|
||||
tryExceptOSErrorMessage("invocation of external compiler program failed."):
|
||||
res = execWithEcho(cmds[i])
|
||||
if res != 0: rawMessage(errExecutionOfProgramFailed, cmds[i])
|
||||
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
|
||||
res = execWithEcho(conf, cmds[i])
|
||||
if res != 0:
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
cmds[i])
|
||||
else:
|
||||
tryExceptOSErrorMessage("invocation of external compiler program failed."):
|
||||
if optListCmd in gGlobalOptions or gVerbosity > 1:
|
||||
tryExceptOSErrorMessage(conf, "invocation of external compiler program failed."):
|
||||
if optListCmd in conf.globalOptions or conf.verbosity > 1:
|
||||
res = execProcesses(cmds, {poEchoCmd, poStdErrToStdOut, poUsePath},
|
||||
gNumberOfProcessors, afterRunEvent=runCb)
|
||||
elif gVerbosity == 1:
|
||||
conf.numberOfProcessors, afterRunEvent=runCb)
|
||||
elif conf.verbosity == 1:
|
||||
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
|
||||
gNumberOfProcessors, prettyCb, afterRunEvent=runCb)
|
||||
conf.numberOfProcessors, prettyCb, afterRunEvent=runCb)
|
||||
else:
|
||||
res = execProcesses(cmds, {poStdErrToStdOut, poUsePath},
|
||||
gNumberOfProcessors, afterRunEvent=runCb)
|
||||
conf.numberOfProcessors, afterRunEvent=runCb)
|
||||
if res != 0:
|
||||
if gNumberOfProcessors <= 1:
|
||||
rawMessage(errExecutionOfProgramFailed, cmds.join())
|
||||
if conf.numberOfProcessors <= 1:
|
||||
rawMessage(conf, errGenerated, "execution of an external program failed: '$1'" %
|
||||
cmds.join())
|
||||
|
||||
proc callCCompiler*(projectfile: string) =
|
||||
proc callCCompiler*(conf: ConfigRef; projectfile: string) =
|
||||
var
|
||||
linkCmd: string
|
||||
if gGlobalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
if conf.globalOptions * {optCompileOnly, optGenScript} == {optCompileOnly}:
|
||||
return # speed up that call if only compiling and no script shall be
|
||||
# generated
|
||||
#var c = cCompiler
|
||||
@@ -758,36 +766,36 @@ proc callCCompiler*(projectfile: string) =
|
||||
var prettyCmds: TStringSeq = @[]
|
||||
let prettyCb = proc (idx: int) =
|
||||
echo prettyCmds[idx]
|
||||
compileCFile(toCompile, script, cmds, prettyCmds)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
execCmdsInParallel(cmds, prettyCb)
|
||||
if optNoLinking notin gGlobalOptions:
|
||||
compileCFile(conf, toCompile, script, cmds, prettyCmds)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
execCmdsInParallel(conf, cmds, prettyCb)
|
||||
if optNoLinking notin conf.globalOptions:
|
||||
# call the linker:
|
||||
var objfiles = ""
|
||||
for it in externalToLink:
|
||||
let objFile = if noAbsolutePaths(): it.extractFilename else: it
|
||||
let objFile = if noAbsolutePaths(conf): it.extractFilename else: it
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteShell(
|
||||
addFileExt(objFile, CC[cCompiler].objExt)))
|
||||
for x in toCompile:
|
||||
let objFile = if noAbsolutePaths(): x.obj.extractFilename else: x.obj
|
||||
let objFile = if noAbsolutePaths(conf): x.obj.extractFilename else: x.obj
|
||||
add(objfiles, ' ')
|
||||
add(objfiles, quoteShell(objFile))
|
||||
|
||||
linkCmd = getLinkCmd(projectfile, objfiles)
|
||||
if optCompileOnly notin gGlobalOptions:
|
||||
execLinkCmd(linkCmd)
|
||||
linkCmd = getLinkCmd(conf, projectfile, objfiles)
|
||||
if optCompileOnly notin conf.globalOptions:
|
||||
execLinkCmd(conf, linkCmd)
|
||||
else:
|
||||
linkCmd = ""
|
||||
if optGenScript in gGlobalOptions:
|
||||
if optGenScript in conf.globalOptions:
|
||||
add(script, linkCmd)
|
||||
add(script, tnl)
|
||||
generateScript(projectfile, script)
|
||||
generateScript(conf, projectfile, script)
|
||||
|
||||
#from json import escapeJson
|
||||
import json
|
||||
|
||||
proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
proc writeJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
template lit(x: untyped) = f.write x
|
||||
template str(x: untyped) =
|
||||
when compiles(escapeJson(x, buf)):
|
||||
@@ -797,11 +805,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
else:
|
||||
f.write escapeJson(x)
|
||||
|
||||
proc cfiles(f: File; buf: var string; clist: CfileList, isExternal: bool) =
|
||||
proc cfiles(conf: ConfigRef; f: File; buf: var string; clist: CfileList, isExternal: bool) =
|
||||
var pastStart = false
|
||||
for it in clist:
|
||||
if CfileFlag.Cached in it.flags: continue
|
||||
let compileCmd = getCompileCFileCmd(it)
|
||||
let compileCmd = getCompileCFileCmd(conf, it)
|
||||
if pastStart: lit "],\L"
|
||||
lit "["
|
||||
str it.cname
|
||||
@@ -810,11 +818,11 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
pastStart = true
|
||||
lit "]\L"
|
||||
|
||||
proc linkfiles(f: File; buf, objfiles: var string; clist: CfileList;
|
||||
proc linkfiles(conf: ConfigRef; f: File; buf, objfiles: var string; clist: CfileList;
|
||||
llist: seq[string]) =
|
||||
var pastStart = false
|
||||
for it in llist:
|
||||
let objfile = if noAbsolutePaths(): it.extractFilename
|
||||
let objfile = if noAbsolutePaths(conf): it.extractFilename
|
||||
else: it
|
||||
let objstr = addFileExt(objfile, CC[cCompiler].objExt)
|
||||
add(objfiles, ' ')
|
||||
@@ -835,25 +843,25 @@ proc writeJsonBuildInstructions*(projectfile: string) =
|
||||
var buf = newStringOfCap(50)
|
||||
|
||||
let file = projectfile.splitFile.name
|
||||
let jsonFile = toGeneratedFile(file, "json")
|
||||
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||
|
||||
var f: File
|
||||
if open(f, jsonFile, fmWrite):
|
||||
lit "{\"compile\":[\L"
|
||||
cfiles(f, buf, toCompile, false)
|
||||
cfiles(conf, f, buf, toCompile, false)
|
||||
lit "],\L\"link\":[\L"
|
||||
var objfiles = ""
|
||||
# XXX add every file here that is to link
|
||||
linkfiles(f, buf, objfiles, toCompile, externalToLink)
|
||||
linkfiles(conf, f, buf, objfiles, toCompile, externalToLink)
|
||||
|
||||
lit "],\L\"linkcmd\": "
|
||||
str getLinkCmd(projectfile, objfiles)
|
||||
str getLinkCmd(conf, projectfile, objfiles)
|
||||
lit "\L}\L"
|
||||
close(f)
|
||||
|
||||
proc runJsonBuildInstructions*(projectfile: string) =
|
||||
proc runJsonBuildInstructions*(conf: ConfigRef; projectfile: string) =
|
||||
let file = projectfile.splitFile.name
|
||||
let jsonFile = toGeneratedFile(file, "json")
|
||||
let jsonFile = toGeneratedFile(conf, file, "json")
|
||||
try:
|
||||
let data = json.parseFile(jsonFile)
|
||||
let toCompile = data["compile"]
|
||||
@@ -870,32 +878,32 @@ proc runJsonBuildInstructions*(projectfile: string) =
|
||||
|
||||
let prettyCb = proc (idx: int) =
|
||||
echo prettyCmds[idx]
|
||||
execCmdsInParallel(cmds, prettyCb)
|
||||
execCmdsInParallel(conf, cmds, prettyCb)
|
||||
|
||||
let linkCmd = data["linkcmd"]
|
||||
doAssert linkCmd.kind == JString
|
||||
execLinkCmd(linkCmd.getStr)
|
||||
execLinkCmd(conf, linkCmd.getStr)
|
||||
except:
|
||||
echo getCurrentException().getStackTrace()
|
||||
quit "error evaluating JSON file: " & jsonFile
|
||||
|
||||
proc genMappingFiles(list: CFileList): Rope =
|
||||
proc genMappingFiles(conf: ConfigRef; list: CFileList): Rope =
|
||||
for it in list:
|
||||
addf(result, "--file:r\"$1\"$N", [rope(it.cname)])
|
||||
|
||||
proc writeMapping*(gSymbolMapping: Rope) =
|
||||
if optGenMapping notin gGlobalOptions: return
|
||||
proc writeMapping*(conf: ConfigRef; symbolMapping: Rope) =
|
||||
if optGenMapping notin conf.globalOptions: return
|
||||
var code = rope("[C_Files]\n")
|
||||
add(code, genMappingFiles(toCompile))
|
||||
add(code, genMappingFiles(conf, toCompile))
|
||||
add(code, "\n[C_Compiler]\nFlags=")
|
||||
add(code, strutils.escape(getCompileOptions()))
|
||||
add(code, strutils.escape(getCompileOptions(conf)))
|
||||
|
||||
add(code, "\n[Linker]\nFlags=")
|
||||
add(code, strutils.escape(getLinkOptions() & " " &
|
||||
getConfigVar(cCompiler, ".options.linker")))
|
||||
add(code, strutils.escape(getLinkOptions(conf) & " " &
|
||||
getConfigVar(conf, cCompiler, ".options.linker")))
|
||||
|
||||
add(code, "\n[Environment]\nlibpath=")
|
||||
add(code, strutils.escape(libpath))
|
||||
add(code, strutils.escape(conf.libpath))
|
||||
|
||||
addf(code, "\n[Symbols]$n$1", [gSymbolMapping])
|
||||
writeRope(code, joinPath(gProjectPath, "mapping.txt"))
|
||||
addf(code, "\n[Symbols]$n$1", [symbolMapping])
|
||||
writeRope(code, joinPath(conf.projectPath, "mapping.txt"))
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 & ')')
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, magicsys, rodread, lowerings, tables
|
||||
idents, renderer, types, magicsys, rodread, lowerings, tables,
|
||||
modulegraphs
|
||||
|
||||
discard """
|
||||
The basic approach is that captured vars need to be put on the heap and
|
||||
@@ -125,32 +126,32 @@ proc newCall(a: PSym, b: PNode): PNode =
|
||||
result.add newSymNode(a)
|
||||
result.add b
|
||||
|
||||
proc createStateType(iter: PSym): PType =
|
||||
proc createStateType(g: ModuleGraph; iter: PSym): PType =
|
||||
var n = newNodeI(nkRange, iter.info)
|
||||
addSon(n, newIntNode(nkIntLit, -1))
|
||||
addSon(n, newIntNode(nkIntLit, 0))
|
||||
result = newType(tyRange, iter)
|
||||
result.n = n
|
||||
var intType = nilOrSysInt()
|
||||
var intType = nilOrSysInt(g)
|
||||
if intType.isNil: intType = newType(tyInt, iter)
|
||||
rawAddSon(result, intType)
|
||||
|
||||
proc createStateField(iter: PSym): PSym =
|
||||
result = newSym(skField, getIdent(":state"), iter, iter.info)
|
||||
result.typ = createStateType(iter)
|
||||
proc createStateField(g: ModuleGraph; iter: PSym): PSym =
|
||||
result = newSym(skField, getIdent(":state"), iter, iter.info, {})
|
||||
result.typ = createStateType(g, iter)
|
||||
|
||||
proc createEnvObj(owner: PSym; info: TLineInfo): PType =
|
||||
proc createEnvObj(g: ModuleGraph; owner: PSym; info: TLineInfo): PType =
|
||||
# YYY meh, just add the state field for every closure for now, it's too
|
||||
# hard to figure out if it comes from a closure iterator:
|
||||
result = createObj(owner, info, final=false)
|
||||
rawAddField(result, createStateField(owner))
|
||||
result = createObj(g, owner, info, final=false)
|
||||
rawAddField(result, createStateField(g, owner))
|
||||
|
||||
proc getIterResult(iter: PSym): PSym =
|
||||
if resultPos < iter.ast.len:
|
||||
result = iter.ast.sons[resultPos].sym
|
||||
else:
|
||||
# XXX a bit hacky:
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info)
|
||||
result = newSym(skResult, getIdent":result", iter, iter.info, {})
|
||||
result.typ = iter.typ.sons[0]
|
||||
incl(result.flags, sfUsed)
|
||||
iter.ast.add newSymNode(result)
|
||||
@@ -166,7 +167,7 @@ proc addHiddenParam(routine: PSym, param: PSym) =
|
||||
assert sfFromGeneric in param.flags
|
||||
#echo "produced environment: ", param.id, " for ", routine.id
|
||||
|
||||
proc getHiddenParam(routine: PSym): PSym =
|
||||
proc getHiddenParam(g: ModuleGraph; routine: PSym): PSym =
|
||||
let params = routine.ast.sons[paramsPos]
|
||||
let hidden = lastSon(params)
|
||||
if hidden.kind == nkSym and hidden.sym.kind == skParam and hidden.sym.name.s == paramName:
|
||||
@@ -174,7 +175,7 @@ proc getHiddenParam(routine: PSym): PSym =
|
||||
assert sfFromGeneric in result.flags
|
||||
else:
|
||||
# writeStackTrace()
|
||||
localError(routine.info, "internal error: could not find env param for " & routine.name.s)
|
||||
localError(g.config, routine.info, "internal error: could not find env param for " & routine.name.s)
|
||||
result = routine
|
||||
|
||||
proc getEnvParam*(routine: PSym): PSym =
|
||||
@@ -208,14 +209,14 @@ proc newAsgnStmt(le, ri: PNode, info: TLineInfo): PNode =
|
||||
result.sons[0] = le
|
||||
result.sons[1] = ri
|
||||
|
||||
proc makeClosure*(prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
proc makeClosure*(g: ModuleGraph; prc: PSym; env: PNode; info: TLineInfo): PNode =
|
||||
result = newNodeIT(nkClosure, info, prc.typ)
|
||||
result.add(newSymNode(prc))
|
||||
if env == nil:
|
||||
result.add(newNodeIT(nkNilLit, info, getSysType(tyNil)))
|
||||
result.add(newNodeIT(nkNilLit, info, getSysType(g, info, tyNil)))
|
||||
else:
|
||||
if env.skipConv.kind == nkClosure:
|
||||
localError(info, "internal error: taking closure of closure")
|
||||
localError(g.config, info, "internal error: taking closure of closure")
|
||||
result.add(env)
|
||||
|
||||
proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
@@ -227,23 +228,23 @@ proc interestingIterVar(s: PSym): bool {.inline.} =
|
||||
template isIterator*(owner: PSym): bool =
|
||||
owner.kind == skIterator and owner.typ.callConv == ccClosure
|
||||
|
||||
proc liftingHarmful(owner: PSym): bool {.inline.} =
|
||||
proc liftingHarmful(conf: ConfigRef; owner: PSym): bool {.inline.} =
|
||||
## lambda lifting can be harmful for JS-like code generators.
|
||||
let isCompileTime = sfCompileTime in owner.flags or owner.kind == skMacro
|
||||
result = gCmd == cmdCompileToJS and not isCompileTime
|
||||
result = conf.cmd == cmdCompileToJS and not isCompileTime
|
||||
|
||||
proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
||||
proc liftIterSym*(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
# transforms (iter) to (let env = newClosure[iter](); (iter, env))
|
||||
if liftingHarmful(owner): return n
|
||||
if liftingHarmful(g.config, owner): return n
|
||||
let iter = n.sym
|
||||
assert iter.isIterator
|
||||
|
||||
result = newNodeIT(nkStmtListExpr, n.info, n.typ)
|
||||
|
||||
let hp = getHiddenParam(iter)
|
||||
let hp = getHiddenParam(g, iter)
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(owner)
|
||||
let it = getHiddenParam(g, owner)
|
||||
addUniqueField(it.typ.sons[0], hp)
|
||||
env = indirectAccess(newSymNode(it), hp, hp.info)
|
||||
else:
|
||||
@@ -255,11 +256,11 @@ proc liftIterSym*(n: PNode; owner: PSym): PNode =
|
||||
addVar(v, env)
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add newCall(getSysSym"internalNew", env)
|
||||
result.add makeClosure(iter, env, n.info)
|
||||
result.add newCall(getSysSym(g, n.info, "internalNew"), env)
|
||||
result.add makeClosure(g, iter, env, n.info)
|
||||
|
||||
proc freshVarForClosureIter*(s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(owner)
|
||||
proc freshVarForClosureIter*(g: ModuleGraph; s, owner: PSym): PNode =
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
let obj = envParam.typ.lastSon
|
||||
addField(obj, s)
|
||||
|
||||
@@ -269,18 +270,18 @@ proc freshVarForClosureIter*(s, owner: PSym): PNode =
|
||||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, s.info)
|
||||
else:
|
||||
localError(s.info, "internal error: cannot generate fresh variable")
|
||||
localError(g.config, s.info, "internal error: cannot generate fresh variable")
|
||||
result = access
|
||||
|
||||
# ------------------ new stuff -------------------------------------------
|
||||
|
||||
proc markAsClosure(owner: PSym; n: PNode) =
|
||||
proc markAsClosure(g: ModuleGraph; owner: PSym; n: PNode) =
|
||||
let s = n.sym
|
||||
if illegalCapture(s):
|
||||
localError(n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
|
||||
localError(g.config, n.info, "illegal capture '$1' of type <$2> which is declared here: $3" %
|
||||
[s.name.s, typeToString(s.typ), $s.info])
|
||||
elif owner.typ.callConv notin {ccClosure, ccDefault}:
|
||||
localError(n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
localError(g.config, n.info, "illegal capture '$1' because '$2' has the calling convention: <$3>" %
|
||||
[s.name.s, owner.name.s, CallingConvToStr[owner.typ.callConv]])
|
||||
incl(owner.typ.flags, tfCapturesEnv)
|
||||
owner.typ.callConv = ccClosure
|
||||
@@ -290,12 +291,14 @@ type
|
||||
processed, capturedVars: IntSet
|
||||
ownerToType: Table[int, PType]
|
||||
somethingToDo: bool
|
||||
graph: ModuleGraph
|
||||
|
||||
proc initDetectionPass(fn: PSym): DetectionPass =
|
||||
proc initDetectionPass(g: ModuleGraph; fn: PSym): DetectionPass =
|
||||
result.processed = initIntSet()
|
||||
result.capturedVars = initIntSet()
|
||||
result.ownerToType = initTable[int, PType]()
|
||||
result.processed.incl(fn.id)
|
||||
result.graph = g
|
||||
|
||||
discard """
|
||||
proc outer =
|
||||
@@ -312,7 +315,7 @@ proc getEnvTypeForOwner(c: var DetectionPass; owner: PSym;
|
||||
result = c.ownerToType.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
result = newType(tyRef, owner)
|
||||
let obj = createEnvObj(owner, info)
|
||||
let obj = createEnvObj(c.graph, owner, info)
|
||||
rawAddSon(result, obj)
|
||||
c.ownerToType[owner.id] = result
|
||||
|
||||
@@ -321,13 +324,13 @@ proc createUpField(c: var DetectionPass; dest, dep: PSym; info: TLineInfo) =
|
||||
let obj = refObj.lastSon
|
||||
let fieldType = c.getEnvTypeForOwner(dep, info) #getHiddenParam(dep).typ
|
||||
if refObj == fieldType:
|
||||
localError(dep.info, "internal error: invalid up reference computed")
|
||||
localError(c.graph.config, dep.info, "internal error: invalid up reference computed")
|
||||
|
||||
let upIdent = getIdent(upName)
|
||||
let upField = lookupInRecord(obj.n, upIdent)
|
||||
if upField != nil:
|
||||
if upField.typ != fieldType:
|
||||
localError(dep.info, "internal error: up references do not agree")
|
||||
localError(c.graph.config, dep.info, "internal error: up references do not agree")
|
||||
else:
|
||||
let result = newSym(skField, upIdent, obj.owner, obj.owner.info)
|
||||
result.typ = fieldType
|
||||
@@ -369,7 +372,7 @@ proc addClosureParam(c: var DetectionPass; fn: PSym; info: TLineInfo) =
|
||||
cp.typ = t
|
||||
addHiddenParam(fn, cp)
|
||||
elif cp.typ != t and fn.kind != skIterator:
|
||||
localError(fn.info, "internal error: inconsistent environment type")
|
||||
localError(c.graph.config, fn.info, "internal error: inconsistent environment type")
|
||||
#echo "adding closure to ", fn.name.s
|
||||
|
||||
proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
@@ -395,7 +398,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
addClosureParam(c, owner, n.info)
|
||||
if interestingIterVar(s):
|
||||
if not c.capturedVars.containsOrIncl(s.id):
|
||||
let obj = getHiddenParam(owner).typ.lastSon
|
||||
let obj = getHiddenParam(c.graph, owner).typ.lastSon
|
||||
#let obj = c.getEnvTypeForOwner(s.owner).lastSon
|
||||
addField(obj, s)
|
||||
# but always return because the rest of the proc is only relevant when
|
||||
@@ -415,7 +418,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
"""
|
||||
# mark 'owner' as taking a closure:
|
||||
c.somethingToDo = true
|
||||
markAsClosure(owner, n)
|
||||
markAsClosure(c.graph, owner, n)
|
||||
addClosureParam(c, owner, n.info)
|
||||
#echo "capturing ", n.info
|
||||
# variable 's' is actually captured:
|
||||
@@ -440,7 +443,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
"""
|
||||
let up = w.skipGenericOwner
|
||||
#echo "up for ", w.name.s, " up ", up.name.s
|
||||
markAsClosure(w, n)
|
||||
markAsClosure(c.graph, w, n)
|
||||
addClosureParam(c, w, n.info) # , ow
|
||||
createUpField(c, w, up, n.info)
|
||||
w = up
|
||||
@@ -467,10 +470,10 @@ proc initLiftingPass(fn: PSym): LiftingPass =
|
||||
result.processed.incl(fn.id)
|
||||
result.envVars = initTable[int, PNode]()
|
||||
|
||||
proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
|
||||
proc accessViaEnvParam(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
let s = n.sym
|
||||
# Type based expression construction for simplicity:
|
||||
let envParam = getHiddenParam(owner)
|
||||
let envParam = getHiddenParam(g, owner)
|
||||
if not envParam.isNil:
|
||||
var access = newSymNode(envParam)
|
||||
while true:
|
||||
@@ -482,7 +485,7 @@ proc accessViaEnvParam(n: PNode; owner: PSym): PNode =
|
||||
let upField = lookupInRecord(obj.n, getIdent(upName))
|
||||
if upField == nil: break
|
||||
access = rawIndirectAccess(access, upField, n.info)
|
||||
localError(n.info, "internal error: environment misses: " & s.name.s)
|
||||
localError(g.config, n.info, "internal error: environment misses: " & s.name.s)
|
||||
result = n
|
||||
|
||||
proc newEnvVar(owner: PSym; typ: PType): PNode =
|
||||
@@ -501,22 +504,22 @@ proc newEnvVar(owner: PSym; typ: PType): PNode =
|
||||
proc setupEnvVar(owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
if owner.isIterator:
|
||||
return getHiddenParam(owner).newSymNode
|
||||
return getHiddenParam(d.graph, owner).newSymNode
|
||||
result = c.envvars.getOrDefault(owner.id)
|
||||
if result.isNil:
|
||||
let envVarType = d.ownerToType.getOrDefault(owner.id)
|
||||
if envVarType.isNil:
|
||||
localError owner.info, "internal error: could not determine closure type"
|
||||
localError d.graph.config, owner.info, "internal error: could not determine closure type"
|
||||
result = newEnvVar(owner, envVarType)
|
||||
c.envVars[owner.id] = result
|
||||
|
||||
proc getUpViaParam(owner: PSym): PNode =
|
||||
let p = getHiddenParam(owner)
|
||||
proc getUpViaParam(g: ModuleGraph; owner: PSym): PNode =
|
||||
let p = getHiddenParam(g, owner)
|
||||
result = p.newSymNode
|
||||
if owner.isIterator:
|
||||
let upField = lookupInRecord(p.typ.lastSon.n, getIdent(upName))
|
||||
if upField == nil:
|
||||
localError(owner.info, "could not find up reference for closure iter")
|
||||
localError(g.config, owner.info, "could not find up reference for closure iter")
|
||||
else:
|
||||
result = rawIndirectAccess(result, upField, p.info)
|
||||
|
||||
@@ -526,7 +529,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
|
||||
var env: PNode
|
||||
if owner.isIterator:
|
||||
env = getHiddenParam(owner).newSymNode
|
||||
env = getHiddenParam(d.graph, owner).newSymNode
|
||||
else:
|
||||
env = setupEnvVar(owner, d, c)
|
||||
if env.kind == nkSym:
|
||||
@@ -534,7 +537,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
addVar(v, env)
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env))
|
||||
result.add(newCall(getSysSym(d.graph, env.info, "internalNew"), env))
|
||||
# add assignment statements for captured parameters:
|
||||
for i in 1..<owner.typ.n.len:
|
||||
let local = owner.typ.n[i].sym
|
||||
@@ -545,7 +548,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
|
||||
let upField = lookupInRecord(env.typ.lastSon.n, getIdent(upName))
|
||||
if upField != nil:
|
||||
let up = getUpViaParam(owner)
|
||||
let up = getUpViaParam(d.graph, owner)
|
||||
if up != nil and upField.typ == up.typ:
|
||||
result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
up, env.info))
|
||||
@@ -553,7 +556,7 @@ proc rawClosureCreation(owner: PSym;
|
||||
# result.add(newAsgnStmt(rawIndirectAccess(env, upField, env.info),
|
||||
# oldenv, env.info))
|
||||
else:
|
||||
localError(env.info, "internal error: cannot create up reference")
|
||||
localError(d.graph.config, env.info, "internal error: cannot create up reference")
|
||||
|
||||
proc closureCreationForIter(iter: PNode;
|
||||
d: DetectionPass; c: var LiftingPass): PNode =
|
||||
@@ -561,10 +564,10 @@ proc closureCreationForIter(iter: PNode;
|
||||
let owner = iter.sym.skipGenericOwner
|
||||
var v = newSym(skVar, getIdent(envName), owner, iter.info)
|
||||
incl(v.flags, sfShadowed)
|
||||
v.typ = getHiddenParam(iter.sym).typ
|
||||
v.typ = getHiddenParam(d.graph, iter.sym).typ
|
||||
var vnode: PNode
|
||||
if owner.isIterator:
|
||||
let it = getHiddenParam(owner)
|
||||
let it = getHiddenParam(d.graph, owner)
|
||||
addUniqueField(it.typ.sons[0], v)
|
||||
vnode = indirectAccess(newSymNode(it), v, v.info)
|
||||
else:
|
||||
@@ -572,7 +575,7 @@ proc closureCreationForIter(iter: PNode;
|
||||
var vs = newNodeI(nkVarSection, iter.info)
|
||||
addVar(vs, vnode)
|
||||
result.add(vs)
|
||||
result.add(newCall(getSysSym"internalNew", vnode))
|
||||
result.add(newCall(getSysSym(d.graph, iter.info, "internalNew"), vnode))
|
||||
|
||||
let upField = lookupInRecord(v.typ.lastSon.n, getIdent(upName))
|
||||
if upField != nil:
|
||||
@@ -581,8 +584,8 @@ proc closureCreationForIter(iter: PNode;
|
||||
result.add(newAsgnStmt(rawIndirectAccess(vnode, upField, iter.info),
|
||||
u, iter.info))
|
||||
else:
|
||||
localError(iter.info, "internal error: cannot create up reference for iter")
|
||||
result.add makeClosure(iter.sym, vnode, iter.info)
|
||||
localError(d.graph.config, iter.info, "internal error: cannot create up reference for iter")
|
||||
result.add makeClosure(d.graph, iter.sym, vnode, iter.info)
|
||||
|
||||
proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
@@ -592,11 +595,11 @@ proc accessViaEnvVar(n: PNode; owner: PSym; d: DetectionPass;
|
||||
if field != nil:
|
||||
result = rawIndirectAccess(access, field, n.info)
|
||||
else:
|
||||
localError(n.info, "internal error: not part of closure object type")
|
||||
localError(d.graph.config, n.info, "internal error: not part of closure object type")
|
||||
result = n
|
||||
|
||||
proc getStateField(owner: PSym): PSym =
|
||||
getHiddenParam(owner).typ.sons[0].n.sons[0].sym
|
||||
proc getStateField(g: ModuleGraph; owner: PSym): PSym =
|
||||
getHiddenParam(g, owner).typ.sons[0].n.sons[0].sym
|
||||
|
||||
proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode
|
||||
@@ -604,8 +607,8 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
if c.inContainer > 0:
|
||||
localError(n.info, "invalid control flow: 'yield' within a constructor")
|
||||
let state = getStateField(owner)
|
||||
localError(d.graph.config, n.info, "invalid control flow: 'yield' within a constructor")
|
||||
let state = getStateField(d.graph, owner)
|
||||
assert state != nil
|
||||
assert state.typ != nil
|
||||
assert state.typ.n != nil
|
||||
@@ -615,7 +618,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
|
||||
state, n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, stateNo,
|
||||
getSysType(d.graph, n.info, tyInt)))
|
||||
|
||||
var retStmt = newNodeI(nkReturnStmt, n.info)
|
||||
if n.sons[0].kind != nkEmpty:
|
||||
@@ -628,7 +632,8 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
||||
retStmt.add(emptyNode)
|
||||
|
||||
var stateLabelStmt = newNodeI(nkState, n.info)
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo, getSysType(tyInt)))
|
||||
stateLabelStmt.add(newIntTypeNode(nkIntLit, stateNo,
|
||||
getSysType(d.graph, n.info, tyInt)))
|
||||
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
result.add(stateAsgnStmt)
|
||||
@@ -637,16 +642,16 @@ proc transformYield(n: PNode; owner: PSym; d: DetectionPass;
|
||||
|
||||
proc transformReturn(n: PNode; owner: PSym; d: DetectionPass;
|
||||
c: var LiftingPass): PNode =
|
||||
let state = getStateField(owner)
|
||||
let state = getStateField(d.graph, owner)
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, n.info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getEnvParam(owner)),
|
||||
state, n.info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(d.graph, n.info, tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
result.add(n)
|
||||
|
||||
proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
||||
proc wrapIterBody(g: ModuleGraph; n: PNode; owner: PSym): PNode =
|
||||
if not owner.isIterator: return n
|
||||
when false:
|
||||
# unfortunately control flow is still convoluted and we can end up
|
||||
@@ -660,7 +665,7 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
||||
let info = n.info
|
||||
result = newNodeI(nkStmtList, info)
|
||||
var gs = newNodeI(nkGotoState, info)
|
||||
gs.add(rawIndirectAccess(newSymNode(owner.getHiddenParam), getStateField(owner), info))
|
||||
gs.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)), getStateField(g, owner), info))
|
||||
result.add(gs)
|
||||
var state0 = newNodeI(nkState, info)
|
||||
state0.add(newIntNode(nkIntLit, 0))
|
||||
@@ -669,9 +674,9 @@ proc wrapIterBody(n: PNode; owner: PSym): PNode =
|
||||
result.add(n)
|
||||
|
||||
var stateAsgnStmt = newNodeI(nkAsgn, info)
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(owner.getHiddenParam),
|
||||
getStateField(owner), info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(tyInt)))
|
||||
stateAsgnStmt.add(rawIndirectAccess(newSymNode(getHiddenParam(g, owner)),
|
||||
getStateField(g, owner), info))
|
||||
stateAsgnStmt.add(newIntTypeNode(nkIntLit, -1, getSysType(g, info, tyInt)))
|
||||
result.add(stateAsgnStmt)
|
||||
|
||||
proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
@@ -679,25 +684,25 @@ proc symToClosure(n: PNode; owner: PSym; d: DetectionPass;
|
||||
let s = n.sym
|
||||
if s == owner:
|
||||
# recursive calls go through (lambda, hiddenParam):
|
||||
let available = getHiddenParam(owner)
|
||||
result = makeClosure(s, available.newSymNode, n.info)
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
result = makeClosure(d.graph, s, available.newSymNode, n.info)
|
||||
elif s.isIterator:
|
||||
result = closureCreationForIter(n, d, c)
|
||||
elif s.skipGenericOwner == owner:
|
||||
# direct dependency, so use the outer's env variable:
|
||||
result = makeClosure(s, setupEnvVar(owner, d, c), n.info)
|
||||
result = makeClosure(d.graph, s, setupEnvVar(owner, d, c), n.info)
|
||||
else:
|
||||
let available = getHiddenParam(owner)
|
||||
let wanted = getHiddenParam(s).typ
|
||||
let available = getHiddenParam(d.graph, owner)
|
||||
let wanted = getHiddenParam(d.graph, s).typ
|
||||
# ugh: call through some other inner proc;
|
||||
var access = newSymNode(available)
|
||||
while true:
|
||||
if access.typ == wanted:
|
||||
return makeClosure(s, access, n.info)
|
||||
return makeClosure(d.graph, s, access, n.info)
|
||||
let obj = access.typ.sons[0]
|
||||
let upField = lookupInRecord(obj.n, getIdent(upName))
|
||||
if upField == nil:
|
||||
localError(n.info, "internal error: no environment found")
|
||||
localError(d.graph.config, n.info, "internal error: no environment found")
|
||||
return n
|
||||
access = rawIndirectAccess(access, upField, n.info)
|
||||
|
||||
@@ -713,7 +718,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
let body = wrapIterBody(liftCapturedVars(s.getBody, s, d, c), s)
|
||||
let body = wrapIterBody(d.graph, liftCapturedVars(s.getBody, s, d, c), s)
|
||||
if c.envvars.getOrDefault(s.id).isNil:
|
||||
s.ast.sons[bodyPos] = body
|
||||
else:
|
||||
@@ -723,9 +728,9 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: DetectionPass;
|
||||
result = symToClosure(n, owner, d, c)
|
||||
elif s.id in d.capturedVars:
|
||||
if s.owner != owner:
|
||||
result = accessViaEnvParam(n, owner)
|
||||
result = accessViaEnvParam(d.graph, n, owner)
|
||||
elif owner.isIterator and interestingIterVar(s):
|
||||
result = accessViaEnvParam(n, owner)
|
||||
result = accessViaEnvParam(d.graph, n, owner)
|
||||
else:
|
||||
result = accessViaEnvVar(n, owner, d, c)
|
||||
of nkEmpty..pred(nkSym), succ(nkSym)..nkNilLit, nkComesFrom,
|
||||
@@ -791,8 +796,8 @@ proc semCaptureSym*(s, owner: PSym) =
|
||||
# since the analysis is not entirely correct, we don't set 'tfCapturesEnv'
|
||||
# here
|
||||
|
||||
proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||
var d = initDetectionPass(fn)
|
||||
proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||
var d = initDetectionPass(g, fn)
|
||||
var c = initLiftingPass(fn)
|
||||
# pretend 'fn' is a closure iterator for the analysis:
|
||||
let oldKind = fn.kind
|
||||
@@ -801,25 +806,25 @@ proc liftIterToProc*(fn: PSym; body: PNode; ptrType: PType): PNode =
|
||||
fn.typ.callConv = ccClosure
|
||||
d.ownerToType[fn.id] = ptrType
|
||||
detectCapturedVars(body, fn, d)
|
||||
result = wrapIterBody(liftCapturedVars(body, fn, d, c), fn)
|
||||
result = wrapIterBody(g, liftCapturedVars(body, fn, d, c), fn)
|
||||
fn.kind = oldKind
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
# XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
# XXX conf.cmd == cmdCompileToJS does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
# However we can do lifting for the stuff which is *only* compiletime.
|
||||
let isCompileTime = sfCompileTime in fn.flags or fn.kind == skMacro
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
gCmd == cmdCompileToJS and not isCompileTime) or
|
||||
g.config.cmd == cmdCompileToJS and not isCompileTime) or
|
||||
fn.skipGenericOwner.kind != skModule:
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
tooEarly = true
|
||||
else:
|
||||
var d = initDetectionPass(fn)
|
||||
var d = initDetectionPass(g, fn)
|
||||
detectCapturedVars(body, fn, d)
|
||||
if not d.somethingToDo and fn.isIterator:
|
||||
addClosureParam(d, fn, body.info)
|
||||
@@ -829,7 +834,7 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
var newBody = liftCapturedVars(body, fn, d, c)
|
||||
if c.envvars.getOrDefault(fn.id) != nil:
|
||||
newBody = newTree(nkStmtList, rawClosureCreation(fn, d, c), newBody)
|
||||
result = wrapIterBody(newBody, fn)
|
||||
result = wrapIterBody(g, newBody, fn)
|
||||
else:
|
||||
result = body
|
||||
#if fn.name.s == "get2":
|
||||
@@ -837,15 +842,12 @@ proc liftLambdas*(fn: PSym, body: PNode; tooEarly: var bool): PNode =
|
||||
# echo renderTree(result, {renderIds})
|
||||
|
||||
proc liftLambdasForTopLevel*(module: PSym, body: PNode): PNode =
|
||||
if body.kind == nkEmpty or gCmd == cmdCompileToJS:
|
||||
result = body
|
||||
else:
|
||||
# XXX implement it properly
|
||||
result = body
|
||||
# XXX implement it properly
|
||||
result = body
|
||||
|
||||
# ------------------- iterator transformation --------------------------------
|
||||
|
||||
proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
|
||||
# problem ahead: the iterator could be invoked indirectly, but then
|
||||
# we don't know what environment to create here:
|
||||
#
|
||||
@@ -873,10 +875,10 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
nkBreakState(cl.state)
|
||||
...
|
||||
"""
|
||||
if liftingHarmful(owner): return body
|
||||
if liftingHarmful(g.config, owner): return body
|
||||
var L = body.len
|
||||
if not (body.kind == nkForStmt and body[L-2].kind in nkCallKinds):
|
||||
localError(body.info, "ignored invalid for loop")
|
||||
localError(g.config, body.info, "ignored invalid for loop")
|
||||
return body
|
||||
var call = body[L-2]
|
||||
|
||||
@@ -889,7 +891,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
# createClosure()
|
||||
let iter = op.sym
|
||||
|
||||
let hp = getHiddenParam(iter)
|
||||
let hp = getHiddenParam(g, iter)
|
||||
env = newSym(skLet, iter.name, owner, body.info)
|
||||
env.typ = hp.typ
|
||||
env.flags = hp.flags
|
||||
@@ -898,7 +900,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
addVar(v, newSymNode(env))
|
||||
result.add(v)
|
||||
# add 'new' statement:
|
||||
result.add(newCall(getSysSym"internalNew", env.newSymNode))
|
||||
result.add(newCall(getSysSym(g, env.info, "internalNew"), env.newSymNode))
|
||||
elif op.kind == nkStmtListExpr:
|
||||
let closure = op.lastSon
|
||||
if closure.kind == nkClosure:
|
||||
@@ -908,7 +910,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
|
||||
var loopBody = newNodeI(nkStmtList, body.info, 3)
|
||||
var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(tyBool))
|
||||
whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
|
||||
whileLoop.sons[1] = loopBody
|
||||
result.add whileLoop
|
||||
|
||||
@@ -923,7 +925,7 @@ proc liftForLoop*(body: PNode; owner: PSym): PNode =
|
||||
|
||||
addSon(vpart, ast.emptyNode) # no explicit type
|
||||
if not env.isNil:
|
||||
call.sons[0] = makeClosure(call.sons[0].sym, env.newSymNode, body.info)
|
||||
call.sons[0] = makeClosure(g, call.sons[0].sym, env.newSymNode, body.info)
|
||||
addSon(vpart, call)
|
||||
addSon(v2, vpart)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,63 +10,62 @@
|
||||
# Built-in types and compilerprocs are registered here.
|
||||
|
||||
import
|
||||
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread
|
||||
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread,
|
||||
modulegraphs
|
||||
|
||||
var systemModule*: PSym
|
||||
export createMagic
|
||||
|
||||
var
|
||||
gSysTypes: array[TTypeKind, PType]
|
||||
compilerprocs: TStrTable
|
||||
exposed: TStrTable
|
||||
proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
|
||||
|
||||
proc nilOrSysInt*: PType = gSysTypes[tyInt]
|
||||
proc registerSysType*(g: ModuleGraph; t: PType) =
|
||||
if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t
|
||||
|
||||
proc registerSysType*(t: PType) =
|
||||
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
|
||||
|
||||
proc newSysType(kind: TTypeKind, size: int): PType =
|
||||
result = newType(kind, systemModule)
|
||||
proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
|
||||
result = newType(kind, g.systemModule)
|
||||
result.size = size
|
||||
result.align = size.int16
|
||||
|
||||
proc getSysSym*(name: string): PSym =
|
||||
result = strTableGet(systemModule.tab, getIdent(name))
|
||||
proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
|
||||
result = strTableGet(g.systemModule.tab, getIdent(name))
|
||||
if result == nil:
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, getIdent(name), systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, g.systemModule)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc createMagic*(name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
|
||||
result.magic = m
|
||||
when false:
|
||||
proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
|
||||
result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
|
||||
result.magic = m
|
||||
|
||||
let
|
||||
opNot* = createMagic("not", mNot)
|
||||
opContains* = createMagic("contains", mInSet)
|
||||
when false:
|
||||
let
|
||||
opNot* = createMagic("not", mNot)
|
||||
opContains* = createMagic("contains", mInSet)
|
||||
|
||||
proc getSysMagic*(name: string, m: TMagic): PSym =
|
||||
proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
|
||||
var ti: TIdentIter
|
||||
let id = getIdent(name)
|
||||
var r = initIdentIter(ti, systemModule.tab, id)
|
||||
var r = initIdentIter(ti, g.systemModule.tab, id)
|
||||
while r != nil:
|
||||
if r.kind == skStub: loadStub(r)
|
||||
if r.magic == m:
|
||||
# prefer the tyInt variant:
|
||||
if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
|
||||
result = r
|
||||
r = nextIdentIter(ti, systemModule.tab)
|
||||
r = nextIdentIter(ti, g.systemModule.tab)
|
||||
if result != nil: return result
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = newSym(skError, id, systemModule, systemModule.info)
|
||||
result.typ = newType(tyError, systemModule)
|
||||
localError(g.config, info, "system module needs: " & name)
|
||||
result = newSym(skError, id, g.systemModule, g.systemModule.info, {})
|
||||
result.typ = newType(tyError, g.systemModule)
|
||||
|
||||
proc sysTypeFromName*(name: string): PType =
|
||||
result = getSysSym(name).typ
|
||||
proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
|
||||
result = getSysSym(g, info, name).typ
|
||||
|
||||
proc getSysType*(kind: TTypeKind): PType =
|
||||
result = gSysTypes[kind]
|
||||
proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
|
||||
template sysTypeFromName(s: string): untyped = sysTypeFromName(g, info, s)
|
||||
result = g.sysTypes[kind]
|
||||
if result == nil:
|
||||
case kind
|
||||
of tyInt: result = sysTypeFromName("int")
|
||||
@@ -88,51 +87,49 @@ proc getSysType*(kind: TTypeKind): PType =
|
||||
of tyString: result = sysTypeFromName("string")
|
||||
of tyCString: result = sysTypeFromName("cstring")
|
||||
of tyPointer: result = sysTypeFromName("pointer")
|
||||
of tyNil: result = newSysType(tyNil, ptrSize)
|
||||
else: internalError("request for typekind: " & $kind)
|
||||
gSysTypes[kind] = result
|
||||
of tyNil: result = newSysType(g, tyNil, ptrSize)
|
||||
else: internalError(g.config, "request for typekind: " & $kind)
|
||||
g.sysTypes[kind] = result
|
||||
if result.kind != kind:
|
||||
internalError("wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: internalError("type not found: " & $kind)
|
||||
internalError(g.config, "wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: internalError(g.config, "type not found: " & $kind)
|
||||
|
||||
var
|
||||
intTypeCache: array[-5..64, PType]
|
||||
proc resetSysTypes*(g: ModuleGraph) =
|
||||
g.systemModule = nil
|
||||
initStrTable(g.compilerprocs)
|
||||
initStrTable(g.exposed)
|
||||
for i in low(g.sysTypes)..high(g.sysTypes):
|
||||
g.sysTypes[i] = nil
|
||||
|
||||
proc resetSysTypes* =
|
||||
systemModule = nil
|
||||
initStrTable(compilerprocs)
|
||||
initStrTable(exposed)
|
||||
for i in low(gSysTypes)..high(gSysTypes):
|
||||
gSysTypes[i] = nil
|
||||
for i in low(g.intTypeCache)..high(g.intTypeCache):
|
||||
g.intTypeCache[i] = nil
|
||||
|
||||
for i in low(intTypeCache)..high(intTypeCache):
|
||||
intTypeCache[i] = nil
|
||||
|
||||
proc getIntLitType*(literal: PNode): PType =
|
||||
proc getIntLitType*(g: ModuleGraph; literal: PNode): PType =
|
||||
# we cache some common integer literal types for performance:
|
||||
let value = literal.intVal
|
||||
if value >= low(intTypeCache) and value <= high(intTypeCache):
|
||||
result = intTypeCache[value.int]
|
||||
if value >= low(g.intTypeCache) and value <= high(g.intTypeCache):
|
||||
result = g.intTypeCache[value.int]
|
||||
if result == nil:
|
||||
let ti = getSysType(tyInt)
|
||||
let ti = getSysType(g, literal.info, tyInt)
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
intTypeCache[value.int] = result
|
||||
g.intTypeCache[value.int] = result
|
||||
else:
|
||||
let ti = getSysType(tyInt)
|
||||
let ti = getSysType(g, literal.info, tyInt)
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
|
||||
proc getFloatLitType*(literal: PNode): PType =
|
||||
proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
|
||||
# for now we do not cache these:
|
||||
result = newSysType(tyFloat, size=8)
|
||||
result = newSysType(g, tyFloat, size=8)
|
||||
result.n = literal
|
||||
|
||||
proc skipIntLit*(t: PType): PType {.inline.} =
|
||||
if t.n != nil:
|
||||
if t.kind in {tyInt, tyFloat}:
|
||||
return getSysType(t.kind)
|
||||
result = t
|
||||
if t.n != nil and t.kind in {tyInt, tyFloat}:
|
||||
result = copyType(t, t.owner, false)
|
||||
result.n = nil
|
||||
else:
|
||||
result = t
|
||||
|
||||
proc addSonSkipIntLit*(father, son: PType) =
|
||||
if isNil(father.sons): father.sons = @[]
|
||||
@@ -140,60 +137,59 @@ proc addSonSkipIntLit*(father, son: PType) =
|
||||
add(father.sons, s)
|
||||
propagateToOwner(father, s)
|
||||
|
||||
proc setIntLitType*(result: PNode) =
|
||||
proc setIntLitType*(g: ModuleGraph; result: PNode) =
|
||||
let i = result.intVal
|
||||
case platform.intSize
|
||||
of 8: result.typ = getIntLitType(result)
|
||||
of 8: result.typ = getIntLitType(g, result)
|
||||
of 4:
|
||||
if i >= low(int32) and i <= high(int32):
|
||||
result.typ = getIntLitType(result)
|
||||
result.typ = getIntLitType(g, result)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
result.typ = getSysType(g, result.info, tyInt64)
|
||||
of 2:
|
||||
if i >= low(int16) and i <= high(int16):
|
||||
result.typ = getIntLitType(result)
|
||||
result.typ = getIntLitType(g, result)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(tyInt32)
|
||||
result.typ = getSysType(g, result.info, tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
result.typ = getSysType(g, result.info, tyInt64)
|
||||
of 1:
|
||||
# 8 bit CPUs are insane ...
|
||||
if i >= low(int8) and i <= high(int8):
|
||||
result.typ = getIntLitType(result)
|
||||
result.typ = getIntLitType(g, result)
|
||||
elif i >= low(int16) and i <= high(int16):
|
||||
result.typ = getSysType(tyInt16)
|
||||
result.typ = getSysType(g, result.info, tyInt16)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(tyInt32)
|
||||
result.typ = getSysType(g, result.info, tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
else: internalError(result.info, "invalid int size")
|
||||
|
||||
proc getCompilerProc*(name: string): PSym =
|
||||
let ident = getIdent(name)
|
||||
result = strTableGet(compilerprocs, ident)
|
||||
if result == nil:
|
||||
result = strTableGet(rodCompilerprocs, ident)
|
||||
if result != nil:
|
||||
strTableAdd(compilerprocs, result)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc registerCompilerProc*(s: PSym) =
|
||||
strTableAdd(compilerprocs, s)
|
||||
|
||||
proc registerNimScriptSymbol*(s: PSym) =
|
||||
# Nimscript symbols must be al unique:
|
||||
let conflict = strTableGet(exposed, s.name)
|
||||
if conflict == nil:
|
||||
strTableAdd(exposed, s)
|
||||
result.typ = getSysType(g, result.info, tyInt64)
|
||||
else:
|
||||
localError(s.info, "symbol conflicts with other .exportNims symbol at: " &
|
||||
$conflict.info)
|
||||
internalError(g.config, result.info, "invalid int size")
|
||||
|
||||
proc getNimScriptSymbol*(name: string): PSym =
|
||||
strTableGet(exposed, getIdent(name))
|
||||
proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
|
||||
let ident = getIdent(name)
|
||||
result = strTableGet(g.compilerprocs, ident)
|
||||
when false:
|
||||
if result == nil:
|
||||
result = strTableGet(g.rodCompilerprocs, ident)
|
||||
if result != nil:
|
||||
strTableAdd(g.compilerprocs, result)
|
||||
if result.kind == skStub: loadStub(result)
|
||||
if result.kind == skAlias: result = result.owner
|
||||
|
||||
proc resetNimScriptSymbols*() = initStrTable(exposed)
|
||||
proc registerCompilerProc*(g: ModuleGraph; s: PSym) =
|
||||
strTableAdd(g.compilerprocs, s)
|
||||
|
||||
initStrTable(compilerprocs)
|
||||
initStrTable(exposed)
|
||||
proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
|
||||
# Nimscript symbols must be al unique:
|
||||
let conflict = strTableGet(g.exposed, s.name)
|
||||
if conflict == nil:
|
||||
strTableAdd(g.exposed, s)
|
||||
else:
|
||||
localError(g.config, s.info,
|
||||
"symbol conflicts with other .exportNims symbol at: " & $conflict.info)
|
||||
|
||||
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
|
||||
strTableGet(g.exposed, getIdent(name))
|
||||
|
||||
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -8,481 +8,13 @@
|
||||
#
|
||||
|
||||
import
|
||||
options, strutils, os, tables, ropes, platform, terminal, macros
|
||||
options, strutils, os, tables, ropes, platform, terminal, macros,
|
||||
configuration
|
||||
|
||||
const
|
||||
explanationsBaseUrl* = "https://nim-lang.org/docs/manual"
|
||||
#type
|
||||
# MsgConfig* = ref object of RootObj
|
||||
|
||||
type
|
||||
TMsgKind* = enum
|
||||
errUnknown, errInternal, errIllFormedAstX, errCannotOpenFile, errGenerated,
|
||||
errStringLiteralExpected,
|
||||
errIntLiteralExpected, errInvalidCharacterConstant,
|
||||
errClosingTripleQuoteExpected, errClosingQuoteExpected,
|
||||
errTabulatorsAreNotAllowed, errInvalidToken,
|
||||
errInvalidNumber, errInvalidNumberOctalCode, errNumberOutOfRange,
|
||||
errNnotAllowedInCharacter, errClosingBracketExpected, errMissingFinalQuote,
|
||||
errIdentifierExpected, errNewlineExpected, errInvalidModuleName,
|
||||
errOperatorExpected, errTokenExpected,
|
||||
errRecursiveDependencyX, errOnOrOffExpected, errNoneSpeedOrSizeExpected,
|
||||
errInvalidPragma, errUnknownPragma, errInvalidDirectiveX,
|
||||
errAtPopWithoutPush, errEmptyAsm, errInvalidIndentation,
|
||||
errExceptionAlreadyHandled,
|
||||
errYieldNotAllowedHere, errYieldNotAllowedInTryStmt,
|
||||
errInvalidNumberOfYieldExpr, errCannotReturnExpr,
|
||||
errNoReturnWithReturnTypeNotAllowed, errAttemptToRedefine,
|
||||
errStmtInvalidAfterReturn, errStmtExpected, errInvalidLabel,
|
||||
errInvalidCmdLineOption, errCmdLineArgExpected, errCmdLineNoArgExpected,
|
||||
errInvalidVarSubstitution, errUnknownVar, errUnknownCcompiler,
|
||||
errOnOrOffExpectedButXFound, errOnOffOrListExpectedButXFound,
|
||||
errNoneBoehmRefcExpectedButXFound,
|
||||
errNoneSpeedOrSizeExpectedButXFound, errGuiConsoleOrLibExpectedButXFound,
|
||||
errUnknownOS, errUnknownCPU, errGenOutExpectedButXFound,
|
||||
errArgsNeedRunOption, errInvalidMultipleAsgn, errColonOrEqualsExpected,
|
||||
errExprExpected, errUndeclaredField,
|
||||
errUndeclaredRoutine, errUseQualifier,
|
||||
errTypeExpected,
|
||||
errSystemNeeds, errExecutionOfProgramFailed, errNotOverloadable,
|
||||
errInvalidArgForX, errStmtHasNoEffect, errXExpectsTypeOrValue,
|
||||
errXExpectsArrayType, errIteratorCannotBeInstantiated, errExprXAmbiguous,
|
||||
errConstantDivisionByZero, errOrdinalTypeExpected,
|
||||
errOrdinalOrFloatTypeExpected, errOverOrUnderflow,
|
||||
errCannotEvalXBecauseIncompletelyDefined, errChrExpectsRange0_255,
|
||||
errDynlibRequiresExportc, errUndeclaredFieldX, errNilAccess,
|
||||
errIndexOutOfBounds, errIndexTypesDoNotMatch, errBracketsInvalidForType,
|
||||
errValueOutOfSetBounds, errFieldInitTwice, errFieldNotInit,
|
||||
errExprXCannotBeCalled, errExprHasNoType, errExprXHasNoType,
|
||||
errCastNotInSafeMode, errExprCannotBeCastToX, errCommaOrParRiExpected,
|
||||
errCurlyLeOrParLeExpected, errSectionExpected, errRangeExpected,
|
||||
errMagicOnlyInSystem, errPowerOfTwoExpected,
|
||||
errStringMayNotBeEmpty, errCallConvExpected, errProcOnlyOneCallConv,
|
||||
errSymbolMustBeImported, errExprMustBeBool, errConstExprExpected,
|
||||
errDuplicateCaseLabel, errRangeIsEmpty, errSelectorMustBeOfCertainTypes,
|
||||
errSelectorMustBeOrdinal, errOrdXMustNotBeNegative, errLenXinvalid,
|
||||
errWrongNumberOfVariables, errExprCannotBeRaised, errBreakOnlyInLoop,
|
||||
errTypeXhasUnknownSize, errConstNeedsConstExpr, errConstNeedsValue,
|
||||
errResultCannotBeOpenArray, errSizeTooBig, errSetTooBig,
|
||||
errBaseTypeMustBeOrdinal, errInheritanceOnlyWithNonFinalObjects,
|
||||
errInheritanceOnlyWithEnums, errIllegalRecursionInTypeX,
|
||||
errCannotInstantiateX, errExprHasNoAddress, errXStackEscape,
|
||||
errVarForOutParamNeededX,
|
||||
errPureTypeMismatch, errTypeMismatch, errButExpected, errButExpectedX,
|
||||
errAmbiguousCallXYZ, errWrongNumberOfArguments,
|
||||
errWrongNumberOfArgumentsInCall,
|
||||
errMissingGenericParamsForTemplate,
|
||||
errXCannotBePassedToProcVar,
|
||||
errPragmaOnlyInHeaderOfProcX, errImplOfXNotAllowed,
|
||||
errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX,
|
||||
errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice,
|
||||
errInvalidOrderInArrayConstructor,
|
||||
errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry,
|
||||
errOptionExpected, errXisNoLabel, errNotAllCasesCovered,
|
||||
errUnknownSubstitionVar, errComplexStmtRequiresInd, errXisNotCallable,
|
||||
errNoPragmasAllowedForX, errNoGenericParamsAllowedForX,
|
||||
errInvalidParamKindX, errDefaultArgumentInvalid, errNamedParamHasToBeIdent,
|
||||
errNoReturnTypeForX, errConvNeedsOneArg, errInvalidPragmaX,
|
||||
errXNotAllowedHere, errInvalidControlFlowX,
|
||||
errXisNoType, errCircumNeedsPointer, errInvalidExpression,
|
||||
errInvalidExpressionX, errEnumHasNoValueX, errNamedExprExpected,
|
||||
errNamedExprNotAllowed, errXExpectsOneTypeParam,
|
||||
errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed,
|
||||
errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType,
|
||||
errNoReturnTypeDeclared,
|
||||
errNoCommand, errInvalidCommandX, errXOnlyAtModuleScope,
|
||||
errXNeedsParamObjectType,
|
||||
errTemplateInstantiationTooNested, errMacroInstantiationTooNested,
|
||||
errInstantiationFrom,
|
||||
errInvalidIndexValueForTuple, errCommandExpectsFilename,
|
||||
errMainModuleMustBeSpecified,
|
||||
errXExpected,
|
||||
errTIsNotAConcreteType,
|
||||
errCastToANonConcreteType,
|
||||
errInvalidSectionStart, errGridTableNotImplemented, errGeneralParseError,
|
||||
errNewSectionExpected, errWhitespaceExpected, errXisNoValidIndexFile,
|
||||
errCannotRenderX, errVarVarTypeNotAllowed, errInstantiateXExplicitly,
|
||||
errOnlyACallOpCanBeDelegator, errUsingNoSymbol,
|
||||
errMacroBodyDependsOnGenericTypes,
|
||||
errDestructorNotGenericEnough,
|
||||
errInlineIteratorsAsProcParams,
|
||||
errXExpectsTwoArguments,
|
||||
errXExpectsObjectTypes, errXcanNeverBeOfThisSubtype, errTooManyIterations,
|
||||
errCannotInterpretNodeX, errFieldXNotFound, errInvalidConversionFromTypeX,
|
||||
errAssertionFailed, errCannotGenerateCodeForX, errXRequiresOneArgument,
|
||||
errUnhandledExceptionX, errCyclicTree, errXisNoMacroOrTemplate,
|
||||
errXhasSideEffects, errIteratorExpected, errLetNeedsInit,
|
||||
errThreadvarCannotInit, errWrongSymbolX, errIllegalCaptureX,
|
||||
errXCannotBeClosure, errXMustBeCompileTime,
|
||||
errCannotInferTypeOfTheLiteral,
|
||||
errCannotInferReturnType,
|
||||
errCannotInferStaticParam,
|
||||
errGenericLambdaNotAllowed,
|
||||
errProcHasNoConcreteType,
|
||||
errCompilerDoesntSupportTarget,
|
||||
errInOutFlagNotExtern,
|
||||
errUser,
|
||||
warnCannotOpenFile,
|
||||
warnOctalEscape, warnXIsNeverRead, warnXmightNotBeenInit,
|
||||
warnDeprecated, warnConfigDeprecated,
|
||||
warnSmallLshouldNotBeUsed, warnUnknownMagic, warnRedefinitionOfLabel,
|
||||
warnUnknownSubstitutionX, warnLanguageXNotSupported,
|
||||
warnFieldXNotSupported, warnCommentXIgnored,
|
||||
warnTypelessParam,
|
||||
warnUseBase, warnWriteToForeignHeap, warnUnsafeCode,
|
||||
warnEachIdentIsTuple, warnShadowIdent,
|
||||
warnProveInit, warnProveField, warnProveIndex, warnGcUnsafe, warnGcUnsafe2,
|
||||
warnUninit, warnGcMem, warnDestructor, warnLockLevel, warnResultShadowed,
|
||||
warnInconsistentSpacing, warnUser,
|
||||
hintSuccess, hintSuccessX,
|
||||
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
|
||||
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
|
||||
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
|
||||
hintConditionAlwaysTrue, hintName, hintPattern,
|
||||
hintExecuting, hintLinking, hintDependency,
|
||||
hintSource, hintPerformance, hintStackTrace, hintGCStats,
|
||||
hintUser, hintUserRaw
|
||||
|
||||
const
|
||||
MsgKindToStr*: array[TMsgKind, string] = [
|
||||
errUnknown: "unknown error",
|
||||
errInternal: "internal error: $1",
|
||||
errIllFormedAstX: "illformed AST: $1",
|
||||
errCannotOpenFile: "cannot open '$1'",
|
||||
errGenerated: "$1",
|
||||
errStringLiteralExpected: "string literal expected",
|
||||
errIntLiteralExpected: "integer literal expected",
|
||||
errInvalidCharacterConstant: "invalid character constant",
|
||||
errClosingTripleQuoteExpected: "closing \"\"\" expected, but end of file reached",
|
||||
errClosingQuoteExpected: "closing \" expected",
|
||||
errTabulatorsAreNotAllowed: "tabulators are not allowed",
|
||||
errInvalidToken: "invalid token: $1",
|
||||
errInvalidNumber: "$1 is not a valid number",
|
||||
errInvalidNumberOctalCode: "$1 is not a valid number; did you mean octal? Then use one of '0o', '0c' or '0C'.",
|
||||
errNumberOutOfRange: "number $1 out of valid range",
|
||||
errNnotAllowedInCharacter: "\\n not allowed in character literal",
|
||||
errClosingBracketExpected: "closing ']' expected, but end of file reached",
|
||||
errMissingFinalQuote: "missing final ' for character literal",
|
||||
errIdentifierExpected: "identifier expected, but found '$1'",
|
||||
errNewlineExpected: "newline expected, but found '$1'",
|
||||
errInvalidModuleName: "invalid module name: '$1'",
|
||||
errOperatorExpected: "operator expected, but found '$1'",
|
||||
errTokenExpected: "'$1' expected",
|
||||
errRecursiveDependencyX: "recursive dependency: '$1'",
|
||||
errOnOrOffExpected: "'on' or 'off' expected",
|
||||
errNoneSpeedOrSizeExpected: "'none', 'speed' or 'size' expected",
|
||||
errInvalidPragma: "invalid pragma",
|
||||
errUnknownPragma: "unknown pragma: '$1'",
|
||||
errInvalidDirectiveX: "invalid directive: '$1'",
|
||||
errAtPopWithoutPush: "'pop' without a 'push' pragma",
|
||||
errEmptyAsm: "empty asm statement",
|
||||
errInvalidIndentation: "invalid indentation",
|
||||
errExceptionAlreadyHandled: "exception already handled",
|
||||
errYieldNotAllowedHere: "'yield' only allowed in an iterator",
|
||||
errYieldNotAllowedInTryStmt: "'yield' cannot be used within 'try' in a non-inlined iterator",
|
||||
errInvalidNumberOfYieldExpr: "invalid number of 'yield' expressions",
|
||||
errCannotReturnExpr: "current routine cannot return an expression",
|
||||
errNoReturnWithReturnTypeNotAllowed: "routines with NoReturn pragma are not allowed to have return type",
|
||||
errAttemptToRedefine: "redefinition of '$1'",
|
||||
errStmtInvalidAfterReturn: "statement not allowed after 'return', 'break', 'raise', 'continue' or proc call with noreturn pragma",
|
||||
errStmtExpected: "statement expected",
|
||||
errInvalidLabel: "'$1' is no label",
|
||||
errInvalidCmdLineOption: "invalid command line option: '$1'",
|
||||
errCmdLineArgExpected: "argument for command line option expected: '$1'",
|
||||
errCmdLineNoArgExpected: "invalid argument for command line option: '$1'",
|
||||
errInvalidVarSubstitution: "invalid variable substitution in '$1'",
|
||||
errUnknownVar: "unknown variable: '$1'",
|
||||
errUnknownCcompiler: "unknown C compiler: '$1'",
|
||||
errOnOrOffExpectedButXFound: "'on' or 'off' expected, but '$1' found",
|
||||
errOnOffOrListExpectedButXFound: "'on', 'off' or 'list' expected, but '$1' found",
|
||||
errNoneBoehmRefcExpectedButXFound: "'none', 'boehm' or 'refc' expected, but '$1' found",
|
||||
errNoneSpeedOrSizeExpectedButXFound: "'none', 'speed' or 'size' expected, but '$1' found",
|
||||
errGuiConsoleOrLibExpectedButXFound: "'gui', 'console' or 'lib' expected, but '$1' found",
|
||||
errUnknownOS: "unknown OS: '$1'",
|
||||
errUnknownCPU: "unknown CPU: '$1'",
|
||||
errGenOutExpectedButXFound: "'c', 'c++' or 'yaml' expected, but '$1' found",
|
||||
errArgsNeedRunOption: "arguments can only be given if the '--run' option is selected",
|
||||
errInvalidMultipleAsgn: "multiple assignment is not allowed",
|
||||
errColonOrEqualsExpected: "':' or '=' expected, but found '$1'",
|
||||
errExprExpected: "expression expected, but found '$1'",
|
||||
errUndeclaredField: "undeclared field: '$1'",
|
||||
errUndeclaredRoutine: "attempting to call undeclared routine: '$1'",
|
||||
errUseQualifier: "ambiguous identifier: '$1' -- use a qualifier",
|
||||
errTypeExpected: "type expected",
|
||||
errSystemNeeds: "system module needs '$1'",
|
||||
errExecutionOfProgramFailed: "execution of an external program failed: '$1'",
|
||||
errNotOverloadable: "overloaded '$1' leads to ambiguous calls",
|
||||
errInvalidArgForX: "invalid argument for '$1'",
|
||||
errStmtHasNoEffect: "statement has no effect",
|
||||
errXExpectsTypeOrValue: "'$1' expects a type or value",
|
||||
errXExpectsArrayType: "'$1' expects an array type",
|
||||
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
|
||||
errExprXAmbiguous: "expression '$1' ambiguous in this context",
|
||||
errConstantDivisionByZero: "division by zero",
|
||||
errOrdinalTypeExpected: "ordinal type expected",
|
||||
errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
|
||||
errOverOrUnderflow: "over- or underflow",
|
||||
errCannotEvalXBecauseIncompletelyDefined: "cannot evaluate '$1' because type is not defined completely",
|
||||
errChrExpectsRange0_255: "'chr' expects an int in the range 0..255",
|
||||
errDynlibRequiresExportc: "'dynlib' requires 'exportc'",
|
||||
errUndeclaredFieldX: "undeclared field: '$1'",
|
||||
errNilAccess: "attempt to access a nil address",
|
||||
errIndexOutOfBounds: "index out of bounds",
|
||||
errIndexTypesDoNotMatch: "index types do not match",
|
||||
errBracketsInvalidForType: "'[]' operator invalid for this type",
|
||||
errValueOutOfSetBounds: "value out of set bounds",
|
||||
errFieldInitTwice: "field initialized twice: '$1'",
|
||||
errFieldNotInit: "field '$1' not initialized",
|
||||
errExprXCannotBeCalled: "expression '$1' cannot be called",
|
||||
errExprHasNoType: "expression has no type",
|
||||
errExprXHasNoType: "expression '$1' has no type (or is ambiguous)",
|
||||
errCastNotInSafeMode: "'cast' not allowed in safe mode",
|
||||
errExprCannotBeCastToX: "expression cannot be cast to $1",
|
||||
errCommaOrParRiExpected: "',' or ')' expected",
|
||||
errCurlyLeOrParLeExpected: "'{' or '(' expected",
|
||||
errSectionExpected: "section ('type', 'proc', etc.) expected",
|
||||
errRangeExpected: "range expected",
|
||||
errMagicOnlyInSystem: "'magic' only allowed in system module",
|
||||
errPowerOfTwoExpected: "power of two expected",
|
||||
errStringMayNotBeEmpty: "string literal may not be empty",
|
||||
errCallConvExpected: "calling convention expected",
|
||||
errProcOnlyOneCallConv: "a proc can only have one calling convention",
|
||||
errSymbolMustBeImported: "symbol must be imported if 'lib' pragma is used",
|
||||
errExprMustBeBool: "expression must be of type 'bool'",
|
||||
errConstExprExpected: "constant expression expected",
|
||||
errDuplicateCaseLabel: "duplicate case label",
|
||||
errRangeIsEmpty: "range is empty",
|
||||
errSelectorMustBeOfCertainTypes: "selector must be of an ordinal type, float or string",
|
||||
errSelectorMustBeOrdinal: "selector must be of an ordinal type",
|
||||
errOrdXMustNotBeNegative: "ord($1) must not be negative",
|
||||
errLenXinvalid: "len($1) must be less than 32768",
|
||||
errWrongNumberOfVariables: "wrong number of variables",
|
||||
errExprCannotBeRaised: "only a 'ref object' can be raised",
|
||||
errBreakOnlyInLoop: "'break' only allowed in loop construct",
|
||||
errTypeXhasUnknownSize: "type '$1' has unknown size",
|
||||
errConstNeedsConstExpr: "a constant can only be initialized with a constant expression",
|
||||
errConstNeedsValue: "a constant needs a value",
|
||||
errResultCannotBeOpenArray: "the result type cannot be on open array",
|
||||
errSizeTooBig: "computing the type's size produced an overflow",
|
||||
errSetTooBig: "set is too large",
|
||||
errBaseTypeMustBeOrdinal: "base type of a set must be an ordinal",
|
||||
errInheritanceOnlyWithNonFinalObjects: "inheritance only works with non-final objects",
|
||||
errInheritanceOnlyWithEnums: "inheritance only works with an enum",
|
||||
errIllegalRecursionInTypeX: "illegal recursion in type '$1'",
|
||||
errCannotInstantiateX: "cannot instantiate: '$1'",
|
||||
errExprHasNoAddress: "expression has no address",
|
||||
errXStackEscape: "address of '$1' may not escape its stack frame",
|
||||
errVarForOutParamNeededX: "for a 'var' type a variable needs to be passed; but '$1' is immutable",
|
||||
errPureTypeMismatch: "type mismatch",
|
||||
errTypeMismatch: "type mismatch: got <",
|
||||
errButExpected: "but expected one of: ",
|
||||
errButExpectedX: "but expected '$1'",
|
||||
errAmbiguousCallXYZ: "ambiguous call; both $1 and $2 match for: $3",
|
||||
errWrongNumberOfArguments: "wrong number of arguments",
|
||||
errWrongNumberOfArgumentsInCall: "wrong number of arguments in call to '$1'",
|
||||
errMissingGenericParamsForTemplate: "'$1' has unspecified generic parameters",
|
||||
errXCannotBePassedToProcVar: "'$1' cannot be passed to a procvar",
|
||||
errPragmaOnlyInHeaderOfProcX: "pragmas are only allowed in the header of a proc; redefinition of $1",
|
||||
errImplOfXNotAllowed: "implementation of '$1' is not allowed",
|
||||
errImplOfXexpected: "implementation of '$1' expected",
|
||||
errNoSymbolToBorrowFromFound: "no symbol to borrow from found",
|
||||
errDiscardValueX: "value of type '$1' has to be discarded",
|
||||
errInvalidDiscard: "statement returns no value that can be discarded",
|
||||
errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
|
||||
errCannotBindXTwice: "cannot bind parameter '$1' twice",
|
||||
errInvalidOrderInArrayConstructor: "invalid order in array constructor",
|
||||
errInvalidOrderInEnumX: "invalid order in enum '$1'",
|
||||
errEnumXHasHoles: "enum '$1' has holes",
|
||||
errExceptExpected: "'except' or 'finally' expected",
|
||||
errInvalidTry: "after catch all 'except' or 'finally' no section may follow",
|
||||
errOptionExpected: "option expected, but found '$1'",
|
||||
errXisNoLabel: "'$1' is not a label",
|
||||
errNotAllCasesCovered: "not all cases are covered",
|
||||
errUnknownSubstitionVar: "unknown substitution variable: '$1'",
|
||||
errComplexStmtRequiresInd: "complex statement requires indentation",
|
||||
errXisNotCallable: "'$1' is not callable",
|
||||
errNoPragmasAllowedForX: "no pragmas allowed for $1",
|
||||
errNoGenericParamsAllowedForX: "no generic parameters allowed for $1",
|
||||
errInvalidParamKindX: "invalid param kind: '$1'",
|
||||
errDefaultArgumentInvalid: "default argument invalid",
|
||||
errNamedParamHasToBeIdent: "named parameter has to be an identifier",
|
||||
errNoReturnTypeForX: "no return type allowed for $1",
|
||||
errConvNeedsOneArg: "a type conversion needs exactly one argument",
|
||||
errInvalidPragmaX: "invalid pragma: $1",
|
||||
errXNotAllowedHere: "$1 not allowed here",
|
||||
errInvalidControlFlowX: "invalid control flow: $1",
|
||||
errXisNoType: "invalid type: '$1'",
|
||||
errCircumNeedsPointer: "'[]' needs a pointer or reference type",
|
||||
errInvalidExpression: "invalid expression",
|
||||
errInvalidExpressionX: "invalid expression: '$1'",
|
||||
errEnumHasNoValueX: "enum has no value '$1'",
|
||||
errNamedExprExpected: "named expression expected",
|
||||
errNamedExprNotAllowed: "named expression not allowed here",
|
||||
errXExpectsOneTypeParam: "'$1' expects one type parameter",
|
||||
errArrayExpectsTwoTypeParams: "array expects two type parameters",
|
||||
errInvalidVisibilityX: "invalid visibility: '$1'",
|
||||
errInitHereNotAllowed: "initialization not allowed here",
|
||||
errXCannotBeAssignedTo: "'$1' cannot be assigned to",
|
||||
errIteratorNotAllowed: "iterators can only be defined at the module's top level",
|
||||
errXNeedsReturnType: "$1 needs a return type",
|
||||
errNoReturnTypeDeclared: "no return type declared",
|
||||
errNoCommand: "no command given",
|
||||
errInvalidCommandX: "invalid command: '$1'",
|
||||
errXOnlyAtModuleScope: "'$1' is only allowed at top level",
|
||||
errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
|
||||
errTemplateInstantiationTooNested: "template instantiation too nested, try --evalTemplateLimit:N",
|
||||
errMacroInstantiationTooNested: "macro instantiation too nested, try --evalMacroLimit:N",
|
||||
errInstantiationFrom: "template/generic instantiation from here",
|
||||
errInvalidIndexValueForTuple: "invalid index value for tuple subscript",
|
||||
errCommandExpectsFilename: "command expects a filename argument",
|
||||
errMainModuleMustBeSpecified: "please, specify a main module in the project configuration file",
|
||||
errXExpected: "'$1' expected",
|
||||
errTIsNotAConcreteType: "'$1' is not a concrete type.",
|
||||
errCastToANonConcreteType: "cannot cast to a non concrete type: '$1'",
|
||||
errInvalidSectionStart: "invalid section start",
|
||||
errGridTableNotImplemented: "grid table is not implemented",
|
||||
errGeneralParseError: "general parse error",
|
||||
errNewSectionExpected: "new section expected",
|
||||
errWhitespaceExpected: "whitespace expected, got '$1'",
|
||||
errXisNoValidIndexFile: "'$1' is no valid index file",
|
||||
errCannotRenderX: "cannot render reStructuredText element '$1'",
|
||||
errVarVarTypeNotAllowed: "type 'var var' is not allowed",
|
||||
errInstantiateXExplicitly: "instantiate '$1' explicitly",
|
||||
errOnlyACallOpCanBeDelegator: "only a call operator can be a delegator",
|
||||
errUsingNoSymbol: "'$1' is not a variable, constant or a proc name",
|
||||
errMacroBodyDependsOnGenericTypes: "the macro body cannot be compiled, " &
|
||||
"because the parameter '$1' has a generic type",
|
||||
errDestructorNotGenericEnough: "Destructor signature is too specific. " &
|
||||
"A destructor must be associated will all instantiations of a generic type",
|
||||
errInlineIteratorsAsProcParams: "inline iterators can be used as parameters only for " &
|
||||
"templates, macros and other inline iterators",
|
||||
errXExpectsTwoArguments: "'$1' expects two arguments",
|
||||
errXExpectsObjectTypes: "'$1' expects object types",
|
||||
errXcanNeverBeOfThisSubtype: "'$1' can never be of this subtype",
|
||||
errTooManyIterations: "interpretation requires too many iterations; " &
|
||||
"if you are sure this is not a bug in your code edit " &
|
||||
"compiler/vmdef.MaxLoopIterations and rebuild the compiler",
|
||||
errCannotInterpretNodeX: "cannot evaluate '$1'",
|
||||
errFieldXNotFound: "field '$1' cannot be found",
|
||||
errInvalidConversionFromTypeX: "invalid conversion from type '$1'",
|
||||
errAssertionFailed: "assertion failed",
|
||||
errCannotGenerateCodeForX: "cannot generate code for '$1'",
|
||||
errXRequiresOneArgument: "$1 requires one parameter",
|
||||
errUnhandledExceptionX: "unhandled exception: $1",
|
||||
errCyclicTree: "macro returned a cyclic abstract syntax tree",
|
||||
errXisNoMacroOrTemplate: "'$1' is no macro or template",
|
||||
errXhasSideEffects: "'$1' can have side effects",
|
||||
errIteratorExpected: "iterator within for loop context expected",
|
||||
errLetNeedsInit: "'let' symbol requires an initialization",
|
||||
errThreadvarCannotInit: "a thread var cannot be initialized explicitly; this would only run for the main thread",
|
||||
errWrongSymbolX: "usage of '$1' is a user-defined error",
|
||||
errIllegalCaptureX: "illegal capture '$1'",
|
||||
errXCannotBeClosure: "'$1' cannot have 'closure' calling convention",
|
||||
errXMustBeCompileTime: "'$1' can only be used in compile-time context",
|
||||
errCannotInferTypeOfTheLiteral: "cannot infer the type of the $1",
|
||||
errCannotInferReturnType: "cannot infer the return type of the proc",
|
||||
errCannotInferStaticParam: "cannot infer the value of the static param `$1`",
|
||||
errGenericLambdaNotAllowed: "A nested proc can have generic parameters only when " &
|
||||
"it is used as an operand to another routine and the types " &
|
||||
"of the generic paramers can be inferred from the expected signature.",
|
||||
errProcHasNoConcreteType: "'$1' doesn't have a concrete type, due to unspecified generic parameters.",
|
||||
errCompilerDoesntSupportTarget: "The current compiler '$1' doesn't support the requested compilation target",
|
||||
errInOutFlagNotExtern: "The `$1` modifier can be used only with imported types",
|
||||
errUser: "$1",
|
||||
warnCannotOpenFile: "cannot open '$1'",
|
||||
warnOctalEscape: "octal escape sequences do not exist; leading zero is ignored",
|
||||
warnXIsNeverRead: "'$1' is never read",
|
||||
warnXmightNotBeenInit: "'$1' might not have been initialized",
|
||||
warnDeprecated: "$1 is deprecated",
|
||||
warnConfigDeprecated: "config file '$1' is deprecated",
|
||||
warnSmallLshouldNotBeUsed: "'l' should not be used as an identifier; may look like '1' (one)",
|
||||
warnUnknownMagic: "unknown magic '$1' might crash the compiler",
|
||||
warnRedefinitionOfLabel: "redefinition of label '$1'",
|
||||
warnUnknownSubstitutionX: "unknown substitution '$1'",
|
||||
warnLanguageXNotSupported: "language '$1' not supported",
|
||||
warnFieldXNotSupported: "field '$1' not supported",
|
||||
warnCommentXIgnored: "comment '$1' ignored",
|
||||
warnTypelessParam: "'$1' has no type. Typeless parameters are deprecated; only allowed for 'template'",
|
||||
warnUseBase: "use {.base.} for base methods; baseless methods are deprecated",
|
||||
warnWriteToForeignHeap: "write to foreign heap",
|
||||
warnUnsafeCode: "unsafe code: '$1'",
|
||||
warnEachIdentIsTuple: "each identifier is a tuple",
|
||||
warnShadowIdent: "shadowed identifier: '$1'",
|
||||
warnProveInit: "Cannot prove that '$1' is initialized. This will become a compile time error in the future.",
|
||||
warnProveField: "cannot prove that field '$1' is accessible",
|
||||
warnProveIndex: "cannot prove index '$1' is valid",
|
||||
warnGcUnsafe: "not GC-safe: '$1'",
|
||||
warnGcUnsafe2: "$1",
|
||||
warnUninit: "'$1' might not have been initialized",
|
||||
warnGcMem: "'$1' uses GC'ed memory",
|
||||
warnDestructor: "usage of a type with a destructor in a non destructible context. This will become a compile time error in the future.",
|
||||
warnLockLevel: "$1",
|
||||
warnResultShadowed: "Special variable 'result' is shadowed.",
|
||||
warnInconsistentSpacing: "Number of spaces around '$#' is not consistent",
|
||||
warnUser: "$1",
|
||||
hintSuccess: "operation successful",
|
||||
hintSuccessX: "operation successful ($# lines compiled; $# sec total; $#; $#)",
|
||||
hintLineTooLong: "line too long",
|
||||
hintXDeclaredButNotUsed: "'$1' is declared but not used",
|
||||
hintConvToBaseNotNeeded: "conversion to base object is not needed",
|
||||
hintConvFromXtoItselfNotNeeded: "conversion from $1 to itself is pointless",
|
||||
hintExprAlwaysX: "expression evaluates always to '$1'",
|
||||
hintQuitCalled: "quit() called",
|
||||
hintProcessing: "$1",
|
||||
hintCodeBegin: "generated code listing:",
|
||||
hintCodeEnd: "end of listing",
|
||||
hintConf: "used config file '$1'",
|
||||
hintPath: "added path: '$1'",
|
||||
hintConditionAlwaysTrue: "condition is always true: '$1'",
|
||||
hintName: "name should be: '$1'",
|
||||
hintPattern: "$1",
|
||||
hintExecuting: "$1",
|
||||
hintLinking: "",
|
||||
hintDependency: "$1",
|
||||
hintSource: "$1",
|
||||
hintPerformance: "$1",
|
||||
hintStackTrace: "$1",
|
||||
hintGCStats: "$1",
|
||||
hintUser: "$1",
|
||||
hintUserRaw: "$1"]
|
||||
|
||||
const
|
||||
WarningsToStr* = ["CannotOpenFile", "OctalEscape",
|
||||
"XIsNeverRead", "XmightNotBeenInit",
|
||||
"Deprecated", "ConfigDeprecated",
|
||||
"SmallLshouldNotBeUsed", "UnknownMagic",
|
||||
"RedefinitionOfLabel", "UnknownSubstitutionX",
|
||||
"LanguageXNotSupported", "FieldXNotSupported",
|
||||
"CommentXIgnored",
|
||||
"TypelessParam", "UseBase", "WriteToForeignHeap",
|
||||
"UnsafeCode", "EachIdentIsTuple", "ShadowIdent",
|
||||
"ProveInit", "ProveField", "ProveIndex", "GcUnsafe", "GcUnsafe2", "Uninit",
|
||||
"GcMem", "Destructor", "LockLevel", "ResultShadowed",
|
||||
"Spacing", "User"]
|
||||
|
||||
HintsToStr* = ["Success", "SuccessX", "LineTooLong",
|
||||
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
|
||||
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
|
||||
"Path", "CondTrue", "Name", "Pattern", "Exec", "Link", "Dependency",
|
||||
"Source", "Performance", "StackTrace", "GCStats",
|
||||
"User", "UserRaw"]
|
||||
|
||||
const
|
||||
fatalMin* = errUnknown
|
||||
fatalMax* = errInternal
|
||||
errMin* = errUnknown
|
||||
errMax* = errUser
|
||||
warnMin* = warnCannotOpenFile
|
||||
warnMax* = pred(hintSuccess)
|
||||
hintMin* = hintSuccess
|
||||
hintMax* = high(TMsgKind)
|
||||
|
||||
static:
|
||||
doAssert HintsToStr.len == ord(hintMax) - ord(hintMin) + 1
|
||||
doAssert WarningsToStr.len == ord(warnMax) - ord(warnMin) + 1
|
||||
|
||||
type
|
||||
TNoteKind* = range[warnMin..hintMax] # "notes" are warnings or hints
|
||||
TNoteKinds* = set[TNoteKind]
|
||||
|
||||
TFileInfo* = object
|
||||
fullPath: string # This is a canonical full filesystem path
|
||||
projPath*: string # This is relative to the project's root
|
||||
@@ -527,35 +59,11 @@ type
|
||||
|
||||
proc `==`*(a, b: FileIndex): bool {.borrow.}
|
||||
|
||||
const
|
||||
NotesVerbosity*: array[0..3, TNoteKinds] = [
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintSuccessX, hintPath, hintConf,
|
||||
hintProcessing, hintPattern,
|
||||
hintDependency,
|
||||
hintExecuting, hintLinking,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {warnShadowIdent, warnUninit,
|
||||
warnProveField, warnProveIndex,
|
||||
warnGcUnsafe,
|
||||
hintPath,
|
||||
hintDependency,
|
||||
hintCodeBegin, hintCodeEnd,
|
||||
hintSource, hintStackTrace,
|
||||
hintGCStats},
|
||||
{low(TNoteKind)..high(TNoteKind)} - {hintStackTrace, warnUninit},
|
||||
{low(TNoteKind)..high(TNoteKind)}]
|
||||
|
||||
const
|
||||
InvalidFileIDX* = FileIndex(-1)
|
||||
|
||||
var
|
||||
ForeignPackageNotes*: TNoteKinds = {hintProcessing, warnUnknownMagic,
|
||||
hintQuitCalled, hintExecuting}
|
||||
filenameToIndexTbl = initTable[string, FileIndex]()
|
||||
fileInfos*: seq[TFileInfo] = @[]
|
||||
systemFileIdx*: FileIndex
|
||||
@@ -591,8 +99,7 @@ proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||
result.shortName = fileName.changeFileExt("")
|
||||
result.quotedName = fileName.makeCString
|
||||
result.quotedFullName = fullPath.makeCString
|
||||
if optEmbedOrigSrc in gGlobalOptions or true:
|
||||
result.lines = @[]
|
||||
result.lines = @[]
|
||||
when defined(nimpretty):
|
||||
if result.fullPath.len > 0:
|
||||
try:
|
||||
@@ -606,22 +113,22 @@ when defined(nimpretty):
|
||||
proc fileSection*(fid: FileIndex; a, b: int): string =
|
||||
substr(fileInfos[fid.int].fullContent, a, b)
|
||||
|
||||
proc fileInfoKnown*(filename: string): bool =
|
||||
proc fileInfoKnown*(conf: ConfigRef; filename: string): bool =
|
||||
var
|
||||
canon: string
|
||||
try:
|
||||
canon = canonicalizePath(filename)
|
||||
canon = canonicalizePath(conf, filename)
|
||||
except:
|
||||
canon = filename
|
||||
result = filenameToIndexTbl.hasKey(canon)
|
||||
|
||||
proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: string; isKnownFile: var bool): FileIndex =
|
||||
var
|
||||
canon: string
|
||||
pseudoPath = false
|
||||
|
||||
try:
|
||||
canon = canonicalizePath(filename)
|
||||
canon = canonicalizePath(conf, filename)
|
||||
shallow(canon)
|
||||
except:
|
||||
canon = filename
|
||||
@@ -635,39 +142,32 @@ proc fileInfoIdx*(filename: string; isKnownFile: var bool): FileIndex =
|
||||
isKnownFile = false
|
||||
result = fileInfos.len.FileIndex
|
||||
fileInfos.add(newFileInfo(canon, if pseudoPath: filename
|
||||
else: canon.shortenDir))
|
||||
else: shortenDir(conf, canon)))
|
||||
filenameToIndexTbl[canon] = result
|
||||
|
||||
proc fileInfoIdx*(filename: string): FileIndex =
|
||||
proc fileInfoIdx*(conf: ConfigRef; filename: string): FileIndex =
|
||||
var dummy: bool
|
||||
result = fileInfoIdx(filename, dummy)
|
||||
result = fileInfoIdx(conf, filename, dummy)
|
||||
|
||||
proc newLineInfo*(fileInfoIdx: FileIndex, line, col: int): TLineInfo =
|
||||
result.fileIndex = fileInfoIdx
|
||||
result.line = uint16(line)
|
||||
result.col = int16(col)
|
||||
|
||||
proc newLineInfo*(filename: string, line, col: int): TLineInfo {.inline.} =
|
||||
result = newLineInfo(filename.fileInfoIdx, line, col)
|
||||
proc newLineInfo*(conf: ConfigRef; filename: string, line, col: int): TLineInfo {.inline.} =
|
||||
result = newLineInfo(fileInfoIdx(conf, filename), line, col)
|
||||
|
||||
fileInfos.add(newFileInfo("", "command line"))
|
||||
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
|
||||
when false:
|
||||
fileInfos.add(newFileInfo("", "command line"))
|
||||
var gCmdLineInfo* = newLineInfo(FileIndex(0), 1, 1)
|
||||
|
||||
fileInfos.add(newFileInfo("", "compilation artifact"))
|
||||
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
|
||||
fileInfos.add(newFileInfo("", "compilation artifact"))
|
||||
var gCodegenLineInfo* = newLineInfo(FileIndex(1), 1, 1)
|
||||
|
||||
proc raiseRecoverableError*(msg: string) {.noinline, noreturn.} =
|
||||
raise newException(ERecoverableError, msg)
|
||||
|
||||
proc sourceLine*(i: TLineInfo): Rope
|
||||
|
||||
var
|
||||
gNotes*: TNoteKinds = NotesVerbosity[1] # defaults to verbosity of 1
|
||||
gErrorCounter*: int = 0 # counts the number of errors
|
||||
gHintCounter*: int = 0
|
||||
gWarnCounter*: int = 0
|
||||
gErrorMax*: int = 1 # stop after gErrorMax errors
|
||||
gMainPackageNotes*: TNoteKinds = NotesVerbosity[1]
|
||||
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope
|
||||
|
||||
proc unknownLineInfo*(): TLineInfo =
|
||||
result.line = uint16(0)
|
||||
@@ -767,10 +267,10 @@ template toFilename*(info: TLineInfo): string =
|
||||
template toFullPath*(info: TLineInfo): string =
|
||||
info.fileIndex.toFullPath
|
||||
|
||||
proc toMsgFilename*(info: TLineInfo): string =
|
||||
proc toMsgFilename*(conf: ConfigRef; info: TLineInfo): string =
|
||||
if info.fileIndex.int32 < 0:
|
||||
result = "???"
|
||||
elif gListFullPaths:
|
||||
elif optListFullPaths in conf.globalOptions:
|
||||
result = fileInfos[info.fileIndex.int32].fullPath
|
||||
else:
|
||||
result = fileInfos[info.fileIndex.int32].projPath
|
||||
@@ -805,7 +305,7 @@ type
|
||||
msgSkipHook ## skip message hook even if it is present
|
||||
MsgFlags* = set[MsgFlag]
|
||||
|
||||
proc msgWriteln*(s: string, flags: MsgFlags = {}) =
|
||||
proc msgWriteln*(conf: ConfigRef; s: string, flags: MsgFlags = {}) =
|
||||
## Writes given message string to stderr by default.
|
||||
## If ``--stdout`` option is given, writes to stdout instead. If message hook
|
||||
## is present, then it is used to output message rather than stderr/stdout.
|
||||
@@ -813,11 +313,11 @@ proc msgWriteln*(s: string, flags: MsgFlags = {}) =
|
||||
|
||||
## This is used for 'nim dump' etc. where we don't have nimsuggest
|
||||
## support.
|
||||
#if gCmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
#if conf.cmd == cmdIdeTools and optCDebug notin gGlobalOptions: return
|
||||
|
||||
if not isNil(writelnHook) and msgSkipHook notin flags:
|
||||
writelnHook(s)
|
||||
elif optStdout in gGlobalOptions or msgStdout in flags:
|
||||
elif optStdout in conf.globalOptions or msgStdout in flags:
|
||||
if eStdOut in errorOutputs:
|
||||
writeLine(stdout, s)
|
||||
flushFile(stdout)
|
||||
@@ -858,13 +358,13 @@ template callWritelnHook(args: varargs[string, `$`]) =
|
||||
template styledMsgWriteln*(args: varargs[typed]) =
|
||||
if not isNil(writelnHook):
|
||||
callIgnoringStyle(callWritelnHook, nil, args)
|
||||
elif optStdout in gGlobalOptions:
|
||||
elif optStdout in conf.globalOptions:
|
||||
if eStdOut in errorOutputs:
|
||||
callIgnoringStyle(writeLine, stdout, args)
|
||||
flushFile(stdout)
|
||||
else:
|
||||
if eStdErr in errorOutputs:
|
||||
if optUseColors in gGlobalOptions:
|
||||
if optUseColors in conf.globalOptions:
|
||||
callStyledWriteLineStderr(args)
|
||||
else:
|
||||
callIgnoringStyle(writeLine, stderr, args)
|
||||
@@ -892,27 +392,27 @@ proc log*(s: string) {.procvar.} =
|
||||
f.writeLine(s)
|
||||
close(f)
|
||||
|
||||
proc quit(msg: TMsgKind) =
|
||||
if defined(debug) or msg == errInternal or hintStackTrace in gNotes:
|
||||
proc quit(conf: ConfigRef; msg: TMsgKind) =
|
||||
if defined(debug) or msg == errInternal or hintStackTrace in conf.notes:
|
||||
if stackTraceAvailable() and isNil(writelnHook):
|
||||
writeStackTrace()
|
||||
else:
|
||||
styledMsgWriteln(fgRed, "No stack traceback available\n" &
|
||||
"To create a stacktrace, rerun compilation with ./koch temp " &
|
||||
options.command & " <file>")
|
||||
conf.command & " <file>")
|
||||
quit 1
|
||||
|
||||
proc handleError(msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) =
|
||||
if msg >= fatalMin and msg <= fatalMax:
|
||||
if gCmd == cmdIdeTools: log(s)
|
||||
quit(msg)
|
||||
if conf.cmd == cmdIdeTools: log(s)
|
||||
quit(conf, msg)
|
||||
if msg >= errMin and msg <= errMax:
|
||||
inc(gErrorCounter)
|
||||
options.gExitcode = 1'i8
|
||||
if gErrorCounter >= gErrorMax:
|
||||
quit(msg)
|
||||
elif eh == doAbort and gCmd != cmdIdeTools:
|
||||
quit(msg)
|
||||
inc(conf.errorCounter)
|
||||
conf.exitcode = 1'i8
|
||||
if conf.errorCounter >= conf.errorMax:
|
||||
quit(conf, msg)
|
||||
elif eh == doAbort and conf.cmd != cmdIdeTools:
|
||||
quit(conf, msg)
|
||||
elif eh == doRaise:
|
||||
raiseRecoverableError(s)
|
||||
|
||||
@@ -922,26 +422,27 @@ proc `==`*(a, b: TLineInfo): bool =
|
||||
proc exactEquals*(a, b: TLineInfo): bool =
|
||||
result = a.fileIndex == b.fileIndex and a.line == b.line and a.col == b.col
|
||||
|
||||
proc writeContext(lastinfo: TLineInfo) =
|
||||
proc writeContext(conf: ConfigRef; lastinfo: TLineInfo) =
|
||||
const instantiationFrom = "template/generic instantiation from here"
|
||||
var info = lastinfo
|
||||
for i in countup(0, len(msgContext) - 1):
|
||||
if msgContext[i] != lastinfo and msgContext[i] != info:
|
||||
if structuredErrorHook != nil:
|
||||
structuredErrorHook(msgContext[i], getMessageStr(errInstantiationFrom, ""),
|
||||
structuredErrorHook(msgContext[i], instantiationFrom,
|
||||
Severity.Error)
|
||||
else:
|
||||
styledMsgWriteln(styleBright,
|
||||
PosFormat % [toMsgFilename(msgContext[i]),
|
||||
PosFormat % [toMsgFilename(conf, msgContext[i]),
|
||||
coordToStr(msgContext[i].line.int),
|
||||
coordToStr(msgContext[i].col+1)],
|
||||
resetStyle,
|
||||
getMessageStr(errInstantiationFrom, ""))
|
||||
instantiationFrom)
|
||||
info = msgContext[i]
|
||||
|
||||
proc ignoreMsgBecauseOfIdeTools(msg: TMsgKind): bool =
|
||||
msg >= errGenerated and gCmd == cmdIdeTools and optIdeDebug notin gGlobalOptions
|
||||
proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool =
|
||||
msg >= errGenerated and conf.cmd == cmdIdeTools and optIdeDebug notin conf.globalOptions
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
||||
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) =
|
||||
var
|
||||
title: string
|
||||
color: ForegroundColor
|
||||
@@ -950,62 +451,62 @@ proc rawMessage*(msg: TMsgKind, args: openArray[string]) =
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
sev = Severity.Error
|
||||
writeContext(unknownLineInfo())
|
||||
writeContext(conf, unknownLineInfo())
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
of warnMin..warnMax:
|
||||
sev = Severity.Warning
|
||||
if optWarns notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
writeContext(unknownLineInfo())
|
||||
if optWarns notin conf.options: return
|
||||
if msg notin conf.notes: return
|
||||
writeContext(conf, unknownLineInfo())
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||
inc(gWarnCounter)
|
||||
inc(conf.warnCounter)
|
||||
of hintMin..hintMax:
|
||||
sev = Severity.Hint
|
||||
if optHints notin gOptions: return
|
||||
if msg notin gNotes: return
|
||||
if optHints notin conf.options: return
|
||||
if msg notin conf.notes: return
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
inc(conf.hintCounter)
|
||||
let s = msgKindToString(msg) % args
|
||||
|
||||
if structuredErrorHook != nil:
|
||||
structuredErrorHook(unknownLineInfo(), s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||
|
||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||
if kind != nil:
|
||||
styledMsgWriteln(color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
styledMsgWriteln(color, title, resetStyle, s)
|
||||
handleError(msg, doAbort, s)
|
||||
handleError(conf, msg, doAbort, s)
|
||||
|
||||
proc rawMessage*(msg: TMsgKind, arg: string) =
|
||||
rawMessage(msg, [arg])
|
||||
proc rawMessage*(conf: ConfigRef; msg: TMsgKind, arg: string) =
|
||||
rawMessage(conf, msg, [arg])
|
||||
|
||||
proc resetAttributes* =
|
||||
if {optUseColors, optStdout} * gGlobalOptions == {optUseColors}:
|
||||
proc resetAttributes*(conf: ConfigRef) =
|
||||
if {optUseColors, optStdout} * conf.globalOptions == {optUseColors}:
|
||||
terminal.resetAttributes(stderr)
|
||||
|
||||
proc writeSurroundingSrc(info: TLineInfo) =
|
||||
proc writeSurroundingSrc(conf: ConfigRef; info: TLineInfo) =
|
||||
const indent = " "
|
||||
msgWriteln(indent & $info.sourceLine)
|
||||
msgWriteln(indent & spaces(info.col) & '^')
|
||||
msgWriteln(conf, indent & $sourceLine(conf, info))
|
||||
msgWriteln(conf, indent & spaces(info.col) & '^')
|
||||
|
||||
proc formatMsg*(info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
proc formatMsg*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string): string =
|
||||
let title = case msg
|
||||
of warnMin..warnMax: WarningTitle
|
||||
of hintMin..hintMax: HintTitle
|
||||
else: ErrorTitle
|
||||
result = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
|
||||
result = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
|
||||
coordToStr(info.col+1)] &
|
||||
title &
|
||||
getMessageStr(msg, arg)
|
||||
|
||||
proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
eh: TErrorHandling) =
|
||||
var
|
||||
title: string
|
||||
@@ -1016,7 +517,7 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
case msg
|
||||
of errMin..errMax:
|
||||
sev = Severity.Error
|
||||
writeContext(info)
|
||||
writeContext(conf, info)
|
||||
title = ErrorTitle
|
||||
color = ErrorColor
|
||||
# we try to filter error messages so that not two error message
|
||||
@@ -1025,101 +526,101 @@ proc liMessage(info: TLineInfo, msg: TMsgKind, arg: string,
|
||||
lastError = info
|
||||
of warnMin..warnMax:
|
||||
sev = Severity.Warning
|
||||
ignoreMsg = optWarns notin gOptions or msg notin gNotes
|
||||
if not ignoreMsg: writeContext(info)
|
||||
ignoreMsg = optWarns notin conf.options or msg notin conf.notes
|
||||
if not ignoreMsg: writeContext(conf, info)
|
||||
title = WarningTitle
|
||||
color = WarningColor
|
||||
kind = WarningsToStr[ord(msg) - ord(warnMin)]
|
||||
inc(gWarnCounter)
|
||||
inc(conf.warnCounter)
|
||||
of hintMin..hintMax:
|
||||
sev = Severity.Hint
|
||||
ignoreMsg = optHints notin gOptions or msg notin gNotes
|
||||
ignoreMsg = optHints notin conf.options or msg notin conf.notes
|
||||
title = HintTitle
|
||||
color = HintColor
|
||||
if msg != hintUserRaw: kind = HintsToStr[ord(msg) - ord(hintMin)]
|
||||
inc(gHintCounter)
|
||||
inc(conf.hintCounter)
|
||||
# NOTE: currently line info line numbers start with 1,
|
||||
# but column numbers start with 0, however most editors expect
|
||||
# first column to be 1, so we need to +1 here
|
||||
let x = PosFormat % [toMsgFilename(info), coordToStr(info.line.int),
|
||||
let x = PosFormat % [toMsgFilename(conf, info), coordToStr(info.line.int),
|
||||
coordToStr(info.col+1)]
|
||||
let s = getMessageStr(msg, arg)
|
||||
|
||||
if not ignoreMsg:
|
||||
if structuredErrorHook != nil:
|
||||
structuredErrorHook(info, s & (if kind != nil: KindFormat % kind else: ""), sev)
|
||||
if not ignoreMsgBecauseOfIdeTools(msg):
|
||||
if not ignoreMsgBecauseOfIdeTools(conf, msg):
|
||||
if kind != nil:
|
||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s,
|
||||
KindColor, `%`(KindFormat, kind))
|
||||
else:
|
||||
styledMsgWriteln(styleBright, x, resetStyle, color, title, resetStyle, s)
|
||||
if hintSource in gNotes:
|
||||
info.writeSurroundingSrc
|
||||
handleError(msg, eh, s)
|
||||
if hintSource in conf.notes:
|
||||
conf.writeSurroundingSrc(info)
|
||||
handleError(conf, msg, eh, s)
|
||||
|
||||
proc fatal*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
proc fatal*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
# this fixes bug #7080 so that it is at least obvious 'fatal'
|
||||
# was executed.
|
||||
errorOutputs = {eStdOut, eStdErr}
|
||||
liMessage(info, msg, arg, doAbort)
|
||||
liMessage(conf, info, msg, arg, doAbort)
|
||||
|
||||
proc globalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doRaise)
|
||||
proc globalError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(conf, info, msg, arg, doRaise)
|
||||
|
||||
proc globalError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doRaise)
|
||||
proc globalError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||
liMessage(conf, info, errGenerated, arg, doRaise)
|
||||
|
||||
proc localError*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(conf, info, msg, arg, doNothing)
|
||||
|
||||
proc localError*(info: TLineInfo, arg: string) =
|
||||
liMessage(info, errGenerated, arg, doNothing)
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, arg: string) =
|
||||
liMessage(conf, info, errGenerated, arg, doNothing)
|
||||
|
||||
proc localError*(info: TLineInfo, format: string, params: openarray[string]) =
|
||||
localError(info, format % params)
|
||||
proc localError*(conf: ConfigRef; info: TLineInfo, format: string, params: openarray[string]) =
|
||||
localError(conf, info, format % params)
|
||||
|
||||
proc message*(info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(info, msg, arg, doNothing)
|
||||
proc message*(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg = "") =
|
||||
liMessage(conf, info, msg, arg, doNothing)
|
||||
|
||||
proc internalError*(info: TLineInfo, errMsg: string) =
|
||||
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||
writeContext(info)
|
||||
liMessage(info, errInternal, errMsg, doAbort)
|
||||
proc internalError*(conf: ConfigRef; info: TLineInfo, errMsg: string) =
|
||||
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||
writeContext(conf, info)
|
||||
liMessage(conf, info, errInternal, errMsg, doAbort)
|
||||
|
||||
proc internalError*(errMsg: string) =
|
||||
if gCmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||
writeContext(unknownLineInfo())
|
||||
rawMessage(errInternal, errMsg)
|
||||
proc internalError*(conf: ConfigRef; errMsg: string) =
|
||||
if conf.cmd == cmdIdeTools and structuredErrorHook.isNil: return
|
||||
writeContext(conf, unknownLineInfo())
|
||||
rawMessage(conf, errInternal, errMsg)
|
||||
|
||||
template assertNotNil*(e): untyped =
|
||||
if e == nil: internalError($instantiationInfo())
|
||||
template assertNotNil*(conf: ConfigRef; e): untyped =
|
||||
if e == nil: internalError(conf, $instantiationInfo())
|
||||
e
|
||||
|
||||
template internalAssert*(e: bool) =
|
||||
if not e: internalError($instantiationInfo())
|
||||
template internalAssert*(conf: ConfigRef, e: bool) =
|
||||
if not e: internalError(conf, $instantiationInfo())
|
||||
|
||||
proc addSourceLine*(fileIdx: FileIndex, line: string) =
|
||||
fileInfos[fileIdx.int32].lines.add line.rope
|
||||
|
||||
proc sourceLine*(i: TLineInfo): Rope =
|
||||
proc sourceLine*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
if i.fileIndex.int32 < 0: return nil
|
||||
|
||||
if not optPreserveOrigSource and fileInfos[i.fileIndex.int32].lines.len == 0:
|
||||
if not optPreserveOrigSource(conf) and fileInfos[i.fileIndex.int32].lines.len == 0:
|
||||
try:
|
||||
for line in lines(i.toFullPath):
|
||||
addSourceLine i.fileIndex, line.string
|
||||
except IOError:
|
||||
discard
|
||||
internalAssert i.fileIndex.int32 < fileInfos.len
|
||||
assert i.fileIndex.int32 < fileInfos.len
|
||||
# can happen if the error points to EOF:
|
||||
if i.line.int > fileInfos[i.fileIndex.int32].lines.len: return nil
|
||||
|
||||
result = fileInfos[i.fileIndex.int32].lines[i.line.int-1]
|
||||
|
||||
proc quotedFilename*(i: TLineInfo): Rope =
|
||||
internalAssert i.fileIndex.int32 >= 0
|
||||
if optExcessiveStackTrace in gGlobalOptions:
|
||||
proc quotedFilename*(conf: ConfigRef; i: TLineInfo): Rope =
|
||||
assert i.fileIndex.int32 >= 0
|
||||
if optExcessiveStackTrace in conf.globalOptions:
|
||||
result = fileInfos[i.fileIndex.int32].quotedFullName
|
||||
else:
|
||||
result = fileInfos[i.fileIndex.int32].quotedName
|
||||
@@ -1127,26 +628,22 @@ proc quotedFilename*(i: TLineInfo): Rope =
|
||||
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
|
||||
case err
|
||||
of rInvalidFormatStr:
|
||||
internalError("ropes: invalid format string: " & msg)
|
||||
internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg)
|
||||
of rCannotOpenFile:
|
||||
rawMessage(if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||
rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
|
||||
|
||||
proc listWarnings*() =
|
||||
msgWriteln("Warnings:")
|
||||
proc listWarnings*(conf: ConfigRef) =
|
||||
msgWriteln(conf, "Warnings:")
|
||||
for warn in warnMin..warnMax:
|
||||
msgWriteln(" [$1] $2" % [
|
||||
if warn in gNotes: "x" else: " ",
|
||||
msgs.WarningsToStr[ord(warn) - ord(warnMin)]
|
||||
msgWriteln(conf, " [$1] $2" % [
|
||||
if warn in conf.notes: "x" else: " ",
|
||||
configuration.WarningsToStr[ord(warn) - ord(warnMin)]
|
||||
])
|
||||
|
||||
proc listHints*() =
|
||||
msgWriteln("Hints:")
|
||||
proc listHints*(conf: ConfigRef) =
|
||||
msgWriteln(conf, "Hints:")
|
||||
for hint in hintMin..hintMax:
|
||||
msgWriteln(" [$1] $2" % [
|
||||
if hint in gNotes: "x" else: " ",
|
||||
msgs.HintsToStr[ord(hint) - ord(hintMin)]
|
||||
msgWriteln(conf, " [$1] $2" % [
|
||||
if hint in conf.notes: "x" else: " ",
|
||||
configuration.HintsToStr[ord(hint) - ord(hintMin)]
|
||||
])
|
||||
|
||||
# enable colors by default on terminals
|
||||
if terminal.isatty(stderr):
|
||||
incl(gGlobalOptions, optUseColors)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#
|
||||
|
||||
import
|
||||
os, strutils, strtabs, osproc, sets
|
||||
os, strutils, strtabs, osproc, sets, configuration, platform
|
||||
|
||||
from terminal import isatty
|
||||
|
||||
const
|
||||
hasTinyCBackend* = defined(tinyc)
|
||||
@@ -17,7 +19,6 @@ const
|
||||
hasFFI* = defined(useFFI)
|
||||
newScopeForIf* = true
|
||||
useCaas* = not defined(noCaas)
|
||||
noTimeMachine* = defined(avoidTimeMachine) and defined(macosx)
|
||||
copyrightYear* = "2018"
|
||||
|
||||
type # please make sure we have under 32 options
|
||||
@@ -71,6 +72,11 @@ type # please make sure we have under 32 options
|
||||
optIdeTerse # idetools: use terse descriptions
|
||||
optNoCppExceptions # use C exception handling even with CPP
|
||||
optExcessiveStackTrace # fully qualified module filenames
|
||||
optWholeProject # for 'doc2': output any dependency
|
||||
optListFullPaths
|
||||
optNoNimblePath
|
||||
optDynlibOverrideAll
|
||||
optUseNimNamespace
|
||||
|
||||
TGlobalOptions* = set[TGlobalOption]
|
||||
|
||||
@@ -112,74 +118,177 @@ type
|
||||
destructor,
|
||||
notnil
|
||||
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
|
||||
ConfigRef* = ref object ## eventually all global configuration should be moved here
|
||||
linesCompiled*: int # all lines that have been compiled
|
||||
options*: TOptions
|
||||
globalOptions*: TGlobalOptions
|
||||
exitcode*: int8
|
||||
cmd*: TCommands # the command
|
||||
selectedGC*: TGCMode # the selected GC
|
||||
verbosity*: int # how verbose the compiler is
|
||||
numberOfProcessors*: int # number of processors
|
||||
evalExpr*: string # expression for idetools --eval
|
||||
lastCmdTime*: float # when caas is enabled, we measure each command
|
||||
symbolFiles*: SymbolFilesOption
|
||||
|
||||
cppDefines*: HashSet[string]
|
||||
headerFile*: string
|
||||
features*: set[Feature]
|
||||
arguments*: string ## the arguments to be passed to the program that
|
||||
## should be run
|
||||
helpWritten*: bool
|
||||
ideCmd*: IdeCmd
|
||||
oldNewlines*: bool
|
||||
enableNotes*: TNoteKinds
|
||||
disableNotes*: TNoteKinds
|
||||
foreignPackageNotes*: TNoteKinds
|
||||
notes*: TNoteKinds
|
||||
mainPackageNotes*: TNoteKinds
|
||||
errorCounter*: int
|
||||
hintCounter*: int
|
||||
warnCounter*: int
|
||||
errorMax*: int
|
||||
configVars*: StringTableRef
|
||||
symbols*: StringTableRef ## We need to use a StringTableRef here as defined
|
||||
## symbols are always guaranteed to be style
|
||||
## insensitive. Otherwise hell would break lose.
|
||||
packageCache*: StringTableRef
|
||||
searchPaths*: seq[string]
|
||||
lazyPaths*: seq[string]
|
||||
outFile*, prefixDir*, libpath*, nimcacheDir*: string
|
||||
dllOverrides, moduleOverrides*: StringTableRef
|
||||
projectName*: string # holds a name like 'nim'
|
||||
projectPath*: string # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull*: string # projectPath/projectName
|
||||
projectIsStdin*: bool # whether we're compiling from stdin
|
||||
projectMainIdx*: int32 # the canonical path id of the main module
|
||||
command*: string # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs*: seq[string] # any arguments after the main command
|
||||
keepComments*: bool # whether the parser needs to keep comments
|
||||
implicitImports*: seq[string] # modules that are to be implicitly imported
|
||||
implicitIncludes*: seq[string] # modules that are to be implicitly included
|
||||
docSeeSrcUrl*: string # if empty, no seeSrc will be generated. \
|
||||
# The string uses the formatting variables `path` and `line`.
|
||||
|
||||
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
|
||||
|
||||
proc newConfigRef*(): ConfigRef =
|
||||
result = ConfigRef(cppDefines: initSet[string](),
|
||||
headerFile: "", features: {})
|
||||
|
||||
proc cppDefine*(c: ConfigRef; define: string) =
|
||||
c.cppDefines.incl define
|
||||
|
||||
var
|
||||
gIdeCmd*: IdeCmd
|
||||
gOldNewlines*: bool
|
||||
|
||||
const
|
||||
ChecksOptions* = {optObjCheck, optFieldCheck, optRangeCheck, optNilCheck,
|
||||
optOverflowCheck, optBoundsCheck, optAssert, optNaNCheck, optInfCheck,
|
||||
optMoveCheck}
|
||||
|
||||
var
|
||||
gOptions*: TOptions = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||
optHints, optStackTrace, optLineTrace,
|
||||
optPatterns, optNilCheck, optMoveCheck}
|
||||
gGlobalOptions*: TGlobalOptions = {optThreadAnalysis}
|
||||
gExitcode*: int8
|
||||
gCmd*: TCommands = cmdNone # the command
|
||||
gSelectedGC* = gcRefc # the selected GC
|
||||
searchPaths*: seq[string] = @[]
|
||||
lazyPaths*: seq[string] = @[]
|
||||
outFile*: string = ""
|
||||
docSeeSrcUrl*: string = "" # if empty, no seeSrc will be generated. \
|
||||
# The string uses the formatting variables `path` and `line`.
|
||||
#headerFile*: string = ""
|
||||
gVerbosity* = 1 # how verbose the compiler is
|
||||
gNumberOfProcessors*: int # number of processors
|
||||
gWholeProject*: bool # for 'doc2': output any dependency
|
||||
gEvalExpr* = "" # expression for idetools --eval
|
||||
gLastCmdTime*: float # when caas is enabled, we measure each command
|
||||
gListFullPaths*: bool
|
||||
gPreciseStack*: bool = false
|
||||
gNoNimblePath* = false
|
||||
gDynlibOverrideAll*: bool
|
||||
useNimNamespace*: bool
|
||||
DefaultOptions* = {optObjCheck, optFieldCheck, optRangeCheck,
|
||||
optBoundsCheck, optOverflowCheck, optAssert, optWarns,
|
||||
optHints, optStackTrace, optLineTrace,
|
||||
optPatterns, optNilCheck, optMoveCheck}
|
||||
DefaultGlobalOptions* = {optThreadAnalysis}
|
||||
|
||||
type
|
||||
SymbolFilesOption* = enum
|
||||
disabledSf, enabledSf, writeOnlySf, readOnlySf, v2Sf
|
||||
template newPackageCache*(): untyped =
|
||||
newStringTable(when FileSystemCaseSensitive:
|
||||
modeCaseInsensitive
|
||||
else:
|
||||
modeCaseSensitive)
|
||||
|
||||
var gSymbolFiles*: SymbolFilesOption
|
||||
proc newConfigRef*(): ConfigRef =
|
||||
result = ConfigRef(
|
||||
selectedGC: gcRefc,
|
||||
verbosity: 1,
|
||||
options: DefaultOptions,
|
||||
globalOptions: DefaultGlobalOptions,
|
||||
evalExpr: "",
|
||||
cppDefines: initSet[string](),
|
||||
headerFile: "", features: {}, foreignPackageNotes: {hintProcessing, warnUnknownMagic,
|
||||
hintQuitCalled, hintExecuting},
|
||||
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
|
||||
configVars: newStringTable(modeStyleInsensitive),
|
||||
symbols: newStringTable(modeStyleInsensitive),
|
||||
packageCache: newPackageCache(),
|
||||
searchPaths: @[],
|
||||
lazyPaths: @[],
|
||||
outFile: "", prefixDir: "", libpath: "", nimcacheDir: "",
|
||||
dllOverrides: newStringTable(modeCaseInsensitive),
|
||||
moduleOverrides: newStringTable(modeStyleInsensitive),
|
||||
projectName: "", # holds a name like 'nim'
|
||||
projectPath: "", # holds a path like /home/alice/projects/nim/compiler/
|
||||
projectFull: "", # projectPath/projectName
|
||||
projectIsStdin: false, # whether we're compiling from stdin
|
||||
projectMainIdx: 0'i32, # the canonical path id of the main module
|
||||
command: "", # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs: @[], # any arguments after the main command
|
||||
keepComments: true, # whether the parser needs to keep comments
|
||||
implicitImports: @[], # modules that are to be implicitly imported
|
||||
implicitIncludes: @[], # modules that are to be implicitly included
|
||||
docSeeSrcUrl: ""
|
||||
)
|
||||
# enable colors by default on terminals
|
||||
if terminal.isatty(stderr):
|
||||
incl(result.globalOptions, optUseColors)
|
||||
|
||||
proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools}
|
||||
proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc
|
||||
template preciseStack*(): bool = gPreciseStack
|
||||
proc newPartialConfigRef*(): ConfigRef =
|
||||
## create a new ConfigRef that is only good enough for error reporting.
|
||||
result = ConfigRef(
|
||||
selectedGC: gcRefc,
|
||||
verbosity: 1,
|
||||
options: DefaultOptions,
|
||||
globalOptions: DefaultGlobalOptions,
|
||||
foreignPackageNotes: {hintProcessing, warnUnknownMagic,
|
||||
hintQuitCalled, hintExecuting},
|
||||
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1])
|
||||
|
||||
template compilationCachePresent*: untyped =
|
||||
gSymbolFiles in {enabledSf, writeOnlySf}
|
||||
proc cppDefine*(c: ConfigRef; define: string) =
|
||||
c.cppDefines.incl define
|
||||
|
||||
proc isDefined*(conf: ConfigRef; symbol: string): bool =
|
||||
if conf.symbols.hasKey(symbol):
|
||||
result = conf.symbols[symbol] != "false"
|
||||
elif cmpIgnoreStyle(symbol, CPU[targetCPU].name) == 0:
|
||||
result = true
|
||||
elif cmpIgnoreStyle(symbol, platform.OS[targetOS].name) == 0:
|
||||
result = true
|
||||
else:
|
||||
case symbol.normalize
|
||||
of "x86": result = targetCPU == cpuI386
|
||||
of "itanium": result = targetCPU == cpuIa64
|
||||
of "x8664": result = targetCPU == cpuAmd64
|
||||
of "posix", "unix":
|
||||
result = targetOS in {osLinux, osMorphos, osSkyos, osIrix, osPalmos,
|
||||
osQnx, osAtari, osAix,
|
||||
osHaiku, osVxWorks, osSolaris, osNetbsd,
|
||||
osFreebsd, osOpenbsd, osDragonfly, osMacosx,
|
||||
osAndroid}
|
||||
of "linux":
|
||||
result = targetOS in {osLinux, osAndroid}
|
||||
of "bsd":
|
||||
result = targetOS in {osNetbsd, osFreebsd, osOpenbsd, osDragonfly}
|
||||
of "emulatedthreadvars":
|
||||
result = platform.OS[targetOS].props.contains(ospLacksThreadVars)
|
||||
of "msdos": result = targetOS == osDos
|
||||
of "mswindows", "win32": result = targetOS == osWindows
|
||||
of "macintosh": result = targetOS in {osMacos, osMacosx}
|
||||
of "sunos": result = targetOS == osSolaris
|
||||
of "littleendian": result = CPU[targetCPU].endian == platform.littleEndian
|
||||
of "bigendian": result = CPU[targetCPU].endian == platform.bigEndian
|
||||
of "cpu8": result = CPU[targetCPU].bit == 8
|
||||
of "cpu16": result = CPU[targetCPU].bit == 16
|
||||
of "cpu32": result = CPU[targetCPU].bit == 32
|
||||
of "cpu64": result = CPU[targetCPU].bit == 64
|
||||
of "nimrawsetjmp":
|
||||
result = targetOS in {osSolaris, osNetbsd, osFreebsd, osOpenbsd,
|
||||
osDragonfly, osMacosx}
|
||||
else: discard
|
||||
|
||||
proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools}
|
||||
proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc
|
||||
|
||||
template compilationCachePresent*(conf: ConfigRef): untyped =
|
||||
conf.symbolFiles in {enabledSf, writeOnlySf}
|
||||
# {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {}
|
||||
|
||||
template optPreserveOrigSource*: untyped =
|
||||
optEmbedOrigSrc in gGlobalOptions
|
||||
template optPreserveOrigSource*(conf: ConfigRef): untyped =
|
||||
optEmbedOrigSrc in conf.globalOptions
|
||||
|
||||
const
|
||||
genSubDir* = "nimcache"
|
||||
@@ -194,82 +303,62 @@ const
|
||||
DocConfig* = "nimdoc.cfg"
|
||||
DocTexConfig* = "nimdoc.tex.cfg"
|
||||
|
||||
# additional configuration variables:
|
||||
var
|
||||
gConfigVars* = newStringTable(modeStyleInsensitive)
|
||||
gDllOverrides = newStringTable(modeCaseInsensitive)
|
||||
gModuleOverrides* = newStringTable(modeStyleInsensitive)
|
||||
gPrefixDir* = "" # Overrides the default prefix dir in getPrefixDir proc.
|
||||
libpath* = ""
|
||||
gProjectName* = "" # holds a name like 'nim'
|
||||
gProjectPath* = "" # holds a path like /home/alice/projects/nim/compiler/
|
||||
gProjectFull* = "" # projectPath/projectName
|
||||
gProjectIsStdin* = false # whether we're compiling from stdin
|
||||
gProjectMainIdx*: int32 # the canonical path id of the main module
|
||||
nimcacheDir* = ""
|
||||
command* = "" # the main command (e.g. cc, check, scan, etc)
|
||||
commandArgs*: seq[string] = @[] # any arguments after the main command
|
||||
gKeepComments*: bool = true # whether the parser needs to keep comments
|
||||
implicitImports*: seq[string] = @[] # modules that are to be implicitly imported
|
||||
implicitIncludes*: seq[string] = @[] # modules that are to be implicitly included
|
||||
|
||||
const oKeepVariableNames* = true
|
||||
|
||||
template compilingLib*: bool =
|
||||
template compilingLib*(conf: ConfigRef): bool =
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
|
||||
|
||||
proc mainCommandArg*: string =
|
||||
proc mainCommandArg*(conf: ConfigRef): string =
|
||||
## This is intended for commands like check or parse
|
||||
## which will work on the main project file unless
|
||||
## explicitly given a specific file argument
|
||||
if commandArgs.len > 0:
|
||||
result = commandArgs[0]
|
||||
if conf.commandArgs.len > 0:
|
||||
result = conf.commandArgs[0]
|
||||
else:
|
||||
result = gProjectName
|
||||
result = conf.projectName
|
||||
|
||||
proc existsConfigVar*(key: string): bool =
|
||||
result = hasKey(gConfigVars, key)
|
||||
proc existsConfigVar*(conf: ConfigRef; key: string): bool =
|
||||
result = hasKey(conf.configVars, key)
|
||||
|
||||
proc getConfigVar*(key: string): string =
|
||||
result = gConfigVars.getOrDefault key
|
||||
proc getConfigVar*(conf: ConfigRef; key: string): string =
|
||||
result = conf.configVars.getOrDefault key
|
||||
|
||||
proc setConfigVar*(key, val: string) =
|
||||
gConfigVars[key] = val
|
||||
proc setConfigVar*(conf: ConfigRef; key, val: string) =
|
||||
conf.configVars[key] = val
|
||||
|
||||
proc getOutFile*(filename, ext: string): string =
|
||||
if options.outFile != "": result = options.outFile
|
||||
proc getOutFile*(conf: ConfigRef; filename, ext: string): string =
|
||||
if conf.outFile != "": result = conf.outFile
|
||||
else: result = changeFileExt(filename, ext)
|
||||
|
||||
proc getPrefixDir*(): string =
|
||||
proc getPrefixDir*(conf: ConfigRef): string =
|
||||
## Gets the prefix dir, usually the parent directory where the binary resides.
|
||||
##
|
||||
## This is overridden by some tools (namely nimsuggest) via the ``gPrefixDir``
|
||||
## This is overridden by some tools (namely nimsuggest) via the ``conf.prefixDir``
|
||||
## global.
|
||||
if gPrefixDir != "": result = gPrefixDir
|
||||
else:
|
||||
result = splitPath(getAppDir()).head
|
||||
if conf.prefixDir != "": result = conf.prefixDir
|
||||
else: result = splitPath(getAppDir()).head
|
||||
|
||||
proc setDefaultLibpath*() =
|
||||
proc setDefaultLibpath*(conf: ConfigRef) =
|
||||
# set default value (can be overwritten):
|
||||
if libpath == "":
|
||||
if conf.libpath == "":
|
||||
# choose default libpath:
|
||||
var prefix = getPrefixDir()
|
||||
var prefix = getPrefixDir(conf)
|
||||
when defined(posix):
|
||||
if prefix == "/usr": libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": libpath = "/usr/local/lib/nim"
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
else: libpath = joinPath(prefix, "lib")
|
||||
if prefix == "/usr": conf.libpath = "/usr/lib/nim"
|
||||
elif prefix == "/usr/local": conf.libpath = "/usr/local/lib/nim"
|
||||
else: conf.libpath = joinPath(prefix, "lib")
|
||||
else: conf.libpath = joinPath(prefix, "lib")
|
||||
|
||||
# Special rule to support other tools (nimble) which import the compiler
|
||||
# modules and make use of them.
|
||||
let realNimPath = findExe("nim")
|
||||
# Find out if $nim/../../lib/system.nim exists.
|
||||
let parentNimLibPath = realNimPath.parentDir().parentDir() / "lib"
|
||||
if not fileExists(libpath / "system.nim") and
|
||||
let parentNimLibPath = realNimPath.parentDir.parentDir / "lib"
|
||||
if not fileExists(conf.libpath / "system.nim") and
|
||||
fileExists(parentNimlibPath / "system.nim"):
|
||||
libpath = parentNimLibPath
|
||||
conf.libpath = parentNimLibPath
|
||||
|
||||
proc canonicalizePath*(path: string): string =
|
||||
proc canonicalizePath*(conf: ConfigRef; path: string): string =
|
||||
# on Windows, 'expandFilename' calls getFullPathName which doesn't do
|
||||
# case corrections, so we have to use this convoluted way of retrieving
|
||||
# the true filename (see tests/modules and Nimble uses 'import Uri' instead
|
||||
@@ -281,12 +370,12 @@ proc canonicalizePath*(path: string): string =
|
||||
else:
|
||||
result = path.expandFilename
|
||||
|
||||
proc shortenDir*(dir: string): string =
|
||||
proc shortenDir*(conf: ConfigRef; dir: string): string =
|
||||
## returns the interesting part of a dir
|
||||
var prefix = gProjectPath & DirSep
|
||||
var prefix = conf.projectPath & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
prefix = getPrefixDir() & DirSep
|
||||
prefix = getPrefixDir(conf) & DirSep
|
||||
if startsWith(dir, prefix):
|
||||
return substr(dir, len(prefix))
|
||||
result = dir
|
||||
@@ -297,114 +386,89 @@ proc removeTrailingDirSep*(path: string): string =
|
||||
else:
|
||||
result = path
|
||||
|
||||
proc disableNimblePath*() =
|
||||
gNoNimblePath = true
|
||||
lazyPaths.setLen(0)
|
||||
proc disableNimblePath*(conf: ConfigRef) =
|
||||
incl conf.globalOptions, optNoNimblePath
|
||||
conf.lazyPaths.setLen(0)
|
||||
|
||||
include packagehandling
|
||||
|
||||
proc getNimcacheDir*: string =
|
||||
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
|
||||
genSubDir
|
||||
proc getNimcacheDir*(conf: ConfigRef): string =
|
||||
result = if conf.nimcacheDir.len > 0: conf.nimcacheDir
|
||||
else: shortenDir(conf, conf.projectPath) / genSubDir
|
||||
|
||||
|
||||
proc pathSubs*(p, config: string): string =
|
||||
proc pathSubs*(conf: ConfigRef; p, config: string): string =
|
||||
let home = removeTrailingDirSep(os.getHomeDir())
|
||||
result = unixToNativePath(p % [
|
||||
"nim", getPrefixDir(),
|
||||
"lib", libpath,
|
||||
"nim", getPrefixDir(conf),
|
||||
"lib", conf.libpath,
|
||||
"home", home,
|
||||
"config", config,
|
||||
"projectname", options.gProjectName,
|
||||
"projectpath", options.gProjectPath,
|
||||
"projectdir", options.gProjectPath,
|
||||
"nimcache", getNimcacheDir()])
|
||||
"projectname", conf.projectName,
|
||||
"projectpath", conf.projectPath,
|
||||
"projectdir", conf.projectPath,
|
||||
"nimcache", getNimcacheDir(conf)])
|
||||
if "~/" in result:
|
||||
result = result.replace("~/", home & '/')
|
||||
|
||||
proc toGeneratedFile*(path, ext: string): string =
|
||||
proc toGeneratedFile*(conf: ConfigRef; path, ext: string): string =
|
||||
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
|
||||
var (head, tail) = splitPath(path)
|
||||
#if len(head) > 0: head = shortenDir(head & dirSep)
|
||||
result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)])
|
||||
result = joinPath([getNimcacheDir(conf), changeFileExt(tail, ext)])
|
||||
#echo "toGeneratedFile(", path, ", ", ext, ") = ", result
|
||||
|
||||
when noTimeMachine:
|
||||
var alreadyExcludedDirs = initSet[string]()
|
||||
proc excludeDirFromTimeMachine(dir: string) {.raises: [].} =
|
||||
## Calls a macosx command on the directory to exclude it from backups.
|
||||
##
|
||||
## The macosx tmutil command is invoked to mark the specified path as an
|
||||
## item to be excluded from time machine backups. If a path already exists
|
||||
## with files before excluding it, newer files won't be added to the
|
||||
## directory, but previous files won't be removed from the backup until the
|
||||
## user deletes that directory.
|
||||
##
|
||||
## The whole proc is optional and will ignore all kinds of errors. The only
|
||||
## way to be sure that it works is to call ``tmutil isexcluded path``.
|
||||
if alreadyExcludedDirs.contains(dir): return
|
||||
alreadyExcludedDirs.incl(dir)
|
||||
try:
|
||||
var p = startProcess("/usr/bin/tmutil", args = ["addexclusion", dir])
|
||||
discard p.waitForExit
|
||||
p.close
|
||||
except Exception:
|
||||
discard
|
||||
|
||||
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
|
||||
proc completeGeneratedFilePath*(conf: ConfigRef; f: string, createSubDir: bool = true): string =
|
||||
var (head, tail) = splitPath(f)
|
||||
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
|
||||
var subdir = getNimcacheDir() # / head
|
||||
var subdir = getNimcacheDir(conf) # / head
|
||||
if createSubDir:
|
||||
try:
|
||||
createDir(subdir)
|
||||
when noTimeMachine:
|
||||
excludeDirFromTimeMachine(subdir)
|
||||
except OSError:
|
||||
writeLine(stdout, "cannot create directory: " & subdir)
|
||||
quit(1)
|
||||
result = joinPath(subdir, tail)
|
||||
#echo "completeGeneratedFilePath(", f, ") = ", result
|
||||
|
||||
proc rawFindFile(f: string): string =
|
||||
for it in searchPaths:
|
||||
proc rawFindFile(conf: ConfigRef; f: string): string =
|
||||
for it in conf.searchPaths:
|
||||
result = joinPath(it, f)
|
||||
if existsFile(result):
|
||||
return result.canonicalizePath
|
||||
return canonicalizePath(conf, result)
|
||||
result = ""
|
||||
|
||||
proc rawFindFile2(f: string): string =
|
||||
for i, it in lazyPaths:
|
||||
proc rawFindFile2(conf: ConfigRef; f: string): string =
|
||||
for i, it in conf.lazyPaths:
|
||||
result = joinPath(it, f)
|
||||
if existsFile(result):
|
||||
# bring to front
|
||||
for j in countDown(i,1):
|
||||
swap(lazyPaths[j], lazyPaths[j-1])
|
||||
swap(conf.lazyPaths[j], conf.lazyPaths[j-1])
|
||||
|
||||
return result.canonicalizePath
|
||||
return canonicalizePath(conf, result)
|
||||
result = ""
|
||||
|
||||
template patchModule() {.dirty.} =
|
||||
if result.len > 0 and gModuleOverrides.len > 0:
|
||||
let key = getPackageName(result) & "_" & splitFile(result).name
|
||||
if gModuleOverrides.hasKey(key):
|
||||
let ov = gModuleOverrides[key]
|
||||
template patchModule(conf: ConfigRef) {.dirty.} =
|
||||
if result.len > 0 and conf.moduleOverrides.len > 0:
|
||||
let key = getPackageName(conf, result) & "_" & splitFile(result).name
|
||||
if conf.moduleOverrides.hasKey(key):
|
||||
let ov = conf.moduleOverrides[key]
|
||||
if ov.len > 0: result = ov
|
||||
|
||||
proc findFile*(f: string): string {.procvar.} =
|
||||
proc findFile*(conf: ConfigRef; f: string): string {.procvar.} =
|
||||
if f.isAbsolute:
|
||||
result = if f.existsFile: f else: ""
|
||||
else:
|
||||
result = f.rawFindFile
|
||||
result = rawFindFile(conf, f)
|
||||
if result.len == 0:
|
||||
result = f.toLowerAscii.rawFindFile
|
||||
result = rawFindFile(conf, f.toLowerAscii)
|
||||
if result.len == 0:
|
||||
result = f.rawFindFile2
|
||||
result = rawFindFile2(conf, f)
|
||||
if result.len == 0:
|
||||
result = f.toLowerAscii.rawFindFile2
|
||||
patchModule()
|
||||
result = rawFindFile2(conf, f.toLowerAscii)
|
||||
patchModule(conf)
|
||||
|
||||
proc findModule*(modulename, currentModule: string): string =
|
||||
proc findModule*(conf: ConfigRef; modulename, currentModule: string): string =
|
||||
# returns path to module
|
||||
when defined(nimfix):
|
||||
# '.nimfix' modules are preferred over '.nim' modules so that specialized
|
||||
@@ -414,16 +478,16 @@ proc findModule*(modulename, currentModule: string): string =
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = findFile(m)
|
||||
result = findFile(conf, m)
|
||||
if existsFile(result): return result
|
||||
let m = addFileExt(modulename, NimExt)
|
||||
let currentPath = currentModule.splitFile.dir
|
||||
result = currentPath / m
|
||||
if not existsFile(result):
|
||||
result = findFile(m)
|
||||
patchModule()
|
||||
result = findFile(conf, m)
|
||||
patchModule(conf)
|
||||
|
||||
proc findProjectNimFile*(pkg: string): string =
|
||||
proc findProjectNimFile*(conf: ConfigRef; pkg: string): string =
|
||||
const extensions = [".nims", ".cfg", ".nimcfg", ".nimble"]
|
||||
var candidates: seq[string] = @[]
|
||||
for k, f in os.walkDir(pkg, relative=true):
|
||||
@@ -448,11 +512,12 @@ proc canonDynlibName(s: string): string =
|
||||
else:
|
||||
result = s.substr(start)
|
||||
|
||||
proc inclDynlibOverride*(lib: string) =
|
||||
gDllOverrides[lib.canonDynlibName] = "true"
|
||||
proc inclDynlibOverride*(conf: ConfigRef; lib: string) =
|
||||
conf.dllOverrides[lib.canonDynlibName] = "true"
|
||||
|
||||
proc isDynlibOverride*(lib: string): bool =
|
||||
result = gDynlibOverrideAll or gDllOverrides.hasKey(lib.canonDynlibName)
|
||||
proc isDynlibOverride*(conf: ConfigRef; lib: string): bool =
|
||||
result = optDynlibOverrideAll in conf.globalOptions or
|
||||
conf.dllOverrides.hasKey(lib.canonDynlibName)
|
||||
|
||||
proc binaryStrSearch*(x: openArray[string], y: string): int =
|
||||
var a = 0
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
|
||||
result = newNodeI(nkStmtList, n.info)
|
||||
let iter = n[1]
|
||||
if iter.kind != nkSym or iter.sym.kind != skIterator:
|
||||
localError(iter.info, "first argument needs to be an iterator")
|
||||
localError(c.config, iter.info, "first argument needs to be an iterator")
|
||||
return
|
||||
if n[2].typ.isNil:
|
||||
localError(n[2].info, "second argument needs to be a type")
|
||||
localError(c.config, n[2].info, "second argument needs to be a type")
|
||||
return
|
||||
if n[3].kind != nkIdent:
|
||||
localError(n[3].info, "third argument needs to be an identifier")
|
||||
localError(c.config, n[3].info, "third argument needs to be an identifier")
|
||||
return
|
||||
|
||||
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
|
||||
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
|
||||
localError(n[2].info,
|
||||
localError(c.config, n[2].info,
|
||||
"type must be a non-generic ref|ptr to object with state field")
|
||||
return
|
||||
let body = liftIterToProc(iter.sym, iter.sym.getBody, t)
|
||||
let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t)
|
||||
|
||||
let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
|
||||
prc.typ = copyType(iter.sym.typ, prc, false)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# This module implements the renderer of the standard Nim representation.
|
||||
|
||||
import
|
||||
lexer, options, idents, strutils, ast, msgs
|
||||
lexer, options, idents, strutils, ast, msgs, configuration
|
||||
|
||||
type
|
||||
TRenderFlag* = enum
|
||||
@@ -40,6 +40,7 @@ type
|
||||
when defined(nimpretty):
|
||||
pendingNewlineCount: int
|
||||
fid*: FileIndex
|
||||
config*: ConfigRef
|
||||
|
||||
# We render the source code in a two phases: The first
|
||||
# determines how long the subtree will likely be, the second
|
||||
@@ -90,7 +91,7 @@ const
|
||||
MaxLineLen = 80
|
||||
LineCommentColumn = 30
|
||||
|
||||
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
||||
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
|
||||
g.comStack = @[]
|
||||
g.tokens = @[]
|
||||
g.indent = 0
|
||||
@@ -102,6 +103,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
|
||||
g.pendingNL = -1
|
||||
g.pendingWhitespace = -1
|
||||
g.inGenericParams = false
|
||||
g.config = config
|
||||
|
||||
proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
|
||||
var length = len(g.tokens)
|
||||
@@ -377,7 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string =
|
||||
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
|
||||
else: result = "[type node]"
|
||||
else:
|
||||
internalError("rnimsyn.atom " & $n.kind)
|
||||
internalError(g.config, "rnimsyn.atom " & $n.kind)
|
||||
result = ""
|
||||
|
||||
proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
|
||||
@@ -1422,11 +1424,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
|
||||
gTypeClassTy(g, n)
|
||||
else:
|
||||
#nkNone, nkExplicitTypeListCall:
|
||||
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||
internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
|
||||
|
||||
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
|
||||
var g: TSrcGen
|
||||
initSrcGen(g, renderFlags)
|
||||
initSrcGen(g, renderFlags, newPartialConfigRef())
|
||||
# do not indent the initial statement list so that
|
||||
# writeFile("file.nim", repr n)
|
||||
# produces working Nim code:
|
||||
@@ -1444,7 +1446,7 @@ proc renderModule*(n: PNode, infile, outfile: string,
|
||||
var
|
||||
f: File
|
||||
g: TSrcGen
|
||||
initSrcGen(g, renderFlags)
|
||||
initSrcGen(g, renderFlags, newPartialConfigRef())
|
||||
g.fid = fid
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
gsub(g, n.sons[i])
|
||||
@@ -1454,16 +1456,14 @@ proc renderModule*(n: PNode, infile, outfile: string,
|
||||
nkCommentStmt: putNL(g)
|
||||
else: discard
|
||||
gcoms(g)
|
||||
if optStdout in gGlobalOptions:
|
||||
write(stdout, g.buf)
|
||||
elif open(f, outfile, fmWrite):
|
||||
if open(f, outfile, fmWrite):
|
||||
write(f, g.buf)
|
||||
close(f)
|
||||
else:
|
||||
rawMessage(errCannotOpenFile, outfile)
|
||||
rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
|
||||
|
||||
proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
|
||||
initSrcGen(r, renderFlags)
|
||||
initSrcGen(r, renderFlags, newPartialConfigRef())
|
||||
gsub(r, n)
|
||||
|
||||
proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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':
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
134
compiler/sem.nim
134
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -14,7 +14,7 @@ import
|
||||
wordrecg,
|
||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef,
|
||||
modulegraphs
|
||||
modulegraphs, configuration
|
||||
|
||||
type
|
||||
TOptionEntry* = object # entries to put on a stack for pragma parsing
|
||||
@@ -140,6 +140,8 @@ type
|
||||
# would otherwise fail.
|
||||
runnableExamples*: PNode
|
||||
|
||||
template config*(c: PContext): ConfigRef = c.graph.config
|
||||
|
||||
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
|
||||
result.genericSym = s
|
||||
result.inst = inst
|
||||
@@ -165,7 +167,7 @@ proc pushOwner*(c: PContext; owner: PSym) =
|
||||
proc popOwner*(c: PContext) =
|
||||
var length = len(c.graph.owners)
|
||||
if length > 0: setLen(c.graph.owners, length - 1)
|
||||
else: internalError("popOwner")
|
||||
else: internalError(c.config, "popOwner")
|
||||
|
||||
proc lastOptionEntry*(c: PContext): POptionEntry =
|
||||
result = c.optionStack[^1]
|
||||
@@ -201,19 +203,19 @@ proc considerGenSyms*(c: PContext; n: PNode) =
|
||||
for i in 0..<n.safeLen:
|
||||
considerGenSyms(c, n.sons[i])
|
||||
|
||||
proc newOptionEntry*(): POptionEntry =
|
||||
proc newOptionEntry*(conf: ConfigRef): POptionEntry =
|
||||
new(result)
|
||||
result.options = gOptions
|
||||
result.options = conf.options
|
||||
result.defaultCC = ccDefault
|
||||
result.dynlib = nil
|
||||
result.notes = gNotes
|
||||
result.notes = conf.notes
|
||||
|
||||
proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext =
|
||||
new(result)
|
||||
result.ambiguousSymbols = initIntSet()
|
||||
result.optionStack = @[]
|
||||
result.libs = @[]
|
||||
result.optionStack.add(newOptionEntry())
|
||||
result.optionStack.add(newOptionEntry(graph.config))
|
||||
result.module = module
|
||||
result.friendModules = @[module]
|
||||
result.converters = @[]
|
||||
@@ -256,7 +258,7 @@ proc newTypeS*(kind: TTypeKind, c: PContext): PType =
|
||||
|
||||
proc makePtrType*(c: PContext, baseType: PType): PType =
|
||||
result = newTypeS(tyPtr, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
addSonSkipIntLit(result, baseType)
|
||||
|
||||
proc makeTypeWithModifier*(c: PContext,
|
||||
modifier: TTypeKind,
|
||||
@@ -267,25 +269,26 @@ proc makeTypeWithModifier*(c: PContext,
|
||||
result = baseType
|
||||
else:
|
||||
result = newTypeS(modifier, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
addSonSkipIntLit(result, baseType)
|
||||
|
||||
proc makeVarType*(c: PContext, baseType: PType; kind = tyVar): PType =
|
||||
if baseType.kind == kind:
|
||||
result = baseType
|
||||
else:
|
||||
result = newTypeS(kind, c)
|
||||
addSonSkipIntLit(result, baseType.assertNotNil)
|
||||
addSonSkipIntLit(result, baseType)
|
||||
|
||||
proc makeTypeDesc*(c: PContext, typ: PType): PType =
|
||||
if typ.kind == tyTypeDesc:
|
||||
result = typ
|
||||
else:
|
||||
result = newTypeS(tyTypeDesc, c)
|
||||
result.addSonSkipIntLit(typ.assertNotNil)
|
||||
result.addSonSkipIntLit(typ)
|
||||
|
||||
proc makeTypeSymNode*(c: PContext, typ: PType, info: TLineInfo): PNode =
|
||||
let typedesc = makeTypeDesc(c, typ)
|
||||
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info).linkTo(typedesc)
|
||||
let sym = newSym(skType, c.cache.idAnon, getCurrOwner(c), info,
|
||||
c.config.options).linkTo(typedesc)
|
||||
return newSymNode(sym, info)
|
||||
|
||||
proc makeTypeFromExpr*(c: PContext, n: PNode): PType =
|
||||
@@ -340,21 +343,20 @@ proc makeNotType*(c: PContext, t1: PType): PType =
|
||||
result.flags.incl(t1.flags * {tfHasStatic})
|
||||
result.flags.incl tfHasMeta
|
||||
|
||||
proc nMinusOne*(n: PNode): PNode =
|
||||
proc nMinusOne(c: PContext; n: PNode): PNode =
|
||||
result = newNode(nkCall, n.info, @[
|
||||
newSymNode(getSysMagic("pred", mPred)),
|
||||
n])
|
||||
newSymNode(getSysMagic(c.graph, n.info, "pred", mPred)), n])
|
||||
|
||||
# Remember to fix the procs below this one when you make changes!
|
||||
proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
|
||||
let intType = getSysType(tyInt)
|
||||
let intType = getSysType(c.graph, n.info, tyInt)
|
||||
result = newTypeS(tyRange, c)
|
||||
result.sons = @[intType]
|
||||
if n.typ != nil and n.typ.n == nil:
|
||||
result.flags.incl tfUnresolved
|
||||
result.n = newNode(nkRange, n.info, @[
|
||||
newIntTypeNode(nkIntLit, 0, intType),
|
||||
makeStaticExpr(c, n.nMinusOne)])
|
||||
makeStaticExpr(c, nMinusOne(c, n))])
|
||||
|
||||
template rangeHasUnresolvedStatic*(t: PType): bool =
|
||||
tfUnresolved in t.flags
|
||||
@@ -373,7 +375,8 @@ proc fillTypeS*(dest: PType, kind: TTypeKind, c: PContext) =
|
||||
dest.size = - 1
|
||||
|
||||
proc makeRangeType*(c: PContext; first, last: BiggestInt;
|
||||
info: TLineInfo; intType = getSysType(tyInt)): PType =
|
||||
info: TLineInfo; intType: PType = nil): PType =
|
||||
let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
|
||||
var n = newNodeI(nkRange, info)
|
||||
addSon(n, newIntTypeNode(nkIntLit, first, intType))
|
||||
addSon(n, newIntTypeNode(nkIntLit, last, intType))
|
||||
@@ -386,17 +389,17 @@ proc markIndirect*(c: PContext, s: PSym) {.inline.} =
|
||||
incl(s.flags, sfAddrTaken)
|
||||
# XXX add to 'c' for global analysis
|
||||
|
||||
proc illFormedAst*(n: PNode) =
|
||||
globalError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
proc illFormedAst*(n: PNode; conf: ConfigRef) =
|
||||
globalError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc illFormedAstLocal*(n: PNode) =
|
||||
localError(n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
proc illFormedAstLocal*(n: PNode; conf: ConfigRef) =
|
||||
localError(conf, n.info, errIllFormedAstX, renderTree(n, {renderNoComments}))
|
||||
|
||||
proc checkSonsLen*(n: PNode, length: int) =
|
||||
if sonsLen(n) != length: illFormedAst(n)
|
||||
proc checkSonsLen*(n: PNode, length: int; conf: ConfigRef) =
|
||||
if sonsLen(n) != length: illFormedAst(n, conf)
|
||||
|
||||
proc checkMinSonsLen*(n: PNode, length: int) =
|
||||
if sonsLen(n) < length: illFormedAst(n)
|
||||
proc checkMinSonsLen*(n: PNode, length: int; conf: ConfigRef) =
|
||||
if sonsLen(n) < length: illFormedAst(n, conf)
|
||||
|
||||
proc isTopLevel*(c: PContext): bool {.inline.} =
|
||||
result = c.currentScope.depthLevel <= 2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -13,84 +13,16 @@
|
||||
import
|
||||
strutils, options, ast, astalgo, trees, treetab, nimsets, times,
|
||||
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
|
||||
commands, magicsys
|
||||
commands, magicsys, modulegraphs, strtabs
|
||||
|
||||
proc getConstExpr*(m: PSym, n: PNode): PNode
|
||||
# evaluates the constant expression or returns nil if it is no constant
|
||||
# expression
|
||||
proc evalOp*(m: TMagic, n, a, b, c: PNode): PNode
|
||||
proc leValueConv*(a, b: PNode): bool
|
||||
proc newIntNodeT*(intVal: BiggestInt, n: PNode): PNode
|
||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode
|
||||
proc newStrNodeT*(strVal: string, n: PNode): PNode
|
||||
|
||||
proc checkInRange(n: PNode, res: BiggestInt): bool =
|
||||
if res in firstOrd(n.typ)..lastOrd(n.typ):
|
||||
result = true
|
||||
|
||||
proc foldAdd(a, b: BiggestInt, n: PNode): PNode =
|
||||
let res = a +% b
|
||||
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
|
||||
checkInRange(n, res):
|
||||
result = newIntNodeT(res, n)
|
||||
|
||||
proc foldSub*(a, b: BiggestInt, n: PNode): PNode =
|
||||
let res = a -% b
|
||||
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
|
||||
checkInRange(n, res):
|
||||
result = newIntNodeT(res, n)
|
||||
|
||||
proc foldAbs*(a: BiggestInt, n: PNode): PNode =
|
||||
if a != firstOrd(n.typ):
|
||||
result = newIntNodeT(a, n)
|
||||
|
||||
proc foldMod*(a, b: BiggestInt, n: PNode): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a mod b, n)
|
||||
|
||||
proc foldModU*(a, b: BiggestInt, n: PNode): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a %% b, n)
|
||||
|
||||
proc foldDiv*(a, b: BiggestInt, n: PNode): PNode =
|
||||
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
|
||||
result = newIntNodeT(a div b, n)
|
||||
|
||||
proc foldDivU*(a, b: BiggestInt, n: PNode): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a /% b, n)
|
||||
|
||||
proc foldMul*(a, b: BiggestInt, n: PNode): PNode =
|
||||
let res = a *% b
|
||||
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
|
||||
let resAsFloat = toBiggestFloat(res)
|
||||
|
||||
# Fast path for normal case: small multiplicands, and no info
|
||||
# is lost in either method.
|
||||
if resAsFloat == floatProd and checkInRange(n, res):
|
||||
return newIntNodeT(res, n)
|
||||
|
||||
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||
# The difference either is or isn't significant compared to the
|
||||
# true value (of which floatProd is a good approximation).
|
||||
|
||||
# abs(diff)/abs(prod) <= 1/32 iff
|
||||
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
|
||||
checkInRange(n, res):
|
||||
return newIntNodeT(res, n)
|
||||
|
||||
# implementation
|
||||
|
||||
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||
proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyInt:
|
||||
result = newIntNode(nkIntLit, intVal)
|
||||
# See bug #6989. 'pred' et al only produce an int literal type if the
|
||||
# original type was 'int', not a distinct int etc.
|
||||
if n.typ.kind == tyInt:
|
||||
result.typ = getIntLitType(result)
|
||||
result.typ = getIntLitType(g, result)
|
||||
else:
|
||||
result.typ = n.typ
|
||||
# hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
|
||||
@@ -103,20 +35,82 @@ proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
|
||||
proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newFloatNode(nkFloatLit, floatVal)
|
||||
if skipTypes(n.typ, abstractVarRange).kind == tyFloat:
|
||||
result.typ = getFloatLitType(result)
|
||||
result.typ = getFloatLitType(g, result)
|
||||
else:
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newStrNodeT(strVal: string, n: PNode): PNode =
|
||||
proc newStrNodeT*(strVal: string, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newStrNode(nkStrLit, strVal)
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc ordinalValToString*(a: PNode): string =
|
||||
proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
|
||||
# evaluates the constant expression or returns nil if it is no constant
|
||||
# expression
|
||||
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
|
||||
|
||||
proc checkInRange(n: PNode, res: BiggestInt): bool =
|
||||
if res in firstOrd(n.typ)..lastOrd(n.typ):
|
||||
result = true
|
||||
|
||||
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a +% b
|
||||
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
|
||||
checkInRange(n, res):
|
||||
result = newIntNodeT(res, n, g)
|
||||
|
||||
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a -% b
|
||||
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
|
||||
checkInRange(n, res):
|
||||
result = newIntNodeT(res, n, g)
|
||||
|
||||
proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if a != firstOrd(n.typ):
|
||||
result = newIntNodeT(a, n, g)
|
||||
|
||||
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a mod b, n, g)
|
||||
|
||||
proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a %% b, n, g)
|
||||
|
||||
proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64 and (a != firstOrd(n.typ) or b != -1'i64):
|
||||
result = newIntNodeT(a div b, n, g)
|
||||
|
||||
proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
if b != 0'i64:
|
||||
result = newIntNodeT(a /% b, n, g)
|
||||
|
||||
proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
|
||||
let res = a *% b
|
||||
let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
|
||||
let resAsFloat = toBiggestFloat(res)
|
||||
|
||||
# Fast path for normal case: small multiplicands, and no info
|
||||
# is lost in either method.
|
||||
if resAsFloat == floatProd and checkInRange(n, res):
|
||||
return newIntNodeT(res, n, g)
|
||||
|
||||
# Somebody somewhere lost info. Close enough, or way off? Note
|
||||
# that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
|
||||
# The difference either is or isn't significant compared to the
|
||||
# true value (of which floatProd is a good approximation).
|
||||
|
||||
# abs(diff)/abs(prod) <= 1/32 iff
|
||||
# 32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
|
||||
if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
|
||||
checkInRange(n, res):
|
||||
return newIntNodeT(res, n, g)
|
||||
|
||||
proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
|
||||
# because $ has the param ordinal[T], `a` is not necessarily an enum, but an
|
||||
# ordinal
|
||||
var x = getInt(a)
|
||||
@@ -128,14 +122,14 @@ proc ordinalValToString*(a: PNode): string =
|
||||
of tyEnum:
|
||||
var n = t.n
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
if n.sons[i].kind != nkSym: internalError(a.info, "ordinalValToString")
|
||||
if n.sons[i].kind != nkSym: internalError(g.config, a.info, "ordinalValToString")
|
||||
var field = n.sons[i].sym
|
||||
if field.position == x:
|
||||
if field.ast == nil:
|
||||
return field.name.s
|
||||
else:
|
||||
return field.ast.strVal
|
||||
internalError(a.info, "no symbol for ordinal value: " & $x)
|
||||
internalError(g.config, a.info, "no symbol for ordinal value: " & $x)
|
||||
else:
|
||||
result = $x
|
||||
|
||||
@@ -154,12 +148,12 @@ proc pickIntRange(a, b: PType): PType =
|
||||
proc isIntRangeOrLit(t: PType): bool =
|
||||
result = isIntRange(t) or isIntLit(t)
|
||||
|
||||
proc makeRange(typ: PType, first, last: BiggestInt): PType =
|
||||
proc makeRange(typ: PType, first, last: BiggestInt; g: ModuleGraph): PType =
|
||||
let minA = min(first, last)
|
||||
let maxA = max(first, last)
|
||||
let lowerNode = newIntNode(nkIntLit, minA)
|
||||
if typ.kind == tyInt and minA == maxA:
|
||||
result = getIntLitType(lowerNode)
|
||||
result = getIntLitType(g, lowerNode)
|
||||
elif typ.kind in {tyUint, tyUInt64}:
|
||||
# these are not ordinal types, so you get no subrange type for these:
|
||||
result = typ
|
||||
@@ -171,7 +165,7 @@ proc makeRange(typ: PType, first, last: BiggestInt): PType =
|
||||
result.n = n
|
||||
addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
|
||||
proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
|
||||
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
|
||||
@@ -181,9 +175,9 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat): PType =
|
||||
|
||||
proc evalIs(n, a: PNode): PNode =
|
||||
# XXX: This should use the standard isOpImpl
|
||||
internalAssert a.kind == nkSym and a.sym.kind == skType
|
||||
internalAssert n.sonsLen == 3 and
|
||||
n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
#internalAssert a.kind == nkSym and a.sym.kind == skType
|
||||
#internalAssert n.sonsLen == 3 and
|
||||
# n[2].kind in {nkStrLit..nkTripleStrLit, nkType}
|
||||
|
||||
let t1 = a.sym.typ
|
||||
|
||||
@@ -207,113 +201,113 @@ proc evalIs(n, a: PNode): PNode =
|
||||
result = newIntNode(nkIntLit, ord(match))
|
||||
result.typ = n.typ
|
||||
|
||||
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
|
||||
# b and c may be nil
|
||||
result = nil
|
||||
case m
|
||||
of mOrd: result = newIntNodeT(getOrdValue(a), n)
|
||||
of mChr: result = newIntNodeT(getInt(a), n)
|
||||
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n)
|
||||
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n)
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(a), n)
|
||||
of mBitnotI: result = newIntNodeT(not getInt(a), n)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n)
|
||||
of mOrd: result = newIntNodeT(getOrdValue(a), n, g)
|
||||
of mChr: result = newIntNodeT(getInt(a), n, g)
|
||||
of mUnaryMinusI, mUnaryMinusI64: result = newIntNodeT(- getInt(a), n, g)
|
||||
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
|
||||
of mNot: result = newIntNodeT(1 - getInt(a), n, g)
|
||||
of mCard: result = newIntNodeT(nimsets.cardSet(a), n, g)
|
||||
of mBitnotI: result = newIntNodeT(not getInt(a), n, g)
|
||||
of mLengthArray: result = newIntNodeT(lengthOrd(a.typ), n, g)
|
||||
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
|
||||
if a.kind == nkNilLit:
|
||||
result = newIntNodeT(0, n)
|
||||
result = newIntNodeT(0, n, g)
|
||||
elif a.kind in {nkStrLit..nkTripleStrLit}:
|
||||
result = newIntNodeT(len a.strVal, n)
|
||||
result = newIntNodeT(len a.strVal, n, g)
|
||||
else:
|
||||
result = newIntNodeT(sonsLen(a), n) # BUGFIX
|
||||
result = newIntNodeT(sonsLen(a), n, g)
|
||||
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
|
||||
of mToFloat, mToBiggestFloat:
|
||||
result = newFloatNodeT(toFloat(int(getInt(a))), n)
|
||||
result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
|
||||
# XXX: Hides overflow/underflow
|
||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n)
|
||||
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n)
|
||||
of mAbsI: result = foldAbs(getInt(a), n)
|
||||
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
|
||||
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
|
||||
of mAbsI: result = foldAbs(getInt(a), n, g)
|
||||
of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
|
||||
# byte(-128) = 1...1..1000_0000'64 --> 0...0..1000_0000'64
|
||||
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n)
|
||||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n)
|
||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n)
|
||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n)
|
||||
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n)
|
||||
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n)
|
||||
of mPred: result = foldSub(getOrdValue(a), getInt(b), n)
|
||||
of mAddI: result = foldAdd(getInt(a), getInt(b), n)
|
||||
of mSubI: result = foldSub(getInt(a), getInt(b), n)
|
||||
of mMulI: result = foldMul(getInt(a), getInt(b), n)
|
||||
result = newIntNodeT(getInt(a) and (`shl`(1, getSize(a.typ) * 8) - 1), n, g)
|
||||
of mToU8: result = newIntNodeT(getInt(a) and 0x000000FF, n, g)
|
||||
of mToU16: result = newIntNodeT(getInt(a) and 0x0000FFFF, n, g)
|
||||
of mToU32: result = newIntNodeT(getInt(a) and 0x00000000FFFFFFFF'i64, n, g)
|
||||
of mUnaryLt: result = foldSub(getOrdValue(a), 1, n, g)
|
||||
of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
|
||||
of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
|
||||
of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
|
||||
of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
|
||||
of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
|
||||
of mMinI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n)
|
||||
else: result = newIntNodeT(getInt(a), n)
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
|
||||
else: result = newIntNodeT(getInt(a), n, g)
|
||||
of mMaxI:
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n)
|
||||
else: result = newIntNodeT(getInt(b), n)
|
||||
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
|
||||
else: result = newIntNodeT(getInt(b), n, g)
|
||||
of mShlI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
|
||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
|
||||
else: internalError(n.info, "constant folding for shl")
|
||||
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
|
||||
else: internalError(g.config, n.info, "constant folding for shl")
|
||||
of mShrI:
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
|
||||
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n, g)
|
||||
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n, g)
|
||||
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n, g)
|
||||
of tyInt64, tyInt, tyUInt..tyUInt64:
|
||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
|
||||
else: internalError(n.info, "constant folding for shr")
|
||||
of mDivI: result = foldDiv(getInt(a), getInt(b), n)
|
||||
of mModI: result = foldMod(getInt(a), getInt(b), n)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)
|
||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n)
|
||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n)
|
||||
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n, g)
|
||||
else: internalError(g.config, n.info, "constant folding for shr")
|
||||
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
|
||||
of mModI: result = foldMod(getInt(a), getInt(b), n, g)
|
||||
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
|
||||
of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
|
||||
of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
|
||||
of mDivF64:
|
||||
if getFloat(b) == 0.0:
|
||||
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n)
|
||||
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n)
|
||||
else: result = newFloatNodeT(Inf, n)
|
||||
if getFloat(a) == 0.0: result = newFloatNodeT(NaN, n, g)
|
||||
elif getFloat(b).classify == fcNegZero: result = newFloatNodeT(-Inf, n, g)
|
||||
else: result = newFloatNodeT(Inf, n, g)
|
||||
else:
|
||||
result = newFloatNodeT(getFloat(a) / getFloat(b), n)
|
||||
result = newFloatNodeT(getFloat(a) / getFloat(b), n, g)
|
||||
of mMaxF64:
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n)
|
||||
else: result = newFloatNodeT(getFloat(b), n)
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(a), n, g)
|
||||
else: result = newFloatNodeT(getFloat(b), n, g)
|
||||
of mMinF64:
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n)
|
||||
else: result = newFloatNodeT(getFloat(a), n)
|
||||
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n)
|
||||
if getFloat(a) > getFloat(b): result = newFloatNodeT(getFloat(b), n, g)
|
||||
else: result = newFloatNodeT(getFloat(a), n, g)
|
||||
of mIsNil: result = newIntNodeT(ord(a.kind == nkNilLit), n, g)
|
||||
of mLtI, mLtB, mLtEnum, mLtCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n)
|
||||
result = newIntNodeT(ord(getOrdValue(a) < getOrdValue(b)), n, g)
|
||||
of mLeI, mLeB, mLeEnum, mLeCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n)
|
||||
result = newIntNodeT(ord(getOrdValue(a) <= getOrdValue(b)), n, g)
|
||||
of mEqI, mEqB, mEqEnum, mEqCh:
|
||||
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n)
|
||||
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n)
|
||||
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n)
|
||||
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n)
|
||||
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n)
|
||||
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n)
|
||||
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n)
|
||||
result = newIntNodeT(ord(getOrdValue(a) == getOrdValue(b)), n, g)
|
||||
of mLtF64: result = newIntNodeT(ord(getFloat(a) < getFloat(b)), n, g)
|
||||
of mLeF64: result = newIntNodeT(ord(getFloat(a) <= getFloat(b)), n, g)
|
||||
of mEqF64: result = newIntNodeT(ord(getFloat(a) == getFloat(b)), n, g)
|
||||
of mLtStr: result = newIntNodeT(ord(getStr(a) < getStr(b)), n, g)
|
||||
of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
|
||||
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
|
||||
of mLtU, mLtU64:
|
||||
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n)
|
||||
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||
of mLeU, mLeU64:
|
||||
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n)
|
||||
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n)
|
||||
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n)
|
||||
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n)
|
||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n)
|
||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n)
|
||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n)
|
||||
of mModU: result = foldModU(getInt(a), getInt(b), n)
|
||||
of mDivU: result = foldDivU(getInt(a), getInt(b), n)
|
||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n)
|
||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n)
|
||||
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
|
||||
of mBitandI, mAnd: result = newIntNodeT(a.getInt and b.getInt, n, g)
|
||||
of mBitorI, mOr: result = newIntNodeT(getInt(a) or getInt(b), n, g)
|
||||
of mBitxorI, mXor: result = newIntNodeT(a.getInt xor b.getInt, n, g)
|
||||
of mAddU: result = newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)
|
||||
of mSubU: result = newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)
|
||||
of mMulU: result = newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)
|
||||
of mModU: result = foldModU(getInt(a), getInt(b), n, g)
|
||||
of mDivU: result = foldDivU(getInt(a), getInt(b), n, g)
|
||||
of mLeSet: result = newIntNodeT(ord(containsSets(a, b)), n, g)
|
||||
of mEqSet: result = newIntNodeT(ord(equalSets(a, b)), n, g)
|
||||
of mLtSet:
|
||||
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n)
|
||||
result = newIntNodeT(ord(containsSets(a, b) and not equalSets(a, b)), n, g)
|
||||
of mMulSet:
|
||||
result = nimsets.intersectSets(a, b)
|
||||
result.info = n.info
|
||||
@@ -326,125 +320,125 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
of mSymDiffSet:
|
||||
result = nimsets.symdiffSets(a, b)
|
||||
result.info = n.info
|
||||
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n)
|
||||
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n)
|
||||
of mConStrStr: result = newStrNodeT(getStrOrChar(a) & getStrOrChar(b), n, g)
|
||||
of mInSet: result = newIntNodeT(ord(inSet(a, b)), n, g)
|
||||
of mRepr:
|
||||
# BUGFIX: we cannot eval mRepr here for reasons that I forgot.
|
||||
discard
|
||||
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n)
|
||||
of mIntToStr, mInt64ToStr: result = newStrNodeT($(getOrdValue(a)), n, g)
|
||||
of mBoolToStr:
|
||||
if getOrdValue(a) == 0: result = newStrNodeT("false", n)
|
||||
else: result = newStrNodeT("true", n)
|
||||
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n)
|
||||
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
|
||||
else: result = newStrNodeT("true", n, g)
|
||||
of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
|
||||
of mCopyStrLast:
|
||||
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
|
||||
int(getOrdValue(c))), n)
|
||||
of mFloatToStr: result = newStrNodeT($getFloat(a), n)
|
||||
int(getOrdValue(c))), n, g)
|
||||
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
|
||||
of mCStrToStr, mCharToStr:
|
||||
if a.kind == nkBracket:
|
||||
var s = ""
|
||||
for b in a.sons:
|
||||
s.add b.getStrOrChar
|
||||
result = newStrNodeT(s, n)
|
||||
result = newStrNodeT(s, n, g)
|
||||
else:
|
||||
result = newStrNodeT(getStrOrChar(a), n)
|
||||
result = newStrNodeT(getStrOrChar(a), n, g)
|
||||
of mStrToStr: result = a
|
||||
of mEnumToStr: result = newStrNodeT(ordinalValToString(a), n)
|
||||
of mEnumToStr: result = newStrNodeT(ordinalValToString(a, g), n, g)
|
||||
of mArrToSeq:
|
||||
result = copyTree(a)
|
||||
result.typ = n.typ
|
||||
of mCompileOption:
|
||||
result = newIntNodeT(ord(commands.testCompileOption(a.getStr, n.info)), n)
|
||||
result = newIntNodeT(ord(commands.testCompileOption(g.config, a.getStr, n.info)), n, g)
|
||||
of mCompileOptionArg:
|
||||
result = newIntNodeT(ord(
|
||||
testCompileOptionArg(getStr(a), getStr(b), n.info)), n)
|
||||
testCompileOptionArg(g.config, getStr(a), getStr(b), n.info)), n, g)
|
||||
of mEqProc:
|
||||
result = newIntNodeT(ord(
|
||||
exprStructuralEquivalent(a, b, strictSymEquality=true)), n)
|
||||
exprStructuralEquivalent(a, b, strictSymEquality=true)), n, g)
|
||||
else: discard
|
||||
|
||||
proc getConstIfExpr(c: PSym, n: PNode): PNode =
|
||||
proc getConstIfExpr(c: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result = nil
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var it = n.sons[i]
|
||||
if it.len == 2:
|
||||
var e = getConstExpr(c, it.sons[0])
|
||||
var e = getConstExpr(c, it.sons[0], g)
|
||||
if e == nil: return nil
|
||||
if getOrdValue(e) != 0:
|
||||
if result == nil:
|
||||
result = getConstExpr(c, it.sons[1])
|
||||
result = getConstExpr(c, it.sons[1], g)
|
||||
if result == nil: return
|
||||
elif it.len == 1:
|
||||
if result == nil: result = getConstExpr(c, it.sons[0])
|
||||
else: internalError(it.info, "getConstIfExpr()")
|
||||
if result == nil: result = getConstExpr(c, it.sons[0], g)
|
||||
else: internalError(g.config, it.info, "getConstIfExpr()")
|
||||
|
||||
proc leValueConv(a, b: PNode): bool =
|
||||
proc leValueConv*(a, b: PNode): bool =
|
||||
result = false
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt64Lit:
|
||||
case b.kind
|
||||
of nkCharLit..nkUInt64Lit: result = a.intVal <= b.intVal
|
||||
of nkFloatLit..nkFloat128Lit: result = a.intVal <= round(b.floatVal).int
|
||||
else: internalError(a.info, "leValueConv")
|
||||
else: result = false #internalError(a.info, "leValueConv")
|
||||
of nkFloatLit..nkFloat128Lit:
|
||||
case b.kind
|
||||
of nkFloatLit..nkFloat128Lit: result = a.floatVal <= b.floatVal
|
||||
of nkCharLit..nkUInt64Lit: result = a.floatVal <= toFloat(int(b.intVal))
|
||||
else: internalError(a.info, "leValueConv")
|
||||
else: internalError(a.info, "leValueConv")
|
||||
else: result = false # internalError(a.info, "leValueConv")
|
||||
else: result = false # internalError(a.info, "leValueConv")
|
||||
|
||||
proc magicCall(m: PSym, n: PNode): PNode =
|
||||
proc magicCall(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
if sonsLen(n) <= 1: return
|
||||
|
||||
var s = n.sons[0].sym
|
||||
var a = getConstExpr(m, n.sons[1])
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
var b, c: PNode
|
||||
if a == nil: return
|
||||
if sonsLen(n) > 2:
|
||||
b = getConstExpr(m, n.sons[2])
|
||||
b = getConstExpr(m, n.sons[2], g)
|
||||
if b == nil: return
|
||||
if sonsLen(n) > 3:
|
||||
c = getConstExpr(m, n.sons[3])
|
||||
c = getConstExpr(m, n.sons[3], g)
|
||||
if c == nil: return
|
||||
result = evalOp(s.magic, n, a, b, c)
|
||||
result = evalOp(s.magic, n, a, b, c, g)
|
||||
|
||||
proc getAppType(n: PNode): PNode =
|
||||
if gGlobalOptions.contains(optGenDynLib):
|
||||
result = newStrNodeT("lib", n)
|
||||
elif gGlobalOptions.contains(optGenStaticLib):
|
||||
result = newStrNodeT("staticlib", n)
|
||||
elif gGlobalOptions.contains(optGenGuiApp):
|
||||
result = newStrNodeT("gui", n)
|
||||
proc getAppType(n: PNode; g: ModuleGraph): PNode =
|
||||
if g.config.globalOptions.contains(optGenDynLib):
|
||||
result = newStrNodeT("lib", n, g)
|
||||
elif g.config.globalOptions.contains(optGenStaticLib):
|
||||
result = newStrNodeT("staticlib", n, g)
|
||||
elif g.config.globalOptions.contains(optGenGuiApp):
|
||||
result = newStrNodeT("gui", n, g)
|
||||
else:
|
||||
result = newStrNodeT("console", n)
|
||||
result = newStrNodeT("console", n, g)
|
||||
|
||||
proc rangeCheck(n: PNode, value: BiggestInt) =
|
||||
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
||||
var err = false
|
||||
if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
|
||||
err = value <% firstOrd(n.typ) or value >% lastOrd(n.typ, fixedUnsigned=true)
|
||||
else:
|
||||
err = value < firstOrd(n.typ) or value > lastOrd(n.typ)
|
||||
if err:
|
||||
localError(n.info, errGenerated, "cannot convert " & $value &
|
||||
localError(g.config, n.info, "cannot convert " & $value &
|
||||
" to " & typeToString(n.typ))
|
||||
|
||||
proc foldConv*(n, a: PNode; check = false): PNode =
|
||||
proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||
# XXX range checks?
|
||||
case skipTypes(n.typ, abstractRange).kind
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
case skipTypes(a.typ, abstractRange).kind
|
||||
of tyFloat..tyFloat64:
|
||||
result = newIntNodeT(int(getFloat(a)), n)
|
||||
of tyChar: result = newIntNodeT(getOrdValue(a), n)
|
||||
result = newIntNodeT(int(getFloat(a)), n, g)
|
||||
of tyChar: result = newIntNodeT(getOrdValue(a), n, g)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
if check and result.kind in {nkCharLit..nkUInt64Lit}:
|
||||
rangeCheck(n, result.intVal)
|
||||
rangeCheck(n, result.intVal, g)
|
||||
of tyFloat..tyFloat64:
|
||||
case skipTypes(a.typ, abstractRange).kind
|
||||
of tyInt..tyInt64, tyEnum, tyBool, tyChar:
|
||||
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n)
|
||||
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
|
||||
else:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
@@ -454,19 +448,19 @@ proc foldConv*(n, a: PNode; check = false): PNode =
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
|
||||
proc getArrayConstr(m: PSym, n: PNode): PNode =
|
||||
proc getArrayConstr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
if n.kind == nkBracket:
|
||||
result = n
|
||||
else:
|
||||
result = getConstExpr(m, n)
|
||||
result = getConstExpr(m, n, g)
|
||||
if result == nil: result = n
|
||||
|
||||
proc foldArrayAccess(m: PSym, n: PNode): PNode =
|
||||
var x = getConstExpr(m, n.sons[0])
|
||||
proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
var x = getConstExpr(m, n.sons[0], g)
|
||||
if x == nil or x.typ.skipTypes({tyGenericInst, tyAlias, tySink}).kind == tyTypeDesc:
|
||||
return
|
||||
|
||||
var y = getConstExpr(m, n.sons[1])
|
||||
var y = getConstExpr(m, n.sons[1], g)
|
||||
if y == nil: return
|
||||
|
||||
var idx = getOrdValue(y)
|
||||
@@ -476,24 +470,24 @@ proc foldArrayAccess(m: PSym, n: PNode): PNode =
|
||||
result = x.sons[int(idx)]
|
||||
if result.kind == nkExprColonExpr: result = result.sons[1]
|
||||
else:
|
||||
localError(n.info, errIndexOutOfBounds)
|
||||
localError(g.config, n.info, "index out of bounds: " & $n)
|
||||
of nkBracket:
|
||||
idx = idx - x.typ.firstOrd
|
||||
if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
|
||||
else: localError(n.info, errIndexOutOfBounds)
|
||||
else: localError(g.config, n.info, "index out of bounds: " & $n)
|
||||
of nkStrLit..nkTripleStrLit:
|
||||
result = newNodeIT(nkCharLit, x.info, n.typ)
|
||||
if idx >= 0 and idx < len(x.strVal):
|
||||
result.intVal = ord(x.strVal[int(idx)])
|
||||
elif idx == len(x.strVal):
|
||||
elif idx == len(x.strVal) and optLaxStrings in g.config.options:
|
||||
discard
|
||||
else:
|
||||
localError(n.info, errIndexOutOfBounds)
|
||||
localError(g.config, n.info, "index out of bounds: " & $n)
|
||||
else: discard
|
||||
|
||||
proc foldFieldAccess(m: PSym, n: PNode): PNode =
|
||||
proc foldFieldAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
# a real field access; proc calls have already been transformed
|
||||
var x = getConstExpr(m, n.sons[0])
|
||||
var x = getConstExpr(m, n.sons[0], g)
|
||||
if x == nil or x.kind notin {nkObjConstr, nkPar, nkTupleConstr}: return
|
||||
|
||||
var field = n.sons[1].sym
|
||||
@@ -507,13 +501,13 @@ proc foldFieldAccess(m: PSym, n: PNode): PNode =
|
||||
if it.sons[0].sym.name.id == field.name.id:
|
||||
result = x.sons[i].sons[1]
|
||||
return
|
||||
localError(n.info, errFieldXNotFound, field.name.s)
|
||||
localError(g.config, n.info, "field not found: " & field.name.s)
|
||||
|
||||
proc foldConStrStr(m: PSym, n: PNode): PNode =
|
||||
proc foldConStrStr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result = newNodeIT(nkStrLit, n.info, n.typ)
|
||||
result.strVal = ""
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
let a = getConstExpr(m, n.sons[i])
|
||||
let a = getConstExpr(m, n.sons[i], g)
|
||||
if a == nil: return nil
|
||||
result.strVal.add(getStrOrChar(a))
|
||||
|
||||
@@ -525,7 +519,7 @@ proc newSymNodeTypeDesc*(s: PSym; info: TLineInfo): PNode =
|
||||
else:
|
||||
result.typ = s.typ
|
||||
|
||||
proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
|
||||
result = nil
|
||||
|
||||
proc getSrcTimestamp(): DateTime =
|
||||
@@ -545,32 +539,35 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
var s = n.sym
|
||||
case s.kind
|
||||
of skEnumField:
|
||||
result = newIntNodeT(s.position, n)
|
||||
result = newIntNodeT(s.position, n, g)
|
||||
of skConst:
|
||||
case s.magic
|
||||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n)
|
||||
of mIsMainModule: result = newIntNodeT(ord(sfMainModule in m.flags), n, g)
|
||||
of mCompileDate: result = newStrNodeT(format(getSrcTimestamp(),
|
||||
"yyyy-MM-dd"), n)
|
||||
"yyyy-MM-dd"), n, g)
|
||||
of mCompileTime: result = newStrNodeT(format(getSrcTimestamp(),
|
||||
"HH:mm:ss"), n)
|
||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
|
||||
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
|
||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
|
||||
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n)
|
||||
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n)
|
||||
of mAppType: result = getAppType(n)
|
||||
of mNaN: result = newFloatNodeT(NaN, n)
|
||||
of mInf: result = newFloatNodeT(Inf, n)
|
||||
of mNegInf: result = newFloatNodeT(NegInf, n)
|
||||
"HH:mm:ss"), n, g)
|
||||
of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n, g)
|
||||
of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n, g)
|
||||
of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n, g)
|
||||
of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n, g)
|
||||
of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n, g)
|
||||
of mAppType: result = getAppType(n, g)
|
||||
of mNaN: result = newFloatNodeT(NaN, n, g)
|
||||
of mInf: result = newFloatNodeT(Inf, n, g)
|
||||
of mNegInf: result = newFloatNodeT(NegInf, n, g)
|
||||
of mIntDefine:
|
||||
if isDefined(s.name):
|
||||
result = newIntNodeT(lookupSymbol(s.name).parseInt, n)
|
||||
if isDefined(g.config, s.name.s):
|
||||
try:
|
||||
result = newIntNodeT(g.config.symbols[s.name.s].parseInt, n, g)
|
||||
except ValueError:
|
||||
localError(g.config, n.info, "expression is not an integer literal")
|
||||
of mStrDefine:
|
||||
if isDefined(s.name):
|
||||
result = newStrNodeT(lookupSymbol(s.name), n)
|
||||
if isDefined(g.config, s.name.s):
|
||||
result = newStrNodeT(g.config.symbols[s.name.s], n, g)
|
||||
else:
|
||||
result = copyTree(s.ast)
|
||||
of {skProc, skFunc, skMethod}:
|
||||
of skProc, skFunc, skMethod:
|
||||
result = n
|
||||
of skType:
|
||||
# XXX gensym'ed symbols can come here and cannot be resolved. This is
|
||||
@@ -590,7 +587,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of nkCharLit..nkNilLit:
|
||||
result = copyNode(n)
|
||||
of nkIfExpr:
|
||||
result = getConstIfExpr(m, n)
|
||||
result = getConstIfExpr(m, n, g)
|
||||
of nkCallKinds:
|
||||
if n.sons[0].kind != nkSym: return
|
||||
var s = n.sons[0].sym
|
||||
@@ -603,68 +600,67 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of mSizeOf:
|
||||
var a = n.sons[1]
|
||||
if computeSize(a.typ) < 0:
|
||||
localError(a.info, errCannotEvalXBecauseIncompletelyDefined,
|
||||
"sizeof")
|
||||
localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
|
||||
result = nil
|
||||
elif skipTypes(a.typ, typedescInst+{tyRange}).kind in
|
||||
IntegralTypes+NilableTypes+{tySet}:
|
||||
#{tyArray,tyObject,tyTuple}:
|
||||
result = newIntNodeT(getSize(a.typ), n)
|
||||
result = newIntNodeT(getSize(a.typ), n, g)
|
||||
else:
|
||||
result = nil
|
||||
# XXX: size computation for complex types is still wrong
|
||||
of mLow:
|
||||
result = newIntNodeT(firstOrd(n.sons[1].typ), n)
|
||||
result = newIntNodeT(firstOrd(n.sons[1].typ), n, g)
|
||||
of mHigh:
|
||||
if skipTypes(n.sons[1].typ, abstractVar).kind notin
|
||||
{tySequence, tyString, tyCString, tyOpenArray, tyVarargs}:
|
||||
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n)
|
||||
result = newIntNodeT(lastOrd(skipTypes(n[1].typ, abstractVar)), n, g)
|
||||
else:
|
||||
var a = getArrayConstr(m, n.sons[1])
|
||||
var a = getArrayConstr(m, n.sons[1], g)
|
||||
if a.kind == nkBracket:
|
||||
# we can optimize it away:
|
||||
result = newIntNodeT(sonsLen(a)-1, n)
|
||||
result = newIntNodeT(sonsLen(a)-1, n, g)
|
||||
of mLengthOpenArray:
|
||||
var a = getArrayConstr(m, n.sons[1])
|
||||
var a = getArrayConstr(m, n.sons[1], g)
|
||||
if a.kind == nkBracket:
|
||||
# we can optimize it away! This fixes the bug ``len(134)``.
|
||||
result = newIntNodeT(sonsLen(a), n)
|
||||
result = newIntNodeT(sonsLen(a), n, g)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
result = magicCall(m, n, g)
|
||||
of mLengthArray:
|
||||
# It doesn't matter if the argument is const or not for mLengthArray.
|
||||
# This fixes bug #544.
|
||||
result = newIntNodeT(lengthOrd(n.sons[1].typ), n)
|
||||
result = newIntNodeT(lengthOrd(n.sons[1].typ), n, g)
|
||||
of mAstToStr:
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n, g)
|
||||
of mConStrStr:
|
||||
result = foldConStrStr(m, n)
|
||||
result = foldConStrStr(m, n, g)
|
||||
of mIs:
|
||||
let a = getConstExpr(m, n[1])
|
||||
let a = getConstExpr(m, n[1], g)
|
||||
if a != nil and a.kind == nkSym and a.sym.kind == skType:
|
||||
result = evalIs(n, a)
|
||||
else:
|
||||
result = magicCall(m, n)
|
||||
result = magicCall(m, n, g)
|
||||
except OverflowError:
|
||||
localError(n.info, errOverOrUnderflow)
|
||||
localError(g.config, n.info, "over- or underflow")
|
||||
except DivByZeroError:
|
||||
localError(n.info, errConstantDivisionByZero)
|
||||
localError(g.config, n.info, "division by zero")
|
||||
of nkAddr:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
var a = getConstExpr(m, n.sons[0], g)
|
||||
if a != nil:
|
||||
result = n
|
||||
n.sons[0] = a
|
||||
of nkBracket:
|
||||
result = copyTree(n)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = getConstExpr(m, n.sons[i])
|
||||
var a = getConstExpr(m, n.sons[i], g)
|
||||
if a == nil: return nil
|
||||
result.sons[i] = a
|
||||
incl(result.flags, nfAllConst)
|
||||
of nkRange:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
var a = getConstExpr(m, n.sons[0], g)
|
||||
if a == nil: return
|
||||
var b = getConstExpr(m, n.sons[1])
|
||||
var b = getConstExpr(m, n.sons[1], g)
|
||||
if b == nil: return
|
||||
result = copyNode(n)
|
||||
addSon(result, a)
|
||||
@@ -672,7 +668,7 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
of nkCurly:
|
||||
result = copyTree(n)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = getConstExpr(m, n.sons[i])
|
||||
var a = getConstExpr(m, n.sons[i], g)
|
||||
if a == nil: return nil
|
||||
result.sons[i] = a
|
||||
incl(result.flags, nfAllConst)
|
||||
@@ -688,45 +684,45 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
|
||||
result = copyTree(n)
|
||||
if (sonsLen(n) > 0) and (n.sons[0].kind == nkExprColonExpr):
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = getConstExpr(m, n.sons[i].sons[1])
|
||||
var a = getConstExpr(m, n.sons[i].sons[1], g)
|
||||
if a == nil: return nil
|
||||
result.sons[i].sons[1] = a
|
||||
else:
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
var a = getConstExpr(m, n.sons[i])
|
||||
var a = getConstExpr(m, n.sons[i], g)
|
||||
if a == nil: return nil
|
||||
result.sons[i] = a
|
||||
incl(result.flags, nfAllConst)
|
||||
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
var a = getConstExpr(m, n.sons[0], g)
|
||||
if a == nil: return
|
||||
if leValueConv(n.sons[1], a) and leValueConv(a, n.sons[2]):
|
||||
result = a # a <= x and x <= b
|
||||
result.typ = n.typ
|
||||
else:
|
||||
localError(n.info, errGenerated, `%`(
|
||||
msgKindToString(errIllegalConvFromXtoY),
|
||||
[typeToString(n.sons[0].typ), typeToString(n.typ)]))
|
||||
localError(g.config, n.info,
|
||||
"conversion from $1 to $2 is invalid" %
|
||||
[typeToString(n.sons[0].typ), typeToString(n.typ)])
|
||||
of nkStringToCString, nkCStringToString:
|
||||
var a = getConstExpr(m, n.sons[0])
|
||||
var a = getConstExpr(m, n.sons[0], g)
|
||||
if a == nil: return
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
|
||||
var a = getConstExpr(m, n.sons[1])
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
if a == nil: return
|
||||
result = foldConv(n, a, check=n.kind == nkHiddenStdConv)
|
||||
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
|
||||
of nkCast:
|
||||
var a = getConstExpr(m, n.sons[1])
|
||||
var a = getConstExpr(m, n.sons[1], g)
|
||||
if a == nil: return
|
||||
if n.typ != nil and n.typ.kind in NilableTypes:
|
||||
# we allow compile-time 'cast' for pointer types:
|
||||
result = a
|
||||
result.typ = n.typ
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n)
|
||||
of nkBracketExpr: result = foldArrayAccess(m, n, g)
|
||||
of nkDotExpr: result = foldFieldAccess(m, n, g)
|
||||
of nkStmtListExpr:
|
||||
if n.len == 2 and n[0].kind == nkComesFrom:
|
||||
result = getConstExpr(m, n[1])
|
||||
result = getConstExpr(m, n[1], g)
|
||||
else:
|
||||
discard
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -54,10 +54,13 @@ proc pushProcCon*(c: PContext; owner: PSym) =
|
||||
rawPushProcCon(c, owner)
|
||||
rawHandleSelf(c, owner)
|
||||
|
||||
const
|
||||
errCannotInstantiateX = "cannot instantiate: '$1'"
|
||||
|
||||
iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym =
|
||||
internalAssert n.kind == nkGenericParams
|
||||
internalAssert c.config, n.kind == nkGenericParams
|
||||
for i, a in n.pairs:
|
||||
internalAssert a.kind == nkSym
|
||||
internalAssert c.config, a.kind == nkSym
|
||||
var q = a.sym
|
||||
if q.typ.kind notin {tyTypeDesc, tyGenericParam, tyStatic}+tyTypeClasses:
|
||||
continue
|
||||
@@ -71,10 +74,10 @@ iterator instantiateGenericParamList(c: PContext, n: PNode, pt: TIdTable): PSym
|
||||
# later by semAsgn in return type inference scenario
|
||||
t = q.typ
|
||||
else:
|
||||
localError(a.info, errCannotInstantiateX, s.name.s)
|
||||
localError(c.config, a.info, errCannotInstantiateX % s.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericParam:
|
||||
localError(a.info, errCannotInstantiateX, q.name.s)
|
||||
localError(c.config, a.info, errCannotInstantiateX % q.name.s)
|
||||
t = errorType(c)
|
||||
elif t.kind == tyGenericInvocation:
|
||||
#t = instGenericContainer(c, a, t)
|
||||
@@ -145,7 +148,7 @@ proc instantiateBody(c: PContext, n, params: PNode, result, orig: PSym) =
|
||||
freshGenSyms(b, result, orig, symMap)
|
||||
b = semProcBody(c, b)
|
||||
b = hloBody(c, b)
|
||||
n.sons[bodyPos] = transformBody(c.module, b, result)
|
||||
n.sons[bodyPos] = transformBody(c.graph, c.module, b, result)
|
||||
#echo "code instantiated ", result.name.s
|
||||
excl(result.flags, sfForward)
|
||||
dec c.inGenericInst
|
||||
@@ -174,7 +177,7 @@ proc sideEffectsCheck(c: PContext, s: PSym) =
|
||||
|
||||
proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
allowMetaTypes = false): PType =
|
||||
internalAssert header.kind == tyGenericInvocation
|
||||
internalAssert c.config, header.kind == tyGenericInvocation
|
||||
|
||||
var
|
||||
typeMap: LayeredIdTable
|
||||
@@ -199,7 +202,7 @@ proc instGenericContainer(c: PContext, info: TLineInfo, header: PType,
|
||||
var param: PSym
|
||||
|
||||
template paramSym(kind): untyped =
|
||||
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
|
||||
newSym(kind, genParam.sym.name, genericTyp.sym, genParam.sym.info)
|
||||
|
||||
if genParam.kind == tyStatic:
|
||||
param = paramSym skConst
|
||||
@@ -233,14 +236,12 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
# at this point semtypinst have to become part of sem, because it
|
||||
# will need to use openScope, addDecl, etc.
|
||||
#addDecl(c, prc)
|
||||
|
||||
pushInfoContext(info)
|
||||
var typeMap = initLayeredTypeMap(pt)
|
||||
var cl = initTypeVars(c, addr(typeMap), info, nil)
|
||||
var result = instCopyType(cl, prc.typ)
|
||||
let originalParams = result.n
|
||||
result.n = originalParams.shallowCopy
|
||||
|
||||
for i in 1 ..< result.len:
|
||||
# twrong_field_caching requires these 'resetIdTable' calls:
|
||||
if i > 1:
|
||||
@@ -248,7 +249,7 @@ proc instantiateProcType(c: PContext, pt: TIdTable,
|
||||
resetIdTable(cl.localCache)
|
||||
result.sons[i] = replaceTypeVarsT(cl, result.sons[i])
|
||||
propagateToOwner(result, result.sons[i])
|
||||
internalAssert originalParams[i].kind == nkSym
|
||||
internalAssert c.config, originalParams[i].kind == nkSym
|
||||
when true:
|
||||
let oldParam = originalParams[i].sym
|
||||
let param = copySym(oldParam)
|
||||
@@ -285,9 +286,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
## The `pt` parameter is a type-unsafe mapping table used to link generic
|
||||
## parameters to their concrete types within the generic instance.
|
||||
# no need to instantiate generic templates/macros:
|
||||
internalAssert fn.kind notin {skMacro, skTemplate}
|
||||
internalAssert c.config, fn.kind notin {skMacro, skTemplate}
|
||||
# generates an instantiated proc
|
||||
if c.instCounter > 1000: internalError(fn.ast.info, "nesting too deep")
|
||||
if c.instCounter > 1000: internalError(c.config, fn.ast.info, "nesting too deep")
|
||||
inc(c.instCounter)
|
||||
# careful! we copy the whole AST including the possibly nil body!
|
||||
var n = copyTree(fn.ast)
|
||||
@@ -306,7 +307,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
|
||||
|
||||
openScope(c)
|
||||
let gp = n.sons[genericParamsPos]
|
||||
internalAssert gp.kind != nkEmpty
|
||||
internalAssert c.config, gp.kind != nkEmpty
|
||||
n.sons[namePos] = newSymNode(result)
|
||||
pushInfoContext(info)
|
||||
var entry = TInstantiation.new
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
|
||||
import
|
||||
intsets, ast, astalgo, msgs, renderer, magicsys, types, idents, trees,
|
||||
wordrecg, strutils, options, guards, writetracking
|
||||
wordrecg, strutils, options, guards, writetracking, configuration,
|
||||
modulegraphs
|
||||
|
||||
when defined(useDfa):
|
||||
import dfa
|
||||
@@ -52,6 +53,8 @@ type
|
||||
locked: seq[PNode] # locked locations
|
||||
gcUnsafe, isRecursive, isToplevel, hasSideEffect, inEnforcedGcSafe: bool
|
||||
maxLockLevel, currLockLevel: TLockLevel
|
||||
config: ConfigRef
|
||||
graph: ModuleGraph
|
||||
PEffects = var TEffects
|
||||
|
||||
proc `<`(a, b: TLockLevel): bool {.borrow.}
|
||||
@@ -72,24 +75,23 @@ proc getLockLevel(t: PType): TLockLevel =
|
||||
|
||||
proc lockLocations(a: PEffects; pragma: PNode) =
|
||||
if pragma.kind != nkExprColonExpr:
|
||||
localError(pragma.info, errGenerated, "locks pragma without argument")
|
||||
localError(a.config, pragma.info, "locks pragma without argument")
|
||||
return
|
||||
var firstLL = TLockLevel(-1'i16)
|
||||
for x in pragma[1]:
|
||||
let thisLL = getLockLevel(x.typ)
|
||||
if thisLL != 0.TLockLevel:
|
||||
if thisLL < 0.TLockLevel or thisLL > MaxLockLevel.TLockLevel:
|
||||
localError(x.info, "invalid lock level: " & $thisLL)
|
||||
localError(a.config, x.info, "invalid lock level: " & $thisLL)
|
||||
elif firstLL < 0.TLockLevel: firstLL = thisLL
|
||||
elif firstLL != thisLL:
|
||||
localError(x.info, errGenerated,
|
||||
localError(a.config, x.info,
|
||||
"multi-lock requires the same static lock level for every operand")
|
||||
a.maxLockLevel = max(a.maxLockLevel, firstLL)
|
||||
a.locked.add x
|
||||
if firstLL >= 0.TLockLevel and firstLL != a.currLockLevel:
|
||||
if a.currLockLevel > 0.TLockLevel and a.currLockLevel <= firstLL:
|
||||
localError(pragma.info, errGenerated,
|
||||
"invalid nested locking")
|
||||
localError(a.config, pragma.info, "invalid nested locking")
|
||||
a.currLockLevel = firstLL
|
||||
|
||||
proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
|
||||
@@ -102,7 +104,7 @@ proc guardGlobal(a: PEffects; n: PNode; guard: PSym) =
|
||||
# message(n.info, warnUnguardedAccess, renderTree(n))
|
||||
#else:
|
||||
if not a.isTopLevel:
|
||||
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||
localError(a.config, n.info, "unguarded access: " & renderTree(n))
|
||||
|
||||
# 'guard*' are checks which are concerned with 'guard' annotations
|
||||
# (var x{.guard: y.}: int)
|
||||
@@ -125,7 +127,7 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||
if ty == nil: break
|
||||
ty = ty.skipTypes(skipPtrs)
|
||||
if field == nil:
|
||||
localError(n.info, errGenerated, "invalid guard field: " & g.name.s)
|
||||
localError(a.config, n.info, "invalid guard field: " & g.name.s)
|
||||
return
|
||||
g = field
|
||||
#ri.sym.guard = field
|
||||
@@ -138,13 +140,13 @@ proc guardDotAccess(a: PEffects; n: PNode) =
|
||||
for L in a.locked:
|
||||
#if a.guards.sameSubexprs(dot, L): return
|
||||
if guards.sameTree(dot, L): return
|
||||
localError(n.info, errGenerated, "unguarded access: " & renderTree(n))
|
||||
localError(a.config, n.info, "unguarded access: " & renderTree(n))
|
||||
else:
|
||||
guardGlobal(a, n, g)
|
||||
|
||||
proc makeVolatile(a: PEffects; s: PSym) {.inline.} =
|
||||
template compileToCpp(a): untyped =
|
||||
gCmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
|
||||
a.config.cmd == cmdCompileToCpp or sfCompileToCpp in getModule(a.owner).flags
|
||||
if a.inTryStmt > 0 and not compileToCpp(a):
|
||||
incl(s.flags, sfVolatile)
|
||||
|
||||
@@ -167,9 +169,9 @@ proc initVarViaNew(a: PEffects, n: PNode) =
|
||||
elif isLocalVar(a, s):
|
||||
makeVolatile(a, s)
|
||||
|
||||
proc warnAboutGcUnsafe(n: PNode) =
|
||||
proc warnAboutGcUnsafe(n: PNode; conf: ConfigRef) =
|
||||
#assert false
|
||||
message(n.info, warnGcUnsafe, renderTree(n))
|
||||
message(conf, n.info, warnGcUnsafe, renderTree(n))
|
||||
|
||||
proc markGcUnsafe(a: PEffects; reason: PSym) =
|
||||
if not a.inEnforcedGcSafe:
|
||||
@@ -184,7 +186,7 @@ proc markGcUnsafe(a: PEffects; reason: PNode) =
|
||||
a.owner.gcUnsafetyReason = reason.sym
|
||||
else:
|
||||
a.owner.gcUnsafetyReason = newSym(skUnknown, getIdent("<unknown>"),
|
||||
a.owner, reason.info)
|
||||
a.owner, reason.info, {})
|
||||
|
||||
when true:
|
||||
template markSideEffect(a: PEffects; reason: typed) =
|
||||
@@ -194,42 +196,42 @@ else:
|
||||
a.hasSideEffect = true
|
||||
markGcUnsafe(a, reason)
|
||||
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet) =
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; cycleCheck: var IntSet; conf: ConfigRef) =
|
||||
let u = s.gcUnsafetyReason
|
||||
if u != nil and not cycleCheck.containsOrIncl(u.id):
|
||||
let msgKind = if onlyWarning: warnGcUnsafe2 else: errGenerated
|
||||
case u.kind
|
||||
of skLet, skVar:
|
||||
message(s.info, msgKind,
|
||||
message(conf, s.info, msgKind,
|
||||
("'$#' is not GC-safe as it accesses '$#'" &
|
||||
" which is a global using GC'ed memory") % [s.name.s, u.name.s])
|
||||
of routineKinds:
|
||||
# recursive call *always* produces only a warning so the full error
|
||||
# message is printed:
|
||||
listGcUnsafety(u, true, cycleCheck)
|
||||
message(s.info, msgKind,
|
||||
listGcUnsafety(u, true, cycleCheck, conf)
|
||||
message(conf, s.info, msgKind,
|
||||
"'$#' is not GC-safe as it calls '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
of skParam, skForVar:
|
||||
message(s.info, msgKind,
|
||||
message(conf, s.info, msgKind,
|
||||
"'$#' is not GC-safe as it performs an indirect call via '$#'" %
|
||||
[s.name.s, u.name.s])
|
||||
else:
|
||||
message(u.info, msgKind,
|
||||
message(conf, u.info, msgKind,
|
||||
"'$#' is not GC-safe as it performs an indirect call here" % s.name.s)
|
||||
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool) =
|
||||
proc listGcUnsafety(s: PSym; onlyWarning: bool; conf: ConfigRef) =
|
||||
var cycleCheck = initIntSet()
|
||||
listGcUnsafety(s, onlyWarning, cycleCheck)
|
||||
listGcUnsafety(s, onlyWarning, cycleCheck, conf)
|
||||
|
||||
proc useVar(a: PEffects, n: PNode) =
|
||||
let s = n.sym
|
||||
if isLocalVar(a, s):
|
||||
if s.id notin a.init:
|
||||
if {tfNeedsInit, tfNotNil} * s.typ.flags != {}:
|
||||
message(n.info, warnProveInit, s.name.s)
|
||||
message(a.config, n.info, warnProveInit, s.name.s)
|
||||
else:
|
||||
message(n.info, warnUninit, s.name.s)
|
||||
message(a.config, n.info, warnUninit, s.name.s)
|
||||
# prevent superfluous warnings about the same variable:
|
||||
a.init.add s.id
|
||||
if {sfGlobal, sfThread} * s.flags != {} and s.kind in {skVar, skLet} and
|
||||
@@ -257,34 +259,30 @@ proc addToIntersection(inter: var TIntersection, s: int) =
|
||||
proc throws(tracked, n: PNode) =
|
||||
if n.typ == nil or n.typ.kind != tyError: tracked.add n
|
||||
|
||||
proc getEbase(): PType =
|
||||
result = if getCompilerProc("Exception") != nil: sysTypeFromName"Exception"
|
||||
else: sysTypeFromName"E_Base"
|
||||
proc getEbase(g: ModuleGraph; info: TLineInfo): PType =
|
||||
result = g.sysTypeFromName(info, "Exception")
|
||||
|
||||
proc excType(n: PNode): PType =
|
||||
proc excType(g: ModuleGraph; n: PNode): PType =
|
||||
# reraise is like raising E_Base:
|
||||
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase() else: n.typ
|
||||
let t = if n.kind == nkEmpty or n.typ.isNil: getEbase(g, n.info) else: n.typ
|
||||
result = skipTypes(t, skipPtrs)
|
||||
|
||||
proc createRaise(n: PNode): PNode =
|
||||
proc createRaise(g: ModuleGraph; n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
result.typ = getEbase()
|
||||
result.typ = getEbase(g, n.info)
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc createTag(n: PNode): PNode =
|
||||
proc createTag(g: ModuleGraph; n: PNode): PNode =
|
||||
result = newNode(nkType)
|
||||
if getCompilerProc("RootEffect") != nil:
|
||||
result.typ = sysTypeFromName"RootEffect"
|
||||
else:
|
||||
result.typ = sysTypeFromName"TEffect"
|
||||
result.typ = g.sysTypeFromName(n.info, "RootEffect")
|
||||
if not n.isNil: result.info = n.info
|
||||
|
||||
proc addEffect(a: PEffects, e: PNode, useLineInfo=true) =
|
||||
assert e.kind != nkRaiseStmt
|
||||
var aa = a.exc
|
||||
for i in a.bottom ..< aa.len:
|
||||
if sameType(aa[i].excType, e.excType):
|
||||
if not useLineInfo or gCmd == cmdDoc: return
|
||||
if sameType(a.graph.excType(aa[i]), a.graph.excType(e)):
|
||||
if not useLineInfo or a.config.cmd == cmdDoc: return
|
||||
elif aa[i].info == e.info: return
|
||||
throws(a.exc, e)
|
||||
|
||||
@@ -292,25 +290,25 @@ proc addTag(a: PEffects, e: PNode, useLineInfo=true) =
|
||||
var aa = a.tags
|
||||
for i in 0 ..< aa.len:
|
||||
if sameType(aa[i].typ.skipTypes(skipPtrs), e.typ.skipTypes(skipPtrs)):
|
||||
if not useLineInfo or gCmd == cmdDoc: return
|
||||
if not useLineInfo or a.config.cmd == cmdDoc: return
|
||||
elif aa[i].info == e.info: return
|
||||
throws(a.tags, e)
|
||||
|
||||
proc mergeEffects(a: PEffects, b, comesFrom: PNode) =
|
||||
if b.isNil:
|
||||
addEffect(a, createRaise(comesFrom))
|
||||
addEffect(a, createRaise(a.graph, comesFrom))
|
||||
else:
|
||||
for effect in items(b): addEffect(a, effect, useLineInfo=comesFrom != nil)
|
||||
|
||||
proc mergeTags(a: PEffects, b, comesFrom: PNode) =
|
||||
if b.isNil:
|
||||
addTag(a, createTag(comesFrom))
|
||||
addTag(a, createTag(a.graph, comesFrom))
|
||||
else:
|
||||
for effect in items(b): addTag(a, effect, useLineInfo=comesFrom != nil)
|
||||
|
||||
proc listEffects(a: PEffects) =
|
||||
for e in items(a.exc): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.tags): message(e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.exc): message(a.config, e.info, hintUser, typeToString(e.typ))
|
||||
for e in items(a.tags): message(a.config, e.info, hintUser, typeToString(e.typ))
|
||||
#if a.maxLockLevel != 0:
|
||||
# message(e.info, hintUser, "lockLevel: " & a.maxLockLevel)
|
||||
|
||||
@@ -320,7 +318,7 @@ proc catches(tracked: PEffects, e: PType) =
|
||||
var i = tracked.bottom
|
||||
while i < L:
|
||||
# r supertype of e?
|
||||
if safeInheritanceDiff(tracked.exc[i].excType, e) <= 0:
|
||||
if safeInheritanceDiff(tracked.graph.excType(tracked.exc[i]), e) <= 0:
|
||||
tracked.exc.sons[i] = tracked.exc.sons[L-1]
|
||||
dec L
|
||||
else:
|
||||
@@ -489,7 +487,7 @@ proc mergeLockLevels(tracked: PEffects, n: PNode, lockLevel: TLockLevel) =
|
||||
if lockLevel >= tracked.currLockLevel:
|
||||
# if in lock section:
|
||||
if tracked.currLockLevel > 0.TLockLevel:
|
||||
localError n.info, errGenerated,
|
||||
localError tracked.config, n.info, errGenerated,
|
||||
"expected lock level < " & $tracked.currLockLevel &
|
||||
" but got lock level " & $lockLevel
|
||||
tracked.maxLockLevel = max(tracked.maxLockLevel, lockLevel)
|
||||
@@ -503,22 +501,22 @@ proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
|
||||
mergeTags(tracked, tagSpec, n)
|
||||
|
||||
if notGcSafe(s.typ) and sfImportc notin s.flags:
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, s)
|
||||
if tfNoSideEffect notin s.typ.flags:
|
||||
markSideEffect(tracked, s)
|
||||
mergeLockLevels(tracked, n, s.getLockLevel)
|
||||
|
||||
proc procVarcheck(n: PNode) =
|
||||
proc procVarcheck(n: PNode; conf: ConfigRef) =
|
||||
if n.kind in nkSymChoices:
|
||||
for x in n: procVarCheck(x)
|
||||
for x in n: procVarCheck(x, conf)
|
||||
elif n.kind == nkSym and n.sym.magic != mNone and n.sym.kind in routineKinds:
|
||||
localError(n.info, errXCannotBePassedToProcVar, n.sym.name.s)
|
||||
localError(conf, n.info, "'$1' cannot be passed to a procvar" % n.sym.name.s)
|
||||
|
||||
proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let n = n.skipConv
|
||||
if paramType.isNil or paramType.kind != tyTypeDesc:
|
||||
procVarcheck skipConvAndClosure(n)
|
||||
procVarcheck skipConvAndClosure(n), tracked.config
|
||||
#elif n.kind in nkSymChoices:
|
||||
# echo "came here"
|
||||
let paramType = paramType.skipTypesOrNil(abstractInst)
|
||||
@@ -534,15 +532,16 @@ proc notNilCheck(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
return
|
||||
case impliesNotNil(tracked.guards, n)
|
||||
of impUnknown:
|
||||
message(n.info, errGenerated,
|
||||
message(tracked.config, n.info, errGenerated,
|
||||
"cannot prove '$1' is not nil" % n.renderTree)
|
||||
of impNo:
|
||||
message(n.info, errGenerated, "'$1' is provably nil" % n.renderTree)
|
||||
message(tracked.config, n.info, errGenerated,
|
||||
"'$1' is provably nil" % n.renderTree)
|
||||
of impYes: discard
|
||||
|
||||
proc assumeTheWorst(tracked: PEffects; n: PNode; op: PType) =
|
||||
addEffect(tracked, createRaise(n))
|
||||
addTag(tracked, createTag(n))
|
||||
addEffect(tracked, createRaise(tracked.graph, n))
|
||||
addTag(tracked, createTag(tracked.graph, n))
|
||||
let lockLevel = if op.lockLevel == UnspecifiedLockLevel: UnknownLockLevel
|
||||
else: op.lockLevel
|
||||
#if lockLevel == UnknownLockLevel:
|
||||
@@ -557,7 +556,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
let a = skipConvAndClosure(n)
|
||||
let op = a.typ
|
||||
if op != nil and op.kind == tyProc and n.skipConv.kind != nkNilLit:
|
||||
internalAssert op.n.sons[0].kind == nkEffectList
|
||||
internalAssert tracked.config, op.n.sons[0].kind == nkEffectList
|
||||
var effectList = op.n.sons[0]
|
||||
let s = n.skipConv
|
||||
if s.kind == nkSym and s.sym.kind in routineKinds:
|
||||
@@ -572,7 +571,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
assumeTheWorst(tracked, n, op)
|
||||
# assume GcUnsafe unless in its type; 'forward' does not matter:
|
||||
if notGcSafe(op) and not isOwnedProcVar(a, tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
elif tfNoSideEffect notin op.flags and not isOwnedProcVar(a, tracked.owner):
|
||||
markSideEffect(tracked, a)
|
||||
@@ -580,7 +579,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
mergeEffects(tracked, effectList.sons[exceptionEffects], n)
|
||||
mergeTags(tracked, effectList.sons[tagEffects], n)
|
||||
if notGcSafe(op):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
elif tfNoSideEffect notin op.flags:
|
||||
markSideEffect(tracked, a)
|
||||
@@ -592,7 +591,7 @@ proc trackOperand(tracked: PEffects, n: PNode, paramType: PType) =
|
||||
# XXX figure out why this can be a non tyProc here. See httpclient.nim for an
|
||||
# example that triggers it.
|
||||
if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
|
||||
localError(n.info, $n & " is not GC safe")
|
||||
localError(tracked.config, n.info, $n & " is not GC safe")
|
||||
notNilCheck(tracked, n, paramType)
|
||||
|
||||
proc breaksBlock(n: PNode): bool =
|
||||
@@ -608,18 +607,18 @@ proc breaksBlock(n: PNode): bool =
|
||||
proc trackCase(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n.sons[0])
|
||||
let oldState = tracked.init.len
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
let stringCase = skipTypes(n.sons[0].typ,
|
||||
abstractVarRange-{tyTypeDesc}).kind in {tyFloat..tyFloat128, tyString}
|
||||
let interesting = not stringCase and interestingCaseExpr(n.sons[0]) and
|
||||
warnProveField in gNotes
|
||||
warnProveField in tracked.config.notes
|
||||
var inter: TIntersection = @[]
|
||||
var toCover = 0
|
||||
for i in 1..<n.len:
|
||||
let branch = n.sons[i]
|
||||
setLen(tracked.init, oldState)
|
||||
if interesting:
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
addCaseBranchFacts(tracked.guards, n, i)
|
||||
for i in 0 ..< branch.len:
|
||||
track(tracked, branch.sons[i])
|
||||
@@ -632,11 +631,11 @@ proc trackCase(tracked: PEffects, n: PNode) =
|
||||
for id, count in items(inter):
|
||||
if count >= toCover: tracked.init.add id
|
||||
# else we can't merge
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
|
||||
proc trackIf(tracked: PEffects, n: PNode) =
|
||||
track(tracked, n.sons[0].sons[0])
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
addFact(tracked.guards, n.sons[0].sons[0])
|
||||
let oldState = tracked.init.len
|
||||
|
||||
@@ -649,7 +648,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
|
||||
|
||||
for i in 1..<n.len:
|
||||
let branch = n.sons[i]
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
for j in 0..i-1:
|
||||
addFactNeg(tracked.guards, n.sons[j].sons[0])
|
||||
if branch.len > 1:
|
||||
@@ -665,7 +664,7 @@ proc trackIf(tracked: PEffects, n: PNode) =
|
||||
for id, count in items(inter):
|
||||
if count >= toCover: tracked.init.add id
|
||||
# else we can't merge as it is not exhaustive
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
|
||||
proc trackBlock(tracked: PEffects, n: PNode) =
|
||||
if n.kind in {nkStmtList, nkStmtListExpr}:
|
||||
@@ -693,7 +692,7 @@ proc paramType(op: PType, i: int): PType =
|
||||
proc cstringCheck(tracked: PEffects; n: PNode) =
|
||||
if n.sons[0].typ.kind == tyCString and (let a = skipConv(n[1]);
|
||||
a.typ.kind == tyString and a.kind notin {nkStrLit..nkTripleStrLit}):
|
||||
message(n.info, warnUnsafeCode, renderTree(n))
|
||||
message(tracked.config, n.info, warnUnsafeCode, renderTree(n))
|
||||
|
||||
proc track(tracked: PEffects, n: PNode) =
|
||||
case n.kind
|
||||
@@ -735,7 +734,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
if notGcSafe(op) and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
if not (a.kind == nkSym and a.sym == tracked.owner):
|
||||
if warnGcUnsafe in gNotes: warnAboutGcUnsafe(n)
|
||||
if warnGcUnsafe in tracked.config.notes: warnAboutGcUnsafe(n, tracked.config)
|
||||
markGcUnsafe(tracked, a)
|
||||
if tfNoSideEffect notin op.flags and not importedFromC(a):
|
||||
# and it's not a recursive call:
|
||||
@@ -753,7 +752,7 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
# var s: seq[notnil]; newSeq(s, 0) is a special case!
|
||||
discard
|
||||
else:
|
||||
message(arg.info, warnProveInit, $arg)
|
||||
message(tracked.config, arg.info, warnProveInit, $arg)
|
||||
for i in 0 ..< safeLen(n):
|
||||
track(tracked, n.sons[i])
|
||||
of nkDotExpr:
|
||||
@@ -761,7 +760,8 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
for i in 0 ..< len(n): track(tracked, n.sons[i])
|
||||
of nkCheckedFieldExpr:
|
||||
track(tracked, n.sons[0])
|
||||
if warnProveField in gNotes: checkFieldAccess(tracked.guards, n)
|
||||
if warnProveField in tracked.config.notes:
|
||||
checkFieldAccess(tracked.guards, n, tracked.config)
|
||||
of nkTryStmt: trackTryStmt(tracked, n)
|
||||
of nkPragma: trackPragmaStmt(tracked, n)
|
||||
of nkAsgn, nkFastAsgn:
|
||||
@@ -798,11 +798,11 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
else:
|
||||
# loop may never execute:
|
||||
let oldState = tracked.init.len
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
addFact(tracked.guards, n.sons[0])
|
||||
track(tracked, n.sons[1])
|
||||
setLen(tracked.init, oldState)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
of nkForStmt, nkParForStmt:
|
||||
# we are very conservative here and assume the loop is never executed:
|
||||
let oldState = tracked.init.len
|
||||
@@ -811,13 +811,13 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
setLen(tracked.init, oldState)
|
||||
of nkObjConstr:
|
||||
when false: track(tracked, n.sons[0])
|
||||
let oldFacts = tracked.guards.len
|
||||
let oldFacts = tracked.guards.s.len
|
||||
for i in 1 ..< len(n):
|
||||
let x = n.sons[i]
|
||||
track(tracked, x)
|
||||
if x.sons[0].kind == nkSym and sfDiscriminant in x.sons[0].sym.flags:
|
||||
addDiscriminantFact(tracked.guards, x)
|
||||
setLen(tracked.guards, oldFacts)
|
||||
setLen(tracked.guards.s, oldFacts)
|
||||
of nkPragmaBlock:
|
||||
let pragmaList = n.sons[0]
|
||||
let oldLocked = tracked.locked.len
|
||||
@@ -844,31 +844,31 @@ proc track(tracked: PEffects, n: PNode) =
|
||||
else:
|
||||
for i in 0 ..< safeLen(n): track(tracked, n.sons[i])
|
||||
|
||||
proc subtypeRelation(spec, real: PNode): bool =
|
||||
result = safeInheritanceDiff(real.excType, spec.typ) <= 0
|
||||
proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
|
||||
result = safeInheritanceDiff(g.excType(real), spec.typ) <= 0
|
||||
|
||||
proc checkRaisesSpec(spec, real: PNode, msg: string, hints: bool;
|
||||
effectPredicate: proc (a, b: PNode): bool {.nimcall.}) =
|
||||
proc checkRaisesSpec(g: ModuleGraph; spec, real: PNode, msg: string, hints: bool;
|
||||
effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.}) =
|
||||
# check that any real exception is listed in 'spec'; mark those as used;
|
||||
# report any unused exception
|
||||
var used = initIntSet()
|
||||
for r in items(real):
|
||||
block search:
|
||||
for s in 0 ..< spec.len:
|
||||
if effectPredicate(spec[s], r):
|
||||
if effectPredicate(g, spec[s], r):
|
||||
used.incl(s)
|
||||
break search
|
||||
# XXX call graph analysis would be nice here!
|
||||
pushInfoContext(spec.info)
|
||||
localError(r.info, errGenerated, msg & typeToString(r.typ))
|
||||
localError(g.config, r.info, errGenerated, msg & typeToString(r.typ))
|
||||
popInfoContext()
|
||||
# hint about unnecessarily listed exception types:
|
||||
if hints:
|
||||
for s in 0 ..< spec.len:
|
||||
if not used.contains(s):
|
||||
message(spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
|
||||
message(g.config, spec[s].info, hintXDeclaredButNotUsed, renderTree(spec[s]))
|
||||
|
||||
proc checkMethodEffects*(disp, branch: PSym) =
|
||||
proc checkMethodEffects*(g: ModuleGraph; disp, branch: PSym) =
|
||||
## checks for consistent effects for multi methods.
|
||||
let actual = branch.typ.n.sons[0]
|
||||
if actual.len != effectListLen: return
|
||||
@@ -876,42 +876,42 @@ proc checkMethodEffects*(disp, branch: PSym) =
|
||||
let p = disp.ast.sons[pragmasPos]
|
||||
let raisesSpec = effectSpec(p, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
checkRaisesSpec(raisesSpec, actual.sons[exceptionEffects],
|
||||
checkRaisesSpec(g, raisesSpec, actual.sons[exceptionEffects],
|
||||
"can raise an unlisted exception: ", hints=off, subtypeRelation)
|
||||
let tagsSpec = effectSpec(p, wTags)
|
||||
if not isNil(tagsSpec):
|
||||
checkRaisesSpec(tagsSpec, actual.sons[tagEffects],
|
||||
checkRaisesSpec(g, tagsSpec, actual.sons[tagEffects],
|
||||
"can have an unlisted effect: ", hints=off, subtypeRelation)
|
||||
if sfThread in disp.flags and notGcSafe(branch.typ):
|
||||
localError(branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
localError(g.config, branch.info, "base method is GC-safe, but '$1' is not" %
|
||||
branch.name.s)
|
||||
if branch.typ.lockLevel > disp.typ.lockLevel:
|
||||
when true:
|
||||
message(branch.info, warnLockLevel,
|
||||
message(g.config, branch.info, warnLockLevel,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
else:
|
||||
# XXX make this an error after bigbreak has been released:
|
||||
localError(branch.info,
|
||||
localError(g.config, branch.info,
|
||||
"base method has lock level $1, but dispatcher has $2" %
|
||||
[$branch.typ.lockLevel, $disp.typ.lockLevel])
|
||||
|
||||
proc setEffectsForProcType*(t: PType, n: PNode) =
|
||||
proc setEffectsForProcType*(g: ModuleGraph; t: PType, n: PNode) =
|
||||
var effects = t.n.sons[0]
|
||||
internalAssert t.kind == tyProc and effects.kind == nkEffectList
|
||||
if t.kind != tyProc or effects.kind != nkEffectList: return
|
||||
|
||||
let
|
||||
raisesSpec = effectSpec(n, wRaises)
|
||||
tagsSpec = effectSpec(n, wTags)
|
||||
if not isNil(raisesSpec) or not isNil(tagsSpec):
|
||||
internalAssert effects.len == 0
|
||||
internalAssert g.config, effects.len == 0
|
||||
newSeq(effects.sons, effectListLen)
|
||||
if not isNil(raisesSpec):
|
||||
effects.sons[exceptionEffects] = raisesSpec
|
||||
if not isNil(tagsSpec):
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
|
||||
proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||
proc initEffects(g: ModuleGraph; effects: PNode; s: PSym; t: var TEffects) =
|
||||
newSeq(effects.sons, effectListLen)
|
||||
effects.sons[exceptionEffects] = newNodeI(nkArgList, s.info)
|
||||
effects.sons[tagEffects] = newNodeI(nkArgList, s.info)
|
||||
@@ -922,52 +922,55 @@ proc initEffects(effects: PNode; s: PSym; t: var TEffects) =
|
||||
t.tags = effects.sons[tagEffects]
|
||||
t.owner = s
|
||||
t.init = @[]
|
||||
t.guards = @[]
|
||||
t.guards.s = @[]
|
||||
t.guards.o = initOperators(g)
|
||||
t.locked = @[]
|
||||
t.graph = g
|
||||
t.config = g.config
|
||||
|
||||
proc trackProc*(s: PSym, body: PNode) =
|
||||
proc trackProc*(g: ModuleGraph; s: PSym, body: PNode) =
|
||||
var effects = s.typ.n.sons[0]
|
||||
internalAssert effects.kind == nkEffectList
|
||||
if effects.kind != nkEffectList: return
|
||||
# effects already computed?
|
||||
if sfForward in s.flags: return
|
||||
if effects.len == effectListLen: return
|
||||
|
||||
var t: TEffects
|
||||
initEffects(effects, s, t)
|
||||
initEffects(g, effects, s, t)
|
||||
track(t, body)
|
||||
if not isEmptyType(s.typ.sons[0]) and
|
||||
{tfNeedsInit, tfNotNil} * s.typ.sons[0].flags != {} and
|
||||
s.kind in {skProc, skFunc, skConverter, skMethod}:
|
||||
var res = s.ast.sons[resultPos].sym # get result symbol
|
||||
if res.id notin t.init:
|
||||
message(body.info, warnProveInit, "result")
|
||||
message(g.config, body.info, warnProveInit, "result")
|
||||
let p = s.ast.sons[pragmasPos]
|
||||
let raisesSpec = effectSpec(p, wRaises)
|
||||
if not isNil(raisesSpec):
|
||||
checkRaisesSpec(raisesSpec, t.exc, "can raise an unlisted exception: ",
|
||||
checkRaisesSpec(g, raisesSpec, t.exc, "can raise an unlisted exception: ",
|
||||
hints=on, subtypeRelation)
|
||||
# after the check, use the formal spec:
|
||||
effects.sons[exceptionEffects] = raisesSpec
|
||||
|
||||
let tagsSpec = effectSpec(p, wTags)
|
||||
if not isNil(tagsSpec):
|
||||
checkRaisesSpec(tagsSpec, t.tags, "can have an unlisted effect: ",
|
||||
checkRaisesSpec(g, tagsSpec, t.tags, "can have an unlisted effect: ",
|
||||
hints=off, subtypeRelation)
|
||||
# after the check, use the formal spec:
|
||||
effects.sons[tagEffects] = tagsSpec
|
||||
|
||||
if sfThread in s.flags and t.gcUnsafe:
|
||||
if optThreads in gGlobalOptions and optThreadAnalysis in gGlobalOptions:
|
||||
if optThreads in g.config.globalOptions and optThreadAnalysis in g.config.globalOptions:
|
||||
#localError(s.info, "'$1' is not GC-safe" % s.name.s)
|
||||
listGcUnsafety(s, onlyWarning=false)
|
||||
listGcUnsafety(s, onlyWarning=false, g.config)
|
||||
else:
|
||||
listGcUnsafety(s, onlyWarning=true)
|
||||
listGcUnsafety(s, onlyWarning=true, g.config)
|
||||
#localError(s.info, warnGcUnsafe2, s.name.s)
|
||||
if sfNoSideEffect in s.flags and t.hasSideEffect:
|
||||
when false:
|
||||
listGcUnsafety(s, onlyWarning=false)
|
||||
listGcUnsafety(s, onlyWarning=false, g.config)
|
||||
else:
|
||||
localError(s.info, errXhasSideEffects, s.name.s)
|
||||
localError(g.config, s.info, "'$1' can have side effects" % s.name.s)
|
||||
if not t.gcUnsafe:
|
||||
s.typ.flags.incl tfGcSafe
|
||||
if not t.hasSideEffect and sfSideEffect notin s.flags:
|
||||
@@ -976,7 +979,7 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
s.typ.lockLevel = t.maxLockLevel
|
||||
elif t.maxLockLevel > s.typ.lockLevel:
|
||||
#localError(s.info,
|
||||
message(s.info, warnLockLevel,
|
||||
message(g.config, s.info, warnLockLevel,
|
||||
"declared lock level is $1, but real lock level is $2" %
|
||||
[$s.typ.lockLevel, $t.maxLockLevel])
|
||||
when defined(useDfa):
|
||||
@@ -984,12 +987,12 @@ proc trackProc*(s: PSym, body: PNode) =
|
||||
dataflowAnalysis(s, body)
|
||||
when false: trackWrites(s, body)
|
||||
|
||||
proc trackTopLevelStmt*(module: PSym; n: PNode) =
|
||||
proc trackTopLevelStmt*(g: ModuleGraph; module: PSym; n: PNode) =
|
||||
if n.kind in {nkPragma, nkMacroDef, nkTemplateDef, nkProcDef, nkFuncDef,
|
||||
nkTypeSection, nkConverterDef, nkMethodDef, nkIteratorDef}:
|
||||
return
|
||||
var effects = newNode(nkEffectList, n.info)
|
||||
var t: TEffects
|
||||
initEffects(effects, module, t)
|
||||
initEffects(g, effects, module, t)
|
||||
t.isToplevel = true
|
||||
track(t, n)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
import
|
||||
intsets, strutils, options, ast, astalgo, trees, treetab, msgs, os,
|
||||
idents, renderer, types, passes, semfold, magicsys, cgmeth, rodread,
|
||||
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals
|
||||
lambdalifting, sempass2, lowerings, lookups, destroyer, liftlocals,
|
||||
modulegraphs
|
||||
|
||||
type
|
||||
PTransNode* = distinct PNode
|
||||
@@ -44,6 +45,7 @@ type
|
||||
nestedProcs: int # > 0 if we are in a nested proc
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
deferDetected, tooEarly, needsDestroyPass: bool
|
||||
graph: ModuleGraph
|
||||
PTransf = ref TTransfContext
|
||||
|
||||
proc newTransNode(a: PNode): PTransNode {.inline.} =
|
||||
@@ -84,7 +86,7 @@ proc pushTransCon(c: PTransf, t: PTransCon) =
|
||||
c.transCon = t
|
||||
|
||||
proc popTransCon(c: PTransf) =
|
||||
if (c.transCon == nil): internalError("popTransCon")
|
||||
if (c.transCon == nil): internalError(c.graph.config, "popTransCon")
|
||||
c.transCon = c.transCon.next
|
||||
|
||||
proc getCurrOwner(c: PTransf): PSym =
|
||||
@@ -97,7 +99,7 @@ proc newTemp(c: PTransf, typ: PType, info: TLineInfo): PNode =
|
||||
incl(r.flags, sfFromGeneric)
|
||||
let owner = getCurrOwner(c)
|
||||
if owner.isIterator and not c.tooEarly:
|
||||
result = freshVarForClosureIter(r, owner)
|
||||
result = freshVarForClosureIter(c.graph, r, owner)
|
||||
else:
|
||||
result = newSymNode(r)
|
||||
|
||||
@@ -118,10 +120,10 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
if s.kind == skIterator:
|
||||
if c.tooEarly: return n
|
||||
else: return liftIterSym(n, getCurrOwner(c))
|
||||
else: return liftIterSym(c.graph, n, getCurrOwner(c))
|
||||
elif s.kind in {skProc, skFunc, skConverter, skMethod} and not c.tooEarly:
|
||||
# top level .closure procs are still somewhat supported for 'Nake':
|
||||
return makeClosure(s, nil, n.info)
|
||||
return makeClosure(c.graph, s, nil, n.info)
|
||||
#elif n.sym.kind in {skVar, skLet} and n.sym.typ.callConv == ccClosure:
|
||||
# echo n.info, " come heer for ", c.tooEarly
|
||||
# if not c.tooEarly:
|
||||
@@ -130,7 +132,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
if sfBorrow in s.flags and s.kind in routineKinds:
|
||||
# simply exchange the symbol:
|
||||
b = s.getBody
|
||||
if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
|
||||
if b.kind != nkSym: internalError(c.graph.config, n.info, "wrong AST for borrowed symbol")
|
||||
b = newSymNode(b.sym, n.info)
|
||||
else:
|
||||
b = n
|
||||
@@ -151,7 +153,7 @@ proc transformSym(c: PTransf, n: PNode): PTransNode =
|
||||
proc freshVar(c: PTransf; v: PSym): PNode =
|
||||
let owner = getCurrOwner(c)
|
||||
if owner.isIterator and not c.tooEarly:
|
||||
result = freshVarForClosureIter(v, owner)
|
||||
result = freshVarForClosureIter(c.graph, v, owner)
|
||||
else:
|
||||
var newVar = copySym(v)
|
||||
incl(newVar.flags, sfFromGeneric)
|
||||
@@ -166,11 +168,11 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||
result[i] = PTransNode(it)
|
||||
elif it.kind == nkIdentDefs:
|
||||
if it.sons[0].kind == nkSym:
|
||||
internalAssert(it.len == 3)
|
||||
internalAssert(c.graph.config, it.len == 3)
|
||||
let x = freshVar(c, it.sons[0].sym)
|
||||
idNodeTablePut(c.transCon.mapping, it.sons[0].sym, x)
|
||||
var defs = newTransNode(nkIdentDefs, it.info, 3)
|
||||
if importantComments():
|
||||
if importantComments(c.graph.config):
|
||||
# keep documentation information:
|
||||
PNode(defs).comment = it.comment
|
||||
defs[0] = x.PTransNode
|
||||
@@ -184,7 +186,7 @@ proc transformVarSection(c: PTransf, v: PNode): PTransNode =
|
||||
result[i] = transform(c, it)
|
||||
else:
|
||||
if it.kind != nkVarTuple:
|
||||
internalError(it.info, "transformVarSection: not nkVarTuple")
|
||||
internalError(c.graph.config, it.info, "transformVarSection: not nkVarTuple")
|
||||
var L = sonsLen(it)
|
||||
var defs = newTransNode(it.kind, it.info, L)
|
||||
for j in countup(0, L-3):
|
||||
@@ -203,9 +205,9 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode =
|
||||
if it.kind == nkCommentStmt:
|
||||
result[i] = PTransNode(it)
|
||||
else:
|
||||
if it.kind != nkConstDef: internalError(it.info, "transformConstSection")
|
||||
if it.kind != nkConstDef: internalError(c.graph.config, it.info, "transformConstSection")
|
||||
if it.sons[0].kind != nkSym:
|
||||
internalError(it.info, "transformConstSection")
|
||||
internalError(c.graph.config, it.info, "transformConstSection")
|
||||
|
||||
result[i] = PTransNode(it)
|
||||
|
||||
@@ -301,7 +303,7 @@ proc unpackTuple(c: PTransf, n: PNode, father: PTransNode) =
|
||||
# XXX: BUG: what if `n` is an expression with side-effects?
|
||||
for i in countup(0, sonsLen(c.transCon.forStmt) - 3):
|
||||
add(father, newAsgnStmt(c, c.transCon.forStmt.sons[i],
|
||||
transform(c, newTupleAccess(n, i))))
|
||||
transform(c, newTupleAccess(c.graph, n, i))))
|
||||
|
||||
proc introduceNewLocalVars(c: PTransf, n: PNode): PTransNode =
|
||||
case n.kind
|
||||
@@ -356,7 +358,7 @@ proc transformYield(c: PTransf, n: PNode): PTransNode =
|
||||
|
||||
proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||
result = transformSons(c, n)
|
||||
if gCmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
|
||||
if c.graph.config.cmd == cmdCompileToCpp or sfCompileToCpp in c.module.flags: return
|
||||
var n = result.PNode
|
||||
case n.sons[0].kind
|
||||
of nkObjUpConv, nkObjDownConv, nkChckRange, nkChckRangeF, nkChckRange64:
|
||||
@@ -382,21 +384,21 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
|
||||
if n.typ.skipTypes(abstractVar).kind != tyOpenArray:
|
||||
PNode(result).typ = n.typ
|
||||
|
||||
proc generateThunk(prc: PNode, dest: PType): PNode =
|
||||
proc generateThunk(c: PTransf; prc: PNode, dest: PType): PNode =
|
||||
## Converts 'prc' into '(thunk, nil)' so that it's compatible with
|
||||
## a closure.
|
||||
|
||||
# we cannot generate a proper thunk here for GC-safety reasons
|
||||
# (see internal documentation):
|
||||
if gCmd == cmdCompileToJS: return prc
|
||||
if c.graph.config.cmd == cmdCompileToJS: return prc
|
||||
result = newNodeIT(nkClosure, prc.info, dest)
|
||||
var conv = newNodeIT(nkHiddenSubConv, prc.info, dest)
|
||||
conv.add(emptyNode)
|
||||
conv.add(prc)
|
||||
if prc.kind == nkClosure:
|
||||
internalError(prc.info, "closure to closure created")
|
||||
internalError(c.graph.config, prc.info, "closure to closure created")
|
||||
result.add(conv)
|
||||
result.add(newNodeIT(nkNilLit, prc.info, getSysType(tyNil)))
|
||||
result.add(newNodeIT(nkNilLit, prc.info, getSysType(c.graph, prc.info, tyNil)))
|
||||
|
||||
proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
# numeric types need range checks:
|
||||
@@ -481,7 +483,7 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
|
||||
of tyProc:
|
||||
result = transformSons(c, n)
|
||||
if dest.callConv == ccClosure and source.callConv == ccDefault:
|
||||
result = generateThunk(result[1].PNode, dest).PTransNode
|
||||
result = generateThunk(c, result[1].PNode, dest).PTransNode
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
|
||||
@@ -513,7 +515,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
|
||||
if n.kind == nkVarSection:
|
||||
let x = n.sons[0].sons[0]
|
||||
if x.kind == nkSym and x.sym.owner != getCurrOwner(c):
|
||||
internalError(x.info, "bah " & x.sym.name.s & " " &
|
||||
internalError(c.graph.config, x.info, "bah " & x.sym.name.s & " " &
|
||||
x.sym.owner.name.s & " " & getCurrOwner(c).name.s)
|
||||
else:
|
||||
for i in 0 ..< safeLen(n): findWrongOwners(c, n.sons[i])
|
||||
@@ -521,7 +523,7 @@ proc findWrongOwners(c: PTransf, n: PNode) =
|
||||
proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
# generate access statements for the parameters (unless they are constant)
|
||||
# put mapping from formal parameters to actual parameters
|
||||
if n.kind != nkForStmt: internalError(n.info, "transformFor")
|
||||
if n.kind != nkForStmt: internalError(c.graph.config, n.info, "transformFor")
|
||||
|
||||
var length = sonsLen(n)
|
||||
var call = n.sons[length - 2]
|
||||
@@ -539,7 +541,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
|
||||
n.sons[length-1] = transformLoopBody(c, n.sons[length-1]).PNode
|
||||
if not c.tooEarly:
|
||||
n.sons[length-2] = transform(c, n.sons[length-2]).PNode
|
||||
result[1] = lambdalifting.liftForLoop(n, getCurrOwner(c)).PTransNode
|
||||
result[1] = lambdalifting.liftForLoop(c.graph, n, getCurrOwner(c)).PTransNode
|
||||
else:
|
||||
result[1] = newNode(nkEmpty).PTransNode
|
||||
discard c.breakSyms.pop
|
||||
@@ -689,7 +691,7 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
while (j < sonsLen(n)):
|
||||
let b = transform(c, n.sons[j]).PNode
|
||||
if not isConstExpr(b): break
|
||||
a = evalOp(op.magic, n, a, b, nil)
|
||||
a = evalOp(op.magic, n, a, b, nil, c.graph)
|
||||
inc(j)
|
||||
add(result, a.PTransNode)
|
||||
if len(result) == 2: result = result[1]
|
||||
@@ -708,18 +710,18 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||
let t = lastSon(s.sons[0].sym.ast)
|
||||
if t.kind != nkSym or sfDispatcher notin t.sym.flags:
|
||||
methodDef(s.sons[0].sym, false)
|
||||
result = methodCall(s).PTransNode
|
||||
result = methodCall(s, c.graph.config).PTransNode
|
||||
else:
|
||||
result = s.PTransNode
|
||||
|
||||
proc transformExceptBranch(c: PTransf, n: PNode): PTransNode =
|
||||
result = transformSons(c, n)
|
||||
if n[0].isInfixAs() and (not isImportedException(n[0][1].typ)):
|
||||
if n[0].isInfixAs() and not isImportedException(n[0][1].typ, c.graph.config):
|
||||
let excTypeNode = n[0][1]
|
||||
let actions = newTransNode(nkStmtListExpr, n[1], 2)
|
||||
# Generating `let exc = (excType)(getCurrentException())`
|
||||
# -> getCurrentException()
|
||||
let excCall = PTransNode(callCodegenProc("getCurrentException", ast.emptyNode))
|
||||
let excCall = PTransNode(callCodegenProc(c.graph, "getCurrentException", ast.emptyNode))
|
||||
# -> (excType)
|
||||
let convNode = newTransNode(nkHiddenSubConv, n[1].info, 2)
|
||||
convNode[0] = PTransNode(ast.emptyNode)
|
||||
@@ -748,10 +750,10 @@ proc dontInlineConstant(orig, cnst: PNode): bool {.inline.} =
|
||||
result = orig.kind == nkSym and cnst.kind in {nkCurly, nkPar, nkTupleConstr, nkBracket} and
|
||||
cnst.len != 0
|
||||
|
||||
proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||
proc commonOptimizations*(g: ModuleGraph; c: PSym, n: PNode): PNode =
|
||||
result = n
|
||||
for i in 0 ..< n.safeLen:
|
||||
result.sons[i] = commonOptimizations(c, n.sons[i])
|
||||
result.sons[i] = commonOptimizations(g, c, n.sons[i])
|
||||
var op = getMergeOp(n)
|
||||
if (op != nil) and (op.magic != mNone) and (sonsLen(n) >= 3):
|
||||
result = newNodeIT(nkCall, n.info, n.typ)
|
||||
@@ -766,12 +768,12 @@ proc commonOptimizations*(c: PSym, n: PNode): PNode =
|
||||
while j < sonsLen(args):
|
||||
let b = args.sons[j]
|
||||
if not isConstExpr(b): break
|
||||
a = evalOp(op.magic, result, a, b, nil)
|
||||
a = evalOp(op.magic, result, a, b, nil, g)
|
||||
inc(j)
|
||||
add(result, a)
|
||||
if len(result) == 2: result = result[1]
|
||||
else:
|
||||
var cnst = getConstExpr(c, n)
|
||||
var cnst = getConstExpr(c, n, g)
|
||||
# we inline constants if they are not complex constants:
|
||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
result = cnst
|
||||
@@ -888,7 +890,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
let L = n.len-1
|
||||
result[L] = transform(c, n.sons[L])
|
||||
# XXX comment handling really sucks:
|
||||
if importantComments():
|
||||
if importantComments(c.graph.config):
|
||||
PNode(result).comment = n.comment
|
||||
of nkClosure:
|
||||
# it can happen that for-loop-inlining produced a fresh
|
||||
@@ -905,7 +907,7 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
||||
when false:
|
||||
if oldDeferAnchor != nil: c.deferAnchor = oldDeferAnchor
|
||||
|
||||
var cnst = getConstExpr(c.module, PNode(result))
|
||||
var cnst = getConstExpr(c.module, PNode(result), c.graph)
|
||||
# we inline constants if they are not complex constants:
|
||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
result = PTransNode(cnst) # do not miss an optimization
|
||||
@@ -920,11 +922,12 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||
popTransCon(c)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc openTransf(module: PSym, filename: string): PTransf =
|
||||
proc openTransf(g: ModuleGraph; module: PSym, filename: string): PTransf =
|
||||
new(result)
|
||||
result.contSyms = @[]
|
||||
result.breakSyms = @[]
|
||||
result.module = module
|
||||
result.graph = g
|
||||
|
||||
proc flattenStmts(n: PNode) =
|
||||
var goOn = true
|
||||
@@ -967,46 +970,46 @@ template liftDefer(c, root) =
|
||||
if c.deferDetected:
|
||||
liftDeferAux(root)
|
||||
|
||||
proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
|
||||
proc transformBody*(g: ModuleGraph; module: PSym, n: PNode, prc: PSym): PNode =
|
||||
if nfTransf in n.flags or prc.kind in {skTemplate}:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
result = liftLambdas(prc, n, c.tooEarly)
|
||||
var c = openTransf(g, module, "")
|
||||
result = liftLambdas(g, prc, n, c.tooEarly)
|
||||
#result = n
|
||||
result = processTransf(c, result, prc)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdas(prc, result)
|
||||
when useEffectSystem: trackProc(prc, result)
|
||||
result = liftLocalsIfRequested(prc, result)
|
||||
when useEffectSystem: trackProc(g, prc, result)
|
||||
result = liftLocalsIfRequested(prc, result, g.config)
|
||||
if c.needsDestroyPass: #and newDestructors:
|
||||
result = injectDestructorCalls(prc, result)
|
||||
result = injectDestructorCalls(g, prc, result)
|
||||
incl(result.flags, nfTransf)
|
||||
#if prc.name.s == "testbody":
|
||||
# echo renderTree(result)
|
||||
|
||||
proc transformStmt*(module: PSym, n: PNode): PNode =
|
||||
proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
var c = openTransf(g, module, "")
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdasForTopLevel(module, result)
|
||||
when useEffectSystem: trackTopLevelStmt(module, result)
|
||||
when useEffectSystem: trackTopLevelStmt(g, module, result)
|
||||
#if n.info ?? "temp.nim":
|
||||
# echo renderTree(result, {renderIds})
|
||||
if c.needsDestroyPass:
|
||||
result = injectDestructorCalls(module, result)
|
||||
result = injectDestructorCalls(g, module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc transformExpr*(module: PSym, n: PNode): PNode =
|
||||
proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(module, "")
|
||||
var c = openTransf(g, module, "")
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
if c.needsDestroyPass:
|
||||
result = injectDestructorCalls(module, result)
|
||||
result = injectDestructorCalls(g, module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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`.
|
||||
|
||||
228
compiler/vm.nim
228
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 out of bounds"
|
||||
errNilAccess = "attempt to access a nil address"
|
||||
errOverOrUnderflow = "over- or underflow"
|
||||
errConstantDivisionByZero = "division by zero"
|
||||
errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
|
||||
errTooManyIterations = "interpretation requires too many iterations; " &
|
||||
"if you are sure this is not a bug in your code edit " &
|
||||
"compiler/vmdef.MaxLoopIterations and rebuild the compiler"
|
||||
errFieldXNotFound = "node lacks field: "
|
||||
|
||||
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
var pc = start
|
||||
var tos = tos
|
||||
@@ -453,7 +464,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
#if c.traceActive:
|
||||
when traceCode:
|
||||
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
|
||||
# message(c.debug[pc], warnUser, "Trace")
|
||||
# message(c.config, c.debug[pc], warnUser, "Trace")
|
||||
|
||||
case instr.opcode
|
||||
of opcEof: return regs[ra]
|
||||
@@ -586,7 +597,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[rb].kind == rkNode:
|
||||
regs[ra].nodeAddr = addr(regs[rb].node)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'addr'")
|
||||
stackTrace(c, tos, pc, "limited VM support for 'addr'")
|
||||
of opcLdDeref:
|
||||
# a = b[]
|
||||
let ra = instr.regA
|
||||
@@ -629,7 +640,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
stackTrace(c, tos, pc, errOverOrUnderflow)
|
||||
of opcAddImmInt:
|
||||
decodeBImm(rkInt)
|
||||
#message(c.debug[pc], warnUser, "came here")
|
||||
#message(c.config, c.debug[pc], warnUser, "came here")
|
||||
#debug regs[rb].node
|
||||
let
|
||||
bVal = regs[rb].intVal
|
||||
@@ -898,17 +909,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
|
||||
else: copyTree(a.sym.ast)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
|
||||
stackTrace(c, tos, pc, "node is not a symbol")
|
||||
of opcEcho:
|
||||
let rb = instr.regB
|
||||
if rb == 1:
|
||||
msgWriteln(regs[ra].node.strVal, {msgStdout})
|
||||
msgWriteln(c.config, regs[ra].node.strVal, {msgStdout})
|
||||
else:
|
||||
var outp = ""
|
||||
for i in ra..ra+rb-1:
|
||||
#if regs[i].kind != rkNode: debug regs[i]
|
||||
outp.add(regs[i].node.strVal)
|
||||
msgWriteln(outp, {msgStdout})
|
||||
msgWriteln(c.config, outp, {msgStdout})
|
||||
of opcContainsSet:
|
||||
decodeBC(rkInt)
|
||||
regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
|
||||
@@ -937,9 +948,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let rc = instr.regC
|
||||
if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
|
||||
leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
|
||||
stackTrace(c, tos, pc, errGenerated,
|
||||
msgKindToString(errIllegalConvFromXtoY) % [
|
||||
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
|
||||
stackTrace(c, tos, pc,
|
||||
errIllegalConvFromXtoY % [
|
||||
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
|
||||
of opcIndCall, opcIndCallAsgn:
|
||||
# dest = call regStart, n; where regStart = fn, arg1, ...
|
||||
let rb = instr.regB
|
||||
@@ -955,20 +966,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
currentLineInfo: c.debug[pc]))
|
||||
elif sfImportc in prc.flags:
|
||||
if allowFFI notin c.features:
|
||||
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
|
||||
globalError(c.config, c.debug[pc], "VM not allowed to do FFI")
|
||||
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep
|
||||
# 'regs' in a register:
|
||||
when hasFFI:
|
||||
let prcValue = c.globals.sons[prc.position-1]
|
||||
if prcValue.kind == nkEmpty:
|
||||
globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
|
||||
globalError(c.config, c.debug[pc], "canot run " & prc.name.s)
|
||||
let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
|
||||
rb+1, rc-1, c.debug[pc])
|
||||
if newValue.kind != nkEmpty:
|
||||
assert instr.opcode == opcIndCallAsgn
|
||||
putIntoReg(regs[ra], newValue)
|
||||
else:
|
||||
globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
|
||||
globalError(c.config, c.debug[pc], "VM not built with FFI support")
|
||||
elif prc.kind != skTemplate:
|
||||
let newPc = compile(c, prc)
|
||||
# tricky: a recursion is also a jump back, so we use the same
|
||||
@@ -978,7 +989,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
||||
newSeq(newFrame.slots, prc.offset+ord(isClosure))
|
||||
if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
|
||||
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
|
||||
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
|
||||
for i in 1 .. rc-1:
|
||||
newFrame.slots[i] = regs[rb+i]
|
||||
if isClosure:
|
||||
@@ -1000,7 +1011,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let node = regs[rb+i].regToNode
|
||||
node.info = c.debug[pc]
|
||||
macroCall.add(node)
|
||||
var a = evalTemplate(macroCall, prc, genSymOwner)
|
||||
var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
|
||||
if a.kind == nkStmtList and a.len == 1: a = a[0]
|
||||
a.recSetFlagIsRef
|
||||
ensureKind(rkNode)
|
||||
@@ -1085,7 +1096,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcNew:
|
||||
ensureKind(rkNode)
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc])
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
|
||||
regs[ra].node.flags.incl nfIsRef
|
||||
of opcNewSeq:
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
@@ -1097,7 +1108,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node.typ = typ
|
||||
newSeq(regs[ra].node.sons, count)
|
||||
for i in 0 ..< count:
|
||||
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
|
||||
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
|
||||
of opcNewStr:
|
||||
decodeB(rkNode)
|
||||
regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
|
||||
@@ -1109,7 +1120,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcLdNull:
|
||||
ensureKind(rkNode)
|
||||
let typ = c.types[instr.regBx - wordExcess]
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc])
|
||||
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
|
||||
# opcLdNull really is the gist of the VM's problems: should it load
|
||||
# a fresh null to regs[ra].node or to regs[ra].node[]? This really
|
||||
# depends on whether regs[ra] represents the variable itself or wether
|
||||
@@ -1156,7 +1167,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
|
||||
of opcQuit:
|
||||
if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
|
||||
message(c.debug[pc], hintQuitCalled)
|
||||
message(c.config, c.debug[pc], hintQuitCalled)
|
||||
msgQuit(int8(getOrdValue(regs[ra].regToNode)))
|
||||
else:
|
||||
return TFullReg(kind: rkNone)
|
||||
@@ -1182,14 +1193,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
|
||||
else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
|
||||
of opcReset:
|
||||
internalError(c.debug[pc], "too implement")
|
||||
internalError(c.config, c.debug[pc], "too implement")
|
||||
of opcNarrowS:
|
||||
decodeB(rkInt)
|
||||
let min = -(1.BiggestInt shl (rb-1))
|
||||
let max = (1.BiggestInt shl (rb-1))-1
|
||||
if regs[ra].intVal < min or regs[ra].intVal > max:
|
||||
stackTrace(c, tos, pc, errGenerated,
|
||||
msgKindToString(errUnhandledExceptionX) % "value out of range")
|
||||
stackTrace(c, tos, pc, "unhandled exception: value out of range")
|
||||
of opcNarrowU:
|
||||
decodeB(rkInt)
|
||||
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
|
||||
@@ -1223,7 +1233,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if u.kind notin {nkEmpty..nkNilLit}:
|
||||
u.add(regs[rc].node)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
|
||||
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
|
||||
regs[ra].node = u
|
||||
of opcNAddMultiple:
|
||||
decodeBC(rkNode)
|
||||
@@ -1233,7 +1243,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
# XXX can be optimized:
|
||||
for i in 0..<x.len: u.add(x.sons[i])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
|
||||
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
|
||||
regs[ra].node = u
|
||||
of opcNKind:
|
||||
decodeB(rkInt)
|
||||
@@ -1245,34 +1255,34 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if a.kind == nkSym:
|
||||
regs[ra].intVal = ord(a.sym.kind)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
|
||||
stackTrace(c, tos, pc, "node is not a symbol")
|
||||
c.comesFromHeuristic = regs[rb].node.info
|
||||
of opcNIntVal:
|
||||
decodeB(rkInt)
|
||||
let a = regs[rb].node
|
||||
case a.kind
|
||||
of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
|
||||
of opcNFloatVal:
|
||||
decodeB(rkFloat)
|
||||
let a = regs[rb].node
|
||||
case a.kind
|
||||
of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
|
||||
of opcNSymbol:
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
if a.kind == nkSym:
|
||||
regs[ra].node = copyNode(a)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
|
||||
of opcNIdent:
|
||||
decodeB(rkNode)
|
||||
let a = regs[rb].node
|
||||
if a.kind == nkIdent:
|
||||
regs[ra].node = copyNode(a)
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
|
||||
of opcNGetType:
|
||||
let rb = instr.regB
|
||||
let rc = instr.regC
|
||||
@@ -1283,28 +1293,28 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
stackTrace(c, tos, pc, "node has no type")
|
||||
of 1:
|
||||
# typeKind opcode:
|
||||
ensureKind(rkInt)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].intVal = ord(regs[rb].node.typ.kind)
|
||||
#else:
|
||||
# stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
# stackTrace(c, tos, pc, "node has no type")
|
||||
of 2:
|
||||
# getTypeInst opcode:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
stackTrace(c, tos, pc, "node has no type")
|
||||
else:
|
||||
# getTypeImpl opcode:
|
||||
ensureKind(rkNode)
|
||||
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
|
||||
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
|
||||
else:
|
||||
stackTrace(c, tos, pc, errGenerated, "node has no type")
|
||||
stackTrace(c, tos, pc, "node has no type")
|
||||
of opcNStrVal:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
@@ -1319,12 +1329,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of nkSym:
|
||||
regs[ra].node.strVal = a.sym.name.s
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
|
||||
of opcSlurp:
|
||||
decodeB(rkNode)
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
|
||||
c.module)
|
||||
c.module, c.config)
|
||||
of opcGorge:
|
||||
decodeBC(rkNode)
|
||||
inc pc
|
||||
@@ -1333,29 +1343,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
|
||||
regs[rc].node.strVal, regs[rd].node.strVal,
|
||||
c.debug[pc])[0]
|
||||
c.debug[pc], c.config)[0]
|
||||
of opcNError:
|
||||
decodeB(rkNode)
|
||||
let a = regs[ra].node
|
||||
let b = regs[rb].node
|
||||
stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b)
|
||||
stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b)
|
||||
of opcNWarning:
|
||||
message(c.debug[pc], warnUser, regs[ra].node.strVal)
|
||||
message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal)
|
||||
of opcNHint:
|
||||
message(c.debug[pc], hintUser, regs[ra].node.strVal)
|
||||
message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal)
|
||||
of opcParseExprToAst:
|
||||
decodeB(rkNode)
|
||||
# c.debug[pc].line.int - countLines(regs[rb].strVal) ?
|
||||
var error: string
|
||||
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
|
||||
c.debug[pc].toFullPath, c.debug[pc].line.int,
|
||||
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
if error.isNil and msg <= msgs.errMax:
|
||||
error = formatMsg(info, msg, arg))
|
||||
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
if error.isNil and msg <= errMax:
|
||||
error = formatMsg(conf, info, msg, arg))
|
||||
if not error.isNil:
|
||||
c.errorFlag = error
|
||||
elif sonsLen(ast) != 1:
|
||||
c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements")
|
||||
c.errorFlag = formatMsg(c.config, c.debug[pc], errGenerated,
|
||||
"expected expression, but got multiple statements")
|
||||
else:
|
||||
regs[ra].node = ast.sons[0]
|
||||
of opcParseStmtToAst:
|
||||
@@ -1363,9 +1374,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
var error: string
|
||||
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
|
||||
c.debug[pc].toFullPath, c.debug[pc].line.int,
|
||||
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
if error.isNil and msg <= msgs.errMax:
|
||||
error = formatMsg(info, msg, arg))
|
||||
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
|
||||
if error.isNil and msg <= errMax:
|
||||
error = formatMsg(conf, info, msg, arg))
|
||||
if not error.isNil:
|
||||
c.errorFlag = error
|
||||
else:
|
||||
@@ -1377,7 +1388,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcCallSite:
|
||||
ensureKind(rkNode)
|
||||
if c.callsite != nil: regs[ra].node = c.callsite
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
|
||||
else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
|
||||
of opcNGetFile:
|
||||
decodeB(rkNode)
|
||||
let n = regs[rb].node
|
||||
@@ -1439,13 +1450,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
of opcStrToIdent:
|
||||
decodeB(rkNode)
|
||||
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
|
||||
else:
|
||||
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
|
||||
regs[ra].node.ident = getIdent(regs[rb].node.strVal)
|
||||
of opcSetType:
|
||||
if regs[ra].kind != rkNode:
|
||||
internalError(c.debug[pc], "cannot set type")
|
||||
internalError(c.config, c.debug[pc], "cannot set type")
|
||||
regs[ra].node.typ = c.types[instr.regBx - wordExcess]
|
||||
of opcConv:
|
||||
let rb = instr.regB
|
||||
@@ -1454,9 +1465,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
inc pc
|
||||
let srctyp = c.types[c.code[pc].regBx - wordExcess]
|
||||
|
||||
if opConv(regs[ra], regs[rb], desttyp, srctyp):
|
||||
stackTrace(c, tos, pc, errGenerated,
|
||||
msgKindToString(errIllegalConvFromXtoY) % [
|
||||
if opConv(c, regs[ra], regs[rb], desttyp, srctyp):
|
||||
stackTrace(c, tos, pc,
|
||||
errIllegalConvFromXtoY % [
|
||||
typeToString(srctyp), typeToString(desttyp)])
|
||||
of opcCast:
|
||||
let rb = instr.regB
|
||||
@@ -1469,7 +1480,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let dest = fficast(regs[rb], desttyp)
|
||||
asgnRef(regs[ra], dest)
|
||||
else:
|
||||
globalError(c.debug[pc], "cannot evaluate cast")
|
||||
globalError(c.config, c.debug[pc], "cannot evaluate cast")
|
||||
of opcNSetIntVal:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
@@ -1477,7 +1488,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[rb].kind in {rkInt}:
|
||||
dest.intVal = regs[rb].intVal
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
|
||||
of opcNSetFloatVal:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
@@ -1485,26 +1496,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
regs[rb].kind in {rkFloat}:
|
||||
dest.floatVal = regs[rb].floatVal
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
|
||||
of opcNSetSymbol:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
|
||||
dest.sym = regs[rb].node.sym
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
|
||||
of opcNSetIdent:
|
||||
decodeB(rkNode)
|
||||
var dest = regs[ra].node
|
||||
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
|
||||
dest.ident = regs[rb].node.ident
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
|
||||
of opcNSetType:
|
||||
decodeB(rkNode)
|
||||
let b = regs[rb].node
|
||||
internalAssert b.kind == nkSym and b.sym.kind == skType
|
||||
internalAssert regs[ra].node != nil
|
||||
internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
|
||||
internalAssert c.config, regs[ra].node != nil
|
||||
regs[ra].node.typ = b.sym.typ
|
||||
of opcNSetStrVal:
|
||||
decodeB(rkNode)
|
||||
@@ -1515,12 +1526,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
|
||||
dest.comment = regs[rb].node.strVal
|
||||
else:
|
||||
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
|
||||
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
|
||||
of opcNNewNimNode:
|
||||
decodeBC(rkNode)
|
||||
var k = regs[rb].intVal
|
||||
if k < 0 or k > ord(high(TNodeKind)):
|
||||
internalError(c.debug[pc],
|
||||
internalError(c.config, c.debug[pc],
|
||||
"request to create a NimNode of invalid kind")
|
||||
let cc = regs[rc].node
|
||||
|
||||
@@ -1554,7 +1565,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let name = if regs[rc].node.strVal.len == 0: ":tmp"
|
||||
else: regs[rc].node.strVal
|
||||
if k < 0 or k > ord(high(TSymKind)):
|
||||
internalError(c.debug[pc], "request to create symbol of invalid kind")
|
||||
internalError(c.config, c.debug[pc], "request to create symbol of invalid kind")
|
||||
var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc])
|
||||
incl(sym.flags, sfGenSym)
|
||||
regs[ra].node = newSymNode(sym)
|
||||
@@ -1563,7 +1574,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
# type trait operation
|
||||
decodeB(rkNode)
|
||||
var typ = regs[rb].node.typ
|
||||
internalAssert typ != nil
|
||||
internalAssert c.config, typ != nil
|
||||
while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
|
||||
createStr regs[ra]
|
||||
regs[ra].node.strVal = typ.typeToString(preferExported)
|
||||
@@ -1572,14 +1583,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let rb = instr.regB
|
||||
inc pc
|
||||
let typ = c.types[c.code[pc].regBx - wordExcess]
|
||||
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
|
||||
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config))
|
||||
of opcMarshalStore:
|
||||
decodeB(rkNode)
|
||||
inc pc
|
||||
let typ = c.types[c.code[pc].regBx - wordExcess]
|
||||
createStrKeepNode(regs[ra])
|
||||
if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
|
||||
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
|
||||
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
|
||||
of opcToNarrowInt:
|
||||
decodeBC(rkInt)
|
||||
let mask = (1'i64 shl rc) - 1 # 0xFF
|
||||
@@ -1601,7 +1612,7 @@ proc execute(c: PCtx, start: int): PNode =
|
||||
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
if sym.kind in routineKinds:
|
||||
if sym.typ.len-1 != args.len:
|
||||
localError(sym.info,
|
||||
localError(c.config, sym.info,
|
||||
"NimScript: expected $# arguments, but got $#" % [
|
||||
$(sym.typ.len-1), $args.len])
|
||||
else:
|
||||
@@ -1613,18 +1624,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
|
||||
|
||||
# setup parameters:
|
||||
if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
|
||||
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info))
|
||||
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
|
||||
# XXX We could perform some type checking here.
|
||||
for i in 1..<sym.typ.len:
|
||||
putIntoReg(tos.slots[i], args[i-1])
|
||||
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
else:
|
||||
localError(sym.info,
|
||||
localError(c.config, sym.info,
|
||||
"NimScript: attempt to call non-routine: " & sym.name.s)
|
||||
|
||||
proc evalStmt*(c: PCtx, n: PNode) =
|
||||
let n = transformExpr(c.module, n)
|
||||
let n = transformExpr(c.graph, c.module, n)
|
||||
let start = genStmt(c, n)
|
||||
# execute new instructions; this redundant opcEof check saves us lots
|
||||
# of allocations in 'execute':
|
||||
@@ -1632,13 +1643,13 @@ proc evalStmt*(c: PCtx, n: PNode) =
|
||||
discard execute(c, start)
|
||||
|
||||
proc evalExpr*(c: PCtx, n: PNode): PNode =
|
||||
let n = transformExpr(c.module, n)
|
||||
let n = transformExpr(c.graph, c.module, n)
|
||||
let start = genExpr(c, n)
|
||||
assert c.code[start].opcode != opcEof
|
||||
result = execute(c, start)
|
||||
|
||||
proc getGlobalValue*(c: PCtx; s: PSym): PNode =
|
||||
internalAssert s.kind in {skLet, skVar} and sfGlobal in s.flags
|
||||
internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
|
||||
result = c.globals.sons[s.position-1]
|
||||
|
||||
include vmops
|
||||
@@ -1649,9 +1660,9 @@ include vmops
|
||||
var
|
||||
globalCtx*: PCtx
|
||||
|
||||
proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) =
|
||||
proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) =
|
||||
if globalCtx.isNil:
|
||||
globalCtx = newCtx(module, cache, config)
|
||||
globalCtx = newCtx(module, cache, graph)
|
||||
registerAdditionalOps(globalCtx)
|
||||
else:
|
||||
refresh(globalCtx, module)
|
||||
@@ -1662,21 +1673,20 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
|
||||
#pushStackFrame(c, newStackFrame())
|
||||
|
||||
# XXX produce a new 'globals' environment here:
|
||||
setupGlobalCtx(module, cache, graph.config)
|
||||
setupGlobalCtx(module, cache, graph)
|
||||
result = globalCtx
|
||||
when hasFFI:
|
||||
globalCtx.features = {allowFFI, allowCast}
|
||||
|
||||
var oldErrorCount: int
|
||||
|
||||
proc myProcess(c: PPassContext, n: PNode): PNode =
|
||||
let c = PCtx(c)
|
||||
# don't eval errornous code:
|
||||
if oldErrorCount == msgs.gErrorCounter:
|
||||
evalStmt(PCtx(c), n)
|
||||
if c.oldErrorCount == c.config.errorCounter:
|
||||
evalStmt(c, n)
|
||||
result = emptyNode
|
||||
else:
|
||||
result = n
|
||||
oldErrorCount = msgs.gErrorCounter
|
||||
c.oldErrorCount = c.config.errorCounter
|
||||
|
||||
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
|
||||
myProcess(c, n)
|
||||
@@ -1684,10 +1694,10 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
|
||||
const evalPass* = makePass(myOpen, nil, myProcess, myClose)
|
||||
|
||||
proc evalConstExprAux(module: PSym; cache: IdentCache;
|
||||
config: ConfigRef; prc: PSym, n: PNode,
|
||||
g: ModuleGraph; prc: PSym, n: PNode,
|
||||
mode: TEvalMode): PNode =
|
||||
let n = transformExpr(module, n)
|
||||
setupGlobalCtx(module, cache, config)
|
||||
let n = transformExpr(g, module, n)
|
||||
setupGlobalCtx(module, cache, g)
|
||||
var c = globalCtx
|
||||
let oldMode = c.mode
|
||||
defer: c.mode = oldMode
|
||||
@@ -1702,17 +1712,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
if result.info.col < 0: result.info = n.info
|
||||
|
||||
proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode =
|
||||
result = evalConstExprAux(module, cache, config, nil, e, emConst)
|
||||
proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode =
|
||||
result = evalConstExprAux(module, cache, g, nil, e, emConst)
|
||||
|
||||
proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode =
|
||||
result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr)
|
||||
proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode =
|
||||
result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr)
|
||||
|
||||
proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) =
|
||||
discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt)
|
||||
proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) =
|
||||
discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt)
|
||||
|
||||
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) =
|
||||
discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt)
|
||||
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) =
|
||||
discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt)
|
||||
|
||||
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
|
||||
case typ.kind
|
||||
@@ -1740,20 +1750,20 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
|
||||
const evalMacroLimit = 1000
|
||||
var evalMacroCounter: int
|
||||
|
||||
proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
|
||||
proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
|
||||
n, nOrig: PNode, sym: PSym): PNode =
|
||||
# XXX globalError() is ugly here, but I don't know a better solution for now
|
||||
inc(evalMacroCounter)
|
||||
if evalMacroCounter > evalMacroLimit:
|
||||
globalError(n.info, errMacroInstantiationTooNested)
|
||||
globalError(g.config, n.info, "macro instantiation too nested")
|
||||
|
||||
# immediate macros can bypass any type and arity checking so we check the
|
||||
# arity here too:
|
||||
if sym.typ.len > n.safeLen and sym.typ.len > 1:
|
||||
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
|
||||
globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
|
||||
n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
|
||||
|
||||
setupGlobalCtx(module, cache, config)
|
||||
setupGlobalCtx(module, cache, g)
|
||||
var c = globalCtx
|
||||
c.comesFromHeuristic.line = 0'u16
|
||||
|
||||
@@ -1787,16 +1797,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
|
||||
else:
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
localError(n.info, "expected " & $gp.len &
|
||||
localError(c.config, n.info, "expected " & $gp.len &
|
||||
" generic parameter(s)")
|
||||
elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}:
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
globalError(n.info, "static[T] or typedesc nor supported for .immediate macros")
|
||||
globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros")
|
||||
# temporary storage:
|
||||
#for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||
result = rawExecute(c, start, tos).regToNode
|
||||
if result.info.line < 0: result.info = n.info
|
||||
if cyclicTree(result): globalError(n.info, errCyclicTree)
|
||||
if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
|
||||
dec(evalMacroCounter)
|
||||
c.callsite = nil
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
|
||||
|
||||
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
|
||||
|
||||
from options import gProjectPath
|
||||
|
||||
template mathop(op) {.dirty.} =
|
||||
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
|
||||
|
||||
@@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
|
||||
result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord),
|
||||
newStrNode(nkStrLit, f))
|
||||
|
||||
proc gorgeExWrapper(a: VmArgs) {.nimcall.} =
|
||||
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
|
||||
a.currentLineInfo)
|
||||
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
|
||||
|
||||
proc getProjectPathWrapper(a: VmArgs) {.nimcall.} =
|
||||
setResult a, gProjectPath
|
||||
|
||||
proc registerAdditionalOps*(c: PCtx) =
|
||||
proc gorgeExWrapper(a: VmArgs) =
|
||||
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
|
||||
a.currentLineInfo, c.config)
|
||||
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
|
||||
|
||||
proc getProjectPathWrapper(a: VmArgs) =
|
||||
setResult a, c.config.projectPath
|
||||
|
||||
wrap1f_math(sqrt)
|
||||
wrap1f_math(ln)
|
||||
wrap1f_math(log10)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
## * Computing an aliasing relation based on the assignments. This relation
|
||||
## is then used to compute the 'writes' and 'escapes' effects.
|
||||
|
||||
import intsets, idents, ast, astalgo, trees, renderer, msgs, types
|
||||
import intsets, idents, ast, astalgo, trees, renderer, msgs, types, options
|
||||
|
||||
const
|
||||
debug = false
|
||||
@@ -180,7 +180,7 @@ proc deps(w: var W; n: PNode) =
|
||||
let last = lastSon(child)
|
||||
if last.kind == nkEmpty: continue
|
||||
if child.kind == nkVarTuple and last.kind in {nkPar, nkTupleConstr}:
|
||||
internalAssert child.len-2 == last.len
|
||||
if child.len-2 != last.len: return
|
||||
for i in 0 .. child.len-3:
|
||||
deps(w, child.sons[i], last.sons[i], {})
|
||||
else:
|
||||
@@ -220,7 +220,7 @@ proc possibleAliases(w: var W; result: var seq[ptr TSym]) =
|
||||
# x = f(..., y, ....)
|
||||
for i in 0 ..< a.srcNoTc: addNoDup a.src[i]
|
||||
|
||||
proc markWriteOrEscape(w: var W) =
|
||||
proc markWriteOrEscape(w: var W; conf: ConfigRef) =
|
||||
## Both 'writes' and 'escapes' effects ultimately only care
|
||||
## about *parameters*.
|
||||
## However, due to aliasing, even locals that might not look as parameters
|
||||
@@ -249,7 +249,7 @@ proc markWriteOrEscape(w: var W) =
|
||||
if p.kind == skParam and p.owner == w.owner:
|
||||
incl(p.flags, sfWrittenTo)
|
||||
if w.owner.kind == skFunc and p.typ.kind != tyVar:
|
||||
localError(a.info, "write access to non-var parameter: " & p.name.s)
|
||||
localError(conf, a.info, "write access to non-var parameter: " & p.name.s)
|
||||
|
||||
if {rootIsResultOrParam, rootIsHeapAccess, markAsEscaping}*a.destInfo != {}:
|
||||
var destIsParam = false
|
||||
@@ -263,14 +263,14 @@ proc markWriteOrEscape(w: var W) =
|
||||
if p.kind == skParam and p.owner == w.owner:
|
||||
incl(p.flags, sfEscapes)
|
||||
|
||||
proc trackWrites*(owner: PSym; body: PNode) =
|
||||
proc trackWrites*(owner: PSym; body: PNode; conf: ConfigRef) =
|
||||
var w: W
|
||||
w.owner = owner
|
||||
w.assignments = @[]
|
||||
# Phase 1: Collect and preprocess any assignments in the proc body:
|
||||
deps(w, body)
|
||||
# Phase 2: Compute the 'writes' and 'escapes' effects:
|
||||
markWriteOrEscape(w)
|
||||
markWriteOrEscape(w, conf)
|
||||
if w.returnsNew != asgnOther and not isEmptyType(owner.typ.sons[0]) and
|
||||
containsGarbageCollectedRef(owner.typ.sons[0]):
|
||||
incl(owner.typ.flags, tfReturnsNew)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user