diff options
author | Araq <rumpf_a@web.de> | 2012-06-26 01:00:32 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-06-26 01:00:32 +0200 |
commit | b5d34242ca7156ec702f8e63a01c9cd059d28e5f (patch) | |
tree | 4c44e50159d95b15f3ac82ddead4212384526fd3 /compiler | |
parent | 5a838d3e06222f44b4c9876774ea2bd304afcc49 (diff) | |
download | Nim-b5d34242ca7156ec702f8e63a01c9cd059d28e5f.tar.gz |
added proc annotations: macros invoked as pragmas
Diffstat (limited to 'compiler')
-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 |
4 files changed, 52 insertions, 6 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) |