Skip to content

Commit

Permalink
macros.quote: document hard to use op; add more useful examples (ni…
Browse files Browse the repository at this point in the history
…m-lang#16489)

* macros.quote: document hard to use `op`; add more useful examples

* add back doc comment removed in a60305f

* address comment

* fixup

* clarify quoting rules

* Update lib/core/macros.nim

Co-authored-by: Clyybber <[email protected]>

Co-authored-by: Clyybber <[email protected]>
  • Loading branch information
2 people authored and ardek66 committed Mar 26, 2021
1 parent 71999cb commit 35b3712
Showing 1 changed file with 71 additions and 23 deletions.
94 changes: 71 additions & 23 deletions lib/core/macros.nim
Original file line number Diff line number Diff line change
Expand Up @@ -566,34 +566,82 @@ proc getAst*(macroOrTemplate: untyped): NimNode {.magic: "ExpandToAst", noSideEf
## macro FooMacro() =
## var ast = getAst(BarTemplate())

proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.}
proc quote*(bl: typed, op = "``"): NimNode {.magic: "QuoteAst", noSideEffect.} =
## 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
## from the surrounding scope. If no operator is given, quoting is done using
## backticks. Otherwise, the given operator must be used as a prefix operator
## for any interpolated expression.
##
## Example:
##
## .. code-block:: nim
##
## macro check(ex: untyped) =
## # this is a simplified version of the check macro from the
## # unittest module.
##
## # If there is a failed check, we want to make it easy for
## # the user to jump to the faulty line in the code, so we
## # get the line info here:
## var info = ex.lineinfo
##
## # We will also display the code string of the failed check:
## var expString = ex.toStrLit
##
## # Finally we compose the code to implement the check:
## result = quote do:
## if not `ex`:
## echo `info` & ": Check failed: " & `expString`
## for any interpolated expression. The original meaning of the interpolation
## operator may be obtained by escaping it (by prefixing it with itself) when used
## as a unary operator:
## e.g. `@` is escaped as `@@`, `&%` is escaped as `&%&%` and so on; see examples.
runnableExamples:
macro check(ex: untyped) =
# this is a simplified version of the check macro from the
# unittest module.

# If there is a failed check, we want to make it easy for
# the user to jump to the faulty line in the code, so we
# get the line info here:
var info = ex.lineinfo

# We will also display the code string of the failed check:
var expString = ex.toStrLit

# Finally we compose the code to implement the check:
result = quote do:
if not `ex`:
echo `info` & ": Check failed: " & `expString`
check 1 + 1 == 2

runnableExamples:
# example showing how to define a symbol that requires backtick without
# quoting it.
var destroyCalled = false
macro bar() =
let s = newTree(nnkAccQuoted, ident"=destroy")
# let s = ident"`=destroy`" # this would not work
result = quote do:
type Foo = object
# proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work
proc `s`(a: var Foo) = destroyCalled = true
block:
let a = Foo()
bar()
doAssert destroyCalled

runnableExamples:
# custom `op`
var destroyCalled = false
macro bar() =
var x = 1.5
result = quote("@") do:
type Foo = object
proc `=destroy`(a: var Foo) =
doAssert @x == 1.5
doAssert compiles(@x == 1.5)
let b1 = @[1,2]
let b2 = @@[1,2]
doAssert $b1 == "[1, 2]"
doAssert $b2 == "@[1, 2]"
destroyCalled = true
block:
let a = Foo()
bar()
doAssert destroyCalled

proc `&%`(x: int): int = 1
proc `&%`(x, y: int): int = 2

macro bar2() =
var x = 3
result = quote("&%") do:
var y = &%x # quoting operator
doAssert &%&%y == 1 # unary operator => need to escape
doAssert y &% y == 2 # binary operator => no need to escape
doAssert y == 3
bar2()

proc expectKind*(n: NimNode, k: NimNodeKind) {.compileTime.} =
## Checks that `n` is of kind `k`. If this is not the case,
Expand Down

0 comments on commit 35b3712

Please sign in to comment.