added proc annotations: macros invoked as pragmas
This commit is contained in:
parent
5a838d3e06
commit
b5d34242ca
7 changed files with 76 additions and 7 deletions
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue