Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Macros

Macros are how BitterASM does everything. An instruction like add a0, a1, a2 is a call to a macro named add. A “pseudo-instruction” is a macro too, and so is a helper that computes a value. The language draws no line between them.

A macro runs at compile time. It can compute values, check conditions, call other macros, and emit values into the program’s output.

Declaring a macro

macro name(param: Type, ...) -> ReturnType
    | facet ...
{
    body
}
  • Parameters each have a name and a type. See Parameters and defaults.
  • -> ReturnType is optional. See Returning values.
  • Facets (| before ..., | syntax { ... }, …) are optional modifiers, one per line, before the body.
  • pub macro lets other files import it. See Visibility.

Two ways to call a macro

As a statement, like an instruction: the name, then its arguments separated by commas, with no parentheses. Whatever the macro emits goes into the output.

As an expression, like a function: the name, then its arguments in parentheses. The call’s value is whatever the macro returns.

macro square(x: int) -> int {
    @return x * x
}

macro show(value: int) {
    @emit value
}

show 3              # statement call
show square(4)      # `square(4)` is an expression call
3 16

A statement call throws away the macro’s return value, so a statement call of square would do nothing. An expression call can’t throw away emitted values, so a macro that emits can only be called as an expression in a few places. See Where emitted values can go.

A macro with no parameters is called by its name alone:

macro nop() {
    @emit 0x13
}

nop
nop
19 19

Inside a macro

A macro’s body is a list of statements:

  • Meta keywords such as @emit, @return, @if and @for.
  • Calls to other macros, which emit into this macro’s output.
  • const declarations naming intermediate values.
  • Declarations that the macro generates when it’s called. See Generating declarations.
macro show(value: int) {
    @emit value
}

macro countdown(start: int) {
    @for i in 0..start {
        show start - i
    }
    show 0
}

countdown 3
3 2 1 0

In this chapter

Macros can also be generic, and can take other macros as arguments. See Generics.