Use `assert` keyword throughout compiler
7a8ab6ad4fb655460a4afe56c055efc1b4d73b4322bae437a51d56884d6d25e0
1 parent
16d67a26
lib/std.rad
+0 -1
| 2 | 2 | ||
| 3 | 3 | pub mod io; |
|
| 4 | 4 | pub mod collections; |
|
| 5 | 5 | pub mod lang; |
|
| 6 | 6 | pub mod sys; |
|
| 7 | - | pub mod debug; |
|
| 8 | 7 | pub mod arch; |
|
| 9 | 8 | pub mod fmt; |
|
| 10 | 9 | pub mod mem; |
|
| 11 | 10 | pub mod vec; |
|
| 12 | 11 | pub mod intrinsics; |
lib/std/arch/rv64.rad
+1 -2
| 16 | 16 | pub mod isel; |
|
| 17 | 17 | pub mod printer; |
|
| 18 | 18 | ||
| 19 | 19 | @test mod tests; |
|
| 20 | 20 | ||
| 21 | - | use std::debug; |
|
| 22 | 21 | use std::mem; |
|
| 23 | 22 | use std::lang::il; |
|
| 24 | 23 | use std::lang::alloc; |
|
| 25 | 24 | use std::lang::gen::labels; |
|
| 26 | 25 | use std::lang::gen::regalloc; |
| 66 | 65 | pub const T5: Reg = { n: 30 }; /// Temporary. |
|
| 67 | 66 | pub const T6: Reg = { n: 31 }; /// Temporary. |
|
| 68 | 67 | ||
| 69 | 68 | /// Create a register from a number. Panics if `n > 31`. |
|
| 70 | 69 | pub fn reg(n: u8) -> Reg { |
|
| 71 | - | debug::check(n < 32); |
|
| 70 | + | assert n < 32; |
|
| 72 | 71 | return Reg { n }; |
|
| 73 | 72 | } |
|
| 74 | 73 | ||
| 75 | 74 | //////////////////////////// |
|
| 76 | 75 | // Architecture constants // |
lib/std/arch/rv64/emit.rad
+2 -3
| 1 | 1 | //! RV64 binary emission. |
|
| 2 | 2 | //! |
|
| 3 | 3 | //! Emits RV64 machine code as `u32` list. |
|
| 4 | 4 | ||
| 5 | - | use std::debug; |
|
| 6 | 5 | use std::lang::il; |
|
| 7 | 6 | use std::lang::alloc; |
|
| 8 | 7 | use std::lang::gen::labels; |
|
| 9 | 8 | use std::collections::dict; |
|
| 10 | 9 | use std::mem; |
| 232 | 231 | e.code[index] = instr; |
|
| 233 | 232 | } |
|
| 234 | 233 | ||
| 235 | 234 | /// Record a block's address for branch resolution. |
|
| 236 | 235 | pub fn recordBlock(e: *mut Emitter, blockIdx: u32) { |
|
| 237 | - | debug::check(e.codeLen <= MAX_CODE_LEN); |
|
| 236 | + | assert e.codeLen <= MAX_CODE_LEN; |
|
| 238 | 237 | labels::recordBlock(&mut e.labels, blockIdx, e.codeLen as i32 * super::INSTR_SIZE); |
|
| 239 | 238 | } |
|
| 240 | 239 | ||
| 241 | 240 | /// Record a function's code offset for call resolution. |
|
| 242 | 241 | pub fn recordFuncOffset(e: *mut Emitter, name: *[u8]) { |
|
| 243 | - | debug::check(e.codeLen <= MAX_CODE_LEN); |
|
| 242 | + | assert e.codeLen <= MAX_CODE_LEN; |
|
| 244 | 243 | dict::insert(&mut e.labels.funcs, name, e.codeLen as i32 * super::INSTR_SIZE); |
|
| 245 | 244 | } |
|
| 246 | 245 | ||
| 247 | 246 | /// Record a function's start position for printing. |
|
| 248 | 247 | pub fn recordFunc(e: *mut Emitter, name: *[u8]) { |
lib/std/arch/rv64/encode.rad
+10 -12
| 1 | 1 | //! RISC-V RV64I+M instruction encoding. |
|
| 2 | 2 | //! |
|
| 3 | 3 | //! Provides type-safe functions for encoding RV64 instructions. |
|
| 4 | 4 | ||
| 5 | - | use std::debug; |
|
| 6 | - | ||
| 7 | 5 | ////////////////////// |
|
| 8 | 6 | // Opcode Constants // |
|
| 9 | 7 | ////////////////////// |
|
| 10 | 8 | ||
| 11 | 9 | pub const OP_LOAD: u32 = 0x03; |
| 104 | 102 | | ((funct7 & 0x7F) << 25); |
|
| 105 | 103 | } |
|
| 106 | 104 | ||
| 107 | 105 | /// Encode an I-type instruction. |
|
| 108 | 106 | fn encodeI(opcode: u32, rd: super::Reg, rs1: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 109 | - | debug::check(isSmallImm(imm)); |
|
| 107 | + | assert isSmallImm(imm); |
|
| 110 | 108 | ||
| 111 | 109 | return (opcode & 0x7F) |
|
| 112 | 110 | | ((rd.n as u32 & 0x1F) << 7) |
|
| 113 | 111 | | ((funct3 & 0x07) << 12) |
|
| 114 | 112 | | ((rs1.n as u32 & 0x1F) << 15) |
|
| 115 | 113 | | ((imm as u32 & 0xFFF) << 20); |
|
| 116 | 114 | } |
|
| 117 | 115 | ||
| 118 | 116 | /// Encode an S-type instruction. |
|
| 119 | 117 | fn encodeS(opcode: u32, rs1: super::Reg, rs2: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 120 | - | debug::check(isSmallImm(imm)); |
|
| 118 | + | assert isSmallImm(imm); |
|
| 121 | 119 | ||
| 122 | 120 | return (opcode & 0x7F) |
|
| 123 | 121 | | ((imm as u32 & 0x1F) << 7) |
|
| 124 | 122 | | ((funct3 & 0x07) << 12) |
|
| 125 | 123 | | ((rs1.n as u32 & 0x1F) << 15) |
| 127 | 125 | | ((imm as u32 >> 5 & 0x7F) << 25); |
|
| 128 | 126 | } |
|
| 129 | 127 | ||
| 130 | 128 | /// Encode a B-type (branch) instruction. |
|
| 131 | 129 | fn encodeB(opcode: u32, rs1: super::Reg, rs2: super::Reg, funct3: u32, imm: i32) -> u32 { |
|
| 132 | - | debug::check(isBranchImm(imm)); |
|
| 130 | + | assert isBranchImm(imm); |
|
| 133 | 131 | ||
| 134 | 132 | let imm11 = (imm as u32 >> 11) & 0x1; |
|
| 135 | 133 | let imm4_1 = (imm as u32 >> 1) & 0xF; |
|
| 136 | 134 | let imm10_5 = (imm as u32 >> 5) & 0x3F; |
|
| 137 | 135 | let imm12 = (imm as u32 >> 12) & 0x1; |
| 153 | 151 | | ((imm as u32 & 0xFFFFF) << 12); |
|
| 154 | 152 | } |
|
| 155 | 153 | ||
| 156 | 154 | /// Encode a J-type (jump) instruction. |
|
| 157 | 155 | fn encodeJ(opcode: u32, rd: super::Reg, imm: i32) -> u32 { |
|
| 158 | - | debug::check(isJumpImm(imm)); |
|
| 156 | + | assert isJumpImm(imm); |
|
| 159 | 157 | ||
| 160 | 158 | let imm20 = (imm as u32 >> 20) & 0x1; |
|
| 161 | 159 | let imm10_1 = (imm as u32 >> 1) & 0x3FF; |
|
| 162 | 160 | let imm11 = (imm as u32 >> 11) & 0x1; |
|
| 163 | 161 | let imm19_12 = (imm as u32 >> 12) & 0xFF; |
| 204 | 202 | return encodeI(OP_IMM, rd, rs1, F3_AND, imm); |
|
| 205 | 203 | } |
|
| 206 | 204 | ||
| 207 | 205 | /// Shift left logical immediate: `rd = rs1 << shamt`. |
|
| 208 | 206 | pub fn slli(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 209 | - | debug::check(shamt >= 0 and shamt < 64); |
|
| 207 | + | assert shamt >= 0 and shamt < 64; |
|
| 210 | 208 | return encodeI(OP_IMM, rd, rs1, F3_SLL, shamt & 0x3F); |
|
| 211 | 209 | } |
|
| 212 | 210 | ||
| 213 | 211 | /// Shift right logical immediate: `rd = rs1 >> shamt` (zero-extend). |
|
| 214 | 212 | pub fn srli(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 215 | - | debug::check(shamt >= 0 and shamt < 64); |
|
| 213 | + | assert shamt >= 0 and shamt < 64; |
|
| 216 | 214 | return encodeI(OP_IMM, rd, rs1, F3_SRL, shamt & 0x3F); |
|
| 217 | 215 | } |
|
| 218 | 216 | ||
| 219 | 217 | /// Shift right arithmetic immediate: `rd = rs1 >> shamt` (sign-extend). |
|
| 220 | 218 | pub fn srai(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 221 | - | debug::check(shamt >= 0 and shamt < 64); |
|
| 219 | + | assert shamt >= 0 and shamt < 64; |
|
| 222 | 220 | // SRAI has bit 10 set in immediate field (becomes bit 30 in instruction) |
|
| 223 | 221 | return encodeI(OP_IMM, rd, rs1, F3_SRL, (shamt & 0x3F) | 0b10000000000); |
|
| 224 | 222 | } |
|
| 225 | 223 | ||
| 226 | 224 | /////////////////////////// |
| 330 | 328 | return encodeI(OP_IMM32, rd, rs1, F3_ADD, imm); |
|
| 331 | 329 | } |
|
| 332 | 330 | ||
| 333 | 331 | /// Shift left logical immediate word: `rd = sign_ext((rs1 << shamt)[31:0])`. |
|
| 334 | 332 | pub fn slliw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 335 | - | debug::check(shamt >= 0 and shamt < 32); |
|
| 333 | + | assert shamt >= 0 and shamt < 32; |
|
| 336 | 334 | return encodeI(OP_IMM32, rd, rs1, F3_SLL, shamt & 0x1F); |
|
| 337 | 335 | } |
|
| 338 | 336 | ||
| 339 | 337 | /// Shift right logical immediate word: `rd = sign_ext((rs1[31:0] >> shamt))`. |
|
| 340 | 338 | pub fn srliw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 341 | - | debug::check(shamt >= 0 and shamt < 32); |
|
| 339 | + | assert shamt >= 0 and shamt < 32; |
|
| 342 | 340 | return encodeI(OP_IMM32, rd, rs1, F3_SRL, shamt & 0x1F); |
|
| 343 | 341 | } |
|
| 344 | 342 | ||
| 345 | 343 | /// Shift right arithmetic immediate word: `rd = sign_ext((rs1[31:0] >> shamt))` (sign-extended). |
|
| 346 | 344 | pub fn sraiw(rd: super::Reg, rs1: super::Reg, shamt: i32) -> u32 { |
|
| 347 | - | debug::check(shamt >= 0 and shamt < 32); |
|
| 345 | + | assert shamt >= 0 and shamt < 32; |
|
| 348 | 346 | return encodeI(OP_IMM32, rd, rs1, F3_SRL, (shamt & 0x1F) | 0b10000000000); |
|
| 349 | 347 | } |
|
| 350 | 348 | ||
| 351 | 349 | /// Add word: `rd = sign_ext((rs1 + rs2)[31:0])`. |
|
| 352 | 350 | pub fn addw(rd: super::Reg, rs1: super::Reg, rs2: super::Reg) -> u32 { |
lib/std/arch/rv64/isel.rad
+1 -2
| 26 | 26 | //! loadVal(rd, val) -> Reg |
|
| 27 | 27 | //! Force an [`il::Val`] into a specific register `rd`. Built on [`resolveVal`] + [`emitMv`]. |
|
| 28 | 28 | //! Used when the instruction requires the value in `rd` (e.g. `sub rd, rd, rs2`). |
|
| 29 | 29 | ||
| 30 | 30 | use std::mem; |
|
| 31 | - | use std::debug; |
|
| 32 | 31 | use std::lang::il; |
|
| 33 | 32 | use std::lang::gen::regalloc; |
|
| 34 | 33 | use std::lang::gen::labels; |
|
| 35 | 34 | ||
| 36 | 35 | use super::encode; |
| 389 | 388 | ||
| 390 | 389 | emit::emit(s.e, encode::sub(super::SP, super::SP, rs)); |
|
| 391 | 390 | ||
| 392 | 391 | if alignment > 1 { |
|
| 393 | 392 | let mask = 0 - alignment as i32; |
|
| 394 | - | debug::check(encode::isSmallImm(mask)); |
|
| 393 | + | assert encode::isSmallImm(mask); |
|
| 395 | 394 | ||
| 396 | 395 | emit::emit(s.e, encode::andi(super::SP, super::SP, mask)); |
|
| 397 | 396 | } |
|
| 398 | 397 | emit::emit(s.e, encode::mv(rd, super::SP)); |
|
| 399 | 398 | }, |
lib/std/arch/rv64/tests/assert.false.rad
added
+6 -0
| 1 | + | //! returns: 133 |
|
| 2 | + | //! Test that assert with a false condition triggers EBREAK. |
|
| 3 | + | @default fn main() -> i32 { |
|
| 4 | + | assert false; |
|
| 5 | + | return 0; |
|
| 6 | + | } |
lib/std/arch/rv64/tests/assert.true.rad
added
+8 -0
| 1 | + | ||
| 2 | + | @default fn main() -> i32 { |
|
| 3 | + | assert true; |
|
| 4 | + | assert 1 == 1; |
|
| 5 | + | assert 5 > 3; |
|
| 6 | + | ||
| 7 | + | return 0; |
|
| 8 | + | } |
lib/std/arch/rv64/tests/debug.assert.true.rad
deleted
+0 -8
| 1 | - | ||
| 2 | - | @default fn main() -> i32 { |
|
| 3 | - | if not (true) { panic "assert"; } |
|
| 4 | - | if not (1 == 1) { panic "assert"; } |
|
| 5 | - | if not (5 > 3) { panic "assert"; } |
|
| 6 | - | ||
| 7 | - | return 0; |
|
| 8 | - | } |
lib/std/arch/rv64/tests/error.try.catch.binding.rad
+6 -7
| 1 | 1 | ||
| 2 | - | ||
| 3 | 2 | union TestError { Boom, Bust } |
|
| 4 | 3 | ||
| 5 | 4 | @default fn main() -> u32 { |
|
| 6 | 5 | // Test catching and using the error value. |
|
| 7 | 6 | let mut caught: u32 = 0; |
| 10 | 9 | caught = 1; |
|
| 11 | 10 | } else { |
|
| 12 | 11 | caught = 2; |
|
| 13 | 12 | } |
|
| 14 | 13 | }; |
|
| 15 | - | if not (caught == 1) { panic "assert"; } |
|
| 14 | + | assert caught == 1; |
|
| 16 | 15 | ||
| 17 | 16 | // Test catching a different error variant. |
|
| 18 | 17 | caught = 0; |
|
| 19 | 18 | try failWithBust() catch e { |
|
| 20 | 19 | if (e == TestError::Bust) { |
|
| 21 | 20 | caught = 10; |
|
| 22 | 21 | } else { |
|
| 23 | 22 | caught = 20; |
|
| 24 | 23 | } |
|
| 25 | 24 | }; |
|
| 26 | - | if not (caught == 10) { panic "assert"; } |
|
| 25 | + | assert caught == 10; |
|
| 27 | 26 | ||
| 28 | 27 | // Test that success path doesn't execute catch block. |
|
| 29 | 28 | caught = 0; |
|
| 30 | 29 | try succeed() catch e { |
|
| 31 | 30 | caught = 99; |
|
| 32 | 31 | }; |
|
| 33 | - | if not (caught == 0) { panic "assert"; } |
|
| 32 | + | assert caught == 0; |
|
| 34 | 33 | ||
| 35 | 34 | // Test catch block that returns early from function. |
|
| 36 | 35 | let early: u32 = testCatchReturn(); |
|
| 37 | - | if not (early == 100) { panic "assert"; } |
|
| 36 | + | assert early == 100; |
|
| 38 | 37 | ||
| 39 | 38 | // Test using success value when catch diverges. |
|
| 40 | 39 | let success: u32 = testCatchDiverges(); |
|
| 41 | - | if not (success == 77) { panic "assert"; } |
|
| 40 | + | assert success == 77; |
|
| 42 | 41 | ||
| 43 | 42 | // Test error value is correctly bound. |
|
| 44 | 43 | let errVal: u32 = testErrorValue(); |
|
| 45 | - | if not (errVal == 1) { panic "assert"; } |
|
| 44 | + | assert errVal == 1; |
|
| 46 | 45 | ||
| 47 | 46 | return 0; |
|
| 48 | 47 | } |
|
| 49 | 48 | ||
| 50 | 49 | fn failWithBoom() throws (TestError) { |
lib/std/arch/rv64/tests/debug.assert.false.rad → lib/std/arch/rv64/tests/panic.rad
renamed
+0 -0
lib/std/arch/rv64/tests/string.escape.rad
+7 -21
| 1 | 1 | //! Test string escape sequences. |
|
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let s1: *[u8] = "Hello\tWorld!\n"; |
|
| 4 | - | if s1.len != 13 { |
|
| 5 | - | panic; |
|
| 6 | - | } |
|
| 4 | + | assert s1.len == 13; |
|
| 7 | 5 | ||
| 8 | 6 | let s2: *[u8] = "\""; |
|
| 9 | - | if s2.len != 1 { |
|
| 10 | - | panic; |
|
| 11 | - | } |
|
| 12 | - | if s2[0] != '"' { |
|
| 13 | - | panic; |
|
| 14 | - | } |
|
| 7 | + | assert s2.len == 1; |
|
| 8 | + | assert s2[0] == '"'; |
|
| 15 | 9 | ||
| 16 | 10 | let s3: *[u8] = "\"\\\""; |
|
| 17 | - | if s3.len != 3 { |
|
| 18 | - | panic; |
|
| 19 | - | } |
|
| 20 | - | if s3[0] != '"' { |
|
| 21 | - | panic; |
|
| 22 | - | } |
|
| 23 | - | if s3[1] != '\\' { |
|
| 24 | - | panic; |
|
| 25 | - | } |
|
| 26 | - | if s3[2] != '"' { |
|
| 27 | - | panic; |
|
| 28 | - | } |
|
| 11 | + | assert s3.len == 3; |
|
| 12 | + | assert s3[0] == '"'; |
|
| 13 | + | assert s3[1] == '\\'; |
|
| 14 | + | assert s3[2] == '"'; |
|
| 29 | 15 | return 0; |
|
| 30 | 16 | } |
lib/std/arch/rv64/tests/var.infer.rad
+5 -6
| 1 | 1 | ||
| 2 | - | ||
| 3 | 2 | record Pair { |
|
| 4 | 3 | left: bool, |
|
| 5 | 4 | right: bool, |
|
| 6 | 5 | } |
|
| 7 | 6 |
| 17 | 16 | return 5; |
|
| 18 | 17 | } |
|
| 19 | 18 | ||
| 20 | 19 | @default fn main() -> i32 { |
|
| 21 | 20 | let inferredFlag = alwaysTrue(); |
|
| 22 | - | if not (inferredFlag) { panic "assert"; } |
|
| 21 | + | assert inferredFlag; |
|
| 23 | 22 | ||
| 24 | 23 | let mut counter = returnsCount(); |
|
| 25 | 24 | counter += 1; |
|
| 26 | - | if not (counter == 6) { panic "assert"; } |
|
| 25 | + | assert counter == 6; |
|
| 27 | 26 | ||
| 28 | 27 | let pair = loadPair(); |
|
| 29 | 28 | let left = pair.left; |
|
| 30 | 29 | ||
| 31 | - | if not (left) { panic "assert"; } |
|
| 32 | - | if not (not pair.right) { panic "assert"; } |
|
| 30 | + | assert left; |
|
| 31 | + | assert not pair.right; |
|
| 33 | 32 | ||
| 34 | 33 | let copy = inferredFlag; |
|
| 35 | - | if not (copy) { panic "assert"; } |
|
| 34 | + | assert copy; |
|
| 36 | 35 | ||
| 37 | 36 | return 0; |
|
| 38 | 37 | } |
lib/std/debug.rad
deleted
+0 -14
| 1 | - | // TODO: Re-export `core::debug::*`. |
|
| 2 | - | use super::intrinsics; |
|
| 3 | - | ||
| 4 | - | /// Check that a condition is true, otherwise trigger a breakpoint. |
|
| 5 | - | pub fn check(cond: bool) { |
|
| 6 | - | if not cond { |
|
| 7 | - | intrinsics::ebreak(); |
|
| 8 | - | } |
|
| 9 | - | } |
|
| 10 | - | ||
| 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); |
|
| 14 | - | } |
lib/std/fmt.rad
+4 -5
| 1 | 1 | //! Formatting utilities for converting values to strings. |
|
| 2 | 2 | use super::mem; |
|
| 3 | - | use super::debug; |
|
| 4 | 3 | ||
| 5 | 4 | /// Maximum string length for a formatted u32 (eg. "4294967295"). |
|
| 6 | 5 | pub const U32_STR_LEN: u32 = 10; |
|
| 7 | 6 | /// Maximum string length for a formatted i32 (eg. "-2147483648"). |
|
| 8 | 7 | pub const I32_STR_LEN: u32 = 11; |
| 13 | 12 | /// Maximum string length for a formatted bool (eg. "false"). |
|
| 14 | 13 | pub const BOOL_STR_LEN: u32 = 5; |
|
| 15 | 14 | ||
| 16 | 15 | /// Format a u32 by writing it to the provided buffer. |
|
| 17 | 16 | pub fn formatU32(val: u32, buffer: *mut [u8]) -> *[u8] { |
|
| 18 | - | debug::check(buffer.len >= U32_STR_LEN); |
|
| 17 | + | assert buffer.len >= U32_STR_LEN; |
|
| 19 | 18 | ||
| 20 | 19 | let mut x: u32 = val; |
|
| 21 | 20 | let mut i: u32 = buffer.len; |
|
| 22 | 21 | ||
| 23 | 22 | // Handle the zero case separately to ensure a single '0' is written. |
| 37 | 36 | return &buffer[i..]; |
|
| 38 | 37 | } |
|
| 39 | 38 | ||
| 40 | 39 | /// Format a i32 by writing it to the provided buffer. |
|
| 41 | 40 | pub fn formatI32(val: i32, buffer: *mut [u8]) -> *[u8] { |
|
| 42 | - | debug::check(buffer.len >= I32_STR_LEN); |
|
| 41 | + | assert buffer.len >= I32_STR_LEN; |
|
| 43 | 42 | ||
| 44 | 43 | let neg: bool = val < 0; |
|
| 45 | 44 | let mut x: u32 = -val as u32 if neg else val as u32; |
|
| 46 | 45 | let mut i: u32 = buffer.len; |
|
| 47 | 46 | // Handle the zero case separately to ensure a single '0' is written. |
| 64 | 63 | return &buffer[i..]; |
|
| 65 | 64 | } |
|
| 66 | 65 | ||
| 67 | 66 | /// Format a u64 by writing it to the provided buffer. |
|
| 68 | 67 | pub fn formatU64(val: u64, buffer: *mut [u8]) -> *[u8] { |
|
| 69 | - | debug::check(buffer.len >= U64_STR_LEN); |
|
| 68 | + | assert buffer.len >= U64_STR_LEN; |
|
| 70 | 69 | ||
| 71 | 70 | let mut x: u64 = val; |
|
| 72 | 71 | let mut i: u32 = buffer.len; |
|
| 73 | 72 | ||
| 74 | 73 | if x == 0 { |
| 84 | 83 | return &buffer[i..]; |
|
| 85 | 84 | } |
|
| 86 | 85 | ||
| 87 | 86 | /// Format a i64 by writing it to the provided buffer. |
|
| 88 | 87 | pub fn formatI64(val: i64, buffer: *mut [u8]) -> *[u8] { |
|
| 89 | - | debug::check(buffer.len >= I64_STR_LEN); |
|
| 88 | + | assert buffer.len >= I64_STR_LEN; |
|
| 90 | 89 | ||
| 91 | 90 | let neg: bool = val < 0; |
|
| 92 | 91 | let mut x: u64 = -val as u64 if neg else val as u64; |
|
| 93 | 92 | let mut i: u32 = buffer.len; |
|
| 94 | 93 | if x == 0 { |
lib/std/lang/alloc.rad
+2 -3
| 4 | 4 | //! byte buffer. Memory is never freed individually - the entire arena is |
|
| 5 | 5 | //! reset at once. This is ideal for compiler passes where all allocations |
|
| 6 | 6 | //! have the same lifetime. |
|
| 7 | 7 | @test mod tests; |
|
| 8 | 8 | ||
| 9 | - | use std::debug; |
|
| 10 | 9 | use std::mem; |
|
| 11 | 10 | ||
| 12 | 11 | /// Error thrown by allocator. |
|
| 13 | 12 | pub union AllocError { |
|
| 14 | 13 | /// Allocator is out of memory. |
| 35 | 34 | /// |
|
| 36 | 35 | /// Returns an opaque pointer to the allocated memory. Throws `AllocError` if |
|
| 37 | 36 | /// the arena is exhausted. The caller is responsible for casting to the |
|
| 38 | 37 | /// appropriate type and initializing the memory. |
|
| 39 | 38 | pub fn alloc(arena: *mut Arena, size: u32, alignment: u32) -> *mut opaque throws (AllocError) { |
|
| 40 | - | debug::check(alignment > 0); |
|
| 41 | - | debug::check(size > 0); |
|
| 39 | + | assert alignment > 0; |
|
| 40 | + | assert size > 0; |
|
| 42 | 41 | ||
| 43 | 42 | let aligned = mem::alignUp(arena.offset, alignment); |
|
| 44 | 43 | let newOffset = aligned + size; |
|
| 45 | 44 | ||
| 46 | 45 | if newOffset > arena.data.len as u32 { |
lib/std/lang/ast.rad
+1 -2
| 1 | 1 | //! Radiance AST modules. |
|
| 2 | 2 | pub mod printer; |
|
| 3 | 3 | ||
| 4 | 4 | use std::io; |
|
| 5 | - | use std::debug; |
|
| 6 | 5 | use std::lang::alloc; |
|
| 7 | 6 | ||
| 8 | 7 | /// Maximum number of trait methods. |
|
| 9 | 8 | pub const MAX_TRAIT_METHODS: u32 = 8; |
|
| 10 | 9 |
| 107 | 106 | return self.list.len; |
|
| 108 | 107 | } |
|
| 109 | 108 | ||
| 110 | 109 | /// Fetch the attribute node at the specified index. |
|
| 111 | 110 | pub fn attributesGet(self: *Attributes, index: u32) -> *Node { |
|
| 112 | - | debug::checkMsg(index < self.list.len, "attributesGet: invalid index"); |
|
| 111 | + | assert index < self.list.len, "attributesGet: invalid index"; |
|
| 113 | 112 | return self.list.list[index]; |
|
| 114 | 113 | } |
|
| 115 | 114 | ||
| 116 | 115 | /// Check if an attributes list contains an attribute. |
|
| 117 | 116 | pub fn attributesContains(self: *Attributes, attr: Attribute) -> bool { |
lib/std/lang/lower.rad
+13 -14
| 85 | 85 | //! โ |
|
| 86 | 86 | //! il::DataValue |
|
| 87 | 87 | //! โ |
|
| 88 | 88 | //! il::Data |
|
| 89 | 89 | //! |
|
| 90 | - | use std::debug; |
|
| 91 | 90 | use std::fmt; |
|
| 92 | 91 | use std::io; |
|
| 93 | 92 | use std::lang::alloc; |
|
| 94 | 93 | use std::mem; |
|
| 95 | 94 | use std::lang::ast; |
| 1040 | 1039 | } else { |
|
| 1041 | 1040 | func.returnType = ilType(self, *fnType.returnType); |
|
| 1042 | 1041 | } |
|
| 1043 | 1042 | let body = decl.body else { |
|
| 1044 | 1043 | // Extern functions have no body. |
|
| 1045 | - | debug::check(isExtern); |
|
| 1044 | + | assert isExtern; |
|
| 1046 | 1045 | return func; |
|
| 1047 | 1046 | }; |
|
| 1048 | 1047 | func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 1049 | 1048 | ||
| 1050 | 1049 | return func; |
| 2112 | 2111 | switchToBlock(self, target); |
|
| 2113 | 2112 | } |
|
| 2114 | 2113 | ||
| 2115 | 2114 | /// Emit a conditional branch based on `cond`. |
|
| 2116 | 2115 | fn emitBr(self: *mut FnLowerer, cond: il::Reg, thenBlock: BlockId, elseBlock: BlockId) throws (LowerError) { |
|
| 2117 | - | debug::check(thenBlock != elseBlock); |
|
| 2116 | + | assert thenBlock != elseBlock; |
|
| 2118 | 2117 | emit(self, il::Instr::Br { |
|
| 2119 | 2118 | op: il::CmpOp::Ne, |
|
| 2120 | 2119 | typ: il::Type::W32, |
|
| 2121 | 2120 | a: il::Val::Reg(cond), |
|
| 2122 | 2121 | b: il::Val::Imm(0), |
| 2137 | 2136 | a: il::Val, |
|
| 2138 | 2137 | b: il::Val, |
|
| 2139 | 2138 | thenBlock: BlockId, |
|
| 2140 | 2139 | elseBlock: BlockId |
|
| 2141 | 2140 | ) throws (LowerError) { |
|
| 2142 | - | debug::check(thenBlock != elseBlock); |
|
| 2141 | + | assert thenBlock != elseBlock; |
|
| 2143 | 2142 | emit(self, il::Instr::Br { |
|
| 2144 | 2143 | op, typ, a, b, |
|
| 2145 | 2144 | thenTarget: thenBlock.n, thenArgs: &mut [], |
|
| 2146 | 2145 | elseTarget: elseBlock.n, elseArgs: &mut [], |
|
| 2147 | 2146 | }); |
| 2380 | 2379 | ||
| 2381 | 2380 | try emitBr(self, eqReg, matchBlock, fallthrough); |
|
| 2382 | 2381 | } |
|
| 2383 | 2382 | } |
|
| 2384 | 2383 | case MatchSubjectKind::Union(unionInfo) => { |
|
| 2385 | - | debug::check(not isNil); |
|
| 2384 | + | assert not isNil; |
|
| 2386 | 2385 | ||
| 2387 | 2386 | let case resolver::NodeExtra::UnionVariant { tag: variantTag, .. } = |
|
| 2388 | 2387 | resolver::nodeData(self.low.resolver, pattern).extra |
|
| 2389 | 2388 | else { |
|
| 2390 | 2389 | throw LowerError::ExpectedVariant; |
| 2408 | 2407 | ||
| 2409 | 2408 | try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, il::Val::Reg(tagReg), il::Val::Imm(variantTag as i64), matchBlock, fallthrough); |
|
| 2410 | 2409 | } |
|
| 2411 | 2410 | } |
|
| 2412 | 2411 | else => { // Scalar comparison. |
|
| 2413 | - | debug::check(not isNil); |
|
| 2412 | + | assert not isNil; |
|
| 2414 | 2413 | let pattVal = try lowerExpr(self, pattern); |
|
| 2415 | 2414 | try emitBrCmp(self, il::CmpOp::Eq, subject.ilType, subject.val, pattVal, matchBlock, fallthrough); |
|
| 2416 | 2415 | } |
|
| 2417 | 2416 | } |
|
| 2418 | 2417 | } |
| 2425 | 2424 | subject: *MatchSubject, |
|
| 2426 | 2425 | patterns: ast::NodeList, |
|
| 2427 | 2426 | matchBlock: BlockId, |
|
| 2428 | 2427 | fallthrough: BlockId |
|
| 2429 | 2428 | ) throws (LowerError) { |
|
| 2430 | - | debug::check(patterns.len > 0); |
|
| 2429 | + | assert patterns.len > 0; |
|
| 2431 | 2430 | ||
| 2432 | 2431 | for i in 0..(patterns.len - 1) { |
|
| 2433 | 2432 | let pattern = patterns.list[i]; |
|
| 2434 | 2433 | let nextArm = try createBlock(self, "arm"); |
|
| 2435 | 2434 | try emitPatternMatch(self, subject, pattern, matchBlock, nextArm); |
| 2735 | 2734 | /// Define (write) a variable. Record the SSA value of a variable in the |
|
| 2736 | 2735 | /// current block. Called when a variable is assigned or initialized (`let` |
|
| 2737 | 2736 | /// bindings, assignments, loop updates). When [`useVar`] is later called, |
|
| 2738 | 2737 | /// it will retrieve this value. |
|
| 2739 | 2738 | fn defVar(self: *mut FnLowerer, v: Var, val: il::Val) { |
|
| 2740 | - | debug::check(v.id < self.varsLen); |
|
| 2739 | + | assert v.id < self.varsLen; |
|
| 2741 | 2740 | getBlockMut(self, currentBlock(self)).vars[v.id] = val; |
|
| 2742 | 2741 | } |
|
| 2743 | 2742 | ||
| 2744 | 2743 | /// Use (read) the current value of a variable in the current block. |
|
| 2745 | 2744 | /// May insert block parameters if the value must come from predecessors. |
| 2752 | 2751 | /// Given a variable and a block where it's used, this function finds the |
|
| 2753 | 2752 | /// correct [`il::Val`] that holds the variable's value at that program point. |
|
| 2754 | 2753 | /// When control flow merges from multiple predecessors with different |
|
| 2755 | 2754 | /// definitions, it creates a block parameter to unify them. |
|
| 2756 | 2755 | fn useVarInBlock(self: *mut FnLowerer, block: BlockId, v: Var) -> il::Val throws (LowerError) { |
|
| 2757 | - | debug::check(v.id < self.varsLen); |
|
| 2756 | + | assert v.id < self.varsLen; |
|
| 2758 | 2757 | ||
| 2759 | 2758 | let blk = getBlockMut(self, block); |
|
| 2760 | 2759 | if let val = blk.vars[v.id] { |
|
| 2761 | 2760 | return val; |
|
| 2762 | 2761 | } |
| 2819 | 2818 | self.varsLen = savedVarsLen; |
|
| 2820 | 2819 | } |
|
| 2821 | 2820 | ||
| 2822 | 2821 | /// Get the metadata for a variable. |
|
| 2823 | 2822 | fn getVar(self: *FnLowerer, v: Var) -> *VarData { |
|
| 2824 | - | debug::check(v.id < self.varsLen); |
|
| 2823 | + | assert v.id < self.varsLen; |
|
| 2825 | 2824 | return &self.vars[v.id]; |
|
| 2826 | 2825 | } |
|
| 2827 | 2826 | ||
| 2828 | 2827 | /// Create a block parameter to merge a variable's value from multiple |
|
| 2829 | 2828 | /// control flow paths. |
| 3051 | 3050 | let offset: u32 = 1 if self.returnReg != nil else 0; |
|
| 3052 | 3051 | let totalLen = fnType.paramTypesLen + offset; |
|
| 3053 | 3052 | if totalLen == 0 { |
|
| 3054 | 3053 | return &[]; |
|
| 3055 | 3054 | } |
|
| 3056 | - | debug::check(fnType.paramTypesLen <= resolver::MAX_FN_PARAMS); |
|
| 3055 | + | assert fnType.paramTypesLen <= resolver::MAX_FN_PARAMS; |
|
| 3057 | 3056 | ||
| 3058 | 3057 | let params = try! alloc::allocSlice( |
|
| 3059 | 3058 | self.low.arena, @sizeOf(il::Param), @alignOf(il::Param), totalLen |
|
| 3060 | 3059 | ) as *mut [il::Param]; |
|
| 3061 | 3060 |
| 3487 | 3486 | /// jmp else#0; // guard failed, fallthrough to `else` |
|
| 3488 | 3487 | /// else#0: |
|
| 3489 | 3488 | /// ret 0; // `else` body |
|
| 3490 | 3489 | /// |
|
| 3491 | 3490 | fn lowerMatch(self: *mut FnLowerer, node: *ast::Node, m: ast::Match) throws (LowerError) { |
|
| 3492 | - | debug::check(m.prongs.len > 0); |
|
| 3491 | + | assert m.prongs.len > 0; |
|
| 3493 | 3492 | ||
| 3494 | 3493 | let prongs = &m.prongs; |
|
| 3495 | 3494 | // Lower the subject expression once; reused across all arms. |
|
| 3496 | 3495 | let subject = try lowerMatchSubject(self, m.subject); |
|
| 3497 | 3496 | // Merge block created lazily if any arm needs it (i.e., doesn't diverge). |
| 4406 | 4405 | let tagBlock = try createBlock(self, "eq#tag"); |
|
| 4407 | 4406 | ||
| 4408 | 4407 | // Compare tags: if they differ, jump to merge with `false`; otherwise check payloads. |
|
| 4409 | 4408 | let falseArgs = try allocVal(self, il::Val::Imm(0)); |
|
| 4410 | 4409 | ||
| 4411 | - | debug::check(tagBlock != mergeBlock); |
|
| 4410 | + | assert tagBlock != mergeBlock; |
|
| 4412 | 4411 | ||
| 4413 | 4412 | // TODO: Use the helper once the compiler supports more than eight function params. |
|
| 4414 | 4413 | emit(self, il::Instr::Br { |
|
| 4415 | 4414 | op: il::CmpOp::Eq, typ: il::Type::W8, a: tagA, b: tagB, |
|
| 4416 | 4415 | thenTarget: tagBlock.n, thenArgs: &mut [], |
| 5474 | 5473 | try emitRetVal(self, val); |
|
| 5475 | 5474 | } |
|
| 5476 | 5475 | ||
| 5477 | 5476 | /// Lower a throw statement. |
|
| 5478 | 5477 | fn lowerThrowStmt(self: *mut FnLowerer, expr: *ast::Node) throws (LowerError) { |
|
| 5479 | - | debug::check(self.fnType.throwListLen > 0); |
|
| 5478 | + | assert self.fnType.throwListLen > 0; |
|
| 5480 | 5479 | ||
| 5481 | 5480 | let errType = resolver::typeFor(self.low.resolver, expr) else { |
|
| 5482 | 5481 | throw LowerError::MissingType(expr); |
|
| 5483 | 5482 | }; |
|
| 5484 | 5483 | let tag = getOrAssignErrorTag(self.low, errType) as i64; |
lib/std/lang/module.rad
+7 -8
| 7 | 7 | pub mod printer; |
|
| 8 | 8 | ||
| 9 | 9 | @test mod tests; |
|
| 10 | 10 | ||
| 11 | 11 | use std::mem; |
|
| 12 | - | use std::debug; |
|
| 13 | 12 | use std::lang::alloc; |
|
| 14 | 13 | use std::lang::ast; |
|
| 15 | 14 | use std::lang::strings; |
|
| 16 | 15 | ||
| 17 | 16 | /// Maximum number of modules tracked in a single compilation graph. |
| 149 | 148 | graph: *mut ModuleGraph, |
|
| 150 | 149 | parentId: u16, |
|
| 151 | 150 | name: *[u8], |
|
| 152 | 151 | filePath: *[u8] |
|
| 153 | 152 | ) -> u16 throws (ModuleError) { |
|
| 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"); |
|
| 153 | + | assert name.len > 0, "registerChild: name must not be empty"; |
|
| 154 | + | assert filePath.len > 0, "registerChild: file path must not be empty"; |
|
| 156 | 155 | ||
| 157 | 156 | let parent = getMut(graph, parentId) |
|
| 158 | 157 | else throw ModuleError::NotFound(parentId); |
|
| 159 | 158 | ||
| 160 | 159 | // If the child already exists under this parent, return it. |
| 193 | 192 | return &mut graph.entries[id as u32]; |
|
| 194 | 193 | } |
|
| 195 | 194 | ||
| 196 | 195 | /// Return the identifier of the child stored at `index`. |
|
| 197 | 196 | pub fn childAt(m: *ModuleEntry, index: u32) -> u16 { |
|
| 198 | - | debug::checkMsg(index < m.childrenLen, "childAt: index must be valid"); |
|
| 197 | + | assert index < m.childrenLen, "childAt: index must be valid"; |
|
| 199 | 198 | return m.children[index]; |
|
| 200 | 199 | } |
|
| 201 | 200 | ||
| 202 | 201 | /// Public accessor for a module's directory prefix. |
|
| 203 | 202 | pub fn moduleDir(m: *ModuleEntry) -> *[u8] { |
|
| 204 | 203 | return &m.filePath[..m.dirLen]; |
|
| 205 | 204 | } |
|
| 206 | 205 | ||
| 207 | 206 | /// Public accessor to the logical module path segments. |
|
| 208 | 207 | pub fn moduleQualifiedPath(m: *ModuleEntry) -> *[*[u8]] { |
|
| 209 | - | debug::checkMsg(m.pathDepth > 0, "moduleQualifiedPath: path must not be empty"); |
|
| 208 | + | assert m.pathDepth > 0, "moduleQualifiedPath: path must not be empty"; |
|
| 210 | 209 | return &m.path[..m.pathDepth]; |
|
| 211 | 210 | } |
|
| 212 | 211 | ||
| 213 | 212 | /// Update the recorded lifecycle state for `id`. |
|
| 214 | 213 | pub fn setState(graph: *mut ModuleGraph, id: u16, state: ModuleState) throws (ModuleError) { |
| 237 | 236 | m.source = source; |
|
| 238 | 237 | } |
|
| 239 | 238 | ||
| 240 | 239 | /// Look up a child module by name under the given parent. |
|
| 241 | 240 | pub fn findChild(graph: *ModuleGraph, name: *[u8], parentId: u16) -> ?*ModuleEntry { |
|
| 242 | - | debug::checkMsg(isValidId(graph, parentId), "findChild: parent identifier is valid"); |
|
| 241 | + | assert isValidId(graph, parentId), "findChild: parent identifier is valid"; |
|
| 243 | 242 | ||
| 244 | 243 | let parent = &graph.entries[parentId as u32]; |
|
| 245 | 244 | for i in 0..parent.childrenLen { |
|
| 246 | 245 | let childId = parent.children[i]; |
|
| 247 | 246 | let child = &graph.entries[childId as u32]; |
| 261 | 260 | ||
| 262 | 261 | // Split on '/' to extract all but the last component. |
|
| 263 | 262 | for i in 0..filePath.len { |
|
| 264 | 263 | if filePath[i] == PATH_SEP { |
|
| 265 | 264 | if i > last { |
|
| 266 | - | debug::checkMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 265 | + | assert count < components.len, "parsePath: output slice is large enough"; |
|
| 267 | 266 | components[count] = &filePath[last..i]; |
|
| 268 | 267 | count += 1; |
|
| 269 | 268 | } |
|
| 270 | 269 | last = i + 1; |
|
| 271 | 270 | } |
| 273 | 272 | if last >= filePath.len { |
|
| 274 | 273 | return nil; // Path ends with separator or is empty. |
|
| 275 | 274 | } |
|
| 276 | 275 | ||
| 277 | 276 | // Handle the last component by removing extension. |
|
| 278 | - | debug::checkMsg(count < components.len, "parsePath: output slice is large enough"); |
|
| 277 | + | assert count < components.len, "parsePath: output slice is large enough"; |
|
| 279 | 278 | if let name = trimExtension(&filePath[last..]) { |
|
| 280 | 279 | components[count] = name; |
|
| 281 | 280 | } else { |
|
| 282 | 281 | return nil; |
|
| 283 | 282 | }; |
lib/std/lang/parser.rad
+2 -3
| 1 | 1 | //! Recursive descent parser for the Radiance programming language. |
|
| 2 | 2 | @test pub mod tests; |
|
| 3 | 3 | ||
| 4 | 4 | use std::mem; |
|
| 5 | 5 | use std::io; |
|
| 6 | - | use std::debug; |
|
| 7 | 6 | use std::lang::alloc; |
|
| 8 | 7 | use std::lang::ast; |
|
| 9 | 8 | use std::lang::strings; |
|
| 10 | 9 | use std::lang::scanner; |
|
| 11 | 10 |
| 162 | 161 | return node(p, ast::NodeValue::Bool(value)); |
|
| 163 | 162 | } |
|
| 164 | 163 | ||
| 165 | 164 | /// Convert a single ASCII digit into its numeric value for the given radix. |
|
| 166 | 165 | pub fn digitFromAscii(ch: u8, radix: u32) -> ?u32 { |
|
| 167 | - | debug::check(radix >= 2 and radix <= 36); |
|
| 166 | + | assert radix >= 2 and radix <= 36; |
|
| 168 | 167 | ||
| 169 | 168 | // Default to an out-of-range value so non-digits fall through to `nil`. |
|
| 170 | 169 | let mut value: u32 = 36; |
|
| 171 | 170 | ||
| 172 | 171 | if ch >= '0' and ch <= '9' { |
| 1142 | 1141 | } |
|
| 1143 | 1142 | } |
|
| 1144 | 1143 | ||
| 1145 | 1144 | /// Report a parser error. |
|
| 1146 | 1145 | fn reportError(p: *mut Parser, token: scanner::Token, message: *[u8]) { |
|
| 1147 | - | debug::check(message.len > 0); |
|
| 1146 | + | assert message.len > 0; |
|
| 1148 | 1147 | ||
| 1149 | 1148 | // Ignore errors once the error list is full. |
|
| 1150 | 1149 | if p.errors.count < p.errors.list.len { |
|
| 1151 | 1150 | p.errors.list[p.errors.count] = Error { message, token }; |
|
| 1152 | 1151 | p.errors.count += 1; |
lib/std/lang/resolver.rad
+9 -10
| 12 | 12 | // TODO: When a function declaration fails to typecheck, it should still "exist". |
|
| 13 | 13 | // TODO: `ensureNominalResolved` should just run when you call `typeFor`. |
|
| 14 | 14 | // TODO: Have different types for positional vs. named field records. |
|
| 15 | 15 | ||
| 16 | 16 | use std::mem; |
|
| 17 | - | use std::debug; |
|
| 18 | 17 | use std::io; |
|
| 19 | 18 | use std::lang::alloc; |
|
| 20 | 19 | use std::lang::ast; |
|
| 21 | 20 | use std::lang::parser; |
|
| 22 | 21 | use std::lang::module; |
| 2831 | 2830 | if let a = decl.alignment { |
|
| 2832 | 2831 | let case ast::NodeValue::Align { value } = a.value |
|
| 2833 | 2832 | else panic "resolveLet: expected Align node"; |
|
| 2834 | 2833 | alignment = try checkSizeInt(self, value); |
|
| 2835 | 2834 | } |
|
| 2836 | - | debug::check(bindingTy != Type::Unknown); |
|
| 2835 | + | assert bindingTy != Type::Unknown; |
|
| 2837 | 2836 | ||
| 2838 | 2837 | // Alignment must be zero or a power of two. |
|
| 2839 | 2838 | if alignment != 0 and (alignment & (alignment - 1)) != 0 { |
|
| 2840 | 2839 | throw emitError(self, decl.value, ErrorKind::InvalidAlignmentValue(alignment)); |
|
| 2841 | 2840 | } |
| 2992 | 2991 | ||
| 2993 | 2992 | // Validate it fits within u32 range. |
|
| 2994 | 2993 | if not validateConstIntRange(value, Type::U32) { |
|
| 2995 | 2994 | throw emitError(self, node, ErrorKind::NumericLiteralOverflow); |
|
| 2996 | 2995 | } |
|
| 2997 | - | debug::check(not int.negative); |
|
| 2996 | + | assert not int.negative; |
|
| 2998 | 2997 | try setNodeType(self, node, Type::U32); |
|
| 2999 | 2998 | ||
| 3000 | 2999 | return int.magnitude as u32; |
|
| 3001 | 3000 | } |
|
| 3002 | 3001 |
| 4724 | 4723 | expected: info.paramTypesLen, |
|
| 4725 | 4724 | actual: call.args.len, |
|
| 4726 | 4725 | })); |
|
| 4727 | 4726 | } |
|
| 4728 | 4727 | for i in 0..call.args.len { |
|
| 4729 | - | debug::check(i < MAX_FN_PARAMS); |
|
| 4728 | + | assert i < MAX_FN_PARAMS; |
|
| 4730 | 4729 | ||
| 4731 | 4730 | let argNode = call.args.list[i]; |
|
| 4732 | 4731 | let expectedTy = *info.paramTypes[i]; |
|
| 4733 | 4732 | ||
| 4734 | 4733 | try checkAssignable(self, argNode, expectedTy); |
| 5113 | 5112 | expectedTy = *ary.item; |
|
| 5114 | 5113 | }; |
|
| 5115 | 5114 | for i in 0..length { |
|
| 5116 | 5115 | let itemNode = items.list[i]; |
|
| 5117 | 5116 | let itemTy = try visit(self, itemNode, expectedTy); |
|
| 5118 | - | debug::check(itemTy != Type::Unknown); |
|
| 5117 | + | assert itemTy != Type::Unknown; |
|
| 5119 | 5118 | ||
| 5120 | 5119 | // Set the expected type to the first type we encounter. |
|
| 5121 | 5120 | if expectedTy == Type::Unknown { |
|
| 5122 | 5121 | expectedTy = itemTy; |
|
| 5123 | 5122 | } else { |
| 5510 | 5509 | throws (ResolveError) |
|
| 5511 | 5510 | { |
|
| 5512 | 5511 | let targetTy = try infer(self, expr.type); |
|
| 5513 | 5512 | let sourceTy = try visit(self, expr.value, targetTy); |
|
| 5514 | 5513 | ||
| 5515 | - | debug::check(sourceTy != Type::Unknown); |
|
| 5516 | - | debug::check(targetTy != Type::Unknown); |
|
| 5514 | + | assert sourceTy != Type::Unknown; |
|
| 5515 | + | assert targetTy != Type::Unknown; |
|
| 5517 | 5516 | ||
| 5518 | 5517 | if isValidCast(sourceTy, targetTy) { |
|
| 5519 | 5518 | return try setNodeType(self, node, targetTy); |
|
| 5520 | 5519 | } |
|
| 5521 | 5520 | throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast { |
| 6266 | 6265 | let case ast::NodeValue::Block(block) = node.value |
|
| 6267 | 6266 | else panic "resolvePackage: expected block for module root"; |
|
| 6268 | 6267 | ||
| 6269 | 6268 | // Module graph analysis phase: bind all module name symbols and scopes. |
|
| 6270 | 6269 | try resolveModuleGraph(self, &block) catch { |
|
| 6271 | - | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 6270 | + | assert self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"; |
|
| 6272 | 6271 | return Diagnostics { errors: self.errors }; |
|
| 6273 | 6272 | }; |
|
| 6274 | 6273 | ||
| 6275 | 6274 | // Declaration phase: bind all names and analyze top-level declarations. |
|
| 6276 | 6275 | try resolveModuleDecls(self, &block) catch { |
|
| 6277 | - | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 6276 | + | assert self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"; |
|
| 6278 | 6277 | }; |
|
| 6279 | 6278 | if self.errors.listLen > 0 { |
|
| 6280 | 6279 | return Diagnostics { errors: self.errors }; |
|
| 6281 | 6280 | } |
|
| 6282 | 6281 | ||
| 6283 | 6282 | // Definition phase: analyze function bodies and sub-module definitions. |
|
| 6284 | 6283 | try resolveModuleDefs(self, &block) catch { |
|
| 6285 | - | debug::checkMsg(self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"); |
|
| 6284 | + | assert self.errors.listLen > 0, "resolvePackage: failure should have diagnostics"; |
|
| 6286 | 6285 | }; |
|
| 6287 | 6286 | try setNodeType(self, node, Type::Void); |
|
| 6288 | 6287 | ||
| 6289 | 6288 | return Diagnostics { errors: self.errors }; |
|
| 6290 | 6289 | } |
lib/std/lang/scanner.rad
+0 -1
| 2 | 2 | //! |
|
| 3 | 3 | //! This module implements a hand-written scanner that tokenizes Radiance |
|
| 4 | 4 | //! source code into a stream of tokens for consumption by the parser. |
|
| 5 | 5 | @test mod tests; |
|
| 6 | 6 | ||
| 7 | - | use std::debug; |
|
| 8 | 7 | use std::mem; |
|
| 9 | 8 | use std::lang::strings; |
|
| 10 | 9 | ||
| 11 | 10 | /// Token kinds representing all lexical elements in Radiance. |
|
| 12 | 11 | /// |
lib/std/vec.rad
+4 -6
| 2 | 2 | //! |
|
| 3 | 3 | //! Users provide their own arena (static array) and the vector manages |
|
| 4 | 4 | //! element count within that arena. The arena should be aligned according |
|
| 5 | 5 | //! to the element type's requirements. |
|
| 6 | 6 | ||
| 7 | - | use super::debug; |
|
| 8 | - | ||
| 9 | 7 | /// Raw vector metadata structure. |
|
| 10 | 8 | /// |
|
| 11 | 9 | /// Does not own storage, points to user-provided arena. |
|
| 12 | 10 | pub record RawVec { |
|
| 13 | 11 | /// Pointer to user-provided byte arena. |
| 24 | 22 | /// |
|
| 25 | 23 | /// * `arena` is a pointer to static array backing storage. |
|
| 26 | 24 | /// * `stride` is the size of each element. |
|
| 27 | 25 | /// * `alignment` is the required alignment for elements. |
|
| 28 | 26 | pub fn new(arena: *mut [u8], stride: u32, alignment: u32) -> RawVec { |
|
| 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); |
|
| 27 | + | assert stride > 0; |
|
| 28 | + | assert alignment > 0; |
|
| 29 | + | assert (arena.ptr as u32) % alignment == 0; |
|
| 30 | + | assert (arena.len % stride) == 0; |
|
| 33 | 31 | ||
| 34 | 32 | return RawVec { data: arena, len: 0, stride, alignment }; |
|
| 35 | 33 | } |
|
| 36 | 34 | ||
| 37 | 35 | /// Get the current number of elements in the vector. |
std.lib
+0 -1
| 2 | 2 | lib/std/fmt.rad |
|
| 3 | 3 | lib/std/mem.rad |
|
| 4 | 4 | lib/std/vec.rad |
|
| 5 | 5 | lib/std/io.rad |
|
| 6 | 6 | lib/std/intrinsics.rad |
|
| 7 | - | lib/std/debug.rad |
|
| 8 | 7 | lib/std/sys.rad |
|
| 9 | 8 | lib/std/collections.rad |
|
| 10 | 9 | lib/std/collections/dict.rad |
|
| 11 | 10 | lib/std/sys/unix.rad |
|
| 12 | 11 | lib/std/arch.rad |