transf and vmgen compile again
This commit is contained in:
parent
1310279691
commit
fedc136985
9 changed files with 234 additions and 223 deletions
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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``.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue