Implement `assert` statements
66464ff6dada83798cc74ca7af758148e3cececd429291b16d62c172ef3b90be
1 parent
d21f24aa
lib/std/arch/rv64.rad
+1 -1
| 66 | 66 | pub const T5: Reg = { n: 30 }; /// Temporary. |
|
| 67 | 67 | pub const T6: Reg = { n: 31 }; /// Temporary. |
|
| 68 | 68 | ||
| 69 | 69 | /// Create a register from a number. Panics if `n > 31`. |
|
| 70 | 70 | pub fn reg(n: u8) -> Reg { |
|
| 71 | - | debug::assert(n < 32); |
|
| 71 | + | debug::check(n < 32); |
|
| 72 | 72 | return Reg { n }; |
|
| 73 | 73 | } |
|
| 74 | 74 | ||
| 75 | 75 | //////////////////////////// |
|
| 76 | 76 | // Architecture constants // |
lib/std/arch/rv64/emit.rad
+2 -2
| 232 | 232 | e.code[index] = instr; |
|
| 233 | 233 | } |
|
| 234 | 234 | ||
| 235 | 235 | /// Record a block's address for branch resolution. |
|
| 236 | 236 | pub fn recordBlock(e: *mut Emitter, blockIdx: u32) { |
|
| 237 | - | debug::assert(e.codeLen <= MAX_CODE_LEN); |
|
| 237 | + | debug::check(e.codeLen <= MAX_CODE_LEN); |
|
| 238 | 238 | labels::recordBlock(&mut e.labels, blockIdx, e.codeLen as i32 * super::INSTR_SIZE); |
|
| 239 | 239 | } |
|
| 240 | 240 | ||
| 241 | 241 | /// Record a function's code offset for call resolution. |
|
| 242 | 242 | pub fn recordFuncOffset(e: *mut Emitter, name: *[u8]) { |
|
| 243 | - | debug::assert(e.codeLen <= MAX_CODE_LEN); |
|
| 243 | + | debug::check(e.codeLen <= MAX_CODE_LEN); |
|
| 244 | 244 | dict::insert(&mut e.labels.funcs, name, e.codeLen as i32 * super::INSTR_SIZE); |
|
| 245 | 245 | } |
|
| 246 | 246 | ||
| 247 | 247 | /// Record a function's start position for printing. |
|
| 248 | 248 | pub fn recordFunc(e: *mut Emitter, name: *[u8]) { |
lib/std/arch/rv64/encode.rad
+10 -10
| 104 | 104 | | ((funct7 & 0x7F) << 25); |
|
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | /// Encode an I-type instruction. |
|
| 108 | 108 | fn encodeI(opcode: u32, rd: super::Reg, rs1: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 109 | - | debug::assert(isSmallImm(imm)); |
|
| 109 | + | debug::check(isSmallImm(imm)); |
|
| 110 | 110 | ||
| 111 | 111 | return (opcode & 0x7F) |
|
| 112 | 112 | | ((rd.n as u32 & 0x1F) << 7) |
|
| 113 | 113 | | ((funct3 & 0x07) << 12) |
|
| 114 | 114 | | ((rs1.n as u32 & 0x1F) << 15) |
|
| 115 | 115 | | ((imm as u32 & 0xFFF) << 20); |
|
| 116 | 116 | } |
|
| 117 | 117 | ||
| 118 | 118 | /// Encode an S-type instruction. |
|
| 119 | 119 | fn encodeS(opcode: u32, rs1: super::Reg, rs2: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 120 | - | debug::assert(isSmallImm(imm)); |
|
| 120 | + | debug::check(isSmallImm(imm)); |
|
| 121 | 121 | ||
| 122 | 122 | return (opcode & 0x7F) |
|
| 123 | 123 | | ((imm as u32 & 0x1F) << 7) |
|
| 124 | 124 | | ((funct3 & 0x07) << 12) |
|
| 125 | 125 | | ((rs1.n as u32 & 0x1F) << 15) |
| 127 | 127 | | ((imm as u32 >> 5 & 0x7F) << 25); |
|
| 128 | 128 | } |
|
| 129 | 129 | ||
| 130 | 130 | /// Encode a B-type (branch) instruction. |
|
| 131 | 131 | fn encodeB(opcode: u32, rs1: super::Reg, rs2: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 132 | - | debug::assert(isBranchImm(imm)); |
|
| 132 | + | debug::check(isBranchImm(imm)); |
|
| 133 | 133 | ||
| 134 | 134 | let imm11 = (imm as u32 >> 11) & 0x1; |
|
| 135 | 135 | let imm4_1 = (imm as u32 >> 1) & 0xF; |
|
| 136 | 136 | let imm10_5 = (imm as u32 >> 5) & 0x3F; |
|
| 137 | 137 | let imm12 = (imm as u32 >> 12) & 0x1; |
| 153 | 153 | | ((imm as u32 & 0xFFFFF) << 12); |
|
| 154 | 154 | } |
|
| 155 | 155 | ||
| 156 | 156 | /// Encode a J-type (jump) instruction. |
|
| 157 | 157 | fn encodeJ(opcode: u32, rd: super::Reg, imm: i32) -> u32 { |
|
| 158 | - | debug::assert(isJumpImm(imm)); |
|
| 158 | + | debug::check(isJumpImm(imm)); |
|
| 159 | 159 | ||
| 160 | 160 | let imm20 = (imm as u32 >> 20) & 0x1; |
|
| 161 | 161 | let imm10_1 = (imm as u32 >> 1) & 0x3FF; |
|
| 162 | 162 | let imm11 = (imm as u32 >> 11) & 0x1; |
|
| 163 | 163 | let imm19_12 = (imm as u32 >> 12) & 0xFF; |
| 204 | 204 | return encodeI(OP_IMM, rd, rs1, F3_AND, imm); |
|
| 205 | 205 | } |
|
| 206 | 206 | ||
| 207 | 207 | /// Shift left logical immediate: `rd = rs1 << shamt`. |
|
| 208 | 208 | pub fn slli(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 209 | - | debug::assert(shamt >= 0 and shamt < 64); |
|
| 209 | + | debug::check(shamt >= 0 and shamt < 64); |
|
| 210 | 210 | return encodeI(OP_IMM, rd, rs1, F3_SLL, shamt & 0x3F); |
|
| 211 | 211 | } |
|
| 212 | 212 | ||
| 213 | 213 | /// Shift right logical immediate: `rd = rs1 >> shamt` (zero-extend). |
|
| 214 | 214 | pub fn srli(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 215 | - | debug::assert(shamt >= 0 and shamt < 64); |
|
| 215 | + | debug::check(shamt >= 0 and shamt < 64); |
|
| 216 | 216 | return encodeI(OP_IMM, rd, rs1, F3_SRL, shamt & 0x3F); |
|
| 217 | 217 | } |
|
| 218 | 218 | ||
| 219 | 219 | /// Shift right arithmetic immediate: `rd = rs1 >> shamt` (sign-extend). |
|
| 220 | 220 | pub fn srai(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 221 | - | debug::assert(shamt >= 0 and shamt < 64); |
|
| 221 | + | debug::check(shamt >= 0 and shamt < 64); |
|
| 222 | 222 | // SRAI has bit 10 set in immediate field (becomes bit 30 in instruction) |
|
| 223 | 223 | return encodeI(OP_IMM, rd, rs1, F3_SRL, (shamt & 0x3F) | 0b10000000000); |
|
| 224 | 224 | } |
|
| 225 | 225 | ||
| 226 | 226 | /////////////////////////// |
| 330 | 330 | return encodeI(OP_IMM32, rd, rs1, F3_ADD, imm); |
|
| 331 | 331 | } |
|
| 332 | 332 | ||
| 333 | 333 | /// Shift left logical immediate word: `rd = sign_ext((rs1 << shamt)[31:0])`. |
|
| 334 | 334 | pub fn slliw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 335 | - | debug::assert(shamt >= 0 and shamt < 32); |
|
| 335 | + | debug::check(shamt >= 0 and shamt < 32); |
|
| 336 | 336 | return encodeI(OP_IMM32, rd, rs1, F3_SLL, shamt & 0x1F); |
|
| 337 | 337 | } |
|
| 338 | 338 | ||
| 339 | 339 | /// Shift right logical immediate word: `rd = sign_ext((rs1[31:0] >> shamt))`. |
|
| 340 | 340 | pub fn srliw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 341 | - | debug::assert(shamt >= 0 and shamt < 32); |
|
| 341 | + | debug::check(shamt >= 0 and shamt < 32); |
|
| 342 | 342 | return encodeI(OP_IMM32, rd, rs1, F3_SRL, shamt & 0x1F); |
|
| 343 | 343 | } |
|
| 344 | 344 | ||
| 345 | 345 | /// Shift right arithmetic immediate word: `rd = sign_ext((rs1[31:0] >> shamt))` (sign-extended). |
|
| 346 | 346 | pub fn sraiw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 347 | - | debug::assert(shamt >= 0 and shamt < 32); |
|
| 347 | + | debug::check(shamt >= 0 and shamt < 32); |
|
| 348 | 348 | return encodeI(OP_IMM32, rd, rs1, F3_SRL, (shamt & 0x1F) | 0b10000000000); |
|
| 349 | 349 | } |
|
| 350 | 350 | ||
| 351 | 351 | /// Add word: `rd = sign_ext((rs1 + rs2)[31:0])`. |
|
| 352 | 352 | pub fn addw(rd: super::Reg, rs1: super::Reg, rs2: super::Reg) -> u32 { |
lib/std/arch/rv64/isel.rad
+1 -1
| 389 | 389 | ||
| 390 | 390 | emit::emit(s.e, encode::sub(super::SP, super::SP, rs)); |
|
| 391 | 391 | ||
| 392 | 392 | if alignment > 1 { |
|
| 393 | 393 | let mask = 0 - alignment as i32; |
|
| 394 | - | debug::assert(encode::isSmallImm(mask)); |
|
| 394 | + | debug::check(encode::isSmallImm(mask)); |
|
| 395 | 395 | ||
| 396 | 396 | emit::emit(s.e, encode::andi(super::SP, super::SP, mask)); |
|
| 397 | 397 | } |
|
| 398 | 398 | emit::emit(s.e, encode::mv(rd, super::SP)); |
|
| 399 | 399 | }, |
lib/std/arch/rv64/tests/assert.basic.rad
added
+19 -0
| 1 | + | /// Test assert keyword. |
|
| 2 | + | @default fn main() -> i32 { |
|
| 3 | + | // Assert with true condition should pass. |
|
| 4 | + | assert true; |
|
| 5 | + | ||
| 6 | + | // Assert with comparison. |
|
| 7 | + | let x: i32 = 42; |
|
| 8 | + | assert x == 42; |
|
| 9 | + | assert x > 0; |
|
| 10 | + | assert x != 0; |
|
| 11 | + | ||
| 12 | + | // Assert with message. |
|
| 13 | + | assert x == 42, "x should be 42"; |
|
| 14 | + | ||
| 15 | + | // Assert with block form. |
|
| 16 | + | assert { x > 0 }, "x must be positive"; |
|
| 17 | + | ||
| 18 | + | return 0; |
|
| 19 | + | } |
lib/std/arch/rv64/tests/assert.fail.rad
added
+6 -0
| 1 | + | /// Test that assert with false condition triggers ebreak. |
|
| 2 | + | //! returns: 133 |
|
| 3 | + | @default fn main() -> i32 { |
|
| 4 | + | assert false; |
|
| 5 | + | return 0; |
|
| 6 | + | } |
lib/std/arch/rv64/tests/bool.comparison.slice.rad
+15 -21
| 1 | - | fn assert(cond: bool) { |
|
| 2 | - | if not cond { |
|
| 3 | - | panic; |
|
| 4 | - | } |
|
| 5 | - | } |
|
| 6 | - | ||
| 7 | 1 | fn memEq(a: *[u8], b: *[u8]) -> bool { |
|
| 8 | 2 | if a.len != b.len { |
|
| 9 | 3 | return false; |
|
| 10 | 4 | } |
|
| 11 | 5 | for i in 0..a.len { |
| 181 | 175 | return memEq(sliceU8("ABC"), "ABC") |
|
| 182 | 176 | and sliceEqualI32(sliceI32(&[1, 2, 3]), &[1, 2, 3]); |
|
| 183 | 177 | } |
|
| 184 | 178 | ||
| 185 | 179 | @default fn main() -> i32 { |
|
| 186 | - | assert(sliceEqual1()); |
|
| 187 | - | assert(sliceEqual2()); |
|
| 188 | - | assert(sliceEqual3()); |
|
| 189 | - | assert(sliceEqual4()); |
|
| 190 | - | assert(sliceEqualString1()); |
|
| 191 | - | assert(sliceEqualString2()); |
|
| 192 | - | assert(sliceEqualString3()); |
|
| 193 | - | assert(sliceEqualString4()); |
|
| 194 | - | assert(sliceEqualString5()); |
|
| 195 | - | assert(sliceNotEqualSameArray1()); |
|
| 196 | - | assert(sliceNotEqualSameArray2()); |
|
| 197 | - | assert(sliceEqualDifferentArray()); |
|
| 198 | - | assert(sliceNotEqualU8()); |
|
| 199 | - | assert(sliceNotEqualU16()); |
|
| 200 | - | assert(sliceReturnEqual()); |
|
| 180 | + | assert sliceEqual1(); |
|
| 181 | + | assert sliceEqual2(); |
|
| 182 | + | assert sliceEqual3(); |
|
| 183 | + | assert sliceEqual4(); |
|
| 184 | + | assert sliceEqualString1(); |
|
| 185 | + | assert sliceEqualString2(); |
|
| 186 | + | assert sliceEqualString3(); |
|
| 187 | + | assert sliceEqualString4(); |
|
| 188 | + | assert sliceEqualString5(); |
|
| 189 | + | assert sliceNotEqualSameArray1(); |
|
| 190 | + | assert sliceNotEqualSameArray2(); |
|
| 191 | + | assert sliceEqualDifferentArray(); |
|
| 192 | + | assert sliceNotEqualU8(); |
|
| 193 | + | assert sliceNotEqualU16(); |
|
| 194 | + | assert sliceReturnEqual(); |
|
| 201 | 195 | ||
| 202 | 196 | return 0; |
|
| 203 | 197 | } |
lib/std/arch/rv64/tests/builtin.size.align.rad
+36 -42
| 1 | 1 | record Foo { |
|
| 2 | 2 | x: u8, |
|
| 3 | 3 | y: u32, |
|
| 4 | 4 | } |
|
| 5 | 5 | ||
| 6 | - | fn assert(cond: bool) { |
|
| 7 | - | if not cond { |
|
| 8 | - | panic; |
|
| 9 | - | } |
|
| 10 | - | } |
|
| 11 | - | ||
| 12 | 6 | @default fn main() -> u8 { |
|
| 13 | - | assert(@sizeOf(u8) == 1); |
|
| 14 | - | assert(@alignOf(u8) == 1); |
|
| 7 | + | assert @sizeOf(u8) == 1; |
|
| 8 | + | assert @alignOf(u8) == 1; |
|
| 15 | 9 | ||
| 16 | - | assert(@sizeOf(u16) == 2); |
|
| 17 | - | assert(@alignOf(u16) == 2); |
|
| 10 | + | assert @sizeOf(u16) == 2; |
|
| 11 | + | assert @alignOf(u16) == 2; |
|
| 18 | 12 | ||
| 19 | - | assert(@sizeOf(u32) == 4); |
|
| 20 | - | assert(@alignOf(u32) == 4); |
|
| 13 | + | assert @sizeOf(u32) == 4; |
|
| 14 | + | assert @alignOf(u32) == 4; |
|
| 21 | 15 | ||
| 22 | - | assert(@sizeOf(i32) == 4); |
|
| 23 | - | assert(@alignOf(i32) == 4); |
|
| 16 | + | assert @sizeOf(i32) == 4; |
|
| 17 | + | assert @alignOf(i32) == 4; |
|
| 24 | 18 | ||
| 25 | - | assert(@sizeOf(Foo) == 8); |
|
| 26 | - | assert(@alignOf(Foo) == 4); |
|
| 19 | + | assert @sizeOf(Foo) == 8; |
|
| 20 | + | assert @alignOf(Foo) == 4; |
|
| 27 | 21 | ||
| 28 | - | assert(@sizeOf([u16; 3]) == 6); |
|
| 29 | - | assert(@alignOf([u16; 3]) == 2); |
|
| 22 | + | assert @sizeOf([u16; 3]) == 6; |
|
| 23 | + | assert @alignOf([u16; 3]) == 2; |
|
| 30 | 24 | ||
| 31 | - | assert(@sizeOf(?u8) == 2); |
|
| 32 | - | assert(@alignOf(?u8) == 1); |
|
| 25 | + | assert @sizeOf(?u8) == 2; |
|
| 26 | + | assert @alignOf(?u8) == 1; |
|
| 33 | 27 | ||
| 34 | - | assert(@sizeOf(?*u32) == 8); |
|
| 35 | - | assert(@alignOf(?*u32) == 8); |
|
| 28 | + | assert @sizeOf(?*u32) == 8; |
|
| 29 | + | assert @alignOf(?*u32) == 8; |
|
| 36 | 30 | ||
| 37 | - | assert(@sizeOf(?*mut u32) == 8); |
|
| 38 | - | assert(@alignOf(?*mut u32) == 8); |
|
| 31 | + | assert @sizeOf(?*mut u32) == 8; |
|
| 32 | + | assert @alignOf(?*mut u32) == 8; |
|
| 39 | 33 | ||
| 40 | - | assert(@sizeOf(?*[u16]) == 16); |
|
| 41 | - | assert(@alignOf(?*[u16]) == 8); |
|
| 34 | + | assert @sizeOf(?*[u16]) == 16; |
|
| 35 | + | assert @alignOf(?*[u16]) == 8; |
|
| 42 | 36 | ||
| 43 | - | assert(@sizeOf(?*mut [u8]) == 16); |
|
| 44 | - | assert(@alignOf(?*mut [u8]) == 8); |
|
| 37 | + | assert @sizeOf(?*mut [u8]) == 16; |
|
| 38 | + | assert @alignOf(?*mut [u8]) == 8; |
|
| 45 | 39 | ||
| 46 | - | assert(@sizeOf(?Foo) == 12); |
|
| 47 | - | assert(@alignOf(?Foo) == 4); |
|
| 40 | + | assert @sizeOf(?Foo) == 12; |
|
| 41 | + | assert @alignOf(?Foo) == 4; |
|
| 48 | 42 | ||
| 49 | - | assert(@sizeOf(?[u16; 3]) == 8); |
|
| 50 | - | assert(@alignOf(?[u16; 3]) == 2); |
|
| 43 | + | assert @sizeOf(?[u16; 3]) == 8; |
|
| 44 | + | assert @alignOf(?[u16; 3]) == 2; |
|
| 51 | 45 | ||
| 52 | - | assert(@sizeOf(*u32) == 8); |
|
| 53 | - | assert(@alignOf(*u32) == 8); |
|
| 46 | + | assert @sizeOf(*u32) == 8; |
|
| 47 | + | assert @alignOf(*u32) == 8; |
|
| 54 | 48 | ||
| 55 | - | assert(@sizeOf(*mut u32) == 8); |
|
| 56 | - | assert(@alignOf(*mut u32) == 8); |
|
| 49 | + | assert @sizeOf(*mut u32) == 8; |
|
| 50 | + | assert @alignOf(*mut u32) == 8; |
|
| 57 | 51 | ||
| 58 | - | assert(@sizeOf(*[u16]) == 16); |
|
| 59 | - | assert(@alignOf(*[u16]) == 8); |
|
| 52 | + | assert @sizeOf(*[u16]) == 16; |
|
| 53 | + | assert @alignOf(*[u16]) == 8; |
|
| 60 | 54 | ||
| 61 | - | assert(@sizeOf(*mut [u8]) == 16); |
|
| 62 | - | assert(@alignOf(*mut [u8]) == 8); |
|
| 55 | + | assert @sizeOf(*mut [u8]) == 16; |
|
| 56 | + | assert @alignOf(*mut [u8]) == 8; |
|
| 63 | 57 | ||
| 64 | - | assert(@sizeOf(void) == 0); |
|
| 65 | - | assert(@alignOf(void) == 0); |
|
| 58 | + | assert @sizeOf(void) == 0; |
|
| 59 | + | assert @alignOf(void) == 0; |
|
| 66 | 60 | ||
| 67 | 61 | return 0; |
|
| 68 | 62 | } |
lib/std/arch/rv64/tests/error.catch.rad
+10 -16
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | ||
| 3 | - | fn assert(cond: bool) { |
|
| 4 | - | if not cond { |
|
| 5 | - | panic; |
|
| 6 | - | } |
|
| 7 | - | } |
|
| 8 | - | ||
| 9 | 3 | union TestError { Fail } |
|
| 10 | 4 | static PTR_VALUE: i32 = 7; |
|
| 11 | 5 | ||
| 12 | 6 | @default fn main() -> u32 { |
|
| 13 | 7 | // Catch block with early return |
|
| 14 | 8 | let val1: u32 = catchWithReturn(true); |
|
| 15 | - | assert(val1 == 42); |
|
| 9 | + | assert val1 == 42; |
|
| 16 | 10 | ||
| 17 | 11 | // Catch block with early return (success case) |
|
| 18 | 12 | let val2: u32 = catchWithReturn(false); |
|
| 19 | - | assert(val2 == 21); |
|
| 13 | + | assert val2 == 21; |
|
| 20 | 14 | ||
| 21 | 15 | // Catch block that discards error |
|
| 22 | 16 | let mut flag: u32 = 0; |
|
| 23 | 17 | try returnsErr() catch {}; |
|
| 24 | 18 | flag = 1; |
|
| 25 | - | assert(flag == 1); |
|
| 19 | + | assert flag == 1; |
|
| 26 | 20 | ||
| 27 | 21 | // Catch block with return in function |
|
| 28 | 22 | let val3: u32 = returnsEarly(); |
|
| 29 | - | assert(val3 == 42); |
|
| 23 | + | assert val3 == 42; |
|
| 30 | 24 | ||
| 31 | 25 | // try? converts to optional on error |
|
| 32 | 26 | let ptr_ok: ?*i32 = try? returnsPtrOk(); |
|
| 33 | 27 | if let p = ptr_ok { |
|
| 34 | - | assert(*p == 7); |
|
| 28 | + | assert *p == 7; |
|
| 35 | 29 | } else { |
|
| 36 | - | assert(false); |
|
| 30 | + | assert false; |
|
| 37 | 31 | } |
|
| 38 | 32 | ||
| 39 | 33 | // try? converts to nil on error |
|
| 40 | 34 | let ptr_err: ?*i32 = try? returnsPtrErr(); |
|
| 41 | - | assert(ptr_err == nil); |
|
| 35 | + | assert ptr_err == nil; |
|
| 42 | 36 | ||
| 43 | 37 | // try? on success |
|
| 44 | 38 | let opt_ok: ?u32 = try? returnsOk(); |
|
| 45 | - | assert(opt_ok != nil); |
|
| 39 | + | assert opt_ok != nil; |
|
| 46 | 40 | if let v = opt_ok { |
|
| 47 | - | assert(v == 21); |
|
| 41 | + | assert v == 21; |
|
| 48 | 42 | } |
|
| 49 | 43 | ||
| 50 | 44 | // try? on error |
|
| 51 | 45 | let opt_err: ?u32 = try? returnsErr(); |
|
| 52 | - | assert(opt_err == nil); |
|
| 46 | + | assert opt_err == nil; |
|
| 53 | 47 | ||
| 54 | 48 | return 0; |
|
| 55 | 49 | } |
|
| 56 | 50 | ||
| 57 | 51 | fn catchWithReturn(fail: bool) -> u32 { |
lib/std/arch/rv64/tests/error.try.bang.success.rad
+3 -9
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | ||
| 3 | - | fn assert(cond: bool) { |
|
| 4 | - | if not cond { |
|
| 5 | - | panic; |
|
| 6 | - | } |
|
| 7 | - | } |
|
| 8 | - | ||
| 9 | 3 | union PanicError { Boom } |
|
| 10 | 4 | ||
| 11 | 5 | fn makeOk(value: u32) -> u32 throws (PanicError) { |
|
| 12 | 6 | return value; |
|
| 13 | 7 | } |
|
| 14 | 8 | ||
| 15 | 9 | @default fn main() -> u32 { |
|
| 16 | 10 | let first: u32 = try! makeOk(7); |
|
| 17 | 11 | let second: u32 = 2 * try! makeOk(11); |
|
| 18 | 12 | ||
| 19 | - | assert(first == 7); |
|
| 20 | - | assert(second == 22); |
|
| 13 | + | assert first == 7; |
|
| 14 | + | assert second == 22; |
|
| 21 | 15 | ||
| 22 | 16 | let combined: u32 = try! makeOk(first + second); |
|
| 23 | - | assert(combined == 29); |
|
| 17 | + | assert combined == 29; |
|
| 24 | 18 | ||
| 25 | 19 | return 0; |
|
| 26 | 20 | } |
lib/std/arch/rv64/tests/opt.slice.npo.rad
+0 -6
| 1 | 1 | //! Test null pointer optimization for optional slices (?*[T]). |
|
| 2 | 2 | //! Optional slices should have the same size as slices (16 bytes), |
|
| 3 | 3 | //! using a null data pointer to represent `nil`. |
|
| 4 | 4 | ||
| 5 | - | fn assert(cond: bool) { |
|
| 6 | - | if not cond { |
|
| 7 | - | panic; |
|
| 8 | - | } |
|
| 9 | - | } |
|
| 10 | - | ||
| 11 | 5 | fn checkSizes() -> u8 { |
|
| 12 | 6 | // ?*[T] should be the same size as *[T] (16 bytes, not 24). |
|
| 13 | 7 | if @sizeOf(?*[u8]) != 16 { |
|
| 14 | 8 | return 1; |
|
| 15 | 9 | } |
lib/std/arch/rv64/tests/regalloc.spill.reuse.rad
+1 -7
| 1 | 1 | fn callPressure(a: u32, b: u32, c: u32, d: u32, e: u32, f: u32, g: u32, h: u32) -> u32 { |
|
| 2 | 2 | return a + b + c + d + e + f + g + h; |
|
| 3 | 3 | } |
|
| 4 | 4 | ||
| 5 | - | fn assert(cond: bool) { |
|
| 6 | - | if not cond { |
|
| 7 | - | panic "assert"; |
|
| 8 | - | } |
|
| 9 | - | } |
|
| 10 | - | ||
| 11 | 5 | fn bump(old: u32) -> u32 { |
|
| 12 | 6 | let saved: u32 = old + 1; |
|
| 13 | 7 | ||
| 14 | 8 | let first: u32 = callPressure(1, 2, 3, 4, 5, 6, 7, 8); |
|
| 15 | 9 | let second: u32 = callPressure(8, 7, 6, 5, 4, 3, 2, 1); |
| 21 | 15 | return saved; |
|
| 22 | 16 | } |
|
| 23 | 17 | ||
| 24 | 18 | @default fn main() -> i32 { |
|
| 25 | 19 | let result: u32 = bump(0); |
|
| 26 | - | assert(result == 1); |
|
| 20 | + | assert result == 1; |
|
| 27 | 21 | ||
| 28 | 22 | return 0; |
|
| 29 | 23 | } |
lib/std/arch/rv64/tests/var.align.rad
+8 -14
| 1 | - | fn assert(cond: bool) { |
|
| 2 | - | if not cond { |
|
| 3 | - | panic; |
|
| 4 | - | } |
|
| 5 | - | } |
|
| 6 | - | ||
| 7 | 1 | fn testDefaultAlignment() { |
|
| 8 | 2 | let p1: u8 = 1; |
|
| 9 | 3 | let p2: u8 = 2; |
|
| 10 | 4 | ||
| 11 | 5 | let p3: u16 = 3; |
| 15 | 9 | let p6: u32 = 6; |
|
| 16 | 10 | ||
| 17 | 11 | // Each variable must be naturally aligned. |
|
| 18 | 12 | let a1: u32 = (&p1) as u32; |
|
| 19 | 13 | let a2: u32 = (&p2) as u32; |
|
| 20 | - | assert((a1 % @alignOf(u8)) == 0); |
|
| 21 | - | assert((a2 % @alignOf(u8)) == 0); |
|
| 14 | + | assert (a1 % @alignOf(u8)) == 0; |
|
| 15 | + | assert (a2 % @alignOf(u8)) == 0; |
|
| 22 | 16 | ||
| 23 | 17 | let a3: u32 = (&p3) as u32; |
|
| 24 | 18 | let a4: u32 = (&p4) as u32; |
|
| 25 | - | assert((a3 % @alignOf(u16)) == 0); |
|
| 26 | - | assert((a4 % @alignOf(u16)) == 0); |
|
| 19 | + | assert (a3 % @alignOf(u16)) == 0; |
|
| 20 | + | assert (a4 % @alignOf(u16)) == 0; |
|
| 27 | 21 | ||
| 28 | 22 | let a5: u32 = (&p5) as u32; |
|
| 29 | 23 | let a6: u32 = (&p6) as u32; |
|
| 30 | - | assert((a5 % @alignOf(u32)) == 0); |
|
| 31 | - | assert((a6 % @alignOf(u32)) == 0); |
|
| 24 | + | assert (a5 % @alignOf(u32)) == 0; |
|
| 25 | + | assert (a6 % @alignOf(u32)) == 0; |
|
| 32 | 26 | } |
|
| 33 | 27 | ||
| 34 | 28 | fn testAlignAnnotation() { |
|
| 35 | 29 | let pad: [u8; 3] = [0; 3]; |
|
| 36 | 30 | let plain: u32 = 1; |
|
| 37 | 31 | let custom: u32 align(16) = 2; |
|
| 38 | 32 | ||
| 39 | 33 | let plainAddr: u32 = (&plain) as u32; |
|
| 40 | 34 | let customAddr: u32 = (&custom) as u32; |
|
| 41 | 35 | ||
| 42 | - | assert((customAddr % 16) == 0); |
|
| 43 | - | assert((plainAddr % @alignOf(u32)) == 0); |
|
| 36 | + | assert (customAddr % 16) == 0; |
|
| 37 | + | assert (plainAddr % @alignOf(u32)) == 0; |
|
| 44 | 38 | } |
|
| 45 | 39 | ||
| 46 | 40 | @default fn main() -> i32 { |
|
| 47 | 41 | testDefaultAlignment(); |
|
| 48 | 42 | testAlignAnnotation(); |
lib/std/debug.rad
+5 -3
| 1 | 1 | // TODO: Re-export `core::debug::*`. |
|
| 2 | 2 | use super::intrinsics; |
|
| 3 | 3 | ||
| 4 | - | pub fn assert(cond: bool) { |
|
| 4 | + | /// Check that a condition is true, otherwise trigger a breakpoint. |
|
| 5 | + | pub fn check(cond: bool) { |
|
| 5 | 6 | if not cond { |
|
| 6 | 7 | intrinsics::ebreak(); |
|
| 7 | 8 | } |
|
| 8 | 9 | } |
|
| 9 | 10 | ||
| 10 | - | pub fn assertMsg(cond: bool, msg: *[u8]) { |
|
| 11 | - | assert(cond); |
|
| 11 | + | /// Check that a condition is true with a message, otherwise trigger a breakpoint. |
|
| 12 | + | pub fn checkMsg(cond: bool, msg: *[u8]) { |
|
| 13 | + | check(cond); |
|
| 12 | 14 | } |
lib/std/fmt.rad
+4 -4
| 13 | 13 | /// Maximum string length for a formatted bool (eg. "false"). |
|
| 14 | 14 | pub const BOOL_STR_LEN: u32 = 5; |
|
| 15 | 15 | ||
| 16 | 16 | /// Format a u32 by writing it to the provided buffer. |
|
| 17 | 17 | pub fn formatU32(val: u32, buffer: *mut [u8]) -> *[u8] { |
|
| 18 | - | debug::assert(buffer.len >= U32_STR_LEN); |
|
| 18 | + | debug::check(buffer.len >= U32_STR_LEN); |
|
| 19 | 19 | ||
| 20 | 20 | let mut x: u32 = val; |
|
| 21 | 21 | let mut i: u32 = buffer.len; |
|
| 22 | 22 | ||
| 23 | 23 | // Handle the zero case separately to ensure a single '0' is written. |
| 37 | 37 | return &buffer[i..]; |
|
| 38 | 38 | } |
|
| 39 | 39 | ||
| 40 | 40 | /// Format a i32 by writing it to the provided buffer. |
|
| 41 | 41 | pub fn formatI32(val: i32, buffer: *mut [u8]) -> *[u8] { |
|
| 42 | - | debug::assert(buffer.len >= I32_STR_LEN); |
|
| 42 | + | debug::check(buffer.len >= I32_STR_LEN); |
|
| 43 | 43 | ||
| 44 | 44 | let neg: bool = val < 0; |
|
| 45 | 45 | let mut x: u32 = -val as u32 if neg else val as u32; |
|
| 46 | 46 | let mut i: u32 = buffer.len; |
|
| 47 | 47 | // Handle the zero case separately to ensure a single '0' is written. |
| 64 | 64 | return &buffer[i..]; |
|
| 65 | 65 | } |
|
| 66 | 66 | ||
| 67 | 67 | /// Format a u64 by writing it to the provided buffer. |
|
| 68 | 68 | pub fn formatU64(val: u64, buffer: *mut [u8]) -> *[u8] { |
|
| 69 | - | debug::assert(buffer.len >= U64_STR_LEN); |
|
| 69 | + | debug::check(buffer.len >= U64_STR_LEN); |
|
| 70 | 70 | ||
| 71 | 71 | let mut x: u64 = val; |
|
| 72 | 72 | let mut i: u32 = buffer.len; |
|
| 73 | 73 | ||
| 74 | 74 | if x == 0 { |
| 84 | 84 | return &buffer[i..]; |
|
| 85 | 85 | } |
|
| 86 | 86 | ||
| 87 | 87 | /// Format a i64 by writing it to the provided buffer. |
|
| 88 | 88 | pub fn formatI64(val: i64, buffer: *mut [u8]) -> *[u8] { |
|
| 89 | - | debug::assert(buffer.len >= I64_STR_LEN); |
|
| 89 | + | debug::check(buffer.len >= I64_STR_LEN); |
|
| 90 | 90 | ||
| 91 | 91 | let neg: bool = val < 0; |
|
| 92 | 92 | let mut x: u64 = -val as u64 if neg else val as u64; |
|
| 93 | 93 | let mut i: u32 = buffer.len; |
|
| 94 | 94 | if x == 0 { |
lib/std/lang/alloc.rad
+2 -2
| 35 | 35 | /// |
|
| 36 | 36 | /// Returns an opaque pointer to the allocated memory. Throws `AllocError` if |
|
| 37 | 37 | /// the arena is exhausted. The caller is responsible for casting to the |
|
| 38 | 38 | /// appropriate type and initializing the memory. |
|
| 39 | 39 | pub fn alloc(arena: *mut Arena, size: u32, alignment: u32) -> *mut opaque throws (AllocError) { |
|
| 40 | - | debug::assert(alignment > 0); |
|
| 41 | - | debug::assert(size > 0); |
|
| 40 | + | debug::check(alignment > 0); |
|
| 41 | + | debug::check(size > 0); |
|
| 42 | 42 | ||
| 43 | 43 | let aligned = mem::alignUp(arena.offset, alignment); |
|
| 44 | 44 | let newOffset = aligned + size; |
|
| 45 | 45 | ||
| 46 | 46 | if newOffset > arena.data.len as u32 { |
lib/std/lang/ast.rad
+8 -1
| 101 | 101 | return self.list.len; |
|
| 102 | 102 | } |
|
| 103 | 103 | ||
| 104 | 104 | /// Fetch the attribute node at the specified index. |
|
| 105 | 105 | pub fn attributesGet(self: *Attributes, index: u32) -> *Node { |
|
| 106 | - | debug::assertMsg(index < self.list.len, "attributesGet: invalid index"); |
|
| 106 | + | debug::checkMsg(index < self.list.len, "attributesGet: invalid index"); |
|
| 107 | 107 | return self.list.list[index]; |
|
| 108 | 108 | } |
|
| 109 | 109 | ||
| 110 | 110 | /// Check if an attributes list contains an attribute. |
|
| 111 | 111 | pub fn attributesContains(self: *Attributes, attr: Attribute) -> bool { |
| 730 | 730 | /// Panic statement. |
|
| 731 | 731 | Panic { |
|
| 732 | 732 | /// Optional panic message expression. |
|
| 733 | 733 | message: ?*Node, |
|
| 734 | 734 | }, |
|
| 735 | + | /// Assert statement. |
|
| 736 | + | Assert { |
|
| 737 | + | /// Condition expression that must be true. |
|
| 738 | + | condition: *Node, |
|
| 739 | + | /// Optional assertion failure message. |
|
| 740 | + | message: ?*Node, |
|
| 741 | + | }, |
|
| 735 | 742 | /// Conditional statement. |
|
| 736 | 743 | If(If), |
|
| 737 | 744 | /// Conditional expression. |
|
| 738 | 745 | CondExpr(CondExpr), |
|
| 739 | 746 | /// `if let` conditional binding. |
lib/std/lang/ast/printer.rad
+2 -0
| 357 | 357 | return sexpr::list(a, "return", &[toExprOrNull(a, value)]), |
|
| 358 | 358 | case super::NodeValue::Throw { expr } => |
|
| 359 | 359 | return sexpr::list(a, "throw", &[toExpr(a, expr)]), |
|
| 360 | 360 | case super::NodeValue::Panic { message } => |
|
| 361 | 361 | return sexpr::list(a, "panic", &[toExprOrNull(a, message)]), |
|
| 362 | + | case super::NodeValue::Assert { condition, message } => |
|
| 363 | + | return sexpr::list(a, "assert", &[toExpr(a, condition), toExprOrNull(a, message)]), |
|
| 362 | 364 | case super::NodeValue::If(c) => |
|
| 363 | 365 | return sexpr::block(a, "if", &[toExpr(a, c.condition)], |
|
| 364 | 366 | &[toExpr(a, c.thenBranch), toExprOrNull(a, c.elseBranch)]), |
|
| 365 | 367 | case super::NodeValue::IfLet(c) => |
|
| 366 | 368 | return sexpr::block(a, "if-let", &[ |
lib/std/lang/lower.rad
+34 -13
| 1017 | 1017 | } else { |
|
| 1018 | 1018 | func.returnType = ilType(self, *fnType.returnType); |
|
| 1019 | 1019 | } |
|
| 1020 | 1020 | let body = decl.body else { |
|
| 1021 | 1021 | // Extern functions have no body. |
|
| 1022 | - | debug::assert(isExtern); |
|
| 1022 | + | debug::check(isExtern); |
|
| 1023 | 1023 | return func; |
|
| 1024 | 1024 | }; |
|
| 1025 | 1025 | func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 1026 | 1026 | ||
| 1027 | 1027 | return func; |
| 1942 | 1942 | switchToBlock(self, target); |
|
| 1943 | 1943 | } |
|
| 1944 | 1944 | ||
| 1945 | 1945 | /// Emit a conditional branch based on `cond`. |
|
| 1946 | 1946 | fn emitBr(self: *mut FnLowerer, cond: il::Reg, thenBlock: BlockId, elseBlock: BlockId) throws (LowerError) { |
|
| 1947 | - | debug::assert(thenBlock != elseBlock); |
|
| 1947 | + | debug::check(thenBlock != elseBlock); |
|
| 1948 | 1948 | emit(self, il::Instr::Br { |
|
| 1949 | 1949 | op: il::CmpOp::Ne, |
|
| 1950 | 1950 | typ: il::Type::W32, |
|
| 1951 | 1951 | a: il::Val::Reg(cond), |
|
| 1952 | 1952 | b: il::Val::Imm(0), |
| 1967 | 1967 | a: il::Val, |
|
| 1968 | 1968 | b: il::Val, |
|
| 1969 | 1969 | thenBlock: BlockId, |
|
| 1970 | 1970 | elseBlock: BlockId |
|
| 1971 | 1971 | ) throws (LowerError) { |
|
| 1972 | - | debug::assert(thenBlock != elseBlock); |
|
| 1972 | + | debug::check(thenBlock != elseBlock); |
|
| 1973 | 1973 | emit(self, il::Instr::Br { |
|
| 1974 | 1974 | op, typ, a, b, |
|
| 1975 | 1975 | thenTarget: thenBlock.n, thenArgs: &mut [], |
|
| 1976 | 1976 | elseTarget: elseBlock.n, elseArgs: &mut [], |
|
| 1977 | 1977 | }); |
| 2210 | 2210 | ||
| 2211 | 2211 | try emitBr(self, eqReg, matchBlock, fallthrough); |
|
| 2212 | 2212 | } |
|
| 2213 | 2213 | } |
|
| 2214 | 2214 | case MatchSubjectKind::Union(unionInfo) => { |
|
| 2215 | - | debug::assert(not isNil); |
|
| 2215 | + | debug::check(not isNil); |
|
| 2216 | 2216 | ||
| 2217 | 2217 | let case resolver::NodeExtra::UnionVariant { tag: variantTag, .. } = |
|
| 2218 | 2218 | resolver::nodeData(self.low.resolver, pattern).extra |
|
| 2219 | 2219 | else { |
|
| 2220 | 2220 | throw LowerError::ExpectedVariant; |
| 2238 | 2238 | ||
| 2239 | 2239 | try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, il::Val::Reg(tagReg), il::Val::Imm(variantTag as i64), matchBlock, fallthrough); |
|
| 2240 | 2240 | } |
|
| 2241 | 2241 | } |
|
| 2242 | 2242 | else => { // Scalar comparison. |
|
| 2243 | - | debug::assert(not isNil); |
|
| 2243 | + | debug::check(not isNil); |
|
| 2244 | 2244 | let pattVal = try lowerExpr(self, pattern); |
|
| 2245 | 2245 | try emitBrCmp(self, il::CmpOp::Eq, subject.ilType, subject.val, pattVal, matchBlock, fallthrough); |
|
| 2246 | 2246 | } |
|
| 2247 | 2247 | } |
|
| 2248 | 2248 | } |
| 2255 | 2255 | subject: *MatchSubject, |
|
| 2256 | 2256 | patterns: ast::NodeList, |
|
| 2257 | 2257 | matchBlock: BlockId, |
|
| 2258 | 2258 | fallthrough: BlockId |
|
| 2259 | 2259 | ) throws (LowerError) { |
|
| 2260 | - | debug::assert(patterns.len > 0); |
|
| 2260 | + | debug::check(patterns.len > 0); |
|
| 2261 | 2261 | ||
| 2262 | 2262 | for i in 0..(patterns.len - 1) { |
|
| 2263 | 2263 | let pattern = patterns.list[i]; |
|
| 2264 | 2264 | let nextArm = try createBlock(self, "arm"); |
|
| 2265 | 2265 | try emitPatternMatch(self, subject, pattern, matchBlock, nextArm); |
| 2565 | 2565 | /// Define (write) a variable. Record the SSA value of a variable in the |
|
| 2566 | 2566 | /// current block. Called when a variable is assigned or initialized (`let` |
|
| 2567 | 2567 | /// bindings, assignments, loop updates). When [`useVar`] is later called, |
|
| 2568 | 2568 | /// it will retrieve this value. |
|
| 2569 | 2569 | fn defVar(self: *mut FnLowerer, v: Var, val: il::Val) { |
|
| 2570 | - | debug::assert(v.id < self.varsLen); |
|
| 2570 | + | debug::check(v.id < self.varsLen); |
|
| 2571 | 2571 | getBlockMut(self, currentBlock(self)).vars[v.id] = val; |
|
| 2572 | 2572 | } |
|
| 2573 | 2573 | ||
| 2574 | 2574 | /// Use (read) the current value of a variable in the current block. |
|
| 2575 | 2575 | /// May insert block parameters if the value must come from predecessors. |
| 2582 | 2582 | /// Given a variable and a block where it's used, this function finds the |
|
| 2583 | 2583 | /// correct [`il::Val`] that holds the variable's value at that program point. |
|
| 2584 | 2584 | /// When control flow merges from multiple predecessors with different |
|
| 2585 | 2585 | /// definitions, it creates a block parameter to unify them. |
|
| 2586 | 2586 | fn useVarInBlock(self: *mut FnLowerer, block: BlockId, v: Var) -> il::Val throws (LowerError) { |
|
| 2587 | - | debug::assert(v.id < self.varsLen); |
|
| 2587 | + | debug::check(v.id < self.varsLen); |
|
| 2588 | 2588 | ||
| 2589 | 2589 | let blk = getBlockMut(self, block); |
|
| 2590 | 2590 | if let val = blk.vars[v.id] { |
|
| 2591 | 2591 | return val; |
|
| 2592 | 2592 | } |
| 2649 | 2649 | self.varsLen = savedVarsLen; |
|
| 2650 | 2650 | } |
|
| 2651 | 2651 | ||
| 2652 | 2652 | /// Get the metadata for a variable. |
|
| 2653 | 2653 | fn getVar(self: *FnLowerer, v: Var) -> *VarData { |
|
| 2654 | - | debug::assert(v.id < self.varsLen); |
|
| 2654 | + | debug::check(v.id < self.varsLen); |
|
| 2655 | 2655 | return &self.vars[v.id]; |
|
| 2656 | 2656 | } |
|
| 2657 | 2657 | ||
| 2658 | 2658 | /// Create a block parameter to merge a variable's value from multiple |
|
| 2659 | 2659 | /// control flow paths. |
| 2869 | 2869 | let totalLen = fnType.paramTypesLen + offset; |
|
| 2870 | 2870 | ||
| 2871 | 2871 | if totalLen == 0 { |
|
| 2872 | 2872 | return &[]; |
|
| 2873 | 2873 | } |
|
| 2874 | - | debug::assert(fnType.paramTypesLen <= resolver::MAX_FN_PARAMS); |
|
| 2874 | + | debug::check(fnType.paramTypesLen <= resolver::MAX_FN_PARAMS); |
|
| 2875 | 2875 | ||
| 2876 | 2876 | let params = try! alloc::allocSlice( |
|
| 2877 | 2877 | self.low.arena, @sizeOf(il::Param), @alignOf(il::Param), totalLen |
|
| 2878 | 2878 | ) as *mut [il::Param]; |
|
| 2879 | 2879 |
| 3297 | 3297 | /// jmp else#0; // guard failed, fallthrough to `else` |
|
| 3298 | 3298 | /// else#0: |
|
| 3299 | 3299 | /// ret 0; // `else` body |
|
| 3300 | 3300 | /// |
|
| 3301 | 3301 | fn lowerMatch(self: *mut FnLowerer, node: *ast::Node, m: ast::Match) throws (LowerError) { |
|
| 3302 | - | debug::assert(m.prongs.len > 0); |
|
| 3302 | + | debug::check(m.prongs.len > 0); |
|
| 3303 | 3303 | ||
| 3304 | 3304 | let prongs = &m.prongs; |
|
| 3305 | 3305 | // Lower the subject expression once; reused across all arms. |
|
| 3306 | 3306 | let subject = try lowerMatchSubject(self, m.subject); |
|
| 3307 | 3307 | // Merge block created lazily if any arm needs it (i.e., doesn't diverge). |
| 3589 | 3589 | let _ = try lowerExpr(self, expr); |
|
| 3590 | 3590 | } |
|
| 3591 | 3591 | case ast::NodeValue::Panic { .. } => { |
|
| 3592 | 3592 | emit(self, il::Instr::Unreachable); |
|
| 3593 | 3593 | } |
|
| 3594 | + | case ast::NodeValue::Assert { condition, .. } => { |
|
| 3595 | + | // Lower `assert <cond>` as: `if not cond { unreachable; }`. |
|
| 3596 | + | let thenBlock = try createBlock(self, "assert.fail"); |
|
| 3597 | + | let endBlock = try createBlock(self, "assert.ok"); |
|
| 3598 | + | ||
| 3599 | + | // Branch: if condition is `true`, go to `endBlock`; if `false`, go to `thenBlock`. |
|
| 3600 | + | try emitCondBranch(self, condition, endBlock, thenBlock); |
|
| 3601 | + | try sealBlock(self, thenBlock); |
|
| 3602 | + | ||
| 3603 | + | // Emit `unreachable` in the failure block. |
|
| 3604 | + | switchToBlock(self, thenBlock); |
|
| 3605 | + | emit(self, il::Instr::Unreachable); |
|
| 3606 | + | ||
| 3607 | + | // Continue after the assert. |
|
| 3608 | + | try switchToAndSeal(self, endBlock); |
|
| 3609 | + | } |
|
| 3594 | 3610 | else => { |
|
| 3595 | 3611 | // Treat as expression statement, discard result. |
|
| 3596 | 3612 | let _ = try lowerExpr(self, node); |
|
| 3597 | 3613 | } |
|
| 3598 | 3614 | } |
| 4155 | 4171 | let tagBlock = try createBlock(self, "eq#tag"); |
|
| 4156 | 4172 | ||
| 4157 | 4173 | // Compare tags: if they differ, jump to merge with `false`; otherwise check payloads. |
|
| 4158 | 4174 | let falseArgs = try allocVal(self, il::Val::Imm(0)); |
|
| 4159 | 4175 | ||
| 4160 | - | debug::assert(tagBlock != mergeBlock); |
|
| 4176 | + | debug::check(tagBlock != mergeBlock); |
|
| 4161 | 4177 | ||
| 4162 | 4178 | // TODO: Use the helper once the compiler supports more than eight function params. |
|
| 4163 | 4179 | emit(self, il::Instr::Br { |
|
| 4164 | 4180 | op: il::CmpOp::Eq, typ: il::Type::W8, a: tagA, b: tagB, |
|
| 4165 | 4181 | thenTarget: tagBlock.n, thenArgs: &mut [], |
| 5223 | 5239 | try emitRetVal(self, val); |
|
| 5224 | 5240 | } |
|
| 5225 | 5241 | ||
| 5226 | 5242 | /// Lower a throw statement. |
|
| 5227 | 5243 | fn lowerThrowStmt(self: *mut FnLowerer, expr: *ast::Node) throws (LowerError) { |
|
| 5228 | - | debug::assert(self.fnType.throwListLen > 0); |
|
| 5244 | + | debug::check(self.fnType.throwListLen > 0); |
|
| 5229 | 5245 | ||
| 5230 | 5246 | let errType = resolver::typeFor(self.low.resolver, expr) else { |
|
| 5231 | 5247 | throw LowerError::MissingType(expr); |
|
| 5232 | 5248 | }; |
|
| 5233 | 5249 | let tag = getOrAssignErrorTag(self.low, errType) as i64; |
| 6373 | 6389 | // Panic in expression context (e.g. match arm). Emit unreachable |
|
| 6374 | 6390 | // and return a dummy value since control won't continue. |
|
| 6375 | 6391 | emit(self, il::Instr::Unreachable); |
|
| 6376 | 6392 | val = il::Val::Undef; |
|
| 6377 | 6393 | } |
|
| 6394 | + | case ast::NodeValue::Assert { .. } => { |
|
| 6395 | + | // Assert in expression context. Lower as statement, return `void`. |
|
| 6396 | + | try lowerNode(self, node); |
|
| 6397 | + | val = il::Val::Undef; |
|
| 6398 | + | } |
|
| 6378 | 6399 | case ast::NodeValue::Block(_) => { |
|
| 6379 | 6400 | try lowerBlock(self, node); |
|
| 6380 | 6401 | val = il::Val::Undef; |
|
| 6381 | 6402 | } |
|
| 6382 | 6403 | case ast::NodeValue::ExprStmt(expr) => { |
lib/std/lang/lower/tests/assert.basic.rad
added
+5 -0
| 1 | + | /// Test lowering of assert statement. |
|
| 2 | + | fn test(x: bool) -> i32 { |
|
| 3 | + | assert x; |
|
| 4 | + | return 0; |
|
| 5 | + | } |
lib/std/lang/lower/tests/assert.basic.ril
added
+8 -0
| 1 | + | fn w32 $test(w8 %0) { |
|
| 2 | + | @entry0 |
|
| 3 | + | br.ne w32 %0 0 @assert.ok2 @assert.fail1; |
|
| 4 | + | @assert.fail1 |
|
| 5 | + | unreachable; |
|
| 6 | + | @assert.ok2 |
|
| 7 | + | ret 0; |
|
| 8 | + | } |
lib/std/lang/lower/tests/assert.message.rad
added
+5 -0
| 1 | + | /// Test lowering of assert with message. |
|
| 2 | + | fn test(x: i32) -> i32 { |
|
| 3 | + | assert x > 0, "x must be positive"; |
|
| 4 | + | return x; |
|
| 5 | + | } |
lib/std/lang/lower/tests/assert.message.ril
added
+8 -0
| 1 | + | fn w32 $test(w32 %0) { |
|
| 2 | + | @entry0 |
|
| 3 | + | br.slt w32 0 %0 @assert.ok2 @assert.fail1; |
|
| 4 | + | @assert.fail1 |
|
| 5 | + | unreachable; |
|
| 6 | + | @assert.ok2 |
|
| 7 | + | ret %0; |
|
| 8 | + | } |
lib/std/lang/module.rad
+7 -7
| 149 | 149 | graph: *mut ModuleGraph, |
|
| 150 | 150 | parentId: u16, |
|
| 151 | 151 | name: *[u8], |
|
| 152 | 152 | filePath: *[u8] |
|
| 153 | 153 | ) -> u16 throws (ModuleError) { |
|
| 154 | - | debug::assertMsg(name.len > 0, "registerChild: name must not be empty"); |
|
| 155 | - | debug::assertMsg(filePath.len > 0, "registerChild: file path must not be empty"); |
|
| 154 | + | debug::checkMsg(name.len > 0, "registerChild: name must not be empty"); |
|
| 155 | + | debug::checkMsg(filePath.len > 0, "registerChild: file path must not be empty"); |
|
| 156 | 156 | ||
| 157 | 157 | let parent = getMut(graph, parentId) |
|
| 158 | 158 | else throw ModuleError::NotFound(parentId); |
|
| 159 | 159 | ||
| 160 | 160 | // If the child already exists under this parent, return it. |
| 193 | 193 | return &mut graph.entries[id as u32]; |
|
| 194 | 194 | } |
|
| 195 | 195 | ||
| 196 | 196 | /// Return the identifier of the child stored at `index`. |
|
| 197 | 197 | pub fn childAt(m: *ModuleEntry, index: u32) -> u16 { |
|
| 198 | - | debug::assertMsg(index < m.childrenLen, "childAt: index must be valid"); |
|
| 198 | + | debug::checkMsg(index < m.childrenLen, "childAt: index must be valid"); |
|
| 199 | 199 | return m.children[index]; |
|
| 200 | 200 | } |
|
| 201 | 201 | ||
| 202 | 202 | /// Public accessor for a module's directory prefix. |
|
| 203 | 203 | pub fn moduleDir(m: *ModuleEntry) -> *[u8] { |
|
| 204 | 204 | return &m.filePath[..m.dirLen]; |
|
| 205 | 205 | } |
|
| 206 | 206 | ||
| 207 | 207 | /// Public accessor to the logical module path segments. |
|
| 208 | 208 | pub fn moduleQualifiedPath(m: *ModuleEntry) -> *[*[u8]] { |
|
| 209 | - | debug::assertMsg(m.pathDepth > 0, "moduleQualifiedPath: path must not be empty"); |
|
| 209 | + | debug::checkMsg(m.pathDepth > 0, "moduleQualifiedPath: path must not be empty"); |
|
| 210 | 210 | return &m.path[..m.pathDepth]; |
|
| 211 | 211 | } |
|
| 212 | 212 | ||
| 213 | 213 | /// Update the recorded lifecycle state for `id`. |
|
| 214 | 214 | pub fn setState(graph: *mut ModuleGraph, id: u16, state: ModuleState) throws (ModuleError) { |
| 237 | 237 | m.source = source; |
|
| 238 | 238 | } |
|
| 239 | 239 | ||
| 240 | 240 | /// Look up a child module by name under the given parent. |
|
| 241 | 241 | pub fn findChild(graph: *ModuleGraph, name: *[u8], parentId: u16) -> ?*ModuleEntry { |
|
| 242 | - | debug::assertMsg(isValidId(graph, parentId), "findChild: parent identifier is valid"); |
|
| 242 | + | debug::checkMsg(isValidId(graph, parentId), "findChild: parent identifier is valid"); |
|
| 243 | 243 | ||
| 244 | 244 | let parent = &graph.entries[parentId as u32]; |
|
| 245 | 245 | for i in 0..parent.childrenLen { |
|
| 246 | 246 | let childId = parent.children[i]; |
|
| 247 | 247 | let child = &graph.entries[childId as u32]; |
| 261 | 261 | ||
| 262 | 262 | // Split on '/' to extract all but the last component. |
|
| 263 | 263 | for i in 0..filePath.len { |
|
| 264 | 264 | if filePath[i] == PATH_SEP { |
|
| 265 | 265 | if i > last { |
|
| 266 | - | debug::assertMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 266 | + | debug::checkMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 267 | 267 | components[count] = &filePath[last..i]; |
|
| 268 | 268 | count += 1; |
|
| 269 | 269 | } |
|
| 270 | 270 | last = i + 1; |
|
| 271 | 271 | } |
| 273 | 273 | if last >= filePath.len { |
|
| 274 | 274 | return nil; // Path ends with separator or is empty. |
|
| 275 | 275 | } |
|
| 276 | 276 | ||
| 277 | 277 | // Handle the last component by removing extension. |
|
| 278 | - | debug::assertMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 278 | + | debug::checkMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 279 | 279 | if let name = trimExtension(&filePath[last..]) { |
|
| 280 | 280 | components[count] = name; |
|
| 281 | 281 | } else { |
|
| 282 | 282 | return nil; |
|
| 283 | 283 | }; |
lib/std/lang/parser.rad
+31 -2
| 162 | 162 | return node(p, ast::NodeValue::Bool(value)); |
|
| 163 | 163 | } |
|
| 164 | 164 | ||
| 165 | 165 | /// Convert a single ASCII digit into its numeric value for the given radix. |
|
| 166 | 166 | pub fn digitFromAscii(ch: u8, radix: u32) -> ?u32 { |
|
| 167 | - | debug::assert(radix >= 2 and radix <= 36); |
|
| 167 | + | debug::check(radix >= 2 and radix <= 36); |
|
| 168 | 168 | ||
| 169 | 169 | // Default to an out-of-range value so non-digits fall through to `nil`. |
|
| 170 | 170 | let mut value: u32 = 36; |
|
| 171 | 171 | ||
| 172 | 172 | if ch >= '0' and ch <= '9' { |
| 987 | 987 | return try parseThrow(p); |
|
| 988 | 988 | } |
|
| 989 | 989 | case scanner::TokenKind::Panic => { |
|
| 990 | 990 | return try parsePanic(p); |
|
| 991 | 991 | } |
|
| 992 | + | case scanner::TokenKind::Assert => { |
|
| 993 | + | return try parseAssert(p); |
|
| 994 | + | } |
|
| 992 | 995 | case scanner::TokenKind::Break => { |
|
| 993 | 996 | advance(p); |
|
| 994 | 997 | return node(p, ast::NodeValue::Break); |
|
| 995 | 998 | } |
|
| 996 | 999 | case scanner::TokenKind::Continue => { |
| 1130 | 1133 | } |
|
| 1131 | 1134 | } |
|
| 1132 | 1135 | ||
| 1133 | 1136 | /// Report a parser error. |
|
| 1134 | 1137 | fn reportError(p: *mut Parser, token: scanner::Token, message: *[u8]) { |
|
| 1135 | - | debug::assert(message.len > 0); |
|
| 1138 | + | debug::check(message.len > 0); |
|
| 1136 | 1139 | ||
| 1137 | 1140 | // Ignore errors once the error list is full. |
|
| 1138 | 1141 | if p.errors.count < p.errors.list.len { |
|
| 1139 | 1142 | p.errors.list[p.errors.count] = Error { message, token }; |
|
| 1140 | 1143 | p.errors.count += 1; |
| 1351 | 1354 | // `panic` or `panic "message"`. |
|
| 1352 | 1355 | let message: ?*ast::Node = try? parseExpr(p); |
|
| 1353 | 1356 | return node(p, ast::NodeValue::Panic { message }); |
|
| 1354 | 1357 | } |
|
| 1355 | 1358 | ||
| 1359 | + | /// Parse an `assert` statement. |
|
| 1360 | + | /// |
|
| 1361 | + | /// Forms: |
|
| 1362 | + | /// `assert <expr>` |
|
| 1363 | + | /// `assert <expr>, "message"` |
|
| 1364 | + | /// `assert { <expr> }, "message"` |
|
| 1365 | + | fn parseAssert(p: *mut Parser) -> *ast::Node |
|
| 1366 | + | throws (ParseError) |
|
| 1367 | + | { |
|
| 1368 | + | try expect(p, scanner::TokenKind::Assert, "expected `assert`"); |
|
| 1369 | + | ||
| 1370 | + | // `assert { expr }` block form or `assert <expr>`. |
|
| 1371 | + | let mut condition: *ast::Node = undefined; |
|
| 1372 | + | if consume(p, scanner::TokenKind::LBrace) { |
|
| 1373 | + | condition = try parseExpr(p); |
|
| 1374 | + | try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression"); |
|
| 1375 | + | } else { |
|
| 1376 | + | condition = try parseExpr(p); |
|
| 1377 | + | } |
|
| 1378 | + | let mut message: ?*ast::Node = nil; |
|
| 1379 | + | if consume(p, scanner::TokenKind::Comma) { |
|
| 1380 | + | message = try parseExpr(p); |
|
| 1381 | + | } |
|
| 1382 | + | return node(p, ast::NodeValue::Assert { condition, message }); |
|
| 1383 | + | } |
|
| 1384 | + | ||
| 1356 | 1385 | /// Parse a `break` statement. |
|
| 1357 | 1386 | fn parseBreak(p: *mut Parser) -> *ast::Node |
|
| 1358 | 1387 | throws (ParseError) |
|
| 1359 | 1388 | { |
|
| 1360 | 1389 | try expect(p, scanner::TokenKind::Break, "expected `break`"); |
lib/std/lang/resolver.rad
+19 -11
| 2524 | 2524 | item: allocType(self, Type::U8), |
|
| 2525 | 2525 | mutable: false |
|
| 2526 | 2526 | }); |
|
| 2527 | 2527 | return try setNodeType(self, node, Type::Never); |
|
| 2528 | 2528 | }, |
|
| 2529 | + | case ast::NodeValue::Assert { condition, message } => { |
|
| 2530 | + | try visit(self, condition, Type::Bool); |
|
| 2531 | + | try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type. |
|
| 2532 | + | item: allocType(self, Type::U8), |
|
| 2533 | + | mutable: false |
|
| 2534 | + | }); |
|
| 2535 | + | return try setNodeType(self, node, Type::Void); |
|
| 2536 | + | }, |
|
| 2529 | 2537 | case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop), |
|
| 2530 | 2538 | case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop), |
|
| 2531 | 2539 | case ast::NodeValue::ExprStmt(expr) => { |
|
| 2532 | 2540 | // Pass `Void` as expected type to indicate value is discarded. |
|
| 2533 | 2541 | let exprTy = try visit(self, expr, Type::Void); |
| 2713 | 2721 | if let a = decl.alignment { |
|
| 2714 | 2722 | let case ast::NodeValue::Align { value } = a.value |
|
| 2715 | 2723 | else panic "resolveLet: expected Align node"; |
|
| 2716 | 2724 | alignment = try checkSizeInt(self, value); |
|
| 2717 | 2725 | } |
|
| 2718 | - | debug::assert(bindingTy != Type::Unknown); |
|
| 2726 | + | debug::check(bindingTy != Type::Unknown); |
|
| 2719 | 2727 | ||
| 2720 | 2728 | // Alignment must be zero or a power of two. |
|
| 2721 | 2729 | if alignment != 0 and (alignment & (alignment - 1)) != 0 { |
|
| 2722 | 2730 | throw emitError(self, decl.value, ErrorKind::InvalidAlignmentValue(alignment)); |
|
| 2723 | 2731 | } |
| 2874 | 2882 | ||
| 2875 | 2883 | // Validate it fits within u32 range. |
|
| 2876 | 2884 | if not validateConstIntRange(value, Type::U32) { |
|
| 2877 | 2885 | throw emitError(self, node, ErrorKind::NumericLiteralOverflow); |
|
| 2878 | 2886 | } |
|
| 2879 | - | debug::assert(not int.negative); |
|
| 2887 | + | debug::check(not int.negative); |
|
| 2880 | 2888 | try setNodeType(self, node, Type::U32); |
|
| 2881 | 2889 | ||
| 2882 | 2890 | return int.magnitude as u32; |
|
| 2883 | 2891 | } |
|
| 2884 | 2892 |
| 4175 | 4183 | actual: call.args.len, |
|
| 4176 | 4184 | })); |
|
| 4177 | 4185 | } |
|
| 4178 | 4186 | // TODO: Check what happens when we exceed `MAX_FN_PARAMS`. |
|
| 4179 | 4187 | for i in 0..call.args.len { |
|
| 4180 | - | debug::assert(i < MAX_FN_PARAMS); |
|
| 4188 | + | debug::check(i < MAX_FN_PARAMS); |
|
| 4181 | 4189 | ||
| 4182 | 4190 | let argNode = call.args.list[i]; |
|
| 4183 | 4191 | let expectedTy = *info.paramTypes[i]; |
|
| 4184 | 4192 | try checkAssignable(self, argNode, expectedTy); |
|
| 4185 | 4193 | } |
| 4503 | 4511 | expectedTy = *ary.item; |
|
| 4504 | 4512 | }; |
|
| 4505 | 4513 | for i in 0..length { |
|
| 4506 | 4514 | let itemNode = items.list[i]; |
|
| 4507 | 4515 | let itemTy = try visit(self, itemNode, expectedTy); |
|
| 4508 | - | debug::assert(itemTy != Type::Unknown); |
|
| 4516 | + | debug::check(itemTy != Type::Unknown); |
|
| 4509 | 4517 | ||
| 4510 | 4518 | // Set the expected type to the first type we encounter. |
|
| 4511 | 4519 | if expectedTy == Type::Unknown { |
|
| 4512 | 4520 | expectedTy = itemTy; |
|
| 4513 | 4521 | } else { |
| 4889 | 4897 | throws (ResolveError) |
|
| 4890 | 4898 | { |
|
| 4891 | 4899 | let targetTy = try infer(self, expr.type); |
|
| 4892 | 4900 | let sourceTy = try visit(self, expr.value, targetTy); |
|
| 4893 | 4901 | ||
| 4894 | - | debug::assert(sourceTy != Type::Unknown); |
|
| 4895 | - | debug::assert(targetTy != Type::Unknown); |
|
| 4902 | + | debug::check(sourceTy != Type::Unknown); |
|
| 4903 | + | debug::check(targetTy != Type::Unknown); |
|
| 4896 | 4904 | ||
| 4897 | 4905 | if isValidCast(sourceTy, targetTy) { |
|
| 4898 | 4906 | return try setNodeType(self, node, targetTy); |
|
| 4899 | 4907 | } |
|
| 4900 | 4908 | throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast { |
| 5367 | 5375 | returnType: allocType(self, Type::Void), |
|
| 5368 | 5376 | throwList: undefined, |
|
| 5369 | 5377 | throwListLen: 0, |
|
| 5370 | 5378 | localCount: 0, |
|
| 5371 | 5379 | }; |
|
| 5372 | - | debug::assert(t.params.len <= fnType.paramTypes.len); |
|
| 5373 | - | debug::assert(t.throwList.len <= fnType.throwList.len); |
|
| 5380 | + | debug::check(t.params.len <= fnType.paramTypes.len); |
|
| 5381 | + | debug::check(t.throwList.len <= fnType.throwList.len); |
|
| 5374 | 5382 | ||
| 5375 | 5383 | for i in 0..t.params.len { |
|
| 5376 | 5384 | let paramTy = try infer(self, t.params.list[i]); |
|
| 5377 | 5385 | ||
| 5378 | 5386 | fnType.paramTypes[fnType.paramTypesLen] = allocType(self, paramTy); |
| 5623 | 5631 | let case ast::NodeValue::Block(block) = node.value |
|
| 5624 | 5632 | else panic "resolvePackage: expected block for module root"; |
|
| 5625 | 5633 | ||
| 5626 | 5634 | // Module graph analysis phase: bind all module name symbols and scopes. |
|
| 5627 | 5635 | try resolveModuleGraph(self, &block) catch { |
|
| 5628 | - | debug::assertMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5636 | + | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5629 | 5637 | return Diagnostics { errors: self.errors }; |
|
| 5630 | 5638 | }; |
|
| 5631 | 5639 | ||
| 5632 | 5640 | // Declaration phase: bind all names and analyze top-level declarations. |
|
| 5633 | 5641 | try resolveModuleDecls(self, &block) catch { |
|
| 5634 | - | debug::assertMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5642 | + | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5635 | 5643 | }; |
|
| 5636 | 5644 | if self.errors.listLen > 0 { |
|
| 5637 | 5645 | return Diagnostics { errors: self.errors }; |
|
| 5638 | 5646 | } |
|
| 5639 | 5647 | ||
| 5640 | 5648 | // Definition phase: analyze function bodies and sub-module definitions. |
|
| 5641 | 5649 | try resolveModuleDefs(self, &block) catch { |
|
| 5642 | - | debug::assertMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5650 | + | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 5643 | 5651 | }; |
|
| 5644 | 5652 | try setNodeType(self, node, Type::Void); |
|
| 5645 | 5653 | ||
| 5646 | 5654 | return Diagnostics { errors: self.errors }; |
|
| 5647 | 5655 | } |
lib/std/lang/scanner.rad
+4 -3
| 89 | 89 | ||
| 90 | 90 | // Control flow tokens. |
|
| 91 | 91 | If, Else, Return, Break, |
|
| 92 | 92 | Continue, While, For, In, |
|
| 93 | 93 | Loop, Match, Case, Try, Catch, |
|
| 94 | - | Throw, Throws, Panic, |
|
| 94 | + | Throw, Throws, Panic, Assert, |
|
| 95 | 95 | ||
| 96 | 96 | // Variable binding tokens. |
|
| 97 | 97 | Let, Mut, Const, Align, |
|
| 98 | 98 | ||
| 99 | 99 | // Module-related tokens. |
| 185 | 185 | case TokenKind::Try => return "Try", |
|
| 186 | 186 | case TokenKind::Catch => return "Catch", |
|
| 187 | 187 | case TokenKind::Throw => return "Throw", |
|
| 188 | 188 | case TokenKind::Throws => return "Throws", |
|
| 189 | 189 | case TokenKind::Panic => return "Panic", |
|
| 190 | + | case TokenKind::Assert => return "Assert", |
|
| 190 | 191 | case TokenKind::Let => return "Let", |
|
| 191 | 192 | case TokenKind::Mut => return "Mut", |
|
| 192 | 193 | case TokenKind::Const => return "Const", |
|
| 193 | 194 | case TokenKind::Align => return "Align", |
|
| 194 | 195 | case TokenKind::Mod => return "Mod", |
| 222 | 223 | /// Corresponding token. |
|
| 223 | 224 | tok: TokenKind, |
|
| 224 | 225 | } |
|
| 225 | 226 | ||
| 226 | 227 | /// Sorted keyword table for binary search. |
|
| 227 | - | const KEYWORDS: [Keyword; 49] = [ |
|
| 228 | + | const KEYWORDS: [Keyword; 50] = [ |
|
| 228 | 229 | { name: "align", tok: TokenKind::Align }, |
|
| 229 | 230 | { name: "and", tok: TokenKind::And }, |
|
| 230 | 231 | { name: "as", tok: TokenKind::As }, |
|
| 232 | + | { name: "assert", tok: TokenKind::Assert }, |
|
| 231 | 233 | { name: "bool", tok: TokenKind::Bool }, |
|
| 232 | 234 | { name: "break", tok: TokenKind::Break }, |
|
| 233 | 235 | { name: "case", tok: TokenKind::Case }, |
|
| 234 | 236 | { name: "catch", tok: TokenKind::Catch }, |
|
| 235 | 237 | { name: "const", tok: TokenKind::Const }, |
| 274 | 276 | { name: "use", tok: TokenKind::Use }, |
|
| 275 | 277 | { name: "void", tok: TokenKind::Void }, |
|
| 276 | 278 | { name: "while", tok: TokenKind::While }, |
|
| 277 | 279 | ]; |
|
| 278 | 280 | ||
| 279 | - | ||
| 280 | 281 | /// Lexical scanner state for tokenizing Radiance source code. |
|
| 281 | 282 | /// |
|
| 282 | 283 | /// Maintains position information and source buffer reference. |
|
| 283 | 284 | pub record Scanner { |
|
| 284 | 285 | /// File path. |
lib/std/vec.rad
+4 -4
| 24 | 24 | /// |
|
| 25 | 25 | /// * `arena` is a pointer to static array backing storage. |
|
| 26 | 26 | /// * `stride` is the size of each element. |
|
| 27 | 27 | /// * `alignment` is the required alignment for elements. |
|
| 28 | 28 | pub fn new(arena: *mut [u8], stride: u32, alignment: u32) -> RawVec { |
|
| 29 | - | debug::assert(stride > 0); |
|
| 30 | - | debug::assert(alignment > 0); |
|
| 31 | - | debug::assert((arena.ptr as u32) % alignment == 0); |
|
| 32 | - | debug::assert((arena.len % stride) == 0); |
|
| 29 | + | debug::check(stride > 0); |
|
| 30 | + | debug::check(alignment > 0); |
|
| 31 | + | debug::check((arena.ptr as u32) % alignment == 0); |
|
| 32 | + | debug::check((arena.len % stride) == 0); |
|
| 33 | 33 | ||
| 34 | 34 | return RawVec { data: arena, len: 0, stride, alignment }; |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | /// Get the current number of elements in the vector. |
vim/radiance.vim
+1 -1
| 16 | 16 | ||
| 17 | 17 | " Keywords |
|
| 18 | 18 | syntax keyword radianceKeyword mod fn return if else while true false and or not case align static |
|
| 19 | 19 | syntax keyword radianceKeyword pub extern break continue use loop in for match nil undefined |
|
| 20 | 20 | syntax keyword radianceKeyword let mut as register device const log record union |
|
| 21 | - | syntax keyword radianceKeyword throws throw try catch panic super |
|
| 21 | + | syntax keyword radianceKeyword throws throw try catch panic assert super |
|
| 22 | 22 | syntax keyword radianceType i8 i16 i32 i64 u8 u16 u32 u64 f32 void bool bit opaque |
|
| 23 | 23 | ||
| 24 | 24 | " Double-quoted strings |
|
| 25 | 25 | syntax region radianceString start=/"/ skip=/\\"/ end=/"/ contains=radianceEscape |
|
| 26 | 26 | " Characters |