Skip to content

Commit

Permalink
improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Apr 2, 2021
1 parent 1fafc0a commit c8e4a17
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
5 changes: 2 additions & 3 deletions lib/core/macros.nim
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,6 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf
## var ast = getAst(BarTemplate())

proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} =
## .. warning:: `quote` comes with many caveats, use `genasts <genasts.html>`_
## instead.
##
## Quasi-quoting operator.
## Accepts an expression or a block and returns the AST that represents it.
## Within the quoted AST, you are able to interpolate NimNode expressions
Expand All @@ -563,6 +560,8 @@ proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} =
##
## A custom operator interpolation needs accent quoted (``) whenever it resolves
## to a symbol.
##
## See also `genasts <genasts.html>`_ which avoids some issues with `quote`.
runnableExamples:
macro check(ex: untyped) =
# this is a simplified version of the check macro from the
Expand Down
32 changes: 25 additions & 7 deletions lib/std/genasts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,32 @@ macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untype
## AST that represents it. Local `{.inject.}` symbols (e.g. procs) are captured
## unless `kDirtyTemplate in options`.
runnableExamples:
macro fun(a: bool, b: static bool): untyped =
let c = false # doesn't override parameter `c`
import std/[macros, strutils]

# This examples shows how one could write a simplified version of `unittest.check`.
macro check2(cond: bool): untyped =
assert cond.kind == nnkInfix, "$# not implemented" % $cond.kind
result = genAst(cond, s = repr(cond), lhs = cond[1], rhs = cond[2]):
# each local symbol we access must be explicitly captured.
if not cond:
doAssert false, "'$#'' failed: lhs: '$#', rhs: '$#'" % [s, $lhs, $rhs]
let a = 3
check2 a*2 == a+3
if false: check2 a*2 < a+1 # would error with: 'a * 2 < a + 1'' failed: lhs: '6', rhs: '4'

runnableExamples:
# This example goes in more details about the capture semantics.
macro fun(a: string, b: static bool): untyped =
let c = 'z'
var d = 11 # var => gensym'd
proc localFun(): auto = 12 # proc => inject'd
proc localFun(): auto = 12
genAst(a, b, c = true):
# echo d # not captured => gives `var not init`
(a, b, c, localFun())
assert fun(true, false) == (true, false, true, 12)
# `c = true` masks local macro variable `c = 'z'`.
const b2 = b # macro static param `b` is forwarded here as a static param.
# `echo d` would give: `var not init` because `d` is not captured.
# `localFun` doesn't need to be captured, it's a routine.
(a & a, b, c, localFun())
assert fun("ab", false) == ("abab", false, true, 12)

let params = newTree(nnkFormalParams, newEmptyNode())
let pragmas =
Expand Down Expand Up @@ -67,5 +85,5 @@ macro genAstOpt*(options: static set[GenAstOpt], args: varargs[untyped]): untype
result.add newCall(bindSym"getAst", call)

template genAst*(args: varargs[untyped]): untyped =
## convenience wrapper around `genAstOpt`
## Convenience wrapper around `genAstOpt`.
genAstOpt({}, args)

0 comments on commit c8e4a17

Please sign in to comment.