1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594 |
- The AST in Nim
- ==============
- This section describes how the AST is modelled with Nim's type system.
- 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:
- ```nim
- type
- NimNodeKind = enum ## kind of a node; only explanatory
- nnkNone, ## invalid node kind
- nnkEmpty, ## empty node
- nnkIdent, ## node contains an identifier
- nnkIntLit, ## node contains an int literal (example: 10)
- nnkStrLit, ## node contains a string literal (example: "abc")
- nnkNilLit, ## node contains a nil literal (example: nil)
- nnkCaseStmt, ## node represents a case statement
- ... ## many more
- NimNode = ref NimNodeObj
- NimNodeObj = object
- case kind: NimNodeKind ## the node's kind
- of nnkNone, nnkEmpty, nnkNilLit:
- discard ## node contains no additional fields
- of nnkCharLit..nnkUInt64Lit:
- intVal: BiggestInt ## the int literal
- of nnkFloatLit..nnkFloat64Lit:
- floatVal: BiggestFloat ## the float literal
- of nnkStrLit..nnkTripleStrLit, nnkCommentStmt, nnkIdent, nnkSym:
- strVal: string ## the string literal
- 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.
- To specify the AST for the different Nim constructs, the notation
- ``nodekind(son1, son2, ...)`` or ``nodekind(value)`` or
- ``nodekind(field=value)`` is used.
- Some child may be missing. A missing child is a node of kind ``nnkEmpty``;
- a child can never be nil.
- Leaf nodes/Atoms
- ================
- 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)``
- ``42'i32`` ``nnkInt32Lit(intVal = 42)``
- ``42'i64`` ``nnkInt64Lit(intVal = 42)``
- ``42'u8`` ``nnkUInt8Lit(intVal = 42)``
- ``42'u16`` ``nnkUInt16Lit(intVal = 42)``
- ``42'u32`` ``nnkUInt32Lit(intVal = 42)``
- ``42'u64`` ``nnkUInt64Lit(intVal = 42)``
- ``42.0`` ``nnkFloat64Lit(floatVal = 42.0)``
- ``42.0'f32`` ``nnkFloat32Lit(floatVal = 42.0)``
- ``42.0'f64`` ``nnkFloat64Lit(floatVal = 42.0)``
- ``"abc"`` ``nnkStrLit(strVal = "abc")``
- ``r"abc"`` ``nnkRStrLit(strVal = "abc")``
- ``"""abc"""`` ``nnkTripleStrLit(strVal = "abc")``
- ``' '`` ``nnkCharLit(intVal = 32)``
- ``nil`` ``nnkNilLit()``
- ``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.
- Calls/expressions
- =================
- Command call
- ------------
- Concrete syntax:
- ```nim
- echo "abc", "xyz"
- ```
- AST:
- ```nim
- nnkCommand(
- nnkIdent("echo"),
- nnkStrLit("abc"),
- nnkStrLit("xyz")
- )
- ```
- Call with ``()``
- ----------------
- Concrete syntax:
- ```nim
- echo("abc", "xyz")
- ```
- AST:
- ```nim
- nnkCall(
- nnkIdent("echo"),
- nnkStrLit("abc"),
- nnkStrLit("xyz")
- )
- ```
- Infix operator call
- -------------------
- Concrete syntax:
- ```nim
- "abc" & "xyz"
- ```
- AST:
- ```nim
- nnkInfix(
- nnkIdent("&"),
- nnkStrLit("abc"),
- nnkStrLit("xyz")
- )
- ```
- Note that with multiple infix operators, the command is parsed by operator
- precedence.
- Concrete syntax:
- ```nim
- 5 + 3 * 4
- ```
- AST:
- ```nim
- nnkInfix(
- nnkIdent("+"),
- nnkIntLit(5),
- nnkInfix(
- 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](#callsslashexpressions-call-with) with
- ``nnkAccQuoted``, as follows:
- Concrete syntax:
- ```nim
- `+`(3, 4)
- ```
- AST:
- ```nim
- nnkCall(
- nnkAccQuoted(
- nnkIdent("+")
- ),
- nnkIntLit(3),
- nnkIntLit(4)
- )
- ```
- Prefix operator call
- --------------------
- Concrete syntax:
- ```nim
- ? "xyz"
- ```
- AST:
- ```nim
- nnkPrefix(
- nnkIdent("?"),
- nnkStrLit("abc")
- )
- ```
- Postfix operator call
- ---------------------
- **Note:** There are no postfix operators in Nim. However, the
- ``nnkPostfix`` node is used for the *asterisk export marker* ``*``:
- Concrete syntax:
- ```nim
- identifier*
- ```
- AST:
- ```nim
- nnkPostfix(
- nnkIdent("*"),
- nnkIdent("identifier")
- )
- ```
- Call with named arguments
- -------------------------
- Concrete syntax:
- ```nim
- writeLine(file=stdout, "hallo")
- ```
- AST:
- ```nim
- nnkCall(
- nnkIdent("writeLine"),
- nnkExprEqExpr(
- nnkIdent("file"),
- nnkIdent("stdout")
- ),
- nnkStrLit("hallo")
- )
- ```
- Call with raw string literal
- ----------------------------
- This is used, for example, in the ``bindSym`` examples
- [here](manual.html#macros-bindsym) and with
- ``re"some regexp"`` in the regular expression module.
- Concrete syntax:
- ```nim
- echo"abc"
- ```
- AST:
- ```nim
- nnkCallStrLit(
- nnkIdent("echo"),
- nnkRStrLit("hello")
- )
- ```
- Dereference operator ``[]``
- ---------------------------
- Concrete syntax:
- ```nim
- x[]
- ```
- AST:
- ```nim
- nnkDerefExpr(nnkIdent("x"))
- ```
- Addr operator
- -------------
- Concrete syntax:
- ```nim
- addr(x)
- ```
- AST:
- ```nim
- nnkAddr(nnkIdent("x"))
- ```
- Cast operator
- -------------
- Concrete syntax:
- ```nim
- cast[T](x)
- ```
- AST:
- ```nim
- nnkCast(nnkIdent("T"), nnkIdent("x"))
- ```
- Object access operator ``.``
- ----------------------------
- Concrete syntax:
- ```nim
- x.y
- ```
- AST:
- ```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``.
- Array access operator ``[]``
- ----------------------------
- Concrete syntax:
- ```nim
- x[y]
- ```
- AST:
- ```nim
- nnkBracketExpr(nnkIdent("x"), nnkIdent("y"))
- ```
- Parentheses
- -----------
- Parentheses for affecting operator precedence use the ``nnkPar`` node.
- Concrete syntax:
- ```nim
- (a + b) * c
- ```
- AST:
- ```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
- ------------
- Curly braces are used as the set constructor.
- Concrete syntax:
- ```nim
- {1, 2, 3}
- ```
- AST:
- ```nim
- nnkCurly(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
- ```
- When used as a table constructor, the syntax is different.
- Concrete syntax:
- ```nim
- {a: 3, b: 5}
- ```
- AST:
- ```nim
- nnkTableConstr(
- nnkExprColonExpr(nnkIdent("a"), nnkIntLit(3)),
- nnkExprColonExpr(nnkIdent("b"), nnkIntLit(5))
- )
- ```
- Brackets
- --------
- Brackets are used as the array constructor.
- Concrete syntax:
- ```nim
- [1, 2, 3]
- ```
- AST:
- ```nim
- nnkBracket(nnkIntLit(1), nnkIntLit(2), nnkIntLit(3))
- ```
- Ranges
- ------
- Ranges occur in set constructors, case statement branches, or array slices.
- Internally, the node kind ``nnkRange`` is used, but when constructing the
- AST, construction with ``..`` as an infix operator should be used instead.
- Concrete syntax:
- ```nim
- 1..3
- ```
- AST:
- ```nim
- nnkInfix(
- nnkIdent(".."),
- nnkIntLit(1),
- nnkIntLit(3)
- )
- ```
- Example code:
- ```nim
- macro genRepeatEcho() =
- result = newNimNode(nnkStmtList)
- var forStmt = newNimNode(nnkForStmt) # generate a for statement
- forStmt.add(ident("i")) # use the variable `i` for iteration
- var rangeDef = newNimNode(nnkInfix).add(
- ident("..")).add(
- newIntLitNode(3),newIntLitNode(5)) # iterate over the range 3..5
- forStmt.add(rangeDef)
- forStmt.add(newCall(ident("echo"), newIntLitNode(3))) # meat of the loop
- result.add(forStmt)
- genRepeatEcho() # gives:
- # 3
- # 3
- # 3
- ```
- If expression
- -------------
- The representation of the ``if`` expression is subtle, but easy to traverse.
- Concrete syntax:
- ```nim
- if cond1: expr1 elif cond2: expr2 else: expr3
- ```
- AST:
- ```nim
- nnkIfExpr(
- nnkElifExpr(cond1, expr1),
- nnkElifExpr(cond2, expr2),
- nnkElseExpr(expr3)
- )
- ```
- Documentation Comments
- ----------------------
- Double-hash (``##``) comments in the code actually have their own format,
- using ``strVal`` to get and set the comment text. Single-hash (``#``)
- comments are ignored.
- Concrete syntax:
- ```nim
- ## This is a comment
- ## This is part of the first comment
- stmt1
- ## Yet another
- ```
- AST:
- ```nim
- nnkCommentStmt() # only appears once for the first two lines!
- stmt1
- nnkCommentStmt() # another nnkCommentStmt because there is another comment
- # (separate from the first)
- ```
- Pragmas
- -------
- One of Nim's cool features is pragmas, which allow fine-tuning of various
- aspects of the language. They come in all types, such as adorning procs and
- objects, but the standalone ``emit`` pragma shows the basics with the AST.
- Concrete syntax:
- ```nim
- {.emit: "#include <stdio.h>".}
- ```
- AST:
- ```nim
- nnkPragma(
- nnkExprColonExpr(
- 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:
- ```nim
- {.pragma: cdeclRename, cdecl.}
- ```
- AST:
- ```nim
- nnkPragma(
- nnkExprColonExpr(
- nnkIdent("pragma"), # this is always first when declaring a new pragma
- nnkIdent("cdeclRename") # the name of the pragma
- ),
- nnkIdent("cdecl")
- )
- ```
- Statements
- ==========
- If statement
- ------------
- The representation of the if statement is subtle, but easy to traverse. If
- there is no ``else`` branch, no ``nnkElse`` child exists.
- Concrete syntax:
- ```nim
- if cond1:
- stmt1
- elif cond2:
- stmt2
- elif cond3:
- stmt3
- else:
- stmt4
- ```
- AST:
- ```nim
- nnkIfStmt(
- nnkElifBranch(cond1, stmt1),
- nnkElifBranch(cond2, stmt2),
- nnkElifBranch(cond3, stmt3),
- nnkElse(stmt4)
- )
- ```
- When statement
- --------------
- Like the ``if`` statement, but the root has the kind ``nnkWhenStmt``.
- Assignment
- ----------
- Concrete syntax:
- ```nim
- x = 42
- ```
- AST:
- ```nim
- nnkAsgn(nnkIdent("x"), nnkIntLit(42))
- ```
- This is not the syntax for assignment when combined with ``var``, ``let``,
- or ``const``.
- Statement list
- --------------
- Concrete syntax:
- ```nim
- stmt1
- stmt2
- stmt3
- ```
- AST:
- ```nim
- nnkStmtList(stmt1, stmt2, stmt3)
- ```
- Case statement
- --------------
- Concrete syntax:
- ```nim
- case expr1
- of expr2, expr3..expr4:
- stmt1
- of expr5:
- stmt2
- elif cond1:
- stmt3
- else:
- stmt4
- ```
- AST:
- ```nim
- nnkCaseStmt(
- expr1,
- nnkOfBranch(expr2, nnkRange(expr3, expr4), stmt1),
- nnkOfBranch(expr5, stmt2),
- nnkElifBranch(cond1, stmt3),
- nnkElse(stmt4)
- )
- ```
- The ``nnkElifBranch`` and ``nnkElse`` parts may be missing.
- While statement
- ---------------
- Concrete syntax:
- ```nim
- while expr1:
- stmt1
- ```
- AST:
- ```nim
- nnkWhileStmt(expr1, stmt1)
- ```
- For statement
- -------------
- Concrete syntax:
- ```nim
- for ident1, ident2 in expr1:
- stmt1
- ```
- AST:
- ```nim
- nnkForStmt(ident1, ident2, expr1, stmt1)
- ```
- Try statement
- -------------
- Concrete syntax:
- ```nim
- try:
- stmt1
- except e1, e2:
- stmt2
- except e3:
- stmt3
- except:
- stmt4
- finally:
- stmt5
- ```
- AST:
- ```nim
- nnkTryStmt(
- stmt1,
- nnkExceptBranch(e1, e2, stmt2),
- nnkExceptBranch(e3, stmt3),
- nnkExceptBranch(stmt4),
- nnkFinally(stmt5)
- )
- ```
- Return statement
- ----------------
- Concrete syntax:
- ```nim
- return expr1
- ```
- AST:
- ```nim
- nnkReturnStmt(expr1)
- ```
- Yield statement
- ---------------
- Like ``return``, but with ``nnkYieldStmt`` kind.
- ```nim
- nnkYieldStmt(expr1)
- ```
- Discard statement
- -----------------
- Like ``return``, but with ``nnkDiscardStmt`` kind.
- ```nim
- nnkDiscardStmt(expr1)
- ```
- Continue statement
- ------------------
- Concrete syntax:
- ```nim
- continue
- ```
- AST:
- ```nim
- nnkContinueStmt()
- ```
- Break statement
- ---------------
- Concrete syntax:
- ```nim
- break otherLocation
- ```
- AST:
- ```nim
- nnkBreakStmt(nnkIdent("otherLocation"))
- ```
- If ``break`` is used without a jump-to location, ``nnkEmpty`` replaces ``nnkIdent``.
- Block statement
- ---------------
- Concrete syntax:
- ```nim
- block name:
- ```
- AST:
- ```nim
- nnkBlockStmt(nnkIdent("name"), nnkStmtList(...))
- ```
- A ``block`` doesn't need an name, in which case ``nnkEmpty`` is used.
- Asm statement
- -------------
- Concrete syntax:
- ```nim
- asm """
- some asm
- """
- ```
- AST:
- ```nim
- nnkAsmStmt(
- nnkEmpty(), # for pragmas
- nnkTripleStrLit("some asm"),
- )
- ```
- Import section
- --------------
- Nim's ``import`` statement actually takes different variations depending
- on what keywords are present. Let's start with the simplest form.
- Concrete syntax:
- ```nim
- import math
- ```
- AST:
- ```nim
- nnkImportStmt(nnkIdent("math"))
- ```
- With ``except``, we get ``nnkImportExceptStmt``.
- Concrete syntax:
- ```nim
- import math except pow
- ```
- AST:
- ```nim
- 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.
- Concrete syntax:
- ```nim
- import strutils as su
- ```
- AST:
- ```nim
- nnkImportStmt(
- nnkInfix(
- nnkIdent("as"),
- nnkIdent("strutils"),
- nnkIdent("su")
- )
- )
- ```
- From statement
- --------------
- If we use ``from ... import``, the result is different, too.
- Concrete syntax:
- ```nim
- from math import pow
- ```
- AST:
- ```nim
- 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``.
- Export statement
- ----------------
- When you are making an imported module accessible by modules that import yours,
- the ``export`` syntax is pretty straightforward.
- Concrete syntax:
- ```nim
- export unsigned
- ```
- AST:
- ```nim
- nnkExportStmt(nnkIdent("unsigned"))
- ```
- Similar to the ``import`` statement, the AST is different for
- ``export ... except``.
- Concrete syntax:
- ```nim
- export math except pow # we're going to implement our own exponentiation
- ```
- AST:
- ```nim
- nnkExportExceptStmt(nnkIdent("math"),nnkIdent("pow"))
- ```
- Include statement
- -----------------
- Like a plain ``import`` statement but with ``nnkIncludeStmt``.
- Concrete syntax:
- ```nim
- include blocks
- ```
- AST:
- ```nim
- nnkIncludeStmt(nnkIdent("blocks"))
- ```
- Var section
- -----------
- Concrete syntax:
- ```nim
- var a = 3
- ```
- AST:
- ```nim
- nnkVarSection(
- nnkIdentDefs(
- 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](macros.html#statements-procedure-declaration)
- for details.
- Let section
- -----------
- This is equivalent to ``var``, but with ``nnkLetSection`` rather than
- ``nnkVarSection``.
- Concrete syntax:
- ```nim
- let a = 3
- ```
- AST:
- ```nim
- nnkLetSection(
- nnkIdentDefs(
- nnkIdent("a"),
- nnkEmpty(), # or nnkIdent(...) for the type
- nnkIntLit(3),
- )
- )
- ```
- Const section
- -------------
- Concrete syntax:
- ```nim
- const a = 3
- ```
- AST:
- ```nim
- nnkConstSection(
- nnkConstDef( # not nnkConstDefs!
- nnkIdent("a"),
- nnkEmpty(), # or nnkIdent(...) if the variable declares the type
- nnkIntLit(3), # required in a const declaration!
- )
- )
- ```
- Type section
- ------------
- Starting with the simplest case, a ``type`` section appears much like ``var``
- and ``const``.
- Concrete syntax:
- ```nim
- type A = int
- ```
- AST:
- ```nim
- nnkTypeSection(
- nnkTypeDef(
- nnkIdent("A"),
- nnkEmpty(),
- nnkIdent("int")
- )
- )
- ```
- Declaring ``distinct`` types is similar, with the last ``nnkIdent`` wrapped
- in ``nnkDistinctTy``.
- Concrete syntax:
- ```nim
- type MyInt = distinct int
- ```
- AST:
- ```nim
- # ...
- nnkTypeDef(
- nnkIdent("MyInt"),
- nnkEmpty(),
- nnkDistinctTy(
- nnkIdent("int")
- )
- )
- ```
- If a type section uses generic parameters, they are treated here:
- Concrete syntax:
- ```nim
- type A[T] = expr1
- ```
- AST:
- ```nim
- nnkTypeSection(
- nnkTypeDef(
- nnkIdent("A"),
- nnkGenericParams(
- nnkIdentDefs(
- nnkIdent("T"),
- nnkEmpty(), # if the type is declared with options, like
- # ``[T: SomeInteger]``, they are given here
- nnkEmpty(),
- )
- )
- expr1,
- )
- )
- ```
- Note that not all ``nnkTypeDef`` utilize ``nnkIdent`` as their
- parameter. One of the most common uses of type declarations
- is to work with objects.
- Concrete syntax:
- ```nim
- type IO = object of RootObj
- ```
- AST:
- ```nim
- # ...
- nnkTypeDef(
- nnkIdent("IO"),
- nnkEmpty(),
- nnkObjectTy(
- nnkEmpty(), # no pragmas here
- nnkOfInherit(
- 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:
- ```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:
- ```nim
- # ...
- nnkPragmaExpr(
- nnkIdent("Obj"),
- nnkPragma(nnkIdent("inheritable"))
- ),
- nnkGenericParams(
- nnkIdentDefs(
- nnkIdent("T"),
- nnkEmpty(),
- nnkEmpty())
- ),
- nnkObjectTy(
- nnkEmpty(),
- nnkEmpty(),
- nnkRecList( # list of object parameters
- nnkIdentDefs(
- nnkIdent("name"),
- nnkIdent("string"),
- nnkEmpty()
- ),
- nnkRecCase( # case statement within object (not nnkCaseStmt)
- nnkIdentDefs(
- nnkIdent("isFat"),
- nnkIdent("bool"),
- nnkEmpty()
- ),
- nnkOfBranch(
- nnkIdent("true"),
- nnkRecList( # again, a list of object parameters
- nnkIdentDefs(
- nnkIdent("m"),
- nnkBracketExpr(
- nnkIdent("array"),
- nnkIntLit(100000),
- nnkIdent("T")
- ),
- nnkEmpty()
- )
- ),
- nnkOfBranch(
- nnkIdent("false"),
- nnkRecList(
- nnkIdentDefs(
- nnkIdent("m"),
- nnkBracketExpr(
- nnkIdent("array"),
- nnkIntLit(10),
- nnkIdent("T")
- ),
- nnkEmpty()
- )
- )
- )
- )
- )
- )
- ```
- Using an ``enum`` is similar to using an ``object``.
- Concrete syntax:
- ```nim
- type X = enum
- First
- ```
- AST:
- ```nim
- # ...
- nnkEnumTy(
- nnkEmpty(),
- nnkIdent("First") # you need at least one nnkIdent or the compiler complains
- )
- ```
- The usage of ``concept`` (experimental) is similar to objects.
- Concrete syntax:
- ```nim
- type Con = concept x,y,z
- (x & y & z) is string
- ```
- AST:
- ```nim
- # ...
- nnkTypeClassTy( # note this isn't nnkConceptTy!
- nnkArgList(
- # ... idents for x, y, z
- )
- # ...
- )
- ```
- Static types, like ``static[int]``, use ``nnkIdent`` wrapped in
- ``nnkStaticTy``.
- Concrete syntax:
- ```nim
- type A[T: static[int]] = object
- ```
- AST:
- ```nim
- # ... within nnkGenericParams
- nnkIdentDefs(
- nnkIdent("T"),
- nnkStaticTy(
- 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``
- ``ptr`` ``nnkPtrTy``
- ``ref`` ``nnkRefTy``
- ``distinct`` ``nnkDistinctTy``
- ``enum`` ``nnkEnumTy``
- ``concept`` ``nnkTypeClassTy``\*
- ``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``.
- Generic parameters are treated in the type, not the ``proc`` itself.
- Concrete syntax:
- ```nim
- type MyProc[T] = proc(x: T)
- ```
- AST:
- ```nim
- # ...
- nnkTypeDef(
- nnkIdent("MyProc"),
- nnkGenericParams( # here, not with the proc
- # ...
- )
- nnkProcTy( # behaves like a procedure declaration from here on
- nnkFormalParams(
- # ...
- )
- )
- )
- ```
- The same syntax applies to ``iterator`` (with ``nnkIteratorTy``), but
- *does not* apply to ``converter`` or ``template``.
- Mixin statement
- ---------------
- Concrete syntax:
- ```nim
- mixin x
- ```
- AST:
- ```nim
- nnkMixinStmt(nnkIdent("x"))
- ```
- Bind statement
- --------------
- Concrete syntax:
- ```nim
- bind x
- ```
- AST:
- ```nim
- nnkBindStmt(nnkIdent("x"))
- ```
- Procedure declaration
- ---------------------
- Let's take a look at a procedure with a lot of interesting aspects to get
- a feel for how procedure calls are broken down.
- Concrete syntax:
- ```nim
- proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
- ```
- AST:
- ```nim
- nnkProcDef(
- 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"),
- nnkEmpty()
- )
- ),
- nnkFormalParams(
- 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)
- nnkIntLit(3) # a default value
- ),
- nnkIdentDefs(
- nnkIdent("y"),
- nnkIdent("float32"),
- nnkEmpty()
- )
- ),
- 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)``
- are equivalent in the code, the AST is a little different for the latter.
- Concrete syntax:
- ```nim
- proc(a, b: int)
- ```
- AST:
- ```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
- 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:
- ```nim
- proc hello(): var int
- ```
- AST:
- ```nim
- # ...
- nnkFormalParams(
- nnkVarTy(
- nnkIdent("int")
- )
- )
- ```
- Iterator declaration
- --------------------
- The syntax for iterators is similar to procs, but with ``nnkIteratorDef``
- replacing ``nnkProcDef``.
- Concrete syntax:
- ```nim
- iterator nonsense[T](x: seq[T]): float {.closure.} = ...
- ```
- AST:
- ```nim
- nnkIteratorDef(
- nnkIdent("nonsense"),
- nnkEmpty(),
- ...
- )
- ```
- Converter declaration
- ---------------------
- A converter is similar to a proc.
- Concrete syntax:
- ```nim
- converter toBool(x: float): bool
- ```
- AST:
- ```nim
- nnkConverterDef(
- 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](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:
- ```nim
- template optOpt{expr1}(a: int): int
- ```
- AST:
- ```nim
- nnkTemplateDef(
- 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``.
- 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
- ==================
- There are several node kinds that are used for semantic checking or code
- generation. These are accessible from this module, but should not be used.
- Other node kinds are especially designed to make AST manipulations easier.
- These are explained here.
- To be written.
|