mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-26 12:55:06 +00:00
eval context for macros lives as long as the current module is compiled
This commit is contained in:
@@ -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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
19
tests/accept/run/tidgen.nim
Normal file
19
tests/accept/run/tidgen.nim
Normal file
@@ -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()
|
||||
|
||||
12
todo.txt
12
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
|
||||
|
||||
Reference in New Issue
Block a user