diff --git a/compiler/evals.nim b/compiler/evals.nim index 876f800d9e..a332490d19 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -32,6 +32,7 @@ type tos*: PStackFrame # top of stack lastException*: PNode optEval*: bool # evaluation done for optimization purposes + globals*: TIdNodeTable # state of global vars PEvalContext* = ref TEvalContext @@ -56,13 +57,14 @@ proc newEvalContext*(module: PSym, filename: string, new(result) result.module = module result.optEval = optEval + initIdNodeTable(result.globals) proc pushStackFrame*(c: PEvalContext, t: PStackFrame) {.inline.} = t.next = c.tos c.tos = t proc popStackFrame*(c: PEvalContext) {.inline.} = - if (c.tos == nil): InternalError("popStackFrame") + if c.tos == nil: InternalError("popStackFrame") c.tos = c.tos.next proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode @@ -306,6 +308,20 @@ proc evalVariable(c: PStackFrame, sym: PSym, flags: TEvalFlags): PNode = x = x.next result = emptyNode +proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode = + result = IdNodeTableGet(c.globals, s) + if result != nil: + if not aliasNeeded(result, flags): + result = copyTree(result) + else: + result = s.ast + if result == nil or result.kind == nkEmpty: + result = getNullValue(s.typ, s.info) + else: + result = evalAux(c, result, {}) + if isSpecial(result): return + IdNodeTablePut(c.globals, s, result) + proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = result = evalAux(c, n.sons[0], flags) if isSpecial(result): return @@ -430,19 +446,23 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode = result = emptyNode proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = - case n.sym.kind - of skProc, skConverter, skMacro: result = n.sym.ast.sons[codePos] - of skVar, skForVar, skTemp, skResult: - result = evalVariable(c.tos, n.sym, flags) + var s = n.sym + case s.kind + of skProc, skConverter, skMacro: result = s.ast.sons[codePos] + of skVar, skForVar, skTemp, skResult: + if sfGlobal notin s.flags: + result = evalVariable(c.tos, s, flags) + else: + result = evalGlobalVar(c, s, flags) of skParam: # XXX what about LValue? - result = c.tos.params[n.sym.position + 1] - of skConst: result = n.sym.ast - of skEnumField: result = newIntNodeT(n.sym.position, n) + result = c.tos.params[s.position + 1] + of skConst: result = s.ast + of skEnumField: result = newIntNodeT(s.position, n) else: - stackTrace(c, n, errCannotInterpretNodeX, $n.sym.kind) + stackTrace(c, n, errCannotInterpretNodeX, $s.kind) result = emptyNode - if result == nil: stackTrace(c, n, errCannotInterpretNodeX, n.sym.name.s) + if result == nil: stackTrace(c, n, errCannotInterpretNodeX, s.name.s) proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode = result = evalAux(c, n.sons[1], {efLValue}) @@ -532,11 +552,12 @@ proc evalAddr(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = proc evalConv(c: PEvalContext, n: PNode): PNode = result = evalAux(c, n.sons[1], {efLValue}) if isSpecial(result): return - var a = result - result = foldConv(n, a) - if result == nil: - # foldConv() cannot deal with everything that we want to do here: - result = a + if result.typ != nil: + var a = result + result = foldConv(n, a) + if result == nil: + # foldConv() cannot deal with everything that we want to do here: + result = a proc evalCheckedFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = diff --git a/compiler/sem.nim b/compiler/sem.nim index e530d6140f..5090187d52 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -107,8 +107,9 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode = proc semMacroExpr(c: PContext, n: PNode, sym: PSym, semCheck: bool = true): PNode = markUsed(n, sym) - var p = newEvalContext(c.module, "", false) - result = evalMacroCall(p, n, sym) + if c.evalContext == nil: + c.evalContext = newEvalContext(c.module, "", false) + result = evalMacroCall(c.evalContext, n, sym) if semCheck: result = semAfterMacroCall(c, result, sym) proc forceBool(c: PContext, n: PNode): PNode = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 65ff119636..1169ec8436 100755 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -13,7 +13,7 @@ import strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, wordrecg, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, - magicsys, nversion, nimsets, parser, times, passes, rodread + magicsys, nversion, nimsets, parser, times, passes, rodread, evals type TOptionEntry* = object of lists.TListEntry # entries to put on a @@ -69,6 +69,7 @@ type includedFiles*: TIntSet # used to detect recursive include files filename*: string # the module's filename userPragmas*: TStrTable + evalContext*: PEvalContext var gGenericsCache: PGenericsCache # save for modularity diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index c5ac1f1531..d6ccad5a4f 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -257,6 +257,9 @@ proc semVar(c: PContext, n: PNode): PNode = for j in countup(0, length-3): var v = semIdentDef(c, a.sons[j], skVar) addInterfaceDecl(c, v) + if def != nil and def.kind != nkEmpty: + # this is only needed for the evaluation pass: + v.ast = def if a.kind != nkVarTuple: v.typ = typ b = newNodeI(nkIdentDefs, a.info) diff --git a/tests/accept/run/tidgen.nim b/tests/accept/run/tidgen.nim new file mode 100644 index 0000000000..68fffbabb5 --- /dev/null +++ b/tests/accept/run/tidgen.nim @@ -0,0 +1,19 @@ +discard """ + output: "3 4" +""" + +import macros + +# Test compile-time state in same module + +var gid = 3 + +macro genId(invokation: expr): expr = + result = newIntLitNode(gid) + inc gid + +proc Id1(): int = return genId() +proc Id2(): int = return genId() + +echo Id1(), " ", Id2() + diff --git a/todo.txt b/todo.txt index 9a220d6d52..6455ca8a40 100755 --- a/todo.txt +++ b/todo.txt @@ -6,17 +6,15 @@ Version 0.8.14 - fix actors.nim - make threadvar efficient again on linux after testing - document & test splicing; don't forget to test negative indexes -- implement lib/pure/memfiles properly -- eval context is per module; this way modularity is kept; global id generation - macro can still be done once macros support basic IO (store current id in - some file) - +- dead code elim for JS backend + incremental compilation ----------------------- -- the loading has to be MUCH more lazy! --> next version: We should re-load - symbol.ast lazily +- the loading has to be MUCH lazier! --> next version: We should re-load + symbol.ast.sons[codePos] lazily +- implement lib/pure/memfiles properly version 0.9.0