Skip to content

macros

Macros are functions that run while compiling and return code.

Terminal window
jihoo run examples/macros.jh
jihoo emit-ir examples/macros.jh // `main` contains only the expanded code
examples/macros.jh
// `expr` parameters receive code; other parameters receive compile-time values.
macro power(x: expr, n: i64) -> expr {
let e = quote(1)
let i = 0
while i < n {
e = quote($e * $x) // `$x` is inserted in parentheses
i = i + 1
}
return e
}
// `stringify` turns code back into text: handy for messages.
macro expect(cond: expr) -> expr {
return quote(report($cond, $(stringify(cond))))
}
// Macros can make any expression, including struct literals and other macro calls.
macro point(x: expr) -> expr {
return quote(Point { x: $x, y: power!($x, 2) })
}
// `stmts` macros add statements to the block they are used in. Macros are
// hygienic: the template's `tmp` is the macro's own, so `swap!(tmp, x)` works
// and `tmp` is gone after the macro. A name the caller should see goes through
// a hole, as `fn $getter` in `getters!` below.
macro swap(a: expr, b: expr) -> stmts {
return quote {
let tmp = $a
$a = $b
$b = tmp
}
}
// `items` macros define functions and types at the top level. `$name` in a name
// position inserts a `str` as a name.
macro getters(name: str, fields: i64) -> items {
let out = quote items {}
let i = 0
while i < fields {
let getter = name + "_" + to_str(i)
out = quote items {
$out
fn $getter(p: Point) -> i64 { return p.x * $i + p.y }
}
i = i + 1
}
return out
}
getters!("mix", 3) // defines mix_0, mix_1 and mix_2
struct Point {
x: i64
y: i64
}
fn report(ok: bool, what: str) -> i64 {
if ok {
print("ok: " + what)
return 0
}
print("FAILED: " + what)
return 1
}
fn main() -> i64 {
let y = 3
print(power!(y, 4)) // 81, as y * y * y * y with no loop at runtime
print(power!(y + 1, 2)) // 16: (y + 1) * (y + 1)
let p = point!(y)
let a = 1
let b = 2
swap!(a, b)
print(a * 10 + b) // 21
print(mix_2(p)) // 3 * 2 + 9 = 15
let failures = expect!(p.y == 9)
failures = failures + expect!(power!(2, 10) == 1024)
failures = failures + expect!(p.x + 1 == 5)
return failures // 1: the last check fails on purpose
}

View on GitHub