diff options
-rwxr-xr-x | compiler/ast.nim | 2 | ||||
-rwxr-xr-x | compiler/evals.nim | 44 | ||||
-rwxr-xr-x | compiler/renderer.nim | 2 | ||||
-rwxr-xr-x | compiler/sem.nim | 6 | ||||
-rwxr-xr-x | compiler/semexprs.nim | 15 | ||||
-rwxr-xr-x | compiler/semgnrc.nim | 4 | ||||
-rwxr-xr-x | compiler/semstmts.nim | 3 | ||||
-rwxr-xr-x | compiler/semtypes.nim | 8 | ||||
-rwxr-xr-x | doc/manual.txt | 15 | ||||
-rwxr-xr-x | doc/tut2.txt | 12 | ||||
-rwxr-xr-x | lib/core/macros.nim | 66 | ||||
-rwxr-xr-x | lib/pure/htmlgen.nim | 231 | ||||
-rwxr-xr-x | lib/pure/terminal.nim | 3 | ||||
-rwxr-xr-x | lib/pure/xmltree.nim | 5 | ||||
-rwxr-xr-x | todo.txt | 32 | ||||
-rwxr-xr-x | web/news.txt | 2 |
16 files changed, 270 insertions, 180 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 79adafcf8..a8176501f 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -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 diff --git a/compiler/evals.nim b/compiler/evals.nim index 4ec6cb4d7..bb0e5936d 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -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) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index c24a22fd5..b6b34287a 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -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, "[") diff --git a/compiler/sem.nim b/compiler/sem.nim index 34b6f1f78..d92c1657d 100755 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -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 = diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 06014bf6f..9219cacf6 100755 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -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) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index 849d04fb1..ea3eebc3a 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -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 diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index d12ad23cf..3a8424d9e 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -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) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 5b6183005..8ec3c337c 100755 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -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: diff --git a/doc/manual.txt b/doc/manual.txt index e10c934f1..df64649ed 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -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(": "))) diff --git a/doc/tut2.txt b/doc/tut2.txt index 96507bcb1..85a68c983 100755 --- a/doc/tut2.txt +++ b/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 - - diff --git a/lib/core/macros.nim b/lib/core/macros.nim index fac935430..610360fb2 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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*. ## diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim index 86ee4159b..75af2c892 100755 --- a/lib/pure/htmlgen.nim +++ b/lib/pure/htmlgen.nim @@ -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)) diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index d24d81112..3be6088ed 100755 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.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): diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 0ea777e93..b657ee05c 100755 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -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 = diff --git a/todo.txt b/todo.txt index a255315a7..8c5d172da 100755 --- a/todo.txt +++ b/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 diff --git a/web/news.txt b/web/news.txt index e456f70f3..80f74cd1e 100755 --- a/web/news.txt +++ b/web/news.txt @@ -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 |