summary refs log tree commit diff stats
path: root/doc/astspec.txt
diff options
context:
space:
mode:
Diffstat (limited to 'doc/astspec.txt')
-rw-r--r--doc/astspec.txt727
1 files changed, 473 insertions, 254 deletions
diff --git a/doc/astspec.txt b/doc/astspec.txt
index f430677af..7a7053a2d 100644
--- a/doc/astspec.txt
+++ b/doc/astspec.txt
@@ -6,8 +6,7 @@ The AST consists of nodes (``NimNode``) with a variable number of
 children. Each node has a field named ``kind`` which describes what the node
 contains:
 
-.. code-block:: nim
-
+  ```nim
   type
     NimNodeKind = enum     ## kind of a node; only explanatory
       nnkNone,             ## invalid node kind
@@ -28,14 +27,11 @@ 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)
+  ```
 
 For the ``NimNode`` type, the ``[]`` operator has been overloaded:
 ``n[i]`` is ``n``'s ``i``-th child.
@@ -54,9 +50,9 @@ A leaf of the AST often corresponds to a terminal symbol in the concrete
 syntax. Note that the default ``float`` in Nim maps to ``float64`` such that
 the default AST for a float is ``nnkFloat64Lit`` as below.
 
------------------                ---------------------------------------------
+=================                =============================================
 Nim expression                   Corresponding AST
------------------                ---------------------------------------------
+=================                =============================================
 ``42``                           ``nnkIntLit(intVal = 42)``
 ``42'i8``                        ``nnkInt8Lit(intVal = 42)``
 ``42'i16``                       ``nnkInt16Lit(intVal = 42)``
@@ -74,9 +70,9 @@ 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
 get transferred into ``nnkSym`` nodes.
@@ -90,17 +86,19 @@ Command call
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   echo "abc", "xyz"
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCommand(
-    nnkIdent(!"echo"),
+    nnkIdent("echo"),
     nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
+  ```
 
 
 Call with ``()``
@@ -108,17 +106,19 @@ Call with ``()``
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   echo("abc", "xyz")
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCall(
-    nnkIdent(!"echo"),
+    nnkIdent("echo"),
     nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
+  ```
 
 
 Infix operator call
@@ -126,75 +126,83 @@ Infix operator call
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   "abc" & "xyz"
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkInfix(
-    nnkIdent(!"&"),
+    nnkIdent("&"),
     nnkStrLit("abc"),
     nnkStrLit("xyz")
   )
+  ```
 
 Note that with multiple infix operators, the command is parsed by operator
 precedence.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   5 + 3 * 4
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkInfix(
-    nnkIdent(!"+"),
+    nnkIdent("+"),
     nnkIntLit(5),
     nnkInfix(
-      nnkIdent(!"*"),
+      nnkIdent("*"),
       nnkIntLit(3),
       nnkIntLit(4)
     )
   )
+  ```
 
 As a side note, if you choose to use infix operators in a prefix form, the AST
 behaves as a
-[parenthetical function call](./macros.html#calls-expressions-call-with) with
+[parenthetical function call](#callsslashexpressions-call-with) with
 ``nnkAccQuoted``, as follows:
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   `+`(3, 4)
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCall(
     nnkAccQuoted(
-      nnkIdent(!"+")
+      nnkIdent("+")
     ),
     nnkIntLit(3),
     nnkIntLit(4)
   )
+  ```
 
 Prefix operator call
 --------------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   ? "xyz"
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkPrefix(
-    nnkIdent(!"?"),
+    nnkIdent("?"),
     nnkStrLit("abc")
   )
+  ```
 
 
 Postfix operator call
@@ -205,16 +213,18 @@ Postfix operator call
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   identifier*
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkPostfix(
-    nnkIdent(!"*"),
-    nnkIdent(!"identifier")
+    nnkIdent("*"),
+    nnkIdent("identifier")
   )
+  ```
 
 
 Call with named arguments
@@ -222,53 +232,59 @@ Call with named arguments
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   writeLine(file=stdout, "hallo")
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCall(
-    nnkIdent(!"writeLine"),
+    nnkIdent("writeLine"),
     nnkExprEqExpr(
-      nnkIdent(!"file"),
-      nnkIdent(!"stdout")
+      nnkIdent("file"),
+      nnkIdent("stdout")
     ),
     nnkStrLit("hallo")
   )
+  ```
 
 Call with raw string literal
 ----------------------------
 
 This is used, for example, in the ``bindSym`` examples
-[here](http://nim-lang.org/docs/manual.html#macros-bindsym) and with
+[here](manual.html#macros-bindsym) and with
 ``re"some regexp"`` in the regular expression module.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   echo"abc"
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCallStrLit(
-    nnkIdent(!"echo"),
+    nnkIdent("echo"),
     nnkRStrLit("hello")
   )
+  ```
 
 Dereference operator ``[]``
 ---------------------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   x[]
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkDerefExpr(nnkIdent(!"x"))
+  ```nim
+  nnkDerefExpr(nnkIdent("x"))
+  ```
 
 
 Addr operator
@@ -276,13 +292,15 @@ Addr operator
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   addr(x)
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkAddr(nnkIdent(!"x"))
+  ```nim
+  nnkAddr(nnkIdent("x"))
+  ```
 
 
 Cast operator
@@ -290,13 +308,15 @@ Cast operator
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   cast[T](x)
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkCast(nnkIdent(!"T"), nnkIdent(!"x"))
+  ```nim
+  nnkCast(nnkIdent("T"), nnkIdent("x"))
+  ```
 
 
 Object access operator ``.``
@@ -304,13 +324,15 @@ Object access operator ``.``
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   x.y
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkDotExpr(nnkIdent(!"x"), nnkIdent(!"y"))
+  ```nim
+  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``.
@@ -321,31 +343,77 @@ Array access operator ``[]``
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   x[y]
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkBracketExpr(nnkIdent(!"x"), nnkIdent(!"y"))
+  ```nim
+  nnkBracketExpr(nnkIdent("x"), nnkIdent("y"))
+  ```
 
 
 Parentheses
 -----------
 
-Parentheses for affecting operator precedence or tuple construction
-are built with the ``nnkPar`` node.
+Parentheses for affecting operator precedence use the ``nnkPar`` node.
 
 Concrete syntax:
 
-.. code-block:: nim
-  (1, 2, (3))
+  ```nim
+  (a + b) * c
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkPar(nnkIntLit(1), nnkIntLit(2), nnkPar(nnkIntLit(3)))
+  ```nim
+  nnkInfix(nnkIdent("*"),
+    nnkPar(
+      nnkInfix(nnkIdent("+"), nnkIdent("a"), nnkIdent("b"))),
+    nnkIdent("c"))
+  ```
+
+Tuple Constructors
+------------------
+
+Nodes for tuple construction are built with the ``nnkTupleConstr`` node.
+
+Concrete syntax:
+
+  ```nim
+  (1, 2, 3)
+  (a: 1, b: 2, c: 3)
+  ()
+  ```
+
+AST:
+
+  ```nim
+  nnkTupleConstr(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
+  nnkTupleConstr(
+    nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)),
+    nnkExprColonExpr(nnkIdent("b"), nnkIntLit(2)),
+    nnkExprColonExpr(nnkIdent("c"), nnkIntLit(3)))
+  nnkTupleConstr()
+  ```
+
+Since the one tuple would be syntactically identical to parentheses
+with an expression in them, the parser expects a trailing comma for
+them. For tuple constructors with field names, this is not necessary.
 
+  ```nim
+  (1,)
+  (a: 1)
+  ```
+
+AST:
+
+  ```nim
+  nnkTupleConstr(nnkIntLit(1))
+  nnkTupleConstr(
+    nnkExprColonExpr(nnkIdent("a"), nnkIntLit(1)))
+  ```
 
 Curly braces
 ------------
@@ -354,28 +422,32 @@ Curly braces are used as the set constructor.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   {1, 2, 3}
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
+  ```
 
 When used as a table constructor, the syntax is different.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   {a: 3, b: 5}
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkTableConstr(
-    nnkExprColonExpr(nnkIdent(!"a"), nnkIntLit(3)),
-    nnkExprColonExpr(nnkIdent(!"b"), nnkIntLit(5))
+    nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)),
+    nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5))
   )
+  ```
 
 
 Brackets
@@ -385,13 +457,15 @@ Brackets are used as the array constructor.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   [1, 2, 3]
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
+  ```
 
 
 Ranges
@@ -403,22 +477,24 @@ AST, construction with ``..`` as an infix operator should be used instead.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   1..3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkInfix(
-    nnkIdent(!".."),
+    nnkIdent(".."),
     nnkIntLit(1),
     nnkIntLit(3)
   )
+  ```
 
 Example code:
 
-.. code-block:: nim
-  macro genRepeatEcho(): stmt =
+  ```nim
+  macro genRepeatEcho() =
     result = newNimNode(nnkStmtList)
 
     var forStmt = newNimNode(nnkForStmt) # generate a for statement
@@ -436,6 +512,7 @@ Example code:
                   # 3
                   # 3
                   # 3
+  ```
 
 
 If expression
@@ -445,40 +522,44 @@ The representation of the ``if`` expression is subtle, but easy to traverse.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   if cond1: expr1 elif cond2: expr2 else: expr3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkIfExpr(
     nnkElifExpr(cond1, expr1),
     nnkElifExpr(cond2, expr2),
     nnkElseExpr(expr3)
   )
+  ```
 
 Documentation Comments
 ----------------------
 
 Double-hash (``##``) comments in the code actually have their own format,
-but the comments do not yet show up in the AST, which will only show that
-a comment exists, not what it contains. Single-hash (``#``) comments are ignored.
+using ``strVal`` to get and set the comment text. Single-hash (``#``)
+comments are ignored.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   ## This is a comment
   ## This is part of the first comment
   stmt1
   ## Yet another
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCommentStmt() # only appears once for the first two lines!
   stmt1
   nnkCommentStmt() # another nnkCommentStmt because there is another comment
                    # (separate from the first)
+  ```
 
 Pragmas
 -------
@@ -489,37 +570,41 @@ objects, but the standalone ``emit`` pragma shows the basics with the AST.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   {.emit: "#include <stdio.h>".}
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkPragma(
     nnkExprColonExpr(
-      nnkIdent(!"emit"),
+      nnkIdent("emit"),
       nnkStrLit("#include <stdio.h>") # the "argument"
     )
   )
+  ```
 
 As many ``nnkIdent`` appear as there are pragmas between ``{..}``. Note that
 the declaration of new pragmas is essentially the same:
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   {.pragma: cdeclRename, cdecl.}
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```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
 ==========
@@ -532,7 +617,7 @@ there is no ``else`` branch, no ``nnkElse`` child exists.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   if cond1:
     stmt1
   elif cond2:
@@ -541,16 +626,18 @@ Concrete syntax:
     stmt3
   else:
     stmt4
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkIfStmt(
     nnkElifBranch(cond1, stmt1),
     nnkElifBranch(cond2, stmt2),
     nnkElifBranch(cond3, stmt3),
     nnkElse(stmt4)
   )
+  ```
 
 
 When statement
@@ -564,13 +651,15 @@ Assignment
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   x = 42
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkAsgn(nnkIdent(!"x"), nnkIntLit(42))
+  ```nim
+  nnkAsgn(nnkIdent("x"), nnkIntLit(42))
+  ```
 
 This is not the syntax for assignment when combined with ``var``, ``let``,
 or ``const``.
@@ -580,15 +669,17 @@ Statement list
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   stmt1
   stmt2
   stmt3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkStmtList(stmt1, stmt2, stmt3)
+  ```
 
 
 Case statement
@@ -596,7 +687,7 @@ Case statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   case expr1
   of expr2, expr3..expr4:
     stmt1
@@ -606,10 +697,11 @@ Concrete syntax:
     stmt3
   else:
     stmt4
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkCaseStmt(
     expr1,
     nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1),
@@ -617,6 +709,7 @@ AST:
     nnkElifBranch(cond1, stmt3),
     nnkElse(stmt4)
   )
+  ```
 
 The ``nnkElifBranch`` and ``nnkElse`` parts may be missing.
 
@@ -626,14 +719,16 @@ While statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   while expr1:
     stmt1
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkWhileStmt(expr1, stmt1)
+  ```
 
 
 For statement
@@ -641,14 +736,16 @@ For statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   for ident1, ident2 in expr1:
     stmt1
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkForStmt(ident1, ident2, expr1, stmt1)
+  ```
 
 
 Try statement
@@ -656,7 +753,7 @@ Try statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   try:
     stmt1
   except e1, e2:
@@ -667,10 +764,11 @@ Concrete syntax:
     stmt4
   finally:
     stmt5
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkTryStmt(
     stmt1,
     nnkExceptBranch(e1, e2, stmt2),
@@ -678,6 +776,7 @@ AST:
     nnkExceptBranch(stmt4),
     nnkFinally(stmt5)
   )
+  ```
 
 
 Return statement
@@ -685,13 +784,15 @@ Return statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   return expr1
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkReturnStmt(expr1)
+  ```
 
 
 Yield statement
@@ -699,8 +800,9 @@ Yield statement
 
 Like ``return``, but with ``nnkYieldStmt`` kind.
 
-.. code-block:: nim
+  ```nim
   nnkYieldStmt(expr1)
+  ```
 
 
 Discard statement
@@ -708,8 +810,9 @@ Discard statement
 
 Like ``return``, but with ``nnkDiscardStmt`` kind.
 
-.. code-block:: nim
+  ```nim
   nnkDiscardStmt(expr1)
+  ```
 
 
 Continue statement
@@ -717,26 +820,30 @@ Continue statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   continue
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkContinueStmt()
+  ```
 
 Break statement
 ---------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   break otherLocation
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkBreakStmt(nnkIdent(!"otherLocation"))
+  ```nim
+  nnkBreakStmt(nnkIdent("otherLocation"))
+  ```
 
 If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``.
 
@@ -745,13 +852,15 @@ Block statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   block name:
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkBlockStmt(nnkIdent(!"name"), nnkStmtList(...))
+  ```nim
+  nnkBlockStmt(nnkIdent("name"), nnkStmtList(...))
+  ```
 
 A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used.
 
@@ -760,18 +869,20 @@ Asm statement
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   asm """
     some asm
   """
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkAsmStmt(
     nnkEmpty(), # for pragmas
     nnkTripleStrLit("some asm"),
   )
+  ```
 
 Import section
 --------------
@@ -781,44 +892,50 @@ on what keywords are present. Let's start with the simplest form.
 
 Concrete syntax:
 
-.. code-block:: nim
-  import math
+  ```nim
+  import std/math
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkImportStmt(nnkIdent(!"math"))
+  ```nim
+  nnkImportStmt(nnkIdent("math"))
+  ```
 
 With ``except``, we get ``nnkImportExceptStmt``.
 
 Concrete syntax:
 
-.. code-block:: nim
-  import math except pow
+  ```nim
+  import std/math except pow
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkImportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow"))
+  ```nim
+  nnkImportExceptStmt(nnkIdent("math"),nnkIdent("pow"))
+  ```
 
-Note that ``import math as m`` does not use a different node; rather,
+Note that ``import std/math as m`` does not use a different node; rather,
 we use ``nnkImportStmt`` with ``as`` as an infix operator.
 
 Concrete syntax:
 
-.. code-block:: nim
-  import strutils as su
+  ```nim
+  import std/strutils as su
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkImportStmt(
     nnkInfix(
-      nnkIdent(!"as"),
-      nnkIdent(!"strutils"),
-      nnkIdent(!"su")
+      nnkIdent("as"),
+      nnkIdent("strutils"),
+      nnkIdent("su")
     )
   )
+  ```
 
 From statement
 --------------
@@ -827,15 +944,17 @@ If we use ``from ... import``, the result is different, too.
 
 Concrete syntax:
 
-.. code-block:: nim
-  from math import pow
+  ```nim
+  from std/math import pow
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkFromStmt(nnkIdent(!"math"), nnkIdent(!"pow"))
+  ```nim
+  nnkFromStmt(nnkIdent("math"), nnkIdent("pow"))
+  ```
 
-Using ``from math as m import pow`` works identically to the ``as`` modifier
+Using ``from std/math as m import pow`` works identically to the ``as`` modifier
 with the ``import`` statement, but wrapped in ``nnkFromStmt``.
 
 Export statement
@@ -846,26 +965,30 @@ the ``export`` syntax is pretty straightforward.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   export unsigned
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkExportStmt(nnkIdent(!"unsigned"))
+  ```nim
+  nnkExportStmt(nnkIdent("unsigned"))
+  ```
 
 Similar to the ``import`` statement, the AST is different for
 ``export ... except``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   export math except pow # we're going to implement our own exponentiation
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkExportExceptStmt(nnkIdent(!"math"),nnkIdent(!"pow"))
+  ```nim
+  nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow"))
+  ```
 
 Include statement
 -----------------
@@ -874,39 +997,43 @@ Like a plain ``import`` statement but with ``nnkIncludeStmt``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   include blocks
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkIncludeStmt(nnkIdent(!"blocks"))
+  ```nim
+  nnkIncludeStmt(nnkIdent("blocks"))
+  ```
 
 Var section
 -----------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   var a = 3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkVarSection(
     nnkIdentDefs(
-      nnkIdent(!"a"),
+      nnkIdent("a"),
       nnkEmpty(), # or nnkIdent(...) if the variable declares the type
       nnkIntLit(3),
     )
   )
+  ```
 
 Note that either the second or third (or both) parameters above must exist,
 as the compiler needs to know the type somehow (which it can infer from
 the given assignment).
 
 This is not the same AST for all uses of ``var``. See
-[Procedure declaration](http://nim-lang.org/docs/macros.html#statements-procedure-declaration)
+[Procedure declaration](macros.html#statements-procedure-declaration)
 for details.
 
 Let section
@@ -917,38 +1044,42 @@ This is equivalent to ``var``, but with ``nnkLetSection`` rather than
 
 Concrete syntax:
 
-.. code-block:: nim
-  let v = 3
+  ```nim
+  let a = 3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkLetSection(
     nnkIdentDefs(
-      nnkIdent(!"a"),
+      nnkIdent("a"),
       nnkEmpty(), # or nnkIdent(...) for the type
       nnkIntLit(3),
     )
   )
+  ```
 
 Const section
 -------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   const a = 3
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```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!
     )
   )
+  ```
 
 Type section
 ------------
@@ -958,56 +1089,61 @@ and ``const``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type A = int
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkTypeSection(
     nnkTypeDef(
-      nnkIdent(!"A"),
+      nnkIdent("A"),
       nnkEmpty(),
-      nnkIdent(!"int")
+      nnkIdent("int")
     )
   )
+  ```
 
 Declaring ``distinct`` types is similar, with the last ``nnkIdent`` wrapped
 in ``nnkDistinctTy``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type MyInt = distinct int
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   nnkTypeDef(
-    nnkIdent(!"MyInt"),
+    nnkIdent("MyInt"),
     nnkEmpty(),
     nnkDistinctTy(
-      nnkIdent(!"int")
+      nnkIdent("int")
     )
   )
+  ```
 
 If a type section uses generic parameters, they are treated here:
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type A[T] = expr1
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```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(),
@@ -1016,89 +1152,101 @@ AST:
       expr1,
     )
   )
+  ```
 
 Note that not all ``nnkTypeDef`` utilize ``nnkIdent`` as their
-their parameter. One of the most common uses of type declarations
+parameter. One of the most common uses of type declarations
 is to work with objects.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type IO = object of RootObj
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   nnkTypeDef(
-    nnkIdent(!"IO"),
+    nnkIdent("IO"),
     nnkEmpty(),
     nnkObjectTy(
       nnkEmpty(), # no pragmas here
       nnkOfInherit(
-        nnkIdent(!"RootObj") # inherits from RootObj
-      )
+        nnkIdent("RootObj") # inherits from RootObj
+      ),
       nnkEmpty()
     )
   )
+  ```
 
 Nim's object syntax is rich. Let's take a look at an involved example in
 its entirety to see some of the complexities.
 
 Concrete syntax:
 
-.. code-block:: nim
-  type Obj[T] = object {.inheritable.}
+  ```nim
+  type Obj[T] {.inheritable.} = object
     name: string
     case isFat: bool
     of true:
       m: array[100_000, T]
     of false:
       m: array[10, T]
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
+  nnkPragmaExpr(
+    nnkIdent("Obj"),
+    nnkPragma(nnkIdent("inheritable"))
+  ),
+  nnkGenericParams(
+  nnkIdentDefs(
+    nnkIdent("T"),
+    nnkEmpty(),
+    nnkEmpty())
+  ),
   nnkObjectTy(
-    nnkPragma(
-      nnkIdent(!"inheritable")
-    ),
+    nnkEmpty(),
     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()
             )
@@ -1107,71 +1255,78 @@ AST:
       )
     )
   )
+  ```
 
 
 Using an ``enum`` is similar to using an ``object``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type X = enum
     First
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   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.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type Con = concept x,y,z
     (x & y & z) is string
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   nnkTypeClassTy( # note this isn't nnkConceptTy!
-    nnkArglist(
+    nnkArgList(
       # ... idents for x, y, z
     )
     # ...
   )
+  ```
 
 Static types, like ``static[int]``, use ``nnkIdent`` wrapped in
 ``nnkStaticTy``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   type A[T: static[int]] = object
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ... within nnkGenericParams
   nnkIdentDefs(
-    nnkIdent(!"T"),
+    nnkIdent("T"),
     nnkStaticTy(
-      nnkIdent(!"int")
+      nnkIdent("int")
     ),
     nnkEmpty()
   )
   # ...
+  ```
 
 In general, declaring types mirrors this syntax (i.e., ``nnkStaticTy`` for
 ``static``, etc.). Examples follow (exceptions marked by ``*``):
 
--------------                ---------------------------------------------
+=============                =============================================
 Nim type                     Corresponding AST
--------------                ---------------------------------------------
+=============                =============================================
 ``static``                   ``nnkStaticTy``
 ``tuple``                    ``nnkTupleTy``
 ``var``                      ``nnkVarTy``
@@ -1180,11 +1335,11 @@ Nim type                     Corresponding AST
 ``distinct``                 ``nnkDistinctTy``
 ``enum``                     ``nnkEnumTy``
 ``concept``                  ``nnkTypeClassTy``\*
-``array``                    ``nnkBracketExpr(nnkIdent(!"array"),...``\*
+``array``                    ``nnkBracketExpr(nnkIdent("array"),...``\*
 ``proc``                     ``nnkProcTy``
 ``iterator``                 ``nnkIteratorTy``
 ``object``                   ``nnkObjectTy``
--------------                ---------------------------------------------
+=============                =============================================
 
 Take special care when declaring types as ``proc``. The behavior is similar
 to ``Procedure declaration``, below, but does not treat ``nnkGenericParams``.
@@ -1192,53 +1347,91 @@ Generic parameters are treated in the type, not the ``proc`` itself.
 
 Concrete syntax:
 
-.. code-block:: nim
-  type MyProc[T] = proc(x: T)
+  ```nim
+  type MyProc[T] = proc(x: T) {.nimcall.}
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   nnkTypeDef(
-    nnkIdent(!"MyProc"),
+    nnkIdent("MyProc"),
     nnkGenericParams( # here, not with the proc
       # ...
     )
     nnkProcTy( # behaves like a procedure declaration from here on
       nnkFormalParams(
         # ...
-      )
+      ),
+      nnkPragma(nnkIdent("nimcall"))
     )
   )
+  ```
 
 The same syntax applies to ``iterator`` (with ``nnkIteratorTy``), but
 *does not* apply to ``converter`` or ``template``.
 
+Type class versions of these nodes generally share the same node kind but
+without any child nodes. The ``tuple`` type class is represented by
+``nnkTupleClassTy``, while a ``proc`` or ``iterator`` type class with pragmas
+has an ``nnkEmpty`` node in place of the ``nnkFormalParams`` node of a
+concrete ``proc`` or ``iterator`` type node.
+
+  ```nim
+  type TypeClass = proc {.nimcall.} | ref | tuple
+  ```
+
+AST:
+
+  ```nim
+  nnkTypeDef(
+    nnkIdent("TypeClass"),
+    nnkEmpty(),
+    nnkInfix(
+      nnkIdent("|"),
+      nnkProcTy(
+        nnkEmpty(),
+        nnkPragma(nnkIdent("nimcall"))
+      ),
+      nnkInfix(
+        nnkIdent("|"),
+        nnkRefTy(),
+        nnkTupleClassTy()
+      )
+    )
+  )
+  ```
+
 Mixin statement
 ---------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   mixin x
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkMixinStmt(nnkIdent(!"x"))
+  ```nim
+  nnkMixinStmt(nnkIdent("x"))
+  ```
 
 Bind statement
 --------------
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   bind x
+  ```
 
 AST:
 
-.. code-block:: nim
-  nnkBindStmt(nnkIdent(!"x"))
+  ```nim
+  nnkBindStmt(nnkIdent("x"))
+  ```
 
 Procedure declaration
 ---------------------
@@ -1248,37 +1441,41 @@ a feel for how procedure calls are broken down.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```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"),
+        nnkEmpty()
       )
     ),
     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")),
-      nnkEmpty(), # reserved slot for future use
-      nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc
-    )
+    ),
+    nnkPragma(nnkIdent("inline")),
+    nnkEmpty(), # reserved slot for future use
+    nnkStmtList(nnkDiscardStmt(nnkEmpty())) # the meat of the proc
   )
+  ```
 
 There is another consideration. Nim has flexible type identification for
 its procs. Even though ``proc(a: int, b: int)`` and ``proc(a, b: int)``
@@ -1286,41 +1483,45 @@ are equivalent in the code, the AST is a little different for the latter.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   proc(a, b: int)
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...AST as above...
   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
     )
   ),
   # ...
+  ```
 
 When a procedure uses the special ``var`` type return variable, the result
 is different from that of a var section.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   proc hello(): var int
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   # ...
   nnkFormalParams(
     nnkVarTy(
-      nnkIdent(!"int")
+      nnkIdent("int")
     )
   )
+  ```
 
 Iterator declaration
 --------------------
@@ -1330,17 +1531,19 @@ replacing ``nnkProcDef``.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   iterator nonsense[T](x: seq[T]): float {.closure.} = ...
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkIteratorDef(
-    nnkIdent(!"nonsense"),
+    nnkIdent("nonsense"),
     nnkEmpty(),
     ...
   )
+  ```
 
 Converter declaration
 ---------------------
@@ -1349,41 +1552,45 @@ A converter is similar to a proc.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   converter toBool(x: float): bool
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkConverterDef(
-    nnkIdent(!"toBool"),
+    nnkIdent("toBool"),
     # ...
   )
+  ```
 
 Template declaration
 --------------------
 
 Templates (as well as macros, as we'll see) have a slightly expanded AST when
 compared to procs and iterators. The reason for this is [term-rewriting
-macros](http://nim-lang.org/docs/manual.html#term-rewriting-macros). Notice
+macros](manual.html#term-rewriting-macros). Notice
 the ``nnkEmpty()`` as the second argument to ``nnkProcDef`` and
 ``nnkIteratorDef`` above? That's where the term-rewriting macros go.
 
 Concrete syntax:
 
-.. code-block:: nim
+  ```nim
   template optOpt{expr1}(a: int): int
+  ```
 
 AST:
 
-.. code-block:: nim
+  ```nim
   nnkTemplateDef(
-    nnkIdent(!"optOpt"),
+    nnkIdent("optOpt"),
     nnkStmtList( # instead of nnkEmpty()
       expr1
     ),
     # follows like a proc or iterator
   )
+  ```
 
 If the template does not have types for its parameters, the type identifiers
 inside ``nnkFormalParams`` just becomes ``nnkEmpty``.
@@ -1394,6 +1601,18 @@ Macro declaration
 Macros behave like templates, but ``nnkTemplateDef`` is replaced with
 ``nnkMacroDef``.
 
+Hidden Standard Conversion
+--------------------------
+
+  ```nim
+  var f: float = 1
+  ```
+
+The type of "f" is ``float`` but the type of "1" is actually ``int``. Inserting 
+``int`` into a ``float`` is a type error. Nim inserts the ``nnkHiddenStdConv``  
+node around the ``nnkIntLit`` node so that the new node has the correct type of 
+``float``. This works for any auto converted nodes and makes the conversion 
+explicit.
 
 Special node kinds
 ==================