added proc annotations: macros invoked as pragmas

This commit is contained in:
Araq 2012-06-26 01:00:32 +02:00
commit b5d34242ca
7 changed files with 76 additions and 7 deletions

View file

@ -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)

View file

@ -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:

View file

@ -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)

View file

@ -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)