Merge pull request #2019 from MasonMcGill/devel

Added a few AST-construction shortcuts.
This commit is contained in:
Dominik Picheta 2015-01-27 23:32:29 +00:00
commit 85ae439bb8

View file

@ -23,9 +23,9 @@ type
nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit, nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall, nnkTripleStrLit, nnkNilLit, nnkMetaNode, nnkDotCall,
nnkCommand, nnkCall, nnkCallStrLit, nnkInfix, nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
nnkPrefix, nnkPostfix, nnkHiddenCallConv, nnkPrefix, nnkPostfix, nnkHiddenCallConv,
nnkExprEqExpr, nnkExprEqExpr,
nnkExprColonExpr, nnkIdentDefs, nnkVarTuple, nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr, nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange, nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr, nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
@ -48,7 +48,7 @@ type
nnkConstDef, nnkTypeDef, nnkConstDef, nnkTypeDef,
nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt, nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt, nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
nnkDiscardStmt, nnkStmtList, nnkDiscardStmt, nnkStmtList,
nnkImportStmt, nnkImportStmt,
nnkImportExceptStmt, nnkImportExceptStmt,
nnkExportStmt, nnkExportStmt,
@ -65,7 +65,7 @@ type
nnkRefTy, nnkPtrTy, nnkVarTy, nnkRefTy, nnkPtrTy, nnkVarTy,
nnkConstTy, nnkMutableTy, nnkConstTy, nnkMutableTy,
nnkDistinctTy, nnkDistinctTy,
nnkProcTy, nnkProcTy,
nnkIteratorTy, # iterator type nnkIteratorTy, # iterator type
nnkSharedTy, # 'shared T' nnkSharedTy, # 'shared T'
nnkEnumTy, nnkEnumTy,
@ -87,13 +87,13 @@ type
TNimTypeKinds* = set[TNimrodTypeKind] TNimTypeKinds* = set[TNimrodTypeKind]
TNimrodSymKind* = enum TNimrodSymKind* = enum
nskUnknown, nskConditional, nskDynLib, nskParam, nskUnknown, nskConditional, nskDynLib, nskParam,
nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet, nskGenericParam, nskTemp, nskModule, nskType, nskVar, nskLet,
nskConst, nskResult, nskConst, nskResult,
nskProc, nskMethod, nskIterator, nskClosureIterator, nskProc, nskMethod, nskIterator, nskClosureIterator,
nskConverter, nskMacro, nskTemplate, nskField, nskConverter, nskMacro, nskTemplate, nskField,
nskEnumField, nskForVar, nskLabel, nskEnumField, nskForVar, nskLabel,
nskStub nskStub
TNimSymKinds* = set[TNimrodSymKind] TNimSymKinds* = set[TNimrodSymKind]
type type
@ -293,7 +293,7 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.
## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on. ## e.g. `@` is escaped as `@@`, `@@` is escaped as `@@@` and so on.
## ##
## Example: ## Example:
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
## macro check(ex: expr): stmt = ## macro check(ex: expr): stmt =
@ -312,7 +312,7 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst", noSideEffect.
## result = quote do: ## result = quote do:
## 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: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case, ## checks that `n` is of kind `k`. If this is not the case,
## compilation aborts with an error message. This is useful for writing ## compilation aborts with an error message. This is useful for writing
@ -459,13 +459,17 @@ macro dumpLispImm*(s: stmt): stmt {.immediate, deprecated.} = echo s.lispRepr
proc newEmptyNode*(): PNimrodNode {.compileTime, noSideEffect.} = proc newEmptyNode*(): PNimrodNode {.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[PNimrodNode]): PNimrodNode {.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.}=
## Create a new parentheses-enclosed expression
newNimNode(nnkPar).add(exprs)
proc newBlockStmt*(label, body: PNimrodNode): PNimrodNode {.compileTime.} = proc newBlockStmt*(label, body: PNimrodNode): PNimrodNode {.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)
@ -475,25 +479,35 @@ proc newBlockStmt*(body: PNimrodNode): PNimrodNode {.compiletime.} =
return newNimNode(nnkBlockStmt).add(newEmptyNode(), body) return newNimNode(nnkBlockStmt).add(newEmptyNode(), body)
proc newVarStmt*(name, value: PNimrodNode): PNimrodNode {.compiletime.} = proc newVarStmt*(name, value: PNimrodNode): PNimrodNode {.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: PNimrodNode): PNimrodNode {.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.} =
## Create a new const stmt
newNimNode(nnkConstSection).add(
newNimNode(nnkConstDef).add(name, newNimNode(nnkEmpty), value))
proc newAssignment*(lhs, rhs: PNimrodNode): PNimrodNode {.compileTime.} = proc newAssignment*(lhs, rhs: PNimrodNode): PNimrodNode {.compileTime.} =
return newNimNode(nnkAsgn).add(lhs, rhs) return newNimNode(nnkAsgn).add(lhs, rhs)
proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} = proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.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 newIdentDefs*(name, kind: PNimrodNode; proc newColonExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
default = newEmptyNode()): PNimrodNode {.compileTime.} = ## Create new colon expression
## newColonExpr(a, b) -> `a: b`
newNimNode(nnkExprColonExpr).add(a, b)
proc newIdentDefs*(name, kind: PNimrodNode;
default = newEmptyNode()): PNimrodNode {.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
@ -531,13 +545,13 @@ proc newNilLit*(): PNimrodNode {.compileTime.} =
proc high*(node: PNimrodNode): int {.compileTime.} = len(node) - 1 proc high*(node: PNimrodNode): 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: PNimrodNode): PNimrodNode {.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()]`
const const
RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef} RoutineNodes* = {nnkProcDef, nnkMethodDef, nnkDo, nnkLambda, nnkIteratorDef}
AtomicNodes* = {nnkNone..nnkNilLit} AtomicNodes* = {nnkNone..nnkNilLit}
CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand, CallNodes* = {nnkCall, nnkInfix, nnkPrefix, nnkPostfix, nnkCommand,
nnkCallStrLit, nnkHiddenCallConv} nnkCallStrLit, nnkHiddenCallConv}
from strutils import cmpIgnoreStyle, format from strutils import cmpIgnoreStyle, format
@ -545,11 +559,11 @@ from strutils import cmpIgnoreStyle, format
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} = proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind) assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()]; proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} = body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.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,
## followed by a list of IdentDefs which specify the params. ## followed by a list of IdentDefs which specify the params.
assert procType in RoutineNodes assert procType in RoutineNodes
result = newNimNode(procType).add( result = newNimNode(procType).add(
@ -561,12 +575,12 @@ 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: PNimrodNode]]):
PNimrodNode {.compiletime.} = PNimrodNode {.compiletime.} =
## Constructor for ``if`` statements. ## Constructor for ``if`` statements.
## ##
## .. code-block:: nim ## .. code-block:: nim
## ##
## newIfStmt( ## newIfStmt(
## (Ident, StmtList), ## (Ident, StmtList),
## ... ## ...
@ -575,7 +589,7 @@ proc newIfStmt*(branches: varargs[tuple[cond, body: PNimrodNode]]):
result = newNimNode(nnkIfStmt) result = newNimNode(nnkIfStmt)
for i in branches: for i in branches:
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: PNimrodNode) {.compileTime.}=
## Copy all children from `src` to `dest` ## Copy all children from `src` to `dest`
@ -584,7 +598,7 @@ proc copyChildrenTo*(src, dest: PNimrodNode) {.compileTime.}=
template expectRoutine(node: PNimrodNode): stmt = template expectRoutine(node: PNimrodNode): stmt =
expectKind(node, RoutineNodes) expectKind(node, RoutineNodes)
proc name*(someProc: PNimrodNode): PNimrodNode {.compileTime.} = proc name*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
someProc.expectRoutine someProc.expectRoutine
result = someProc[0] result = someProc[0]
@ -623,11 +637,11 @@ proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
return someProc[1] return someProc[1]
of nnkForStmt: of nnkForStmt:
return someProc.last return someProc.last
else: else:
badNodeKind someProc.kind, "body" badNodeKind someProc.kind, "body"
proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} = proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
case someProc.kind case someProc.kind
of RoutineNodes: of RoutineNodes:
someProc[6] = val someProc[6] = val
of nnkBlockStmt, nnkWhileStmt: of nnkBlockStmt, nnkWhileStmt:
@ -635,10 +649,10 @@ proc `body=`*(someProc: PNimrodNode, val: PNimrodNode) {.compileTime.} =
of nnkForStmt: of nnkForStmt:
someProc[high(someProc)] = val someProc[high(someProc)] = val
else: else:
badNodeKind someProc.kind, "body=" badNodeKind someProc.kind, "body="
proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.} proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.}
proc `$`*(node: PNimrodNode): string {.compileTime.} = proc `$`*(node: PNimrodNode): string {.compileTime.} =
## Get the string of an identifier node ## Get the string of an identifier node
@ -651,7 +665,7 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
result = node.strVal result = node.strVal
of nnkSym: of nnkSym:
result = $node.symbol result = $node.symbol
else: else:
badNodeKind node.kind, "$" badNodeKind node.kind, "$"
proc ident*(name: string): PNimrodNode {.compileTime,inline.} = newIdentNode(name) proc ident*(name: string): PNimrodNode {.compileTime,inline.} = newIdentNode(name)
@ -664,14 +678,14 @@ iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {. template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
immediate, dirty.} = immediate, dirty.} =
## Find the first child node matching condition (or nil). ## Find the first child node matching condition (or nil).
## ##
## .. code-block:: nim ## .. code-block:: nim
## 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: PNimrodNode
for it in n.children: for it in n.children:
if cond: if cond:
result = it result = it
break break
result result
@ -696,9 +710,9 @@ proc basename*(a: PNimrodNode): PNimrodNode =
case a.kind case a.kind
of nnkIdent: return a of nnkIdent: return a
of nnkPostfix, nnkPrefix: return a[1] of nnkPostfix, nnkPrefix: return a[1]
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: PNimrodNode; val: string) {.compileTime.}=
case a.kind case a.kind
of nnkIdent: macros.`ident=`(a, !val) of nnkIdent: macros.`ident=`(a, !val)
@ -706,14 +720,14 @@ proc `basename=`*(a: PNimrodNode; val: string) {.compileTime.}=
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: PNimrodNode; op: string): PNimrodNode {.compileTime.} =
newNimNode(nnkPostfix).add(ident(op), node) newNimNode(nnkPostfix).add(ident(op), node)
proc prefix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} = proc prefix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} =
newNimNode(nnkPrefix).add(ident(op), node) newNimNode(nnkPrefix).add(ident(op), node)
proc infix*(a: PNimrodNode; op: string; proc infix*(a: PNimrodNode; op: string;
b: PNimrodNode): PNimrodNode {.compileTime.} = b: PNimrodNode): PNimrodNode {.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: PNimrodNode): tuple[node: PNimrodNode; op: string] {.
@ -726,7 +740,7 @@ proc unpackPrefix*(node: PNimrodNode): tuple[node: PNimrodNode; op: string] {.
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: PNimrodNode): tuple[left: PNimrodNode; op: string;
right: PNimrodNode] {.compileTime.} = right: PNimrodNode] {.compileTime.} =
assert node.kind == nnkInfix assert node.kind == nnkInfix
result = (node[0], $node[1], node[2]) result = (node[0], $node[1], node[2])
@ -741,7 +755,7 @@ proc eqIdent* (a, b: string): bool = cmpIgnoreStyle(a, b) == 0
proc hasArgOfName* (params: PNimrodNode; name: string): bool {.compiletime.}= proc hasArgOfName* (params: PNimrodNode; 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:
template node: expr = params[i] template node: expr = params[i]
if name.eqIdent( $ node[0]): if name.eqIdent( $ node[0]):
return true return true