diff options
-rwxr-xr-x | compiler/astalgo.nim | 7 | ||||
-rwxr-xr-x | compiler/pragmas.nim | 11 | ||||
-rwxr-xr-x | compiler/seminst.nim | 4 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 36 | ||||
-rwxr-xr-x | doc/manual.txt | 23 | ||||
-rwxr-xr-x | todo.txt | 1 | ||||
-rwxr-xr-x | web/news.txt | 1 |
7 files changed, 76 insertions, 7 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index 41fbd3cf1..70cb8653e 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -91,6 +91,7 @@ type proc InitSymTab*(tab: var TSymTab) proc DeinitSymTab*(tab: var TSymTab) proc SymTabGet*(tab: TSymTab, s: PIdent): PSym +proc SymTabGet*(tab: TSymTab, s: PIdent, filter: TSymKinds): PSym proc SymTabLocalGet*(tab: TSymTab, s: PIdent): PSym proc SymTabAdd*(tab: var TSymTab, e: PSym) proc SymTabAddAt*(tab: var TSymTab, e: PSym, at: Natural) @@ -703,6 +704,12 @@ proc SymTabGet(tab: TSymTab, s: PIdent): PSym = if result != nil: return result = nil +proc SymTabGet*(tab: TSymTab, s: PIdent, filter: TSymKinds): PSym = + for i in countdown(tab.tos - 1, 0): + result = StrTableGet(tab.stack[i], s) + if result != nil and result.kind in filter: return + result = nil + proc SymTabAddAt(tab: var TSymTab, e: PSym, at: Natural) = StrTableAdd(tab.stack[at], e) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index d4a635058..348bf9bc6 100755 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -431,17 +431,20 @@ proc processPragma(c: PContext, n: PNode, i: int) = for j in i+1 .. sonsLen(n)-1: addSon(body, n.sons[j]) userPragma.ast = body StrTableAdd(c.userPragmas, userPragma) - -proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = - if n == nil: return + +proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = + if n == nil: return for i in countup(0, sonsLen(n) - 1): var it = n.sons[i] var key = if it.kind == nkExprColonExpr: it.sons[0] else: it if key.kind == nkIdent: var userPragma = StrTableGet(c.userPragmas, key.ident) if userPragma != nil: + inc c.InstCounter + if c.InstCounter > 100: + GlobalError(it.info, errRecursiveDependencyX, userPragma.name.s) pragma(c, sym, userPragma.ast, validPragmas) - # XXX BUG: possible infinite recursion! + dec c.InstCounter else: var k = whichKeyword(key.ident) if k in validPragmas: diff --git a/compiler/seminst.nim b/compiler/seminst.nim index f44b80223..a2f4129ea 100755 --- a/compiler/seminst.nim +++ b/compiler/seminst.nim @@ -139,6 +139,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # generates an instantiated proc if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep") inc(c.InstCounter) + # careful! we copy the whole AST including the possibly nil body! + var n = copyTree(fn.ast) # NOTE: for access of private fields within generics from a different module # we set the friend module: var oldFriend = c.friendModule @@ -148,8 +150,6 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable, # keep the owner if it's an inner proc (for proper closure transformations): if fn.owner.kind == skModule: result.owner = getCurrOwner().owner - # careful! we copy the whole AST including the possibly nil body! - var n = copyTree(fn.ast) result.ast = n pushOwner(result) openScope(c.tab) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index eb7660dd6..bc7f00c87 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -644,8 +644,42 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) = proc addResultNode(c: PContext, n: PNode) = if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym)) + +proc copyExcept(n: PNode, i: int): PNode = + result = copyNode(n) + for j in 0.. <n.len: + if j != i: result.add(n.sons[j]) + +proc lookupMacro(c: PContext, n: PNode): PSym = + if n.kind == nkSym: + result = n.sym + if result.kind notin {skMacro, skTemplate}: result = nil + else: + result = SymtabGet(c.Tab, considerAcc(n), {skMacro, skTemplate}) + +proc semProcAnnotation(c: PContext, prc: PNode): PNode = + var n = prc.sons[pragmasPos] + if n == nil or n.kind == nkEmpty: return + for i in countup(0, <n.len): + var it = n.sons[i] + var key = if it.kind == nkExprColonExpr: it.sons[0] else: it + let m = lookupMacro(c, key) + if m == nil: continue + # we transform ``proc p {.m, rest.}`` into ``m: proc p {.rest.}`` and + # let the semantic checker deal with it: + var x = newNodeI(nkMacroStmt, n.info) + x.add(newSymNode(m)) + prc.sons[pragmasPos] = copyExcept(n, i) + if it.kind == nkExprColonExpr: + # pass pragma argument to the macro too: + x.add(it.sons[1]) + x.add(prc) + # recursion assures that this works for multiple macro annotations too: + return semStmt(c, x) proc semLambda(c: PContext, n: PNode): PNode = + result = semProcAnnotation(c, n) + if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) var s = newSym(skProc, getIdent":anonymous", getCurrOwner()) @@ -686,6 +720,8 @@ proc instantiateDestructor*(c: PContext, typ: PType): bool proc semProcAux(c: PContext, n: PNode, kind: TSymKind, validPragmas: TSpecialWords): PNode = + result = semProcAnnotation(c, n) + if result != nil: return result result = n checkSonsLen(n, bodyPos + 1) var s = semIdentDef(c, n.sons[0], kind) diff --git a/doc/manual.txt b/doc/manual.txt index 1641f5338..8f9186ec6 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -1680,7 +1680,8 @@ code that has side effects: static: echo "echo at compile time" -It's a static error if the compiler cannot perform the evaluation at compile time. +It's a static error if the compiler cannot perform the evaluation at compile +time. The current implementation poses some restrictions for compile time evaluation: Code which contains ``cast`` or makes use of the foreign function @@ -2958,6 +2959,26 @@ powerful programming construct that still suffices. So the "check list" is: (2) Else: Use a generic proc/iterator, if possible. (3) Else: Use a template, if possible. (4) Else: Use a macro. + + +Macros as pragmas +~~~~~~~~~~~~~~~~~ + +Whole routines (procs, iterators etc.) can also be passed to a template or +a macro via the pragma notation: + +.. code-block:: nimrod + template m(s: stmt) = nil + + proc p() {.m.} = nil + +This is a simple syntactic transformation into: + +.. code-block:: nimrod + template m(s: stmt) = nil + + m: + proc p() = nil Modules diff --git a/todo.txt b/todo.txt index 9b9755664..c77b8680f 100755 --- a/todo.txt +++ b/todo.txt @@ -11,6 +11,7 @@ New pragmas: - ``borrow`` needs to take type classes into account - make templates hygienic by default: try to gensym() everything in the 'block' of a template; find a better solution for gensym instead of `*ident` +- make use of ``tyIter`` to fix the implicit items/pairs issue - ``=`` should be overloadable; requires specialization for ``=`` - optimize genericAssign in the code generator - fix remaining closure bugs: diff --git a/web/news.txt b/web/news.txt index c7dbc5971..8a53b6853 100755 --- a/web/news.txt +++ b/web/news.txt @@ -118,6 +118,7 @@ Language Additions - The precedence for operators starting with ``@`` is different now allowing for *sigil-like* operators. - Stand-alone ``finally`` and ``except`` blocks are now supported. +- Macros and templates can now be invoked as pragmas. 2012-02-09 Version 0.8.14 released |