Check for a positive value.
If not positive, fail at runtime with a helpful message.
let x = -5 assertPositive(x + 3) # Runtime error: expected x + 3 to be > 0
Hint: Inside the macro, build an
if
block usingquote do
(withwhen
orif
).
The insight for you: quote do
generates the if
-code, but does not run it.
When you write quote do
, it builds the code and inserts it where the macro is called. if
only runs when the program runs - not when the macro is expanding.
While the macro appears to be evaluating a runtime if
-check, it isn't:
Instead, the macro injects an if
statement into the place where the macro is used (by the quote do
part).
The macro does not evaluate the expression at compile time.
The if
check is evaluated later, at runtime - because x
is not known at compile time.
Don't use when
to check if the expression is > 0
at runtime - use if
inside the quote do
. Why not when?
if
works for runtime evaluation.
when
only works for things known at compile time.
Thus something like this:
`when `expr` <= 0:`
will fail unless expr
is a compile-time constant (like const y = -2
).
>
0. Here's when when
would be appropriate:
const y = 3
when y > 0: echo "Compile-time check: y is positive" else:
(The {.error: "text".}
part above is a compile-time pragma in Nim, which triggers a compile-time error.)
Be mindful of the difference between quote do:
and just result = quote do:
.
import macros
macro assertPositive(expr: untyped): untyped =
# GENERATE the code, not do an evaluation
quote do:
if `expr` <= 0:
raise newException(
ValueError,
"expected " & astToStr(`expr`) & " to be > 0, got instead: " & $`expr`,
)
# echo astToStr(`expr`) # Shows the expression
# echo `expr` # Shows the evaluated expression
# macro assertPositiveWhen(expr: untyped): untyped =
# NOT POSSIBLE with problem
let x = -5
assertPositive(x + 9)
# assertPositive(x + 2) # Compare to this