diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-01-06 10:28:17 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-06 19:28:17 +0100 |
commit | c21360e67accbbad0c24c84432fdb4506f68c881 (patch) | |
tree | c6996641648111cd674621cca3ae8cce5ca8892b /lib/core | |
parent | 0d5cab77f65df1431ed417a666ba49136af3b2c1 (diff) | |
download | Nim-c21360e67accbbad0c24c84432fdb4506f68c881.tar.gz |
macros.quote: document hard to use `op`; add more useful examples (#16489)
* macros.quote: document hard to use `op`; add more useful examples * add back doc comment removed in a60305fbf3897cd90680e693dd4c0db2334d85d4 * address comment * fixup * clarify quoting rules * Update lib/core/macros.nim Co-authored-by: Clyybber <darkmine956@gmail.com> Co-authored-by: Clyybber <darkmine956@gmail.com>
Diffstat (limited to 'lib/core')
-rw-r--r-- | lib/core/macros.nim | 94 |
1 files changed, 71 insertions, 23 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 748464061..204123f41 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -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, |