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 InitSymTab*(tab: var TSymTab)
proc DeinitSymTab*(tab: var TSymTab) proc DeinitSymTab*(tab: var TSymTab)
proc SymTabGet*(tab: TSymTab, s: PIdent): PSym proc SymTabGet*(tab: TSymTab, s: PIdent): PSym
proc SymTabGet*(tab: TSymTab, s: PIdent, filter: TSymKinds): PSym
proc SymTabLocalGet*(tab: TSymTab, s: PIdent): PSym proc SymTabLocalGet*(tab: TSymTab, s: PIdent): PSym
proc SymTabAdd*(tab: var TSymTab, e: PSym) proc SymTabAdd*(tab: var TSymTab, e: PSym)
proc SymTabAddAt*(tab: var TSymTab, e: PSym, at: Natural) proc SymTabAddAt*(tab: var TSymTab, e: PSym, at: Natural)
@ -703,6 +704,12 @@ proc SymTabGet(tab: TSymTab, s: PIdent): PSym =
if result != nil: return if result != nil: return
result = nil 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) = proc SymTabAddAt(tab: var TSymTab, e: PSym, at: Natural) =
StrTableAdd(tab.stack[at], e) StrTableAdd(tab.stack[at], e)

View file

@ -440,8 +440,11 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if key.kind == nkIdent: if key.kind == nkIdent:
var userPragma = StrTableGet(c.userPragmas, key.ident) var userPragma = StrTableGet(c.userPragmas, key.ident)
if userPragma != nil: if userPragma != nil:
inc c.InstCounter
if c.InstCounter > 100:
GlobalError(it.info, errRecursiveDependencyX, userPragma.name.s)
pragma(c, sym, userPragma.ast, validPragmas) pragma(c, sym, userPragma.ast, validPragmas)
# XXX BUG: possible infinite recursion! dec c.InstCounter
else: else:
var k = whichKeyword(key.ident) var k = whichKeyword(key.ident)
if k in validPragmas: if k in validPragmas:

View file

@ -139,6 +139,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
# generates an instantiated proc # generates an instantiated proc
if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep") if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
inc(c.InstCounter) 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 # NOTE: for access of private fields within generics from a different module
# we set the friend module: # we set the friend module:
var oldFriend = c.friendModule 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): # keep the owner if it's an inner proc (for proper closure transformations):
if fn.owner.kind == skModule: if fn.owner.kind == skModule:
result.owner = getCurrOwner().owner result.owner = getCurrOwner().owner
# careful! we copy the whole AST including the possibly nil body!
var n = copyTree(fn.ast)
result.ast = n result.ast = n
pushOwner(result) pushOwner(result)
openScope(c.tab) openScope(c.tab)

View file

@ -645,7 +645,41 @@ proc addResult(c: PContext, t: PType, info: TLineInfo, owner: TSymKind) =
proc addResultNode(c: PContext, n: PNode) = proc addResultNode(c: PContext, n: PNode) =
if c.p.resultSym != nil: addSon(n, newSymNode(c.p.resultSym)) 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 = proc semLambda(c: PContext, n: PNode): PNode =
result = semProcAnnotation(c, n)
if result != nil: return result
result = n result = n
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
var s = newSym(skProc, getIdent":anonymous", getCurrOwner()) 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, proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
validPragmas: TSpecialWords): PNode = validPragmas: TSpecialWords): PNode =
result = semProcAnnotation(c, n)
if result != nil: return result
result = n result = n
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
var s = semIdentDef(c, n.sons[0], kind) var s = semIdentDef(c, n.sons[0], kind)

View file

@ -1680,7 +1680,8 @@ code that has side effects:
static: static:
echo "echo at compile time" 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 The current implementation poses some restrictions for compile time
evaluation: Code which contains ``cast`` or makes use of the foreign function evaluation: Code which contains ``cast`` or makes use of the foreign function
@ -2960,6 +2961,26 @@ powerful programming construct that still suffices. So the "check list" is:
(4) Else: Use a macro. (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 Modules
------- -------
Nimrod supports splitting a program into pieces by a `module`:idx: concept. Nimrod supports splitting a program into pieces by a `module`:idx: concept.

View file

@ -11,6 +11,7 @@ New pragmas:
- ``borrow`` needs to take type classes into account - ``borrow`` needs to take type classes into account
- make templates hygienic by default: try to gensym() everything in the 'block' - make templates hygienic by default: try to gensym() everything in the 'block'
of a template; find a better solution for gensym instead of `*ident` 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 ``=`` - ``=`` should be overloadable; requires specialization for ``=``
- optimize genericAssign in the code generator - optimize genericAssign in the code generator
- fix remaining closure bugs: - fix remaining closure bugs:

View file

@ -118,6 +118,7 @@ Language Additions
- The precedence for operators starting with ``@`` is different now - The precedence for operators starting with ``@`` is different now
allowing for *sigil-like* operators. allowing for *sigil-like* operators.
- Stand-alone ``finally`` and ``except`` blocks are now supported. - 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 2012-02-09 Version 0.8.14 released