mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 05:50:30 +00:00
parameter passing works the same for macros and templates; use callsite magic to access the invokation AST
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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, "[")
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(": ")))
|
||||
|
||||
12
doc/tut2.txt
12
doc/tut2.txt
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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*.
|
||||
##
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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 =
|
||||
|
||||
32
todo.txt
32
todo.txt
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user