Use `constant` instead of `const`

c92591c97b99e5ab1a677d5c98c941651324ff6970b92acd2a8e424cac4df18a
Alexis Sellier committed ago 1 parent 52b9cccc
compiler/radiance.rad +14 -14
20 20
use std::sys;
21 21
use std::sys::unix;
22 22
use std::collections::dict;
23 23
24 24
/// Maximum number of modules we can load per package.
25 -
const MAX_LOADED_MODULES: u32 = 64;
25 +
constant MAX_LOADED_MODULES: u32 = 64;
26 26
/// Maximum number of packages we can compile.
27 -
const MAX_PACKAGES: u32 = 4;
27 +
constant MAX_PACKAGES: u32 = 4;
28 28
/// Total module entries across all packages.
29 -
const MAX_TOTAL_MODULES: u32 = 192;
29 +
constant MAX_TOTAL_MODULES: u32 = 192;
30 30
/// Source code buffer arena (2 MB).
31 -
const MAX_SOURCES_SIZE: u32 = 2097152;
31 +
constant MAX_SOURCES_SIZE: u32 = 2097152;
32 32
/// Maximum number of test functions we can discover.
33 -
const MAX_TESTS: u32 = 1024;
33 +
constant MAX_TESTS: u32 = 1024;
34 34
35 35
/// Temporary arena size (32 MB) - retains all parsed AST until resolution.
36 36
/// Used for: AST during parsing, then codegen scratch space.
37 -
const TEMP_ARENA_SIZE: u32 = 33554432;
37 +
constant TEMP_ARENA_SIZE: u32 = 33554432;
38 38
/// Main arena size (128 MB) - lives throughout compilation.
39 39
/// Used for: resolver data, types, symbols, lowered IL.
40 -
const MAIN_ARENA_SIZE: u32 = 134217728;
40 +
constant MAIN_ARENA_SIZE: u32 = 134217728;
41 41
42 42
/// Temporary storage arena - reusable between phases.
43 43
static TEMP_ARENA: [u8; TEMP_ARENA_SIZE] = undefined;
44 44
/// Main storage arena - persists throughout compilation.
45 45
static MAIN_ARENA: [u8; MAIN_ARENA_SIZE] = undefined;
60 60
static CODEGEN_DATA_SYMS: [data::DataSym; data::MAX_DATA_SYMS] = undefined;
61 61
/// Hash table entries for data symbol lookup.
62 62
static CODEGEN_DATA_SYM_ENTRIES: [dict::Entry; data::DATA_SYM_TABLE_SIZE] = undefined;
63 63
64 64
/// Debug info file extension.
65 -
const DEBUG_EXT: *[u8] = ".debug";
65 +
constant DEBUG_EXT: *[u8] = ".debug";
66 66
67 67
/// Read-only data file extension.
68 -
const RO_DATA_EXT: *[u8] = ".ro.data";
68 +
constant RO_DATA_EXT: *[u8] = ".ro.data";
69 69
/// Read-write data file extension.
70 -
const RW_DATA_EXT: *[u8] = ".rw.data";
70 +
constant RW_DATA_EXT: *[u8] = ".rw.data";
71 71
/// Maximum rodata size (1MB).
72 -
const MAX_RO_DATA_SIZE: u32 = 1048576;
72 +
constant MAX_RO_DATA_SIZE: u32 = 1048576;
73 73
/// Maximum rwdata size (1MB).
74 -
const MAX_RW_DATA_SIZE: u32 = 1048576;
74 +
constant MAX_RW_DATA_SIZE: u32 = 1048576;
75 75
/// Maximum path length.
76 -
const MAX_PATH_LEN: u32 = 256;
76 +
constant MAX_PATH_LEN: u32 = 256;
77 77
/// Read-only data buffer.
78 78
static RO_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = undefined;
79 79
/// Read-write data buffer.
80 80
static RW_DATA_BUF: [u8; MAX_RW_DATA_SIZE] = undefined;
81 81
82 82
/// Usage string.
83 -
const USAGE: *[u8] =
83 +
constant USAGE: *[u8] =
84 84
    "usage: radiance -pkg <name> -mod <input>.. [-pkg <name> -mod <input>..] -entry <pkg> -o <output>\n";
85 85
86 86
/// Compiler error.
87 87
union Error {
88 88
    Other,
lib/std/arch/rv64.rad +50 -50
30 30
31 31
////////////////
32 32
// Registers  //
33 33
////////////////
34 34
35 -
export const ZERO: gen::Reg = gen::Reg(0);   /// Hard-wired zero.
36 -
export const RA:   gen::Reg = gen::Reg(1);   /// Return address.
37 -
export const SP:   gen::Reg = gen::Reg(2);   /// Stack pointer.
38 -
export const GP:   gen::Reg = gen::Reg(3);   /// Global pointer.
39 -
export const TP:   gen::Reg = gen::Reg(4);   /// Thread pointer.
40 -
export const T0:   gen::Reg = gen::Reg(5);   /// Temporary/alternate link register.
41 -
export const T1:   gen::Reg = gen::Reg(6);   /// Temporary.
42 -
export const T2:   gen::Reg = gen::Reg(7);   /// Temporary.
43 -
export const S0:   gen::Reg = gen::Reg(8);   /// Saved register/frame pointer.
44 -
export const FP:   gen::Reg = gen::Reg(8);   /// Frame pointer (alias for S0).
45 -
export const S1:   gen::Reg = gen::Reg(9);   /// Saved register.
46 -
export const A0:   gen::Reg = gen::Reg(10);  /// Function argument/return.
47 -
export const A1:   gen::Reg = gen::Reg(11);  /// Function argument/return.
48 -
export const A2:   gen::Reg = gen::Reg(12);  /// Function argument.
49 -
export const A3:   gen::Reg = gen::Reg(13);  /// Function argument.
50 -
export const A4:   gen::Reg = gen::Reg(14);  /// Function argument.
51 -
export const A5:   gen::Reg = gen::Reg(15);  /// Function argument.
52 -
export const A6:   gen::Reg = gen::Reg(16);  /// Function argument.
53 -
export const A7:   gen::Reg = gen::Reg(17);  /// Function argument.
54 -
export const S2:   gen::Reg = gen::Reg(18);  /// Saved register.
55 -
export const S3:   gen::Reg = gen::Reg(19);  /// Saved register.
56 -
export const S4:   gen::Reg = gen::Reg(20);  /// Saved register.
57 -
export const S5:   gen::Reg = gen::Reg(21);  /// Saved register.
58 -
export const S6:   gen::Reg = gen::Reg(22);  /// Saved register.
59 -
export const S7:   gen::Reg = gen::Reg(23);  /// Saved register.
60 -
export const S8:   gen::Reg = gen::Reg(24);  /// Saved register.
61 -
export const S9:   gen::Reg = gen::Reg(25);  /// Saved register.
62 -
export const S10:  gen::Reg = gen::Reg(26);  /// Saved register.
63 -
export const S11:  gen::Reg = gen::Reg(27);  /// Saved register.
64 -
export const T3:   gen::Reg = gen::Reg(28);  /// Temporary.
65 -
export const T4:   gen::Reg = gen::Reg(29);  /// Temporary.
66 -
export const T5:   gen::Reg = gen::Reg(30);  /// Temporary.
67 -
export const T6:   gen::Reg = gen::Reg(31);  /// Temporary.
35 +
export constant ZERO: gen::Reg = gen::Reg(0);   /// Hard-wired zero.
36 +
export constant RA:   gen::Reg = gen::Reg(1);   /// Return address.
37 +
export constant SP:   gen::Reg = gen::Reg(2);   /// Stack pointer.
38 +
export constant GP:   gen::Reg = gen::Reg(3);   /// Global pointer.
39 +
export constant TP:   gen::Reg = gen::Reg(4);   /// Thread pointer.
40 +
export constant T0:   gen::Reg = gen::Reg(5);   /// Temporary/alternate link register.
41 +
export constant T1:   gen::Reg = gen::Reg(6);   /// Temporary.
42 +
export constant T2:   gen::Reg = gen::Reg(7);   /// Temporary.
43 +
export constant S0:   gen::Reg = gen::Reg(8);   /// Saved register/frame pointer.
44 +
export constant FP:   gen::Reg = gen::Reg(8);   /// Frame pointer (alias for S0).
45 +
export constant S1:   gen::Reg = gen::Reg(9);   /// Saved register.
46 +
export constant A0:   gen::Reg = gen::Reg(10);  /// Function argument/return.
47 +
export constant A1:   gen::Reg = gen::Reg(11);  /// Function argument/return.
48 +
export constant A2:   gen::Reg = gen::Reg(12);  /// Function argument.
49 +
export constant A3:   gen::Reg = gen::Reg(13);  /// Function argument.
50 +
export constant A4:   gen::Reg = gen::Reg(14);  /// Function argument.
51 +
export constant A5:   gen::Reg = gen::Reg(15);  /// Function argument.
52 +
export constant A6:   gen::Reg = gen::Reg(16);  /// Function argument.
53 +
export constant A7:   gen::Reg = gen::Reg(17);  /// Function argument.
54 +
export constant S2:   gen::Reg = gen::Reg(18);  /// Saved register.
55 +
export constant S3:   gen::Reg = gen::Reg(19);  /// Saved register.
56 +
export constant S4:   gen::Reg = gen::Reg(20);  /// Saved register.
57 +
export constant S5:   gen::Reg = gen::Reg(21);  /// Saved register.
58 +
export constant S6:   gen::Reg = gen::Reg(22);  /// Saved register.
59 +
export constant S7:   gen::Reg = gen::Reg(23);  /// Saved register.
60 +
export constant S8:   gen::Reg = gen::Reg(24);  /// Saved register.
61 +
export constant S9:   gen::Reg = gen::Reg(25);  /// Saved register.
62 +
export constant S10:  gen::Reg = gen::Reg(26);  /// Saved register.
63 +
export constant S11:  gen::Reg = gen::Reg(27);  /// Saved register.
64 +
export constant T3:   gen::Reg = gen::Reg(28);  /// Temporary.
65 +
export constant T4:   gen::Reg = gen::Reg(29);  /// Temporary.
66 +
export constant T5:   gen::Reg = gen::Reg(30);  /// Temporary.
67 +
export constant T6:   gen::Reg = gen::Reg(31);  /// Temporary.
68 68
69 69
/// Create a register from a number. Panics if `n > 31`.
70 70
export fn reg(n: u8) -> gen::Reg {
71 71
    assert n < 32;
72 72
    return gen::Reg(n);
75 75
////////////////////////////
76 76
// Architecture constants //
77 77
////////////////////////////
78 78
79 79
/// Total number of general-purpose registers.
80 -
export const NUM_REGISTERS: u8 = 32;
80 +
export constant NUM_REGISTERS: u8 = 32;
81 81
/// Number of saved registers.
82 -
export const NUM_SAVED_REGISTERS: u8 = 11;
82 +
export constant NUM_SAVED_REGISTERS: u8 = 11;
83 83
/// Word size in bytes (32-bit).
84 -
export const WORD_SIZE: i32 = 4;
84 +
export constant WORD_SIZE: i32 = 4;
85 85
/// Doubleword size in bytes (64-bit).
86 -
export const DWORD_SIZE: i32 = 8;
86 +
export constant DWORD_SIZE: i32 = 8;
87 87
/// Instruction size in bytes.
88 -
export const INSTR_SIZE: i32 = 4;
88 +
export constant INSTR_SIZE: i32 = 4;
89 89
/// Stack alignment requirement in bytes.
90 -
export const STACK_ALIGNMENT: i32 = 16;
90 +
export constant STACK_ALIGNMENT: i32 = 16;
91 91
92 92
/// Minimum blit size (in bytes) to use a loop instead of inline copy.
93 93
/// Blits below this threshold are fully unrolled as LD/SD pairs.
94 -
export const BLIT_LOOP_THRESHOLD: i32 = 256;
94 +
export constant BLIT_LOOP_THRESHOLD: i32 = 256;
95 95
96 96
/////////////////////////
97 97
// Codegen Allocation  //
98 98
/////////////////////////
99 99
100 100
/// Argument registers for function calls.
101 -
export const ARG_REGS: [gen::Reg; 8] = [A0, A1, A2, A3, A4, A5, A6, A7];
101 +
export constant ARG_REGS: [gen::Reg; 8] = [A0, A1, A2, A3, A4, A5, A6, A7];
102 102
103 103
/// Scratch register for code gen. Never allocated to user values.
104 -
export const SCRATCH1: gen::Reg = T5;
104 +
export constant SCRATCH1: gen::Reg = T5;
105 105
106 106
/// Second scratch register for operations needing two temporaries.
107 -
export const SCRATCH2: gen::Reg = T6;
107 +
export constant SCRATCH2: gen::Reg = T6;
108 108
109 109
/// Dedicated scratch for address offset adjustment. Never allocated to user
110 110
/// values and never used for operand materialization, so it can never
111 111
/// conflict with `rd`, `rs`, or `base` in load/store helpers.
112 -
export const ADDR_SCRATCH: gen::Reg = T4;
112 +
export constant ADDR_SCRATCH: gen::Reg = T4;
113 113
114 114
/// Callee-saved registers that need save/restore if used.
115 -
export const CALLEE_SAVED: [gen::Reg; NUM_SAVED_REGISTERS] = [S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11];
115 +
export constant CALLEE_SAVED: [gen::Reg; NUM_SAVED_REGISTERS] = [S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11];
116 116
117 117
/// Maximum 12-bit signed immediate value.
118 -
export const MAX_IMM: i32 = 2047;
118 +
export constant MAX_IMM: i32 = 2047;
119 119
120 120
/// Minimum 12-bit signed immediate value.
121 -
export const MIN_IMM: i32 = -2048;
121 +
export constant MIN_IMM: i32 = -2048;
122 122
123 123
/// Allocatable registers for register allocation.
124 -
const ALLOCATABLE_REGS: [gen::Reg; 23] = [
124 +
constant ALLOCATABLE_REGS: [gen::Reg; 23] = [
125 125
    T0, T1, T2, T3,                             // Temporaries
126 126
    A0, A1, A2, A3, A4, A5, A6, A7,             // Arguments
127 127
    S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, // Saved
128 128
];
129 129
141 141
///////////////////////
142 142
// Codegen Constants //
143 143
///////////////////////
144 144
145 145
/// Base address where read-only data is loaded.
146 -
export const RO_DATA_BASE: u32 = 0x10000;
146 +
export constant RO_DATA_BASE: u32 = 0x10000;
147 147
148 148
/// Base address where read-write data is loaded.
149 -
export const RW_DATA_BASE: u32 = 0xFFFFF0;
149 +
export constant RW_DATA_BASE: u32 = 0xFFFFF0;
150 150
151 151
/// Storage buffers passed from driver for code generation.
152 152
export record Storage {
153 153
    /// Buffer for data symbols.
154 154
    dataSyms: *mut [data::DataSym],
lib/std/arch/rv64/emit.rad +5 -5
11 11
use std::mem;
12 12
13 13
use super::encode;
14 14
15 15
/// Maximum number of instructions in code buffer.
16 -
const MAX_INSTRS: u32 = 2097152;
16 +
constant MAX_INSTRS: u32 = 2097152;
17 17
/// Maximum code length before byte offset overflows signed 32-bits.
18 -
const MAX_CODE_LEN: u32 = 0x7FFFFFFF / super::INSTR_SIZE as u32;
18 +
constant MAX_CODE_LEN: u32 = 0x7FFFFFFF / super::INSTR_SIZE as u32;
19 19
/// Maximum number of pending branches awaiting patching.
20 -
const MAX_PENDING: u32 = 65536;
20 +
constant MAX_PENDING: u32 = 65536;
21 21
/// Maximum number of function entries.
22 -
const MAX_FUNCS: u32 = 4096;
22 +
constant MAX_FUNCS: u32 = 4096;
23 23
/// Maximum number of debug entries.
24 -
const MAX_DEBUG_ENTRIES: u32 = 524288;
24 +
constant MAX_DEBUG_ENTRIES: u32 = 524288;
25 25
26 26
//////////////////////
27 27
// Emission Context //
28 28
//////////////////////
29 29
lib/std/arch/rv64/encode.rad +37 -37
6 6
7 7
//////////////////////
8 8
// Opcode Constants //
9 9
//////////////////////
10 10
11 -
export const OP_LOAD:   u32 = 0x03;
12 -
export const OP_STORE:  u32 = 0x23;
13 -
export const OP_BRANCH: u32 = 0x63;
14 -
export const OP_JALR:   u32 = 0x67;
15 -
export const OP_JAL:    u32 = 0x6F;
16 -
export const OP_OP:     u32 = 0x33;
17 -
export const OP_IMM:    u32 = 0x13;
18 -
export const OP_AUIPC:  u32 = 0x17;
19 -
export const OP_LUI:    u32 = 0x37;
20 -
export const OP_SYSTEM: u32 = 0x73;
21 -
export const OP_OP32:   u32 = 0x3B;  // RV64: 32-bit operations
22 -
export const OP_IMM32:  u32 = 0x1B;  // RV64: 32-bit immediate operations
11 +
export constant OP_LOAD:   u32 = 0x03;
12 +
export constant OP_STORE:  u32 = 0x23;
13 +
export constant OP_BRANCH: u32 = 0x63;
14 +
export constant OP_JALR:   u32 = 0x67;
15 +
export constant OP_JAL:    u32 = 0x6F;
16 +
export constant OP_OP:     u32 = 0x33;
17 +
export constant OP_IMM:    u32 = 0x13;
18 +
export constant OP_AUIPC:  u32 = 0x17;
19 +
export constant OP_LUI:    u32 = 0x37;
20 +
export constant OP_SYSTEM: u32 = 0x73;
21 +
export constant OP_OP32:   u32 = 0x3B;  // RV64: 32-bit operations
22 +
export constant OP_IMM32:  u32 = 0x1B;  // RV64: 32-bit immediate operations
23 23
24 24
//////////////////////
25 25
// Funct3 Constants //
26 26
//////////////////////
27 27
28 28
// Memory operations
29 29
30 -
export const F3_BYTE:   u32 = 0x0;  // LB/SB
31 -
export const F3_HALF:   u32 = 0x1;  // LH/SH
32 -
export const F3_WORD:   u32 = 0x2;  // LW/SW
33 -
export const F3_DWORD:  u32 = 0x3;  // LD/SD (RV64)
34 -
export const F3_BYTE_U: u32 = 0x4;  // LBU
35 -
export const F3_HALF_U: u32 = 0x5;  // LHU
36 -
export const F3_WORD_U: u32 = 0x6;  // LWU (RV64)
30 +
export constant F3_BYTE:   u32 = 0x0;  // LB/SB
31 +
export constant F3_HALF:   u32 = 0x1;  // LH/SH
32 +
export constant F3_WORD:   u32 = 0x2;  // LW/SW
33 +
export constant F3_DWORD:  u32 = 0x3;  // LD/SD (RV64)
34 +
export constant F3_BYTE_U: u32 = 0x4;  // LBU
35 +
export constant F3_HALF_U: u32 = 0x5;  // LHU
36 +
export constant F3_WORD_U: u32 = 0x6;  // LWU (RV64)
37 37
38 38
// ALU operations
39 39
40 -
export const F3_ADD:  u32 = 0x0;  // ADD/SUB/ADDI
41 -
export const F3_SLL:  u32 = 0x1;  // SLL/SLLI
42 -
export const F3_SLT:  u32 = 0x2;  // SLT/SLTI
43 -
export const F3_SLTU: u32 = 0x3;  // SLTU/SLTIU
44 -
export const F3_XOR:  u32 = 0x4;  // XOR/XORI
45 -
export const F3_SRL:  u32 = 0x5;  // SRL/SRA/SRLI/SRAI
46 -
export const F3_OR:   u32 = 0x6;  // OR/ORI
47 -
export const F3_AND:  u32 = 0x7;  // AND/ANDI
40 +
export constant F3_ADD:  u32 = 0x0;  // ADD/SUB/ADDI
41 +
export constant F3_SLL:  u32 = 0x1;  // SLL/SLLI
42 +
export constant F3_SLT:  u32 = 0x2;  // SLT/SLTI
43 +
export constant F3_SLTU: u32 = 0x3;  // SLTU/SLTIU
44 +
export constant F3_XOR:  u32 = 0x4;  // XOR/XORI
45 +
export constant F3_SRL:  u32 = 0x5;  // SRL/SRA/SRLI/SRAI
46 +
export constant F3_OR:   u32 = 0x6;  // OR/ORI
47 +
export constant F3_AND:  u32 = 0x7;  // AND/ANDI
48 48
49 49
// Branch operations
50 50
51 -
export const F3_BEQ:  u32 = 0x0;
52 -
export const F3_BNE:  u32 = 0x1;
53 -
export const F3_BLT:  u32 = 0x4;
54 -
export const F3_BGE:  u32 = 0x5;
55 -
export const F3_BLTU: u32 = 0x6;
56 -
export const F3_BGEU: u32 = 0x7;
51 +
export constant F3_BEQ:  u32 = 0x0;
52 +
export constant F3_BNE:  u32 = 0x1;
53 +
export constant F3_BLT:  u32 = 0x4;
54 +
export constant F3_BGE:  u32 = 0x5;
55 +
export constant F3_BLTU: u32 = 0x6;
56 +
export constant F3_BGEU: u32 = 0x7;
57 57
58 58
//////////////////////
59 59
// Funct7 Constants //
60 60
//////////////////////
61 61
62 -
export const F7_NORMAL: u32 = 0b0000000;
63 -
export const F7_SUB:    u32 = 0b0100000;  // Bit 5 set
64 -
export const F7_SRA:    u32 = 0b0100000;  // Bit 5 set
65 -
export const F7_MUL:    u32 = 0b0000001;  // Bit 0 set
62 +
export constant F7_NORMAL: u32 = 0b0000000;
63 +
export constant F7_SUB:    u32 = 0b0100000;  // Bit 5 set
64 +
export constant F7_SRA:    u32 = 0b0100000;  // Bit 5 set
65 +
export constant F7_MUL:    u32 = 0b0000001;  // Bit 0 set
66 66
67 67
/////////////////////////
68 68
// Validation Helpers  //
69 69
/////////////////////////
70 70
lib/std/arch/rv64/isel.rad +15 -15
40 40
///////////////
41 41
// Constants //
42 42
///////////////
43 43
44 44
/// Shift amount for byte sign/zero extension.
45 -
const SHIFT_W8: i32 = 64 - 8;
45 +
constant SHIFT_W8: i32 = 64 - 8;
46 46
/// Shift amount for halfword sign/zero extension.
47 -
const SHIFT_W16: i32 = 64 - 16;
47 +
constant SHIFT_W16: i32 = 64 - 16;
48 48
/// Shift amount for word sign/zero extension.
49 -
const SHIFT_W32: i32 = 64 - 32;
49 +
constant SHIFT_W32: i32 = 64 - 32;
50 50
/// Mask for extracting byte value.
51 -
const MASK_W8: i32 = 0xFF;
51 +
constant MASK_W8: i32 = 0xFF;
52 52
/// Maximum number of block arguments supported.
53 -
const MAX_BLOCK_ARGS: u32 = 16;
53 +
constant MAX_BLOCK_ARGS: u32 = 16;
54 54
55 55
/// Signed integer range limits.
56 -
const I8_MIN: i64 = -128;
57 -
const I8_MAX: i64 = 127;
58 -
const I16_MIN: i64 = -32768;
59 -
const I16_MAX: i64 = 32767;
60 -
const I32_MIN: i64 = -2147483648;
61 -
const I32_MAX: i64 = 2147483647;
56 +
constant I8_MIN: i64 = -128;
57 +
constant I8_MAX: i64 = 127;
58 +
constant I16_MIN: i64 = -32768;
59 +
constant I16_MAX: i64 = 32767;
60 +
constant I32_MIN: i64 = -2147483648;
61 +
constant I32_MAX: i64 = 2147483647;
62 62
63 63
/// Unsigned integer range limits.
64 -
const U8_MAX: i64 = 255;
65 -
const U16_MAX: i64 = 65535;
66 -
const U32_MAX: i64 = 4294967295;
64 +
constant U8_MAX: i64 = 255;
65 +
constant U16_MAX: i64 = 65535;
66 +
constant U32_MAX: i64 = 4294967295;
67 67
68 68
/// Binary operation.
69 69
union BinOp { Add, And, Or, Xor }
70 70
/// Shift operation.
71 71
union ShiftOp { Sll, Srl, Sra }
750 750
            }
751 751
        },
752 752
        case il::Instr::Ecall { dst, num, a0, a1, a2, a3 } => {
753 753
            // Move arguments using parallel move.
754 754
            // TODO: Can't use slice literals here because the lowerer doesn't
755 -
            // support const-evaluating struct/union values in them.
755 +
            // support constant-evaluating struct/union values in them.
756 756
            let ecallDsts: [gen::Reg; 5] = [super::A7, super::A0, super::A1, super::A2, super::A3];
757 757
            let ecallArgs: [il::Val; 5] = [num, a0, a1, a2, a3];
758 758
759 759
            emitParallelMoves(s, &ecallDsts[..], &ecallArgs[..]);
760 760
            emit::emit(s.e, encode::ecall());
lib/std/arch/rv64/printer.rad +2 -2
15 15
/////////////////////
16 16
// Register Names  //
17 17
/////////////////////
18 18
19 19
/// ABI register names.
20 -
const REG_NAMES: [*[u8]; 32] = [
20 +
constant REG_NAMES: [*[u8]; 32] = [
21 21
    "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
22 22
    "fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
23 23
    "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
24 24
    "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"
25 25
];
66 66
///////////////////////////////
67 67
// Instruction Printing      //
68 68
///////////////////////////////
69 69
70 70
/// Mnemonic column width for alignment.
71 -
const MNEMONIC_WIDTH: u32 = 8;
71 +
constant MNEMONIC_WIDTH: u32 = 8;
72 72
73 73
/// Write text wrapped in parentheses.
74 74
fn writeParens(out: *mut sexpr::Output, s: *[u8]) {
75 75
    write(out, "(");
76 76
    write(out, s);
lib/std/fmt.rad +5 -5
1 1
//! Formatting utilities for converting values to strings.
2 2
use super::mem;
3 3
4 4
/// Maximum string length for a formatted u32 (eg. "4294967295").
5 -
export const U32_STR_LEN: u32 = 10;
5 +
export constant U32_STR_LEN: u32 = 10;
6 6
/// Maximum string length for a formatted i32 (eg. "-2147483648").
7 -
export const I32_STR_LEN: u32 = U32_STR_LEN + 1;
7 +
export constant I32_STR_LEN: u32 = U32_STR_LEN + 1;
8 8
/// Maximum string length for a formatted u64 (eg. "18446744073709551615").
9 -
export const U64_STR_LEN: u32 = 20;
9 +
export constant U64_STR_LEN: u32 = 20;
10 10
/// Maximum string length for a formatted i64 (eg. "-9223372036854775808").
11 -
export const I64_STR_LEN: u32 = 20;
11 +
export constant I64_STR_LEN: u32 = 20;
12 12
/// Maximum string length for a formatted bool (eg. "false").
13 -
export const BOOL_STR_LEN: u32 = 5;
13 +
export constant BOOL_STR_LEN: u32 = 5;
14 14
15 15
/// Format a u32 by writing it to the provided buffer.
16 16
export fn formatU32(val: u32, buffer: *mut [u8]) -> *[u8] {
17 17
    assert buffer.len >= U32_STR_LEN;
18 18
lib/std/lang/ast.rad +1 -1
3 3
4 4
use std::io;
5 5
use std::lang::alloc;
6 6
7 7
/// Maximum number of trait methods.
8 -
export const MAX_TRAIT_METHODS: u32 = 8;
8 +
export constant MAX_TRAIT_METHODS: u32 = 8;
9 9
10 10
/// Arena for all parser allocations.
11 11
///
12 12
/// Uses a bump allocator for both AST nodes and node pointer arrays.
13 13
export record NodeArena {
lib/std/lang/ast/printer.rad +1 -1
346 346
                toExprOrNull(a, decl.type),
347 347
                toExpr(a, decl.value)
348 348
            ]);
349 349
        }
350 350
        case super::NodeValue::ConstDecl(decl) =>
351 -
            return sexpr::list(a, "const", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
351 +
            return sexpr::list(a, "constant", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
352 352
        case super::NodeValue::StaticDecl(decl) =>
353 353
            return sexpr::list(a, "static", &[toExpr(a, decl.ident), toExpr(a, decl.type), toExpr(a, decl.value)]),
354 354
        case super::NodeValue::Assign(a_) =>
355 355
            return sexpr::list(a, "assign", &[toExpr(a, a_.left), toExpr(a, a_.right)]),
356 356
        case super::NodeValue::Return { value } =>
lib/std/lang/gen/bitset.rad +2 -2
215 215
/// Count trailing zeros in a 32-bit value.
216 216
/// Returns the bit position of the lowest set bit (0-31).
217 217
/// Behavior is undefined if `x` is 0.
218 218
fn ctz(x: u32) -> u32 {
219 219
    // De Bruijn sequence for 32-bit CTZ.
220 -
    const DEBRUIJN: u32 = 0x077CB531;
221 -
    const TABLE: [u8; 32] = [
220 +
    constant DEBRUIJN: u32 = 0x077CB531;
221 +
    constant TABLE: [u8; 32] = [
222 222
         0,  1, 28,  2, 29, 14, 24,  3, 30, 22, 20, 15, 25, 17,  4,  8,
223 223
        31, 27, 13, 23, 21, 19, 16,  7, 26, 12, 18,  6, 11,  5, 10,  9,
224 224
    ];
225 225
    // Isolate lowest set bit, multiply by de Bruijn constant, look up.
226 226
    let isolated = x & (~x + 1);
lib/std/lang/gen/data.rad +2 -2
7 7
use std::collections::dict;
8 8
use std::lang::il;
9 9
use std::lang::gen::labels;
10 10
11 11
/// Maximum number of data symbols.
12 -
export const MAX_DATA_SYMS: u32 = 8192;
12 +
export constant MAX_DATA_SYMS: u32 = 8192;
13 13
14 14
/// Size of the data symbol hash table. Must be a power of two
15 15
/// and at least twice the size of [`MAX_DATA_SYMS`].
16 -
export const DATA_SYM_TABLE_SIZE: u32 = MAX_DATA_SYMS * 2;
16 +
export constant DATA_SYM_TABLE_SIZE: u32 = MAX_DATA_SYMS * 2;
17 17
18 18
/// Data symbol entry mapping name to address.
19 19
export record DataSym {
20 20
    /// Symbol name.
21 21
    name: *[u8],
lib/std/lang/gen/labels.rad +3 -3
3 3
//! Provides target-independent block/label tracking for branch resolution.
4 4
5 5
use std::collections::dict;
6 6
7 7
/// Maximum number of blocks per function.
8 -
export const MAX_BLOCKS_PER_FN: u32 = 4096;
8 +
export constant MAX_BLOCKS_PER_FN: u32 = 4096;
9 9
/// Maximum number of functions.
10 -
export const MAX_FUNCS: u32 = 8192;
10 +
export constant MAX_FUNCS: u32 = 8192;
11 11
/// Size of the function hash table. Must be a power of two.
12 -
export const FUNC_TABLE_SIZE: u32 = MAX_FUNCS * 2;
12 +
export constant FUNC_TABLE_SIZE: u32 = MAX_FUNCS * 2;
13 13
14 14
/// Label tracking for code emission.
15 15
export record Labels {
16 16
    /// Block offsets indexed by block index.
17 17
    /// Per-function, reset each function.
lib/std/lang/gen/regalloc/assign.rad +1 -1
12 12
use std::lang::gen::bitset;
13 13
use std::lang::gen::regalloc::liveness;
14 14
use std::lang::gen::regalloc::spill;
15 15
16 16
/// Maximum number of active register mappings.
17 -
const MAX_ACTIVE: u32 = 64;
17 +
constant MAX_ACTIVE: u32 = 64;
18 18
19 19
/// Register mapping at a program point.
20 20
/// Maps SSA registers to physical registers.
21 21
export record RegMap {
22 22
    /// SSA (virtual) registers that have mappings.
lib/std/lang/gen/regalloc/liveness.rad +1 -1
27 27
use std::lang::il;
28 28
use std::lang::alloc;
29 29
use std::lang::gen::bitset;
30 30
31 31
/// Maximum number of SSA registers supported.
32 -
export const MAX_SSA_REGS: u32 = 8192;
32 +
export constant MAX_SSA_REGS: u32 = 8192;
33 33
34 34
/// Liveness information for a function.
35 35
export record LiveInfo {
36 36
    /// Per-block live-in sets (indexed by block index).
37 37
    liveIn: *mut [bitset::Bitset],
lib/std/lang/gen/regalloc/spill.rad +2 -2
34 34
use std::lang::alloc;
35 35
use std::lang::gen::bitset;
36 36
use std::lang::gen::regalloc::liveness;
37 37
38 38
/// Maximum number of candidates for spill sorting.
39 -
const MAX_CANDIDATES: u32 = 256;
39 +
constant MAX_CANDIDATES: u32 = 256;
40 40
/// Maximum loop depth for cost weighting (2^10 = 1024).
41 -
const MAX_LOOP_WEIGHT: u32 = 10;
41 +
constant MAX_LOOP_WEIGHT: u32 = 10;
42 42
43 43
/// Spill cost for a single SSA register.
44 44
record SpillCost {
45 45
    /// Number of definitions (weighted by loop depth).
46 46
    defs: u32,
lib/std/lang/il.rad +2 -2
77 77
///////////////////////
78 78
// Name Formatting   //
79 79
///////////////////////
80 80
81 81
/// Separator for qualified symbol names.
82 -
export const PATH_SEPARATOR: *[u8] = "::";
82 +
export constant PATH_SEPARATOR: *[u8] = "::";
83 83
84 84
/// Format a qualified symbol name: `pkg::mod::path::name`.
85 85
export fn formatQualifiedName(arena: *mut alloc::Arena, path: *[*[u8]], name: *[u8]) -> *[u8] {
86 86
    let mut totalLen: u32 = name.len;
87 87
    for segment in path {
373 373
    /// Size in bytes.
374 374
    size: u32,
375 375
    /// Alignment requirement.
376 376
    alignment: u32,
377 377
    /// Whether this is read-only data.
378 -
    /// Typically, `const` declaration are read-only, while `static`
378 +
    /// Typically, `constant` declaration are read-only, while `static`
379 379
    /// declarations are not.
380 380
    readOnly: bool,
381 381
    /// Whether the data is entirely undefined.
382 382
    /// Undefined data doesn't need to be written since memory is zero-initialized.
383 383
    isUndefined: bool,
lib/std/lang/lower.rad +12 -12
199 199
///////////////
200 200
// Constants //
201 201
///////////////
202 202
203 203
/// Maximum nesting depth of loops.
204 -
const MAX_LOOP_DEPTH: u32 = 16;
204 +
constant MAX_LOOP_DEPTH: u32 = 16;
205 205
/// Maximum number of `catch` clauses per `try`.
206 -
const MAX_CATCH_CLAUSES: u32 = 32;
206 +
constant MAX_CATCH_CLAUSES: u32 = 32;
207 207
208 208
// Slice Layout
209 209
//
210 210
// A slice is a fat pointer consisting of a data pointer and length.
211 211
// `{ ptr: u32, len: u32 }`.
212 212
213 213
/// Slice data pointer offset.
214 -
const SLICE_PTR_OFFSET: i32 = 0;
214 +
constant SLICE_PTR_OFFSET: i32 = 0;
215 215
/// Offset of slice length in slice data structure.
216 -
const SLICE_LEN_OFFSET: i32 = resolver::PTR_SIZE as i32;
216 +
constant SLICE_LEN_OFFSET: i32 = resolver::PTR_SIZE as i32;
217 217
/// Offset of slice capacity in slice data structure.
218 -
const SLICE_CAP_OFFSET: i32 = resolver::PTR_SIZE as i32 + 4;
218 +
constant SLICE_CAP_OFFSET: i32 = resolver::PTR_SIZE as i32 + 4;
219 219
220 220
// Trait Object Layout
221 221
//
222 222
// A trait object is a fat pointer consisting of a data pointer and a
223 223
// v-table pointer. `{ data: *T, vtable: *VTable }`.
224 224
225 225
/// Trait object data pointer offset.
226 -
const TRAIT_OBJ_DATA_OFFSET: i32 = 0;
226 +
constant TRAIT_OBJ_DATA_OFFSET: i32 = 0;
227 227
/// Trait object v-table pointer offset.
228 -
const TRAIT_OBJ_VTABLE_OFFSET: i32 = resolver::PTR_SIZE as i32;
228 +
constant TRAIT_OBJ_VTABLE_OFFSET: i32 = resolver::PTR_SIZE as i32;
229 229
230 230
// Tagged Value Layout (optionals, tagged unions)
231 231
//
232 232
// Optionals and unions use 1-byte tags. Results use 8-byte tags.
233 233
//
237 237
// When `T` is a pointer, the entire optional is stored as a single pointer.
238 238
//
239 239
// Tagged unions have a payload the size of the maximum variant size.
240 240
241 241
/// Offset of tag in tagged value data structure.
242 -
const TVAL_TAG_OFFSET: i32 = 0;
242 +
constant TVAL_TAG_OFFSET: i32 = 0;
243 243
/// Offset of value in result data structure (8-byte tag).
244 -
const RESULT_VAL_OFFSET: i32 = resolver::PTR_SIZE as i32;
244 +
constant RESULT_VAL_OFFSET: i32 = resolver::PTR_SIZE as i32;
245 245
246 246
//////////////////////////
247 247
// Core Data Structures //
248 248
//////////////////////////
249 249
1174 1174
1175 1175
///////////////////////////////
1176 1176
// Data Section Construction //
1177 1177
///////////////////////////////
1178 1178
1179 -
// Functions for building the data section from const/static
1179 +
// Functions for building the data section from constant/static
1180 1180
// declarations and inline literals.
1181 1181
1182 1182
/// Convert a constant integer payload to a signed 64-bit value.
1183 1183
fn constIntToI64(intVal: resolver::ConstInt) -> i64 {
1184 1184
    return (0 - intVal.magnitude as i64) if intVal.negative else intVal.magnitude as i64;
1215 1215
        irTyp = ilType(self, typ);
1216 1216
    }
1217 1217
    return il::DataItem::Val { typ: irTyp, val: constToScalar(val) };
1218 1218
}
1219 1219
1220 -
/// Lower a const or static declaration to the data section.
1220 +
/// Lower a constant or static declaration to the data section.
1221 1221
fn lowerDataDecl(
1222 1222
    self: *mut Lowerer,
1223 1223
    node: *ast::Node,
1224 1224
    value: *ast::Node,
1225 1225
    readOnly: bool
1687 1687
        }
1688 1688
    }
1689 1689
    return nil;
1690 1690
}
1691 1691
1692 -
/// Find existing const data entry with matching content.
1692 +
/// Find existing constant data entry with matching content.
1693 1693
/// Handles both string data and slice data.
1694 1694
fn findConstData(self: *Lowerer, values: *[il::DataValue], alignment: u32) -> ?*[u8] {
1695 1695
    // Fast path for strings.
1696 1696
    if values.len == 1 and alignment == 1 {
1697 1697
        if let case il::DataItem::Str(s) = values[0].item {
lib/std/lang/module.rad +5 -5
12 12
use std::lang::alloc;
13 13
use std::lang::ast;
14 14
use std::lang::strings;
15 15
16 16
/// Maximum number of modules tracked in a single compilation graph.
17 -
export const MAX_MODULES: u32 = 128;
17 +
export constant MAX_MODULES: u32 = 128;
18 18
/// Maximum number of characters for a module path.
19 -
const MAX_PATH_LEN: u32 = 256;
19 +
constant MAX_PATH_LEN: u32 = 256;
20 20
/// Maximum number of components that make up a logical module path.
21 -
const MAX_MODULE_PATH_DEPTH: u32 = 16;
21 +
constant MAX_MODULE_PATH_DEPTH: u32 = 16;
22 22
/// Filesystem separator used when constructing child paths.
23 -
const PATH_SEP: u8 = '/';
23 +
constant PATH_SEP: u8 = '/';
24 24
/// Source file extension handled by the loader.
25 -
const SOURCE_EXT: *[u8] = ".rad";
25 +
constant SOURCE_EXT: *[u8] = ".rad";
26 26
27 27
/// Lifecycle state for modules in the dependency graph.
28 28
export union ModuleState {
29 29
    /// Slot unused or yet to be initialized.
30 30
    Vacant,
lib/std/lang/package.rad +1 -1
4 4
use std::lang::ast;
5 5
use std::lang::module;
6 6
use std::lang::strings;
7 7
8 8
/// Maximum number of packages processed in a single invocation.
9 -
export const MAX_PACKAGES: u32 = 4;
9 +
export constant MAX_PACKAGES: u32 = 4;
10 10
11 11
/// A compilation unit.
12 12
export record Package {
13 13
    /// Package identifier (index in the package array).
14 14
    id: u16,
lib/std/lang/parser.rad +9 -9
7 7
use std::lang::ast;
8 8
use std::lang::strings;
9 9
use std::lang::scanner;
10 10
11 11
/// Maximum `u32` value.
12 -
export const U32_MAX: u32 = 0xFFFFFFFF;
12 +
export constant U32_MAX: u32 = 0xFFFFFFFF;
13 13
/// Maximum representable `u64` value.
14 -
export const U64_MAX: u64 = 0xFFFFFFFFFFFFFFFF;
14 +
export constant U64_MAX: u64 = 0xFFFFFFFFFFFFFFFF;
15 15
/// Maximum number of fields in a record.
16 -
export const MAX_RECORD_FIELDS: u32 = 32;
16 +
export constant MAX_RECORD_FIELDS: u32 = 32;
17 17
18 18
/// Maximum number of parser errors before aborting.
19 -
const MAX_ERRORS: u32 = 8;
19 +
constant MAX_ERRORS: u32 = 8;
20 20
21 21
/// Parser error type.
22 22
export union ParseError {
23 23
    /// Encountered a token that was not expected in the current context.
24 24
    UnexpectedToken,
926 926
            p.current.kind == scanner::TokenKind::Fn or
927 927
            p.current.kind == scanner::TokenKind::Union or
928 928
            p.current.kind == scanner::TokenKind::Record or
929 929
            p.current.kind == scanner::TokenKind::Mod or
930 930
            p.current.kind == scanner::TokenKind::Static or
931 -
            p.current.kind == scanner::TokenKind::Const or
931 +
            p.current.kind == scanner::TokenKind::Constant or
932 932
            p.current.kind == scanner::TokenKind::Use or
933 933
            p.current.kind == scanner::TokenKind::Trait;
934 934
935 935
        if not allowed {
936 936
            throw failParsing(p, "attributes are not allowed in this context");
984 984
            if consume(p, scanner::TokenKind::Mut) {
985 985
                return try parseLet(p, true);
986 986
            }
987 987
            return try parseLet(p, false);
988 988
        }
989 -
        case scanner::TokenKind::Const => {
989 +
        case scanner::TokenKind::Constant => {
990 990
            return try parseConst(p, attrs);
991 991
        }
992 992
        case scanner::TokenKind::Static => {
993 993
            return try parseStatic(p, attrs);
994 994
        }
2119 2119
2120 2120
/// Parse a constant declaration.
2121 2121
fn parseConst(p: *mut Parser, attrs: ?ast::Attributes) -> *ast::Node
2122 2122
    throws (ParseError)
2123 2123
{
2124 -
    try expect(p, scanner::TokenKind::Const, "expected `const`");
2124 +
    try expect(p, scanner::TokenKind::Constant, "expected `constant`");
2125 2125
2126 -
    let ident = try parseIdent(p, "expected identifier in const declaration");
2126 +
    let ident = try parseIdent(p, "expected identifier in constant declaration");
2127 2127
    try expect(p, scanner::TokenKind::Colon, "expected `:` after identifier");
2128 2128
2129 2129
    let type = try parseType(p);
2130 -
    try expect(p, scanner::TokenKind::Equal, "expected `=` in const declaration");
2130 +
    try expect(p, scanner::TokenKind::Equal, "expected `=` in constant declaration");
2131 2131
2132 2132
    let value = try parseExpr(p);
2133 2133
2134 2134
    return node(p, ast::NodeValue::ConstDecl(
2135 2135
        ast::ConstDecl { ident, type, value, attrs }
lib/std/lang/parser/tests.rad +3 -3
5 5
use std::lang::ast;
6 6
use std::lang::scanner;
7 7
use std::lang::strings;
8 8
9 9
/// Unified arena size.
10 -
const ARENA_SIZE: u32 = 2097152;
10 +
constant ARENA_SIZE: u32 = 2097152;
11 11
/// Unified arena storage for all AST allocations.
12 12
static ARENA_STORAGE: [u8; ARENA_SIZE] = undefined;
13 13
/// String pool.
14 14
static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
15 15
746 746
    try expectType(type, ast::TypeSig::Integer {
747 747
        width: 4, sign: ast::Signedness::Signed
748 748
    });
749 749
}
750 750
751 -
/// Test parsing a `const` declaration.
751 +
/// Test parsing a `constant` declaration.
752 752
@test fn testParseConst() throws (testing::TestError) {
753 -
    let node = try! parseStmtStr("const ANSWER: i32 = 42;");
753 +
    let node = try! parseStmtStr("constant ANSWER: i32 = 42;");
754 754
    let case ast::NodeValue::ConstDecl(decl) = node.value
755 755
        else throw testing::TestError::Failed;
756 756
757 757
    try expectIdent(decl.ident, "ANSWER");
758 758
    try expectType(decl.type, ast::TypeSig::Integer {
lib/std/lang/resolver.rad +26 -26
19 19
use std::lang::ast;
20 20
use std::lang::parser;
21 21
use std::lang::module;
22 22
23 23
/// Maximum number of diagnostics recorded.
24 -
export const MAX_ERRORS: u32 = 64;
24 +
export constant MAX_ERRORS: u32 = 64;
25 25
26 26
/// Synthetic function name used when wrapping a bare expression for analysis.
27 -
export const ANALYZE_EXPR_FN_NAME: *[u8] = "__expr__";
27 +
export constant ANALYZE_EXPR_FN_NAME: *[u8] = "__expr__";
28 28
/// Synthetic function name used when wrapping a block for analysis.
29 -
export const ANALYZE_BLOCK_FN_NAME: *[u8] = "__block__";
29 +
export constant ANALYZE_BLOCK_FN_NAME: *[u8] = "__block__";
30 30
31 31
/// Maximum number of symbols stored within a module scope.
32 -
export const MAX_MODULE_SYMBOLS: u32 = 512;
32 +
export constant MAX_MODULE_SYMBOLS: u32 = 512;
33 33
/// Maximum number of symbols stored within a local scope.
34 -
export const MAX_LOCAL_SYMBOLS: u32 = 32;
34 +
export constant MAX_LOCAL_SYMBOLS: u32 = 32;
35 35
/// Maximum function parameters.
36 -
export const MAX_FN_PARAMS: u32 = 8;
36 +
export constant MAX_FN_PARAMS: u32 = 8;
37 37
/// Maximum function thrown types.
38 -
export const MAX_FN_THROWS: u32 = 8;
38 +
export constant MAX_FN_THROWS: u32 = 8;
39 39
/// Maximum number of variants in a union.
40 40
/// Nb. This should not be raised above `255`,
41 41
/// as tags are stored using 8-bits only.
42 -
export const MAX_UNION_VARIANTS: u32 = 128;
42 +
export constant MAX_UNION_VARIANTS: u32 = 128;
43 43
/// Maximum nesting of loops.
44 -
export const MAX_LOOP_DEPTH: u32 = 16;
44 +
export constant MAX_LOOP_DEPTH: u32 = 16;
45 45
/// Maximum trait instances.
46 -
export const MAX_INSTANCES: u32 = 128;
46 +
export constant MAX_INSTANCES: u32 = 128;
47 47
/// Maximum standalone methods (across all types).
48 -
export const MAX_METHODS: u32 = 256;
48 +
export constant MAX_METHODS: u32 = 256;
49 49
50 50
/// Trait definition stored in the resolver.
51 51
export record TraitType {
52 52
    /// Trait name.
53 53
    name: *[u8],
98 98
    /// Symbol for the method.
99 99
    symbol: *mut Symbol,
100 100
}
101 101
102 102
/// Identifier for the synthetic `len` field.
103 -
export const LEN_FIELD: *[u8] = "len";
103 +
export constant LEN_FIELD: *[u8] = "len";
104 104
/// Identifier for the synthetic `ptr` field.
105 -
export const PTR_FIELD: *[u8] = "ptr";
105 +
export constant PTR_FIELD: *[u8] = "ptr";
106 106
/// Identifier for the synthetic `cap` field.
107 -
export const CAP_FIELD: *[u8] = "cap";
107 +
export constant CAP_FIELD: *[u8] = "cap";
108 108
109 109
/// Maximum `u16` value.
110 -
const U16_MAX: u16 = 0xFFFF;
110 +
constant U16_MAX: u16 = 0xFFFF;
111 111
/// Maximum `u8` value.
112 -
const U8_MAX: u16 = 0xFF;
112 +
constant U8_MAX: u16 = 0xFF;
113 113
114 114
/// Minimum `i8` value.
115 -
const I8_MIN: i32 = -128;
115 +
constant I8_MIN: i32 = -128;
116 116
/// Maximum `i8` value.
117 -
const I8_MAX: i32 = 127;
117 +
constant I8_MAX: i32 = 127;
118 118
/// Minimum `i16` value.
119 -
const I16_MIN: i32 = -32768;
119 +
constant I16_MIN: i32 = -32768;
120 120
/// Maximum `i16` value.
121 -
const I16_MAX: i32 = 32767;
121 +
constant I16_MAX: i32 = 32767;
122 122
123 123
/// Minimum `i32` value.
124 -
const I32_MIN: i32 = -2147483648;
124 +
constant I32_MIN: i32 = -2147483648;
125 125
/// Maximum `i32` value.
126 -
const I32_MAX: i32 = 2147483647;
126 +
constant I32_MAX: i32 = 2147483647;
127 127
/// Minimum `i64` value: -(2^63).
128 -
const I64_MIN: i64 = -9223372036854775808;
128 +
constant I64_MIN: i64 = -9223372036854775808;
129 129
/// Maximum `i64` value: 2^63 - 1.
130 -
const I64_MAX: i64 = 9223372036854775807;
130 +
constant I64_MAX: i64 = 9223372036854775807;
131 131
132 132
/// Size of a pointer in bytes.
133 -
export const PTR_SIZE: u32 = 8;
133 +
export constant PTR_SIZE: u32 = 8;
134 134
135 135
/// Information about a record or tuple field.
136 136
export record RecordField {
137 137
    /// Field name, `nil` for positional fields.
138 138
    name: ?*[u8],
2975 2975
            actual: args.len,
2976 2976
        }));
2977 2977
    }
2978 2978
}
2979 2979
2980 -
/// Helper for analyzing `const` and `static` declarations.
2980 +
/// Helper for analyzing `constant` and `static` declarations.
2981 2981
fn resolveConstOrStatic(
2982 2982
    self: *mut Resolver,
2983 2983
    node: *ast::Node,
2984 2984
    ident: *ast::Node,
2985 2985
    typeNode: *ast::Node,
lib/std/lang/resolver/tests.rad +52 -52
8 8
use std::lang::scanner;
9 9
use std::lang::module;
10 10
use std::lang::strings;
11 11
12 12
/// Synthetic file path used for resolver tests.
13 -
const MODULE_PATH: *[u8] = "/dev/test.rad";
13 +
constant MODULE_PATH: *[u8] = "/dev/test.rad";
14 14
15 15
static AST_ARENA: [u8; 2097152] = undefined;
16 16
static ARENA_STORAGE: [u8; 2097152] = undefined;
17 17
static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined;
18 18
static ERROR_STORAGE: [super::Error; 16] = undefined;
22 22
static MODULE_ARENA_STORAGE: [u8; 4096] = undefined;
23 23
static MODULE_ARENA: ast::NodeArena = undefined;
24 24
static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
25 25
26 26
/// String literals used in tests.
27 -
const LITERALS: [*[u8]; 15] = [
27 +
constant LITERALS: [*[u8]; 15] = [
28 28
    "Ok", "Error", "R", "S",
29 29
    "f", "Status", "Pending",
30 30
    "Some", "None", "First",
31 31
    "Second", "Opt", "x",
32 32
    "value", "idx"
545 545
    try expectErrorKind(&result, super::ErrorKind::DuplicateBinding("x"));
546 546
}
547 547
548 548
@test fn testResolveConstLiteralValue() throws (testing::TestError) {
549 549
    let mut a = testResolver();
550 -
    let program = "const ANSWER: i32 = 42;";
550 +
    let program = "constant ANSWER: i32 = 42;";
551 551
    let result = try resolveProgramStr(&mut a, program);
552 552
    try expectNoErrors(&result);
553 553
554 554
    let constNode = try getBlockStmt(result.root, 0);
555 555
    let sym = super::symbolFor(&a, constNode)
559 559
    try testing::expect(constType == super::Type::I32);
560 560
}
561 561
562 562
@test fn testResolveConstRequiresConstantExpr() throws (testing::TestError) {
563 563
    let mut a = testResolver();
564 -
    let program = "fn value() -> i32 { return 1 } fn main() { const ANSWER: i32 = value(); }";
564 +
    let program = "fn value() -> i32 { return 1 } fn main() { constant ANSWER: i32 = value(); }";
565 565
    let result = try resolveProgramStr(&mut a, program);
566 566
    let err = try expectErrorKind(&result, super::ErrorKind::ConstExprRequired);
567 567
568 568
    let errNode = err.node
569 569
        else throw testing::TestError::Failed;
979 979
    }
980 980
}
981 981
982 982
@test fn testResolveArrayLenConstValue() throws (testing::TestError) {
983 983
    let mut a = testResolver();
984 -
    let program = "let xs: [i32; 3] = [1, 2, 3]; const LEN: u32 = xs.len;";
984 +
    let program = "let xs: [i32; 3] = [1, 2, 3]; constant LEN: u32 = xs.len;";
985 985
    let result = try resolveBlockStr(&mut a, program);
986 986
    try expectNoErrors(&result);
987 987
988 988
    let constStmt = try getBlockStmt(result.root, 1);
989 989
    let case ast::NodeValue::ConstDecl(decl) = constStmt.value
1791 1791
    try expectAnalyzeOk("let x: u16 = 0xFFFF;");
1792 1792
    try expectAnalyzeOk("let x: i32 = 2147483647;");
1793 1793
    try expectAnalyzeOk("let x: i32 = -2147483648;");
1794 1794
    try expectAnalyzeOk("let x: u32 = 0xFFFFFFFF;");
1795 1795
1796 -
    try expectAnalyzeOk("const LIMIT: u8 = 0xFF;");
1796 +
    try expectAnalyzeOk("constant LIMIT: u8 = 0xFF;");
1797 1797
1798 1798
    try expectIntMismatch("let x: i8 = 128;", super::Type::I8);
1799 1799
    try expectIntMismatch("let x: i8 = -129;", super::Type::I8);
1800 1800
    try expectIntMismatch("let x: i8 = 0x80;", super::Type::I8);
1801 1801
    try expectIntMismatch("let x: i8 = 0b10000000;", super::Type::I8);
1809 1809
    try expectIntMismatch("let x: i32 = 2147483648;", super::Type::I32);
1810 1810
    try expectIntMismatch("let x: i32 = -2147483649;", super::Type::I32);
1811 1811
    try expectIntMismatch("let x: i32 = 0xFFFFFFFF;", super::Type::I32);
1812 1812
    try expectIntMismatch("let x: u32 = -1;", super::Type::U32);
1813 1813
    try expectIntMismatch("let x: u32 = 0x100000000;", super::Type::U32);
1814 -
    try expectIntMismatch("const LIMIT: u8 = 512;", super::Type::U8);
1815 -
    try expectIntMismatch("const LIMIT: u8 = -5;", super::Type::U8);
1814 +
    try expectIntMismatch("constant LIMIT: u8 = 512;", super::Type::U8);
1815 +
    try expectIntMismatch("constant LIMIT: u8 = -5;", super::Type::U8);
1816 1816
}
1817 1817
1818 1818
@test fn testNilCoercions() throws (testing::TestError) {
1819 1819
    {
1820 1820
        let mut a = testResolver();
1936 1936
}
1937 1937
1938 1938
/// Test that arrays of anonymous records with labeled fields are allowed.
1939 1939
@test fn testResolveAnonRecordArray() throws (testing::TestError) {
1940 1940
    let mut a = testResolver();
1941 -
    let program = "record Pt { x: i32, y: i32 } const ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
1941 +
    let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4 }];";
1942 1942
    let result = try resolveProgramStr(&mut a, program);
1943 1943
    try expectNoErrors(&result);
1944 1944
}
1945 1945
1946 1946
/// Test that arrays of anonymous records with extra fields cause count mismatch.
1947 1947
@test fn testResolveAnonRecordArrayMismatch() throws (testing::TestError) {
1948 1948
    let mut a = testResolver();
1949 -
    let program = "record Pt { x: i32, y: i32 } const ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
1949 +
    let program = "record Pt { x: i32, y: i32 } constant ARR: [Pt; 2] = [{ x: 1, y: 2 }, { x: 3, y: 4, z: 5 }];";
1950 1950
    let result = try resolveProgramStr(&mut a, program);
1951 1951
    let err = try expectError(&result);
1952 1952
    let case super::ErrorKind::RecordFieldCountMismatch(_) = err.kind
1953 1953
        else throw testing::TestError::Failed;
1954 1954
}
3090 3090
    let mut a = testResolver();
3091 3091
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3092 3092
3093 3093
    // Register root with constants module.
3094 3094
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
3095 -
    let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export const MAX_SIZE: i32 = 100;", &mut arena);
3095 +
    let constantsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant MAX_SIZE: i32 = 100;", &mut arena);
3096 3096
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() -> i32 { return consts::MAX_SIZE; }", &mut arena);
3097 3097
3098 3098
    // Resolve should succeed: constants can be accessed.
3099 3099
    let result = try resolveModuleTree(&mut a, rootId);
3100 3100
    try expectNoErrors(&result);
3630 3630
3631 3631
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "mod a; export mod b;", &mut arena);
3632 3632
    let aId = try registerModule(&mut MODULE_GRAPH, rootId, "a", "use root::b; fn main() -> i32 { return b::helper() + b::MAX; }", &mut arena);
3633 3633
    let bId = try registerModule(&mut MODULE_GRAPH, rootId, "b", "mod c; export use c::*;", &mut arena);
3634 3634
    let cId = try registerModule(&mut MODULE_GRAPH, bId, "c", "mod d; export use d::*; export fn helper() -> i32 { return 42; }", &mut arena);
3635 -
    let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "export const MAX: i32 = 100;", &mut arena);
3635 +
    let dId = try registerModule(&mut MODULE_GRAPH, cId, "d", "export constant MAX: i32 = 100;", &mut arena);
3636 3636
3637 3637
    let result = try resolveModuleTree(&mut a, rootId);
3638 3638
    try expectNoErrors(&result);
3639 3639
}
3640 3640
3665 3665
}
3666 3666
3667 3667
/// Test that a constant array can use another constant as its length.
3668 3668
@test fn testConstArrayWithConstLength() throws (testing::TestError) {
3669 3669
    let mut a = testResolver();
3670 -
    let program = "const LEN: u32 = 3; const ARR: [i32; LEN] = [1, 2, 3];";
3670 +
    let program = "constant LEN: u32 = 3; constant ARR: [i32; LEN] = [1, 2, 3];";
3671 3671
    let result = try resolveProgramStr(&mut a, program);
3672 3672
    try expectNoErrors(&result);
3673 3673
3674 3674
    // Verify the array constant has the correct type with length 3.
3675 3675
    let arrStmt = try getBlockStmt(result.root, 1);
3681 3681
}
3682 3682
3683 3683
/// Test that a record field can use a constant as its array length.
3684 3684
@test fn testRecordFieldWithConstArrayLength() throws (testing::TestError) {
3685 3685
    let mut a = testResolver();
3686 -
    let program = "const SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
3686 +
    let program = "constant SIZE: u32 = 4; record Buffer { data: [i32; SIZE], }";
3687 3687
    let result = try resolveProgramStr(&mut a, program);
3688 3688
    try expectNoErrors(&result);
3689 3689
}
3690 3690
3691 3691
/// Test that a constant can have a record literal value (lazy record body resolution).
3692 3692
@test fn testConstWithRecordLiteral() throws (testing::TestError) {
3693 3693
    let mut a = testResolver();
3694 -
    let program = "record Point { x: i32, y: i32 } const ORIGIN: Point = Point { x: 0, y: 0 };";
3694 +
    let program = "record Point { x: i32, y: i32 } constant ORIGIN: Point = Point { x: 0, y: 0 };";
3695 3695
    let result = try resolveProgramStr(&mut a, program);
3696 3696
    try expectNoErrors(&result);
3697 3697
}
3698 3698
3699 3699
/// Test that a constant can have a union variant value (lazy union body resolution).
3700 3700
@test fn testConstWithUnionVariant() throws (testing::TestError) {
3701 3701
    let mut a = testResolver();
3702 -
    let program = "union Color { Red, Green, Blue } const DEFAULT: Color = Color::Red;";
3702 +
    let program = "union Color { Red, Green, Blue } constant DEFAULT: Color = Color::Red;";
3703 3703
    let result = try resolveProgramStr(&mut a, program);
3704 3704
    try expectNoErrors(&result);
3705 3705
}
3706 3706
3707 3707
/// Test that record field types can reference imported types.
3727 3727
@test fn testImportedConstantInArraySize() throws (testing::TestError) {
3728 3728
    let mut a = testResolver();
3729 3729
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
3730 3730
3731 3731
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
3732 -
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export const SIZE: u32 = 8;", &mut arena);
3732 +
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant SIZE: u32 = 8;", &mut arena);
3733 3733
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = undefined;", &mut arena);
3734 3734
3735 3735
    let result = try resolveModuleTree(&mut a, rootId);
3736 3736
    try expectNoErrors(&result);
3737 3737
}
4931 4931
    try testing::expect(intVal.magnitude == expected);
4932 4932
}
4933 4933
4934 4934
/// Test arithmetic constant folding: add, sub, mul, div.
4935 4935
@test fn testConstExprArithmetic() throws (testing::TestError) {
4936 -
    try expectConstFold("const A: i32 = 10; const B: i32 = 20; const C: i32 = A + B;", 2, 30);
4937 -
    try expectConstFold("const A: i32 = 50; const B: i32 = 20; const C: i32 = A - B;", 2, 30);
4938 -
    try expectConstFold("const A: i32 = 6; const B: i32 = 7; const C: i32 = A * B;", 2, 42);
4939 -
    try expectConstFold("const A: i32 = 100; const B: i32 = 5; const C: i32 = A / B;", 2, 20);
4936 +
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B;", 2, 30);
4937 +
    try expectConstFold("constant A: i32 = 50; constant B: i32 = 20; constant C: i32 = A - B;", 2, 30);
4938 +
    try expectConstFold("constant A: i32 = 6; constant B: i32 = 7; constant C: i32 = A * B;", 2, 42);
4939 +
    try expectConstFold("constant A: i32 = 100; constant B: i32 = 5; constant C: i32 = A / B;", 2, 20);
4940 4940
}
4941 4941
4942 4942
/// Test bitwise constant folding: and, or, xor.
4943 4943
@test fn testConstExprBitwise() throws (testing::TestError) {
4944 -
    try expectConstFold("const A: i32 = 0xFF; const B: i32 = 0x0F; const C: i32 = A & B;", 2, 0x0F);
4945 -
    try expectConstFold("const A: i32 = 0xF0; const B: i32 = 0x0F; const C: i32 = A | B;", 2, 0xFF);
4946 -
    try expectConstFold("const A: i32 = 0xFF; const B: i32 = 0x0F; const C: i32 = A ^ B;", 2, 0xF0);
4944 +
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A & B;", 2, 0x0F);
4945 +
    try expectConstFold("constant A: i32 = 0xF0; constant B: i32 = 0x0F; constant C: i32 = A | B;", 2, 0xFF);
4946 +
    try expectConstFold("constant A: i32 = 0xFF; constant B: i32 = 0x0F; constant C: i32 = A ^ B;", 2, 0xF0);
4947 4947
}
4948 4948
4949 4949
/// Test shift constant folding.
4950 4950
@test fn testConstExprShift() throws (testing::TestError) {
4951 -
    try expectConstFold("const A: i32 = 1; const B: i32 = A << 4;", 1, 16);
4952 -
    try expectConstFold("const A: i32 = 32; const B: i32 = A >> 2;", 1, 8);
4951 +
    try expectConstFold("constant A: i32 = 1; constant B: i32 = A << 4;", 1, 16);
4952 +
    try expectConstFold("constant A: i32 = 32; constant B: i32 = A >> 2;", 1, 8);
4953 4953
}
4954 4954
4955 4955
/// Test chained constant expressions (C depends on A + B, D depends on C).
4956 4956
@test fn testConstExprChained() throws (testing::TestError) {
4957 -
    try expectConstFold("const A: i32 = 10; const B: i32 = 20; const C: i32 = A + B; const D: i32 = C * 2;", 3, 60);
4957 +
    try expectConstFold("constant A: i32 = 10; constant B: i32 = 20; constant C: i32 = A + B; constant D: i32 = C * 2;", 3, 60);
4958 4958
}
4959 4959
4960 4960
/// Test constant expression used as array size.
4961 4961
@test fn testConstExprAsArraySize() throws (testing::TestError) {
4962 4962
    let mut a = testResolver();
4963 -
    let program = "const A: u32 = 2; const B: u32 = 3; const SIZE: u32 = A + B; const ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
4963 +
    let program = "constant A: u32 = 2; constant B: u32 = 3; constant SIZE: u32 = A + B; constant ARR: [i32; SIZE] = [1, 2, 3, 4, 5];";
4964 4964
    let result = try resolveProgramStr(&mut a, program);
4965 4965
    try expectNoErrors(&result);
4966 4966
4967 4967
    let arrStmt = try getBlockStmt(result.root, 3);
4968 4968
    let sym = super::symbolFor(&a, arrStmt)
4977 4977
@test fn testCrossModuleConstExpr() throws (testing::TestError) {
4978 4978
    let mut a = testResolver();
4979 4979
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4980 4980
4981 4981
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4982 -
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export const BASE: i32 = 100;", &mut arena);
4983 -
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; const DERIVED: i32 = consts::BASE + 50;", &mut arena);
4982 +
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant BASE: i32 = 100;", &mut arena);
4983 +
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant DERIVED: i32 = consts::BASE + 50;", &mut arena);
4984 4984
4985 4985
    let result = try resolveModuleTree(&mut a, rootId);
4986 4986
    try expectNoErrors(&result);
4987 4987
}
4988 4988
4990 4990
@test fn testCrossModuleConstExprArraySize() throws (testing::TestError) {
4991 4991
    let mut a = testResolver();
4992 4992
    let mut arena = ast::nodeArena(&mut AST_ARENA[..]);
4993 4993
4994 4994
    let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena);
4995 -
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export const WIDTH: u32 = 8; export const HEIGHT: u32 = 4;", &mut arena);
4996 -
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; const TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = undefined;", &mut arena);
4995 +
    let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant WIDTH: u32 = 8; export constant HEIGHT: u32 = 4;", &mut arena);
4996 +
    let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = undefined;", &mut arena);
4997 4997
4998 4998
    let result = try resolveModuleTree(&mut a, rootId);
4999 4999
    try expectNoErrors(&result);
5000 5000
}
5001 5001
5002 -
/// Test that non-constant expressions in const declarations are still rejected.
5002 +
/// Test that non-constant expressions in constant declarations are still rejected.
5003 5003
@test fn testConstExprNonConstRejected() throws (testing::TestError) {
5004 5004
    let mut a = testResolver();
5005 -
    let program = "fn value() -> i32 { return 1; } const BAD: i32 = value() + 1;";
5005 +
    let program = "fn value() -> i32 { return 1; } constant BAD: i32 = value() + 1;";
5006 5006
    let result = try resolveProgramStr(&mut a, program);
5007 5007
    let err = try expectError(&result);
5008 5008
    let case super::ErrorKind::ConstExprRequired = err.kind
5009 5009
        else throw testing::TestError::Failed;
5010 5010
}
5011 5011
5012 5012
/// Test unary negation in constant expressions.
5013 5013
@test fn testConstExprUnaryNeg() throws (testing::TestError) {
5014 5014
    let mut a = testResolver();
5015 -
    let program = "const A: i32 = 10; const B: i32 = -A;";
5015 +
    let program = "constant A: i32 = 10; constant B: i32 = -A;";
5016 5016
    let result = try resolveProgramStr(&mut a, program);
5017 5017
    try expectNoErrors(&result);
5018 5018
}
5019 5019
5020 5020
/// Test unary not in constant expressions.
5021 5021
@test fn testConstExprUnaryNot() throws (testing::TestError) {
5022 5022
    let mut a = testResolver();
5023 -
    let program = "const A: bool = true; const B: bool = not A;";
5023 +
    let program = "constant A: bool = true; constant B: bool = not A;";
5024 5024
    let result = try resolveProgramStr(&mut a, program);
5025 5025
    try expectNoErrors(&result);
5026 5026
}
5027 5027
5028 5028
/// Test `as` casts in constant expressions: widening, narrowing, sign changes, chaining.
5029 5029
@test fn testConstExprCast() throws (testing::TestError) {
5030 -
    try expectConstFold("const A: i32 = 42; const B: u64 = A as u64;", 1, 42);
5031 -
    try expectConstFold("const A: u64 = 10; const B: u8 = A as u8;", 1, 10);
5032 -
    try expectConstFold("const A: i32 = 7; const B: u32 = A as u32;", 1, 7);
5033 -
    try expectConstFold("const A: u32 = 100; const B: i32 = A as i32;", 1, 100);
5034 -
    try expectConstFold("const A: u8 = 5; const B: u64 = (A as u32) as u64;", 1, 5);
5035 -
    try expectConstFold("const A: u8 = 3; const B: u8 = 4; const C: i32 = (A as i32) + (B as i32);", 2, 7);
5030 +
    try expectConstFold("constant A: i32 = 42; constant B: u64 = A as u64;", 1, 42);
5031 +
    try expectConstFold("constant A: u64 = 10; constant B: u8 = A as u8;", 1, 10);
5032 +
    try expectConstFold("constant A: i32 = 7; constant B: u32 = A as u32;", 1, 7);
5033 +
    try expectConstFold("constant A: u32 = 100; constant B: i32 = A as i32;", 1, 100);
5034 +
    try expectConstFold("constant A: u8 = 5; constant B: u64 = (A as u32) as u64;", 1, 5);
5035 +
    try expectConstFold("constant A: u8 = 3; constant B: u8 = 4; constant C: i32 = (A as i32) + (B as i32);", 2, 7);
5036 5036
    // Cast of unsuffixed literal arithmetic.
5037 -
    try expectConstFold("const A: u32 = (3 + 4) as u32;", 0, 7);
5038 -
    try expectConstFold("const A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
5039 -
    try expectConstFold("const A: u32 = (3 + 4) as u32 + 1;", 0, 8);
5040 -
    try expectConstFold("const A: i32 = (2 as i32) * (3 + 4);", 0, 14);
5037 +
    try expectConstFold("constant A: u32 = (3 + 4) as u32;", 0, 7);
5038 +
    try expectConstFold("constant A: u32 = ((3 + 4) as u64) as u32;", 0, 7);
5039 +
    try expectConstFold("constant A: u32 = (3 + 4) as u32 + 1;", 0, 8);
5040 +
    try expectConstFold("constant A: i32 = (2 as i32) * (3 + 4);", 0, 14);
5041 5041
}
5042 5042
5043 5043
/// Test `as` cast in constant expressions used as array size.
5044 5044
@test fn testConstExprCastAsArraySize() throws (testing::TestError) {
5045 5045
    let mut a = testResolver();
5046 -
    let program = "const LEN: u64 = 4; const SIZE: u32 = LEN as u32; const ARR: [i32; SIZE] = [1, 2, 3, 4];";
5046 +
    let program = "constant LEN: u64 = 4; constant SIZE: u32 = LEN as u32; constant ARR: [i32; SIZE] = [1, 2, 3, 4];";
5047 5047
    let result = try resolveProgramStr(&mut a, program);
5048 5048
    try expectNoErrors(&result);
5049 5049
5050 5050
    let arrStmt = try getBlockStmt(result.root, 2);
5051 5051
    let sym = super::symbolFor(&a, arrStmt)
5055 5055
    try testing::expect(arrType.length == 4);
5056 5056
}
5057 5057
5058 5058
/// Test unsuffixed integer literals in constant expressions.
5059 5059
@test fn testConstExprUnsuffixedLiterals() throws (testing::TestError) {
5060 -
    try expectConstFold("const A: u32 = 4 * 4;", 0, 16);
5061 -
    try expectConstFold("const B: u32 = 10; const C: u32 = B * 2;", 1, 20);
5062 -
    try expectConstFold("const D: u32 = 3 + 7;", 0, 10);
5063 -
    try expectConstFold("const E: u32 = 2 * 3 + 4;", 0, 10);
5064 -
    try expectConstFold("const F: i32 = -(3 + 4);", 0, 7);
5060 +
    try expectConstFold("constant A: u32 = 4 * 4;", 0, 16);
5061 +
    try expectConstFold("constant B: u32 = 10; constant C: u32 = B * 2;", 1, 20);
5062 +
    try expectConstFold("constant D: u32 = 3 + 7;", 0, 10);
5063 +
    try expectConstFold("constant E: u32 = 2 * 3 + 4;", 0, 10);
5064 +
    try expectConstFold("constant F: i32 = -(3 + 4);", 0, 7);
5065 5065
}
lib/std/lang/scanner.rad +3 -4
89 89
    Continue, While, For, In,
90 90
    Loop, Match, Case, Try, Catch,
91 91
    Throw, Throws, Panic, Assert,
92 92
93 93
    // Variable binding tokens.
94 -
    Let, Mut, Const, Align,
94 +
    Let, Mut, Constant, Align,
95 95
96 96
    // Module-related tokens.
97 97
    Mod, Use, Super,
98 98
99 99
    // Type or function attributes.
114 114
    /// Corresponding token.
115 115
    tok: TokenKind,
116 116
}
117 117
118 118
/// Sorted keyword table for binary search.
119 -
const KEYWORDS: [Keyword; 51] = [
119 +
constant KEYWORDS: [Keyword; 50] = [
120 120
    { name: "align", tok: TokenKind::Align },
121 121
    { name: "and", tok: TokenKind::And },
122 122
    { name: "as", tok: TokenKind::As },
123 123
    { name: "assert", tok: TokenKind::Assert },
124 124
    { name: "bool", tok: TokenKind::Bool },
125 125
    { name: "break", tok: TokenKind::Break },
126 126
    { name: "case", tok: TokenKind::Case },
127 127
    { name: "catch", tok: TokenKind::Catch },
128 -
    { name: "const", tok: TokenKind::Const },
129 -
    { name: "constant", tok: TokenKind::Const },
128 +
    { name: "constant", tok: TokenKind::Constant },
130 129
    { name: "continue", tok: TokenKind::Continue },
131 130
    { name: "else", tok: TokenKind::Else },
132 131
    { name: "export", tok: TokenKind::Export },
133 132
    { name: "false", tok: TokenKind::False },
134 133
    { name: "fn", tok: TokenKind::Fn },
lib/std/lang/strings.rad +1 -1
8 8
9 9
use std::mem;
10 10
use std::collections::dict;
11 11
12 12
/// Table size.
13 -
const TABLE_SIZE: u32 = 8192;
13 +
constant TABLE_SIZE: u32 = 8192;
14 14
15 15
/// String interning pool using open-addressed hash table.
16 16
///
17 17
/// Each unique string content is stored only once, allowing pointer equality
18 18
/// to be used instead of content comparison for symbol lookups and module names.
lib/std/sys/unix.rad +9 -9
3 3
4 4
/// File access modes.
5 5
export record OpenFlags(i64);
6 6
7 7
/// Open file for reading only.
8 -
export const O_RDONLY: OpenFlags = OpenFlags(0);
8 +
export constant O_RDONLY: OpenFlags = OpenFlags(0);
9 9
10 10
/// Open file for writing only.
11 -
export const O_WRONLY: OpenFlags = OpenFlags(1);
11 +
export constant O_WRONLY: OpenFlags = OpenFlags(1);
12 12
13 13
/// Open file for reading and writing.
14 -
export const O_RDWR: OpenFlags = OpenFlags(2);
14 +
export constant O_RDWR: OpenFlags = OpenFlags(2);
15 15
16 16
/// Create file if it doesn't exist.
17 -
export const O_CREAT: OpenFlags = OpenFlags(64);
17 +
export constant O_CREAT: OpenFlags = OpenFlags(64);
18 18
19 19
/// Truncate file to zero length.
20 -
export const O_TRUNC: OpenFlags = OpenFlags(512);
20 +
export constant O_TRUNC: OpenFlags = OpenFlags(512);
21 21
22 22
/// Standard file descriptor for stdin.
23 -
export const STDIN: i64 = 0;
23 +
export constant STDIN: i64 = 0;
24 24
25 25
/// Standard file descriptor for stdout.
26 -
export const STDOUT: i64 = 1;
26 +
export constant STDOUT: i64 = 1;
27 27
28 28
/// Standard file descriptor for stderr.
29 -
export const STDERR: i64 = 2;
29 +
export constant STDERR: i64 = 2;
30 30
31 31
/// Special value representing current working directory for `openat()`.
32 -
const AT_FDCWD: i64 = -100;
32 +
constant AT_FDCWD: i64 = -100;
33 33
34 34
/// Opens a file at the given path and returns a file descriptor.
35 35
/// Returns a negative value on error.
36 36
export fn open(path: *[u8], flags: OpenFlags) -> i64 {
37 37
    return intrinsics::ecall(56, AT_FDCWD, path.ptr as i64, *flags, 0);
test/runner.rad +7 -7
16 16
use std::lang::resolver;
17 17
use std::lang::strings;
18 18
use std::lang::lower;
19 19
20 20
/// Buffer size for reading source files (8 KB).
21 -
const SOURCE_BUF_SIZE: u32 = 8192;
21 +
constant SOURCE_BUF_SIZE: u32 = 8192;
22 22
/// Buffer size for reading expected IL files (32 KB).
23 -
const EXPECTED_BUF_SIZE: u32 = 32768;
23 +
constant EXPECTED_BUF_SIZE: u32 = 32768;
24 24
/// Buffer size for generated IL output (32 KB).
25 -
const OUTPUT_BUF_SIZE: u32 = 32768;
25 +
constant OUTPUT_BUF_SIZE: u32 = 32768;
26 26
/// Arena size for AST/IL allocations (512 KB).
27 -
const ARENA_SIZE: u32 = 524288;
27 +
constant ARENA_SIZE: u32 = 524288;
28 28
/// Maximum path length for expected IL file path.
29 -
const MAX_PATH_LEN: u32 = 256;
29 +
constant MAX_PATH_LEN: u32 = 256;
30 30
31 31
/// String pool.
32 32
static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
33 33
34 34
/// Maximum number of AST nodes per test file.
35 -
const MAX_NODE_DATA: u32 = 4096;
35 +
constant MAX_NODE_DATA: u32 = 4096;
36 36
/// Maximum number of resolver errors per test file.
37 -
const MAX_ERRORS: u32 = 16;
37 +
constant MAX_ERRORS: u32 = 16;
38 38
39 39
// Static storage for large buffers to avoid stack overflow.
40 40
// Tests run serially so sharing these is safe.
41 41
static SOURCE_BUF: [u8; SOURCE_BUF_SIZE] = undefined;
42 42
static EXPECTED_BUF: [u8; EXPECTED_BUF_SIZE] = undefined;
test/tests/const-expr-array-size.rad +3 -3
1 1
//! returns: 0
2 2
3 3
/// Test that constant expressions referencing other constants
4 4
/// can be used as array sizes.
5 5
6 -
const ROWS: u32 = 3;
7 -
const COLS: u32 = 4;
8 -
const TOTAL: u32 = ROWS * COLS;
6 +
constant ROWS: u32 = 3;
7 +
constant COLS: u32 = 4;
8 +
constant TOTAL: u32 = ROWS * COLS;
9 9
10 10
static DATA: [i32; TOTAL] = undefined;
11 11
12 12
@default fn main() -> i32 {
13 13
    // Verify the array has the expected length.
test/tests/const-expr-cast.rad +17 -17
1 1
//! returns: 0
2 2
3 3
/// Test that `as` casts work in constant expressions.
4 4
5 5
// Widening, narrowing, sign changes.
6 -
const A: i32 = 42;
7 -
const B: u64 = A as u64;
8 -
const C: u8 = 10;
9 -
const D: i32 = C as i32;
10 -
const SHIFTED: u64 = 4 as u64;
6 +
constant A: i32 = 42;
7 +
constant B: u64 = A as u64;
8 +
constant C: u8 = 10;
9 +
constant D: i32 = C as i32;
10 +
constant SHIFTED: u64 = 4 as u64;
11 11
12 12
// Chained casts.
13 -
const LEN: u32 = 8;
14 -
const LEN2: u32 = (LEN as u64) as u32;
13 +
constant LEN: u32 = 8;
14 +
constant LEN2: u32 = (LEN as u64) as u32;
15 15
static BUF: [u8; LEN2] = undefined;
16 16
17 17
// Cast of unsuffixed literal arithmetic.
18 -
const E: u32 = (3 + 4) as u32;
18 +
constant E: u32 = (3 + 4) as u32;
19 19
// Nested casts of literal arithmetic.
20 -
const F: u32 = ((3 + 4) as u64) as u32;
20 +
constant F: u32 = ((3 + 4) as u64) as u32;
21 21
// Cast + arithmetic.
22 -
const G: u32 = (3 + 4) as u32 + 1;
22 +
constant G: u32 = (3 + 4) as u32 + 1;
23 23
// Arithmetic with cast subexprs.
24 -
const H: i32 = (2 as i32) * (3 + 4);
24 +
constant H: i32 = (2 as i32) * (3 + 4);
25 25
26 26
// Cast in static data initializer.
27 -
const INIT_VAL: u8 = 0xFF;
28 -
const WIDE: u32 = INIT_VAL as u32;
27 +
constant INIT_VAL: u8 = 0xFF;
28 +
constant WIDE: u32 = INIT_VAL as u32;
29 29
30 -
// Typed const * typed const through cast.
31 -
const X: u8 = 3;
32 -
const Y: u8 = 4;
33 -
const Z: i32 = (X as i32) * (Y as i32);
30 +
// Typed constant * typed constant through cast.
31 +
constant X: u8 = 3;
32 +
constant Y: u8 = 4;
33 +
constant Z: i32 = (X as i32) * (Y as i32);
34 34
35 35
@default fn main() -> i32 {
36 36
    assert BUF.len == 8;
37 37
    assert WIDE == 255;
38 38
    assert Z == 12;
test/tests/const-expr-literal.rad +8 -8
1 1
//! returns: 0
2 2
3 -
/// Test that unsuffixed integer literals work in const expressions.
3 +
/// Test that unsuffixed integer literals work in constant expressions.
4 4
5 5
// Literal * literal.
6 -
const A: u32 = 4 * 4;
6 +
constant A: u32 = 4 * 4;
7 7
// Const * literal.
8 -
const B: u32 = 10;
9 -
const C: u32 = B * 2;
8 +
constant B: u32 = 10;
9 +
constant C: u32 = B * 2;
10 10
// Literal + literal.
11 -
const D: u32 = 3 + 7;
11 +
constant D: u32 = 3 + 7;
12 12
// Chained with literals.
13 -
const E: u32 = 2 * 3 + 4;
13 +
constant E: u32 = 2 * 3 + 4;
14 14
// Unary negation with literal.
15 -
const F: i32 = -5;
16 -
const G: i32 = F * 2;
15 +
constant F: i32 = -5;
16 +
constant G: i32 = F * 2;
17 17
18 18
static BUF: [u8; A] = undefined;
19 19
static BUF2: [u8; C] = undefined;
20 20
21 21
@default fn main() -> i32 {
test/tests/const-expr-refs.rad +12 -12
1 1
//! returns: 0
2 2
3 3
/// Test that constant expressions can reference other constants,
4 4
/// including arithmetic on constants.
5 5
6 -
const A: i32 = 10;
7 -
const B: i32 = 20;
8 -
const C: i32 = A + B;
9 -
const D: i32 = C * 2;
10 -
const E: i32 = D - A;
11 -
const F: i32 = E / 5;
12 -
const G: i32 = A % 3;
13 -
const H: i32 = A | B;
14 -
const I: i32 = A & B;
15 -
const J: i32 = A ^ B;
16 -
const K: i32 = A << 2;
17 -
const L: i32 = B >> 1;
6 +
constant A: i32 = 10;
7 +
constant B: i32 = 20;
8 +
constant C: i32 = A + B;
9 +
constant D: i32 = C * 2;
10 +
constant E: i32 = D - A;
11 +
constant F: i32 = E / 5;
12 +
constant G: i32 = A % 3;
13 +
constant H: i32 = A | B;
14 +
constant I: i32 = A & B;
15 +
constant J: i32 = A ^ B;
16 +
constant K: i32 = A << 2;
17 +
constant L: i32 = B >> 1;
18 18
19 19
@default fn main() -> i32 {
20 20
    if C != 30 { return 1; }
21 21
    if D != 60 { return 2; }
22 22
    if E != 50 { return 3; }
test/tests/const.array.copy.mutate.rad +1 -1
1 1
//! returns: 22
2 2
//! Test copying and mutating constant arrays.
3 3
4 -
const SEED: [i32; 4] = [1, 2, 3, 4];
4 +
constant SEED: [i32; 4] = [1, 2, 3, 4];
5 5
6 6
fn crunch() -> i32 {
7 7
    let mut working: [i32; 4] = SEED;
8 8
9 9
    working[0] += 5;
test/tests/const.array.ident.rad +3 -3
1 1
/// Test constant array containing references to other constants.
2 -
/// This tests that identifiers referencing constants are treated as const expressions.
2 +
/// This tests that identifiers referencing constants are treated as constant expressions.
3 3
4 -
const A: i32 = 42;
5 -
const B: [i32; 1] = [A];
4 +
constant A: i32 = 42;
5 +
constant B: [i32; 1] = [A];
6 6
7 7
fn test() -> i32 {
8 8
    return B[0];
9 9
}
test/tests/const.array.rad +1 -1
1 1
//! returns: 0
2 2
// Test array constants.
3 3
4 -
const NUMBERS: [i32; 4] = [1, 2, 3, 4];
4 +
constant NUMBERS: [i32; 4] = [1, 2, 3, 4];
5 5
6 6
@default fn main() -> i32 {
7 7
    let mut sum: i32 = 0;
8 8
    for n in (NUMBERS) {
9 9
        sum += n;
test/tests/const.array.record.ident.rad +4 -4
1 1
/// Test constant array containing references to other record constants.
2 -
/// This tests that identifiers referencing record constants work in const arrays.
2 +
/// This tests that identifiers referencing record constants work in constant arrays.
3 3
4 4
record Point {
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 -
const P1: Point = Point { x: 1, y: 2 };
10 -
const P2: Point = Point { x: 3, y: 4 };
11 -
const POINTS: [Point; 2] = [P1, P2];
9 +
constant P1: Point = Point { x: 1, y: 2 };
10 +
constant P2: Point = Point { x: 3, y: 4 };
11 +
constant POINTS: [Point; 2] = [P1, P2];
12 12
13 13
fn getSum() -> i32 {
14 14
    return POINTS[0].x + POINTS[1].y;
15 15
}
test/tests/const.array.repeat.record.rad +1 -1
1 1
/// Test constant array repeat with record elements.
2 2
record Point { x: i32, y: i32 }
3 3
4 -
const POINTS: [Point; 3] = [Point { x: 1, y: 2 }; 3];
4 +
constant POINTS: [Point; 3] = [Point { x: 1, y: 2 }; 3];
5 5
6 6
fn getSum() -> i32 {
7 7
    return POINTS[0].x + POINTS[1].y + POINTS[2].x;
8 8
}
test/tests/const.array.strings.slice.rad +1 -1
1 1
/// Const array of string slices lowers to slice headers (sym+len+padding)
2 2
/// and reuses deduplicated string storage.
3 -
const WORDS: [*[u8]; 3] = [
3 +
constant WORDS: [*[u8]; 3] = [
4 4
    "apple",
5 5
    "pencil",
6 6
    "apple",
7 7
];
8 8
test/tests/const.basic.rad +3 -3
1 1
//! returns: 0
2 2
// Test constant declarations with literals only (no expressions).
3 -
const N: i32 = 3;
4 -
const MAX: i32 = 4;
5 -
const DEBUG: bool = true;
3 +
constant N: i32 = 3;
4 +
constant MAX: i32 = 4;
5 +
constant DEBUG: bool = true;
6 6
7 7
@default fn main() -> i32 {
8 8
    let n: i32 = N;
9 9
    let area: i32 = (n * 10);
10 10
    let result: i32 = MAX * 2;
test/tests/const.char.rad +2 -2
1 1
//! returns: 0
2 2
3 -
const LETTER: u8 = 'A';
4 -
const DIGIT: u8 = '0';
3 +
constant LETTER: u8 = 'A';
4 +
constant DIGIT: u8 = '0';
5 5
6 6
@default fn main() -> u8 {
7 7
    if (DIGIT == '0') {
8 8
        return (LETTER) - 65;
9 9
    }
test/tests/const.fn.array.rad +2 -2
1 -
//! Test function pointers stored in const/static arrays.
1 +
//! Test function pointers stored in constant/static arrays.
2 2
//! Verifies that function references are properly emitted as
3 3
//! data items and can be called through the array.
4 4
//! returns: 0
5 5
6 6
fn add(a: i32, b: i32) -> i32 {
13 13
14 14
fn mul(a: i32, b: i32) -> i32 {
15 15
    return a * b;
16 16
}
17 17
18 -
const OPS: [fn(i32, i32) -> i32; 3] = [add, sub, mul];
18 +
constant OPS: [fn(i32, i32) -> i32; 3] = [add, sub, mul];
19 19
20 20
@default fn main() -> i32 {
21 21
    // add(10, 3) == 13
22 22
    let r0 = OPS[0](10, 3);
23 23
    assert r0 == 13;
test/tests/const.negative.rad +3 -3
1 1
// Test negative constant values
2 2
3 -
const NEG_ONE: i32 = -1;
4 -
const NEG_FORTY_TWO: i32 = -42;
5 -
const NEG_MAX: i32 = -2147483648;
3 +
constant NEG_ONE: i32 = -1;
4 +
constant NEG_FORTY_TWO: i32 = -42;
5 +
constant NEG_MAX: i32 = -2147483648;
6 6
7 7
fn getNegOne() -> i32 {
8 8
    return NEG_ONE;
9 9
}
10 10
test/tests/const.record.array.rad +1 -1
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 9
// A constant array of structs
10 -
const POINTS: [Point; 3] = [
10 +
constant POINTS: [Point; 3] = [
11 11
    Point { x: 1, y: 2 },
12 12
    Point { x: 3, y: 4 },
13 13
    Point { x: 5, y: 6 }
14 14
];
15 15
test/tests/const.record.array.simple.rad +1 -1
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 9
// Define an array of record constants
10 -
const POINTS: [Point; 3] = [
10 +
constant POINTS: [Point; 3] = [
11 11
    Point { x: 1, y: 2 },
12 12
    Point { x: 3, y: 4 },
13 13
    Point { x: 5, y: 6 }
14 14
];
15 15
test/tests/const.record.ctor.rad +1 -1
1 1
//! returns: 0
2 2
//! Constant unlabeled record constructor.
3 3
record Pair(i32, i32);
4 4
5 -
const P: Pair = Pair(40, 2);
5 +
constant P: Pair = Pair(40, 2);
6 6
7 7
@default fn main() -> i32 {
8 8
    assert P == Pair(40, 2);
9 9
    return 0;
10 10
}
test/tests/const.record.fn.rad +1 -1
4 4
record Point {
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 -
const ORIGIN: Point = Point { x: 3, y: 4 };
9 +
constant ORIGIN: Point = Point { x: 3, y: 4 };
10 10
11 11
fn getX(p: Point) -> i32 {
12 12
    return p.x;
13 13
}
14 14
test/tests/const.record.mutcopy.rad +2 -2
1 1
/// Test that accessing an aggregate constant produces a mutable copy
2 2
/// (via Reserve + Blit) so that code can safely assign through the pointer.
3 3
4 4
record Reg { n: u8 }
5 5
6 -
const SCRATCH1: Reg = { n: 30 };
7 -
const SCRATCH2: Reg = { n: 31 };
6 +
constant SCRATCH1: Reg = { n: 30 };
7 +
constant SCRATCH2: Reg = { n: 31 };
8 8
9 9
/// Returns a scratch register, avoiding the one already used by `rs`.
10 10
fn test(rs: Reg) -> Reg {
11 11
    let mut scratch = SCRATCH1;
12 12
    if rs.n == SCRATCH1.n {
test/tests/const.record.nested.rad +1 -1
8 8
    x: u8,
9 9
    inner: Inner,
10 10
    y: u8,
11 11
}
12 12
13 -
const O: Outer = Outer { x: 1, inner: Inner { a: 2, b: 3 }, y: 4 };
13 +
constant O: Outer = Outer { x: 1, inner: Inner { a: 2, b: 3 }, y: 4 };
14 14
15 15
fn getX() -> u8 {
16 16
    return O.x;
17 17
}
18 18
test/tests/const.record.packed.rad +1 -1
3 3
    a: u8,
4 4
    b: u8,
5 5
    c: u8,
6 6
}
7 7
8 -
const P: Packed = Packed { a: 1, b: 2, c: 3 };
8 +
constant P: Packed = Packed { a: 1, b: 2, c: 3 };
9 9
10 10
fn getA() -> u8 {
11 11
    return P.a;
12 12
}
13 13
test/tests/const.record.padded.rad +1 -1
3 3
    a: u8,
4 4
    b: i32,
5 5
    c: u8,
6 6
}
7 7
8 -
const P: Padded = Padded { a: 1, b: 2, c: 3 };
8 +
constant P: Padded = Padded { a: 1, b: 2, c: 3 };
9 9
10 10
fn getA() -> u8 {
11 11
    return P.a;
12 12
}
13 13
test/tests/const.record.rad +1 -1
4 4
record Point {
5 5
    x: i32,
6 6
    y: i32,
7 7
}
8 8
9 -
const ORIGIN: Point = Point { x: 3, y: 4 };
9 +
constant ORIGIN: Point = Point { x: 3, y: 4 };
10 10
11 11
@default fn main() -> i32 {
12 12
    return (ORIGIN.x + ORIGIN.y) - 7;
13 13
}
test/tests/const.record.union.rad +1 -1
9 9
record Keyword {
10 10
    name: *[u8],
11 11
    tok: TokenKind,
12 12
}
13 13
14 -
const KEYWORDS: [Keyword; 3] = [
14 +
constant KEYWORDS: [Keyword; 3] = [
15 15
    Keyword { name: "fn", tok: TokenKind::Fn },
16 16
    Keyword { name: "let", tok: TokenKind::Let },
17 17
    Keyword { name: "if", tok: TokenKind::If },
18 18
];
19 19
test/tests/const.scalar.rad +1 -1
1 1
/// Test scalar constant lowering.
2 -
const VALUE: i32 = 42;
2 +
constant VALUE: i32 = 42;
3 3
4 4
fn getValue() -> i32 {
5 5
    return VALUE;
6 6
}
test/tests/const.slice.of.slices.rad +2 -2
1 -
/// Const nested slices should lower through generic const `&[...]` support.
2 -
const GROUPS: [*[*[u8]]; 2] = [
1 +
/// Const nested slices should lower through generic constant `&[...]` support.
2 +
constant GROUPS: [*[*[u8]]; 2] = [
3 3
    &["ab", "cd"],
4 4
    &["efg"],
5 5
];
6 6
7 7
fn totalLen() -> u32 {
test/tests/const.slice.param.rad +1 -1
1 1
//! returns: 36
2 2
3 -
const DATA: [i32; 4] = [3, 5, 7, 9];
3 +
constant DATA: [i32; 4] = [3, 5, 7, 9];
4 4
5 5
fn sumPair(slice: *[i32]) -> i32 {
6 6
    return slice[0] + slice[1];
7 7
}
8 8
test/tests/const.string.rad +1 -1
1 1
/// Test string constant lowering.
2 -
const HELLO: *[u8] = "hello";
2 +
constant HELLO: *[u8] = "hello";
3 3
4 4
fn getLen() -> u32 {
5 5
    return HELLO.len;
6 6
}
test/tests/const.string.scoped.names.rad +3 -3
1 1
/// Backing string symbols should be declaration-scoped.
2 -
const HELLO1: *[u8] = "hello";
3 -
const HELLO2: *[u8] = "hello";
4 -
const MSGS: [*[u8]; 2] = ["hello", "world"];
2 +
constant HELLO1: *[u8] = "hello";
3 +
constant HELLO2: *[u8] = "hello";
4 +
constant MSGS: [*[u8]; 2] = ["hello", "world"];
5 5
6 6
fn totalLen() -> u32 {
7 7
    return HELLO1.len + HELLO2.len + MSGS[0].len + MSGS[1].len;
8 8
}
test/tests/const.union.payload.ctor.rad +1 -1
4 4
    Int(i32),
5 5
    Bool(bool),
6 6
    None,
7 7
}
8 8
9 -
const V: Value = Value::Int(42);
9 +
constant V: Value = Value::Int(42);
10 10
11 11
@default fn main() -> i32 {
12 12
    match V {
13 13
        case Value::Int(x) => {
14 14
            assert x == 42;
test/tests/const.union.record.literal.rad +1 -1
3 3
union Expr {
4 4
    Nil,
5 5
    Pair { first: i32, second: i32 },
6 6
}
7 7
8 -
const E: Expr = Expr::Pair { first: 20, second: 22 };
8 +
constant E: Expr = Expr::Pair { first: 20, second: 22 };
9 9
10 10
@default fn main() -> i32 {
11 11
    match E {
12 12
        case Expr::Nil => return 1,
13 13
        case Expr::Pair { first, second } => {
test/tests/data.array.rad +7 -7
1 1
//! returns: 0
2 2
//! Test read-only data access for arrays of various types.
3 -
const U8S: [u8; 2] = [10, 20];
4 -
const U16S: [u16; 2] = [1000, 2000];
5 -
const U32S: [u32; 2] = [100000, 200000];
6 -
const I8S: [i8; 2] = [-10, 10];
7 -
const I16S: [i16; 2] = [-1000, 1000];
8 -
const I32S: [i32; 2] = [-100000, 100000];
9 -
const BOOLS: [bool; 2] = [true, false];
3 +
constant U8S: [u8; 2] = [10, 20];
4 +
constant U16S: [u16; 2] = [1000, 2000];
5 +
constant U32S: [u32; 2] = [100000, 200000];
6 +
constant I8S: [i8; 2] = [-10, 10];
7 +
constant I16S: [i16; 2] = [-1000, 1000];
8 +
constant I32S: [i32; 2] = [-100000, 100000];
9 +
constant BOOLS: [bool; 2] = [true, false];
10 10
11 11
@default fn main() -> i32 {
12 12
    assert U8S[0] == 10;
13 13
    assert U8S[1] == 20;
14 14
test/tests/data.bool.rad +2 -2
1 1
//! returns: 0
2 2
//! Test read-only data access for `bool` type.
3 -
const T: bool = true;
4 -
const F: bool = false;
3 +
constant T: bool = true;
4 +
constant F: bool = false;
5 5
6 6
@default fn main() -> i32 {
7 7
    assert T == true;
8 8
    assert F == false;
9 9
    assert T;
test/tests/data.i16.rad +4 -4
1 1
//! returns: 0
2 2
//! Test read-only data access for `i16` type.
3 -
const A: i16 = 0;
4 -
const B: i16 = 32767;
5 -
const C: i16 = -32768;
6 -
const D: i16 = -1;
3 +
constant A: i16 = 0;
4 +
constant B: i16 = 32767;
5 +
constant C: i16 = -32768;
6 +
constant D: i16 = -1;
7 7
8 8
@default fn main() -> i32 {
9 9
    assert A == 0;
10 10
    assert B == 32767;
11 11
    assert C == -32768;
test/tests/data.i32.rad +4 -4
1 1
//! returns: 0
2 2
//! Test read-only data access for `i32` type.
3 -
const A: i32 = 0;
4 -
const B: i32 = 2147483647;
5 -
const C: i32 = -2147483648;
6 -
const D: i32 = -1;
3 +
constant A: i32 = 0;
4 +
constant B: i32 = 2147483647;
5 +
constant C: i32 = -2147483648;
6 +
constant D: i32 = -1;
7 7
8 8
@default fn main() -> i32 {
9 9
    assert A == 0;
10 10
    assert B == 2147483647;
11 11
    assert C == -2147483648;
test/tests/data.i8.rad +4 -4
1 1
//! returns: 0
2 2
//! Test read-only data access for `i8` type.
3 -
const A: i8 = 0;
4 -
const B: i8 = 127;
5 -
const C: i8 = -128;
6 -
const D: i8 = -1;
3 +
constant A: i8 = 0;
4 +
constant B: i8 = 127;
5 +
constant C: i8 = -128;
6 +
constant D: i8 = -1;
7 7
8 8
@default fn main() -> i32 {
9 9
    assert A == 0;
10 10
    assert B == 127;
11 11
    assert C == -128;
test/tests/data.record.rad +3 -3
10 10
    b: u16,
11 11
    c: u32,
12 12
    d: bool,
13 13
}
14 14
15 -
const ORIGIN: Point = Point { x: 0, y: 0 };
16 -
const P1: Point = Point { x: 100, y: -50 };
17 -
const M1: Mixed = Mixed { a: 255, b: 1000, c: 100000, d: true };
15 +
constant ORIGIN: Point = Point { x: 0, y: 0 };
16 +
constant P1: Point = Point { x: 100, y: -50 };
17 +
constant M1: Mixed = Mixed { a: 255, b: 1000, c: 100000, d: true };
18 18
19 19
@default fn main() -> i32 {
20 20
    assert ORIGIN.x == 0;
21 21
    assert ORIGIN.y == 0;
22 22
test/tests/data.simple.rad +1 -1
1 1
//! returns: 0
2 2
//! Simple test for data symbol access.
3 -
const DATA: [u8; 4] = [10, 20, 30, 40];
3 +
constant DATA: [u8; 4] = [10, 20, 30, 40];
4 4
5 5
@default fn main() -> i32 {
6 6
    if DATA[0] == 10 and
7 7
       DATA[1] == 20 and
8 8
       DATA[2] == 30 and
test/tests/data.u16.rad +3 -3
1 1
//! returns: 0
2 2
//! Test read-only data access for `u16` type.
3 -
const A: u16 = 0;
4 -
const B: u16 = 32767;
5 -
const C: u16 = 65535;
3 +
constant A: u16 = 0;
4 +
constant B: u16 = 32767;
5 +
constant C: u16 = 65535;
6 6
7 7
@default fn main() -> i32 {
8 8
    assert A == 0;
9 9
    assert B == 32767;
10 10
    assert C == 65535;
test/tests/data.u32.rad +3 -3
1 1
//! returns: 0
2 2
//! Test read-only data access for `u32` type.
3 -
const A: u32 = 0;
4 -
const B: u32 = 2147483647;
5 -
const C: u32 = 4294967295;
3 +
constant A: u32 = 0;
4 +
constant B: u32 = 2147483647;
5 +
constant C: u32 = 4294967295;
6 6
7 7
@default fn main() -> i32 {
8 8
    assert A == 0;
9 9
    assert B == 2147483647;
10 10
    assert C == 4294967295;
test/tests/data.u8.rad +3 -3
1 1
//! returns: 0
2 2
//! Test read-only data access for `u8` type.
3 -
const A: u8 = 0;
4 -
const B: u8 = 127;
5 -
const C: u8 = 255;
3 +
constant A: u8 = 0;
4 +
constant B: u8 = 127;
5 +
constant C: u8 = 255;
6 6
7 7
@default fn main() -> i32 {
8 8
    assert A == 0;
9 9
    assert B == 127;
10 10
    assert C == 255;
test/tests/data.union.rad +6 -6
10 10
    None,
11 11
    Small,
12 12
    Large,
13 13
}
14 14
15 -
const C1: Color = Color::Red;
16 -
const C2: Color = Color::Green;
17 -
const C3: Color = Color::Blue;
15 +
constant C1: Color = Color::Red;
16 +
constant C2: Color = Color::Green;
17 +
constant C3: Color = Color::Blue;
18 18
19 -
const V1: Value = Value::None;
20 -
const V2: Value = Value::Small;
21 -
const V3: Value = Value::Large;
19 +
constant V1: Value = Value::None;
20 +
constant V2: Value = Value::Small;
21 +
constant V3: Value = Value::Large;
22 22
23 23
@default fn main() -> i32 {
24 24
    match C1 {
25 25
        case Color::Red => {},
26 26
        else => { return 1; },
test/tests/prog.ackermann.rad +2 -2
5 5
//! verify against known results. Also implements a memoized iterative
6 6
//! version and cross-checks the two.
7 7
8 8
/// Maximum memo table dimensions.
9 9
/// We memoize for m <= 3 and n <= MAX_N.
10 -
const MAX_M: u32 = 4;
11 -
const MAX_N: u32 = 128;
10 +
constant MAX_M: u32 = 4;
11 +
constant MAX_N: u32 = 128;
12 12
13 13
/// Classic recursive Ackermann function.
14 14
/// Only call with small arguments to avoid stack overflow.
15 15
fn ack(m: u32, n: u32) -> i32 {
16 16
    if m == 0 {
test/tests/prog.bignum.rad +1 -1
3 3
//! Implement multi-word unsigned integer arithmetic using arrays of u32 limbs
4 4
//! (little-endian). Operations: add, subtract, multiply, compare, shift.
5 5
//! Verify using known large-number identities and cross-checks.
6 6
7 7
/// Number of limbs per big number (128 bits = 4 x 32-bit words).
8 -
const LIMBS: u32 = 4;
8 +
constant LIMBS: u32 = 4;
9 9
10 10
/// Set a big number to a u32 value.
11 11
fn bnFromU32(dst: *mut [u32], val: u32) {
12 12
    dst[0] = val;
13 13
    let mut i: u32 = 1;
test/tests/prog.cordic.rad +5 -5
4 4
//! fixed-point arithmetic (Q16.16 format). This is a classic embedded
5 5
//! systems / DSP benchmark that stress-tests shift, multiply, and
6 6
//! table-driven computation without floating point.
7 7
8 8
/// Fixed-point scale factor: 1.0 = 65536 (Q16.16).
9 -
const SCALE: i32 = 65536;
9 +
constant SCALE: i32 = 65536;
10 10
11 11
/// Number of CORDIC iterations (more = more precision).
12 -
const ITERATIONS: u32 = 16;
12 +
constant ITERATIONS: u32 = 16;
13 13
14 14
/// CORDIC gain factor in Q16.16. After 16 iterations, the gain is
15 15
/// approximately 1/K = 1/1.6468 = 0.60725 * 65536 = 39797.
16 -
const CORDIC_GAIN: i32 = 39797;
16 +
constant CORDIC_GAIN: i32 = 39797;
17 17
18 18
/// Pi in Q16.16: 3.14159 * 65536 = 205887
19 -
const PI: i32 = 205887;
19 +
constant PI: i32 = 205887;
20 20
21 21
/// Pi/2 in Q16.16.
22 -
const HALF_PI: i32 = 102944;
22 +
constant HALF_PI: i32 = 102944;
23 23
24 24
/// Result record for cos and sin.
25 25
record CosSin {
26 26
    cos: i32,
27 27
    sin: i32,
test/tests/prog.dijkstra.rad +2 -2
1 1
//! returns: 0
2 2
//! Dijkstra's shortest path algorithm.
3 3
//! Find shortest paths in a weighted directed graph using an adjacency matrix
4 4
//! and a min-heap priority queue. Reconstruct paths and verify distances.
5 5
6 -
const MAX_NODES: u32 = 16;
7 -
const INF: u32 = 0xFFFFFFFF;
6 +
constant MAX_NODES: u32 = 16;
7 +
constant INF: u32 = 0xFFFFFFFF;
8 8
9 9
record HeapEntry {
10 10
    dist: u32,
11 11
    node: u32,
12 12
}
test/tests/prog.hanoi.rad +2 -2
1 1
//! returns: 0
2 2
//! Tower of Hanoi.
3 3
//! Solve Tower of Hanoi for N disks, recording moves into an array.
4 4
//! Verify the move count and specific moves are correct.
5 5
6 -
const NUM_DISKS: u32 = 6;
6 +
constant NUM_DISKS: u32 = 6;
7 7
/// 2^6 - 1 = 63 moves.
8 -
const MAX_MOVES: u32 = 63;
8 +
constant MAX_MOVES: u32 = 63;
9 9
10 10
/// A single move: move a disk from one peg to another.
11 11
record Move {
12 12
    disk: u32,
13 13
    from: u32,
test/tests/prog.huffman.rad +4 -4
1 1
//! returns: 0
2 2
//! Huffman encoding.
3 3
//! Build a Huffman tree from character frequencies, generate prefix codes,
4 4
//! encode a message, decode it, and verify round-trip correctness.
5 5
6 -
const MAX_SYMBOLS: u32 = 32;
7 -
const MAX_NODES: u32 = 63;
8 -
const MAX_BITS: u32 = 512;
6 +
constant MAX_SYMBOLS: u32 = 32;
7 +
constant MAX_NODES: u32 = 63;
8 +
constant MAX_BITS: u32 = 512;
9 9
10 10
/// A node in the Huffman tree.
11 11
union HNodeKind {
12 12
    /// Leaf node with a symbol index.
13 13
    Leaf(u32),
20 20
    kind: HNodeKind,
21 21
    left: u32,
22 22
    right: u32,
23 23
}
24 24
25 -
const NIL: u32 = 0xFFFFFFFF;
25 +
constant NIL: u32 = 0xFFFFFFFF;
26 26
27 27
record HuffState {
28 28
    nodes: *mut [HNode],
29 29
    nodeCount: u32,
30 30
    heap: *mut [u32],
test/tests/prog.lzw.rad +4 -4
1 1
//! returns: 0
2 2
//! LZW compression and decompression.
3 3
//! Implement the Lempel-Ziv-Welch algorithm with a fixed-size dictionary.
4 4
//! Encode a byte buffer, decode it, and verify perfect round-trip.
5 5
6 -
const MAX_DICT: u32 = 512;
7 -
const INIT_DICT: u32 = 258;
8 -
const CLEAR_CODE: u32 = 256;
9 -
const EOI_CODE: u32 = 257;
6 +
constant MAX_DICT: u32 = 512;
7 +
constant INIT_DICT: u32 = 258;
8 +
constant CLEAR_CODE: u32 = 256;
9 +
constant EOI_CODE: u32 = 257;
10 10
11 11
record DictEntry {
12 12
    prefix: u32,
13 13
    suffix: u8,
14 14
}
test/tests/prog.matmul.rad +1 -1
1 1
//! returns: 0
2 2
//! Matrix multiplication.
3 3
//! Multiply two 4x4 integer matrices and verify the result against
4 4
//! a known expected output. Classic benchmark kernel.
5 5
6 -
const N: u32 = 4;
6 +
constant N: u32 = 4;
7 7
8 8
/// A 4x4 integer matrix (row-major).
9 9
record Mat4 {
10 10
    rows: [[i32; 4]; 4],
11 11
}
test/tests/prog.mersenne.rad +8 -8
1 1
//! returns: 0
2 2
//! Mersenne Twister PRNG with statistical testing.
3 3
4 -
const N: u32 = 624;
5 -
const M: u32 = 397;
6 -
const MATRIX_A: u32 = 0x9908B0DF;
7 -
const UPPER_MASK: u32 = 0x80000000;
8 -
const LOWER_MASK: u32 = 0x7FFFFFFF;
4 +
constant N: u32 = 624;
5 +
constant M: u32 = 397;
6 +
constant MATRIX_A: u32 = 0x9908B0DF;
7 +
constant UPPER_MASK: u32 = 0x80000000;
8 +
constant LOWER_MASK: u32 = 0x7FFFFFFF;
9 9
10 10
record MtState {
11 11
    mt: *mut [u32],
12 12
    mti: u32,
13 13
}
146 146
}
147 147
148 148
fn testChiSquared(s: *mut MtState) -> i32 {
149 149
    mtInit(s, 12345);
150 150
151 -
    const NUM_BINS: u32 = 16;
152 -
    const NUM_SAMPLES: u32 = 1600;
153 -
    const EXPECTED: u32 = 100;
151 +
    constant NUM_BINS: u32 = 16;
152 +
    constant NUM_SAMPLES: u32 = 1600;
153 +
    constant EXPECTED: u32 = 100;
154 154
155 155
    let mut bins: [u32; 16] = [0; 16];
156 156
157 157
    let mut i: u32 = 0;
158 158
    while i < NUM_SAMPLES {
test/tests/prog.nqueens.rad +1 -1
1 1
//! returns: 0
2 2
//! N-Queens solver.
3 3
//! Solve the N-Queens problem using backtracking. Count all valid placements
4 4
//! for boards of size 1 through 8 and verify against known solution counts.
5 5
6 -
const MAX_N: u32 = 8;
6 +
constant MAX_N: u32 = 8;
7 7
8 8
record Board {
9 9
    queens: *mut [i32],
10 10
    solutionCount: u32,
11 11
    boardSize: u32,
test/tests/prog.rbtree.rad +4 -4
1 1
//! returns: 0
2 2
//! Red-black tree.
3 3
//! Implement a red-black tree (balanced BST) using a stack-allocated node pool.
4 4
5 -
const POOL_SIZE: u32 = 128;
6 -
const NIL: u32 = 0;
5 +
constant POOL_SIZE: u32 = 128;
6 +
constant NIL: u32 = 0;
7 7
8 -
const RED: u32 = 0;
9 -
const BLACK: u32 = 1;
8 +
constant RED: u32 = 0;
9 +
constant BLACK: u32 = 1;
10 10
11 11
record RBNode {
12 12
    key: i32,
13 13
    color: u32,
14 14
    left: u32,
test/tests/prog.regex.rad +6 -6
2 2
//! NFA-based regex matcher.
3 3
//! Implement a simple regular expression engine using Thompson's NFA
4 4
//! construction. Supports: literal characters, '.', '*', '+', '?',
5 5
//! and concatenation.
6 6
7 -
const MAX_STATES: u32 = 128;
8 -
const MAX_TRANSITIONS: u32 = 256;
9 -
const NIL: u32 = 0xFFFFFFFF;
7 +
constant MAX_STATES: u32 = 128;
8 +
constant MAX_TRANSITIONS: u32 = 256;
9 +
constant NIL: u32 = 0xFFFFFFFF;
10 10
11 -
const TRANS_CHAR: u32 = 0;
12 -
const TRANS_EPSILON: u32 = 1;
13 -
const TRANS_DOT: u32 = 2;
11 +
constant TRANS_CHAR: u32 = 0;
12 +
constant TRANS_EPSILON: u32 = 1;
13 +
constant TRANS_DOT: u32 = 2;
14 14
15 15
record Trans {
16 16
    kind: u32,
17 17
    ch: u8,
18 18
    to: u32,
test/tests/prog.sha256.rad +1 -1
9 9
    w: [u32; 64],
10 10
}
11 11
12 12
/// SHA-256 initial hash values (first 32 bits of fractional parts of square
13 13
/// roots of the first 8 primes).
14 -
const INIT_H: [u32; 8] = [
14 +
constant INIT_H: [u32; 8] = [
15 15
    0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
16 16
    0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
17 17
];
18 18
19 19
/// Right-rotate a 32-bit value by `n` bits.
test/tests/prog.symtab.rad +4 -4
3 3
//! Implement a multi-scope symbol table with hash-based lookup, scope
4 4
//! push/pop, and symbol resolution. Exercises: optionals, if-let,
5 5
//! while-let, let-else, for-in with indexing, records with pointer
6 6
//! fields, and complex interactions between data structures.
7 7
8 -
const MAX_SYMBOLS: u32 = 256;
9 -
const MAX_SCOPES: u32 = 16;
10 -
const HASH_SIZE: u32 = 64;
11 -
const NIL: u32 = 0xFFFFFFFF;
8 +
constant MAX_SYMBOLS: u32 = 256;
9 +
constant MAX_SCOPES: u32 = 16;
10 +
constant HASH_SIZE: u32 = 64;
11 +
constant NIL: u32 = 0xFFFFFFFF;
12 12
13 13
/// A symbol entry in the table.
14 14
record Symbol {
15 15
    /// Name of the symbol (hash for comparison).
16 16
    nameHash: u32,
test/tests/prog.vm.rad +4 -4
3 3
//! Implement a bytecode interpreter for a simple stack machine with
4 4
//! arithmetic, comparisons, jumps, local variables, and function calls.
5 5
//! Exercises: tagged unions, match, throw/try/catch, error handling,
6 6
//! records with slice fields, and complex interacting state.
7 7
8 -
const MAX_STACK: u32 = 64;
9 -
const MAX_CODE: u32 = 256;
10 -
const MAX_LOCALS: u32 = 16;
11 -
const MAX_FRAMES: u32 = 8;
8 +
constant MAX_STACK: u32 = 64;
9 +
constant MAX_CODE: u32 = 256;
10 +
constant MAX_LOCALS: u32 = 16;
11 +
constant MAX_FRAMES: u32 = 8;
12 12
13 13
/// Bytecode instructions.
14 14
union Op {
15 15
    /// Push an immediate value.
16 16
    Push(i32),
test/tests/slice.runtime.literal.rad +1 -1
1 -
/// Create a slice literal with a runtime (non-const) element.
1 +
/// Create a slice literal with a runtime (non-constant) element.
2 2
fn sliceWithVar(c: u8) -> *[u8] {
3 3
    return &[c];
4 4
}
5 5
6 6
/// Create a slice literal with multiple runtime elements.
test/tests/static.local.decl.rad +2 -2
1 -
/// Test lowering of function-local static and const declarations.
1 +
/// Test lowering of function-local static and constant declarations.
2 2
fn localStaticAndConst() -> i32 {
3 3
    static LOCAL: i32 = 7;
4 -
    const ADD: i32 = 5;
4 +
    constant ADD: i32 = 5;
5 5
6 6
    LOCAL += ADD;
7 7
    return LOCAL;
8 8
}
test/tests/unsigned.compare.rad +1 -1
1 1
//! returns: 1
2 2
//! Test unsigned integer comparisons.
3 3
4 -
const MAX_U32: u32 = 0xFFFFFFFF;
4 +
constant MAX_U32: u32 = 0xFFFFFFFF;
5 5
6 6
/// Test expression-level unsigned comparisons.
7 7
fn testExpressionComparisons() -> bool {
8 8
    let zero: u32 = 0;
9 9
    let one: u32 = 1;