Get symbol kind (#7491)

This commit is contained in:
Arne Döring 2018-04-11 16:48:01 +02:00 • committed by Andreas Rumpf
commit 6baca58693
13 changed files with 319 additions and 272 deletions

View file

@ -26,6 +26,8 @@
- ``macros.astGenRepr``, ``macros.lispRepr`` and ``macros.treeRepr``
now escapes the content of string literals consistently.
- ``macros.NimSym`` and ``macros.NimIdent`` is now deprecated in favor
of the more general ``NimNode``.
### Language additions

View file

@ -632,10 +632,11 @@ type
mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType,
mNaN, mInf, mNegInf,
mCompileOption, mCompileOptionArg,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel,
mNKind, mNSymKind
mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal,
mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNLineInfo,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr,
mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent,
mNBindSym, mLocals, mNCallSite,
mEqIdent, mEqNimrodNode, mSameNodeType, mGetImpl,
mNHint, mNWarning, mNError,

View file

@ -113,3 +113,4 @@ proc initDefines*() =
defineSymbol("nimHasRunnableExamples")
defineSymbol("nimNewDot")
defineSymbol("nimHasNilChecks")
defineSymbol("nimSymKind")

View file

@ -768,8 +768,10 @@ macro `=~`(x: PNode, pat: untyped): bool =
var conds = newTree(nnkBracket)
m(x, pat, conds)
when declared(macros.toNimIdent):
result = nestList(toNimIdent"and", conds)
when compiles(nestList(ident"and", conds)):
result = nestList(ident"and", conds)
#elif declared(macros.toNimIdent):
# result = nestList(toNimIdent"and", conds)
else:
result = nestList(!"and", conds)

View file

@ -892,7 +892,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else: copyTree(a.sym.ast)
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
of opcEcho:
let rb = instr.regB
if rb == 1:
@ -1233,6 +1233,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeB(rkInt)
regs[ra].intVal = ord(regs[rb].node.kind)
c.comesFromHeuristic = regs[rb].node.info
of opcNSymKind:
decodeB(rkInt)
let a = regs[rb].node
if a.kind == nkSym:
regs[ra].intVal = ord(a.sym.kind)
else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
c.comesFromHeuristic = regs[rb].node.info
of opcNIntVal:
decodeB(rkInt)
let a = regs[rb].node
@ -1295,9 +1303,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
decodeB(rkNode)
createStr regs[ra]
let a = regs[rb].node
if a.kind in {nkStrLit..nkTripleStrLit}: regs[ra].node.strVal = a.strVal
elif a.kind == nkCommentStmt: regs[ra].node.strVal = a.comment
else: stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
case a.kind
of {nkStrLit..nkTripleStrLit}:
regs[ra].node.strVal = a.strVal
of nkCommentStmt:
regs[ra].node.strVal = a.comment
of nkIdent:
regs[ra].node.strVal = a.ident.s
of nkSym:
regs[ra].node.strVal = a.sym.name.s
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
of opcSlurp:
decodeB(rkNode)
createStr regs[ra]
@ -1387,17 +1403,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
else:
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
regs[ra].node.ident = getIdent(regs[rb].node.strVal)
of opcIdentToStr:
decodeB(rkNode)
let a = regs[rb].node
createStr regs[ra]
regs[ra].node.info = c.debug[pc]
if a.kind == nkSym:
regs[ra].node.strVal = a.sym.name.s
elif a.kind == nkIdent:
regs[ra].node.strVal = a.ident.s
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
of opcSetType:
if regs[ra].kind != rkNode:
internalError(c.debug[pc], "cannot set type")

View file

@ -79,6 +79,7 @@ type
opcNAdd,
opcNAddMultiple,
opcNKind,
opcNSymKind,
opcNIntVal,
opcNFloatVal,
opcNSymbol,
@ -101,7 +102,6 @@ type
opcNGetLine, opcNGetColumn, opcNGetFile,
opcEqIdent,
opcStrToIdent,
opcIdentToStr,
opcGetImpl,
opcEcho,

View file

@ -1080,6 +1080,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
of mNAdd: genBinaryABC(c, n, dest, opcNAdd)
of mNAddMultiple: genBinaryABC(c, n, dest, opcNAddMultiple)
of mNKind: genUnaryABC(c, n, dest, opcNKind)
of mNSymKind: genUnaryABC(c, n, dest, opcNSymKind)
of mNIntVal: genUnaryABC(c, n, dest, opcNIntVal)
of mNFloatVal: genUnaryABC(c, n, dest, opcNFloatVal)
of mNSymbol: genUnaryABC(c, n, dest, opcNSymbol)
@ -1125,7 +1126,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
else:
localError(n.info, "invalid bindSym usage")
of mStrToIdent: genUnaryABC(c, n, dest, opcStrToIdent)
of mIdentToStr: genUnaryABC(c, n, dest, opcIdentToStr)
of mEqIdent: genBinaryABC(c, n, dest, opcEqIdent)
of mEqNimrodNode: genBinaryABC(c, n, dest, opcEqNimrodNode)
of mSameNodeType: genBinaryABC(c, n, dest, opcSameNodeType)

View file

@ -28,12 +28,8 @@ contains:
intVal: BiggestInt ## the int literal
of nnkFloatLit..nnkFloat64Lit:
floatVal: BiggestFloat ## the float literal
of nnkStrLit..nnkTripleStrLit:
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
strVal: string ## the string literal
of nnkIdent:
ident: NimIdent ## the identifier
of nnkSym:
symbol: NimSym ## the symbol (after symbol lookup phase)
else:
sons: seq[NimNode] ## the node's sons (or children)
@ -74,8 +70,8 @@ Nim expression Corresponding AST
``"""abc"""`` ``nnkTripleStrLit(strVal = "abc")``
``' '`` ``nnkCharLit(intVal = 32)``
``nil`` ``nnkNilLit()``
``myIdentifier`` ``nnkIdent(ident = !"myIdentifier")``
``myIdentifier`` after lookup pass: ``nnkSym(symbol = ...)``
``myIdentifier`` ``nnkIdent(strVal = "myIdentifier")``
``myIdentifier`` after lookup pass: ``nnkSym(strVal = "myIdentifier", ...)``
----------------- ---------------------------------------------
Identifiers are ``nnkIdent`` nodes. After the name lookup pass these nodes
@ -97,7 +93,7 @@ AST:
.. code-block:: nim
nnkCommand(
nnkIdent(!"echo"),
nnkIdent("echo"),
nnkStrLit("abc"),
nnkStrLit("xyz")
)
@ -115,7 +111,7 @@ AST:
.. code-block:: nim
nnkCall(
nnkIdent(!"echo"),
nnkIdent("echo"),
nnkStrLit("abc"),
nnkStrLit("xyz")
)
@ -133,7 +129,7 @@ AST:
.. code-block:: nim
nnkInfix(
nnkIdent(!"&"),
nnkIdent("&"),
nnkStrLit("abc"),
nnkStrLit("xyz")
)
@ -150,10 +146,10 @@ AST:
.. code-block:: nim
nnkInfix(
nnkIdent(!"+"),
nnkIdent("+"),
nnkIntLit(5),
nnkInfix(
nnkIdent(!"*"),
nnkIdent("*"),
nnkIntLit(3),
nnkIntLit(4)
)
@ -174,7 +170,7 @@ AST:
.. code-block:: nim
nnkCall(
nnkAccQuoted(
nnkIdent(!"+")
nnkIdent("+")
),
nnkIntLit(3),
nnkIntLit(4)
@ -192,7 +188,7 @@ AST:
.. code-block:: nim
nnkPrefix(
nnkIdent(!"?"),
nnkIdent("?"),
nnkStrLit("abc")
)
@ -212,8 +208,8 @@ AST:
.. code-block:: nim
nnkPostfix(
nnkIdent(!"*"),
nnkIdent(!"identifier")
nnkIdent("*"),
nnkIdent("identifier")
)
@ -229,10 +225,10 @@ AST:
.. code-block:: nim
nnkCall(
nnkIdent(!"writeLine"),
nnkIdent("writeLine"),
nnkExprEqExpr(
nnkIdent(!"file"),
nnkIdent(!"stdout")
nnkIdent("file"),
nnkIdent("stdout")
),
nnkStrLit("hallo")
)
@ -253,7 +249,7 @@ AST:
.. code-block:: nim
nnkCallStrLit(
nnkIdent(!"echo"),
nnkIdent("echo"),
nnkRStrLit("hello")
)
@ -268,7 +264,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkDerefExpr(nnkIdent(!"x"))
nnkDerefExpr(nnkIdent("x"))
Addr operator
@ -282,7 +278,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkAddr(nnkIdent(!"x"))
nnkAddr(nnkIdent("x"))
Cast operator
@ -296,7 +292,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkCast(nnkIdent(!"T"), nnkIdent(!"x"))
nnkCast(nnkIdent("T"), nnkIdent("x"))
Object access operator ``.``
@ -310,7 +306,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y"))
nnkDotExpr(nnkIdent("x"), nnkIdent("y"))
If you use Nim's flexible calling syntax (as in ``x.len()``), the result is the
same as above but wrapped in an ``nnkCall``.
@ -327,7 +323,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkBracketExpr(nnkIdent(!"x"), nnkIdent(!"y"))
nnkBracketExpr(nnkIdent("x"), nnkIdent("y"))
Parentheses
@ -373,8 +369,8 @@ AST:
.. code-block:: nim
nnkTableConstr(
nnkExprColonExpr(nnkIdent(!"a"), nnkIntLit(3)),
nnkExprColonExpr(nnkIdent(!"b"), nnkIntLit(5))
nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)),
nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5))
)
@ -410,7 +406,7 @@ AST:
.. code-block:: nim
nnkInfix(
nnkIdent(!".."),
nnkIdent(".."),
nnkIntLit(1),
nnkIntLit(3)
)
@ -461,7 +457,7 @@ Documentation Comments
----------------------
Double-hash (``##``) comments in the code actually have their own format,
using ``strVal`` to get and set the comment text. Single-hash (``#``)
using ``strVal`` to get and set the comment text. Single-hash (``#``)
comments are ignored.
Concrete syntax:
@ -497,7 +493,7 @@ AST:
.. code-block:: nim
nnkPragma(
nnkExprColonExpr(
nnkIdent(!"emit"),
nnkIdent("emit"),
nnkStrLit("#include <stdio.h>") # the "argument"
)
)
@ -515,10 +511,10 @@ AST:
.. code-block:: nim
nnkPragma(
nnkExprColonExpr(
nnkIdent(!"pragma"), # this is always first when declaring a new pragma
nnkIdent(!"cdeclRename") # the name of the pragma
nnkIdent("pragma"), # this is always first when declaring a new pragma
nnkIdent("cdeclRename") # the name of the pragma
),
nnkIdent(!"cdecl")
nnkIdent("cdecl")
)
Statements
@ -570,7 +566,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkAsgn(nnkIdent(!"x"), nnkIntLit(42))
nnkAsgn(nnkIdent("x"), nnkIntLit(42))
This is not the syntax for assignment when combined with ``var``, ``let``,
or ``const``.
@ -736,7 +732,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkBreakStmt(nnkIdent(!"otherLocation"))
nnkBreakStmt(nnkIdent("otherLocation"))
If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``.
@ -751,7 +747,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkBlockStmt(nnkIdent(!"name"), nnkStmtList(...))
nnkBlockStmt(nnkIdent("name"), nnkStmtList(...))
A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used.
@ -787,7 +783,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkImportStmt(nnkIdent(!"math"))
nnkImportStmt(nnkIdent("math"))
With ``except``, we get ``nnkImportExceptStmt``.
@ -799,7 +795,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkImportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow"))
nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow"))
Note that ``import math as m`` does not use a different node; rather,
we use ``nnkImportStmt`` with ``as`` as an infix operator.
@ -814,9 +810,9 @@ AST:
.. code-block:: nim
nnkImportStmt(
nnkInfix(
nnkIdent(!"as"),
nnkIdent(!"strutils"),
nnkIdent(!"su")
nnkIdent("as"),
nnkIdent("strutils"),
nnkIdent("su")
)
)
@ -833,7 +829,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkFromStmt(nnkIdent(!"math"), nnkIdent(!"pow"))
nnkFromStmt(nnkIdent("math"), nnkIdent("pow"))
Using ``from math as m import pow`` works identically to the ``as`` modifier
with the ``import`` statement, but wrapped in ``nnkFromStmt``.
@ -852,7 +848,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkExportStmt(nnkIdent(!"unsigned"))
nnkExportStmt(nnkIdent("unsigned"))
Similar to the ``import`` statement, the AST is different for
``export ... except``.
@ -865,7 +861,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkExportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow"))
nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow"))
Include statement
-----------------
@ -880,7 +876,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkIncludeStmt(nnkIdent(!"blocks"))
nnkIncludeStmt(nnkIdent("blocks"))
Var section
-----------
@ -895,7 +891,7 @@ AST:
.. code-block:: nim
nnkVarSection(
nnkIdentDefs(
nnkIdent(!"a"),
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
nnkIntLit(3),
)
@ -925,7 +921,7 @@ AST:
.. code-block:: nim
nnkLetSection(
nnkIdentDefs(
nnkIdent(!"a"),
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) for the type
nnkIntLit(3),
)
@ -944,7 +940,7 @@ AST:
.. code-block:: nim
nnkConstSection(
nnkConstDef( # not nnkConstDefs!
nnkIdent(!"a"),
nnkIdent("a"),
nnkEmpty(), # or nnkIdent(...) if the variable declares the type
nnkIntLit(3), # required in a const declaration!
)
@ -966,9 +962,9 @@ AST:
.. code-block:: nim
nnkTypeSection(
nnkTypeDef(
nnkIdent(!"A"),
nnkIdent("A"),
nnkEmpty(),
nnkIdent(!"int")
nnkIdent("int")
)
)
@ -985,10 +981,10 @@ AST:
.. code-block:: nim
# ...
nnkTypeDef(
nnkIdent(!"MyInt"),
nnkIdent("MyInt"),
nnkEmpty(),
nnkDistinctTy(
nnkIdent(!"int")
nnkIdent("int")
)
)
@ -1004,10 +1000,10 @@ AST:
.. code-block:: nim
nnkTypeSection(
nnkTypeDef(
nnkIdent(!"A"),
nnkIdent("A"),
nnkGenericParams(
nnkIdentDefs(
nnkIdent(!"T"),
nnkIdent("T"),
nnkEmpty(), # if the type is declared with options, like
# ``[T: SomeInteger]``, they are given here
nnkEmpty(),
@ -1031,12 +1027,12 @@ AST:
.. code-block:: nim
# ...
nnkTypeDef(
nnkIdent(!"IO"),
nnkIdent("IO"),
nnkEmpty(),
nnkObjectTy(
nnkEmpty(), # no pragmas here
nnkOfInherit(
nnkIdent(!"RootObj") # inherits from RootObj
nnkIdent("RootObj") # inherits from RootObj
)
nnkEmpty()
)
@ -1062,43 +1058,43 @@ AST:
# ...
nnkObjectTy(
nnkPragma(
nnkIdent(!"inheritable")
nnkIdent("inheritable")
),
nnkEmpty(),
nnkRecList( # list of object parameters
nnkIdentDefs(
nnkIdent(!"name"),
nnkIdent(!"string"),
nnkIdent("name"),
nnkIdent("string"),
nnkEmpty()
),
nnkRecCase( # case statement within object (not nnkCaseStmt)
nnkIdentDefs(
nnkIdent(!"isFat"),
nnkIdent(!"bool"),
nnkIdent("isFat"),
nnkIdent("bool"),
nnkEmpty()
),
nnkOfBranch(
nnkIdent(!"true"),
nnkIdent("true"),
nnkRecList( # again, a list of object parameters
nnkIdentDefs(
nnkIdent(!"m"),
nnkIdent("m"),
nnkBracketExpr(
nnkIdent(!"array"),
nnkIdent("array"),
nnkIntLit(100000),
nnkIdent(!"T")
nnkIdent("T")
),
nnkEmpty()
)
),
nnkOfBranch(
nnkIdent(!"false"),
nnkIdent("false"),
nnkRecList(
nnkIdentDefs(
nnkIdent(!"m"),
nnkIdent("m"),
nnkBracketExpr(
nnkIdent(!"array"),
nnkIdent("array"),
nnkIntLit(10),
nnkIdent(!"T")
nnkIdent("T")
),
nnkEmpty()
)
@ -1123,7 +1119,7 @@ AST:
# ...
nnkEnumTy(
nnkEmpty(),
nnkIdent(!"First") # you need at least one nnkIdent or the compiler complains
nnkIdent("First") # you need at least one nnkIdent or the compiler complains
)
The usage of ``concept`` (experimental) is similar to objects.
@ -1158,9 +1154,9 @@ AST:
.. code-block:: nim
# ... within nnkGenericParams
nnkIdentDefs(
nnkIdent(!"T"),
nnkIdent("T"),
nnkStaticTy(
nnkIdent(!"int")
nnkIdent("int")
),
nnkEmpty()
)
@ -1180,7 +1176,7 @@ Nim type Corresponding AST
``distinct`` ``nnkDistinctTy``
``enum`` ``nnkEnumTy``
``concept`` ``nnkTypeClassTy``\*
``array`` ``nnkBracketExpr(nnkIdent(!"array"),...``\*
``array`` ``nnkBracketExpr(nnkIdent("array"),...``\*
``proc`` ``nnkProcTy``
``iterator`` ``nnkIteratorTy``
``object`` ``nnkObjectTy``
@ -1200,7 +1196,7 @@ AST:
.. code-block:: nim
# ...
nnkTypeDef(
nnkIdent(!"MyProc"),
nnkIdent("MyProc"),
nnkGenericParams( # here, not with the proc
# ...
)
@ -1225,7 +1221,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkMixinStmt(nnkIdent(!"x"))
nnkMixinStmt(nnkIdent("x"))
Bind statement
--------------
@ -1238,7 +1234,7 @@ Concrete syntax:
AST:
.. code-block:: nim
nnkBindStmt(nnkIdent(!"x"))
nnkBindStmt(nnkIdent("x"))
Procedure declaration
---------------------
@ -1255,26 +1251,26 @@ AST:
.. code-block:: nim
nnkProcDef(
nnkPostfix(nnkIdent(!"*"), nnkIdent(!"hello")), # the exported proc name
nnkPostfix(nnkIdent("*"), nnkIdent("hello")), # the exported proc name
nnkEmpty(), # patterns for term rewriting in templates and macros (not procs)
nnkGenericParams( # generic type parameters, like with type declaration
nnkIdentDefs(
nnkIdent(!"T"), nnkIdent(!"SomeInteger")
nnkIdent("T"), nnkIdent("SomeInteger")
)
),
nnkFormalParams(
nnkIdent(!"int"), # the first FormalParam is the return type. nnkEmpty() if there is none
nnkIdent("int"), # the first FormalParam is the return type. nnkEmpty() if there is none
nnkIdentDefs(
nnkIdent(!"x"),
nnkIdent(!"int"), # type type (required for procs, not for templates)
nnkIdent("x"),
nnkIdent("int"), # type type (required for procs, not for templates)
nnkIntLit(3) # a default value
),
nnkIdentDefs(
nnkIdent(!"y"),
nnkIdent(!"float32"),
nnkIdent("y"),
nnkIdent("float32"),
nnkEmpty()
)
nnkPragma(nnkIdent(!"inline")),
nnkPragma(nnkIdent("inline")),
nnkEmpty(), # reserved slot for future use
nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc
)
@ -1296,9 +1292,9 @@ AST:
nnkFormalParams(
nnkEmpty(), # no return here
nnkIdentDefs(
nnkIdent(!"a"), # the first parameter
nnkIdent(!"b"), # directly to the second parameter
nnkIdent(!"int"), # their shared type identifier
nnkIdent("a"), # the first parameter
nnkIdent("b"), # directly to the second parameter
nnkIdent("int"), # their shared type identifier
nnkEmpty(), # default value would go here
)
),
@ -1318,7 +1314,7 @@ AST:
# ...
nnkFormalParams(
nnkVarTy(
nnkIdent(!"int")
nnkIdent("int")
)
)
@ -1337,7 +1333,7 @@ AST:
.. code-block:: nim
nnkIteratorDef(
nnkIdent(!"nonsense"),
nnkIdent("nonsense"),
nnkEmpty(),
...
)
@ -1356,7 +1352,7 @@ AST:
.. code-block:: nim
nnkConverterDef(
nnkIdent(!"toBool"),
nnkIdent("toBool"),
# ...
)
@ -1378,7 +1374,7 @@ AST:
.. code-block:: nim
nnkTemplateDef(
nnkIdent(!"optOpt"),
nnkIdent("optOpt"),
nnkStmtList( # instead of nnkEmpty()
expr1
),

View file

@ -118,7 +118,7 @@ type
## use ``ident"abc"``.
NimSymObj = object # hidden
NimSym* = ref NimSymObj
NimSym* {.deprecated.} = ref NimSymObj
## represents a Nim *symbol* in the compiler; a *symbol* is a looked-up
## *ident*.
@ -134,25 +134,23 @@ const
proc `!`*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated.}
## constructs an identifier from the string `s`
## **Deprecated since version 0.18.0**: Use ``toNimIdent`` instead.
## **Deprecated since version 0.18.0**: Use ``ident`` or ``newIdentNode`` instead.
proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect.}
proc toNimIdent*(s: string): NimIdent {.magic: "StrToIdent", noSideEffect, deprecated.}
## constructs an identifier from the string `s`
## **Deprecated since version 0.18.1**; Use ``ident`` or ``newIdentNode`` instead.
proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
## converts a Nim identifier to a string
proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
## converts a Nim symbol to a string
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect.}
proc `==`*(a, b: NimIdent): bool {.magic: "EqIdent", noSideEffect, deprecated.}
## compares two Nim identifiers
## **Deprecated since version 0.18.1**; Use ``==`` on ``NimNode`` instead.
proc `==`*(a, b: NimNode): bool {.magic: "EqNimrodNode", noSideEffect.}
## compares two Nim nodes
proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect.}
proc `==`*(a, b: NimSym): bool {.magic: "EqNimrodNode", noSideEffect, deprecated.}
## compares two Nim symbols
## **Deprecated since version 0.18.1**; Use ```==`(NimNode,NimNode)`` instead.
proc sameType*(a, b: NimNode): bool {.magic: "SameNodeType", noSideEffect.} =
## compares two Nim nodes' types. Return true if the types are the same,
@ -195,8 +193,47 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect, deprecated.} =
## **Deprecated since version 0.18.1**; All functionality is defined on ``NimNode``.
proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect, deprecated.}
## **Deprecated since version 0.18.1**; All functionality is defined on ``NimNode``.
proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect, deprecated: "use `getImpl: NimNode -> NimNode` instead".}
when defined(nimSymKind):
proc symKind*(symbol: NimNode): NimSymKind {.magic: "NSymKind", noSideEffect.}
proc getImpl*(symbol: NimNode): NimNode {.magic: "GetImpl", noSideEffect.}
proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
## retrieve the implementation of `symbol`. `symbol` can be a
## routine or a const.
proc `$`*(i: NimIdent): string {.magic: "NStrVal", noSideEffect, deprecated.}
## converts a Nim identifier to a string
## **Deprecated since version 0.18.1**; Use ``strVal`` instead.
proc `$`*(s: NimSym): string {.magic: "NStrVal", noSideEffect, deprecated.}
## converts a Nim symbol to a string
## **Deprecated since version 0.18.1**; Use ``strVal`` instead.
else: # bootstrapping substitute
proc getImpl*(symbol: NimNode): NimNode =
symbol.symbol.getImpl
proc strValOld(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
proc `$`*(s: NimSym): string {.magic: "IdentToStr", noSideEffect.}
proc `$`*(i: NimIdent): string {.magic: "IdentToStr", noSideEffect.}
proc strVal*(n: NimNode): string =
if n.kind == nnkIdent:
$n.ident
elif n.kind == nnkSym:
$n.symbol
else:
n.strValOld
proc getType*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
## with 'getType' you can access the node's `type`:idx:. A Nim type is
@ -228,12 +265,15 @@ proc getTypeImpl*(n: NimNode): NimNode {.magic: "NGetType", noSideEffect.}
proc getTypeImpl*(n: typedesc): NimNode {.magic: "NGetType", noSideEffect.}
## Like getType except it includes generic parameters for the implementation
proc strVal*(n: NimNode): string {.magic: "NStrVal", noSideEffect.}
proc `intVal=`*(n: NimNode, val: BiggestInt) {.magic: "NSetIntVal", noSideEffect.}
proc `floatVal=`*(n: NimNode, val: BiggestFloat) {.magic: "NSetFloatVal", noSideEffect.}
proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect.}
proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect.}
proc `symbol=`*(n: NimNode, val: NimSym) {.magic: "NSetSymbol", noSideEffect, deprecated.}
## **Deprecated since version 0.18.1**; Generate a new ``NimNode`` with ``genSym`` instead.
proc `ident=`*(n: NimNode, val: NimIdent) {.magic: "NSetIdent", noSideEffect, deprecated.}
## **Deprecated since version 0.18.1**; Generate a new ``NimNode`` with ``ident(string)`` instead.
#proc `typ=`*(n: NimNode, typ: typedesc) {.magic: "NSetType".}
# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
# can easily do:
@ -255,11 +295,6 @@ proc newNimNode*(kind: NimNodeKind,
proc copyNimNode*(n: NimNode): NimNode {.magic: "NCopyNimNode", noSideEffect.}
proc copyNimTree*(n: NimNode): NimNode {.magic: "NCopyNimTree", noSideEffect.}
proc getImpl*(s: NimSym): NimNode {.magic: "GetImpl", noSideEffect.} =
## retrieve the implementation of a symbol `s`. `s` can be a routine or a
## const.
discard
proc error*(msg: string, n: NimNode = nil) {.magic: "NError", benign.}
## writes an error message at compile time
@ -294,11 +329,9 @@ proc newIdentNode*(i: NimIdent): NimNode {.compileTime.} =
result = newNimNode(nnkIdent)
result.ident = i
proc newIdentNode*(i: string): NimNode {.compileTime.} =
## creates an identifier node from `i`
result = newNimNode(nnkIdent)
result.ident = toNimIdent i
proc newIdentNode*(i: string): NimNode {.magic: "StrToIdent", noSideEffect.}
## creates an identifier node from `i`. It is simply an alias for
## ``ident(string)``. Use that, it's shorter.
type
BindSymRule* = enum ## specifies how ``bindSym`` behaves
@ -464,9 +497,11 @@ proc newCall*(theProc: NimNode,
result.add(args)
proc newCall*(theProc: NimIdent,
args: varargs[NimNode]): NimNode {.compileTime.} =
args: varargs[NimNode]): NimNode {.compileTime, deprecated.} =
## produces a new call node. `theProc` is the proc that is called with
## the arguments ``args[0..]``.
## **Deprecated since version 0.18.1**; Use ``newCall(string, ...)``,
## or ``newCall(NimNode, ...)`` instead.
result = newNimNode(nnkCall)
result.add(newIdentNode(theProc))
result.add(args)
@ -594,17 +629,30 @@ proc newLit*(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkStrLit)
result.strVal = s
proc nestList*(theProc: NimIdent,
x: NimNode): NimNode {.compileTime.} =
## nests the list `x` into a tree of call expressions:
## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``.
proc nestList*(op: NimNode; pack: NimNode): NimNode {.compileTime.} =
## nests the list `pack` into a tree of call expressions:
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
## This is also known as fold expression.
if pack.len < 1:
error("`nestList` expects a node with at least 1 child")
result = pack[^1]
for i in countdown(pack.len - 2, 0):
result = newCall(op, pack[i], result)
proc nestList*(op: NimNode; pack: NimNode; init: NimNode): NimNode {.compileTime.} =
## nests the list `pack` into a tree of call expressions:
## ``[a, b, c]`` is transformed into ``op(a, op(c, d))``.
## This is also known as fold expression.
result = init
for i in countdown(pack.len - 1, 0):
result = newCall(op, pack[i], result)
proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime, deprecated.} =
## **Deprecated since version 0.18.1**; Use one of ``nestList(NimNode, ...)`` instead.
var L = x.len
result = newCall(theProc, x[L-2], x[L-1])
for i in countdown(L-3, 0):
# XXX the 'copyNimTree' here is necessary due to a bug in the evaluation
# engine that would otherwise create an endless loop here. :-(
# 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], result)
proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
## Convert the AST `n` to a human-readable tree-like string.
@ -620,9 +668,8 @@ proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
of nnkNilLit: res.add(" nil")
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
of nnkStrLit..nnkTripleStrLit: res.add(" " & $n.strVal.newLit.repr)
of nnkIdent: res.add(" ident\"" & $n.ident & '"')
of nnkSym: res.add(" \"" & $n.symbol & '"')
of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
res.add(" " & $n.strVal.newLit.repr)
of nnkNone: assert false
else:
for j in 0..n.len-1:
@ -645,9 +692,8 @@ proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
of nnkNilLit: add(result, "nil")
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: add(result, n.strVal.newLit.repr)
of nnkIdent: add(result, "ident\"" & $n.ident & '"')
of nnkSym: add(result, $n.symbol)
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
add(result, n.strVal.newLit.repr)
of nnkNone: assert false
else:
if n.len > 0:
@ -696,9 +742,8 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
of nnkCharLit: res.add("'" & $chr(n.intVal) & "'")
of nnkIntLit..nnkInt64Lit: res.add($n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add($n.floatVal)
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt: res.add($n.strVal.newLit.repr)
of nnkIdent: res.add(($n.ident).newLit.repr())
of nnkSym: res.add(($n.symbol).newLit.repr())
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
res.add(n.strVal.newLit.repr)
of nnkNone: assert false
else:
res.add(".newTree(")
@ -742,10 +787,10 @@ macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr
## See `dumpTree`.
macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
## Deprecated.
## Deprecated. Use `dumpTree` instead.
macro dumpLispImm*(s: untyped): untyped {.deprecated.} = echo s.lispRepr
## Deprecated.
## Deprecated. Use `dumpLisp` instead.
proc newEmptyNode*(): NimNode {.compileTime, noSideEffect.} =
## Create a new empty node
@ -991,28 +1036,21 @@ proc `body=`*(someProc: NimNode, val: NimNode) {.compileTime.} =
proc basename*(a: NimNode): NimNode {.compiletime, benign.}
proc `$`*(node: NimNode): string {.compileTime.} =
## Get the string of an identifier node
case node.kind
of nnkIdent:
result = $node.ident
of nnkPostfix:
result = $node.basename.ident & "*"
of nnkStrLit..nnkTripleStrLit:
result = node.basename.strVal & "*"
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkSym, nnkIdent:
result = node.strVal
of nnkSym:
result = $node.symbol
of nnkOpenSymChoice, nnkClosedSymChoice:
result = $node[0]
of nnkAccQuoted:
result = $node[0]
of nnkCommentStmt:
result = node.strVal
else:
badNodeKind node.kind, "$"
proc ident*(name: string): NimNode {.compileTime,inline.} = newIdentNode(name)
proc ident*(name: string): NimNode {.magic: "StrToIdent", noSideEffect.}
## Create a new ident node from a string
iterator items*(n: NimNode): NimNode {.inline.} =
@ -1129,10 +1167,8 @@ proc eqIdent*(node: NimNode; s: string): bool {.compileTime.} =
## is the same as ``s``. Note that this is the preferred way to check! Most
## other ways like ``node.ident`` are much more error-prone, unfortunately.
case node.kind
of nnkIdent:
result = node.ident == toNimIdent s
of nnkSym:
result = eqIdent($node.symbol, s)
of nnkSym, nnkIdent:
result = eqIdent(node.strVal, s)
of nnkOpenSymChoice, nnkClosedSymChoice:
result = eqIdent($node[0], s)
else:
@ -1189,11 +1225,11 @@ macro expandMacros*(body: typed): untyped =
proc customPragmaNode(n: NimNode): NimNode =
expectKind(n, {nnkSym, nnkDotExpr})
if n.kind == nnkSym:
let sym = n.symbol.getImpl()
let sym = n.getImpl()
sym.expectRoutine()
result = sym.pragma
elif n.kind == nnkDotExpr:
let typDef = getImpl(getTypeInst(n[0]).symbol)
let typDef = getImpl(getTypeInst(n[0]))
typDef.expectKind(nnkTypeDef)
typDef[2].expectKind(nnkObjectTy)
let recList = typDef[2][2]

View file

@ -92,8 +92,10 @@ proc xmlCheckedTag*(e: NimNode, tag: string, optAttr = "", reqAttr = "",
result.add(newStrLitNode("</"))
result.add(newStrLitNode(tag))
result.add(newStrLitNode(">"))
result = nestList(!"&", result)
when compiles(nestList(ident"&", result)):
result = nestList(ident"&", result)
else:
result = nestList(!"&", result)
macro a*(e: varargs[untyped]): untyped =
## generates the HTML ``a`` element.

View file

@ -28,6 +28,7 @@ macro async2(prc: untyped): untyped =
# -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
# Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
var iteratorNameSym = genSym(nskIterator, $prc[0].ident & "Iter")
assert iteratorNameSym.symKind == nskIterator
#var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
var procBody = prc[6].convertReturns(retFutureSym)
@ -42,6 +43,7 @@ macro async2(prc: untyped): untyped =
var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym)
outerProcBody.add varNameIter
var varFirstSym = genSym(nskVar, "first")
assert varFirstSym.symKind == nskVar
var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym))
outerProcBody.add varFirst

View file

@ -1,82 +1,82 @@
discard """
nimout: '''
StmtList
Ident ident"foo010"
Ident "foo010"
Call
Ident ident"foo020"
Ident "foo020"
Call
Ident ident"foo030"
Ident ident"x"
Ident "foo030"
Ident "x"
Command
Ident ident"foo040"
Ident ident"x"
Ident "foo040"
Ident "x"
Call
Ident ident"foo050"
Ident "foo050"
StmtList
DiscardStmt
Empty
Call
Ident ident"foo060"
Ident "foo060"
StmtList
DiscardStmt
Empty
Call
Ident ident"foo070"
Ident "foo070"
StrLit "test"
StmtList
DiscardStmt
Empty
Call
Ident ident"foo080"
Ident "foo080"
StrLit "test"
StmtList
DiscardStmt
Empty
Command
Ident ident"foo090"
Ident "foo090"
StrLit "test"
StmtList
DiscardStmt
Empty
Command
Ident ident"foo100"
Ident "foo100"
Call
StrLit "test"
StmtList
DiscardStmt
Empty
Command
Ident ident"foo101"
Ident "foo101"
Call
IntLit 10
StmtList
DiscardStmt
Empty
Command
Ident ident"foo110"
Ident "foo110"
IntLit 1
Par
Infix
Ident ident"+"
Ident "+"
IntLit 2
IntLit 3
StmtList
DiscardStmt
Empty
Command
Ident ident"foo120"
Ident "foo120"
IntLit 1
Call
Par
Infix
Ident ident"+"
Ident "+"
IntLit 2
IntLit 3
StmtList
DiscardStmt
Empty
Call
Ident ident"foo130"
Ident "foo130"
Do
Empty
Empty
@ -84,7 +84,7 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"x"
Ident "x"
Empty
Empty
Empty
@ -93,7 +93,7 @@ StmtList
DiscardStmt
Empty
Call
Ident ident"foo140"
Ident "foo140"
Do
Empty
Empty
@ -101,8 +101,8 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"x"
Ident ident"int"
Ident "x"
Ident "int"
Empty
Empty
Empty
@ -110,16 +110,16 @@ StmtList
DiscardStmt
Empty
Call
Ident ident"foo150"
Ident "foo150"
Do
Empty
Empty
Empty
FormalParams
Ident ident"int"
Ident "int"
IdentDefs
Ident ident"x"
Ident ident"int"
Ident "x"
Ident "int"
Empty
Empty
Empty
@ -127,9 +127,9 @@ StmtList
DiscardStmt
Empty
Command
Ident ident"foo160"
Ident "foo160"
Call
Ident ident"x"
Ident "x"
Do
Empty
Empty
@ -137,7 +137,7 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"y"
Ident "y"
Empty
Empty
Empty
@ -146,7 +146,7 @@ StmtList
DiscardStmt
Empty
Call
Ident ident"foo170"
Ident "foo170"
StmtList
DiscardStmt
Empty
@ -155,7 +155,7 @@ StmtList
DiscardStmt
Empty
Call
Ident ident"foo180"
Ident "foo180"
StmtList
DiscardStmt
Empty
@ -167,9 +167,9 @@ StmtList
DiscardStmt
Empty
Command
Ident ident"foo190"
Ident "foo190"
Call
Ident ident"x"
Ident "x"
Do
Empty
Empty
@ -177,7 +177,7 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"y"
Ident "y"
Empty
Empty
Empty
@ -190,9 +190,9 @@ StmtList
Empty
Empty
FormalParams
Ident ident"int"
Ident "int"
IdentDefs
Ident ident"z"
Ident "z"
Empty
Empty
Empty
@ -205,10 +205,10 @@ StmtList
Empty
Empty
FormalParams
Ident ident"int"
Ident "int"
IdentDefs
Ident ident"w"
Ident ident"int"
Ident "w"
Ident "int"
Empty
Empty
Empty
@ -223,10 +223,10 @@ StmtList
DiscardStmt
Empty
Call
Ident ident"foo200"
Ident ident"x"
Ident "foo200"
Ident "x"
Call
Ident ident"bar"
Ident "bar"
StmtList
DiscardStmt
Empty
@ -236,53 +236,53 @@ StmtList
Empty
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Ident ident"foo210"
Ident "foo210"
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Call
Ident ident"foo220"
Ident "foo220"
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Call
Ident ident"foo230"
Ident ident"x"
Ident "foo230"
Ident "x"
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Command
Ident ident"foo240"
Ident ident"x"
Ident "foo240"
Ident "x"
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Call
Ident ident"foo250"
Ident "foo250"
StmtList
DiscardStmt
Empty
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Call
Ident ident"foo260"
Ident "foo260"
StmtList
DiscardStmt
Empty
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Call
Ident ident"foo270"
Ident "foo270"
StmtList
DiscardStmt
Empty
@ -292,12 +292,12 @@ StmtList
Empty
VarSection
IdentDefs
Ident ident"a"
Ident "a"
Empty
Command
Ident ident"foo280"
Ident "foo280"
Call
Ident ident"x"
Ident "x"
Do
Empty
Empty
@ -305,7 +305,7 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"y"
Ident "y"
Empty
Empty
Empty
@ -318,40 +318,40 @@ StmtList
DiscardStmt
Empty
Asgn
Ident ident"a"
Ident ident"foo290"
Ident "a"
Ident "foo290"
Asgn
Ident ident"a"
Ident "a"
Call
Ident ident"foo300"
Ident "foo300"
Asgn
Ident ident"a"
Ident "a"
Call
Ident ident"foo310"
Ident ident"x"
Ident "foo310"
Ident "x"
Asgn
Ident ident"a"
Ident "a"
Command
Ident ident"foo320"
Ident ident"x"
Ident "foo320"
Ident "x"
Asgn
Ident ident"a"
Ident "a"
Call
Ident ident"foo330"
Ident "foo330"
StmtList
DiscardStmt
Empty
Asgn
Ident ident"a"
Ident "a"
Call
Ident ident"foo340"
Ident "foo340"
StmtList
DiscardStmt
Empty
Asgn
Ident ident"a"
Ident "a"
Call
Ident ident"foo350"
Ident "foo350"
StmtList
DiscardStmt
Empty
@ -360,13 +360,13 @@ StmtList
DiscardStmt
Empty
Asgn
Ident ident"a"
Ident "a"
Command
Ident ident"foo360"
Ident "foo360"
Call
DotExpr
Ident ident"x"
Ident ident"bar"
Ident "x"
Ident "bar"
Do
Empty
Empty
@ -374,7 +374,7 @@ StmtList
FormalParams
Empty
IdentDefs
Ident ident"y"
Ident "y"
Empty
Empty
Empty
@ -388,20 +388,20 @@ StmtList
Empty
Command
DotExpr
Ident ident"foo370"
Ident ident"add"
Ident "foo370"
Ident "add"
Call
Ident ident"quote"
Ident "quote"
StmtList
DiscardStmt
Empty
Call
DotExpr
Ident ident"foo380"
Ident ident"add"
Ident "foo380"
Ident "add"
BracketExpr
Call
Ident ident"quote"
Ident "quote"
StmtList
DiscardStmt
Empty

View file

@ -26,12 +26,12 @@ proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
seqAppend.add(arg) # bit this creates a copy
arg.add newCall(ident"echo", newLit("Hello World"))
assertEq arg.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq node.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq nodeSeq[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident(ident"echo"), StrLit("Hello World")))"""
assertEq arg.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
assertEq node.lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
assertEq nodeArray[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
assertEq nodeSeq[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
assertEq seqAppend[0].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
assertEq seqAppend[1].lispRepr , """StmtList(DiscardStmt(Empty()), Call(Ident("echo"), StrLit("Hello World")))"""
echo "OK"