compiler bootstraps with new VM
This commit is contained in:
parent
5659a1662e
commit
6a9baf3fd7
11 changed files with 141 additions and 64 deletions
|
|
@ -14,7 +14,7 @@ import
|
||||||
os, condsyms, rodread, rodwrite, times,
|
os, condsyms, rodread, rodwrite, times,
|
||||||
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||||
cgen, jsgen, json, nversion,
|
cgen, jsgen, json, nversion,
|
||||||
platform, nimconf, importer, passaux, depends, evals, types, idgen,
|
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
|
||||||
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
|
tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
|
||||||
pretty
|
pretty
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import
|
||||||
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
|
||||||
magicsys, parser, nversion, nimsets, semfold, importer,
|
magicsys, parser, nversion, nimsets, semfold, importer,
|
||||||
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
|
||||||
semthreads, intsets, transf, evals, idgen, aliases, cgmeth, lambdalifting,
|
semthreads, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
|
||||||
evaltempl, patterns, parampatterns, sempass2
|
evaltempl, patterns, parampatterns, sempass2
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
@ -149,7 +149,8 @@ proc symNodeFromType(c: PContext, t: PType, info: TLineInfo): PNode =
|
||||||
result = newSymNode(symFromType(t, info), info)
|
result = newSymNode(symFromType(t, info), info)
|
||||||
result.typ = makeTypeDesc(c, t)
|
result.typ = makeTypeDesc(c, t)
|
||||||
|
|
||||||
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
|
when false:
|
||||||
|
proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
|
||||||
result = newEvalContext(c.module, mode)
|
result = newEvalContext(c.module, mode)
|
||||||
result.getType = proc (n: PNode): PNode =
|
result.getType = proc (n: PNode): PNode =
|
||||||
var e = tryExpr(c, n)
|
var e = tryExpr(c, n)
|
||||||
|
|
@ -163,10 +164,10 @@ proc createEvalContext(c: PContext, mode: TEvalMode): PEvalContext =
|
||||||
result.handleIsOperator = proc (n: PNode): PNode =
|
result.handleIsOperator = proc (n: PNode): PNode =
|
||||||
result = IsOpImpl(c, n)
|
result = IsOpImpl(c, n)
|
||||||
|
|
||||||
proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode =
|
proc evalConstExpr(c: PContext, module: PSym, e: PNode): PNode =
|
||||||
result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
|
result = evalConstExprAux(c.createEvalContext(emConst), module, nil, e)
|
||||||
|
|
||||||
proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode =
|
proc evalStaticExpr(c: PContext, module: PSym, e: PNode, prc: PSym): PNode =
|
||||||
result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
|
result = evalConstExprAux(c.createEvalContext(emStatic), module, prc, e)
|
||||||
|
|
||||||
proc semConstExpr(c: PContext, n: PNode): PNode =
|
proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
|
|
@ -176,7 +177,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
|
||||||
return n
|
return n
|
||||||
result = getConstExpr(c.module, e)
|
result = getConstExpr(c.module, e)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
result = evalConstExpr(c, c.module, e)
|
result = evalConstExpr(c.module, e)
|
||||||
if result == nil or result.kind == nkEmpty:
|
if result == nil or result.kind == nkEmpty:
|
||||||
if e.info != n.info:
|
if e.info != n.info:
|
||||||
pushInfoContext(n.info)
|
pushInfoContext(n.info)
|
||||||
|
|
@ -222,10 +223,10 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
if sym == c.p.owner:
|
if sym == c.p.owner:
|
||||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
if c.evalContext == nil:
|
#if c.evalContext == nil:
|
||||||
c.evalContext = c.createEvalContext(emStatic)
|
# c.evalContext = c.createEvalContext(emStatic)
|
||||||
|
|
||||||
result = evalMacroCall(c.evalContext, n, nOrig, sym)
|
result = evalMacroCall(c.module, n, nOrig, sym)
|
||||||
if semCheck: result = semAfterMacroCall(c, result, sym)
|
if semCheck: result = semAfterMacroCall(c, result, sym)
|
||||||
|
|
||||||
proc forceBool(c: PContext, n: PNode): PNode =
|
proc forceBool(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import
|
||||||
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
|
||||||
wordrecg,
|
wordrecg,
|
||||||
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
|
||||||
magicsys, nversion, nimsets, parser, times, passes, rodread, evals
|
magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef
|
||||||
|
|
||||||
type
|
type
|
||||||
TOptionEntry* = object of lists.TListEntry # entries to put on a
|
TOptionEntry* = object of lists.TListEntry # entries to put on a
|
||||||
|
|
|
||||||
|
|
@ -631,18 +631,18 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
||||||
call.add(a)
|
call.add(a)
|
||||||
#echo "NOW evaluating at compile time: ", call.renderTree
|
#echo "NOW evaluating at compile time: ", call.renderTree
|
||||||
if sfCompileTime in callee.flags:
|
if sfCompileTime in callee.flags:
|
||||||
result = evalStaticExpr(c, c.module, call, c.p.owner)
|
result = evalStaticExpr(c.module, call, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(call))
|
||||||
else:
|
else:
|
||||||
result = evalConstExpr(c, c.module, call)
|
result = evalConstExpr(c.module, call)
|
||||||
if result.isNil: result = n
|
if result.isNil: result = n
|
||||||
#if result != n:
|
#if result != n:
|
||||||
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
# echo "SUCCESS evaluated at compile time: ", call.renderTree
|
||||||
|
|
||||||
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
proc semStaticExpr(c: PContext, n: PNode): PNode =
|
||||||
let a = semExpr(c, n.sons[0])
|
let a = semExpr(c, n.sons[0])
|
||||||
result = evalStaticExpr(c, c.module, a, c.p.owner)
|
result = evalStaticExpr(c.module, a, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,23 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode =
|
||||||
result.add(filename)
|
result.add(filename)
|
||||||
result.add(line)
|
result.add(line)
|
||||||
|
|
||||||
|
|
||||||
|
proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode =
|
||||||
|
InternalAssert operand.kind == nkSym
|
||||||
|
|
||||||
|
let typ = operand.sym.typ.skipTypes({tyTypeDesc})
|
||||||
|
case trait.sym.name.s.normalize
|
||||||
|
of "name":
|
||||||
|
result = newStrNode(nkStrLit, typ.typeToString(preferName))
|
||||||
|
result.typ = newType(tyString, context)
|
||||||
|
result.info = trait.info
|
||||||
|
of "arity":
|
||||||
|
result = newIntNode(nkIntLit, typ.n.len-1)
|
||||||
|
result.typ = newType(tyInt, context)
|
||||||
|
result.info = trait.info
|
||||||
|
else:
|
||||||
|
internalAssert false
|
||||||
|
|
||||||
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
proc semTypeTraits(c: PContext, n: PNode): PNode =
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
internalAssert n.sons[1].kind == nkSym
|
internalAssert n.sons[1].kind == nkSym
|
||||||
|
|
|
||||||
|
|
@ -1152,14 +1152,14 @@ proc setLine(n: PNode, info: TLineInfo) =
|
||||||
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
proc semPragmaBlock(c: PContext, n: PNode): PNode =
|
||||||
let pragmaList = n.sons[0]
|
let pragmaList = n.sons[0]
|
||||||
pragma(c, nil, pragmaList, exprPragmas)
|
pragma(c, nil, pragmaList, exprPragmas)
|
||||||
result = semStmt(c, n.sons[1])
|
result = semExpr(c, n.sons[1])
|
||||||
for i in 0 .. <pragmaList.len:
|
for i in 0 .. <pragmaList.len:
|
||||||
if whichPragma(pragmaList.sons[i]) == wLine:
|
if whichPragma(pragmaList.sons[i]) == wLine:
|
||||||
setLine(result, pragmaList.sons[i].info)
|
setLine(result, pragmaList.sons[i].info)
|
||||||
|
|
||||||
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
proc semStaticStmt(c: PContext, n: PNode): PNode =
|
||||||
let a = semStmt(c, n.sons[0])
|
let a = semStmt(c, n.sons[0])
|
||||||
result = evalStaticExpr(c, c.module, a, c.p.owner)
|
result = evalStaticExpr(c.module, a, c.p.owner)
|
||||||
if result.isNil:
|
if result.isNil:
|
||||||
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
LocalError(n.info, errCannotInterpretNodeX, renderTree(n))
|
||||||
result = emptyNode
|
result = emptyNode
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned,
|
||||||
parser, vmdeps, idents
|
parser, vmdeps, idents, trees, renderer
|
||||||
|
|
||||||
from semfold import leValueConv, ordinalValToString
|
from semfold import leValueConv, ordinalValToString
|
||||||
|
|
||||||
|
|
@ -231,13 +231,19 @@ proc compile(c: PCtx, s: PSym): int =
|
||||||
result = vmgen.genProc(c, s)
|
result = vmgen.genProc(c, s)
|
||||||
#c.echoCode
|
#c.echoCode
|
||||||
|
|
||||||
proc rawExecute(c: PCtx, start: int, tos: PStackFrame) =
|
proc regsContents(regs: TNodeSeq) =
|
||||||
|
for i in 0.. <regs.len:
|
||||||
|
echo "Register ", i
|
||||||
|
#debug regs[i]
|
||||||
|
|
||||||
|
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
|
||||||
var pc = start
|
var pc = start
|
||||||
var tos = tos
|
var tos = tos
|
||||||
var regs: TNodeSeq # alias to tos.slots for performance
|
var regs: TNodeSeq # alias to tos.slots for performance
|
||||||
move(regs, tos.slots)
|
move(regs, tos.slots)
|
||||||
|
#echo "NEW RUN ------------------------"
|
||||||
while true:
|
while true:
|
||||||
{.computedGoto.}
|
#{.computedGoto.}
|
||||||
let instr = c.code[pc]
|
let instr = c.code[pc]
|
||||||
let ra = instr.regA
|
let ra = instr.regA
|
||||||
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
|
#echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
|
||||||
|
|
@ -248,12 +254,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame) =
|
||||||
pc = tos.comesFrom
|
pc = tos.comesFrom
|
||||||
tos = tos.next
|
tos = tos.next
|
||||||
let retVal = regs[0]
|
let retVal = regs[0]
|
||||||
if tos.isNil: return retVal
|
if tos.isNil:
|
||||||
|
#echo "RET ", retVal.rendertree
|
||||||
|
return retVal
|
||||||
|
|
||||||
move(regs, tos.slots)
|
move(regs, tos.slots)
|
||||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||||
if c.code[pc].opcode == opcIndCallAsgn:
|
if c.code[pc].opcode == opcIndCallAsgn:
|
||||||
regs[c.code[pc].regA] = retVal
|
regs[c.code[pc].regA] = retVal
|
||||||
|
#echo "RET2 ", retVal.rendertree, " ", c.code[pc].regA
|
||||||
of opcYldYoid: assert false
|
of opcYldYoid: assert false
|
||||||
of opcYldVal: assert false
|
of opcYldVal: assert false
|
||||||
of opcAsgnInt:
|
of opcAsgnInt:
|
||||||
|
|
@ -508,7 +517,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame) =
|
||||||
of opcEcho:
|
of opcEcho:
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
for i in ra..ra+rb-1:
|
for i in ra..ra+rb-1:
|
||||||
if regs[i].kind != nkStrLit: debug regs[i]
|
#if regs[i].kind != nkStrLit: debug regs[i]
|
||||||
write(stdout, regs[i].strVal)
|
write(stdout, regs[i].strVal)
|
||||||
writeln(stdout, "")
|
writeln(stdout, "")
|
||||||
of opcContainsSet:
|
of opcContainsSet:
|
||||||
|
|
@ -535,6 +544,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame) =
|
||||||
let rc = instr.regC
|
let rc = instr.regC
|
||||||
let prc = regs[rb].sym
|
let prc = regs[rb].sym
|
||||||
let newPc = compile(c, prc)
|
let newPc = compile(c, prc)
|
||||||
|
#echo "new pc ", newPc, " calling: ", prc.name.s
|
||||||
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
|
||||||
newSeq(newFrame.slots, prc.position)
|
newSeq(newFrame.slots, prc.position)
|
||||||
if not isEmptyType(prc.typ.sons[0]):
|
if not isEmptyType(prc.typ.sons[0]):
|
||||||
|
|
@ -841,10 +851,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame) =
|
||||||
regs[ra].strVal = typ.typeToString(preferExported)
|
regs[ra].strVal = typ.typeToString(preferExported)
|
||||||
inc pc
|
inc pc
|
||||||
|
|
||||||
proc execute(c: PCtx, start: int) =
|
proc execute(c: PCtx, start: int): PNode =
|
||||||
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
rawExecute(c, start, tos)
|
for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
|
result = rawExecute(c, start, tos)
|
||||||
|
|
||||||
proc evalStmt*(c: PCtx, n: PNode) =
|
proc evalStmt*(c: PCtx, n: PNode) =
|
||||||
let start = genStmt(c, n)
|
let start = genStmt(c, n)
|
||||||
|
|
@ -858,11 +869,24 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
|
||||||
assert c.code[start].opcode != opcEof
|
assert c.code[start].opcode != opcEof
|
||||||
result = execute(c, start)
|
result = execute(c, start)
|
||||||
|
|
||||||
|
# for now we share the 'globals' environment. XXX Coming soon: An API for
|
||||||
|
# storing&loading the 'globals' environment to get what a component system
|
||||||
|
# requires.
|
||||||
|
var
|
||||||
|
globalCtx: PCtx
|
||||||
|
|
||||||
|
proc setupGlobalCtx(module: PSym) =
|
||||||
|
if globalCtx.isNil: globalCtx = newCtx(module)
|
||||||
|
else: refresh(globalCtx, module)
|
||||||
|
|
||||||
proc myOpen(module: PSym): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
#var c = newEvalContext(module, emRepl)
|
#var c = newEvalContext(module, emRepl)
|
||||||
#c.features = {allowCast, allowFFI, allowInfiniteLoops}
|
#c.features = {allowCast, allowFFI, allowInfiniteLoops}
|
||||||
#pushStackFrame(c, newStackFrame())
|
#pushStackFrame(c, newStackFrame())
|
||||||
result = newCtx(module)
|
|
||||||
|
# XXX produce a new 'globals' environment here:
|
||||||
|
setupGlobalCtx(module)
|
||||||
|
result = globalCtx
|
||||||
|
|
||||||
var oldErrorCount: int
|
var oldErrorCount: int
|
||||||
|
|
||||||
|
|
@ -875,17 +899,17 @@ proc myProcess(c: PPassContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
oldErrorCount = msgs.gErrorCounter
|
oldErrorCount = msgs.gErrorCounter
|
||||||
|
|
||||||
const vmPass* = makePass(myOpen, nil, myProcess, myProcess)
|
const evalPass* = makePass(myOpen, nil, myProcess, myProcess)
|
||||||
|
|
||||||
proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
|
proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
|
||||||
var p = newCtx(module)
|
setupGlobalCtx(module)
|
||||||
var s = newStackFrame()
|
var c = globalCtx
|
||||||
s.call = e
|
let start = genExpr(c, n)
|
||||||
s.prc = prc
|
assert c.code[start].opcode != opcEof
|
||||||
pushStackFrame(p, s)
|
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
|
||||||
result = tryEval(p, e)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
if result != nil and result.kind == nkExceptBranch: result = nil
|
for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
popStackFrame(p)
|
result = rawExecute(c, start, tos)
|
||||||
|
|
||||||
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
proc evalConstExpr*(module: PSym, e: PNode): PNode =
|
||||||
result = evalConstExprAux(module, nil, e, emConst)
|
result = evalConstExprAux(module, nil, e, emConst)
|
||||||
|
|
@ -897,15 +921,18 @@ proc setupMacroParam(x: PNode): PNode =
|
||||||
result = x
|
result = x
|
||||||
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
|
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
|
||||||
|
|
||||||
proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
var evalMacroCounter: int
|
||||||
|
|
||||||
|
proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
# XXX GlobalError() is ugly here, but I don't know a better solution for now
|
# XXX GlobalError() is ugly here, but I don't know a better solution for now
|
||||||
inc(evalTemplateCounter)
|
inc(evalMacroCounter)
|
||||||
if evalTemplateCounter > 100:
|
if evalMacroCounter > 100:
|
||||||
GlobalError(n.info, errTemplateInstantiationTooNested)
|
GlobalError(n.info, errTemplateInstantiationTooNested)
|
||||||
|
setupGlobalCtx(module)
|
||||||
|
var c = globalCtx
|
||||||
|
|
||||||
c.callsite = nOrig
|
c.callsite = nOrig
|
||||||
let body = optBody(c, sym)
|
let start = genProc(c, sym)
|
||||||
let start = genStmt(c, body)
|
|
||||||
|
|
||||||
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
|
var tos = PStackFrame(prc: sym, comesFrom: 0, next: nil)
|
||||||
newSeq(tos.slots, c.prc.maxSlots)
|
newSeq(tos.slots, c.prc.maxSlots)
|
||||||
|
|
@ -917,8 +944,9 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
tos.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
tos.slots[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
|
||||||
# setup parameters:
|
# setup parameters:
|
||||||
for i in 1 .. < L: tos.slots[i] = setupMacroParam(n.sons[i])
|
for i in 1 .. < L: tos.slots[i] = setupMacroParam(n.sons[i])
|
||||||
rawExecute(c, start, tos)
|
# temporary storage:
|
||||||
result = tos.slots[0]
|
for i in L .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
|
||||||
|
result = rawExecute(c, start, tos)
|
||||||
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
|
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
|
||||||
dec(evalTemplateCounter)
|
dec(evalMacroCounter)
|
||||||
c.callsite = nil
|
c.callsite = nil
|
||||||
|
|
|
||||||
|
|
@ -165,12 +165,30 @@ type
|
||||||
|
|
||||||
PEvalContext* = PCtx
|
PEvalContext* = PCtx
|
||||||
|
|
||||||
|
TEvalMode* = enum ## reason for evaluation
|
||||||
|
emRepl, ## evaluate because in REPL mode
|
||||||
|
emConst, ## evaluate for 'const' according to spec
|
||||||
|
emOptimize, ## evaluate for optimization purposes (same as
|
||||||
|
## emConst?)
|
||||||
|
emStatic ## evaluate for enforced compile time eval
|
||||||
|
## ('static' context)
|
||||||
|
|
||||||
|
TSandboxFlag* = enum ## what the evaluation engine should allow
|
||||||
|
allowCast, ## allow unsafe language feature: 'cast'
|
||||||
|
allowFFI, ## allow the FFI
|
||||||
|
allowInfiniteLoops ## allow endless loops
|
||||||
|
TSandboxFlags* = set[TSandboxFlag]
|
||||||
|
|
||||||
|
|
||||||
proc newCtx*(module: PSym): PCtx =
|
proc newCtx*(module: PSym): PCtx =
|
||||||
PCtx(code: @[], debug: @[],
|
PCtx(code: @[], debug: @[],
|
||||||
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
||||||
prc: PProc(blocks: @[]), module: module)
|
prc: PProc(blocks: @[]), module: module)
|
||||||
|
|
||||||
|
proc refresh*(c: PCtx, module: PSym) =
|
||||||
|
c.module = module
|
||||||
|
c.prc = PProc(blocks: @[])
|
||||||
|
|
||||||
const
|
const
|
||||||
firstABxInstr* = opcTJmp
|
firstABxInstr* = opcTJmp
|
||||||
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ proc codeListing(c: PCtx, result: var string) =
|
||||||
result.add("\n")
|
result.add("\n")
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
proc echoCode*(c: PCtx) =
|
proc echoCode*(c: PCtx) {.deprecated.} =
|
||||||
var buf = ""
|
var buf = ""
|
||||||
codeListing(c, buf)
|
codeListing(c, buf)
|
||||||
echo buf
|
echo buf
|
||||||
|
|
@ -494,7 +494,9 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
genBinaryABC(c, n, dest, opc)
|
genBinaryABC(c, n, dest, opc)
|
||||||
|
|
||||||
proc unused(n: PNode; x: TDest) {.inline.} =
|
proc unused(n: PNode; x: TDest) {.inline.} =
|
||||||
if x >= 0: InternalError(n.info, "not unused")
|
if x >= 0:
|
||||||
|
#debug(n)
|
||||||
|
InternalError(n.info, "not unused")
|
||||||
|
|
||||||
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||||
let tmp = c.genx(arg)
|
let tmp = c.genx(arg)
|
||||||
|
|
@ -508,7 +510,7 @@ proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let tmp = c.genx(n.sons[1])
|
let tmp = c.genx(n.sons[1])
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.genSetType(n.sons[1], tmp)
|
c.genSetType(n.sons[1], tmp)
|
||||||
c.gABC(n, opc, dest, tmp)
|
c.gABC(n, opcCard, dest, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
@ -701,7 +703,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
of mTypeTrait:
|
of mTypeTrait:
|
||||||
let tmp = c.genx(n.sons[1])
|
let tmp = c.genx(n.sons[1])
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
c.gABx(n, opcSetType, tmp, c.genType(n.sons[1]))
|
c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ))
|
||||||
c.gABC(n, opcTypeTrait, dest, tmp)
|
c.gABC(n, opcTypeTrait, dest, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of mIs:
|
of mIs:
|
||||||
|
|
@ -1259,7 +1261,14 @@ proc optimizeJumps(c: PCtx; start: int) =
|
||||||
proc genProc(c: PCtx; s: PSym): int =
|
proc genProc(c: PCtx; s: PSym): int =
|
||||||
let x = s.ast.sons[optimizedCodePos]
|
let x = s.ast.sons[optimizedCodePos]
|
||||||
if x.kind == nkEmpty:
|
if x.kind == nkEmpty:
|
||||||
c.removeLastEof
|
#echo "GENERATING CODE FOR ", s.name.s
|
||||||
|
let last = c.code.len-1
|
||||||
|
var eofInstr: TInstr
|
||||||
|
if last >= 0 and c.code[last].opcode == opcEof:
|
||||||
|
eofInstr = c.code[last]
|
||||||
|
c.code.setLen(last)
|
||||||
|
c.debug.setLen(last)
|
||||||
|
#c.removeLastEof
|
||||||
result = c.code.len+1 # skip the jump instruction
|
result = c.code.len+1 # skip the jump instruction
|
||||||
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
||||||
# thanks to the jmp we can add top level statements easily and also nest
|
# thanks to the jmp we can add top level statements easily and also nest
|
||||||
|
|
@ -1275,9 +1284,9 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
# generate final 'return' statement:
|
# generate final 'return' statement:
|
||||||
c.gABC(body, opcRet)
|
c.gABC(body, opcRet)
|
||||||
c.patch(procStart)
|
c.patch(procStart)
|
||||||
c.gABC(body, opcEof)
|
|
||||||
|
c.gABC(body, opcEof, eofInstr.regA)
|
||||||
s.position = c.prc.maxSlots
|
s.position = c.prc.maxSlots
|
||||||
c.prc = oldPrc
|
c.prc = oldPrc
|
||||||
#c.echoCode
|
|
||||||
else:
|
else:
|
||||||
result = x.intVal.int
|
result = x.intVal.int
|
||||||
|
|
|
||||||
5
todo.txt
5
todo.txt
|
|
@ -2,8 +2,9 @@ version 0.9.4
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- new VM:
|
- new VM:
|
||||||
- implement the glue to replace evals.nim
|
- new VM requires lambda lifting
|
||||||
- implement missing magics
|
- codegen for computed goto still wrong
|
||||||
|
- test and activate the jump optimizer
|
||||||
- implement overflow checking
|
- implement overflow checking
|
||||||
- implement the FFI
|
- implement the FFI
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ Compiler Additions
|
||||||
over the generated code.
|
over the generated code.
|
||||||
- The compiler now supports a ``computedGoto`` pragma to support very fast
|
- The compiler now supports a ``computedGoto`` pragma to support very fast
|
||||||
dispatching for interpreters and the like.
|
dispatching for interpreters and the like.
|
||||||
|
- The old evaluation engine has been replaced by a proper register based
|
||||||
|
virtual machine. This fixes numerous bugs for ``nimrod i`` and for macro
|
||||||
|
evaluation.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
@ -55,7 +58,7 @@ Language Additions
|
||||||
OOP-like syntactic sugar.
|
OOP-like syntactic sugar.
|
||||||
- Added ``delegator pragma`` for handling calls to missing procs and fields at
|
- Added ``delegator pragma`` for handling calls to missing procs and fields at
|
||||||
compile-time.
|
compile-time.
|
||||||
- Support for user-defined type classes have been added.
|
- Support for user-defined type classes has been added.
|
||||||
|
|
||||||
|
|
||||||
Tools improvements
|
Tools improvements
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue