transf and vmgen compile again

This commit is contained in:
Andreas Rumpf 2018-05-12 09:38:41 +02:00
commit fedc136985
9 changed files with 234 additions and 223 deletions

View file

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

View file

@ -23,7 +23,7 @@
## "A Graph–Free Approach to Data–Flow Analysis" by Markus Mohnen. ## "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 ## 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 type
InstrKind* = enum InstrKind* = enum
@ -160,7 +160,7 @@ proc genBreak(c: var Con; n: PNode) =
if c.blocks[i].label == n.sons[0].sym: if c.blocks[i].label == n.sons[0].sym:
c.blocks[i].fixups.add L1 c.blocks[i].fixups.add L1
return return
globalError(n.info, errGenerated, "VM problem: cannot find 'break' target") #globalError(n.info, "VM problem: cannot find 'break' target")
else: else:
c.blocks[c.blocks.high].fixups.add L1 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) of nkVarSection, nkLetSection: genVarSection(c, n)
else: discard else: discard
proc dfa(code: seq[Instr]) = proc dfa(code: seq[Instr]; conf: ConfigRef) =
var u = newSeq[IntSet](code.len) # usages var u = newSeq[IntSet](code.len) # usages
var d = newSeq[IntSet](code.len) # defs var d = newSeq[IntSet](code.len) # defs
var c = newSeq[IntSet](code.len) # consumed var c = newSeq[IntSet](code.len) # consumed
@ -426,17 +426,17 @@ proc dfa(code: seq[Instr]) =
of use, useWithinCall: of use, useWithinCall:
let s = code[i].sym let s = code[i].sym
if s.id notin d[i]: 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]: 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 else: discard
proc dataflowAnalysis*(s: PSym; body: PNode) = proc dataflowAnalysis*(s: PSym; body: PNode; conf: ConfigRef) =
var c = Con(code: @[], blocks: @[]) var c = Con(code: @[], blocks: @[])
gen(c, body) gen(c, body)
when defined(useDfa) and defined(debugDfa): echoCfg(c.code) when defined(useDfa) and defined(debugDfa): echoCfg(c.code)
dfa(c.code) dfa(c.code, conf)
proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph = proc constructCfg*(s: PSym; body: PNode): ControlFlowGraph =
## constructs a control flow graph for ``body``. ## constructs a control flow graph for ``body``.

View file

@ -21,11 +21,11 @@ proc readOutput(p: Process): (string, int) =
result[0].setLen(result[0].len - "\n".len) result[0].setLen(result[0].len - "\n".len)
result[1] = p.waitForExit 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) let workingDir = parentDir(info.toFullPath)
if cache.len > 0:# and optForceFullMake notin gGlobalOptions: if cache.len > 0:# and optForceFullMake notin gGlobalOptions:
let h = secureHash(cmd & "\t" & input & "\t" & cache) 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 var f: File
if open(f, filename): if open(f, filename):
result = (f.readAll, 0) result = (f.readAll, 0)

View file

@ -52,17 +52,17 @@ proc lookupParam(params, dest: PNode): PSym =
if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id: if params[i].kind == nkSym and params[i].sym.name.id == dest.ident.id:
return params[i].sym 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) let liftDest = getPragmaVal(prc.ast, wLiftLocals)
if liftDest == nil: return n if liftDest == nil: return n
let partialParam = lookupParam(prc.typ.n, liftDest) let partialParam = lookupParam(prc.typ.n, liftDest)
if partialParam.isNil: 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]) [$liftDest, prc.name.s])
return n return n
let objType = partialParam.typ.skipTypes(abstractPtrs) let objType = partialParam.typ.skipTypes(abstractPtrs)
if objType.kind != tyObject or tfPartial notin objType.flags: 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 return n
var c = Ctx(partialParam: partialParam, objType: objType) var c = Ctx(partialParam: partialParam, objType: objType)
let w = newTree(nkStmtList, n) let w = newTree(nkStmtList, n)

View file

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

View file

@ -10,7 +10,7 @@
## This module contains the type definitions for the new evaluation engine. ## 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. ## 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 const
byteExcess* = 128 # we use excess-K for immediates byteExcess* = 128 # we use excess-K for immediates
@ -207,18 +207,18 @@ type
errorFlag*: string errorFlag*: string
cache*: IdentCache cache*: IdentCache
config*: ConfigRef config*: ConfigRef
graph*: ModuleGraph
TPosition* = distinct int TPosition* = distinct int
PEvalContext* = PCtx PEvalContext* = PCtx
proc newCtx*(module: PSym; cache: IdentCache; config: ConfigRef = nil): PCtx = proc newCtx*(module: PSym; cache: IdentCache; g: ModuleGraph): PCtx =
let conf = if config != nil: config else: newConfigRef()
PCtx(code: @[], debug: @[], PCtx(code: @[], debug: @[],
globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[], globals: newNode(nkStmtListExpr), constants: newNode(nkStmtList), types: @[],
prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations, prc: PProc(blocks: @[]), module: module, loopIterations: MaxLoopIterations,
comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "", comesFromHeuristic: unknownLineInfo(), callbacks: @[], errorFlag: "",
cache: cache, config: conf) cache: cache, config: g.config, graph: g)
proc refresh*(c: PCtx, module: PSym) = proc refresh*(c: PCtx, module: PSym) =
c.module = module c.module = module

View file

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

View file

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

View file

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