Rename PNimrodNode to NimNode

This commit is contained in:
def 2015-03-17 17:50:32 +01:00
commit fd4e629905
30 changed files with 508 additions and 518 deletions

View file

@ -85,11 +85,11 @@ type
ntyInt8, ntyInt16, ntyInt32, ntyInt64, ntyInt8, ntyInt16, ntyInt32, ntyInt64,
ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128, ntyFloat, ntyFloat32, ntyFloat64, ntyFloat128,
ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64, ntyUInt, ntyUInt8, ntyUInt16, ntyUInt32, ntyUInt64,
ntyBigNum, ntyBigNum,
ntyConst, ntyMutable, ntyVarargs, ntyConst, ntyMutable, ntyVarargs,
ntyIter, ntyIter,
ntyError ntyError
TNimTypeKinds* {.deprecated.} = set[NimTypeKind] TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
NimSymKind* = enum NimSymKind* = enum
nskUnknown, nskConditional, nskDynLib, nskParam, nskUnknown, nskConditional, nskDynLib, nskParam,
@ -120,12 +120,10 @@ const
nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, nnkCallKinds* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit} nnkCallStrLit}
{.push warning[deprecated]: off.} proc `[]`*(n: NimNode, i: int): NimNode {.magic: "NChild", noSideEffect.}
proc `[]`*(n: PNimrodNode, i: int): PNimrodNode {.magic: "NChild", noSideEffect.}
## get `n`'s `i`'th child. ## get `n`'s `i`'th child.
proc `[]=`*(n: PNimrodNode, i: int, child: PNimrodNode) {.magic: "NSetChild", proc `[]=`*(n: NimNode, i: int, child: NimNode) {.magic: "NSetChild",
noSideEffect.} noSideEffect.}
## set `n`'s `i`'th child to `child`. ## set `n`'s `i`'th child to `child`.
@ -141,34 +139,34 @@ proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.} proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.}
## compares two Nim identifiers ## compares two Nim identifiers
proc `==`*(a, b: PNimrodNode): bool {.magic: "EqNimrodNode", noSideEffect.} proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nim nodes ## compares two Nim nodes
proc len*(n: PNimrodNode): int {.magic: "NLen", noSideEffect.} proc len*(n: NimNode): int {.magic: "NLen", noSideEffect.}
## returns the number of children of `n`. ## returns the number of children of `n`.
proc add*(father, child: PNimrodNode): PNimrodNode {.magic: "NAdd", discardable, proc add*(father, child: NimNode): NimNode {.magic: "NAdd", discardable,
noSideEffect, locks: 0.} noSideEffect, locks: 0.}
## Adds the `child` to the `father` node. Returns the ## Adds the `child` to the `father` node. Returns the
## father node so that calls can be nested. ## father node so that calls can be nested.
proc add*(father: PNimrodNode, children: varargs[PNimrodNode]): PNimrodNode {. proc add*(father: NimNode, children: varargs[NimNode]): NimNode {.
magic: "NAddMultiple", discardable, noSideEffect, locks: 0.} magic: "NAddMultiple", discardable, noSideEffect, locks: 0.}
## Adds each child of `children` to the `father` node. ## Adds each child of `children` to the `father` node.
## Returns the `father` node so that calls can be nested. ## Returns the `father` node so that calls can be nested.
proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.} proc del*(father: NimNode, idx = 0, n = 1) {.magic: "NDel", noSideEffect.}
## deletes `n` children of `father` starting at index `idx`. ## deletes `n` children of `father` starting at index `idx`.
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind", noSideEffect.} proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
## returns the `kind` of the node `n`. ## returns the `kind` of the node `n`.
proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal", noSideEffect.} proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.} proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
proc symbol*(n: PNimrodNode): NimSym {.magic: "NSymbol", noSideEffect.} proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
proc ident*(n: PNimrodNode): NimIdent {.magic: "NIdent", noSideEffect.} proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
proc getType*(n: PNimrodNode): PNimrodNode {.magic: "NGetType", noSideEffect.} proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
## with 'getType' you can access the node's `type`:idx:. A Nim type is ## with 'getType' you can access the node's `type`:idx:. A Nim type is
## mapped to a Nim AST too, so it's slightly confusing but it means the same ## mapped to a Nim AST too, so it's slightly confusing but it means the same
## API can be used to traverse types. Recursive types are flattened for you ## API can be used to traverse types. Recursive types are flattened for you
@ -176,30 +174,30 @@ proc getType*(n: PNimrodNode): PNimrodNode {.magic: "NGetType", noSideEffect.}
## resolve recursive types, you have to call 'getType' again. To see what ## resolve recursive types, you have to call 'getType' again. To see what
## kind of type it is, call `typeKind` on getType's result. ## kind of type it is, call `typeKind` on getType's result.
proc typeKind*(n: PNimrodNode): NimTypeKind {.magic: "NGetType", noSideEffect.} proc typeKind*(n: NimNode): NimTypeKind {.magic: "NGetType", noSideEffect.}
## Returns the type kind of the node 'n' that should represent a type, that ## Returns the type kind of the node 'n' that should represent a type, that
## means the node should have been obtained via `getType`. ## means the node should have been obtained via `getType`.
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal", noSideEffect.} proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.} proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.} proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
proc `symbol=`*(n: PNimrodNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.} proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.}
proc `ident=`*(n: PNimrodNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.} proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
#proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".} #proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".}
# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you # this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
# can easily do: # can easily do:
# let bracket = semCheck([1, 2]) # let bracket = semCheck([1, 2])
# let fake = semCheck(2.0) # let fake = semCheck(2.0)
# bracket[0] = fake # constructs a mixed array with ints and floats! # bracket[0] = fake # constructs a mixed array with ints and floats!
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal", noSideEffect.} proc `strVal=`*(n: NimNode, val: string) {.magic: "NSetStrVal", noSideEffect.}
proc newNimNode*(kind: TNimrodNodeKind, proc newNimNode*(kind: NimNodeKind,
n: PNimrodNode=nil): PNimrodNode {.magic: "NNewNimNode", noSideEffect.} n: NimNode=nil): NimNode {.magic: "NNewNimNode", noSideEffect.}
proc copyNimNode*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimNode", noSideEffect.} proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
proc copyNimTree*(n: PNimrodNode): PNimrodNode {.magic: "NCopyNimTree", noSideEffect.} proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
proc error*(msg: string) {.magic: "NError", benign.} proc error*(msg: string) {.magic: "NError", benign.}
## writes an error message at compile time ## writes an error message at compile time
@ -210,27 +208,27 @@ proc warning*(msg: string) {.magic: "NWarning", benign.}
proc hint*(msg: string) {.magic: "NHint", benign.} proc hint*(msg: string) {.magic: "NHint", benign.}
## writes a hint message at compile time ## writes a hint message at compile time
proc newStrLitNode*(s: string): PNimrodNode {.compileTime, noSideEffect.} = proc newStrLitNode*(s: string): NimNode {.compileTime, noSideEffect.} =
## creates a string literal node from `s` ## creates a string literal node from `s`
result = newNimNode(nnkStrLit) result = newNimNode(nnkStrLit)
result.strVal = s result.strVal = s
proc newIntLitNode*(i: BiggestInt): PNimrodNode {.compileTime.} = proc newIntLitNode*(i: BiggestInt): NimNode {.compileTime.} =
## creates a int literal node from `i` ## creates a int literal node from `i`
result = newNimNode(nnkIntLit) result = newNimNode(nnkIntLit)
result.intVal = i result.intVal = i
proc newFloatLitNode*(f: BiggestFloat): PNimrodNode {.compileTime.} = proc newFloatLitNode*(f: BiggestFloat): NimNode {.compileTime.} =
## creates a float literal node from `f` ## creates a float literal node from `f`
result = newNimNode(nnkFloatLit) result = newNimNode(nnkFloatLit)
result.floatVal = f result.floatVal = f
proc newIdentNode*(i: NimIdent): PNimrodNode {.compileTime.} = proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} =
## creates an identifier node from `i` ## creates an identifier node from `i`
result = newNimNode(nnkIdent) result = newNimNode(nnkIdent)
result.ident = i result.ident = i
proc newIdentNode*(i: string): PNimrodNode {.compileTime.} = proc newIdentNode*(i: string): NimNode {.compileTime.} =
## creates an identifier node from `i` ## creates an identifier node from `i`
result = newNimNode(nnkIdent) result = newNimNode(nnkIdent)
result.ident = !i result.ident = !i
@ -247,7 +245,7 @@ type
{.deprecated: [TBindSymRule: BindSymRule].} {.deprecated: [TBindSymRule: BindSymRule].}
proc bindSym*(ident: string, rule: BindSymRule = brClosed): PNimrodNode {. proc bindSym*(ident: string, rule: BindSymRule = brClosed): NimNode {.
magic: "NBindSym", noSideEffect.} magic: "NBindSym", noSideEffect.}
## creates a node that binds `ident` to a symbol node. The bound symbol ## creates a node that binds `ident` to a symbol node. The bound symbol
## may be an overloaded symbol. ## may be an overloaded symbol.
@ -258,48 +256,48 @@ proc bindSym*(ident: string, rule: BindSymRule = brClosed): PNimrodNode {.
## 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 genSym*(kind: NimSymKind = nskLet; ident = ""): PNimrodNode {. proc genSym*(kind: NimSymKind = nskLet; ident = ""): NimNode {.
magic: "NGenSym", noSideEffect.} magic: "NGenSym", noSideEffect.}
## generates a fresh symbol that is guaranteed to be unique. The symbol ## generates a fresh symbol that is guaranteed to be unique. The symbol
## needs to occur in a declaration context. ## needs to occur in a declaration context.
proc callsite*(): PNimrodNode {.magic: "NCallSite", benign.} proc callsite*(): NimNode {.magic: "NCallSite", benign.}
## returns the AST of the invocation expression that invoked this macro. ## returns the AST of the invocation expression that invoked this macro.
proc toStrLit*(n: PNimrodNode): PNimrodNode {.compileTime.} = proc toStrLit*(n: NimNode): NimNode {.compileTime.} =
## converts the AST `n` to the concrete Nim code and wraps that ## converts the AST `n` to the concrete Nim code and wraps that
## in a string literal node ## in a string literal node
return newStrLitNode(repr(n)) return newStrLitNode(repr(n))
proc lineinfo*(n: PNimrodNode): string {.magic: "NLineInfo", noSideEffect.} proc lineinfo*(n: NimNode): string {.magic: "NLineInfo", noSideEffect.}
## returns the position the node appears in the original source file ## returns the position the node appears in the original source file
## in the form filename(line, col) ## in the form filename(line, col)
proc internalParseExpr(s: string): PNimrodNode {. proc internalParseExpr(s: string): NimNode {.
magic: "ParseExprToAst", noSideEffect.} magic: "ParseExprToAst", noSideEffect.}
proc internalParseStmt(s: string): PNimrodNode {. proc internalParseStmt(s: string): NimNode {.
magic: "ParseStmtToAst", noSideEffect.} magic: "ParseStmtToAst", noSideEffect.}
proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.} proc internalErrorFlag*(): string {.magic: "NError", noSideEffect.}
## Some builtins set an error flag. This is then turned into a proper ## Some builtins set an error flag. This is then turned into a proper
## exception. **Note**: Ordinary application code should not call this. ## exception. **Note**: Ordinary application code should not call this.
proc parseExpr*(s: string): PNimrodNode {.noSideEffect, compileTime.} = proc parseExpr*(s: string): NimNode {.noSideEffect, compileTime.} =
## Compiles the passed string to its AST representation. ## Compiles the passed string to its AST representation.
## Expects a single expression. Raises ``ValueError`` for parsing errors. ## Expects a single expression. Raises ``ValueError`` for parsing errors.
result = internalParseExpr(s) result = internalParseExpr(s)
let x = internalErrorFlag() let x = internalErrorFlag()
if x.len > 0: raise newException(ValueError, x) if x.len > 0: raise newException(ValueError, x)
proc parseStmt*(s: string): PNimrodNode {.noSideEffect, compileTime.} = proc parseStmt*(s: string): NimNode {.noSideEffect, compileTime.} =
## Compiles the passed string to its AST representation. ## Compiles the passed string to its AST representation.
## Expects one or more statements. Raises ``ValueError`` for parsing errors. ## Expects one or more statements. Raises ``ValueError`` for parsing errors.
result = internalParseStmt(s) result = internalParseStmt(s)
let x = internalErrorFlag() let x = internalErrorFlag()
if x.len > 0: raise newException(ValueError, x) if x.len > 0: raise newException(ValueError, x)
proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideEffect.} proc getAst*(macroOrTemplate: expr): NimNode {.magic: "ExpandToAst", noSideEffect.}
## Obtains the AST nodes returned from a macro or template invocation. ## Obtains the AST nodes returned from a macro or template invocation.
## Example: ## Example:
## ##
@ -308,10 +306,10 @@ proc getAst*(macroOrTemplate: expr): PNimrodNode {.magic: "ExpandToAst", noSideE
## macro FooMacro() = ## macro FooMacro() =
## var ast = getAst(BarTemplate()) ## var ast = getAst(BarTemplate())
proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.} proc quote*(bl: stmt, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
## Quasi-quoting operator. ## Quasi-quoting operator.
## Accepts an expression or a block and returns the AST that represents it. ## Accepts an expression or a block and returns the AST that represents it.
## Within the quoted AST, you are able to interpolate PNimrodNode expressions ## Within the quoted AST, you are able to interpolate NimNode expressions
## from the surrounding scope. If no operator is given, quoting is done using ## from the surrounding scope. If no operator is given, quoting is done using
## backticks. Otherwise, the given operator must be used as a prefix operator ## backticks. Otherwise, the given operator must be used as a prefix operator
## for any interpolated expression. The original meaning of the interpolation ## for any interpolated expression. The original meaning of the interpolation
@ -339,26 +337,26 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.
## if not `ex`: ## if not `ex`:
## echo `info` & ": Check failed: " & `expString` ## echo `info` & ": Check failed: " & `expString`
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} = proc expectKind*(n: NimNode, k: NimNodeKind) {.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,
## compilation aborts with an error message. This is useful for writing ## compilation aborts with an error message. This is useful for writing
## macros that check the AST that is passed to them. ## macros that check the AST that is passed to them.
if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind) if n.kind != k: error("Expected a node of kind " & $k & ", got " & $n.kind)
proc expectMinLen*(n: PNimrodNode, min: int) {.compileTime.} = proc expectMinLen*(n: NimNode, min: int) {.compileTime.} =
## checks that `n` has at least `min` children. If this is not the case, ## checks that `n` has at least `min` children. If this is not the case,
## compilation aborts with an error message. This is useful for writing ## compilation aborts with an error message. This is useful for writing
## macros that check its number of arguments. ## macros that check its number of arguments.
if n.len < min: error("macro expects a node with " & $min & " children") if n.len < min: error("macro expects a node with " & $min & " children")
proc expectLen*(n: PNimrodNode, len: int) {.compileTime.} = proc expectLen*(n: NimNode, len: int) {.compileTime.} =
## checks that `n` has exactly `len` children. If this is not the case, ## checks that `n` has exactly `len` children. If this is not the case,
## compilation aborts with an error message. This is useful for writing ## compilation aborts with an error message. This is useful for writing
## macros that check its number of arguments. ## macros that check its number of arguments.
if n.len != len: error("macro expects a node with " & $len & " children") if n.len != len: error("macro expects a node with " & $len & " children")
proc newCall*(theProc: PNimrodNode, proc newCall*(theProc: NimNode,
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = args: varargs[NimNode]): NimNode {.compileTime.} =
## produces a new call node. `theProc` is the proc that is called with ## produces a new call node. `theProc` is the proc that is called with
## the arguments ``args[0..]``. ## the arguments ``args[0..]``.
result = newNimNode(nnkCall) result = newNimNode(nnkCall)
@ -366,7 +364,7 @@ proc newCall*(theProc: PNimrodNode,
result.add(args) result.add(args)
proc newCall*(theProc: NimIdent, proc newCall*(theProc: NimIdent,
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = args: varargs[NimNode]): NimNode {.compileTime.} =
## produces a new call node. `theProc` is the proc that is called with ## produces a new call node. `theProc` is the proc that is called with
## the arguments ``args[0..]``. ## the arguments ``args[0..]``.
result = newNimNode(nnkCall) result = newNimNode(nnkCall)
@ -374,35 +372,35 @@ proc newCall*(theProc: NimIdent,
result.add(args) result.add(args)
proc newCall*(theProc: string, proc newCall*(theProc: string,
args: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = args: varargs[NimNode]): NimNode {.compileTime.} =
## produces a new call node. `theProc` is the proc that is called with ## produces a new call node. `theProc` is the proc that is called with
## the arguments ``args[0..]``. ## the arguments ``args[0..]``.
result = newNimNode(nnkCall) result = newNimNode(nnkCall)
result.add(newIdentNode(theProc)) result.add(newIdentNode(theProc))
result.add(args) result.add(args)
proc newLit*(c: char): PNimrodNode {.compileTime.} = proc newLit*(c: char): NimNode {.compileTime.} =
## produces a new character literal node. ## produces a new character literal node.
result = newNimNode(nnkCharLit) result = newNimNode(nnkCharLit)
result.intVal = ord(c) result.intVal = ord(c)
proc newLit*(i: BiggestInt): PNimrodNode {.compileTime.} = proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
## produces a new integer literal node. ## produces a new integer literal node.
result = newNimNode(nnkIntLit) result = newNimNode(nnkIntLit)
result.intVal = i result.intVal = i
proc newLit*(f: BiggestFloat): PNimrodNode {.compileTime.} = proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
## produces a new float literal node. ## produces a new float literal node.
result = newNimNode(nnkFloatLit) result = newNimNode(nnkFloatLit)
result.floatVal = f result.floatVal = f
proc newLit*(s: string): PNimrodNode {.compileTime.} = proc newLit*(s: string): NimNode {.compileTime.} =
## produces a new string literal node. ## produces a new string literal node.
result = newNimNode(nnkStrLit) result = newNimNode(nnkStrLit)
result.strVal = s result.strVal = s
proc nestList*(theProc: NimIdent, proc nestList*(theProc: NimIdent,
x: PNimrodNode): PNimrodNode {.compileTime.} = x: NimNode): NimNode {.compileTime.} =
## nests the list `x` into a tree of call expressions: ## nests the list `x` into a tree of call expressions:
## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``. ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
var L = x.len var L = x.len
@ -413,11 +411,11 @@ proc nestList*(theProc: NimIdent,
# This could easily user code and so should be fixed in evals.nim somehow. # This could easily user code and so should be fixed in evals.nim somehow.
result = newCall(theProc, x[i], copyNimTree(result)) result = newCall(theProc, x[i], copyNimTree(result))
proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} = proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
## 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) {.benign.} = proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
for i in 0..level-1: res.add " " for i in 0..level-1: res.add " "
res.add(($n.kind).substr(3)) res.add(($n.kind).substr(3))
@ -438,7 +436,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime, benign.} =
result = "" result = ""
traverse(result, 0, n) traverse(result, 0, n)
proc lispRepr*(n: PNimrodNode): string {.compileTime, benign.} = proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
## Convert the AST `n` to a human-readable lisp-like string, ## Convert the AST `n` to a human-readable lisp-like string,
## ##
## See also `repr` and `treeRepr`. ## See also `repr` and `treeRepr`.
@ -485,56 +483,56 @@ macro dumpLispImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.lispRepr
## The ``immediate`` version of `dumpLisp`. ## The ``immediate`` version of `dumpLisp`.
proc newEmptyNode*(): PNimrodNode {.compileTime, noSideEffect.} = proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
## Create a new empty node ## Create a new empty node
result = newNimNode(nnkEmpty) result = newNimNode(nnkEmpty)
proc newStmtList*(stmts: varargs[PNimrodNode]): PNimrodNode {.compileTime.}= proc newStmtList*(stmts: varargs[NimNode]): NimNode {.compileTime.}=
## Create a new statement list ## Create a new statement list
result = newNimNode(nnkStmtList).add(stmts) result = newNimNode(nnkStmtList).add(stmts)
proc newPar*(exprs: varargs[PNimrodNode]): PNimrodNode {.compileTime.}= proc newPar*(exprs: varargs[NimNode]): NimNode {.compileTime.}=
## Create a new parentheses-enclosed expression ## Create a new parentheses-enclosed expression
newNimNode(nnkPar).add(exprs) newNimNode(nnkPar).add(exprs)
proc newBlockStmt*(label, body: PNimrodNode): PNimrodNode {.compileTime.} = proc newBlockStmt*(label, body: NimNode): NimNode {.compileTime.} =
## Create a new block statement with label ## Create a new block statement with label
return newNimNode(nnkBlockStmt).add(label, body) return newNimNode(nnkBlockStmt).add(label, body)
proc newBlockStmt*(body: PNimrodNode): PNimrodNode {.compiletime.} = proc newBlockStmt*(body: NimNode): NimNode {.compiletime.} =
## Create a new block: stmt ## Create a new block: stmt
return newNimNode(nnkBlockStmt).add(newEmptyNode(), body) return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
proc newVarStmt*(name, value: PNimrodNode): PNimrodNode {.compiletime.} = proc newVarStmt*(name, value: NimNode): NimNode {.compiletime.} =
## Create a new var stmt ## Create a new var stmt
return newNimNode(nnkVarSection).add( return newNimNode(nnkVarSection).add(
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value)) newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
proc newLetStmt*(name, value: PNimrodNode): PNimrodNode {.compiletime.} = proc newLetStmt*(name, value: NimNode): NimNode {.compiletime.} =
## Create a new let stmt ## Create a new let stmt
return newNimNode(nnkLetSection).add( return newNimNode(nnkLetSection).add(
newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value)) newNimNode(nnkIdentDefs).add(name, newNimNode(nnkEmpty), value))
proc newConstStmt*(name, value: PNimrodNode): PNimrodNode {.compileTime.} = proc newConstStmt*(name, value: NimNode): NimNode {.compileTime.} =
## Create a new const stmt ## Create a new const stmt
newNimNode(nnkConstSection).add( newNimNode(nnkConstSection).add(
newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value)) newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
proc newAssignment*(lhs, rhs: PNimrodNode): PNimrodNode {.compileTime.} = proc newAssignment*(lhs, rhs: NimNode): NimNode {.compileTime.} =
return newNimNode(nnkAsgn).add(lhs, rhs) return newNimNode(nnkAsgn).add(lhs, rhs)
proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = proc newDotExpr*(a, b: NimNode): NimNode {.compileTime.} =
## Create new dot expression ## Create new dot expression
## a.dot(b) -> `a.b` ## a.dot(b) -> `a.b`
return newNimNode(nnkDotExpr).add(a, b) return newNimNode(nnkDotExpr).add(a, b)
proc newColonExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = proc newColonExpr*(a, b: NimNode): NimNode {.compileTime.} =
## Create new colon expression ## Create new colon expression
## newColonExpr(a, b) -> `a: b` ## newColonExpr(a, b) -> `a: b`
newNimNode(nnkExprColonExpr).add(a, b) newNimNode(nnkExprColonExpr).add(a, b)
proc newIdentDefs*(name, kind: PNimrodNode; proc newIdentDefs*(name, kind: NimNode;
default = newEmptyNode()): PNimrodNode {.compileTime.} = default = newEmptyNode()): NimNode {.compileTime.} =
## Creates a new ``nnkIdentDefs`` node of a specific kind and value. ## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
## ##
## ``nnkIdentDefs`` need to have at least three children, but they can have ## ``nnkIdentDefs`` need to have at least three children, but they can have
@ -565,13 +563,13 @@ proc newIdentDefs*(name, kind: PNimrodNode;
## newStrLitNode("Hello")) ## newStrLitNode("Hello"))
newNimNode(nnkIdentDefs).add(name, kind, default) newNimNode(nnkIdentDefs).add(name, kind, default)
proc newNilLit*(): PNimrodNode {.compileTime.} = proc newNilLit*(): NimNode {.compileTime.} =
## New nil literal shortcut ## New nil literal shortcut
result = newNimNode(nnkNilLit) result = newNimNode(nnkNilLit)
proc high*(node: PNimrodNode): int {.compileTime.} = len(node) - 1 proc high*(node: NimNode): int {.compileTime.} = len(node) - 1
## Return the highest index available for a node ## Return the highest index available for a node
proc last*(node: PNimrodNode): PNimrodNode {.compileTime.} = node[node.high] proc last*(node: NimNode): NimNode {.compileTime.} = node[node.high]
## Return the last item in nodes children. Same as `node[node.high()]` ## Return the last item in nodes children. Same as `node[node.high()]`
@ -581,11 +579,11 @@ const
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit, nnkHiddenCallConv} nnkCallStrLit, nnkHiddenCallConv}
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} = proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind assert n.kind in k, "Expected one of " & $k & ", got " & $n.kind
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()]; proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()];
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} = body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} =
## shortcut for creating a new proc ## shortcut for creating a new proc
## ##
## The ``params`` array must start with the return type of the proc, ## The ``params`` array must start with the return type of the proc,
@ -600,8 +598,8 @@ proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyN
newEmptyNode(), newEmptyNode(),
body) body)
proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]): proc newIfStmt*(branches: varargs[tuple[cond, body: NimNode]]):
PNimrodNode {.compiletime.} = NimNode {.compiletime.} =
## Constructor for ``if`` statements. ## Constructor for ``if`` statements.
## ##
## .. code-block:: nim ## .. code-block:: nim
@ -616,35 +614,35 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]):
result.add(newNimNode(nnkElifBranch).add(i.cond, i.body)) result.add(newNimNode(nnkElifBranch).add(i.cond, i.body))
proc copyChildrenTo*(src, dest: PNimrodNode) {.compileTime.}= proc copyChildrenTo*(src, dest: NimNode) {.compileTime.}=
## Copy all children from `src` to `dest` ## Copy all children from `src` to `dest`
for i in 0 .. < src.len: for i in 0 .. < src.len:
dest.add src[i].copyNimTree dest.add src[i].copyNimTree
template expectRoutine(node: PNimrodNode): stmt = template expectRoutine(node: NimNode): stmt =
expectKind(node, RoutineNodes) expectKind(node, RoutineNodes)
proc name*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = proc name*(someProc: NimNode): NimNode {.compileTime.} =
someProc.expectRoutine someProc.expectRoutine
result = someProc[0] result = someProc[0]
proc `name=`*(someProc: PNimrodNode; val: PNimrodNode) {.compileTime.} = proc `name=`*(someProc: NimNode; val: NimNode) {.compileTime.} =
someProc.expectRoutine someProc.expectRoutine
someProc[0] = val someProc[0] = val
proc params*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = proc params*(someProc: NimNode): NimNode {.compileTime.} =
someProc.expectRoutine someProc.expectRoutine
result = someProc[3] result = someProc[3]
proc `params=`* (someProc: PNimrodNode; params: PNimrodNode) {.compileTime.}= proc `params=`* (someProc: NimNode; params: NimNode) {.compileTime.}=
someProc.expectRoutine someProc.expectRoutine
assert params.kind == nnkFormalParams assert params.kind == nnkFormalParams
someProc[3] = params someProc[3] = params
proc pragma*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = proc pragma*(someProc: NimNode): NimNode {.compileTime.} =
## Get the pragma of a proc type ## Get the pragma of a proc type
## These will be expanded ## These will be expanded
someProc.expectRoutine someProc.expectRoutine
result = someProc[4] result = someProc[4]
proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}= proc `pragma=`*(someProc: NimNode; val: NimNode){.compileTime.}=
## Set the pragma of a proc type ## Set the pragma of a proc type
someProc.expectRoutine someProc.expectRoutine
assert val.kind in {nnkEmpty, nnkPragma} assert val.kind in {nnkEmpty, nnkPragma}
@ -654,7 +652,7 @@ proc `pragma=`*(someProc: PNimrodNode; val: PNimrodNode){.compileTime.}=
template badNodeKind(k; f): stmt{.immediate.} = template badNodeKind(k; f): stmt{.immediate.} =
assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`" assert false, "Invalid node kind " & $k & " for macros.`" & $f & "`"
proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = proc body*(someProc: NimNode): NimNode {.compileTime.} =
case someProc.kind: case someProc.kind:
of RoutineNodes: of RoutineNodes:
return someProc[6] return someProc[6]
@ -665,7 +663,7 @@ proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
else: else:
badNodeKind someProc.kind, "body" badNodeKind someProc.kind, "body"
proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} = proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
case someProc.kind case someProc.kind
of RoutineNodes: of RoutineNodes:
someProc[6] = val someProc[6] = val
@ -676,10 +674,10 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
else: else:
badNodeKind someProc.kind, "body=" badNodeKind someProc.kind, "body="
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime, benign.} proc basename*(a: NimNode): NimNode {.compiletime, benign.}
proc `$`*(node: PNimrodNode): string {.compileTime.} = proc `$`*(node: NimNode): string {.compileTime.} =
## Get the string of an identifier node ## Get the string of an identifier node
case node.kind case node.kind
of nnkIdent: of nnkIdent:
@ -693,14 +691,14 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
else: else:
badNodeKind node.kind, "$" badNodeKind node.kind, "$"
proc ident*(name: string): PNimrodNode {.compileTime,inline.} = newIdentNode(name) proc ident*(name: string): NimNode {.compileTime,inline.} = newIdentNode(name)
## Create a new ident node from a string ## Create a new ident node from a string
iterator children*(n: PNimrodNode): PNimrodNode {.inline.}= iterator children*(n: NimNode): NimNode {.inline.}=
for i in 0 .. high(n): for i in 0 .. high(n):
yield n[i] yield n[i]
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {. template findChild*(n: NimNode; cond: expr): NimNode {.
immediate, dirty.} = immediate, dirty.} =
## Find the first child node matching condition (or nil). ## Find the first child node matching condition (or nil).
## ##
@ -708,14 +706,14 @@ template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
## var res = findChild(n, it.kind == nnkPostfix and ## var res = findChild(n, it.kind == nnkPostfix and
## it.basename.ident == !"foo") ## it.basename.ident == !"foo")
block: block:
var result: PNimrodNode var result: NimNode
for it in n.children: for it in n.children:
if cond: if cond:
result = it result = it
break break
result result
proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} = proc insert*(a: NimNode; pos: int; b: NimNode) {.compileTime.} =
## Insert node B into A at pos ## Insert node B into A at pos
if high(a) < pos: if high(a) < pos:
## add some empty nodes first ## add some empty nodes first
@ -730,7 +728,7 @@ proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} =
a[i + 1] = a[i] a[i + 1] = a[i]
a[pos] = b a[pos] = b
proc basename*(a: PNimrodNode): PNimrodNode = proc basename*(a: NimNode): NimNode =
## Pull an identifier from prefix/postfix expressions ## Pull an identifier from prefix/postfix expressions
case a.kind case a.kind
of nnkIdent: return a of nnkIdent: return a
@ -738,39 +736,39 @@ proc basename*(a: PNimrodNode): PNimrodNode =
else: else:
quit "Do not know how to get basename of ("& treeRepr(a) &")\n"& repr(a) quit "Do not know how to get basename of ("& treeRepr(a) &")\n"& repr(a)
proc `basename=`*(a: PNimrodNode; val: string) {.compileTime.}= proc `basename=`*(a: NimNode; val: string) {.compileTime.}=
case a.kind case a.kind
of nnkIdent: macros.`ident=`(a, !val) of nnkIdent: macros.`ident=`(a, !val)
of nnkPostfix, nnkPrefix: a[1] = ident(val) of nnkPostfix, nnkPrefix: a[1] = ident(val)
else: else:
quit "Do not know how to get basename of ("& treeRepr(a)& ")\n"& repr(a) quit "Do not know how to get basename of ("& treeRepr(a)& ")\n"& repr(a)
proc postfix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} = proc postfix*(node: NimNode; op: string): NimNode {.compileTime.} =
newNimNode(nnkPostfix).add(ident(op), node) newNimNode(nnkPostfix).add(ident(op), node)
proc prefix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} = proc prefix*(node: NimNode; op: string): NimNode {.compileTime.} =
newNimNode(nnkPrefix).add(ident(op), node) newNimNode(nnkPrefix).add(ident(op), node)
proc infix*(a: PNimrodNode; op: string; proc infix*(a: NimNode; op: string;
b: PNimrodNode): PNimrodNode {.compileTime.} = b: NimNode): NimNode {.compileTime.} =
newNimNode(nnkInfix).add(ident(op), a, b) newNimNode(nnkInfix).add(ident(op), a, b)
proc unpackPostfix*(node: PNimrodNode): tuple[node: PNimrodNode; op: string] {. proc unpackPostfix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} = compileTime.} =
node.expectKind nnkPostfix node.expectKind nnkPostfix
result = (node[0], $node[1]) result = (node[0], $node[1])
proc unpackPrefix*(node: PNimrodNode): tuple[node: PNimrodNode; op: string] {. proc unpackPrefix*(node: NimNode): tuple[node: NimNode; op: string] {.
compileTime.} = compileTime.} =
node.expectKind nnkPrefix node.expectKind nnkPrefix
result = (node[0], $node[1]) result = (node[0], $node[1])
proc unpackInfix*(node: PNimrodNode): tuple[left: PNimrodNode; op: string; proc unpackInfix*(node: NimNode): tuple[left: NimNode; op: string;
right: PNimrodNode] {.compileTime.} = right: NimNode] {.compileTime.} =
assert node.kind == nnkInfix assert node.kind == nnkInfix
result = (node[0], $node[1], node[2]) result = (node[0], $node[1], node[2])
proc copy*(node: PNimrodNode): PNimrodNode {.compileTime.} = proc copy*(node: NimNode): NimNode {.compileTime.} =
## An alias for copyNimTree(). ## An alias for copyNimTree().
return node.copyNimTree() return node.copyNimTree()
@ -793,7 +791,7 @@ proc cmpIgnoreStyle(a, b: cstring): int {.noSideEffect.} =
proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0 proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
## Check if two idents are identical. ## Check if two idents are identical.
proc hasArgOfName* (params: PNimrodNode; name: string): bool {.compiletime.}= proc hasArgOfName* (params: NimNode; name: string): bool {.compiletime.}=
## Search nnkFormalParams for an argument. ## Search nnkFormalParams for an argument.
assert params.kind == nnkFormalParams assert params.kind == nnkFormalParams
for i in 1 .. <params.len: for i in 1 .. <params.len:
@ -801,7 +799,7 @@ proc hasArgOfName* (params: PNimrodNode; name: string): bool {.compiletime.}=
if name.eqIdent( $ node[0]): if name.eqIdent( $ node[0]):
return true return true
proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} = proc addIdentIfAbsent*(dest: NimNode, ident: string) {.compiletime.} =
## Add ident to dest if it is not present. This is intended for use ## Add ident to dest if it is not present. This is intended for use
## with pragmas. ## with pragmas.
for node in dest.children: for node in dest.children:
@ -825,5 +823,3 @@ when not defined(booting):
macro payload: stmt {.gensym.} = macro payload: stmt {.gensym.} =
result = parseStmt(e) result = parseStmt(e)
payload() payload()
{.pop.}

View file

@ -1064,13 +1064,13 @@ proc accept*(socket: TAsyncFD,
# -- Await Macro # -- Await Macro
proc skipUntilStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} = proc skipUntilStmtList(node: NimNode): NimNode {.compileTime.} =
# Skips a nest of StmtList's. # Skips a nest of StmtList's.
result = node result = node
if node[0].kind == nnkStmtList: if node[0].kind == nnkStmtList:
result = skipUntilStmtList(node[0]) result = skipUntilStmtList(node[0])
proc skipStmtList(node: PNimrodNode): PNimrodNode {.compileTime.} = proc skipStmtList(node: NimNode): NimNode {.compileTime.} =
result = node result = node
if node[0].kind == nnkStmtList: if node[0].kind == nnkStmtList:
result = node[0] result = node[0]
@ -1098,11 +1098,11 @@ template createCb(retFutureSym, iteratorNameSym,
cb() cb()
#{.pop.} #{.pop.}
proc generateExceptionCheck(futSym, proc generateExceptionCheck(futSym,
tryStmt, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} = tryStmt, rootReceiver, fromNode: NimNode): NimNode {.compileTime.} =
if tryStmt.kind == nnkNilLit: if tryStmt.kind == nnkNilLit:
result = rootReceiver result = rootReceiver
else: else:
var exceptionChecks: seq[tuple[cond, body: PNimrodNode]] = @[] var exceptionChecks: seq[tuple[cond, body: NimNode]] = @[]
let errorNode = newDotExpr(futSym, newIdentNode("error")) let errorNode = newDotExpr(futSym, newIdentNode("error"))
for i in 1 .. <tryStmt.len: for i in 1 .. <tryStmt.len:
let exceptBranch = tryStmt[i] let exceptBranch = tryStmt[i]
@ -1110,7 +1110,7 @@ proc generateExceptionCheck(futSym,
exceptionChecks.add((newIdentNode("true"), exceptBranch[0])) exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
else: else:
var exceptIdentCount = 0 var exceptIdentCount = 0
var ifCond: PNimrodNode var ifCond: NimNode
for i in 0 .. <exceptBranch.len: for i in 0 .. <exceptBranch.len:
let child = exceptBranch[i] let child = exceptBranch[i]
if child.kind == nnkIdent: if child.kind == nnkIdent:
@ -1144,10 +1144,10 @@ proc generateExceptionCheck(futSym,
) )
result.add elseNode result.add elseNode
template createVar(result: var PNimrodNode, futSymName: string, template createVar(result: var NimNode, futSymName: string,
asyncProc: PNimrodNode, asyncProc: NimNode,
valueReceiver, rootReceiver: expr, valueReceiver, rootReceiver: expr,
fromNode: PNimrodNode) = fromNode: NimNode) =
result = newNimNode(nnkStmtList, fromNode) result = newNimNode(nnkStmtList, fromNode)
var futSym = genSym(nskVar, "future") var futSym = genSym(nskVar, "future")
result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
@ -1155,9 +1155,9 @@ template createVar(result: var PNimrodNode, futSymName: string,
valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode) result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
proc processBody(node, retFutureSym: PNimrodNode, proc processBody(node, retFutureSym: NimNode,
subTypeIsVoid: bool, subTypeIsVoid: bool,
tryStmt: PNimrodNode): PNimrodNode {.compileTime.} = tryStmt: NimNode): NimNode {.compileTime.} =
#echo(node.treeRepr) #echo(node.treeRepr)
result = node result = node
case node.kind case node.kind
@ -1183,7 +1183,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x result = newNimNode(nnkYieldStmt, node).add(node[1]) # -> yield x
of nnkCall, nnkCommand: of nnkCall, nnkCommand:
# await foo(p, x) # await foo(p, x)
var futureValue: PNimrodNode var futureValue: NimNode
result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue, result.createVar("future" & $node[1][0].toStrLit, node[1], futureValue,
futureValue, node) futureValue, node)
else: else:
@ -1232,8 +1232,8 @@ proc processBody(node, retFutureSym: PNimrodNode,
# working in ``except``? # working in ``except``?
tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil) tryBody[1] = processBody(n[1], retFutureSym, subTypeIsVoid, nil)
proc processForTry(n: PNimrodNode, i: var int, proc processForTry(n: NimNode, i: var int,
res: PNimrodNode): bool {.compileTime.} = res: NimNode): bool {.compileTime.} =
## Transforms the body of the tryStmt. Does not transform the ## Transforms the body of the tryStmt. Does not transform the
## body in ``except``. ## body in ``except``.
## Returns true if the tryStmt node was transformed into an ifStmt. ## Returns true if the tryStmt node was transformed into an ifStmt.
@ -1275,7 +1275,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
for i in 0 .. <result.len: for i in 0 .. <result.len:
result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt) result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt)
proc getName(node: PNimrodNode): string {.compileTime.} = proc getName(node: NimNode): string {.compileTime.} =
case node.kind case node.kind
of nnkPostfix: of nnkPostfix:
return $node[1].ident return $node[1].ident

View file

@ -12,7 +12,7 @@
import macros import macros
proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} = proc createProcType(p, b: NimNode): NimNode {.compileTime.} =
#echo treeRepr(p) #echo treeRepr(p)
#echo treeRepr(b) #echo treeRepr(b)
result = newNimNode(nnkProcTy) result = newNimNode(nnkProcTy)
@ -44,7 +44,7 @@ proc createProcType(p, b: PNimrodNode): PNimrodNode {.compileTime.} =
formalParams.add identDefs formalParams.add identDefs
else: else:
error("Incorrect type list in proc type declaration.") error("Incorrect type list in proc type declaration.")
result.add formalParams result.add formalParams
result.add newEmptyNode() result.add newEmptyNode()
#echo(treeRepr(result)) #echo(treeRepr(result))
@ -59,10 +59,10 @@ macro `=>`*(p, b: expr): expr {.immediate.} =
## f(2, 2) ## f(2, 2)
## ##
## passTwoAndTwo((x, y) => x + y) # 4 ## passTwoAndTwo((x, y) => x + y) # 4
#echo treeRepr(p) #echo treeRepr(p)
#echo(treeRepr(b)) #echo(treeRepr(b))
var params: seq[PNimrodNode] = @[newIdentNode("auto")] var params: seq[NimNode] = @[newIdentNode("auto")]
case p.kind case p.kind
of nnkPar: of nnkPar:
@ -118,7 +118,7 @@ macro `->`*(p, b: expr): expr {.immediate.} =
## ##
## proc pass2(f: (float, float) -> float): float = ## proc pass2(f: (float, float) -> float): float =
## f(2, 2) ## f(2, 2)
## ##
## # is the same as: ## # is the same as:
## ##
## proc pass2(f: proc (x, y: float): float): float = ## proc pass2(f: proc (x, y: float): float): float =

View file

@ -12,7 +12,7 @@
## as ``from htmlgen import nil`` and then fully qualify the macros. ## as ``from htmlgen import nil`` and then fully qualify the macros.
## ##
## ##
## This module implements a simple `XML`:idx: and `HTML`:idx: code ## This module implements a simple `XML`:idx: and `HTML`:idx: code
## generator. Each commonly used HTML tag has a corresponding macro ## generator. Each commonly used HTML tag has a corresponding macro
## that generates a string with its HTML representation. ## that generates a string with its HTML representation.
## ##
@ -21,9 +21,9 @@
## .. code-block:: Nim ## .. code-block:: Nim
## var nim = "Nim" ## var nim = "Nim"
## echo h1(a(href="http://nim-lang.org", nim)) ## echo h1(a(href="http://nim-lang.org", nim))
## ##
## Writes the string:: ## Writes the string::
## ##
## <h1><a href="http://nim-lang.org">Nim</a></h1> ## <h1><a href="http://nim-lang.org">Nim</a></h1>
## ##
@ -36,16 +36,16 @@ const
"onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup " "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup "
commonAttr* = coreAttr & eventAttr commonAttr* = coreAttr & eventAttr
proc getIdent(e: PNimrodNode): string {.compileTime.} = proc getIdent(e: NimNode): string {.compileTime.} =
case e.kind case e.kind
of nnkIdent: result = normalize($e.ident) of nnkIdent: result = normalize($e.ident)
of nnkAccQuoted: of nnkAccQuoted:
result = getIdent(e[0]) result = getIdent(e[0])
for i in 1 .. e.len-1: for i in 1 .. e.len-1:
result.add getIdent(e[i]) result.add getIdent(e[i])
else: error("cannot extract identifier from node: " & toStrLit(e).strVal) else: error("cannot extract identifier from node: " & toStrLit(e).strVal)
proc delete[T](s: var seq[T], attr: T): bool = proc delete[T](s: var seq[T], attr: T): bool =
var idx = find(s, attr) var idx = find(s, attr)
if idx >= 0: if idx >= 0:
var L = s.len var L = s.len
@ -53,10 +53,10 @@ proc delete[T](s: var seq[T], attr: T): bool =
setLen(s, L-1) setLen(s, L-1)
result = true result = true
proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "", proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "",
isLeaf = false): PNimrodNode {.compileTime.} = isLeaf = false): NimNode {.compileTime.} =
## use this procedure to define a new XML tag ## use this procedure to define a new XML tag
# copy the attributes; when iterating over them these lists # copy the attributes; when iterating over them these lists
# will be modified, so that each attribute is only given one value # will be modified, so that each attribute is only given one value
var req = split(reqAttr) var req = split(reqAttr)
@ -66,7 +66,7 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
result.add(newStrLitNode(tag)) result.add(newStrLitNode(tag))
# first pass over attributes: # first pass over attributes:
for i in 1..e.len-1: for i in 1..e.len-1:
if e[i].kind == nnkExprEqExpr: if e[i].kind == nnkExprEqExpr:
var name = getIdent(e[i][0]) var name = getIdent(e[i][0])
if delete(req, name) or delete(opt, name): if delete(req, name) or delete(opt, name):
result.add(newStrLitNode(" ")) result.add(newStrLitNode(" "))
@ -81,7 +81,7 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
error(req[0] & " attribute for '" & tag & "' element expected") error(req[0] & " attribute for '" & tag & "' element expected")
if isLeaf: if isLeaf:
for i in 1..e.len-1: for i in 1..e.len-1:
if e[i].kind != nnkExprEqExpr: if e[i].kind != nnkExprEqExpr:
error("element " & tag & " cannot be nested") error("element " & tag & " cannot be nested")
result.add(newStrLitNode(" />")) result.add(newStrLitNode(" />"))
else: else:
@ -95,389 +95,389 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string, optAttr = "", reqAttr = "",
result = nestList(!"&", result) result = nestList(!"&", result)
macro a*(e: expr): expr {.immediate.} = macro a*(e: expr): expr {.immediate.} =
## generates the HTML ``a`` element. ## generates the HTML ``a`` element.
let e = callsite() 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 {.immediate.} = macro acronym*(e: expr): expr {.immediate.} =
## generates the HTML ``acronym`` element. ## generates the HTML ``acronym`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "acronym", commonAttr) result = xmlCheckedTag(e, "acronym", commonAttr)
macro address*(e: expr): expr {.immediate.} = macro address*(e: expr): expr {.immediate.} =
## generates the HTML ``address`` element. ## generates the HTML ``address`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "address", commonAttr) result = xmlCheckedTag(e, "address", commonAttr)
macro area*(e: expr): expr {.immediate.} = macro area*(e: expr): expr {.immediate.} =
## generates the HTML ``area`` element. ## generates the HTML ``area`` element.
let e = callsite() 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 {.immediate.} = macro b*(e: expr): expr {.immediate.} =
## generates the HTML ``b`` element. ## generates the HTML ``b`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "b", commonAttr) result = xmlCheckedTag(e, "b", commonAttr)
macro base*(e: expr): expr {.immediate.} = macro base*(e: expr): expr {.immediate.} =
## generates the HTML ``base`` element. ## generates the HTML ``base`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "base", "", "href", true) result = xmlCheckedTag(e, "base", "", "href", true)
macro big*(e: expr): expr {.immediate.} = macro big*(e: expr): expr {.immediate.} =
## generates the HTML ``big`` element. ## generates the HTML ``big`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "big", commonAttr) result = xmlCheckedTag(e, "big", commonAttr)
macro blockquote*(e: expr): expr {.immediate.} = macro blockquote*(e: expr): expr {.immediate.} =
## generates the HTML ``blockquote`` element. ## generates the HTML ``blockquote`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr) result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr)
macro body*(e: expr): expr {.immediate.} = macro body*(e: expr): expr {.immediate.} =
## generates the HTML ``body`` element. ## generates the HTML ``body`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "body", commonAttr) result = xmlCheckedTag(e, "body", commonAttr)
macro br*(e: expr): expr {.immediate.} = macro br*(e: expr): expr {.immediate.} =
## generates the HTML ``br`` element. ## generates the HTML ``br`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "br", "", "", true) result = xmlCheckedTag(e, "br", "", "", true)
macro button*(e: expr): expr {.immediate.} = macro button*(e: expr): expr {.immediate.} =
## generates the HTML ``button`` element. ## generates the HTML ``button`` element.
let e = callsite() 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 {.immediate.} = macro caption*(e: expr): expr {.immediate.} =
## generates the HTML ``caption`` element. ## generates the HTML ``caption`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "caption", commonAttr) result = xmlCheckedTag(e, "caption", commonAttr)
macro cite*(e: expr): expr {.immediate.} = macro cite*(e: expr): expr {.immediate.} =
## generates the HTML ``cite`` element. ## generates the HTML ``cite`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "cite", commonAttr) result = xmlCheckedTag(e, "cite", commonAttr)
macro code*(e: expr): expr {.immediate.} = macro code*(e: expr): expr {.immediate.} =
## generates the HTML ``code`` element. ## generates the HTML ``code`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "code", commonAttr) result = xmlCheckedTag(e, "code", commonAttr)
macro col*(e: expr): expr {.immediate.} = macro col*(e: expr): expr {.immediate.} =
## generates the HTML ``col`` element. ## generates the HTML ``col`` element.
let e = callsite() 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 {.immediate.} = macro colgroup*(e: expr): expr {.immediate.} =
## generates the HTML ``colgroup`` element. ## generates the HTML ``colgroup`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr) result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
macro dd*(e: expr): expr {.immediate.} = macro dd*(e: expr): expr {.immediate.} =
## generates the HTML ``dd`` element. ## generates the HTML ``dd`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "dd", commonAttr) result = xmlCheckedTag(e, "dd", commonAttr)
macro del*(e: expr): expr {.immediate.} = macro del*(e: expr): expr {.immediate.} =
## generates the HTML ``del`` element. ## generates the HTML ``del`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr) result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr)
macro dfn*(e: expr): expr {.immediate.} = macro dfn*(e: expr): expr {.immediate.} =
## generates the HTML ``dfn`` element. ## generates the HTML ``dfn`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "dfn", commonAttr) result = xmlCheckedTag(e, "dfn", commonAttr)
macro `div`*(e: expr): expr {.immediate.} = macro `div`*(e: expr): expr {.immediate.} =
## generates the HTML ``div`` element. ## generates the HTML ``div`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "div", commonAttr) result = xmlCheckedTag(e, "div", commonAttr)
macro dl*(e: expr): expr {.immediate.} = macro dl*(e: expr): expr {.immediate.} =
## generates the HTML ``dl`` element. ## generates the HTML ``dl`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "dl", commonAttr) result = xmlCheckedTag(e, "dl", commonAttr)
macro dt*(e: expr): expr {.immediate.} = macro dt*(e: expr): expr {.immediate.} =
## generates the HTML ``dt`` element. ## generates the HTML ``dt`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "dt", commonAttr) result = xmlCheckedTag(e, "dt", commonAttr)
macro em*(e: expr): expr {.immediate.} = macro em*(e: expr): expr {.immediate.} =
## generates the HTML ``em`` element. ## generates the HTML ``em`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "em", commonAttr) result = xmlCheckedTag(e, "em", commonAttr)
macro fieldset*(e: expr): expr {.immediate.} = macro fieldset*(e: expr): expr {.immediate.} =
## generates the HTML ``fieldset`` element. ## generates the HTML ``fieldset`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "fieldset", commonAttr) result = xmlCheckedTag(e, "fieldset", commonAttr)
macro form*(e: expr): expr {.immediate.} = macro form*(e: expr): expr {.immediate.} =
## generates the HTML ``form`` element. ## generates the HTML ``form`` element.
let e = callsite() 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 {.immediate.} = macro h1*(e: expr): expr {.immediate.} =
## generates the HTML ``h1`` element. ## generates the HTML ``h1`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h1", commonAttr) result = xmlCheckedTag(e, "h1", commonAttr)
macro h2*(e: expr): expr {.immediate.} = macro h2*(e: expr): expr {.immediate.} =
## generates the HTML ``h2`` element. ## generates the HTML ``h2`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h2", commonAttr) result = xmlCheckedTag(e, "h2", commonAttr)
macro h3*(e: expr): expr {.immediate.} = macro h3*(e: expr): expr {.immediate.} =
## generates the HTML ``h3`` element. ## generates the HTML ``h3`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h3", commonAttr) result = xmlCheckedTag(e, "h3", commonAttr)
macro h4*(e: expr): expr {.immediate.} = macro h4*(e: expr): expr {.immediate.} =
## generates the HTML ``h4`` element. ## generates the HTML ``h4`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h4", commonAttr) result = xmlCheckedTag(e, "h4", commonAttr)
macro h5*(e: expr): expr {.immediate.} = macro h5*(e: expr): expr {.immediate.} =
## generates the HTML ``h5`` element. ## generates the HTML ``h5`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h5", commonAttr) result = xmlCheckedTag(e, "h5", commonAttr)
macro h6*(e: expr): expr {.immediate.} = macro h6*(e: expr): expr {.immediate.} =
## generates the HTML ``h6`` element. ## generates the HTML ``h6`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "h6", commonAttr) result = xmlCheckedTag(e, "h6", commonAttr)
macro head*(e: expr): expr {.immediate.} = macro head*(e: expr): expr {.immediate.} =
## generates the HTML ``head`` element. ## generates the HTML ``head`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "head", "profile") result = xmlCheckedTag(e, "head", "profile")
macro html*(e: expr): expr {.immediate.} = macro html*(e: expr): expr {.immediate.} =
## generates the HTML ``html`` element. ## generates the HTML ``html`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "html", "xmlns", "") result = xmlCheckedTag(e, "html", "xmlns", "")
macro hr*(): expr {.immediate.} = macro hr*(): expr {.immediate.} =
## generates the HTML ``hr`` element. ## generates the HTML ``hr`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "hr", commonAttr, "", true) result = xmlCheckedTag(e, "hr", commonAttr, "", true)
macro i*(e: expr): expr {.immediate.} = macro i*(e: expr): expr {.immediate.} =
## generates the HTML ``i`` element. ## generates the HTML ``i`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "i", commonAttr) result = xmlCheckedTag(e, "i", commonAttr)
macro img*(e: expr): expr {.immediate.} = macro img*(e: expr): expr {.immediate.} =
## generates the HTML ``img`` element. ## generates the HTML ``img`` element.
let e = callsite() 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 {.immediate.} = macro input*(e: expr): expr {.immediate.} =
## generates the HTML ``input`` element. ## generates the HTML ``input`` element.
let e = callsite() 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 {.immediate.} = macro ins*(e: expr): expr {.immediate.} =
## generates the HTML ``ins`` element. ## generates the HTML ``ins`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr) result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr)
macro kbd*(e: expr): expr {.immediate.} = macro kbd*(e: expr): expr {.immediate.} =
## generates the HTML ``kbd`` element. ## generates the HTML ``kbd`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "kbd", commonAttr) result = xmlCheckedTag(e, "kbd", commonAttr)
macro label*(e: expr): expr {.immediate.} = macro label*(e: expr): expr {.immediate.} =
## generates the HTML ``label`` element. ## generates the HTML ``label`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr) result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
macro legend*(e: expr): expr {.immediate.} = macro legend*(e: expr): expr {.immediate.} =
## generates the HTML ``legend`` element. ## generates the HTML ``legend`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr) result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
macro li*(e: expr): expr {.immediate.} = macro li*(e: expr): expr {.immediate.} =
## generates the HTML ``li`` element. ## generates the HTML ``li`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "li", commonAttr) result = xmlCheckedTag(e, "li", commonAttr)
macro link*(e: expr): expr {.immediate.} = macro link*(e: expr): expr {.immediate.} =
## generates the HTML ``link`` element. ## generates the HTML ``link`` element.
let e = callsite() 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 {.immediate.} = macro map*(e: expr): expr {.immediate.} =
## generates the HTML ``map`` element. ## generates the HTML ``map`` element.
let e = callsite() 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 {.immediate.} = macro meta*(e: expr): expr {.immediate.} =
## generates the HTML ``meta`` element. ## generates the HTML ``meta`` element.
let e = callsite() 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 {.immediate.} = macro noscript*(e: expr): expr {.immediate.} =
## generates the HTML ``noscript`` element. ## generates the HTML ``noscript`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "noscript", commonAttr) result = xmlCheckedTag(e, "noscript", commonAttr)
macro `object`*(e: expr): expr {.immediate.} = macro `object`*(e: expr): expr {.immediate.} =
## generates the HTML ``object`` element. ## generates the HTML ``object`` element.
let e = callsite() 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 {.immediate.} = macro ol*(e: expr): expr {.immediate.} =
## generates the HTML ``ol`` element. ## generates the HTML ``ol`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "ol", commonAttr) result = xmlCheckedTag(e, "ol", commonAttr)
macro optgroup*(e: expr): expr {.immediate.} = macro optgroup*(e: expr): expr {.immediate.} =
## generates the HTML ``optgroup`` element. ## generates the HTML ``optgroup`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false) result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false)
macro option*(e: expr): expr {.immediate.} = macro option*(e: expr): expr {.immediate.} =
## generates the HTML ``option`` element. ## generates the HTML ``option`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "option", "selected value" & commonAttr) result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
macro p*(e: expr): expr {.immediate.} = macro p*(e: expr): expr {.immediate.} =
## generates the HTML ``p`` element. ## generates the HTML ``p`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "p", commonAttr) result = xmlCheckedTag(e, "p", commonAttr)
macro param*(e: expr): expr {.immediate.} = macro param*(e: expr): expr {.immediate.} =
## generates the HTML ``param`` element. ## generates the HTML ``param`` element.
let e = callsite() 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 {.immediate.} = macro pre*(e: expr): expr {.immediate.} =
## generates the HTML ``pre`` element. ## generates the HTML ``pre`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "pre", commonAttr) result = xmlCheckedTag(e, "pre", commonAttr)
macro q*(e: expr): expr {.immediate.} = macro q*(e: expr): expr {.immediate.} =
## generates the HTML ``q`` element. ## generates the HTML ``q`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "q", "cite" & commonAttr) result = xmlCheckedTag(e, "q", "cite" & commonAttr)
macro samp*(e: expr): expr {.immediate.} = macro samp*(e: expr): expr {.immediate.} =
## generates the HTML ``samp`` element. ## generates the HTML ``samp`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "samp", commonAttr) result = xmlCheckedTag(e, "samp", commonAttr)
macro script*(e: expr): expr {.immediate.} = macro script*(e: expr): expr {.immediate.} =
## generates the HTML ``script`` element. ## generates the HTML ``script`` element.
let e = callsite() 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 {.immediate.} = macro select*(e: expr): expr {.immediate.} =
## generates the HTML ``select`` element. ## generates the HTML ``select`` element.
let e = callsite() 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 {.immediate.} = macro small*(e: expr): expr {.immediate.} =
## generates the HTML ``small`` element. ## generates the HTML ``small`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "small", commonAttr) result = xmlCheckedTag(e, "small", commonAttr)
macro span*(e: expr): expr {.immediate.} = macro span*(e: expr): expr {.immediate.} =
## generates the HTML ``span`` element. ## generates the HTML ``span`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "span", commonAttr) result = xmlCheckedTag(e, "span", commonAttr)
macro strong*(e: expr): expr {.immediate.} = macro strong*(e: expr): expr {.immediate.} =
## generates the HTML ``strong`` element. ## generates the HTML ``strong`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "strong", commonAttr) result = xmlCheckedTag(e, "strong", commonAttr)
macro style*(e: expr): expr {.immediate.} = macro style*(e: expr): expr {.immediate.} =
## generates the HTML ``style`` element. ## generates the HTML ``style`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "style", "media title", "type") result = xmlCheckedTag(e, "style", "media title", "type")
macro sub*(e: expr): expr {.immediate.} = macro sub*(e: expr): expr {.immediate.} =
## generates the HTML ``sub`` element. ## generates the HTML ``sub`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "sub", commonAttr) result = xmlCheckedTag(e, "sub", commonAttr)
macro sup*(e: expr): expr {.immediate.} = macro sup*(e: expr): expr {.immediate.} =
## generates the HTML ``sup`` element. ## generates the HTML ``sup`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "sup", commonAttr) result = xmlCheckedTag(e, "sup", commonAttr)
macro table*(e: expr): expr {.immediate.} = macro table*(e: expr): expr {.immediate.} =
## generates the HTML ``table`` element. ## generates the HTML ``table`` element.
let e = callsite() 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 {.immediate.} = macro tbody*(e: expr): expr {.immediate.} =
## generates the HTML ``tbody`` element. ## generates the HTML ``tbody`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr) result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
macro td*(e: expr): expr {.immediate.} = macro td*(e: expr): expr {.immediate.} =
## generates the HTML ``td`` element. ## generates the HTML ``td`` element.
let e = callsite() 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 {.immediate.} = macro textarea*(e: expr): expr {.immediate.} =
## generates the HTML ``textarea`` element. ## generates the HTML ``textarea`` element.
let e = callsite() 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 {.immediate.} = macro tfoot*(e: expr): expr {.immediate.} =
## generates the HTML ``tfoot`` element. ## generates the HTML ``tfoot`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr) result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
macro th*(e: expr): expr {.immediate.} = macro th*(e: expr): expr {.immediate.} =
## generates the HTML ``th`` element. ## generates the HTML ``th`` element.
let e = callsite() 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 {.immediate.} = macro thead*(e: expr): expr {.immediate.} =
## generates the HTML ``thead`` element. ## generates the HTML ``thead`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "thead", "align valign" & commonAttr) result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
macro title*(e: expr): expr {.immediate.} = macro title*(e: expr): expr {.immediate.} =
## generates the HTML ``title`` element. ## generates the HTML ``title`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "title") result = xmlCheckedTag(e, "title")
macro tr*(e: expr): expr {.immediate.} = macro tr*(e: expr): expr {.immediate.} =
## generates the HTML ``tr`` element. ## generates the HTML ``tr`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "tr", "align valign" & commonAttr) result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
macro tt*(e: expr): expr {.immediate.} = macro tt*(e: expr): expr {.immediate.} =
## generates the HTML ``tt`` element. ## generates the HTML ``tt`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "tt", commonAttr) result = xmlCheckedTag(e, "tt", commonAttr)
macro ul*(e: expr): expr {.immediate.} = macro ul*(e: expr): expr {.immediate.} =
## generates the HTML ``ul`` element. ## generates the HTML ``ul`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "ul", commonAttr) result = xmlCheckedTag(e, "ul", commonAttr)
macro `var`*(e: expr): expr {.immediate.} = macro `var`*(e: expr): expr {.immediate.} =
## generates the HTML ``var`` element. ## generates the HTML ``var`` element.
let e = callsite() let e = callsite()
result = xmlCheckedTag(e, "var", commonAttr) result = xmlCheckedTag(e, "var", commonAttr)

View file

@ -8,8 +8,8 @@
# #
## This module implements a simple high performance `JSON`:idx: ## This module implements a simple high performance `JSON`:idx:
## parser. JSON (JavaScript Object Notation) is a lightweight ## parser. JSON (JavaScript Object Notation) is a lightweight
## data-interchange format that is easy for humans to read and write ## data-interchange format that is easy for humans to read and write
## (unlike XML). It is easy for machines to parse and generate. ## (unlike XML). It is easy for machines to parse and generate.
## JSON is based on a subset of the JavaScript Programming Language, ## JSON is based on a subset of the JavaScript Programming Language,
## Standard ECMA-262 3rd Edition - December 1999. ## Standard ECMA-262 3rd Edition - December 1999.
@ -50,10 +50,10 @@
## } ## }
## ] ## ]
import import
hashes, strutils, lexbase, streams, unicode, macros hashes, strutils, lexbase, streams, unicode, macros
type type
JsonEventKind* = enum ## enumeration of all events that may occur when parsing JsonEventKind* = enum ## enumeration of all events that may occur when parsing
jsonError, ## an error occurred during parsing jsonError, ## an error occurred during parsing
jsonEof, ## end of file reached jsonEof, ## end of file reached
@ -67,7 +67,7 @@ type
jsonObjectEnd, ## end of an object: the ``}`` token jsonObjectEnd, ## end of an object: the ``}`` token
jsonArrayStart, ## start of an array: the ``[`` token jsonArrayStart, ## start of an array: the ``[`` token
jsonArrayEnd ## start of an array: the ``]`` token jsonArrayEnd ## start of an array: the ``]`` token
TTokKind = enum # must be synchronized with TJsonEventKind! TTokKind = enum # must be synchronized with TJsonEventKind!
tkError, tkError,
tkEof, tkEof,
@ -83,7 +83,7 @@ type
tkBracketRi, tkBracketRi,
tkColon, tkColon,
tkComma tkComma
JsonError* = enum ## enumeration that lists all errors that can occur JsonError* = enum ## enumeration that lists all errors that can occur
errNone, ## no error errNone, ## no error
errInvalidToken, ## invalid token errInvalidToken, ## invalid token
@ -96,8 +96,8 @@ type
errEOC_Expected, ## ``*/`` expected errEOC_Expected, ## ``*/`` expected
errEofExpected, ## EOF expected errEofExpected, ## EOF expected
errExprExpected ## expr expected errExprExpected ## expr expected
ParserState = enum ParserState = enum
stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma, stateEof, stateStart, stateObject, stateArray, stateExpectArrayComma,
stateExpectObjectComma, stateExpectColon, stateExpectValue stateExpectObjectComma, stateExpectColon, stateExpectValue
@ -111,7 +111,7 @@ type
{.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError, {.deprecated: [TJsonEventKind: JsonEventKind, TJsonError: JsonError,
TJsonParser: JsonParser].} TJsonParser: JsonParser].}
const const
errorMessages: array [JsonError, string] = [ errorMessages: array [JsonError, string] = [
"no error", "no error",
@ -146,56 +146,56 @@ proc open*(my: var JsonParser, input: Stream, filename: string) =
my.state = @[stateStart] my.state = @[stateStart]
my.kind = jsonError my.kind = jsonError
my.a = "" my.a = ""
proc close*(my: var JsonParser) {.inline.} = proc close*(my: var JsonParser) {.inline.} =
## closes the parser `my` and its associated input stream. ## closes the parser `my` and its associated input stream.
lexbase.close(my) lexbase.close(my)
proc str*(my: JsonParser): string {.inline.} = proc str*(my: JsonParser): string {.inline.} =
## returns the character data for the events: ``jsonInt``, ``jsonFloat``, ## returns the character data for the events: ``jsonInt``, ``jsonFloat``,
## ``jsonString`` ## ``jsonString``
assert(my.kind in {jsonInt, jsonFloat, jsonString}) assert(my.kind in {jsonInt, jsonFloat, jsonString})
return my.a return my.a
proc getInt*(my: JsonParser): BiggestInt {.inline.} = proc getInt*(my: JsonParser): BiggestInt {.inline.} =
## returns the number for the event: ``jsonInt`` ## returns the number for the event: ``jsonInt``
assert(my.kind == jsonInt) assert(my.kind == jsonInt)
return parseBiggestInt(my.a) return parseBiggestInt(my.a)
proc getFloat*(my: JsonParser): float {.inline.} = proc getFloat*(my: JsonParser): float {.inline.} =
## returns the number for the event: ``jsonFloat`` ## returns the number for the event: ``jsonFloat``
assert(my.kind == jsonFloat) assert(my.kind == jsonFloat)
return parseFloat(my.a) return parseFloat(my.a)
proc kind*(my: JsonParser): JsonEventKind {.inline.} = proc kind*(my: JsonParser): JsonEventKind {.inline.} =
## returns the current event type for the JSON parser ## returns the current event type for the JSON parser
return my.kind return my.kind
proc getColumn*(my: JsonParser): int {.inline.} = proc getColumn*(my: JsonParser): int {.inline.} =
## get the current column the parser has arrived at. ## get the current column the parser has arrived at.
result = getColNumber(my, my.bufpos) result = getColNumber(my, my.bufpos)
proc getLine*(my: JsonParser): int {.inline.} = proc getLine*(my: JsonParser): int {.inline.} =
## get the current line the parser has arrived at. ## get the current line the parser has arrived at.
result = my.lineNumber result = my.lineNumber
proc getFilename*(my: JsonParser): string {.inline.} = proc getFilename*(my: JsonParser): string {.inline.} =
## get the filename of the file that the parser processes. ## get the filename of the file that the parser processes.
result = my.filename result = my.filename
proc errorMsg*(my: JsonParser): string = proc errorMsg*(my: JsonParser): string =
## returns a helpful error message for the event ``jsonError`` ## returns a helpful error message for the event ``jsonError``
assert(my.kind == jsonError) assert(my.kind == jsonError)
result = "$1($2, $3) Error: $4" % [ result = "$1($2, $3) Error: $4" % [
my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]] my.filename, $getLine(my), $getColumn(my), errorMessages[my.err]]
proc errorMsgExpected*(my: JsonParser, e: string): string = proc errorMsgExpected*(my: JsonParser, e: string): string =
## returns an error message "`e` expected" in the same format as the ## returns an error message "`e` expected" in the same format as the
## other error messages ## other error messages
result = "$1($2, $3) Error: $4" % [ result = "$1($2, $3) Error: $4" % [
my.filename, $getLine(my), $getColumn(my), e & " expected"] my.filename, $getLine(my), $getColumn(my), e & " expected"]
proc handleHexChar(c: char, x: var int): bool = proc handleHexChar(c: char, x: var int): bool =
result = true # Success result = true # Success
case c case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0')) of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@ -208,8 +208,8 @@ proc parseString(my: var JsonParser): TTokKind =
var pos = my.bufpos + 1 var pos = my.bufpos + 1
var buf = my.buf var buf = my.buf
while true: while true:
case buf[pos] case buf[pos]
of '\0': of '\0':
my.err = errQuoteExpected my.err = errQuoteExpected
result = tkError result = tkError
break break
@ -218,21 +218,21 @@ proc parseString(my: var JsonParser): TTokKind =
break break
of '\\': of '\\':
case buf[pos+1] case buf[pos+1]
of '\\', '"', '\'', '/': of '\\', '"', '\'', '/':
add(my.a, buf[pos+1]) add(my.a, buf[pos+1])
inc(pos, 2) inc(pos, 2)
of 'b': of 'b':
add(my.a, '\b') add(my.a, '\b')
inc(pos, 2) inc(pos, 2)
of 'f': of 'f':
add(my.a, '\f') add(my.a, '\f')
inc(pos, 2) inc(pos, 2)
of 'n': of 'n':
add(my.a, '\L') add(my.a, '\L')
inc(pos, 2) inc(pos, 2)
of 'r': of 'r':
add(my.a, '\C') add(my.a, '\C')
inc(pos, 2) inc(pos, 2)
of 't': of 't':
add(my.a, '\t') add(my.a, '\t')
inc(pos, 2) inc(pos, 2)
@ -244,15 +244,15 @@ proc parseString(my: var JsonParser): TTokKind =
if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos)
if handleHexChar(buf[pos], r): inc(pos) if handleHexChar(buf[pos], r): inc(pos)
add(my.a, toUTF8(Rune(r))) add(my.a, toUTF8(Rune(r)))
else: else:
# don't bother with the error # don't bother with the error
add(my.a, buf[pos]) add(my.a, buf[pos])
inc(pos) inc(pos)
of '\c': of '\c':
pos = lexbase.handleCR(my, pos) pos = lexbase.handleCR(my, pos)
buf = my.buf buf = my.buf
add(my.a, '\c') add(my.a, '\c')
of '\L': of '\L':
pos = lexbase.handleLF(my, pos) pos = lexbase.handleLF(my, pos)
buf = my.buf buf = my.buf
add(my.a, '\L') add(my.a, '\L')
@ -260,25 +260,25 @@ proc parseString(my: var JsonParser): TTokKind =
add(my.a, buf[pos]) add(my.a, buf[pos])
inc(pos) inc(pos)
my.bufpos = pos # store back my.bufpos = pos # store back
proc skip(my: var JsonParser) = proc skip(my: var JsonParser) =
var pos = my.bufpos var pos = my.bufpos
var buf = my.buf var buf = my.buf
while true: while true:
case buf[pos] case buf[pos]
of '/': of '/':
if buf[pos+1] == '/': if buf[pos+1] == '/':
# skip line comment: # skip line comment:
inc(pos, 2) inc(pos, 2)
while true: while true:
case buf[pos] case buf[pos]
of '\0': of '\0':
break break
of '\c': of '\c':
pos = lexbase.handleCR(my, pos) pos = lexbase.handleCR(my, pos)
buf = my.buf buf = my.buf
break break
of '\L': of '\L':
pos = lexbase.handleLF(my, pos) pos = lexbase.handleLF(my, pos)
buf = my.buf buf = my.buf
break break
@ -288,44 +288,44 @@ proc skip(my: var JsonParser) =
# skip long comment: # skip long comment:
inc(pos, 2) inc(pos, 2)
while true: while true:
case buf[pos] case buf[pos]
of '\0': of '\0':
my.err = errEOC_Expected my.err = errEOC_Expected
break break
of '\c': of '\c':
pos = lexbase.handleCR(my, pos) pos = lexbase.handleCR(my, pos)
buf = my.buf buf = my.buf
of '\L': of '\L':
pos = lexbase.handleLF(my, pos) pos = lexbase.handleLF(my, pos)
buf = my.buf buf = my.buf
of '*': of '*':
inc(pos) inc(pos)
if buf[pos] == '/': if buf[pos] == '/':
inc(pos) inc(pos)
break break
else: else:
inc(pos) inc(pos)
else: else:
break break
of ' ', '\t': of ' ', '\t':
inc(pos) inc(pos)
of '\c': of '\c':
pos = lexbase.handleCR(my, pos) pos = lexbase.handleCR(my, pos)
buf = my.buf buf = my.buf
of '\L': of '\L':
pos = lexbase.handleLF(my, pos) pos = lexbase.handleLF(my, pos)
buf = my.buf buf = my.buf
else: else:
break break
my.bufpos = pos my.bufpos = pos
proc parseNumber(my: var JsonParser) = proc parseNumber(my: var JsonParser) =
var pos = my.bufpos var pos = my.bufpos
var buf = my.buf var buf = my.buf
if buf[pos] == '-': if buf[pos] == '-':
add(my.a, '-') add(my.a, '-')
inc(pos) inc(pos)
if buf[pos] == '.': if buf[pos] == '.':
add(my.a, "0.") add(my.a, "0.")
inc(pos) inc(pos)
else: else:
@ -350,7 +350,7 @@ proc parseNumber(my: var JsonParser) =
inc(pos) inc(pos)
my.bufpos = pos my.bufpos = pos
proc parseName(my: var JsonParser) = proc parseName(my: var JsonParser) =
var pos = my.bufpos var pos = my.bufpos
var buf = my.buf var buf = my.buf
if buf[pos] in IdentStartChars: if buf[pos] in IdentStartChars:
@ -359,11 +359,11 @@ proc parseName(my: var JsonParser) =
inc(pos) inc(pos)
my.bufpos = pos my.bufpos = pos
proc getTok(my: var JsonParser): TTokKind = proc getTok(my: var JsonParser): TTokKind =
setLen(my.a, 0) setLen(my.a, 0)
skip(my) # skip whitespace, comments skip(my) # skip whitespace, comments
case my.buf[my.bufpos] case my.buf[my.bufpos]
of '-', '.', '0'..'9': of '-', '.', '0'..'9':
parseNumber(my) parseNumber(my)
if {'.', 'e', 'E'} in my.a: if {'.', 'e', 'E'} in my.a:
result = tkFloat result = tkFloat
@ -393,17 +393,17 @@ proc getTok(my: var JsonParser): TTokKind =
result = tkEof result = tkEof
of 'a'..'z', 'A'..'Z', '_': of 'a'..'z', 'A'..'Z', '_':
parseName(my) parseName(my)
case my.a case my.a
of "null": result = tkNull of "null": result = tkNull
of "true": result = tkTrue of "true": result = tkTrue
of "false": result = tkFalse of "false": result = tkFalse
else: result = tkError else: result = tkError
else: else:
inc(my.bufpos) inc(my.bufpos)
result = tkError result = tkError
my.tok = result my.tok = result
proc next*(my: var JsonParser) = proc next*(my: var JsonParser) =
## retrieves the first/next event. This controls the parser. ## retrieves the first/next event. This controls the parser.
var tk = getTok(my) var tk = getTok(my)
var i = my.state.len-1 var i = my.state.len-1
@ -416,13 +416,13 @@ proc next*(my: var JsonParser) =
else: else:
my.kind = jsonError my.kind = jsonError
my.err = errEofExpected my.err = errEofExpected
of stateStart: of stateStart:
# tokens allowed? # tokens allowed?
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state[i] = stateEof # expect EOF next! my.state[i] = stateEof # expect EOF next!
my.kind = JsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateArray) # we expect any my.state.add(stateArray) # we expect any
my.kind = jsonArrayStart my.kind = jsonArrayStart
of tkCurlyLe: of tkCurlyLe:
@ -433,12 +433,12 @@ proc next*(my: var JsonParser) =
else: else:
my.kind = jsonError my.kind = jsonError
my.err = errEofExpected my.err = errEofExpected
of stateObject: of stateObject:
case tk case tk
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state.add(stateExpectColon) my.state.add(stateExpectColon)
my.kind = JsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateExpectColon) my.state.add(stateExpectColon)
my.state.add(stateArray) my.state.add(stateArray)
my.kind = jsonArrayStart my.kind = jsonArrayStart
@ -457,7 +457,7 @@ proc next*(my: var JsonParser) =
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state.add(stateExpectArrayComma) # expect value next! my.state.add(stateExpectArrayComma) # expect value next!
my.kind = JsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state.add(stateExpectArrayComma) my.state.add(stateExpectArrayComma)
my.state.add(stateArray) my.state.add(stateArray)
my.kind = jsonArrayStart my.kind = jsonArrayStart
@ -472,8 +472,8 @@ proc next*(my: var JsonParser) =
my.kind = jsonError my.kind = jsonError
my.err = errBracketRiExpected my.err = errBracketRiExpected
of stateExpectArrayComma: of stateExpectArrayComma:
case tk case tk
of tkComma: of tkComma:
discard my.state.pop() discard my.state.pop()
next(my) next(my)
of tkBracketRi: of tkBracketRi:
@ -484,8 +484,8 @@ proc next*(my: var JsonParser) =
my.kind = jsonError my.kind = jsonError
my.err = errBracketRiExpected my.err = errBracketRiExpected
of stateExpectObjectComma: of stateExpectObjectComma:
case tk case tk
of tkComma: of tkComma:
discard my.state.pop() discard my.state.pop()
next(my) next(my)
of tkCurlyRi: of tkCurlyRi:
@ -495,9 +495,9 @@ proc next*(my: var JsonParser) =
else: else:
my.kind = jsonError my.kind = jsonError
my.err = errCurlyRiExpected my.err = errCurlyRiExpected
of stateExpectColon: of stateExpectColon:
case tk case tk
of tkColon: of tkColon:
my.state[i] = stateExpectValue my.state[i] = stateExpectValue
next(my) next(my)
else: else:
@ -508,7 +508,7 @@ proc next*(my: var JsonParser) =
of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull: of tkString, tkInt, tkFloat, tkTrue, tkFalse, tkNull:
my.state[i] = stateExpectObjectComma my.state[i] = stateExpectObjectComma
my.kind = JsonEventKind(ord(tk)) my.kind = JsonEventKind(ord(tk))
of tkBracketLe: of tkBracketLe:
my.state[i] = stateExpectObjectComma my.state[i] = stateExpectObjectComma
my.state.add(stateArray) my.state.add(stateArray)
my.kind = jsonArrayStart my.kind = jsonArrayStart
@ -532,8 +532,8 @@ type
JString, JString,
JObject, JObject,
JArray JArray
JsonNode* = ref JsonNodeObj ## JSON node JsonNode* = ref JsonNodeObj ## JSON node
JsonNodeObj* {.acyclic.} = object JsonNodeObj* {.acyclic.} = object
case kind*: JsonNodeKind case kind*: JsonNodeKind
of JString: of JString:
@ -644,7 +644,7 @@ proc `%`*(elements: openArray[JsonNode]): JsonNode =
newSeq(result.elems, elements.len) newSeq(result.elems, elements.len)
for i, p in pairs(elements): result.elems[i] = p for i, p in pairs(elements): result.elems[i] = p
proc toJson(x: PNimrodNode): PNimrodNode {.compiletime.} = proc toJson(x: NimNode): NimNode {.compiletime.} =
case x.kind case x.kind
of nnkBracket: of nnkBracket:
result = newNimNode(nnkBracket) result = newNimNode(nnkBracket)
@ -672,7 +672,7 @@ proc `==`* (a,b: JsonNode): bool =
if a.isNil: if a.isNil:
if b.isNil: return true if b.isNil: return true
return false return false
elif b.isNil or a.kind != b.kind: elif b.isNil or a.kind != b.kind:
return false return false
else: else:
return case a.kind return case a.kind
@ -709,7 +709,7 @@ proc hash* (n:JsonNode): THash =
of JNull: of JNull:
result = hash(0) result = hash(0)
proc len*(n: JsonNode): int = proc len*(n: JsonNode): int =
## If `n` is a `JArray`, it returns the number of elements. ## If `n` is a `JArray`, it returns the number of elements.
## If `n` is a `JObject`, it returns the number of pairs. ## If `n` is a `JObject`, it returns the number of pairs.
## Else it returns 0. ## Else it returns 0.
@ -727,7 +727,7 @@ proc `[]`*(node: JsonNode, name: string): JsonNode =
if key == name: if key == name:
return item return item
return nil return nil
proc `[]`*(node: JsonNode, index: int): JsonNode = proc `[]`*(node: JsonNode, index: int): JsonNode =
## Gets the node at `index` in an Array. Result is undefined if `index` ## Gets the node at `index` in an Array. Result is undefined if `index`
## is out of bounds ## is out of bounds
@ -744,12 +744,12 @@ proc hasKey*(node: JsonNode, key: string): bool =
proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key) proc existsKey*(node: JsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
## Deprecated for `hasKey` ## Deprecated for `hasKey`
proc add*(father, child: JsonNode) = proc add*(father, child: JsonNode) =
## Adds `child` to a JArray node `father`. ## Adds `child` to a JArray node `father`.
assert father.kind == JArray assert father.kind == JArray
father.elems.add(child) father.elems.add(child)
proc add*(obj: JsonNode, key: string, val: JsonNode) = proc add*(obj: JsonNode, key: string, val: JsonNode) =
## Adds ``(key, val)`` pair to the JObject node `obj`. For speed ## Adds ``(key, val)`` pair to the JObject node `obj`. For speed
## reasons no check for duplicate keys is performed! ## reasons no check for duplicate keys is performed!
## But ``[]=`` performs the check. ## But ``[]=`` performs the check.
@ -760,7 +760,7 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
## Sets a field from a `JObject`. Performs a check for duplicate keys. ## Sets a field from a `JObject`. Performs a check for duplicate keys.
assert(obj.kind == JObject) assert(obj.kind == JObject)
for i in 0..obj.fields.len-1: for i in 0..obj.fields.len-1:
if obj.fields[i].key == key: if obj.fields[i].key == key:
obj.fields[i].val = val obj.fields[i].val = val
return return
obj.fields.add((key, val)) obj.fields.add((key, val))
@ -815,17 +815,17 @@ proc copy*(p: JsonNode): JsonNode =
# ------------- pretty printing ---------------------------------------------- # ------------- pretty printing ----------------------------------------------
proc indent(s: var string, i: int) = proc indent(s: var string, i: int) =
s.add(spaces(i)) s.add(spaces(i))
proc newIndent(curr, indent: int, ml: bool): int = proc newIndent(curr, indent: int, ml: bool): int =
if ml: return curr + indent if ml: return curr + indent
else: return indent else: return indent
proc nl(s: var string, ml: bool) = proc nl(s: var string, ml: bool) =
if ml: s.add("\n") if ml: s.add("\n")
proc escapeJson*(s: string): string = proc escapeJson*(s: string): string =
## Converts a string `s` to its JSON representation. ## Converts a string `s` to its JSON representation.
result = newStringOfCap(s.len + s.len shr 3) result = newStringOfCap(s.len + s.len shr 3)
result.add("\"") result.add("\"")
@ -842,13 +842,13 @@ proc escapeJson*(s: string): string =
result.add(toHex(r, 4)) result.add(toHex(r, 4))
result.add("\"") result.add("\"")
proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true, proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
lstArr = false, currIndent = 0) = lstArr = false, currIndent = 0) =
case node.kind case node.kind
of JObject: of JObject:
if currIndent != 0 and not lstArr: result.nl(ml) if currIndent != 0 and not lstArr: result.nl(ml)
result.indent(currIndent) # Indentation result.indent(currIndent) # Indentation
if node.fields.len > 0: if node.fields.len > 0:
result.add("{") result.add("{")
result.nl(ml) # New line result.nl(ml) # New line
for i in 0..len(node.fields)-1: for i in 0..len(node.fields)-1:
@ -856,17 +856,17 @@ proc toPretty(result: var string, node: JsonNode, indent = 2, ml = true,
result.add(", ") result.add(", ")
result.nl(ml) # New Line result.nl(ml) # New Line
# Need to indent more than { # Need to indent more than {
result.indent(newIndent(currIndent, indent, ml)) result.indent(newIndent(currIndent, indent, ml))
result.add(escapeJson(node.fields[i].key)) result.add(escapeJson(node.fields[i].key))
result.add(": ") result.add(": ")
toPretty(result, node.fields[i].val, indent, ml, false, toPretty(result, node.fields[i].val, indent, ml, false,
newIndent(currIndent, indent, ml)) newIndent(currIndent, indent, ml))
result.nl(ml) result.nl(ml)
result.indent(currIndent) # indent the same as { result.indent(currIndent) # indent the same as {
result.add("}") result.add("}")
else: else:
result.add("{}") result.add("{}")
of JString: of JString:
if lstArr: result.indent(currIndent) if lstArr: result.indent(currIndent)
result.add(escapeJson(node.str)) result.add(escapeJson(node.str))
of JInt: of JInt:
@ -934,11 +934,11 @@ iterator mpairs*(node: var JsonNode): var tuple[key: string, val: JsonNode] =
for keyVal in mitems(node.fields): for keyVal in mitems(node.fields):
yield keyVal yield keyVal
proc eat(p: var JsonParser, tok: TTokKind) = proc eat(p: var JsonParser, tok: TTokKind) =
if p.tok == tok: discard getTok(p) if p.tok == tok: discard getTok(p)
else: raiseParseErr(p, tokToStr[tok]) else: raiseParseErr(p, tokToStr[tok])
proc parseJson(p: var JsonParser): JsonNode = proc parseJson(p: var JsonParser): JsonNode =
## Parses JSON from a JSON Parser `p`. ## Parses JSON from a JSON Parser `p`.
case p.tok case p.tok
of tkString: of tkString:
@ -955,17 +955,17 @@ proc parseJson(p: var JsonParser): JsonNode =
of tkTrue: of tkTrue:
result = newJBool(true) result = newJBool(true)
discard getTok(p) discard getTok(p)
of tkFalse: of tkFalse:
result = newJBool(false) result = newJBool(false)
discard getTok(p) discard getTok(p)
of tkNull: of tkNull:
result = newJNull() result = newJNull()
discard getTok(p) discard getTok(p)
of tkCurlyLe: of tkCurlyLe:
result = newJObject() result = newJObject()
discard getTok(p) discard getTok(p)
while p.tok != tkCurlyRi: while p.tok != tkCurlyRi:
if p.tok != tkString: if p.tok != tkString:
raiseParseErr(p, "string literal as key expected") raiseParseErr(p, "string literal as key expected")
var key = p.a var key = p.a
discard getTok(p) discard getTok(p)
@ -978,7 +978,7 @@ proc parseJson(p: var JsonParser): JsonNode =
of tkBracketLe: of tkBracketLe:
result = newJArray() result = newJArray()
discard getTok(p) discard getTok(p)
while p.tok != tkBracketRi: while p.tok != tkBracketRi:
result.add(parseJson(p)) result.add(parseJson(p))
if p.tok != tkComma: break if p.tok != tkComma: break
discard getTok(p) discard getTok(p)
@ -1098,10 +1098,10 @@ when false:
of jsonObjectEnd: echo("}") of jsonObjectEnd: echo("}")
of jsonArrayStart: echo("[") of jsonArrayStart: echo("[")
of jsonArrayEnd: echo("]") of jsonArrayEnd: echo("]")
close(x) close(x)
# { "json": 5 } # { "json": 5 }
# To get that we shall use, obj["json"] # To get that we shall use, obj["json"]
when isMainModule: when isMainModule:

View file

@ -47,7 +47,7 @@ type
{.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]} {.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]}
var var
abortOnError* {.threadvar.}: bool abortOnError* {.threadvar.}: bool
outputLevel* {.threadvar.}: OutputLevel outputLevel* {.threadvar.}: OutputLevel
colorOutput* {.threadvar.}: bool colorOutput* {.threadvar.}: bool
@ -144,7 +144,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
when compiles(string($value)): when compiles(string($value)):
checkpoint(name & " was " & $value) checkpoint(name & " was " & $value)
proc inspectArgs(exp: PNimrodNode) = proc inspectArgs(exp: NimNode) =
for i in 1 .. <exp.len: for i in 1 .. <exp.len:
if exp[i].kind notin nnkLiterals: if exp[i].kind notin nnkLiterals:
inc counter inc counter
@ -202,7 +202,7 @@ template require*(conditions: stmt): stmt {.immediate, dirty.} =
macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} = macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
let exp = callsite() let exp = callsite()
template expectBody(errorTypes, lineInfoLit: expr, template expectBody(errorTypes, lineInfoLit: expr,
body: stmt): PNimrodNode {.dirty.} = body: stmt): NimNode {.dirty.} =
try: try:
body body
checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.") checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")

View file

@ -12,20 +12,20 @@
import macros, strtabs import macros, strtabs
type type
XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s. XmlNode* = ref XmlNodeObj ## an XML tree consists of ``PXmlNode``'s.
XmlNodeKind* = enum ## different kinds of ``PXmlNode``'s XmlNodeKind* = enum ## different kinds of ``PXmlNode``'s
xnText, ## a text element xnText, ## a text element
xnElement, ## an element with 0 or more children xnElement, ## an element with 0 or more children
xnCData, ## a CDATA node xnCData, ## a CDATA node
xnEntity, ## an entity (like ``&thing;``) xnEntity, ## an entity (like ``&thing;``)
xnComment ## an XML comment xnComment ## an XML comment
XmlAttributes* = StringTableRef ## an alias for a string to string mapping XmlAttributes* = StringTableRef ## an alias for a string to string mapping
XmlNodeObj {.acyclic.} = object XmlNodeObj {.acyclic.} = object
case k: XmlNodeKind # private, use the kind() proc to read this field. case k: XmlNodeKind # private, use the kind() proc to read this field.
of xnText, xnComment, xnCData, xnEntity: of xnText, xnComment, xnCData, xnEntity:
fText: string fText: string
of xnElement: of xnElement:
fTag: string fTag: string
@ -41,34 +41,34 @@ proc newXmlNode(kind: XmlNodeKind): XmlNode =
new(result) new(result)
result.k = kind result.k = kind
proc newElement*(tag: string): XmlNode = proc newElement*(tag: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`. ## creates a new ``PXmlNode`` of kind ``xnText`` with the given `tag`.
result = newXmlNode(xnElement) result = newXmlNode(xnElement)
result.fTag = tag result.fTag = tag
result.s = @[] result.s = @[]
# init attributes lazily to safe memory # init attributes lazily to safe memory
proc newText*(text: string): XmlNode = proc newText*(text: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnText`` with the text `text`. ## creates a new ``PXmlNode`` of kind ``xnText`` with the text `text`.
result = newXmlNode(xnText) result = newXmlNode(xnText)
result.fText = text result.fText = text
proc newComment*(comment: string): XmlNode = proc newComment*(comment: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `comment`. ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `comment`.
result = newXmlNode(xnComment) result = newXmlNode(xnComment)
result.fText = comment result.fText = comment
proc newCData*(cdata: string): XmlNode = proc newCData*(cdata: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `cdata`. ## creates a new ``PXmlNode`` of kind ``xnComment`` with the text `cdata`.
result = newXmlNode(xnCData) result = newXmlNode(xnCData)
result.fText = cdata result.fText = cdata
proc newEntity*(entity: string): XmlNode = proc newEntity*(entity: string): XmlNode =
## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`. ## creates a new ``PXmlNode`` of kind ``xnEntity`` with the text `entity`.
result = newXmlNode(xnCData) result = newXmlNode(xnCData)
result.fText = entity result.fText = entity
proc text*(n: XmlNode): string {.inline.} = proc text*(n: XmlNode): string {.inline.} =
## gets the associated text with the node `n`. `n` can be a CDATA, Text, ## gets the associated text with the node `n`. `n` can be a CDATA, Text,
## comment, or entity node. ## comment, or entity node.
assert n.k in {xnText, xnComment, xnCData, xnEntity} assert n.k in {xnText, xnComment, xnCData, xnEntity}
@ -93,16 +93,16 @@ proc innerText*(n: XmlNode): string =
for i in 0 .. n.s.len-1: for i in 0 .. n.s.len-1:
if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText) if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText)
proc tag*(n: XmlNode): string {.inline.} = proc tag*(n: XmlNode): string {.inline.} =
## gets the tag name of `n`. `n` has to be an ``xnElement`` node. ## gets the tag name of `n`. `n` has to be an ``xnElement`` node.
assert n.k == xnElement assert n.k == xnElement
result = n.fTag result = n.fTag
proc add*(father, son: XmlNode) {.inline.} = proc add*(father, son: XmlNode) {.inline.} =
## adds the child `son` to `father`. ## adds the child `son` to `father`.
add(father.s, son) add(father.s, son)
proc len*(n: XmlNode): int {.inline.} = proc len*(n: XmlNode): int {.inline.} =
## returns the number `n`'s children. ## returns the number `n`'s children.
if n.k == xnElement: result = len(n.s) if n.k == xnElement: result = len(n.s)
@ -110,38 +110,38 @@ proc kind*(n: XmlNode): XmlNodeKind {.inline.} =
## returns `n`'s kind. ## returns `n`'s kind.
result = n.k result = n.k
proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} = proc `[]`* (n: XmlNode, i: int): XmlNode {.inline.} =
## returns the `i`'th child of `n`. ## returns the `i`'th child of `n`.
assert n.k == xnElement assert n.k == xnElement
result = n.s[i] result = n.s[i]
proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} = proc mget* (n: var XmlNode, i: int): var XmlNode {.inline.} =
## returns the `i`'th child of `n` so that it can be modified ## returns the `i`'th child of `n` so that it can be modified
assert n.k == xnElement assert n.k == xnElement
result = n.s[i] result = n.s[i]
iterator items*(n: XmlNode): XmlNode {.inline.} = iterator items*(n: XmlNode): XmlNode {.inline.} =
## iterates over any child of `n`. ## iterates over any child of `n`.
assert n.k == xnElement assert n.k == xnElement
for i in 0 .. n.len-1: yield n[i] for i in 0 .. n.len-1: yield n[i]
iterator mitems*(n: var XmlNode): var XmlNode {.inline.} = iterator mitems*(n: var XmlNode): var XmlNode {.inline.} =
## iterates over any child of `n`. ## iterates over any child of `n`.
assert n.k == xnElement assert n.k == xnElement
for i in 0 .. n.len-1: yield mget(n, i) for i in 0 .. n.len-1: yield mget(n, i)
proc attrs*(n: XmlNode): XmlAttributes {.inline.} = proc attrs*(n: XmlNode): XmlAttributes {.inline.} =
## gets the attributes belonging to `n`. ## gets the attributes belonging to `n`.
## Returns `nil` if attributes have not been initialised for this node. ## Returns `nil` if attributes have not been initialised for this node.
assert n.k == xnElement assert n.k == xnElement
result = n.fAttr result = n.fAttr
proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} = proc `attrs=`*(n: XmlNode, attr: XmlAttributes) {.inline.} =
## sets the attributes belonging to `n`. ## sets the attributes belonging to `n`.
assert n.k == xnElement assert n.k == xnElement
n.fAttr = attr n.fAttr = attr
proc attrsLen*(n: XmlNode): int {.inline.} = proc attrsLen*(n: XmlNode): int {.inline.} =
## returns the number of `n`'s attributes. ## returns the number of `n`'s attributes.
assert n.k == xnElement assert n.k == xnElement
if not isNil(n.fAttr): result = len(n.fAttr) if not isNil(n.fAttr): result = len(n.fAttr)
@ -151,12 +151,12 @@ proc clientData*(n: XmlNode): int {.inline.} =
## parser and generator. ## parser and generator.
result = n.fClientData result = n.fClientData
proc `clientData=`*(n: XmlNode, data: int) {.inline.} = proc `clientData=`*(n: XmlNode, data: int) {.inline.} =
## sets the client data of `n`. The client data field is used by the HTML ## sets the client data of `n`. The client data field is used by the HTML
## parser and generator. ## parser and generator.
n.fClientData = data n.fClientData = data
proc addEscaped*(result: var string, s: string) = proc addEscaped*(result: var string, s: string) =
## same as ``result.add(escape(s))``, but more efficient. ## same as ``result.add(escape(s))``, but more efficient.
for c in items(s): for c in items(s):
case c case c
@ -168,8 +168,8 @@ proc addEscaped*(result: var string, s: string) =
of '/': result.add("&#x2F;") of '/': result.add("&#x2F;")
else: result.add(c) else: result.add(c)
proc escape*(s: string): string = proc escape*(s: string): string =
## escapes `s` for inclusion into an XML document. ## escapes `s` for inclusion into an XML document.
## Escapes these characters: ## Escapes these characters:
## ##
## ------------ ------------------- ## ------------ -------------------
@ -184,26 +184,26 @@ proc escape*(s: string): string =
## ------------ ------------------- ## ------------ -------------------
result = newStringOfCap(s.len) result = newStringOfCap(s.len)
addEscaped(result, s) addEscaped(result, s)
proc addIndent(result: var string, indent: int) = proc addIndent(result: var string, indent: int) =
result.add("\n") result.add("\n")
for i in 1..indent: result.add(' ') for i in 1..indent: result.add(' ')
proc noWhitespace(n: XmlNode): bool = proc noWhitespace(n: XmlNode): bool =
#for i in 1..n.len-1: #for i in 1..n.len-1:
# if n[i].kind != n[0].kind: return true # if n[i].kind != n[0].kind: return true
for i in 0..n.len-1: for i in 0..n.len-1:
if n[i].kind in {xnText, xnEntity}: return true if n[i].kind in {xnText, xnEntity}: return true
proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) = proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
## adds the textual representation of `n` to `result`. ## adds the textual representation of `n` to `result`.
if n == nil: return if n == nil: return
case n.k case n.k
of xnElement: of xnElement:
result.add('<') result.add('<')
result.add(n.fTag) result.add(n.fTag)
if not isNil(n.fAttr): if not isNil(n.fAttr):
for key, val in pairs(n.fAttr): for key, val in pairs(n.fAttr):
result.add(' ') result.add(' ')
result.add(key) result.add(key)
result.add("=\"") result.add("=\"")
@ -217,7 +217,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
# because this would be wrong. For example: ``a<b>b</b>`` is # because this would be wrong. For example: ``a<b>b</b>`` is
# different from ``a <b>b</b>``. # different from ``a <b>b</b>``.
for i in 0..n.len-1: result.add(n[i], indent+indWidth, indWidth) for i in 0..n.len-1: result.add(n[i], indent+indWidth, indWidth)
else: else:
for i in 0..n.len-1: for i in 0..n.len-1:
result.addIndent(indent+indWidth) result.addIndent(indent+indWidth)
result.add(n[i], indent+indWidth, indWidth) result.add(n[i], indent+indWidth, indWidth)
@ -227,7 +227,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
result.add("</") result.add("</")
result.add(n.fTag) result.add(n.fTag)
result.add(">") result.add(">")
else: else:
result.add(" />") result.add(" />")
of xnText: of xnText:
result.addEscaped(n.fText) result.addEscaped(n.fText)
@ -245,7 +245,7 @@ proc add*(result: var string, n: XmlNode, indent = 0, indWidth = 2) =
result.add(';') result.add(';')
const const
xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" xmlHeader* = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
## header to use for complete XML output ## header to use for complete XML output
proc `$`*(n: XmlNode): string = proc `$`*(n: XmlNode): string =
@ -255,21 +255,21 @@ proc `$`*(n: XmlNode): string =
result.add(n) result.add(n)
proc newXmlTree*(tag: string, children: openArray[XmlNode], proc newXmlTree*(tag: string, children: openArray[XmlNode],
attributes: XmlAttributes = nil): XmlNode = attributes: XmlAttributes = nil): XmlNode =
## creates a new XML tree with `tag`, `children` and `attributes` ## creates a new XML tree with `tag`, `children` and `attributes`
result = newXmlNode(xnElement) result = newXmlNode(xnElement)
result.fTag = tag result.fTag = tag
newSeq(result.s, children.len) newSeq(result.s, children.len)
for i in 0..children.len-1: result.s[i] = children[i] for i in 0..children.len-1: result.s[i] = children[i]
result.fAttr = attributes result.fAttr = attributes
proc xmlConstructor(e: PNimrodNode): PNimrodNode {.compileTime.} = proc xmlConstructor(e: NimNode): NimNode {.compileTime.} =
expectLen(e, 2) expectLen(e, 2)
var a = e[1] var a = e[1]
if a.kind == nnkCall: if a.kind == nnkCall:
result = newCall("newXmlTree", toStrLit(a[0])) result = newCall("newXmlTree", toStrLit(a[0]))
var attrs = newNimNode(nnkBracket, a) var attrs = newNimNode(nnkBracket, a)
var newStringTabCall = newCall("newStringTable", attrs, var newStringTabCall = newCall("newStringTable", attrs,
newIdentNode("modeCaseSensitive")) newIdentNode("modeCaseSensitive"))
var elements = newNimNode(nnkBracket, a) var elements = newNimNode(nnkBracket, a)
for i in 1..a.len-1: for i in 1..a.len-1:
@ -280,13 +280,13 @@ proc xmlConstructor(e: PNimrodNode): PNimrodNode {.compileTime.} =
else: else:
elements.add(a[i]) elements.add(a[i])
result.add(elements) result.add(elements)
if attrs.len > 1: if attrs.len > 1:
#echo repr(newStringTabCall) #echo repr(newStringTabCall)
result.add(newStringTabCall) result.add(newStringTabCall)
else: else:
result = newCall("newXmlTree", toStrLit(a)) result = newCall("newXmlTree", toStrLit(a))
macro `<>`*(x: expr): expr {.immediate.} = macro `<>`*(x: expr): expr {.immediate.} =
## Constructor macro for XML. Example usage: ## Constructor macro for XML. Example usage:
## ##
## .. code-block:: nim ## .. code-block:: nim

View file

@ -3149,15 +3149,9 @@ proc shallow*(s: var string) {.noSideEffect, inline.} =
type type
NimNodeObj = object NimNodeObj = object
when defined(nimnode): NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj
type ## represents a Nim AST node. Macros operate on this type.
NimNode* {.magic: "PNimrodNode".} = ref NimNodeObj {.deprecated: [PNimrodNode: NimNode].}
## represents a Nim AST node. Macros operate on this type.
{.deprecated: [PNimrodNode: NimNode].}
else:
type
PNimrodNode* {.magic: "PNimrodNode".} = ref NimNodeObj
## represents a Nim AST node. Macros operate on this type.
when false: when false:
template eval*(blk: stmt): stmt = template eval*(blk: stmt): stmt =

View file

@ -58,7 +58,7 @@ macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
## Expect docstrings ## Expect docstrings
let exp = callsite() let exp = callsite()
template expectBody(errorTypes, lineInfoLit: expr, template expectBody(errorTypes, lineInfoLit: expr,
body: stmt): PNimrodNode {.dirty.} = body: stmt): NimNode {.dirty.} =
try: try:
body body
assert false assert false

View file

@ -20,13 +20,13 @@ import strutils
# This serves the same purpose as D's `alias` parameters for types, used heavily # This serves the same purpose as D's `alias` parameters for types, used heavily
# in its popular `ranges` and `algorithm` modules. # in its popular `ranges` and `algorithm` modules.
var exprNodes {.compileTime.} = newSeq[PNimrodNode]() var exprNodes {.compileTime.} = newSeq[NimNode]()
proc refExpr(exprNode: PNimrodNode): string {.compileTime.} = proc refExpr(exprNode: NimNode): string {.compileTime.} =
exprNodes.add exprNode.copy exprNodes.add exprNode.copy
"expr" & $(exprNodes.len - 1) "expr" & $(exprNodes.len - 1)
proc derefExpr(exprRef: string): PNimrodNode {.compileTime.} = proc derefExpr(exprRef: string): NimNode {.compileTime.} =
exprNodes[parseInt(exprRef[4 .. -1])] exprNodes[parseInt(exprRef[4 .. -1])]
#=============================================================================== #===============================================================================

View file

@ -46,13 +46,13 @@ echotest()
# bug #1103 # bug #1103
type type
Td = tuple Td = tuple
a:string a:string
b:int b:int
proc get_data(d: Td) : string {.compileTime.} = proc get_data(d: Td) : string {.compileTime.} =
result = d.a # Works if a literal string is used here. result = d.a # Works if a literal string is used here.
# Bugs if line A or B is active. Works with C # Bugs if line A or B is active. Works with C
result &= "aa" # A result &= "aa" # A
#result.add("aa") # B #result.add("aa") # B
@ -69,7 +69,7 @@ m(s)
# bug #933 # bug #933
proc nilcheck(): PNimrodNode {.compileTime.} = proc nilcheck(): NimNode {.compileTime.} =
echo(result == nil) # true echo(result == nil) # true
echo(result.isNil) # true echo(result.isNil) # true
echo(repr(result)) # nil echo(repr(result)) # nil

View file

@ -1,4 +1,4 @@
# Dump the contents of a PNimrodNode # Dump the contents of a NimNode
import macros import macros
@ -7,7 +7,7 @@ template plus(a, b: expr): expr {.dirty} =
macro call(e: expr): expr = macro call(e: expr): expr =
result = newCall("foo", newStrLitNode("bar")) result = newCall("foo", newStrLitNode("bar"))
macro dumpAST(n: stmt): stmt {.immediate.} = macro dumpAST(n: stmt): stmt {.immediate.} =
# dump AST as a side-effect and return the inner node # dump AST as a side-effect and return the inner node
let n = callsite() let n = callsite()
@ -24,10 +24,10 @@ macro dumpAST(n: stmt): stmt {.immediate.} =
echo e.lispRepr echo e.lispRepr
result = n[1] result = n[1]
dumpAST: dumpAST:
proc add(x, y: int): int = proc add(x, y: int): int =
return x + y return x + y
proc sub(x, y: int): int = return x - y proc sub(x, y: int): int = return x - y

View file

@ -1,13 +1,13 @@
# Dump the contents of a PNimrodNode # Dump the contents of a NimNode
import macros import macros
proc dumpit(n: PNimrodNode): string {.compileTime.} = proc dumpit(n: NimNode): string {.compileTime.} =
if n == nil: return "nil" if n == nil: return "nil"
result = $n.kind result = $n.kind
add(result, "(") add(result, "(")
case n.kind case n.kind
of nnkEmpty: discard # same as nil node in this representation of nnkEmpty: discard # same as nil node in this representation
of nnkNilLit: add(result, "nil") of nnkNilLit: add(result, "nil")
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal) of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal) of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
@ -20,17 +20,17 @@ proc dumpit(n: PNimrodNode): string {.compileTime.} =
add(result, ", ") add(result, ", ")
add(result, dumpit(n[j])) add(result, dumpit(n[j]))
add(result, ")") add(result, ")")
macro dumpAST(n: stmt): stmt {.immediate.} = macro dumpAST(n: stmt): stmt {.immediate.} =
# dump AST as a side-effect and return the inner node # dump AST as a side-effect and return the inner node
let n = callsite() let n = callsite()
echo dumpit(n) echo dumpit(n)
result = n[1] result = n[1]
dumpAST: dumpAST:
proc add(x, y: int): int = proc add(x, y: int): int =
return x + y return x + y
proc sub(x, y: int): int = return x - y proc sub(x, y: int): int = return x - y

View file

@ -2,7 +2,7 @@ import rawsockets, asyncdispatch, macros
var p = newDispatcher() var p = newDispatcher()
var sock = newAsyncRawSocket() var sock = newAsyncRawSocket()
proc convertReturns(node, retFutureSym: PNimrodNode): PNimrodNode {.compileTime.} = proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} =
case node.kind case node.kind
of nnkReturnStmt: of nnkReturnStmt:
result = newCall(newIdentNode("complete"), retFutureSym, node[0]) result = newCall(newIdentNode("complete"), retFutureSym, node[0])
@ -19,19 +19,19 @@ macro async2(prc: stmt): stmt {.immediate.} =
# -> var retFuture = newFuture[T]() # -> var retFuture = newFuture[T]()
var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture") var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture")
outerProcBody.add( outerProcBody.add(
newVarStmt(retFutureSym, newVarStmt(retFutureSym,
newCall( newCall(
newNimNode(nnkBracketExpr).add( newNimNode(nnkBracketExpr).add(
newIdentNode("newFuture"), newIdentNode("newFuture"),
prc[3][0][1])))) # Get type from return type of this proc. prc[3][0][1])))) # Get type from return type of this proc.
# -> iterator nameIter(): PFutureBase {.closure.} = <proc_body> # -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
# Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work. # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter") var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter")
#var iteratorNameSym = newIdentNode($prc[0].ident & "Iter") #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
var procBody = prc[6].convertReturns(retFutureSym) var procBody = prc[6].convertReturns(retFutureSym)
var closureIterator = newProc(iteratorNameSym, [newIdentNode("PFutureBase")], var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
procBody, nnkIteratorDef) procBody, nnkIteratorDef)
closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure")) closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
outerProcBody.add(closureIterator) outerProcBody.add(closureIterator)
@ -55,8 +55,8 @@ macro async2(prc: stmt): stmt {.immediate.} =
result[6] = outerProcBody result[6] = outerProcBody
proc readStuff(): PFuture[string] {.async2.} = proc readStuff(): Future[string] {.async2.} =
var fut = connect(sock, "irc.freenode.org", TPort(6667)) var fut = connect(sock, "irc.freenode.org", Port(6667))
yield fut yield fut
var fut2 = recv(sock, 50) var fut2 = recv(sock, 50)
yield fut2 yield fut2

View file

@ -2,7 +2,7 @@
import parseutils, macros import parseutils, macros
proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} = proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
var splitValue: string var splitValue: string
var read = value.parseUntil(splitValue, '$', index) var read = value.parseUntil(splitValue, '$', index)
@ -15,7 +15,7 @@ proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool
if splitValue.len > 0: if splitValue.len > 0:
node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue)) node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
proc parse_template(node: PNimrodNode, value: string) {.compiletime.} = proc parse_template(node: NimNode, value: string) {.compiletime.} =
var index = 0 var index = 0
while index < value.len and while index < value.len and
parse_until_symbol(node, value, index): discard parse_until_symbol(node, value, index): discard

View file

@ -3,17 +3,17 @@ import macros
from uri import `/` from uri import `/`
macro test*(a: stmt): stmt {.immediate.} = macro test*(a: stmt): stmt {.immediate.} =
var nodes: tuple[a, b: int] var nodes: tuple[a, b: int]
nodes.a = 4 nodes.a = 4
nodes[1] = 45 nodes[1] = 45
type type
TTypeEx = object TTypeEx = object
x, y: int x, y: int
case b: bool case b: bool
of false: nil of false: nil
of true: z: float of true: z: float
var t: TTypeEx var t: TTypeEx
t.b = true t.b = true
t.z = 4.5 t.z = 4.5

View file

@ -4,7 +4,7 @@ discard """
import macros import macros
type type
TA = tuple[a: int] TA = tuple[a: int]
PA = ref TA PA = ref TA
@ -19,7 +19,7 @@ test:
macro test2*(a: stmt): stmt {.immediate.} = macro test2*(a: stmt): stmt {.immediate.} =
proc testproc(recurse: int) = proc testproc(recurse: int) =
echo "Thats weird" echo "Thats weird"
var o : PNimrodNode = nil var o : NimNode = nil
echo " no its not!" echo " no its not!"
o = newNimNode(nnkNone) o = newNimNode(nnkNone)
if recurse > 0: if recurse > 0:

View file

@ -7,7 +7,7 @@ import
macro test_macro*(n: stmt): stmt {.immediate.} = macro test_macro*(n: stmt): stmt {.immediate.} =
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
var ass : PNimrodNode = newNimNode(nnkAsgn) var ass : NimNode = newNimNode(nnkAsgn)
add(ass, newIdentNode("str")) add(ass, newIdentNode("str"))
add(ass, newStrLitNode("after")) add(ass, newStrLitNode("after"))
add(result, ass) add(result, ass)

View file

@ -1,7 +1,7 @@
import macros,json import macros,json
var decls{.compileTime.}: seq[PNimrodNode] = @[] var decls{.compileTime.}: seq[NimNode] = @[]
var impls{.compileTime.}: seq[PNimrodNode] = @[] var impls{.compileTime.}: seq[NimNode] = @[]
macro importImpl_forward(name, returns): stmt {.immediate.} = macro importImpl_forward(name, returns): stmt {.immediate.} =
result = newNimNode(nnkEmpty) result = newNimNode(nnkEmpty)
@ -38,7 +38,7 @@ macro importImpl_forward(name, returns): stmt {.immediate.} =
decls.add res decls.add res
echo(repr(res)) echo(repr(res))
macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} = macro importImpl(name, returns: expr, body: stmt): stmt {.immediate.} =
#var res = getAST(importImpl_forward(name, returns)) #var res = getAST(importImpl_forward(name, returns))
discard getAST(importImpl_forward(name, returns)) discard getAST(importImpl_forward(name, returns))
var res = copyNimTree(decls[decls.high]) var res = copyNimTree(decls[decls.high])
@ -56,4 +56,4 @@ importImpl(Item, int):
importImpl(Foo, int16): importImpl(Foo, int16):
echo 77 echo 77
okayy okayy

View file

@ -15,10 +15,10 @@ macro outterMacro*(n: stmt): stmt {.immediate.} =
expectKind(n, TNimrodNodeKind.nnkCall) expectKind(n, TNimrodNodeKind.nnkCall)
if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent: if n.len != 3 or n[1].kind != TNimrodNodeKind.nnkIdent:
error("Macro " & callNode.repr & error("Macro " & callNode.repr &
" requires the ident passed as parameter (eg: " & callNode.repr & " requires the ident passed as parameter (eg: " & callNode.repr &
"(the_name_you_want)): statements.") "(the_name_you_want)): statements.")
result = newNimNode(TNimrodNodeKind.nnkStmtList) result = newNimNode(TNimrodNodeKind.nnkStmtList)
var ass : PNimrodNode = newNimNode(nnkAsgn) var ass : NimNode = newNimNode(nnkAsgn)
ass.add(newIdentNode(n[1].ident)) ass.add(newIdentNode(n[1].ident))
ass.add(newStrLitNode(innerProc(4))) ass.add(newStrLitNode(innerProc(4)))
result.add(ass) result.add(ass)

View file

@ -3,7 +3,7 @@ discard """
""" """
import macros import macros
proc makeMacro: PNimrodNode = proc makeMacro: NimNode =
result = nil result = nil
var p = makeMacro() var p = makeMacro()

View file

@ -19,7 +19,7 @@ template processInterpolations(e: expr) =
macro formatStyleInterpolation(e: expr): expr = macro formatStyleInterpolation(e: expr): expr =
let e = callsite() let e = callsite()
var var
formatString = "" formatString = ""
arrayNode = newNimNode(nnkBracket) arrayNode = newNimNode(nnkBracket)
idx = 1 idx = 1
@ -27,14 +27,14 @@ macro formatStyleInterpolation(e: expr): expr =
proc addString(s: string) = proc addString(s: string) =
formatString.add(s) formatString.add(s)
proc addExpr(e: PNimrodNode) = proc addExpr(e: NimNode) =
arrayNode.add(e) arrayNode.add(e)
formatString.add("$" & $(idx)) formatString.add("$" & $(idx))
inc idx inc idx
proc addDollar() = proc addDollar() =
formatString.add("$$") formatString.add("$$")
processInterpolations(e) processInterpolations(e)
result = parseExpr("\"x\" % [y]") result = parseExpr("\"x\" % [y]")
@ -43,11 +43,11 @@ macro formatStyleInterpolation(e: expr): expr =
macro concatStyleInterpolation(e: expr): expr = macro concatStyleInterpolation(e: expr): expr =
let e = callsite() let e = callsite()
var args: seq[PNimrodNode] var args: seq[NimNode]
newSeq(args, 0) newSeq(args, 0)
proc addString(s: string) = args.add(newStrLitNode(s)) proc addString(s: string) = args.add(newStrLitNode(s))
proc addExpr(e: PNimrodNode) = args.add(e) proc addExpr(e: NimNode) = args.add(e)
proc addDollar() = args.add(newStrLitNode"$") proc addDollar() = args.add(newStrLitNode"$")
processInterpolations(e) processInterpolations(e)
@ -59,7 +59,7 @@ macro concatStyleInterpolation(e: expr): expr =
proc sum(a, b, c: int): int = proc sum(a, b, c: int): int =
return (a + b + c) return (a + b + c)
var var
alice = "Alice" alice = "Alice"
bob = "Bob" bob = "Bob"
a = 10 a = 10

View file

@ -6,7 +6,7 @@ discard """
import macros import macros
proc test(f: var PNimrodNode) {.compileTime.} = proc test(f: var NimNode) {.compileTime.} =
f = newNimNode(nnkStmtList) f = newNimNode(nnkStmtList)
f.add newCall(newIdentNode("echo"), newLit(10)) f.add newCall(newIdentNode("echo"), newLit(10))

View file

@ -18,9 +18,9 @@ proc `$`*[T](x: seq[T]): string =
result.add($x[i]) result.add($x[i])
result.add ']' result.add ']'
macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
let let
typeName = quoted2ident(typeNameN) typeName = quoted2ident(typeNameN)
packetID = ^"p" packetID = ^"p"
streamID = ^"s" streamID = ^"s"
@ -66,7 +66,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody = newNimNode(nnkStmtList) readBody = newNimNode(nnkStmtList)
lenNames = 0 lenNames = 0
for i in 0.. typeFields.len - 1: for i in 0.. typeFields.len - 1:
let let
name = typeFields[i][0] name = typeFields[i][0]
dotName = packetID.dot(name) dotName = packetID.dot(name)
resName = newIdentNode(!"result").dot(name) resName = newIdentNode(!"result").dot(name)
@ -91,11 +91,11 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
newNimNode(nnkDiscardStmt).und( newNimNode(nnkDiscardStmt).und(
newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName)))) newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName))))
packBody.add( packBody.add(
newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName))) newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName)))
of "seq": of "seq":
## let lenX = readInt16(s) ## let lenX = readInt16(s)
newLenName() newLenName()
let let
item = ^"item" ## item name in our iterators item = ^"item" ## item name in our iterators
seqType = typeFields[i][1][1] ## type of seq seqType = typeFields[i][1][1] ## type of seq
readName = newIdentNode("read"& $seqType.ident) readName = newIdentNode("read"& $seqType.ident)
@ -107,7 +107,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody.add( ## result.name = @[] readBody.add( ## result.name = @[]
resName := ("@".prefix(newNimNode(nnkBracket))), resName := ("@".prefix(newNimNode(nnkBracket))),
newNimNode(nnkForStmt).und( ## for item in 1..len: newNimNode(nnkForStmt).und( ## for item in 1..len:
item, item,
infix(1.lit, "..", lenName), infix(1.lit, "..", lenName),
newNimNode(nnkStmtList).und( newNimNode(nnkStmtList).und(
newCall( ## add(result.name, unpack[seqType](stream)) newCall( ## add(result.name, unpack[seqType](stream))
@ -117,7 +117,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und( newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
lenName, ## var lenName = int16(len(p.name)) lenName, ## var lenName = int16(len(p.name))
newIdentNode("int16"), newIdentNode("int16"),
newCall("int16", newCall("len", dotName)))), newCall("int16", newCall("len", dotName)))),
newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit), newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit),
newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream) newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream)
item, item,
@ -143,8 +143,8 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
else: else:
error("I dont know what to do with: "& treerepr(typeFields[i])) error("I dont know what to do with: "& treerepr(typeFields[i]))
var var
toStringFunc = newNimNode(nnkProcDef).und( toStringFunc = newNimNode(nnkProcDef).und(
newNimNode(nnkPostfix).und( newNimNode(nnkPostfix).und(
^"*", ^"*",
@ -161,12 +161,12 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
emptyNode(), emptyNode(),
newNimNode(nnkStmtList).und(#[6] newNimNode(nnkStmtList).und(#[6]
newNimNode(nnkAsgn).und( newNimNode(nnkAsgn).und(
^"result", ## result = ^"result", ## result =
newNimNode(nnkCall).und(#[6][0][1] newNimNode(nnkCall).und(#[6][0][1]
^"format", ## format ^"format", ## format
emptyNode())))) ## "[TypeName $1 $2]" emptyNode())))) ## "[TypeName $1 $2]"
formatStr = "["& $typeName.ident formatStr = "["& $typeName.ident
const emptyFields = {nnkEmpty, nnkNilLit} const emptyFields = {nnkEmpty, nnkNilLit}
var objFields = newNimNode(nnkRecList) var objFields = newNimNode(nnkRecList)
for i in 0.. < len(typeFields): for i in 0.. < len(typeFields):
@ -186,10 +186,10 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
prefix("$", packetID.dot(fname))) prefix("$", packetID.dot(fname)))
formatStr.add " $" formatStr.add " $"
formatStr.add($(i + 1)) formatStr.add($(i + 1))
formatStr.add ']' formatStr.add ']'
toStringFunc[6][0][1][1] = formatStr.lit() toStringFunc[6][0][1][1] = formatStr.lit()
result.add( result.add(
newNimNode(nnkTypeSection).und( newNimNode(nnkTypeSection).und(
newNimNode(nnkTypeDef).und( newNimNode(nnkTypeDef).und(
@ -206,15 +206,15 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
when defined(GenPacketShowOutput): when defined(GenPacketShowOutput):
echo(repr(result)) echo(repr(result))
proc `->`(a: string, b: string): PNimrodNode {.compileTime.} = proc `->`(a: string, b: string): NimNode {.compileTime.} =
result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty)) result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty))
proc `->`(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} = proc `->`(a: string, b: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty)) result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty))
proc `->`(a, b: PNimrodNode): PNimrodNode {.compileTime.} = proc `->`(a, b: NimNode): NimNode {.compileTime.} =
a[2] = b a[2] = b
result = a result = a
proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNode): PNimrodNode {.compileTime.} = proc newProc*(name: string, params: varargs[NimNode], resultType: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkProcDef).und( result = newNimNode(nnkProcDef).und(
^name, ^name,
emptyNode(), emptyNode(),
@ -227,7 +227,7 @@ proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNod
macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} = macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} =
result = newNimNode(nnkStmtList).und( result = newNimNode(nnkStmtList).und(
newProc( newProc(
"read"& $typeName.ident, "read"& $typeName.ident,
["s" -> "PStream" -> newNimNode(nnkNilLit)], ["s" -> "PStream" -> newNimNode(nnkNilLit)],
typeName), typeName),
newProc( newProc(
@ -258,21 +258,21 @@ when isMainModule:
A = 0'i8, A = 0'i8,
B, C B, C
forwardPacket(SomeEnum, int8) forwardPacket(SomeEnum, int8)
defPacket(Foo, tuple[x: array[0..4, int8]]) defPacket(Foo, tuple[x: array[0..4, int8]])
var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8]) var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
var s2 = newStringStream("") var s2 = newStringStream("")
f.pack(s2) f.pack(s2)
assert s2.data == "\4\3\2\1\0" assert s2.data == "\4\3\2\1\0"
var s = newStringStream() var s = newStringStream()
s.flushImpl = proc(s: PStream) = s.flushImpl = proc(s: PStream) =
var z = PStringStream(s) var z = PStringStream(s)
z.setPosition(0) z.setPosition(0)
z.data.setLen(0) z.data.setLen(0)
s.setPosition(0) s.setPosition(0)
s.data.setLen(0) s.data.setLen(0)
var o = B var o = B
@ -283,7 +283,7 @@ when isMainModule:
o.pack(s) o.pack(s)
assert s.data == "\1\0\2" assert s.data == "\1\0\2"
s.flush s.flush
defPacket(Y, tuple[z: int8]) defPacket(Y, tuple[z: int8])
proc `$`(z: Y): string = result = "Y("& $z.z &")" proc `$`(z: Y): string = result = "Y("& $z.z &")"
defPacket(TestPkt, tuple[x: seq[Y]]) defPacket(TestPkt, tuple[x: seq[Y]])
@ -292,4 +292,4 @@ when isMainModule:
for itm in test.x: for itm in test.x:
echo(itm) echo(itm)
test.pack(s) test.pack(s)
echo(repr(s.data)) echo(repr(s.data))

View file

@ -9,9 +9,9 @@ template defPacketImports*(): stmt {.immediate, dirty.} =
import macros, macro_dsl, estreams import macros, macro_dsl, estreams
from strutils import format from strutils import format
macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
result = newNimNode(nnkStmtList) result = newNimNode(nnkStmtList)
let let
typeName = quoted2ident(typeNameN) typeName = quoted2ident(typeNameN)
packetID = ^"p" packetID = ^"p"
streamID = ^"s" streamID = ^"s"
@ -57,7 +57,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody = newNimNode(nnkStmtList) readBody = newNimNode(nnkStmtList)
lenNames = 0 lenNames = 0
for i in 0.. typeFields.len - 1: for i in 0.. typeFields.len - 1:
let let
name = typeFields[i][0] name = typeFields[i][0]
dotName = packetID.dot(name) dotName = packetID.dot(name)
resName = newIdentNode(!"result").dot(name) resName = newIdentNode(!"result").dot(name)
@ -67,7 +67,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
of "seq": of "seq":
## let lenX = readInt16(s) ## let lenX = readInt16(s)
newLenName() newLenName()
let let
item = ^"item" ## item name in our iterators item = ^"item" ## item name in our iterators
seqType = typeFields[i][1][1] ## type of seq seqType = typeFields[i][1][1] ## type of seq
readName = newIdentNode("read"& $seqType.ident) readName = newIdentNode("read"& $seqType.ident)
@ -79,7 +79,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody.add( ## result.name = @[] readBody.add( ## result.name = @[]
resName := ("@".prefix(newNimNode(nnkBracket))), resName := ("@".prefix(newNimNode(nnkBracket))),
newNimNode(nnkForStmt).und( ## for item in 1..len: newNimNode(nnkForStmt).und( ## for item in 1..len:
item, item,
infix(1.lit, "..", lenName), infix(1.lit, "..", lenName),
newNimNode(nnkStmtList).und( newNimNode(nnkStmtList).und(
newCall( ## add(result.name, unpack[seqType](stream)) newCall( ## add(result.name, unpack[seqType](stream))
@ -89,7 +89,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und( newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
lenName, ## var lenName = int16(len(p.name)) lenName, ## var lenName = int16(len(p.name))
newIdentNode("int16"), newIdentNode("int16"),
newCall("int16", newCall("len", dotName)))), newCall("int16", newCall("len", dotName)))),
newCall("writeBE", streamID, lenName), newCall("writeBE", streamID, lenName),
newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream) newNimNode(nnkForStmt).und( ## for item in 0..length - 1: pack(p.name[item], stream)
item, item,
@ -115,8 +115,8 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID)) readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
else: else:
error("I dont know what to do with: "& treerepr(typeFields[i])) error("I dont know what to do with: "& treerepr(typeFields[i]))
var var
toStringFunc = newNimNode(nnkProcDef).und( toStringFunc = newNimNode(nnkProcDef).und(
newNimNode(nnkPostfix).und( newNimNode(nnkPostfix).und(
^"*", ^"*",
@ -133,12 +133,12 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
emptyNode(), emptyNode(),
newNimNode(nnkStmtList).und(#[6] newNimNode(nnkStmtList).und(#[6]
newNimNode(nnkAsgn).und( newNimNode(nnkAsgn).und(
^"result", ## result = ^"result", ## result =
newNimNode(nnkCall).und(#[6][0][1] newNimNode(nnkCall).und(#[6][0][1]
^"format", ## format ^"format", ## format
emptyNode())))) ## "[TypeName $1 $2]" emptyNode())))) ## "[TypeName $1 $2]"
formatStr = "["& $typeName.ident formatStr = "["& $typeName.ident
const emptyFields = {nnkEmpty, nnkNilLit} const emptyFields = {nnkEmpty, nnkNilLit}
var objFields = newNimNode(nnkRecList) var objFields = newNimNode(nnkRecList)
for i in 0.. < len(typeFields): for i in 0.. < len(typeFields):
@ -158,10 +158,10 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
prefix("$", packetID.dot(fname))) prefix("$", packetID.dot(fname)))
formatStr.add " $" formatStr.add " $"
formatStr.add($(i + 1)) formatStr.add($(i + 1))
formatStr.add ']' formatStr.add ']'
toStringFunc[6][0][1][1] = formatStr.lit() toStringFunc[6][0][1][1] = formatStr.lit()
result.add( result.add(
newNimNode(nnkTypeSection).und( newNimNode(nnkTypeSection).und(
newNimNode(nnkTypeDef).und( newNimNode(nnkTypeDef).und(
@ -178,7 +178,7 @@ macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} =
when defined(GenPacketShowOutput): when defined(GenPacketShowOutput):
echo(repr(result)) echo(repr(result))
proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimrodNode): PNimrodNode {.compileTime.} = proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkProcDef).und( result = newNimNode(nnkProcDef).und(
name, name,
emptyNode(), emptyNode(),
@ -189,15 +189,15 @@ proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimr
newNimNode(nnkStmtList)) newNimNode(nnkStmtList))
result[3].add(params) result[3].add(params)
proc body*(procNode: PNimrodNode): PNimrodNode {.compileTime.} = proc body*(procNode: NimNode): NimNode {.compileTime.} =
assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
result = procNode[6] result = procNode[6]
proc iddefs*(a, b: string; c: PNimrodNode): PNimrodNode {.compileTime.} = proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkIdentDefs).und(^a, ^b, c) result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
proc iddefs*(a: string; b: PNimrodNode): PNimrodNode {.compileTime.} = proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode()) result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
proc varTy*(a: PNimrodNode): PNimrodNode {.compileTime.} = proc varTy*(a: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkVarTy).und(a) result = newNimNode(nnkVarTy).und(a)
macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} = macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
@ -206,7 +206,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
streamID = ^"s" streamID = ^"s"
result = newNimNode(nnkStmtList).und( result = newNimNode(nnkStmtList).und(
newProc( newProc(
(^("read"& $typeName.ident)).postfix("*"), (^("read"& $typeName.ident)).postfix("*"),
[ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ], [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
typeName), typeName),
newProc( newProc(
@ -218,7 +218,7 @@ macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
readBody = result[0][6] readBody = result[0][6]
packBody = result[1][6] packBody = result[1][6]
resName = ^"result" resName = ^"result"
case underlyingType.kind case underlyingType.kind
of nnkBracketExpr: of nnkBracketExpr:
case $underlyingType[0].ident case $underlyingType[0].ident
@ -250,21 +250,21 @@ when isMainModule:
A = 0'i8, A = 0'i8,
B, C B, C
forwardPacket(SomeEnum, int8) forwardPacket(SomeEnum, int8)
defPacket(Foo, tuple[x: array[0..4, int8]]) defPacket(Foo, tuple[x: array[0..4, int8]])
var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8]) var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
var s2 = newStringStream("") var s2 = newStringStream("")
f.pack(s2) f.pack(s2)
assert s2.data == "\4\3\2\1\0" assert s2.data == "\4\3\2\1\0"
var s = newStringStream() var s = newStringStream()
s.flushImpl = proc(s: PStream) = s.flushImpl = proc(s: PStream) =
var z = PStringStream(s) var z = PStringStream(s)
z.setPosition(0) z.setPosition(0)
z.data.setLen(0) z.data.setLen(0)
s.setPosition(0) s.setPosition(0)
s.data.setLen(0) s.data.setLen(0)
var o = B var o = B
@ -275,7 +275,7 @@ when isMainModule:
o.pack(s) o.pack(s)
assert s.data == "\1\0\2" assert s.data == "\1\0\2"
s.flush s.flush
defPacket(Y, tuple[z: int8]) defPacket(Y, tuple[z: int8])
proc `$`(z: Y): string = result = "Y("& $z.z &")" proc `$`(z: Y): string = result = "Y("& $z.z &")"
defPacket(TestPkt, tuple[x: seq[Y]]) defPacket(TestPkt, tuple[x: seq[Y]])

View file

@ -1,42 +1,42 @@
import macros import macros
{.deadCodeElim: on.} {.deadCodeElim: on.}
#Inline macro.add() to allow for easier nesting #Inline macro.add() to allow for easier nesting
proc und*(a: PNimrodNode; b: PNimrodNode): PNimrodNode {.compileTime.} = proc und*(a: NimNode; b: NimNode): NimNode {.compileTime.} =
a.add(b) a.add(b)
result = a result = a
proc und*(a: PNimrodNode; b: varargs[PNimrodNode]): PNimrodNode {.compileTime.} = proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} =
a.add(b) a.add(b)
result = a result = a
proc `^`*(a: string): PNimrodNode {.compileTime.} = proc `^`*(a: string): NimNode {.compileTime.} =
## new ident node ## new ident node
result = newIdentNode(!a) result = newIdentNode(!a)
proc `[]`*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
## new bracket expression: node[node] not to be confused with node[indx] ## new bracket expression: node[node] not to be confused with node[indx]
result = newNimNode(nnkBracketExpr).und(a, b) result = newNimNode(nnkBracketExpr).und(a, b)
proc `:=`*(left, right: PNimrodNode): PNimrodNode {.compileTime.} = proc `:=`*(left, right: NimNode): NimNode {.compileTime.} =
## new Asgn node: left = right ## new Asgn node: left = right
result = newNimNode(nnkAsgn).und(left, right) result = newNimNode(nnkAsgn).und(left, right)
proc lit*(a: string): PNimrodNode {.compileTime.} = proc lit*(a: string): NimNode {.compileTime.} =
result = newStrLitNode(a) result = newStrLitNode(a)
proc lit*(a: int): PNimrodNode {.compileTime.} = proc lit*(a: int): NimNode {.compileTime.} =
result = newIntLitNode(a) result = newIntLitNode(a)
proc lit*(a: float): PNimrodNode {.compileTime.} = proc lit*(a: float): NimNode {.compileTime.} =
result = newFloatLitNode(a) result = newFloatLitNode(a)
proc lit*(a: char): PNimrodNode {.compileTime.} = proc lit*(a: char): NimNode {.compileTime.} =
result = newNimNode(nnkCharLit) result = newNimNode(nnkCharLit)
result.intval = a.ord result.intval = a.ord
proc emptyNode*(): PNimrodNode {.compileTime.} = proc emptyNode*(): NimNode {.compileTime.} =
result = newNimNode(nnkEmpty) result = newNimNode(nnkEmpty)
proc dot*(left, right: PNimrodNode): PNimrodNode {.compileTime.} = proc dot*(left, right: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkDotExpr).und(left, right) result = newNimNode(nnkDotExpr).und(left, right)
proc prefix*(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} = proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
result = newNimNode(nnkPrefix).und(newIdentNode(!a), b) result = newNimNode(nnkPrefix).und(newIdentNode(!a), b)
proc quoted2ident*(a: PNimrodNode): PNimrodNode {.compileTime.} = proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
if a.kind != nnkAccQuoted: if a.kind != nnkAccQuoted:
return a return a
var pname = "" var pname = ""

View file

@ -13,7 +13,7 @@ var g = 70
++g ++g
g ++ 7 g ++ 7
g.`++`(10, 20) g.`++`(10, 20)
echo g echo g
#let lv = stdin.readline #let lv = stdin.readline
@ -56,7 +56,7 @@ type
fkLit, ## element is a literal like 0.1 fkLit, ## element is a literal like 0.1
fkAdd, ## element is an addition operation fkAdd, ## element is an addition operation
fkMul, ## element is a multiplication operation fkMul, ## element is a multiplication operation
fkExp ## element is an exponentiation operation fkExp ## element is an exponentiation operation
type type
Formula = ref object Formula = ref object
@ -78,16 +78,16 @@ proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
echo evaluate(Formula(kind: fkLit, value: 0.4), nil) echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
proc isPolyTerm(n: Formula): bool = proc isPolyTerm(n: Formula): bool =
n.kind == fkMul and n.left.kind == fkLit and (let e = n.right; n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit) e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
proc isPolynomial(n: Formula): bool = proc isPolynomial(n: Formula): bool =
isPolyTerm(n) or isPolyTerm(n) or
(n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right)) (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
let myFormula = Formula(kind: fkMul, let myFormula = Formula(kind: fkMul,
left: Formula(kind: fkLit, value: 2.0), left: Formula(kind: fkLit, value: 2.0),
right: Formula(kind: fkExp, right: Formula(kind: fkExp,
left: Formula(kind: fkVar, name: "x"), left: Formula(kind: fkVar, name: "x"),
right: Formula(kind: fkLit, value: 5.0))) right: Formula(kind: fkLit, value: 5.0)))
@ -104,7 +104,7 @@ proc pat2kind(pattern: string): FormulaKind =
import macros import macros
proc matchAgainst(n, pattern: PNimrodNode): PNimrodNode {.compileTime.} = proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
template `@`(current, field: expr): expr = template `@`(current, field: expr): expr =
newDotExpr(current, newIdentNode(astToStr(field))) newDotExpr(current, newIdentNode(astToStr(field)))

View file

@ -18,7 +18,7 @@ const identChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
# Procedure Declarations # Procedure Declarations
proc parse_template(node: PNimrodNode, value: string) {.compiletime.} proc parse_template(node: NimNode, value: string) {.compiletime.}
# Procedure Definitions # Procedure Definitions
@ -166,7 +166,7 @@ iterator parse_compound_statements(value, identifier: string, index: int): strin
get_next_ident(["try", "$except", "$finally"]) get_next_ident(["try", "$except", "$finally"])
proc parse_complex_stmt(value, identifier: string, index: var int): PNimrodNode {.compiletime.} = proc parse_complex_stmt(value, identifier: string, index: var int): NimNode {.compiletime.} =
## Parses if/when/try /elif /else /except /finally statements ## Parses if/when/try /elif /else /except /finally statements
# Build up complex statement string # Build up complex statement string
@ -218,7 +218,7 @@ proc parse_complex_stmt(value, identifier: string, index: var int): PNimrodNode
inc(resultIndex) inc(resultIndex)
proc parse_simple_statement(value: string, index: var int): PNimrodNode {.compiletime.} = proc parse_simple_statement(value: string, index: var int): NimNode {.compiletime.} =
## Parses for/while ## Parses for/while
# Detect indentation # Detect indentation
@ -252,7 +252,7 @@ proc parse_simple_statement(value: string, index: var int): PNimrodNode {.compil
inc(index, value.parse_thru_eol(index)) inc(index, value.parse_thru_eol(index))
proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool {.compiletime.} = proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
## Parses a string until a $ symbol is encountered, if ## Parses a string until a $ symbol is encountered, if
## two $$'s are encountered in a row, a split will happen ## two $$'s are encountered in a row, a split will happen
## removing one of the $'s from the resulting output ## removing one of the $'s from the resulting output
@ -311,7 +311,7 @@ proc parse_until_symbol(node: PNimrodNode, value: string, index: var int): bool
node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue)) node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue))
proc parse_template(node: PNimrodNode, value: string) = proc parse_template(node: NimNode, value: string) =
## Parses through entire template, outputing valid ## Parses through entire template, outputing valid
## Nim code into the input `node` AST. ## Nim code into the input `node` AST.
var index = 0 var index = 0

View file

@ -3,13 +3,13 @@ discard """
output: "Using test.Closing test." output: "Using test.Closing test."
""" """
import import
macros macros
# This macro mimics the using statement from C# # This macro mimics the using statement from C#
# #
# It's kept only as a test for the macro system # It's kept only as a test for the macro system
# Nim's destructors offer a mechanism for automatic # Nim's destructors offer a mechanism for automatic
# disposal of resources. # disposal of resources.
# #
macro autoClose(e: expr): stmt {.immediate.} = macro autoClose(e: expr): stmt {.immediate.} =
@ -20,19 +20,19 @@ macro autoClose(e: expr): stmt {.immediate.} =
var args = e var args = e
var body = e[2] var body = e[2]
var var
variables : seq[PNimrodNode] variables : seq[NimNode]
closingCalls : seq[PNimrodNode] closingCalls : seq[NimNode]
newSeq(variables, 0) newSeq(variables, 0)
newSeq(closingCalls, 0) newSeq(closingCalls, 0)
for i in countup(1, args.len-2): for i in countup(1, args.len-2):
if args[i].kind == nnkExprEqExpr: if args[i].kind == nnkExprEqExpr:
var varName = args[i][0] var varName = args[i][0]
var varValue = args[i][1] var varValue = args[i][1]
var varAssignment = newNimNode(nnkIdentDefs) var varAssignment = newNimNode(nnkIdentDefs)
varAssignment.add(varName) varAssignment.add(varName)
varAssignment.add(newNimNode(nnkEmpty)) # empty means no type varAssignment.add(newNimNode(nnkEmpty)) # empty means no type
@ -43,7 +43,7 @@ macro autoClose(e: expr): stmt {.immediate.} =
else: else:
error "Using statement: Unexpected expression. Got " & error "Using statement: Unexpected expression. Got " &
$args[i].kind & " instead of assignment." $args[i].kind & " instead of assignment."
var varSection = newNimNode(nnkVarSection) var varSection = newNimNode(nnkVarSection)
varSection.add(variables) varSection.add(variables)
@ -67,10 +67,10 @@ macro autoClose(e: expr): stmt {.immediate.} =
targetAst[0][1][0] = varSection targetAst[0][1][0] = varSection
targetAst[0][1][1][0] = body targetAst[0][1][1][0] = body
targetAst[0][1][1][1][0] = finallyBlock targetAst[0][1][1][1][0] = finallyBlock
result = targetAst result = targetAst
type type
TResource* = object TResource* = object
field*: string field*: string

View file

@ -8,9 +8,9 @@ type
suiteDesc: string suiteDesc: string
testName: string testName: string
testDesc: string testDesc: string
testBlock: PNimrodNode testBlock: NimNode
proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: PNimrodNode): tuple[tests: seq[SuiteTest]] {.compileTime.} = proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: seq[SuiteTest]] {.compileTime.} =
var var
tests:seq[SuiteTest] = @[] tests:seq[SuiteTest] = @[]
@ -40,7 +40,7 @@ proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: PNimrodNode): tuple[tes
discard discard
return (tests: tests) return (tests: tests)
macro suite(suiteName, suiteDesc: expr, suiteBloc: stmt): stmt {.immediate.} = macro suite(suiteName, suiteDesc: expr, suiteBloc: stmt): stmt {.immediate.} =
let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc) let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc)