summary refs log tree commit diff stats
path: root/lib/core
diff options
context:
space:
mode:
authorKaushal Modi <kaushal.modi@gmail.com>2018-10-27 09:10:05 -0400
committerDominik Picheta <dominikpicheta@googlemail.com>2018-10-27 14:10:05 +0100
commitf8cef575b322d9736df369e2a33f5ade7d800f95 (patch)
tree64656b79bd130ddf281d2fcfc5733d31f7b31043 /lib/core
parentdd252ce640c7f624acc08a6702193ec15fd7359b (diff)
downloadNim-f8cef575b322d9736df369e2a33f5ade7d800f95.tar.gz
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]
Diffstat (limited to 'lib/core')
-rw-r--r--lib/core/macros.nim158
1 files changed, 96 insertions, 62 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 3801adfc5..87daabb5b 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -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 treeRepr*(n: NimNode): string {.compileTime, benign.} =
-  ## Convert the AST `n` to a human-readable tree-like string.
-  ##
-  ## See also `repr`, `lispRepr`, and `astGenRepr`.
-
-  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
+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:
-      for j in 0..n.len-1:
-        res.add "\n"
-        traverse(res, level + 1, n[j])
+      res.add(" ")
 
-  result = ""
-  traverse(result, 0, n)
-
-proc lispRepr*(n: NimNode): 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, "(")
+  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: 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
+  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:
-    if n.len > 0:
-      add(result, lispRepr(n[0]))
-      for j in 1..n.len-1:
-        add(result, ", ")
-        add(result, lispRepr(n[j]))
+    for j in 0 .. n.len-1:
+      n[j].treeTraverse(res, level+1, isLisp, indented)
 
-  add(result, ")")
+  if isLisp:
+    res.add(")")
 
-proc astGenRepr*(n: NimNode): string {.compileTime, benign.} =
-  ## Convert the AST `n` to the code required to generate that AST. So for example
-  ##
-  ## .. code-block:: nim
-  ##   astGenRepr:
-  ##     echo "Hello world"
+proc treeRepr*(n: NimNode): string {.compileTime, benign.} =
+  ## Convert the AST `n` to a human-readable tree-like string.
   ##
-  ## Would output:
+  ## See also `repr`, `lispRepr`, and `astGenRepr`.
+  n.treeTraverse(result, isLisp = false, indented = true)
+
+proc lispRepr*(n: NimNode; indented = false): string {.compileTime, benign.} =
+  ## Convert the AST ``n`` to a human-readable lisp-like string.
   ##
-  ## .. code-block:: nim
-  ##   nnkStmtList.newTree(
-  ##     nnkCommand.newTree(
-  ##       newIdentNode("echo"),
-  ##       newLit("Hello world")
-  ##     )
-  ##   )
+  ## 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.
   ##
-  ## 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.
+  ##
+  ## 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
+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` function. Printing is done *at compile time*.
+  ## 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.
   ##
-  ## See `dumpTree`.
+  ## 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.