tut3.rst 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. =======================
  2. Nim Tutorial (Part III)
  3. =======================
  4. :Author: Arne Döring
  5. :Version: |nimversion|
  6. .. default-role:: code
  7. .. include:: rstcommon.rst
  8. .. contents::
  9. Introduction
  10. ============
  11. "With Great Power Comes Great Responsibility." -- Spider Man's Uncle
  12. This document is a tutorial about Nim's macro system.
  13. A macro is a function that is executed at compile-time and transforms
  14. a Nim syntax tree into a different tree.
  15. Examples of things that can be implemented in macros:
  16. * An assert macro that prints both sides of a comparison operator, if
  17. the assertion fails. `myAssert(a == b)` is converted to
  18. `if a != b: quit($a " != " $b)`
  19. * A debug macro that prints the value and the name of the symbol.
  20. `myDebugEcho(a)` is converted to `echo "a: ", a`
  21. * Symbolic differentiation of an expression.
  22. `diff(a*pow(x,3) + b*pow(x,2) + c*x + d, x)` is converted to
  23. `3*a*pow(x,2) + 2*b*x + c`
  24. Macro Arguments
  25. ---------------
  26. The types of macro arguments have two faces. One face is used for
  27. the overload resolution and the other face is used within the macro
  28. body. For example, if `macro foo(arg: int)` is called in an
  29. expression `foo(x)`, `x` has to be of a type compatible to int, but
  30. *within* the macro's body `arg` has the type `NimNode`, not `int`!
  31. Why it is done this way will become obvious later, when we have seen
  32. concrete examples.
  33. There are two ways to pass arguments to a macro, an argument can be
  34. either `typed` or `untyped`.
  35. Untyped Arguments
  36. -----------------
  37. Untyped macro arguments are passed to the macro before they are
  38. semantically checked. This means the syntax tree that is passed down
  39. to the macro does not need to make sense for Nim yet, the only
  40. limitation is that it needs to be parsable. Usually, the macro does
  41. not check the argument either but uses it in the transformation's
  42. result somehow. The result of a macro expansion is always checked
  43. by the compiler, so apart from weird error messages, nothing bad
  44. can happen.
  45. The downside for an `untyped` argument is that these do not play
  46. well with Nim's overloading resolution.
  47. The upside for untyped arguments is that the syntax tree is
  48. quite predictable and less complex compared to its `typed`
  49. counterpart.
  50. Typed Arguments
  51. ---------------
  52. For typed arguments, the semantic checker runs on the argument and
  53. does transformations on it, before it is passed to the macro. Here
  54. identifier nodes are resolved as symbols, implicit type
  55. conversions are visible in the tree as calls, templates are
  56. expanded, and probably most importantly, nodes have type information.
  57. Typed arguments can have the type `typed` in the arguments list.
  58. But all other types, such as `int`, `float` or `MyObjectType`
  59. are typed arguments as well, and they are passed to the macro as a
  60. syntax tree.
  61. Static Arguments
  62. ----------------
  63. Static arguments are a way to pass values as values and not as syntax
  64. tree nodes to a macro. For example for `macro foo(arg: static[int])`
  65. in the expression `foo(x)`, `x` needs to be an integer constant,
  66. but in the macro body `arg` is just like a normal parameter of type
  67. `int`.
  68. .. code-block:: nim
  69. import std/macros
  70. macro myMacro(arg: static[int]): untyped =
  71. echo arg # just an int (7), not `NimNode`
  72. myMacro(1 + 2 * 3)
  73. Code Blocks as Arguments
  74. ------------------------
  75. It is possible to pass the last argument of a call expression in a
  76. separate code block with indentation. For example, the following code
  77. example is a valid (but not a recommended) way to call `echo`:
  78. .. code-block:: nim
  79. echo "Hello ":
  80. let a = "Wor"
  81. let b = "ld!"
  82. a & b
  83. For macros this way of calling is very useful; syntax trees of arbitrary
  84. complexity can be passed to macros with this notation.
  85. The Syntax Tree
  86. ---------------
  87. In order to build a Nim syntax tree one needs to know how Nim source
  88. code is represented as a syntax tree, and how such a tree needs to
  89. look like so that the Nim compiler will understand it. The nodes of the
  90. Nim syntax tree are documented in the `macros <macros.html>`_ module.
  91. But a more interactive way to explore the Nim
  92. syntax tree is with `macros.treeRepr`, it converts a syntax tree
  93. into a multi-line string for printing on the console. It can be used
  94. to explore how the argument expressions are represented in tree form
  95. and for debug printing of generated syntax tree. `dumpTree` is a
  96. predefined macro that just prints its argument in a tree representation,
  97. but does nothing else. Here is an example of such a tree representation:
  98. .. code-block:: nim
  99. dumpTree:
  100. var mt: MyType = MyType(a:123.456, b:"abcdef")
  101. # output:
  102. # StmtList
  103. # VarSection
  104. # IdentDefs
  105. # Ident "mt"
  106. # Ident "MyType"
  107. # ObjConstr
  108. # Ident "MyType"
  109. # ExprColonExpr
  110. # Ident "a"
  111. # FloatLit 123.456
  112. # ExprColonExpr
  113. # Ident "b"
  114. # StrLit "abcdef"
  115. Custom Semantic Checking
  116. ------------------------
  117. The first thing that a macro should do with its arguments is to check
  118. if the argument is in the correct form. Not every type of wrong input
  119. needs to be caught here, but anything that could cause a crash during
  120. macro evaluation should be caught and create a nice error message.
  121. `macros.expectKind` and `macros.expectLen` are a good start. If
  122. the checks need to be more complex, arbitrary error messages can
  123. be created with the `macros.error` proc.
  124. .. code-block:: nim
  125. macro myAssert(arg: untyped): untyped =
  126. arg.expectKind nnkInfix
  127. Generating Code
  128. ---------------
  129. There are two ways to generate the code. Either by creating the syntax
  130. tree with expressions that contain a lot of calls to `newTree` and
  131. `newLit`, or with `quote do:` expressions. The first option offers
  132. the best low-level control for the syntax tree generation, but the
  133. second option is much less verbose. If you choose to create the syntax
  134. tree with calls to `newTree` and `newLit` the macro
  135. `macros.dumpAstGen` can help you with the verbosity.
  136. `quote do:` allows you to write the code that you want to generate literally.
  137. Backticks are used to insert code from `NimNode` symbols into the
  138. generated expression.
  139. .. code-block:: nim
  140. :test: "nim c $1"
  141. import std/macros
  142. macro a(i) = quote do:
  143. let `i` = 0
  144. a b
  145. doAssert b == 0
  146. A custom prefix operator can be defined whenever backticks are needed.
  147. .. code-block:: nim
  148. :test: "nim c $1"
  149. import std/macros
  150. macro a(i) = quote("@") do:
  151. assert @i == 0
  152. let b = 0
  153. a b
  154. The injected symbol needs accent quoted when it resolves to a symbol.
  155. .. code-block:: nim
  156. :test: "nim c $1"
  157. import std/macros
  158. macro a(i) = quote("@") do:
  159. let `@i` = 0
  160. a b
  161. doAssert b == 0
  162. Make sure to inject only symbols of type `NimNode` into the generated syntax
  163. tree. You can use `newLit` to convert arbitrary values into
  164. expressions trees of type `NimNode` so that it is safe to inject
  165. them into the tree.
  166. .. code-block:: nim
  167. :test: "nim c $1"
  168. import std/macros
  169. type
  170. MyType = object
  171. a: float
  172. b: string
  173. macro myMacro(arg: untyped): untyped =
  174. var mt: MyType = MyType(a:123.456, b:"abcdef")
  175. # ...
  176. let mtLit = newLit(mt)
  177. result = quote do:
  178. echo `arg`
  179. echo `mtLit`
  180. myMacro("Hallo")
  181. The call to `myMacro` will generate the following code:
  182. .. code-block:: nim
  183. echo "Hallo"
  184. echo MyType(a: 123.456'f64, b: "abcdef")
  185. Building Your First Macro
  186. -------------------------
  187. To give a starting point to writing macros we will show now how to
  188. implement the `myAssert` macro mentioned earlier. The first thing to
  189. do is to build a simple example of the macro usage, and then just
  190. print the argument. This way it is possible to get an idea of what a
  191. correct argument should look like.
  192. .. code-block:: nim
  193. :test: "nim c $1"
  194. import std/macros
  195. macro myAssert(arg: untyped): untyped =
  196. echo arg.treeRepr
  197. let a = 1
  198. let b = 2
  199. myAssert(a != b)
  200. .. code-block::
  201. Infix
  202. Ident "!="
  203. Ident "a"
  204. Ident "b"
  205. From the output, it is possible to see that the argument is an infix
  206. operator (node kind is "Infix"), as well as that the two operands are
  207. at index 1 and 2. With this information, the actual macro can be
  208. written.
  209. .. code-block:: nim
  210. :test: "nim c $1"
  211. import std/macros
  212. macro myAssert(arg: untyped): untyped =
  213. # all node kind identifiers are prefixed with "nnk"
  214. arg.expectKind nnkInfix
  215. arg.expectLen 3
  216. # operator as string literal
  217. let op = newLit(" " & arg[0].repr & " ")
  218. let lhs = arg[1]
  219. let rhs = arg[2]
  220. result = quote do:
  221. if not `arg`:
  222. raise newException(AssertionDefect,$`lhs` & `op` & $`rhs`)
  223. let a = 1
  224. let b = 2
  225. myAssert(a != b)
  226. myAssert(a == b)
  227. This is the code that will be generated. To debug what the macro
  228. actually generated, the statement `echo result.repr` can be used, in
  229. the last line of the macro. It is also the statement that has been
  230. used to get this output.
  231. .. code-block:: nim
  232. if not (a != b):
  233. raise newException(AssertionDefect, $a & " != " & $b)
  234. With Power Comes Responsibility
  235. -------------------------------
  236. Macros are very powerful. A piece of good advice is to use them as little as
  237. possible, but as much as necessary. Macros can change the semantics of
  238. expressions, making the code incomprehensible for anybody who does not
  239. know exactly what the macro does with it. So whenever a macro is not
  240. necessary and the same logic can be implemented using templates or
  241. generics, it is probably better not to use a macro. And when a macro
  242. is used for something, the macro should better have a well-written
  243. documentation. For all the people who claim to write only perfectly
  244. self-explanatory code: when it comes to macros, the implementation is
  245. not enough for documentation.
  246. Limitations
  247. -----------
  248. Since macros are evaluated in the compiler in the NimVM, macros share
  249. all the limitations of the NimVM. They have to be implemented in pure Nim
  250. code. Macros can start external processes on the shell, but they
  251. cannot call C functions except those that are built in the
  252. compiler.
  253. More Examples
  254. =============
  255. This tutorial can only cover the basics of the macro system. There are
  256. macros out there that could be an inspiration for you of what is
  257. possible with it.
  258. Strformat
  259. ---------
  260. In the Nim standard library, the `strformat` library provides a
  261. macro that parses a string literal at compile time. Parsing a string
  262. in a macro like here is generally not recommended. The parsed AST
  263. cannot have type information, and parsing implemented on the VM is
  264. generally not very fast. Working on AST nodes is almost always the
  265. recommended way. But still `strformat` is a good example for a
  266. practical use case for a macro that is slightly more complex than the
  267. `assert` macro.
  268. `Strformat <https://github.com/nim-lang/Nim/blob/5845716df8c96157a047c2bd6bcdd795a7a2b9b1/lib/pure/strformat.nim#L280>`_
  269. Ast Pattern Matching
  270. --------------------
  271. Ast Pattern Matching is a macro library to aid in writing complex
  272. macros. This can be seen as a good example of how to repurpose the
  273. Nim syntax tree with new semantics.
  274. `Ast Pattern Matching <https://github.com/krux02/ast-pattern-matching>`_
  275. OpenGL Sandbox
  276. --------------
  277. This project has a working Nim to GLSL compiler written entirely in
  278. macros. It scans recursively through all used function symbols to
  279. compile them so that cross library functions can be executed on the GPU.
  280. `OpenGL Sandbox <https://github.com/krux02/opengl-sandbox>`_