An AST can be created in different ways and these ways can all be combined
freely. But one of the easiest ways is to use quote do. For example, an
operator ==~ that checks if two floating point values almost equal can be
written as a template:
template ==~(x, y: float): bool = abs(x - y) < 1e-9
Or it can be written as a macro that uses quote do:
import std / macros
macro ==~(x, y: float): bool =
result = quote do:
abs(`x` - `y`) < 1e-9
quote do turns a pattern of code into a NimNode. Inside the pattern backticks
can be used to access symbols from the macro’s scope. The ==~ macro can
also be written as:
import std / macros
macro ==~(x, y: float): bool =
result = newCall(bindSym"<",
newCall(bindSym"abs", newCall(bindSym"-", x, y)),
newLit(1e-9))
In my opinion this more imperative style of AST creation is easier to understand for beginners and so it is what is used in the following more complex examples.