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

@emit

@emit adds one value to the program’s output.

Syntax

@emit value

Example

macro bytes3(a: int, b: int, c: int) {
    @emit a
    @emit b
    @emit c
}

bytes3 1, 2, 3
1 2 3

What can be emitted

Any value: an integer, a struct, an enum variant. The compiler doesn’t care what a value means; it just records it in order in the .em file. What the value turns into is the evaluator’s decision. For example, bitter packs a bits<8> into one byte and an instruction struct into its encoding.

from std.binary import bits

struct Pair {
    pub hi: bits<4>,
    pub lo: bits<4>,
}

macro pair(hi: int, lo: int) {
    @emit Pair(hi as bits<4>, lo as bits<4>)
}

pair 0xA, 0xB
Pair { hi: bits<4> { value: 10 }, lo: bits<4> { value: 11 } }
ab

Emitting from nested calls

A macro’s output includes everything emitted by the macros it calls, in order. So an instruction macro can be built from smaller ones.

A call used as an expression can only emit when its values have somewhere to go. See Where emitted values can go.

Restricting what a macro emits: emits

The emits facet declares which types a macro may emit. It’s optional, but if it’s there, it’s enforced: emitting anything else is a compile error. Give several emits facets to allow several types, and use a wildcard to allow any instance of a generic type, as in | emits bits<...>. This is how instruction macros declare what they encode to; -> is only for what a macro returns.

from std.binary import bits

macro byte(value: int)
    | emits bits<8>
{
    @emit value as bits<8>
}

byte 0x41
bits<8> { value: 65 }
from std.binary import bits

macro byte(value: int)
    | emits bits<8>
{
    @emit value
}

byte 0x41
`@emit`ed value has type `int`, but this macro's `emits` facet(s) only declare `bits<8>`

A macro with no emits facet may emit anything.

Emitting moves labels

Each emitted value takes up one position in the output, and a label is the position of the next value emitted after it.