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
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, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNBindSym, mNBindSym, mNCallSite,
mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError, mEqIdent, mEqNimrodNode, mNHint, mNWarning, mNError,
mInstantiationInfo, mGetTypeInfo mInstantiationInfo, mGetTypeInfo

View file

@ -38,6 +38,7 @@ type
module*: PSym module*: PSym
tos*: PStackFrame # top of stack tos*: PStackFrame # top of stack
lastException*: PNode lastException*: PNode
callsite: PNode # for 'callsite' magic
mode*: TEvalMode mode*: TEvalMode
globals*: TIdNodeTable # state of global vars globals*: TIdNodeTable # state of global vars
@ -74,7 +75,7 @@ proc popStackFrame*(c: PEvalContext) {.inline.} =
if c.tos != nil: c.tos = c.tos.next if c.tos != nil: c.tos = c.tos.next
else: InternalError("popStackFrame") 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 evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode
proc raiseCannotEval(c: PEvalContext, info: TLineInfo): 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.} = proc isSpecial(n: PNode): bool {.inline.} =
result = n.kind == nkExceptBranch result = n.kind == nkExceptBranch
proc myreset(n: PNode) {.inline.} = proc myreset(n: PNode) =
when defined(system.reset): reset(n[]) when defined(system.reset):
var oldInfo = n.info
reset(n[])
n.info = oldInfo
proc evalIf(c: PEvalContext, n: PNode): PNode = proc evalIf(c: PEvalContext, n: PNode): PNode =
var i = 0 var i = 0
@ -245,6 +249,11 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
of tyObject: of tyObject:
result = newNodeIT(nkPar, info, t) result = newNodeIT(nkPar, info, t)
getNullValueAux(t.n, result) 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: of tyArray, tyArrayConstr:
result = newNodeIT(nkBracket, info, t) result = newNodeIT(nkBracket, info, t)
for i in countup(0, int(lengthOrd(t)) - 1): 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 # we want to replace it with nkIdent node featuring
# the original unmangled macro name. # the original unmangled macro name.
macroCall.sons[0] = newIdentNode(expandedSym.name, expandedSym.info) macroCall.sons[0] = newIdentNode(expandedSym.name, expandedSym.info)
result = evalMacroCall(c, macroCall, expandedSym) result = evalMacroCall(c, macroCall, original, expandedSym)
else: else:
InternalError(macroCall.info, InternalError(macroCall.info,
"ExpandToAst: expanded symbol is no macro or template") "ExpandToAst: expanded symbol is no macro or template")
@ -1166,10 +1175,13 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mIdentToStr: of mIdentToStr:
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
if result.kind != nkIdent: InternalError(n.info, "no ident node")
var a = result var a = result
result = newNodeIT(nkStrLit, n.info, n.typ) 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: of mEqIdent:
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
@ -1226,6 +1238,9 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
var a = result var a = result
result = newNodeIT(nkStrLit, n.info, n.typ) result = newNodeIT(nkStrLit, n.info, n.typ)
result.strVal = newString(0) result.strVal = newString(0)
of mNCallSite:
if c.callsite != nil: result = c.callsite
else: stackTrace(c, n, errFieldXNotFound, "callsite")
else: else:
result = evalAux(c, n.sons[1], {}) result = evalAux(c, n.sons[1], {})
if isSpecial(result): return if isSpecial(result): return
@ -1355,24 +1370,31 @@ proc evalConstExpr*(module: PSym, e: PNode): PNode =
proc evalStaticExpr*(module: PSym, e: PNode): PNode = proc evalStaticExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, e, emStatic) 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 # XXX GlobalError() is ugly here, but I don't know a better solution for now
inc(evalTemplateCounter) inc(evalTemplateCounter)
if evalTemplateCounter > 100: if evalTemplateCounter > 100:
GlobalError(n.info, errTemplateInstantiationTooNested) GlobalError(n.info, errTemplateInstantiationTooNested)
#inc genSymBaseId c.callsite = nOrig
var s = newStackFrame() var s = newStackFrame()
s.call = n 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[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) pushStackFrame(c, s)
discard eval(c, sym.getBody) discard eval(c, sym.getBody)
result = s.params[0] result = s.params[0]
popStackFrame(c) popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree) if cyclicTree(result): GlobalError(n.info, errCyclicTree)
dec(evalTemplateCounter) dec(evalTemplateCounter)
c.callsite = nil
proc myOpen(module: PSym, filename: string): PPassContext = proc myOpen(module: PSym, filename: string): PPassContext =
var c = newEvalContext(module, filename, emRepl) 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, "\"", "\"\"") & '\"') put(g, tkRStrLit, '\"' & replace(n[1].strVal, "\"", "\"\"") & '\"')
else: else:
gsub(g, n.sons[1]) 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: of nkCast:
put(g, tkCast, "cast") put(g, tkCast, "cast")
put(g, tkBracketLe, "[") 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 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 semCheck: bool = true): PNode
proc semWhen(c: PContext, n: PNode, 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])) #GlobalError(s.info, errInvalidParamKindX, typeToString(s.typ.sons[0]))
dec(evalTemplateCounter) dec(evalTemplateCounter)
proc semMacroExpr(c: PContext, n: PNode, sym: PSym, proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
semCheck: bool = true): PNode = semCheck: bool = true): PNode =
markUsed(n, sym) markUsed(n, sym)
if sym == c.p.owner: if sym == c.p.owner:
GlobalError(n.info, errRecursiveDependencyX, sym.name.s) GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil: if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic) 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) if semCheck: result = semAfterMacroCall(c, result, sym)
proc forceBool(c: PContext, n: PNode): PNode = 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)
else: else:
result = newSymNode(s, n.info) 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 skTemplate: result = semTemplateExpr(c, n, s)
of skVar, skLet, skResult, skParam, skForVar: of skVar, skLet, skResult, skParam, skForVar:
markUsed(n, s) markUsed(n, s)
@ -705,7 +705,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
return errorNode(c, n) return errorNode(c, n)
let callee = result.sons[0].sym let callee = result.sons[0].sym
case callee.kind 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) of skTemplate: result = semTemplateExpr(c, nOrig, callee)
else: else:
fixAbstractType(c, result) fixAbstractType(c, result)
@ -1398,7 +1398,8 @@ proc semBlockExpr(c: PContext, n: PNode): PNode =
closeScope(c.tab) closeScope(c.tab)
Dec(c.p.nestedBlockCounter) 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) checkMinSonsLen(n, 2)
var a: PNode var a: PNode
if isCallExpr(n.sons[0]): a = n.sons[0].sons[0] 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: if s != nil:
case s.kind case s.kind
of skMacro: of skMacro:
result = semMacroExpr(c, n, s, semCheck) result = semMacroExpr(c, n, n, s, semCheck)
of skTemplate: of skTemplate:
# transform # transform
# nkMacroStmt(nkCall(a...), stmt, b...) # nkMacroStmt(nkCall(a...), stmt, b...)
@ -1499,16 +1500,16 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
if s != nil: if s != nil:
case s.kind case s.kind
of skMacro: of skMacro:
if false and sfImmediate notin s.flags: # XXX not yet enabled if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
result = semMacroExpr(c, n, s) result = semMacroExpr(c, n, n, s)
of skTemplate: of skTemplate:
if sfImmediate notin s.flags: if sfImmediate notin s.flags:
result = semDirectOp(c, n, flags) result = semDirectOp(c, n, flags)
else: else:
result = semTemplateExpr(c, n, s) result = semTemplateExpr(c, n, s)
of skType: of skType:
# XXX think about this more (``set`` procs) # XXX think about this more (``set`` procs)
if n.len == 2: if n.len == 2:
result = semConv(c, n, s) result = semConv(c, n, s)

View file

@ -51,7 +51,7 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
of skTemplate: of skTemplate:
result = semTemplateExpr(c, n, s, false) result = semTemplateExpr(c, n, s, false)
of skMacro: of skMacro:
result = semMacroExpr(c, n, s, false) result = semMacroExpr(c, n, n, s, false)
of skGenericParam: of skGenericParam:
result = newSymNode(s, n.info) result = newSymNode(s, n.info)
of skParam: of skParam:
@ -97,7 +97,7 @@ proc semGenericStmt(c: PContext, n: PNode,
incl(s.flags, sfUsed) incl(s.flags, sfUsed)
case s.kind case s.kind
of skMacro: of skMacro:
result = semMacroExpr(c, n, s, false) result = semMacroExpr(c, n, n, s, false)
of skTemplate: of skTemplate:
result = semTemplateExpr(c, n, s, false) result = semTemplateExpr(c, n, s, false)
# BUGFIX: we must not return here, we need to do first phase of # 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 = proc semMacroDef(c: PContext, n: PNode): PNode =
checkSonsLen(n, bodyPos + 1) checkSonsLen(n, bodyPos + 1)
if n.sons[genericParamsPos].kind != nkEmpty:
LocalError(n.info, errNoGenericParamsAllowedForX, "macro")
result = semProcAux(c, n, skMacro, macroPragmas) result = semProcAux(c, n, skMacro, macroPragmas)
var s = result.sons[namePos].sym var s = result.sons[namePos].sym
var t = s.typ var t = s.typ
if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro") 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: if n.sons[bodyPos].kind == nkEmpty:
LocalError(n.info, errImplOfXexpected, s.name.s) LocalError(n.info, errImplOfXexpected, s.name.s)

View file

@ -237,9 +237,11 @@ proc semTypeIdent(c: PContext, n: PNode): PSym =
return errorSym(c, n) return errorSym(c, n)
if result.typ.kind != tyGenericParam: if result.typ.kind != tyGenericParam:
# XXX get rid of this hack! # XXX get rid of this hack!
var oldInfo = n.info
reset(n[]) reset(n[])
n.kind = nkSym n.kind = nkSym
n.sym = result n.sym = result
n.info = oldInfo
else: else:
LocalError(n.info, errIdentifierExpected) LocalError(n.info, errIdentifierExpected)
result = errorSym(c, n) result = errorSym(c, n)
@ -549,7 +551,9 @@ proc semObjectNode(c: PContext, n: PNode, prev: PType): PType =
incl(result.flags, tfFinal) incl(result.flags, tfFinal)
proc addParamOrResult(c: PContext, param: PSym, kind: TSymKind) = 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" let nn = getSysSym"PNimrodNode"
var a = copySym(param) var a = copySym(param)
a.typ = nn.typ a.typ = nn.typ
@ -779,7 +783,7 @@ proc semTypeFromMacro(c: PContext, n: PNode): PType =
markUsed(n, sym) markUsed(n, sym)
case sym.kind case sym.kind
of skMacro: of skMacro:
result = semTypeNode(c, semMacroExpr(c, n, sym), nil) result = semTypeNode(c, semMacroExpr(c, n, n, sym), nil)
of skTemplate: of skTemplate:
result = semTypeNode(c, semTemplateExpr(c, n, sym), nil) result = semTypeNode(c, semTemplateExpr(c, n, sym), nil)
else: else:

View file

@ -3102,7 +3102,7 @@ a template. ``inject`` and ``gensym`` have no effect in ``dirty`` templates.
Macros 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 to implement `domain specific languages`:idx:. Like templates, macros come in
the 2 flavors *immediate* and *ordinary*. the 2 flavors *immediate* and *ordinary*.
@ -3129,12 +3129,12 @@ variable number of arguments:
# ``macros`` module: # ``macros`` module:
import macros import macros
macro debug(n: expr): stmt = macro debug(n: varargs[expr]): stmt =
# `n` is a Nimrod AST that contains the whole macro invocation # `n` is a Nimrod AST that contains the whole macro invocation
# this macro returns a list of statements: # this macro returns a list of statements:
result = newNimNode(nnkStmtList, n) result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro: # 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; # add a call to the statement list that writes the expression;
# `toStrLit` converts an AST to its string representation: # `toStrLit` converts an AST to its string representation:
add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
@ -3167,6 +3167,11 @@ The macro call expands to:
writeln(stdout, x) 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 BindSym
~~~~~~~ ~~~~~~~
@ -3179,9 +3184,9 @@ builtin can be used for that:
.. code-block:: nimrod .. code-block:: nimrod
import macros import macros
macro debug(n: expr): stmt = macro debug(n: varargs[expr]): stmt =
result = newNimNode(nnkStmtList, n) 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': # 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", toStrLit(n[i])))
add(result, newCall(bindSym"write", bindSym"stdout", newStrLitNode(": "))) 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 person: TPerson
assert(student of TStudent) # is true 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 be marked by ``*``. In contrast to tuples, different object types are
never *equivalent*. New object types can only be defined within a type never *equivalent*. New object types can only be defined within a type
section. section.
@ -631,19 +631,19 @@ Expression Macros
----------------- -----------------
The following example implements a powerful ``debug`` command that accepts a 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 .. code-block:: nimrod
# to work with Nimrod syntax trees, we need an API that is defined in the # to work with Nimrod syntax trees, we need an API that is defined in the
# ``macros`` module: # ``macros`` module:
import macros import macros
macro debug(n: expr): stmt = macro debug(n: varargs[expr]): stmt =
# `n` is a Nimrod AST that contains the whole macro expression # `n` is a Nimrod AST that contains a list of expressions;
# this macro returns a list of statements: # this macro returns a list of statements:
result = newNimNode(nnkStmtList, n) result = newNimNode(nnkStmtList, n)
# iterate over any argument that is passed to this macro: # 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; # add a call to the statement list that writes the expression;
# `toStrLit` converts an AST to its string representation: # `toStrLit` converts an AST to its string representation:
result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i]))) result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
@ -702,5 +702,3 @@ regular expressions:
return tkOperator return tkOperator
else: else:
return tkUnknown return tkUnknown

View file

@ -96,27 +96,25 @@ const
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit} nnkCallStrLit}
# Nodes should be reference counted to make the `copy` operation very fast! proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild".}
# 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".}
## get `n`'s `i`'th child. ## 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`. ## 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` ## constructs an identifier from the string `s`
proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".} proc `$`*(i: TNimrodIdent): string {.magic: "IdentToStr".}
## converts a Nimrod identifier to a string ## 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 ## compares two Nimrod identifiers
proc `==`* (a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.} proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nimrod nodes ## compares two Nimrod nodes
proc len*(n: PNimrodNode): int {.magic: "NLen".} 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. ## returned or ``nkSym`` if the symbol is not ambiguous.
## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is ## If ``rule == brForceOpen`` always an ``nkOpenSymChoice`` tree is
## returned even if the symbol is not ambiguous. ## 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.} = proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} =
## converts the AST `n` to the concrete Nimrod code and wraps that ## converts the AST `n` to the concrete Nimrod code and wraps that
@ -246,15 +247,6 @@ template emit*(s: expr): stmt =
block: block:
const evaluated = s const evaluated = s
eval: result = evaluated.parseStmt 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.} = proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case, ## 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. ## Convert the AST `n` to a human-readable tree-like string.
## ##
## See also `repr` and `lispRepr`. ## See also `repr` and `lispRepr`.
proc traverse(res: var string, level: int, n: PNimrodNode) = proc traverse(res: var string, level: int, n: PNimrodNode) =
for i in 0..level-1: res.add " " for i in 0..level-1: res.add " "
res.add(($n.kind).substr(3))
if n == nil: case n.kind
res.add "nil" 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: else:
res.add(($n.kind).substr(3)) for j in 0..n.len-1:
res.add "\n"
case n.kind traverse(res, level + 1, n[j])
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])
result = "" result = ""
traverse(result, 0, n) traverse(result, 0, n)
@ -342,8 +330,6 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
## ##
## See also `repr` and `treeRepr`. ## See also `repr` and `treeRepr`.
if n == nil: return "nil"
result = ($n.kind).substr(3) result = ($n.kind).substr(3)
add(result, "(") add(result, "(")
@ -363,7 +349,7 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
add(result, ")") 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 ## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toTree` function. Printing is done *at compile time*. ## 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 ## tree and to discover what kind of nodes must be created to represent
## a certain expression/statement. ## 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 ## Accepts a block of nimrod code and prints the parsed abstract syntax
## tree using the `toLisp` function. Printing is done *at compile time*. ## tree using the `toLisp` function. Printing is done *at compile time*.
## ##

View file

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

View file

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

View file

@ -1,7 +1,9 @@
version 0.9.0 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' - make 'bind' default for templates and introduce 'mixin'
- implement "closure tuple consists of a single 'ref'" optimization - implement "closure tuple consists of a single 'ref'" optimization
@ -32,6 +34,17 @@ Bugs
version 0.9.XX 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: - JS gen:
- fix exception handling - fix exception handling
@ -52,7 +65,6 @@ version 0.9.XX
- document nimdoc properly finally - document nimdoc properly finally
- make 'clamp' a magic for the range stuff - make 'clamp' a magic for the range stuff
- implement a warning message for shadowed 'result' variable - 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 - we need to support iteration of 2 different data structures in parallel
- implement proper coroutines - implement proper coroutines
- proc specialization in the code gen for write barrier specialization - proc specialization in the code gen for write barrier specialization
@ -71,17 +83,6 @@ version 0.9.XX
* For parameter ``tyExpr`` any argument matches. * For parameter ``tyExpr`` any argument matches.
* Argument ``tyProxy`` matches any parameter. * 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 Library
------- -------
@ -114,10 +115,7 @@ Low priority
escape analysis for string/seq seems to be easy to do too; escape analysis for string/seq seems to be easy to do too;
even further write barrier specialization even further write barrier specialization
- GC: marker procs Boehm GC - GC: marker procs Boehm GC
- implement marker procs for assignment and message passing - implement marker procs for message passing
- warning for implicit openArray -> varargs conversion
- implement explicit varargs; **but** ``len(varargs)`` problem remains!
--> solve by implicit conversion from varargs to openarray
- optimize method dispatchers - optimize method dispatchers
- activate more thread tests - activate more thread tests
- implement ``--script:sh|bat`` command line option; think about script - 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 - Objects that have no ancestor are now implicitely ``final``. Use
the ``inheritable`` pragma to introduce new object roots apart the ``inheritable`` pragma to introduce new object roots apart
from ``TObject``. from ``TObject``.
- Macros now receive parameters like templates do; use the ``callsite`` builtin
to gain access to the invokating AST.
Compiler Additions Compiler Additions