parameter passing works the same for macros and templates; use callsite magic to access the invokation AST

This commit is contained in:
Araq
2012-08-28 22:15:29 +02:00
parent 6bcdb9c8f4
commit b4844a189d
16 changed files with 270 additions and 180 deletions

View File

@@ -441,7 +441,7 @@ type
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym,
mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo

View File

@@ -38,6 +38,7 @@ type
module*: PSym
tos*: PStackFrame # top of stack
lastException*: PNode
callsite: PNode # for 'callsite' magic
mode*: TEvalMode
globals*: TIdNodeTable # state of global vars
@@ -74,7 +75,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} =
if c.tos != nil: c.tos = c.tos.next
else: InternalError("popStackFrame")
proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode
proc evalMacroCall*(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): PNode =
@@ -106,8 +107,11 @@ proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg = "") =
proc isSpecial(n: PNode): bool {.inline.} =
result = n.kind == nkExceptBranch
proc myreset(n: PNode) {.inline.} =
when defined(system.reset): reset(n[])
proc myreset(n: PNode) =
when defined(system.reset):
var oldInfo = n.info
reset(n[])
n.info = oldInfo
proc evalIf(c: PEvalContext, n: PNode): PNode =
var i = 0
@@ -245,6 +249,11 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyObject:
result = newNodeIT(nkPar, info, t)
getNullValueAux(t.n, result)
# initialize inherited fields:
var base = t.sons[0]
while base != nil:
getNullValueAux(skipTypes(base, skipPtrs).n, result)
base = base.sons[0]
of tyArray, tyArrayConstr:
result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1):
@@ -925,7 +934,7 @@ proc evalExpandToAst(c: PEvalContext, original: PNode): PNode =
# we want to replace it with nkIdent node featuring
# the original unmangled macro name.
macroCall.sons[0] = newIdentNode(expandedSym.name, expandedSym.info)
result = evalMacroCall(c, macroCall, expandedSym)
result = evalMacroCall(c, macroCall, original, expandedSym)
else:
InternalError(macroCall.info,
"ExpandToAst: expanded symbol is no macro or template")
@@ -1166,10 +1175,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mIdentToStr:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIdent: InternalError(n.info, "no ident node")
var a = result
result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = a.ident.s
if a.kind == nkSym:
result.strVal = a.sym.name.s
else:
if a.kind != nkIdent: InternalError(n.info, "no ident node")
result.strVal = a.ident.s
of mEqIdent:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1226,6 +1238,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result
result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = newString(0)
of mNCallSite:
if c.callsite != nil: result = c.callsite
else: stackTrace(c, n, errFieldXNotFound, "callsite")
else:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1355,24 +1370,31 @@ proc evalConstExpr*(module: PSym, e: PNode): PNode =
proc evalStaticExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, e, emStatic)
proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
proc setupMacroParam(x: PNode): PNode =
result = x
if result.kind == nkHiddenStdConv: result = result.sons[1]
proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
# XXX GlobalError() is ugly here, but I don't know a better solution for now
inc(evalTemplateCounter)
if evalTemplateCounter > 100:
if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested)
#inc genSymBaseId
c.callsite = nOrig
var s = newStackFrame()
s.call = n
setlen(s.params, 2)
setlen(s.params, n.len)
# return value:
s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
s.params[1] = n
# setup parameters:
for i in 1 .. < n.len: s.params[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, sym.getBody)
result = s.params[0]
popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalTemplateCounter)
c.callsite = nil
proc myOpen(module: PSym, filename: string): PPassContext =
var c = newEvalContext(module, filename, emRepl)

View File

@@ -774,7 +774,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
else:
gsub(g, n.sons[1])
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[0])
of nkHiddenStdConv, nkHiddenSubConv, nkHiddenCallConv: gsub(g, n.sons[1])
of nkCast:
put(g, tkCast, "cast")
put(g, tkBracketLe, "[")

View File

@@ -81,7 +81,7 @@ proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semTemplateExpr(c: PContext, n: PNode, s: PSym, semCheck = true): PNode
proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode
proc semWhen(c: PContext, n: PNode, semCheck: bool = true): PNode
@@ -127,14 +127,14 @@ proc semAfterMacroCall(c: PContext, n: PNode, s: PSym): PNode =
#GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter)
proc semMacroExpr(c: PContext, n: PNode, sym: PSym,
proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode =
markUsed(n, sym)
if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic)
result = evalMacroCall(c.evalContext, n, sym)
result = evalMacroCall(c.evalContext, n, nOrig, sym)
if semCheck: result = semAfterMacroCall(c, result, sym)
proc forceBool(c: PContext, n: PNode): PNode =

View File

@@ -98,7 +98,7 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
else: result = newSymNode(s, n.info)
else:
result = newSymNode(s, n.info)
of skMacro: result = semMacroExpr(c, n, s)
of skMacro: result = semMacroExpr(c, n, n, s)
of skTemplate: result = semTemplateExpr(c, n, s)
of skVar, skLet, skResult, skParam, skForVar:
markUsed(n, s)
@@ -705,7 +705,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return errorNode(c, n)
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, nOrig, callee)
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else:
fixAbstractType(c, result)
@@ -1398,7 +1398,8 @@ proc semBlockExpr(c: PContext, n: PNode): PNode =
closeScope(c.tab)
Dec(c.p.nestedBlockCounter)
proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
# XXX why no overloading here?
checkMinSonsLen(n, 2)
var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0]
@@ -1407,7 +1408,7 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
if s != nil:
case s.kind
of skMacro:
result = semMacroExpr(c, n, s, semCheck)
result = semMacroExpr(c, n, n, s, semCheck)
of skTemplate:
# transform
# nkMacroStmt(nkCall(a...), stmt, b...)
@@ -1499,16 +1500,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if s != nil:
case s.kind
of skMacro:
if false and sfImmediate notin s.flags: # XXX not yet enabled
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semMacroExpr(c, n, s)
result = semMacroExpr(c, n, n, s)
of skTemplate:
if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags)
else:
result = semTemplateExpr(c, n, s)
of skType:
of skType:
# XXX think about this more (``set`` procs)
if n.len == 2:
result = semConv(c, n, s)

View File

@@ -51,7 +51,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skTemplate:
result = semTemplateExpr(c, n, s, false)
of skMacro:
result = semMacroExpr(c, n, s, false)
result = semMacroExpr(c, n, n, s, false)
of skGenericParam:
result = newSymNode(s, n.info)
of skParam:
@@ -97,7 +97,7 @@ proc semGenericStmt(c: PContext, n: PNode,
incl(s.flags, sfUsed)
case s.kind
of skMacro:
result = semMacroExpr(c, n, s, false)
result = semMacroExpr(c, n, n, s, false)
of skTemplate:
result = semTemplateExpr(c, n, s, false)
# BUGFIX: we must not return here, we need to do first phase of

View File

@@ -892,13 +892,10 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1)
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "macro")
result = semProcAux(c, n, skMacro, macroPragmas)
var s = result.sons[namePos].sym
var t = s.typ
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "macro")
if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s)

View File

@@ -237,9 +237,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
return errorSym(c, n)
if result.typ.kind != tyGenericParam:
# XXX get rid of this hack!
var oldInfo = n.info
reset(n[])
n.kind = nkSym
n.sym = result
n.info = oldInfo
else:
LocalError(n.info, errIdentifierExpected)
result = errorSym(c, n)
@@ -549,7 +551,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) =
if kind == skMacro and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
if kind == skMacro:
# within a macro, every param has the type PNimrodNode!
# and param.typ.kind in {tyTypeDesc, tyExpr, tyStmt}:
let nn = getSysSym"PNimrodNode"
var a = copySym(param)
a.typ = nn.typ
@@ -779,7 +783,7 @@ proc semTypeFromMacro(c: PContext, n: PNode): PType =
markUsed(n, sym)
case sym.kind
of skMacro:
result = semTypeNode(c, semMacroExpr(c, n, sym), nil)
result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil)
of skTemplate:
result = semTypeNode(c, semTemplateExpr(c, n, sym), nil)
else:

View File

@@ -3102,7 +3102,7 @@ a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates.
Macros
------
A `macro`:idx: is a special kind of low level template. They can be used
A `macro`:idx: is a special kind of low level template. Macros can be used
to implement `domain specific languages`:idx:. Like templates, macros come in
the 2 flavors *immediate* and *ordinary*.
@@ -3129,12 +3129,12 @@ variable number of arguments:
# ``macros`` module:
import macros
macro debug(n: expr): stmt =
macro debug(n: varargs[expr]): stmt =
# `n` is a Nimrod AST that contains the whole macro invocation
# this macro returns a list of statements:
result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro:
for i in 1..n.len-1:
for i in 0..n.len-1:
# add a call to the statement list that writes the expression;
# `toStrLit` converts an AST to its string representation:
add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
@@ -3167,6 +3167,11 @@ The macro call expands to:
writeln(stdout, x)
Arguments that are passed to a ``varargs`` parameter are wrapped in an array
constructor expression. This is why ``debug`` iterates over all of ``n``'s
children.
BindSym
~~~~~~~
@@ -3179,9 +3184,9 @@ builtin can be used for that:
.. code-block:: nimrod
import macros
macro debug(n: expr): stmt =
macro debug(n: varargs[expr]): stmt =
result = newNimNode(nnkStmtList, n)
for i in 1..n.len-1:
for i in 0..n.len-1:
# we can bind symbols in scope via 'bindSym':
add(result, newCall(bindSym"write", bindSym"stdout", toStrLit(n[i])))
add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": ")))

View File

@@ -67,7 +67,7 @@ Objects have access to their type at runtime. There is an
person: TPerson
assert(student of TStudent) # is true
Object fields that should be visible from outside the defining module, have to
Object fields that should be visible from outside the defining module have to
be marked by ``*``. In contrast to tuples, different object types are
never *equivalent*. New object types can only be defined within a type
section.
@@ -631,19 +631,19 @@ Expression Macros
-----------------
The following example implements a powerful ``debug`` command that accepts a
variable number of arguments (this cannot be done with templates):
variable number of arguments:
.. code-block:: nimrod
# to work with Nimrod syntax trees, we need an API that is defined in the
# ``macros`` module:
import macros
macro debug(n: expr): stmt =
# `n` is a Nimrod AST that contains the whole macro expression
macro debug(n: varargs[expr]): stmt =
# `n` is a Nimrod AST that contains a list of expressions;
# this macro returns a list of statements:
result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro:
for i in 1..n.len-1:
for i in 0..n.len-1:
# add a call to the statement list that writes the expression;
# `toStrLit` converts an AST to its string representation:
result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
@@ -702,5 +702,3 @@ regular expressions:
return tkOperator
else:
return tkUnknown

View File

@@ -96,27 +96,25 @@ const
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit}
# Nodes should be reference counted to make the `copy` operation very fast!
# However, this is difficult to achieve: modify(n[0][1]) should propagate to
# its father. How to do this without back references? Hm, BS, it works without
# them.
proc `[]`* (n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
## get `n`'s `i`'th child.
proc `[]=`* (n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild".}
## set `n`'s `i`'th child to `child`.
proc `!` *(s: string): TNimrodIdent {.magic: "StrToIdent".}
proc `!`*(s: string): TNimrodIdent {.magic: "StrToIdent".}
## constructs an identifier from the string `s`
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
## converts a Nimrod identifier to a string
proc `==`* (a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
proc `$`*(s: PNimrodSymbol): string {.magic: "IdentToStr".}
## converts a Nimrod symbol to a string
proc `==`*(a, b: TNimrodIdent): bool {.magic: "EqIdent", noSideEffect.}
## compares two Nimrod identifiers
proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nimrod nodes
proc len*(n: PNimrodNode): int {.magic: "NLen".}
@@ -209,6 +207,9 @@ proc bindSym*(ident: string, rule: TBindSymRule = brClosed): PNimrodNode {.
## returned or ``nkSym`` if the symbol is not ambiguous.
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
## returned even if the symbol is not ambiguous.
proc callsite*(): PNimrodNode {.magic: "NCallSite".}
## returns the AST if the invokation expression that invoked this macro.
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
## converts the AST `n` to the concrete Nimrod code and wraps that
@@ -246,15 +247,6 @@ template emit*(s: expr): stmt =
block:
const evaluated = s
eval: result = evaluated.parseStmt
when false:
template once(x: expr): expr =
block:
const y = x
y
macro `payload`(x: stmt): stmt = result = once(s).parseStmt
`payload`()
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case,
@@ -312,27 +304,23 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
## Convert the AST `n` to a human-readable tree-like string.
##
## See also `repr` and `lispRepr`.
proc traverse(res: var string, level: int, n: PNimrodNode) =
for i in 0..level-1: res.add " "
res.add(($n.kind).substr(3))
if n == nil:
res.add "nil"
case n.kind
of nnkEmpty: nil # same as nil node in this representation
of nnkNilLit: res.add(" nil")
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
of nnkIdent: res.add(" !\"" & $n.ident & '"')
of nnkSym: res.add(" \"" & $n.symbol & '"')
of nnkNone: assert false
else:
res.add(($n.kind).substr(3))
case n.kind
of nnkEmpty: nil # same as nil node in this representation
of nnkNilLit: res.add(" nil")
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal)
of nnkIdent: res.add(" !\"" & $n.ident & '"')
of nnkSym, nnkNone: assert false
else:
for j in 0..n.len-1:
res.add "\n"
traverse(res, level + 1, n[j])
for j in 0..n.len-1:
res.add "\n"
traverse(res, level + 1, n[j])
result = ""
traverse(result, 0, n)
@@ -342,8 +330,6 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
##
## See also `repr` and `treeRepr`.
if n == nil: return "nil"
result = ($n.kind).substr(3)
add(result, "(")
@@ -363,7 +349,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
add(result, ")")
macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
macro dumpTree*(s: stmt): stmt = echo s.treeRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toTree` function. Printing is done *at compile time*.
##
@@ -371,7 +357,7 @@ macro dumpTree*(s: stmt): stmt = echo s[1].treeRepr
## tree and to discover what kind of nodes must be created to represent
## a certain expression/statement.
macro dumpLisp*(s: stmt): stmt = echo s[1].lispRepr
macro dumpLisp*(s: stmt): stmt = echo s.lispRepr
## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toLisp` function. Printing is done *at compile time*.
##

View File

@@ -15,11 +15,11 @@
##
## .. code-block:: nimrod
## var nim = "Nimrod"
## echo h1(a(href="http://force7.de/nimrod", nim))
## echo h1(a(href="http://nimrod-code.org", nim))
##
## Writes the string::
##
## <h1><a href="http://force7.de/nimrod">Nimrod</a></h1>
## <h1><a href="http://nimrod-code.org">Nimrod</a></h1>
##
import
@@ -88,319 +88,394 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string,
result = NestList(!"&", result)
macro a*(e: expr): expr =
macro a*(e: expr): expr {.immediate.} =
## generates the HTML ``a`` element.
let e = callsite()
result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " &
"accesskey tabindex" & commonAttr)
macro acronym*(e: expr): expr =
macro acronym*(e: expr): expr {.immediate.} =
## generates the HTML ``acronym`` element.
let e = callsite()
result = xmlCheckedTag(e, "acronym", commonAttr)
macro address*(e: expr): expr =
macro address*(e: expr): expr {.immediate.} =
## generates the HTML ``address`` element.
let e = callsite()
result = xmlCheckedTag(e, "address", commonAttr)
macro area*(e: expr): expr =
macro area*(e: expr): expr {.immediate.} =
## generates the HTML ``area`` element.
let e = callsite()
result = xmlCheckedTag(e, "area", "shape coords href nohref" &
" accesskey tabindex" & commonAttr, "alt", true)
macro b*(e: expr): expr =
macro b*(e: expr): expr {.immediate.} =
## generates the HTML ``b`` element.
let e = callsite()
result = xmlCheckedTag(e, "b", commonAttr)
macro base*(e: expr): expr =
macro base*(e: expr): expr {.immediate.} =
## generates the HTML ``base`` element.
let e = callsite()
result = xmlCheckedTag(e, "base", "", "href", true)
macro big*(e: expr): expr =
macro big*(e: expr): expr {.immediate.} =
## generates the HTML ``big`` element.
let e = callsite()
result = xmlCheckedTag(e, "big", commonAttr)
macro blockquote*(e: expr): expr =
macro blockquote*(e: expr): expr {.immediate.} =
## generates the HTML ``blockquote`` element.
let e = callsite()
result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr)
macro body*(e: expr): expr =
macro body*(e: expr): expr {.immediate.} =
## generates the HTML ``body`` element.
let e = callsite()
result = xmlCheckedTag(e, "body", commonAttr)
macro br*(e: expr): expr =
macro br*(e: expr): expr {.immediate.} =
## generates the HTML ``br`` element.
let e = callsite()
result = xmlCheckedTag(e, "br", "", "", true)
macro button*(e: expr): expr =
macro button*(e: expr): expr {.immediate.} =
## generates the HTML ``button`` element.
let e = callsite()
result = xmlCheckedTag(e, "button", "accesskey tabindex " &
"disabled name type value" & commonAttr)
macro caption*(e: expr): expr =
macro caption*(e: expr): expr {.immediate.} =
## generates the HTML ``caption`` element.
let e = callsite()
result = xmlCheckedTag(e, "caption", commonAttr)
macro cite*(e: expr): expr =
macro cite*(e: expr): expr {.immediate.} =
## generates the HTML ``cite`` element.
let e = callsite()
result = xmlCheckedTag(e, "cite", commonAttr)
macro code*(e: expr): expr =
macro code*(e: expr): expr {.immediate.} =
## generates the HTML ``code`` element.
let e = callsite()
result = xmlCheckedTag(e, "code", commonAttr)
macro col*(e: expr): expr =
macro col*(e: expr): expr {.immediate.} =
## generates the HTML ``col`` element.
let e = callsite()
result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true)
macro colgroup*(e: expr): expr =
macro colgroup*(e: expr): expr {.immediate.} =
## generates the HTML ``colgroup`` element.
let e = callsite()
result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
macro dd*(e: expr): expr =
macro dd*(e: expr): expr {.immediate.} =
## generates the HTML ``dd`` element.
let e = callsite()
result = xmlCheckedTag(e, "dd", commonAttr)
macro del*(e: expr): expr =
macro del*(e: expr): expr {.immediate.} =
## generates the HTML ``del`` element.
let e = callsite()
result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr)
macro dfn*(e: expr): expr =
macro dfn*(e: expr): expr {.immediate.} =
## generates the HTML ``dfn`` element.
let e = callsite()
result = xmlCheckedTag(e, "dfn", commonAttr)
macro `div`*(e: expr): expr =
macro `div`*(e: expr): expr {.immediate.} =
## generates the HTML ``div`` element.
let e = callsite()
result = xmlCheckedTag(e, "div", commonAttr)
macro dl*(e: expr): expr =
macro dl*(e: expr): expr {.immediate.} =
## generates the HTML ``dl`` element.
let e = callsite()
result = xmlCheckedTag(e, "dl", commonAttr)
macro dt*(e: expr): expr =
macro dt*(e: expr): expr {.immediate.} =
## generates the HTML ``dt`` element.
let e = callsite()
result = xmlCheckedTag(e, "dt", commonAttr)
macro em*(e: expr): expr =
macro em*(e: expr): expr {.immediate.} =
## generates the HTML ``em`` element.
let e = callsite()
result = xmlCheckedTag(e, "em", commonAttr)
macro fieldset*(e: expr): expr =
macro fieldset*(e: expr): expr {.immediate.} =
## generates the HTML ``fieldset`` element.
let e = callsite()
result = xmlCheckedTag(e, "fieldset", commonAttr)
macro form*(e: expr): expr =
macro form*(e: expr): expr {.immediate.} =
## generates the HTML ``form`` element.
let e = callsite()
result = xmlCheckedTag(e, "form", "method encype accept accept-charset" &
commonAttr, "action")
macro h1*(e: expr): expr =
macro h1*(e: expr): expr {.immediate.} =
## generates the HTML ``h1`` element.
let e = callsite()
result = xmlCheckedTag(e, "h1", commonAttr)
macro h2*(e: expr): expr =
macro h2*(e: expr): expr {.immediate.} =
## generates the HTML ``h2`` element.
let e = callsite()
result = xmlCheckedTag(e, "h2", commonAttr)
macro h3*(e: expr): expr =
macro h3*(e: expr): expr {.immediate.} =
## generates the HTML ``h3`` element.
let e = callsite()
result = xmlCheckedTag(e, "h3", commonAttr)
macro h4*(e: expr): expr =
macro h4*(e: expr): expr {.immediate.} =
## generates the HTML ``h4`` element.
let e = callsite()
result = xmlCheckedTag(e, "h4", commonAttr)
macro h5*(e: expr): expr =
macro h5*(e: expr): expr {.immediate.} =
## generates the HTML ``h5`` element.
let e = callsite()
result = xmlCheckedTag(e, "h5", commonAttr)
macro h6*(e: expr): expr =
macro h6*(e: expr): expr {.immediate.} =
## generates the HTML ``h6`` element.
let e = callsite()
result = xmlCheckedTag(e, "h6", commonAttr)
macro head*(e: expr): expr =
macro head*(e: expr): expr {.immediate.} =
## generates the HTML ``head`` element.
let e = callsite()
result = xmlCheckedTag(e, "head", "profile")
macro html*(e: expr): expr =
macro html*(e: expr): expr {.immediate.} =
## generates the HTML ``html`` element.
let e = callsite()
result = xmlCheckedTag(e, "html", "xmlns", "")
macro hr*(e: expr): expr =
macro hr*(e: expr): expr {.immediate.} =
## generates the HTML ``hr`` element.
let e = callsite()
result = xmlCheckedTag(e, "hr", commonAttr, "", true)
macro i*(e: expr): expr =
macro i*(e: expr): expr {.immediate.} =
## generates the HTML ``i`` element.
let e = callsite()
result = xmlCheckedTag(e, "i", commonAttr)
macro img*(e: expr): expr =
macro img*(e: expr): expr {.immediate.} =
## generates the HTML ``img`` element.
let e = callsite()
result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true)
macro input*(e: expr): expr =
macro input*(e: expr): expr {.immediate.} =
## generates the HTML ``input`` element.
let e = callsite()
result = xmlCheckedTag(e, "input", "name type value checked maxlength src" &
" alt accept disabled readonly accesskey tabindex" & commonAttr, "", true)
macro ins*(e: expr): expr =
macro ins*(e: expr): expr {.immediate.} =
## generates the HTML ``ins`` element.
let e = callsite()
result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr)
macro kbd*(e: expr): expr =
macro kbd*(e: expr): expr {.immediate.} =
## generates the HTML ``kbd`` element.
let e = callsite()
result = xmlCheckedTag(e, "kbd", commonAttr)
macro label*(e: expr): expr =
macro label*(e: expr): expr {.immediate.} =
## generates the HTML ``label`` element.
let e = callsite()
result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
macro legend*(e: expr): expr =
macro legend*(e: expr): expr {.immediate.} =
## generates the HTML ``legend`` element.
let e = callsite()
result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
macro li*(e: expr): expr =
macro li*(e: expr): expr {.immediate.} =
## generates the HTML ``li`` element.
let e = callsite()
result = xmlCheckedTag(e, "li", commonAttr)
macro link*(e: expr): expr =
macro link*(e: expr): expr {.immediate.} =
## generates the HTML ``link`` element.
let e = callsite()
result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" &
commonAttr, "", true)
macro map*(e: expr): expr =
macro map*(e: expr): expr {.immediate.} =
## generates the HTML ``map`` element.
let e = callsite()
result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false)
macro meta*(e: expr): expr =
macro meta*(e: expr): expr {.immediate.} =
## generates the HTML ``meta`` element.
let e = callsite()
result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true)
macro noscript*(e: expr): expr =
macro noscript*(e: expr): expr {.immediate.} =
## generates the HTML ``noscript`` element.
let e = callsite()
result = xmlCheckedTag(e, "noscript", commonAttr)
macro `object`*(e: expr): expr =
macro `object`*(e: expr): expr {.immediate.} =
## generates the HTML ``object`` element.
let e = callsite()
result = xmlCheckedTag(e, "object", "classid data codebase declare type " &
"codetype archive standby width height name tabindex" & commonAttr)
macro ol*(e: expr): expr =
macro ol*(e: expr): expr {.immediate.} =
## generates the HTML ``ol`` element.
let e = callsite()
result = xmlCheckedTag(e, "ol", commonAttr)
macro optgroup*(e: expr): expr =
macro optgroup*(e: expr): expr {.immediate.} =
## generates the HTML ``optgroup`` element.
let e = callsite()
result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false)
macro option*(e: expr): expr =
macro option*(e: expr): expr {.immediate.} =
## generates the HTML ``option`` element.
let e = callsite()
result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
macro p*(e: expr): expr =
macro p*(e: expr): expr {.immediate.} =
## generates the HTML ``p`` element.
let e = callsite()
result = xmlCheckedTag(e, "p", commonAttr)
macro param*(e: expr): expr =
macro param*(e: expr): expr {.immediate.} =
## generates the HTML ``param`` element.
let e = callsite()
result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true)
macro pre*(e: expr): expr =
macro pre*(e: expr): expr {.immediate.} =
## generates the HTML ``pre`` element.
let e = callsite()
result = xmlCheckedTag(e, "pre", commonAttr)
macro q*(e: expr): expr =
macro q*(e: expr): expr {.immediate.} =
## generates the HTML ``q`` element.
let e = callsite()
result = xmlCheckedTag(e, "q", "cite" & commonAttr)
macro samp*(e: expr): expr =
macro samp*(e: expr): expr {.immediate.} =
## generates the HTML ``samp`` element.
let e = callsite()
result = xmlCheckedTag(e, "samp", commonAttr)
macro script*(e: expr): expr =
macro script*(e: expr): expr {.immediate.} =
## generates the HTML ``script`` element.
let e = callsite()
result = xmlCheckedTag(e, "script", "src charset defer", "type", false)
macro select*(e: expr): expr =
macro select*(e: expr): expr {.immediate.} =
## generates the HTML ``select`` element.
let e = callsite()
result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" &
commonAttr)
macro small*(e: expr): expr =
macro small*(e: expr): expr {.immediate.} =
## generates the HTML ``small`` element.
let e = callsite()
result = xmlCheckedTag(e, "small", commonAttr)
macro span*(e: expr): expr =
macro span*(e: expr): expr {.immediate.} =
## generates the HTML ``span`` element.
let e = callsite()
result = xmlCheckedTag(e, "span", commonAttr)
macro strong*(e: expr): expr =
macro strong*(e: expr): expr {.immediate.} =
## generates the HTML ``strong`` element.
let e = callsite()
result = xmlCheckedTag(e, "strong", commonAttr)
macro style*(e: expr): expr =
macro style*(e: expr): expr {.immediate.} =
## generates the HTML ``style`` element.
let e = callsite()
result = xmlCheckedTag(e, "style", "media title", "type")
macro sub*(e: expr): expr =
macro sub*(e: expr): expr {.immediate.} =
## generates the HTML ``sub`` element.
let e = callsite()
result = xmlCheckedTag(e, "sub", commonAttr)
macro sup*(e: expr): expr =
macro sup*(e: expr): expr {.immediate.} =
## generates the HTML ``sup`` element.
let e = callsite()
result = xmlCheckedTag(e, "sup", commonAttr)
macro table*(e: expr): expr =
macro table*(e: expr): expr {.immediate.} =
## generates the HTML ``table`` element.
let e = callsite()
result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" &
" frame rules width" & commonAttr)
macro tbody*(e: expr): expr =
macro tbody*(e: expr): expr {.immediate.} =
## generates the HTML ``tbody`` element.
let e = callsite()
result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
macro td*(e: expr): expr =
macro td*(e: expr): expr {.immediate.} =
## generates the HTML ``td`` element.
let e = callsite()
result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" &
" align valign" & commonAttr)
macro textarea*(e: expr): expr =
macro textarea*(e: expr): expr {.immediate.} =
## generates the HTML ``textarea`` element.
let e = callsite()
result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" &
" tabindex" & commonAttr, "rows cols", false)
macro tfoot*(e: expr): expr =
macro tfoot*(e: expr): expr {.immediate.} =
## generates the HTML ``tfoot`` element.
let e = callsite()
result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
macro th*(e: expr): expr =
macro th*(e: expr): expr {.immediate.} =
## generates the HTML ``th`` element.
let e = callsite()
result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" &
" align valign" & commonAttr)
macro thead*(e: expr): expr =
macro thead*(e: expr): expr {.immediate.} =
## generates the HTML ``thead`` element.
let e = callsite()
result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
macro title*(e: expr): expr =
macro title*(e: expr): expr {.immediate.} =
## generates the HTML ``title`` element.
let e = callsite()
result = xmlCheckedTag(e, "title")
macro tr*(e: expr): expr =
macro tr*(e: expr): expr {.immediate.} =
## generates the HTML ``tr`` element.
let e = callsite()
result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
macro tt*(e: expr): expr =
macro tt*(e: expr): expr {.immediate.} =
## generates the HTML ``tt`` element.
let e = callsite()
result = xmlCheckedTag(e, "tt", commonAttr)
macro ul*(e: expr): expr =
macro ul*(e: expr): expr {.immediate.} =
## generates the HTML ``ul`` element.
let e = callsite()
result = xmlCheckedTag(e, "ul", commonAttr)
macro `var`*(e: expr): expr =
macro `var`*(e: expr): expr {.immediate.} =
## generates the HTML ``var`` element.
let e = callsite()
result = xmlCheckedTag(e, "var", commonAttr)
when isMainModule:
var nim = "Nimrod"
echo h1(a(href="http://force7.de/nimrod", nim))
echo h1(a(href="http://nimrod-code.org", nim))

View File

@@ -325,8 +325,9 @@ proc styledEchoProcessArg(style: set[TStyle]) = setStyle style
proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
macro styledEcho*(m: stmt): stmt =
macro styledEcho*(m: varargs[expr]): stmt =
## to be documented.
let m = callsite()
result = newNimNode(nnkStmtList)
for i in countup(1, m.len - 1):

View File

@@ -262,12 +262,13 @@ macro `<>`*(x: expr): expr =
## Constructor macro for XML. Example usage:
##
## .. code-block:: nimrod
## <>a(href="http://force7.de/nimrod", "Nimrod rules.")
## <>a(href="http://nimrod-code.org", "Nimrod rules.")
##
## Produces an XML tree for::
##
## <a href="http://force7.de/nimrod">Nimrod rules.</a>
## <a href="http://nimrod-code.org">Nimrod rules.</a>
##
let x = callsite()
result = xmlConstructor(x)
proc child*(n: PXmlNode, name: string): PXmlNode =

View File

@@ -1,7 +1,9 @@
version 0.9.0
=============
- introduce 'callsite' magic and make macros and templates the same
- make 'm: stmt' use overloading resolution
- implement the high level optimizer
- make 'bind' default for templates and introduce 'mixin'
- implement "closure tuple consists of a single 'ref'" optimization
@@ -32,6 +34,17 @@ Bugs
version 0.9.XX
==============
- make:
p(a, b):
echo a
echo b
the same as:
p(a, b, proc() =
echo a
echo b)
- JS gen:
- fix exception handling
@@ -52,7 +65,6 @@ version 0.9.XX
- document nimdoc properly finally
- make 'clamp' a magic for the range stuff
- implement a warning message for shadowed 'result' variable
- implement the high level optimizer
- we need to support iteration of 2 different data structures in parallel
- implement proper coroutines
- proc specialization in the code gen for write barrier specialization
@@ -71,17 +83,6 @@ version 0.9.XX
* For parameter ``tyExpr`` any argument matches.
* Argument ``tyProxy`` matches any parameter.
- nice idea:
p(a, b):
echo a
echo b
is the same as:
p(a, b, proc() =
echo a
echo b)
Library
-------
@@ -114,10 +115,7 @@ Low priority
escape analysis for string/seq seems to be easy to do too;
even further write barrier specialization
- GC: marker procs Boehm GC
- implement marker procs for assignment and message passing
- warning for implicit openArray -> varargs conversion
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
--> solve by implicit conversion from varargs to openarray
- implement marker procs for message passing
- optimize method dispatchers
- activate more thread tests
- implement ``--script:sh|bat`` command line option; think about script

View File

@@ -111,6 +111,8 @@ Changes affecting backwards compatibility
- Objects that have no ancestor are now implicitely ``final``. Use
the ``inheritable`` pragma to introduce new object roots apart
from ``TObject``.
- Macros now receive parameters like templates do; use the ``callsite`` builtin
to gain access to the invokating AST.
Compiler Additions