mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +00:00
Improve dumpLisp macro (#9515)
* Improve dumpLisp macro
- Remove commas from the lisp representation of the AST.
- Make the dumpLisp output "pretty" and indented.
- Improve docs of `dumpTree` and `dumpLisp` macros.
With:
dumpLisp:
echo "Hello, World!"
Output before this commit:
StmtList(Command(Ident("echo"), StrLit("Hello, World!")))
Output after this commit:
(StmtList
(Command
(Ident "echo")
(StrLit "Hello, World!")))
* Re-use the traverse proc inside treeRepr for lispRepr too
- Add module-local `treeTraverse` proc.
- Also fix treeRepr/dumpTree not printing nnkCommentStmt node contents.
* More doc string updates
* Allow unindented lispRepr output for tests
* Update a test affected by the lispRepr change
* Fix dumpTree
* Add note about lispRepr and dumpLisp to changelog [ci skip]
This commit is contained in:
committed by
Dominik Picheta
parent
dd252ce640
commit
f8cef575b3
@@ -38,6 +38,9 @@
|
||||
|
||||
### Library changes
|
||||
|
||||
- The string output of `macros.lispRepr` proc has been tweaked
|
||||
slightly. The `dumpLisp` macro in this module now outputs an
|
||||
indented proper Lisp, devoid of commas.
|
||||
|
||||
### Language additions
|
||||
|
||||
|
||||
@@ -732,72 +732,56 @@ proc nestList*(theProc: NimIdent, x: NimNode): NimNode {.compileTime, deprecated
|
||||
for i in countdown(L-3, 0):
|
||||
result = newCall(theProc, x[i], result)
|
||||
|
||||
proc treeTraverse(n: NimNode; res: var string; level = 0; isLisp = false, indented = false) {.benign.} =
|
||||
if level > 0:
|
||||
if indented:
|
||||
res.add("\n")
|
||||
for i in 0 .. level-1:
|
||||
if isLisp:
|
||||
res.add(" ") # dumpLisp indentation
|
||||
else:
|
||||
res.add(" ") # dumpTree indentation
|
||||
else:
|
||||
res.add(" ")
|
||||
|
||||
if isLisp:
|
||||
res.add("(")
|
||||
res.add(($n.kind).substr(3))
|
||||
|
||||
case n.kind
|
||||
of nnkEmpty, nnkNilLit:
|
||||
discard # same as nil node in this representation
|
||||
of nnkCharLit .. nnkInt64Lit:
|
||||
res.add(" " & $n.intVal)
|
||||
of nnkFloatLit .. nnkFloat64Lit:
|
||||
res.add(" " & $n.floatVal)
|
||||
of nnkStrLit .. nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
|
||||
res.add(" " & $n.strVal.newLit.repr)
|
||||
of nnkNone:
|
||||
assert false
|
||||
else:
|
||||
for j in 0 .. n.len-1:
|
||||
n[j].treeTraverse(res, level+1, isLisp, indented)
|
||||
|
||||
if isLisp:
|
||||
res.add(")")
|
||||
|
||||
proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to a human-readable tree-like string.
|
||||
##
|
||||
## See also `repr`, `lispRepr`, and `astGenRepr`.
|
||||
n.treeTraverse(result, isLisp = false, indented = true)
|
||||
|
||||
proc traverse(res: var string, level: int, n: NimNode) {.benign.} =
|
||||
for i in 0..level-1: res.add " "
|
||||
res.add(($n.kind).substr(3))
|
||||
|
||||
case n.kind
|
||||
of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
|
||||
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
|
||||
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
|
||||
of nnkStrLit..nnkTripleStrLit, nnkIdent, nnkSym:
|
||||
res.add(" " & $n.strVal.newLit.repr)
|
||||
of nnkNone: assert false
|
||||
else:
|
||||
for j in 0..n.len-1:
|
||||
res.add "\n"
|
||||
traverse(res, level + 1, n[j])
|
||||
|
||||
result = ""
|
||||
traverse(result, 0, n)
|
||||
|
||||
proc lispRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to a human-readable lisp-like string,
|
||||
proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} =
|
||||
## Convert the AST ``n`` to a human-readable lisp-like string.
|
||||
##
|
||||
## See also `repr`, `treeRepr`, and `astGenRepr`.
|
||||
|
||||
result = ($n.kind).substr(3)
|
||||
add(result, "(")
|
||||
|
||||
case n.kind
|
||||
of nnkEmpty, nnkNilLit: discard # same as nil node in this representation
|
||||
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
|
||||
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
|
||||
of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkident, nnkSym:
|
||||
add(result, n.strVal.newLit.repr)
|
||||
of nnkNone: assert false
|
||||
else:
|
||||
if n.len > 0:
|
||||
add(result, lispRepr(n[0]))
|
||||
for j in 1..n.len-1:
|
||||
add(result, ", ")
|
||||
add(result, lispRepr(n[j]))
|
||||
|
||||
add(result, ")")
|
||||
## See also ``repr``, ``treeRepr``, and ``astGenRepr``.
|
||||
n.treeTraverse(result, isLisp = true, indented = indented)
|
||||
|
||||
proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
## Convert the AST `n` to the code required to generate that AST. So for example
|
||||
## Convert the AST ``n`` to the code required to generate that AST.
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## astGenRepr:
|
||||
## echo "Hello world"
|
||||
##
|
||||
## Would output:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## nnkStmtList.newTree(
|
||||
## nnkCommand.newTree(
|
||||
## newIdentNode("echo"),
|
||||
## newLit("Hello world")
|
||||
## )
|
||||
## )
|
||||
##
|
||||
## See also `repr`, `treeRepr`, and `lispRepr`.
|
||||
## See also ``repr``, ``treeRepr``, and ``lispRepr``.
|
||||
|
||||
const
|
||||
NodeKinds = {nnkEmpty, nnkIdent, nnkSym, nnkNone, nnkCommentStmt}
|
||||
@@ -842,26 +826,76 @@ proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
|
||||
|
||||
macro dumpTree*(s: untyped): untyped = echo s.treeRepr
|
||||
## Accepts a block of nim code and prints the parsed abstract syntax
|
||||
## tree using the `treeRepr` function. Printing is done *at compile time*.
|
||||
## tree using the ``treeRepr`` proc. Printing is done *at compile time*.
|
||||
##
|
||||
## You can use this as a tool to explore the Nim's abstract syntax
|
||||
## tree and to discover what kind of nodes must be created to represent
|
||||
## a certain expression/statement.
|
||||
|
||||
macro dumpLisp*(s: untyped): untyped = echo s.lispRepr
|
||||
## Accepts a block of nim code and prints the parsed abstract syntax
|
||||
## tree using the `lispRepr` function. Printing is done *at compile time*.
|
||||
##
|
||||
## See `dumpTree`.
|
||||
## For example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## dumpTree:
|
||||
## echo "Hello, World!"
|
||||
##
|
||||
## Outputs:
|
||||
##
|
||||
## .. code-block::
|
||||
## StmtList
|
||||
## Command
|
||||
## Ident "echo"
|
||||
## StrLit "Hello, World!"
|
||||
##
|
||||
## Also see ``dumpAstGen`` and ``dumpLisp``.
|
||||
|
||||
macro dumpLisp*(s: untyped): untyped = echo s.lispRepr(indented = true)
|
||||
## Accepts a block of nim code and prints the parsed abstract syntax
|
||||
## tree using the ``lispRepr`` proc. Printing is done *at compile time*.
|
||||
##
|
||||
## You can use this as a tool to explore the Nim's abstract syntax
|
||||
## tree and to discover what kind of nodes must be created to represent
|
||||
## a certain expression/statement.
|
||||
##
|
||||
## For example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## dumpLisp:
|
||||
## echo "Hello, World!"
|
||||
##
|
||||
## Outputs:
|
||||
##
|
||||
## .. code-block::
|
||||
## (StmtList
|
||||
## (Command
|
||||
## (Ident "echo")
|
||||
## (StrLit "Hello, World!")))
|
||||
##
|
||||
## Also see ``dumpAstGen`` and ``dumpTree``.
|
||||
|
||||
macro dumpAstGen*(s: untyped): untyped = echo s.astGenRepr
|
||||
## Accepts a block of nim code and prints the parsed abstract syntax
|
||||
## tree using the `astGenRepr` function. Printing is done *at compile time*.
|
||||
## tree using the ``astGenRepr`` proc. Printing is done *at compile time*.
|
||||
##
|
||||
## You can use this as a tool to write macros quicker by writing example
|
||||
## outputs and then copying the snippets into the macro for modification.
|
||||
##
|
||||
## See `dumpTree`.
|
||||
## For example:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## dumpAstGen:
|
||||
## echo "Hello, World!"
|
||||
##
|
||||
## Outputs:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
## nnkStmtList.newTree(
|
||||
## nnkCommand.newTree(
|
||||
## newIdentNode("echo"),
|
||||
## newLit("Hello, World!")
|
||||
## )
|
||||
## )
|
||||
##
|
||||
## Also see ``dumpTree`` and ``dumpLisp``.
|
||||
|
||||
macro dumpTreeImm*(s: untyped): untyped {.deprecated.} = echo s.treeRepr
|
||||
## Deprecated. Use `dumpTree` instead.
|
||||
|
||||
@@ -14,7 +14,7 @@ var nodeSeq {.compileTime.} = newSeq[NimNode](2)
|
||||
proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
|
||||
echo "checking ", name
|
||||
|
||||
assertEq arg.lispRepr , "StmtList(DiscardStmt(Empty()))"
|
||||
assertEq arg.lispRepr, """(StmtList (DiscardStmt (Empty)))"""
|
||||
|
||||
node = arg
|
||||
nodeArray = [arg]
|
||||
@@ -24,12 +24,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("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")))"""
|
||||
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"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user