Constants
const gives a value a name:
const WIDTH = 8
const MASK = (1 << WIDTH) - 1
macro show(value: int) {
@emit value
}
show MASK
255
A constant can hold any value: an integer, a struct, an enum variant, or a string.
Syntax
const NAME = value
const NAME: Type = value
pub const NAME = value
: Typeconverts the value toType, and checks it, before binding it. See Conversions.publets other files import the constant. See Visibility.
from std.binary import bits
const BYTE: bits<8> = 200
macro emit_byte(b: bits<8>) {
@emit b
}
emit_byte BYTE
bits<8> { value: 200 }
A value that doesn’t fit the type is a compile error. bits<8> checks that
its value fits in eight bits:
from std.binary import bits
const BYTE: bits<8> = 300
invariant `fits_inside_width(width, value)` was violated for `bits`
Constants never change
There are no variables in BitterASM. A constant is bound once and never
reassigned, and nothing in the language can be mutated. To compute a value
step by step, use recursion or @fold.
Constants inside macros
Inside a macro body, const names an intermediate value. It’s visible for
the rest of that body:
macro hypot_squared(a: int, b: int) {
const aa = a * a
const bb = b * b
@emit aa + bb
}
hypot_squared 3, 4
25
A pub const inside a macro is different: it declares a new top-level
constant when the macro is called. See
Generating declarations.
Registers are constants
Architecture packages use constants for registers. For example,
std.riscv.impl declares each register as a constant of type Reg, a
five-bit number:
pub type Reg = bits<5>
@for i in 0..32 {
pub const x`i` = Reg(i)
}
pub const zero = x0
pub const ra = x1
The x`i` builds the names x0 to x31. See
Spliced names.