Update code to use `set` for assignment
d3dd0b64dde55c9c77b6d2b9f4e8f1bed588b9cbbb88c10937cec60f3f98412f
1 parent
3b92f411
compiler/radiance.rad
+33 -33
| 197 | 197 | }; |
|
| 198 | 198 | } |
|
| 199 | 199 | ||
| 200 | 200 | /// Consume the next argument, or print an error and throw. |
|
| 201 | 201 | fn nextArg(args: *[*[u8]], idx: *mut u32, msg: *[u8]) -> *[u8] throws (Error) { |
|
| 202 | - | *idx += 1; |
|
| 202 | + | set *idx += 1; |
|
| 203 | 203 | if *idx >= args.len { |
|
| 204 | 204 | io::printError(msg); |
|
| 205 | 205 | throw Error::Other; |
|
| 206 | 206 | } |
|
| 207 | 207 | return args[*idx]; |
| 224 | 224 | let mut pkgNames: [*[u8]; MAX_PACKAGES] = undefined; |
|
| 225 | 225 | let mut pkgCount: u32 = 0; |
|
| 226 | 226 | let mut currentPkgIdx: ?u32 = nil; |
|
| 227 | 227 | ||
| 228 | 228 | for i in 0..MAX_PACKAGES { |
|
| 229 | - | moduleCounts[i] = 0; |
|
| 229 | + | set moduleCounts[i] = 0; |
|
| 230 | 230 | } |
|
| 231 | 231 | if args.len == 0 { |
|
| 232 | 232 | io::printError(USAGE); |
|
| 233 | 233 | throw Error::Other; |
|
| 234 | 234 | } |
| 240 | 240 | try nextArg(args, &mut idx, "radiance: `-pkg` requires a package name\n"); |
|
| 241 | 241 | if pkgCount >= MAX_PACKAGES { |
|
| 242 | 242 | io::printError("radiance: too many packages specified\n"); |
|
| 243 | 243 | throw Error::Other; |
|
| 244 | 244 | } |
|
| 245 | - | pkgNames[pkgCount] = args[idx]; |
|
| 246 | - | currentPkgIdx = pkgCount; |
|
| 247 | - | pkgCount += 1; |
|
| 245 | + | set pkgNames[pkgCount] = args[idx]; |
|
| 246 | + | set currentPkgIdx = pkgCount; |
|
| 247 | + | set pkgCount += 1; |
|
| 248 | 248 | } else if mem::eq(arg, "-mod") { |
|
| 249 | 249 | try nextArg(args, &mut idx, "radiance: `-mod` requires a module path\n"); |
|
| 250 | 250 | let pkgIdx = currentPkgIdx else { |
|
| 251 | 251 | io::printError("radiance: `-mod` must follow a `-pkg` argument\n"); |
|
| 252 | 252 | throw Error::Other; |
|
| 253 | 253 | }; |
|
| 254 | 254 | if moduleCounts[pkgIdx] >= MAX_LOADED_MODULES { |
|
| 255 | 255 | io::printError("radiance: too many modules specified for package\n"); |
|
| 256 | 256 | throw Error::Other; |
|
| 257 | 257 | } |
|
| 258 | - | modulePaths[pkgIdx][moduleCounts[pkgIdx]] = args[idx]; |
|
| 259 | - | moduleCounts[pkgIdx] += 1; |
|
| 258 | + | set modulePaths[pkgIdx][moduleCounts[pkgIdx]] = args[idx]; |
|
| 259 | + | set moduleCounts[pkgIdx] += 1; |
|
| 260 | 260 | } else if mem::eq(arg, "-entry") { |
|
| 261 | 261 | try nextArg(args, &mut idx, "radiance: `-entry` requires a package name\n"); |
|
| 262 | - | entryPkgName = args[idx]; |
|
| 262 | + | set entryPkgName = args[idx]; |
|
| 263 | 263 | } else if mem::eq(arg, "-test") { |
|
| 264 | - | buildTest = true; |
|
| 264 | + | set buildTest = true; |
|
| 265 | 265 | } else if mem::eq(arg, "-debug") { |
|
| 266 | - | debugEnabled = true; |
|
| 266 | + | set debugEnabled = true; |
|
| 267 | 267 | } else if mem::eq(arg, "-o") { |
|
| 268 | 268 | try nextArg(args, &mut idx, "radiance: `-o` requires an output path\n"); |
|
| 269 | - | outputPath = args[idx]; |
|
| 269 | + | set outputPath = args[idx]; |
|
| 270 | 270 | } else if mem::eq(arg, "-dump") { |
|
| 271 | 271 | try nextArg(args, &mut idx, "radiance: `-dump` requires a mode (eg. ast)\n"); |
|
| 272 | 272 | let mode = args[idx]; |
|
| 273 | 273 | if mem::eq(mode, "ast") { |
|
| 274 | - | dump = Dump::Ast; |
|
| 274 | + | set dump = Dump::Ast; |
|
| 275 | 275 | } else if mem::eq(mode, "graph") { |
|
| 276 | - | dump = Dump::Graph; |
|
| 276 | + | set dump = Dump::Graph; |
|
| 277 | 277 | } else if mem::eq(mode, "il") { |
|
| 278 | - | dump = Dump::Il; |
|
| 278 | + | set dump = Dump::Il; |
|
| 279 | 279 | } else if mem::eq(mode, "asm") { |
|
| 280 | - | dump = Dump::Asm; |
|
| 280 | + | set dump = Dump::Asm; |
|
| 281 | 281 | } else { |
|
| 282 | 282 | io::printError("radiance: unknown dump mode `"); |
|
| 283 | 283 | io::printError(mode); |
|
| 284 | 284 | io::printError("` (expected: ast, graph, il, asm)\n"); |
|
| 285 | 285 | throw Error::Other; |
| 288 | 288 | io::printError("radiance: unknown argument `"); |
|
| 289 | 289 | io::printError(arg); |
|
| 290 | 290 | io::printError("`\n"); |
|
| 291 | 291 | throw Error::Other; |
|
| 292 | 292 | } |
|
| 293 | - | idx += 1; |
|
| 293 | + | set idx += 1; |
|
| 294 | 294 | } |
|
| 295 | 295 | if pkgCount == 0 { |
|
| 296 | 296 | io::printError("radiance: no package specified\n"); |
|
| 297 | 297 | throw Error::Other; |
|
| 298 | 298 | } |
|
| 299 | 299 | ||
| 300 | 300 | // Determine entry package index. |
|
| 301 | 301 | let mut entryPkgIdx: ?u32 = nil; |
|
| 302 | 302 | if pkgCount == 1 { |
|
| 303 | 303 | // Single package: it is the entry. |
|
| 304 | - | entryPkgIdx = 0; |
|
| 304 | + | set entryPkgIdx = 0; |
|
| 305 | 305 | } else { |
|
| 306 | 306 | // Multiple packages: need -entry. |
|
| 307 | 307 | let entryName = entryPkgName else { |
|
| 308 | 308 | io::printError("radiance: `-entry` required when multiple packages specified\n"); |
|
| 309 | 309 | throw Error::Other; |
|
| 310 | 310 | }; |
|
| 311 | 311 | for i in 0..pkgCount { |
|
| 312 | 312 | if mem::eq(pkgNames[i], entryName) { |
|
| 313 | - | entryPkgIdx = i; |
|
| 313 | + | set entryPkgIdx = i; |
|
| 314 | 314 | break; |
|
| 315 | 315 | } |
|
| 316 | 316 | } |
|
| 317 | 317 | if entryPkgIdx == nil { |
|
| 318 | 318 | io::printError("radiance: fatal: entry package `"); |
| 476 | 476 | for i in 1..path.len { |
|
| 477 | 477 | let child = ast::synthNode( |
|
| 478 | 478 | arena, |
|
| 479 | 479 | ast::NodeValue::Ident(strings::intern(&mut STRING_POOL, path[i])) |
|
| 480 | 480 | ); |
|
| 481 | - | result = ast::synthNode(arena, ast::NodeValue::ScopeAccess(ast::Access { |
|
| 481 | + | set result = ast::synthNode(arena, ast::NodeValue::ScopeAccess(ast::Access { |
|
| 482 | 482 | parent: result, child, |
|
| 483 | 483 | })); |
|
| 484 | 484 | } |
|
| 485 | 485 | return result; |
|
| 486 | 486 | } |
| 513 | 513 | ||
| 514 | 514 | for stmt in block.statements { |
|
| 515 | 515 | if let case ast::NodeValue::FnDecl(decl) = stmt.value { |
|
| 516 | 516 | if let fnName = getTestFnName(&decl) { |
|
| 517 | 517 | if *testCount < tests.len { |
|
| 518 | - | tests[*testCount] = TestDesc { modPath, fnName }; |
|
| 519 | - | *testCount += 1; |
|
| 518 | + | set tests[*testCount] = TestDesc { modPath, fnName }; |
|
| 519 | + | set *testCount += 1; |
|
| 520 | 520 | } else { |
|
| 521 | 521 | panic "collectModuleTests: too many tests"; |
|
| 522 | 522 | } |
|
| 523 | 523 | } |
|
| 524 | 524 | } |
| 537 | 537 | let nameArg = ast::synthNode(arena, ast::NodeValue::String(desc.fnName)); |
|
| 538 | 538 | ||
| 539 | 539 | // Intra-package path: skip the package name prefix. |
|
| 540 | 540 | let mut funcPath: [*[u8]; 16] = undefined; |
|
| 541 | 541 | for j in 1..desc.modPath.len { |
|
| 542 | - | funcPath[j - 1] = desc.modPath[j]; |
|
| 542 | + | set funcPath[j - 1] = desc.modPath[j]; |
|
| 543 | 543 | } |
|
| 544 | - | funcPath[desc.modPath.len - 1] = desc.fnName; |
|
| 544 | + | set funcPath[desc.modPath.len - 1] = desc.fnName; |
|
| 545 | 545 | let funcArg = synthScopeAccess(arena, &funcPath[..desc.modPath.len]); |
|
| 546 | 546 | ||
| 547 | 547 | let a = alloc::arenaAllocator(&mut arena.arena); |
|
| 548 | 548 | let args = ast::nodeSlice(arena, 3) |
|
| 549 | 549 | .append(modArg, a) |
| 654 | 654 | ) { |
|
| 655 | 655 | let case ast::NodeValue::Block(block) = blockNode.value else { |
|
| 656 | 656 | panic "injectIntoBlock: expected Block node"; |
|
| 657 | 657 | }; |
|
| 658 | 658 | let stmts = block.statements.append(decl, alloc::arenaAllocator(&mut arena.arena)); |
|
| 659 | - | blockNode.value = ast::NodeValue::Block(ast::Block { statements: stmts }); |
|
| 659 | + | set blockNode.value = ast::NodeValue::Block(ast::Block { statements: stmts }); |
|
| 660 | 660 | } |
|
| 661 | 661 | ||
| 662 | 662 | /// Write code buffer to file as raw bytes. |
|
| 663 | 663 | fn writeCode(code: *[u32], path: *[u8]) -> bool { |
|
| 664 | 664 | // Convert `u32` slice to `u8` slice (little-endian). |
| 680 | 680 | return; |
|
| 681 | 681 | } |
|
| 682 | 682 | let mut path: [u8; MAX_PATH_LEN] = undefined; |
|
| 683 | 683 | let mut pos: u32 = 0; |
|
| 684 | 684 | ||
| 685 | - | pos += try! mem::copy(&mut path[pos..], basePath); |
|
| 686 | - | pos += try! mem::copy(&mut path[pos..], ext); |
|
| 687 | - | path[pos] = 0; // Null-terminate for syscall. |
|
| 685 | + | set pos += try! mem::copy(&mut path[pos..], basePath); |
|
| 686 | + | set pos += try! mem::copy(&mut path[pos..], ext); |
|
| 687 | + | set path[pos] = 0; // Null-terminate for syscall. |
|
| 688 | 688 | ||
| 689 | 689 | if not unix::writeFile(&path[..pos], data) { |
|
| 690 | 690 | io::printError("radiance: fatal: failed to write data file\n"); |
|
| 691 | 691 | throw Error::Other; |
|
| 692 | 692 | } |
| 711 | 711 | for i in 0..entries.len { |
|
| 712 | 712 | let entry = &entries[i]; |
|
| 713 | 713 | let modEntry = module::get(graph, entry.moduleId) else { |
|
| 714 | 714 | panic "writeDebugInfo: module not found for debug entry"; |
|
| 715 | 715 | }; |
|
| 716 | - | pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.pc as *u8, 4)); |
|
| 717 | - | pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.offset as *u8, 4)); |
|
| 718 | - | pos += try! mem::copy(&mut buf[pos..], modEntry.filePath); |
|
| 716 | + | set pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.pc as *u8, 4)); |
|
| 717 | + | set pos += try! mem::copy(&mut buf[pos..], @sliceOf(&entry.offset as *u8, 4)); |
|
| 718 | + | set pos += try! mem::copy(&mut buf[pos..], modEntry.filePath); |
|
| 719 | 719 | ||
| 720 | - | buf[pos] = 0; |
|
| 721 | - | pos += 1; |
|
| 720 | + | set buf[pos] = 0; |
|
| 721 | + | set pos += 1; |
|
| 722 | 722 | } |
|
| 723 | 723 | try writeDataWithExt(&buf[..pos], basePath, DEBUG_EXT); |
|
| 724 | 724 | } |
|
| 725 | 725 | ||
| 726 | 726 | /// Run the resolver on the parsed modules. |
| 745 | 745 | let mut packages: [resolver::Pkg; MAX_PACKAGES] = undefined; |
|
| 746 | 746 | for i in 0..ctx.packageCount { |
|
| 747 | 747 | let pkg = &ctx.packages[i]; |
|
| 748 | 748 | let root = try getRootModule(pkg, &ctx.graph); |
|
| 749 | 749 | ||
| 750 | - | packages[i] = resolver::Pkg { |
|
| 750 | + | set packages[i] = resolver::Pkg { |
|
| 751 | 751 | rootEntry: root.entry, |
|
| 752 | 752 | rootAst: root.ast, |
|
| 753 | 753 | }; |
|
| 754 | 754 | } |
|
| 755 | 755 |
lib/std/arch/rv64.rad
+1 -1
| 197 | 197 | ||
| 198 | 198 | // Emit placeholder entry jump to default function if there is one. |
|
| 199 | 199 | // We'll patch this at the end once we know where the function is. |
|
| 200 | 200 | let mut defaultName: ?*[u8] = nil; |
|
| 201 | 201 | if let defIdx = program.defaultFnIdx { |
|
| 202 | - | defaultName = program.fns[defIdx].name; |
|
| 202 | + | set defaultName = program.fns[defIdx].name; |
|
| 203 | 203 | emit::emit(&mut e, encode::nop()); // Placeholder for two-instruction jump. |
|
| 204 | 204 | emit::emit(&mut e, encode::nop()); // |
|
| 205 | 205 | } |
|
| 206 | 206 | ||
| 207 | 207 | // Generate code for all functions. |
lib/std/arch/rv64/emit.rad
+20 -20
| 151 | 151 | let savedRegs = mem::popCount(usedCalleeSaved) + 2; |
|
| 152 | 152 | let totalSize = mem::alignUpI32( |
|
| 153 | 153 | localSize + savedRegs * super::DWORD_SIZE, |
|
| 154 | 154 | super::STACK_ALIGNMENT |
|
| 155 | 155 | ); |
|
| 156 | - | frame.totalSize = totalSize; |
|
| 156 | + | set frame.totalSize = totalSize; |
|
| 157 | 157 | ||
| 158 | 158 | // Build list of callee-saved registers with offsets. |
|
| 159 | 159 | let mut offset = totalSize - (super::DWORD_SIZE * 3); |
|
| 160 | 160 | for reg, i in super::CALLEE_SAVED { |
|
| 161 | 161 | // Check if this register is in use. |
|
| 162 | 162 | if (usedCalleeSaved & (1 << i)) <> 0 { |
|
| 163 | - | frame.savedRegs[frame.savedRegsLen] = SavedReg { |
|
| 163 | + | set frame.savedRegs[frame.savedRegsLen] = SavedReg { |
|
| 164 | 164 | reg, |
|
| 165 | 165 | offset, |
|
| 166 | 166 | }; |
|
| 167 | - | frame.savedRegsLen += 1; |
|
| 168 | - | offset -= super::DWORD_SIZE; |
|
| 167 | + | set frame.savedRegsLen += 1; |
|
| 168 | + | set offset -= super::DWORD_SIZE; |
|
| 169 | 169 | } |
|
| 170 | 170 | } |
|
| 171 | 171 | return frame; |
|
| 172 | 172 | } |
|
| 173 | 173 |
| 181 | 181 | let funcEntries = try alloc::allocSlice(arena, @sizeOf(dict::Entry), @alignOf(dict::Entry), labels::FUNC_TABLE_SIZE); |
|
| 182 | 182 | let funcs = try alloc::allocSlice(arena, @sizeOf(types::FuncAddr), @alignOf(types::FuncAddr), MAX_FUNCS); |
|
| 183 | 183 | ||
| 184 | 184 | let mut debugEntries: *mut [types::DebugEntry] = &mut []; |
|
| 185 | 185 | if debug { |
|
| 186 | - | debugEntries = try alloc::allocSlice( |
|
| 186 | + | set debugEntries = try alloc::allocSlice( |
|
| 187 | 187 | arena, @sizeOf(types::DebugEntry), @alignOf(types::DebugEntry), MAX_DEBUG_ENTRIES |
|
| 188 | 188 | ) as *mut [types::DebugEntry]; |
|
| 189 | 189 | } |
|
| 190 | 190 | return Emitter { |
|
| 191 | 191 | code: code as *mut [u32], |
| 209 | 209 | /////////////////////// |
|
| 210 | 210 | ||
| 211 | 211 | /// Emit a single instruction. |
|
| 212 | 212 | export fn emit(e: *mut Emitter, instr: u32) { |
|
| 213 | 213 | assert e.codeLen < e.code.len, "emit: code buffer full"; |
|
| 214 | - | e.code[e.codeLen] = instr; |
|
| 215 | - | e.codeLen += 1; |
|
| 214 | + | set e.code[e.codeLen] = instr; |
|
| 215 | + | set e.codeLen += 1; |
|
| 216 | 216 | } |
|
| 217 | 217 | ||
| 218 | 218 | /// Compute branch offset to a function by name. |
|
| 219 | 219 | export fn branchOffsetToFunc(e: *Emitter, srcIndex: u32, name: *[u8]) -> i32 { |
|
| 220 | 220 | return labels::branchToFunc(&e.labels, srcIndex, name, super::INSTR_SIZE); |
|
| 221 | 221 | } |
|
| 222 | 222 | ||
| 223 | 223 | /// Patch an instruction at a given index. |
|
| 224 | 224 | export fn patch(e: *mut Emitter, index: u32, instr: u32) { |
|
| 225 | - | e.code[index] = instr; |
|
| 225 | + | set e.code[index] = instr; |
|
| 226 | 226 | } |
|
| 227 | 227 | ||
| 228 | 228 | /// Record a block's address for branch resolution. |
|
| 229 | 229 | export fn recordBlock(e: *mut Emitter, blockIdx: u32) { |
|
| 230 | 230 | assert e.codeLen <= MAX_CODE_LEN; |
| 238 | 238 | } |
|
| 239 | 239 | ||
| 240 | 240 | /// Record a function's start position for printing. |
|
| 241 | 241 | export fn recordFunc(e: *mut Emitter, name: *[u8]) { |
|
| 242 | 242 | assert e.funcsLen < e.funcs.len, "recordFunc: funcs buffer full"; |
|
| 243 | - | e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen }; |
|
| 244 | - | e.funcsLen += 1; |
|
| 243 | + | set e.funcs[e.funcsLen] = types::FuncAddr { name, index: e.codeLen }; |
|
| 244 | + | set e.funcsLen += 1; |
|
| 245 | 245 | } |
|
| 246 | 246 | ||
| 247 | 247 | /// Record a local branch needing later patching. |
|
| 248 | 248 | /// Unconditional jumps use a single slot (J-type, +-1MB range). |
|
| 249 | 249 | /// Conditional branches use two slots (B-type has only +-4KB range, |
|
| 250 | 250 | /// so large functions may need the inverted-branch + JAL fallback). |
|
| 251 | 251 | export fn recordBranch(e: *mut Emitter, targetBlock: u32, kind: BranchKind) { |
|
| 252 | 252 | assert e.pendingBranchesLen < e.pendingBranches.len, "recordBranch: buffer full"; |
|
| 253 | - | e.pendingBranches[e.pendingBranchesLen] = PendingBranch { |
|
| 253 | + | set e.pendingBranches[e.pendingBranchesLen] = PendingBranch { |
|
| 254 | 254 | index: e.codeLen, |
|
| 255 | 255 | target: targetBlock, |
|
| 256 | 256 | kind: kind, |
|
| 257 | 257 | }; |
|
| 258 | - | e.pendingBranchesLen += 1; |
|
| 258 | + | set e.pendingBranchesLen += 1; |
|
| 259 | 259 | ||
| 260 | 260 | emit(e, encode::nop()); // First slot, always needed. |
|
| 261 | 261 | ||
| 262 | 262 | match kind { |
|
| 263 | 263 | case BranchKind::Jump => {}, |
| 268 | 268 | /// Record a function call needing later patching. |
|
| 269 | 269 | /// Emits placeholder instructions that will be patched later. |
|
| 270 | 270 | /// Uses two slots to support long-distance calls. |
|
| 271 | 271 | export fn recordCall(e: *mut Emitter, target: *[u8]) { |
|
| 272 | 272 | assert e.pendingCallsLen < e.pendingCalls.len, "recordCall: buffer full"; |
|
| 273 | - | e.pendingCalls[e.pendingCallsLen] = PendingCall { |
|
| 273 | + | set e.pendingCalls[e.pendingCallsLen] = PendingCall { |
|
| 274 | 274 | index: e.codeLen, |
|
| 275 | 275 | target, |
|
| 276 | 276 | }; |
|
| 277 | - | e.pendingCallsLen += 1; |
|
| 277 | + | set e.pendingCallsLen += 1; |
|
| 278 | 278 | ||
| 279 | 279 | emit(e, encode::nop()); // Placeholder for AUIPC. |
|
| 280 | 280 | emit(e, encode::nop()); // Placeholder for JALR. |
|
| 281 | 281 | } |
|
| 282 | 282 | ||
| 283 | 283 | /// Record a function address load needing later patching. |
|
| 284 | 284 | /// Emits placeholder instructions that will be patched to load the function's address. |
|
| 285 | 285 | /// Uses two slots to compute long-distance addresses. |
|
| 286 | 286 | export fn recordAddrLoad(e: *mut Emitter, target: *[u8], rd: gen::Reg) { |
|
| 287 | 287 | assert e.pendingAddrLoadsLen < e.pendingAddrLoads.len, "recordAddrLoad: buffer full"; |
|
| 288 | - | e.pendingAddrLoads[e.pendingAddrLoadsLen] = PendingAddrLoad { |
|
| 288 | + | set e.pendingAddrLoads[e.pendingAddrLoadsLen] = PendingAddrLoad { |
|
| 289 | 289 | index: e.codeLen, |
|
| 290 | 290 | target, |
|
| 291 | 291 | rd: rd, |
|
| 292 | 292 | }; |
|
| 293 | - | e.pendingAddrLoadsLen += 1; |
|
| 293 | + | set e.pendingAddrLoadsLen += 1; |
|
| 294 | 294 | ||
| 295 | 295 | emit(e, encode::nop()); // Placeholder for AUIPC. |
|
| 296 | 296 | emit(e, encode::nop()); // Placeholder for ADDI. |
|
| 297 | 297 | } |
|
| 298 | 298 |
| 332 | 332 | assert encode::isJumpImm(offset), "patchLocalBranches: jump offset too large"; |
|
| 333 | 333 | patch(e, p.index, encode::jal(super::ZERO, offset)); |
|
| 334 | 334 | }, |
|
| 335 | 335 | } |
|
| 336 | 336 | } |
|
| 337 | - | e.pendingBranchesLen = 0; |
|
| 337 | + | set e.pendingBranchesLen = 0; |
|
| 338 | 338 | } |
|
| 339 | 339 | ||
| 340 | 340 | /// Encode a conditional branch instruction. |
|
| 341 | 341 | fn encodeCondBranch(op: il::CmpOp, rs1: gen::Reg, rs2: gen::Reg, offset: i32) -> u32 { |
|
| 342 | 342 | match op { |
| 406 | 406 | let lo = imm & 0xFFF; |
|
| 407 | 407 | let mut hi = (imm >> 12) & 0xFFFFF; |
|
| 408 | 408 | // If `lo`'s sign bit is set, it will be sign-extended to negative. |
|
| 409 | 409 | // Compensate by incrementing `hi`. |
|
| 410 | 410 | if (lo & 0x800) <> 0 { |
|
| 411 | - | hi += 1; |
|
| 411 | + | set hi += 1; |
|
| 412 | 412 | return SplitImm { hi, lo: lo | 0xFFFFF000 as i32 }; |
|
| 413 | 413 | } |
|
| 414 | 414 | return SplitImm { hi, lo }; |
|
| 415 | 415 | } |
|
| 416 | 416 |
| 664 | 664 | if prev.offset == loc.offset and prev.moduleId == loc.moduleId { |
|
| 665 | 665 | return; |
|
| 666 | 666 | } |
|
| 667 | 667 | } |
|
| 668 | 668 | assert e.debugEntriesLen < e.debugEntries.len, "recordSrcLoc: debug entry buffer full"; |
|
| 669 | - | e.debugEntries[e.debugEntriesLen] = types::DebugEntry { |
|
| 669 | + | set e.debugEntries[e.debugEntriesLen] = types::DebugEntry { |
|
| 670 | 670 | pc, |
|
| 671 | 671 | moduleId: loc.moduleId, |
|
| 672 | 672 | offset: loc.offset, |
|
| 673 | 673 | }; |
|
| 674 | - | e.debugEntriesLen += 1; |
|
| 674 | + | set e.debugEntriesLen += 1; |
|
| 675 | 675 | } |
|
| 676 | 676 | ||
| 677 | 677 | /// Get debug entries as a slice. |
|
| 678 | 678 | export fn getDebugEntries(e: *Emitter) -> *[types::DebugEntry] { |
|
| 679 | 679 | return &e.debugEntries[..e.debugEntriesLen]; |
lib/std/arch/rv64/isel.rad
+38 -38
| 144 | 144 | /// If the register is spilled, records a pending spill and returns the scratch |
|
| 145 | 145 | /// register. The pending spill is auto-committed by [`selectBlock`] after each |
|
| 146 | 146 | /// instruction. If not spilled, returns the physical register. |
|
| 147 | 147 | fn getDstReg(s: *mut Selector, ssa: il::Reg, scratch: gen::Reg) -> gen::Reg { |
|
| 148 | 148 | if let _ = regalloc::spill::spillSlot(&s.ralloc.spill, ssa) { |
|
| 149 | - | s.pendingSpill = PendingSpill { ssa, rd: scratch }; |
|
| 149 | + | set s.pendingSpill = PendingSpill { ssa, rd: scratch }; |
|
| 150 | 150 | return scratch; |
|
| 151 | 151 | } |
|
| 152 | 152 | return getReg(s, ssa); |
|
| 153 | 153 | } |
|
| 154 | 154 |
| 255 | 255 | /// Resolve a value, trap if zero (unless known non-zero), and return the register. |
|
| 256 | 256 | fn resolveAndTrapIfZero(s: *mut Selector, b: il::Val) -> gen::Reg { |
|
| 257 | 257 | let rs2 = resolveVal(s, super::SCRATCH2, b); |
|
| 258 | 258 | let mut knownNonZero = false; |
|
| 259 | 259 | if let case il::Val::Imm(imm) = b { |
|
| 260 | - | knownNonZero = imm <> 0; |
|
| 260 | + | set knownNonZero = imm <> 0; |
|
| 261 | 261 | } |
|
| 262 | 262 | if not knownNonZero { |
|
| 263 | 263 | emit::emit(s.e, encode::bne(rs2, super::ZERO, super::INSTR_SIZE * 2)); |
|
| 264 | 264 | emit::emit(s.e, encode::ebreak()); |
|
| 265 | 265 | } |
| 288 | 288 | let block = &func.blocks[b]; |
|
| 289 | 289 | for instr in block.instrs { |
|
| 290 | 290 | match instr { |
|
| 291 | 291 | case il::Instr::Reserve { size, alignment, .. } => { |
|
| 292 | 292 | if let case il::Val::Imm(sz) = size { |
|
| 293 | - | offset = mem::alignUpI32(offset, alignment as i32); |
|
| 294 | - | offset += sz as i32; |
|
| 293 | + | set offset = mem::alignUpI32(offset, alignment as i32); |
|
| 294 | + | set offset += sz as i32; |
|
| 295 | 295 | } else { |
|
| 296 | - | isDynamic = true; |
|
| 296 | + | set isDynamic = true; |
|
| 297 | 297 | } |
|
| 298 | 298 | }, |
|
| 299 | 299 | else => {}, |
|
| 300 | 300 | } |
|
| 301 | 301 | } |
| 379 | 379 | for instr, i in block.instrs { |
|
| 380 | 380 | // Record debug location before emitting machine instructions. |
|
| 381 | 381 | if hasLocs { |
|
| 382 | 382 | emit::recordSrcLoc(s.e, block.locs[i]); |
|
| 383 | 383 | } |
|
| 384 | - | s.pendingSpill = nil; |
|
| 384 | + | set s.pendingSpill = nil; |
|
| 385 | 385 | selectInstr(s, blockIdx, instr, frame, func); |
|
| 386 | 386 | ||
| 387 | 387 | // Flush the pending spill store, if any. |
|
| 388 | 388 | if let p = s.pendingSpill { |
|
| 389 | 389 | if let slot = regalloc::spill::spillSlot(&s.ralloc.spill, p.ssa) { |
|
| 390 | 390 | emit::emitSd(s.e, p.rd, spillBase(s), spillOffset(s, slot)); |
|
| 391 | 391 | } |
|
| 392 | - | s.pendingSpill = nil; |
|
| 392 | + | set s.pendingSpill = nil; |
|
| 393 | 393 | } |
|
| 394 | 394 | } |
|
| 395 | 395 | } |
|
| 396 | 396 | ||
| 397 | 397 | /// Select instructions for a single IL instruction. |
| 436 | 436 | let base = spillBase(s); |
|
| 437 | 437 | let offset = s.ralloc.spill.frameSize + aligned |
|
| 438 | 438 | - (s.frameSize if s.isDynamic else 0); |
|
| 439 | 439 | ||
| 440 | 440 | emit::emitAddImm(s.e, rd, base, offset); |
|
| 441 | - | s.reserveOffset = aligned + (sz as i32); |
|
| 441 | + | set s.reserveOffset = aligned + (sz as i32); |
|
| 442 | 442 | }, |
|
| 443 | 443 | case il::Val::Reg(r) => { |
|
| 444 | 444 | // Dynamic-sized reserve: runtime SP adjustment. |
|
| 445 | 445 | let rd = getDstReg(s, dst, super::SCRATCH1); |
|
| 446 | 446 | let rs = getSrcReg(s, r, super::SCRATCH2); |
| 482 | 482 | }; |
|
| 483 | 483 | let srcSlot = regalloc::spill::spillSlot(&s.ralloc.spill, src) else { |
|
| 484 | 484 | panic "selectInstr: blit src not spilled"; |
|
| 485 | 485 | }; |
|
| 486 | 486 | emit::emitLd(s.e, super::SCRATCH2, spillBase(s), spillOffset(s, dstSlot)); |
|
| 487 | - | srcReload = spillOffset(s, srcSlot); |
|
| 487 | + | set srcReload = spillOffset(s, srcSlot); |
|
| 488 | 488 | } else { |
|
| 489 | - | rdst = getSrcReg(s, dst, super::SCRATCH2); |
|
| 490 | - | rsrc = getSrcReg(s, src, super::SCRATCH2); |
|
| 489 | + | set rdst = getSrcReg(s, dst, super::SCRATCH2); |
|
| 490 | + | set rsrc = getSrcReg(s, src, super::SCRATCH2); |
|
| 491 | 491 | } |
|
| 492 | 492 | let mut offset: i32 = 0; |
|
| 493 | 493 | let mut remaining = staticSize as i32; |
|
| 494 | 494 | ||
| 495 | 495 | // For large blits where both pointers are in real registers, |
| 512 | 512 | emit::emit(s.e, encode::addi(rdst, rdst, super::DWORD_SIZE)); |
|
| 513 | 513 | } |
|
| 514 | 514 | let brOff = (loopStart as i32 - s.e.codeLen as i32) * super::INSTR_SIZE; |
|
| 515 | 515 | ||
| 516 | 516 | emit::emit(s.e, encode::bne(rsrc, super::SCRATCH1, brOff)); |
|
| 517 | - | remaining -= dwordBytes; |
|
| 517 | + | set remaining -= dwordBytes; |
|
| 518 | 518 | } |
|
| 519 | 519 | ||
| 520 | 520 | // Copy remaining: 8 bytes, then 4 bytes, then 1 byte at a time. |
|
| 521 | 521 | // Before each load/store pair, check whether the offset is |
|
| 522 | 522 | // about to exceed the 12-bit signed immediate range. When |
| 526 | 526 | if offset > super::MAX_IMM - super::DWORD_SIZE { |
|
| 527 | 527 | emit::emitAddImm(s.e, rsrc, rsrc, offset); |
|
| 528 | 528 | if *rdst <> *rsrc { |
|
| 529 | 529 | emit::emitAddImm(s.e, rdst, rdst, offset); |
|
| 530 | 530 | } |
|
| 531 | - | offset = 0; |
|
| 531 | + | set offset = 0; |
|
| 532 | 532 | } |
|
| 533 | 533 | if let off = srcReload { |
|
| 534 | 534 | emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off); |
|
| 535 | 535 | emit::emitLd(s.e, super::SCRATCH1, super::SCRATCH1, offset); |
|
| 536 | 536 | } else { |
|
| 537 | 537 | emit::emitLd(s.e, super::SCRATCH1, rsrc, offset); |
|
| 538 | 538 | } |
|
| 539 | 539 | emit::emitSd(s.e, super::SCRATCH1, rdst, offset); |
|
| 540 | - | offset += super::DWORD_SIZE; |
|
| 541 | - | remaining -= super::DWORD_SIZE; |
|
| 540 | + | set offset += super::DWORD_SIZE; |
|
| 541 | + | set remaining -= super::DWORD_SIZE; |
|
| 542 | 542 | } |
|
| 543 | 543 | if remaining >= super::WORD_SIZE { |
|
| 544 | 544 | if offset > super::MAX_IMM - super::WORD_SIZE { |
|
| 545 | 545 | emit::emitAddImm(s.e, rsrc, rsrc, offset); |
|
| 546 | 546 | if *rdst <> *rsrc { |
|
| 547 | 547 | emit::emitAddImm(s.e, rdst, rdst, offset); |
|
| 548 | 548 | } |
|
| 549 | - | offset = 0; |
|
| 549 | + | set offset = 0; |
|
| 550 | 550 | } |
|
| 551 | 551 | if let off = srcReload { |
|
| 552 | 552 | emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off); |
|
| 553 | 553 | emit::emitLw(s.e, super::SCRATCH1, super::SCRATCH1, offset); |
|
| 554 | 554 | } else { |
|
| 555 | 555 | emit::emitLw(s.e, super::SCRATCH1, rsrc, offset); |
|
| 556 | 556 | } |
|
| 557 | 557 | emit::emitSw(s.e, super::SCRATCH1, rdst, offset); |
|
| 558 | - | offset += super::WORD_SIZE; |
|
| 559 | - | remaining -= super::WORD_SIZE; |
|
| 558 | + | set offset += super::WORD_SIZE; |
|
| 559 | + | set remaining -= super::WORD_SIZE; |
|
| 560 | 560 | } |
|
| 561 | 561 | while remaining > 0 { |
|
| 562 | 562 | if offset > super::MAX_IMM - 1 { |
|
| 563 | 563 | emit::emitAddImm(s.e, rsrc, rsrc, offset); |
|
| 564 | 564 | if *rdst <> *rsrc { |
|
| 565 | 565 | emit::emitAddImm(s.e, rdst, rdst, offset); |
|
| 566 | 566 | } |
|
| 567 | - | offset = 0; |
|
| 567 | + | set offset = 0; |
|
| 568 | 568 | } |
|
| 569 | 569 | if let off = srcReload { |
|
| 570 | 570 | emit::emitLd(s.e, super::SCRATCH1, spillBase(s), off); |
|
| 571 | 571 | emit::emitLb(s.e, super::SCRATCH1, super::SCRATCH1, offset); |
|
| 572 | 572 | } else { |
|
| 573 | 573 | emit::emitLb(s.e, super::SCRATCH1, rsrc, offset); |
|
| 574 | 574 | } |
|
| 575 | 575 | emit::emitSb(s.e, super::SCRATCH1, rdst, offset); |
|
| 576 | - | offset += 1; |
|
| 577 | - | remaining -= 1; |
|
| 576 | + | set offset += 1; |
|
| 577 | + | set remaining -= 1; |
|
| 578 | 578 | } |
|
| 579 | 579 | // Restore base registers if they were advanced (never happens |
|
| 580 | 580 | // in the both-spilled case since size <= MAX_IMM). |
|
| 581 | 581 | if not bothSpilled { |
|
| 582 | 582 | let advanced = staticSize as i32 - offset; |
| 639 | 639 | // Skip extension for zero register. |
|
| 640 | 640 | // Determine extension mode: sign-extend for W32 or SLT, |
|
| 641 | 641 | // zero-extend otherwise. |
|
| 642 | 642 | let mut useSext: bool = undefined; |
|
| 643 | 643 | if let case il::CmpOp::Slt = op { |
|
| 644 | - | useSext = true; |
|
| 644 | + | set useSext = true; |
|
| 645 | 645 | } else { |
|
| 646 | - | useSext = typ == il::Type::W32; |
|
| 646 | + | set useSext = typ == il::Type::W32; |
|
| 647 | 647 | } |
|
| 648 | 648 | if useSext { |
|
| 649 | 649 | if not aIsZero and not isExtendedImm(a, typ, true) { |
|
| 650 | 650 | emitSext(s.e, rs1, rs1, typ); |
|
| 651 | 651 | } |
| 697 | 697 | for c in cases { |
|
| 698 | 698 | emit::loadImm(s.e, super::SCRATCH2, c.value); |
|
| 699 | 699 | ||
| 700 | 700 | if c.args.len > 0 { |
|
| 701 | 701 | let skip = s.nextSynthBlock; |
|
| 702 | - | s.nextSynthBlock = skip + 1; |
|
| 702 | + | set s.nextSynthBlock = skip + 1; |
|
| 703 | 703 | ||
| 704 | 704 | emit::recordBranch(s.e, skip, emit::BranchKind::InvertedCond { |
|
| 705 | 705 | op: il::CmpOp::Eq, rs1, rs2: super::SCRATCH2, |
|
| 706 | 706 | }); |
|
| 707 | 707 | emitBlockArgs(s, func, c.target, c.args); |
| 1062 | 1062 | if dst <> super::ZERO { // Skip entries with no destination. |
|
| 1063 | 1063 | match args[i] { |
|
| 1064 | 1064 | case il::Val::Reg(r) => { |
|
| 1065 | 1065 | if let _ = regalloc::spill::spillSlot(&s.ralloc.spill, r) { |
|
| 1066 | 1066 | // Spilled value needs load, not a register move. |
|
| 1067 | - | pending[i] = true; |
|
| 1068 | - | numPending += 1; |
|
| 1067 | + | set pending[i] = true; |
|
| 1068 | + | set numPending += 1; |
|
| 1069 | 1069 | } else { |
|
| 1070 | 1070 | let src = getReg(s, r); |
|
| 1071 | 1071 | if src <> dst { |
|
| 1072 | 1072 | // Register-to-register move needed. |
|
| 1073 | - | srcRegs[i] = src; |
|
| 1074 | - | isRegMove[i] = true; |
|
| 1075 | - | pending[i] = true; |
|
| 1076 | - | numPending += 1; |
|
| 1073 | + | set srcRegs[i] = src; |
|
| 1074 | + | set isRegMove[i] = true; |
|
| 1075 | + | set pending[i] = true; |
|
| 1076 | + | set numPending += 1; |
|
| 1077 | 1077 | } else { |
|
| 1078 | 1078 | // No move needed. |
|
| 1079 | 1079 | } |
|
| 1080 | 1080 | } |
|
| 1081 | 1081 | }, |
|
| 1082 | 1082 | case il::Val::Imm(_), il::Val::DataSym(_), il::Val::FnAddr(_) => { |
|
| 1083 | - | pending[i] = true; |
|
| 1084 | - | numPending += 1; |
|
| 1083 | + | set pending[i] = true; |
|
| 1084 | + | set numPending += 1; |
|
| 1085 | 1085 | }, |
|
| 1086 | 1086 | case il::Val::Undef => { |
|
| 1087 | 1087 | // Undefined values don't need any move. |
|
| 1088 | 1088 | } |
|
| 1089 | 1089 | } |
| 1104 | 1104 | let mut isReady = true; |
|
| 1105 | 1105 | ||
| 1106 | 1106 | // Check if `dst` is used as source by any other pending register move. |
|
| 1107 | 1107 | for j in 0..n { |
|
| 1108 | 1108 | if j <> i and pending[j] and isRegMove[j] and srcRegs[j] == dst { |
|
| 1109 | - | isReady = false; |
|
| 1109 | + | set isReady = false; |
|
| 1110 | 1110 | break; |
|
| 1111 | 1111 | } |
|
| 1112 | 1112 | } |
|
| 1113 | 1113 | if isReady { |
|
| 1114 | 1114 | // Execute this move. |
| 1116 | 1116 | emitMv(s, dst, srcRegs[i]); |
|
| 1117 | 1117 | } else { |
|
| 1118 | 1118 | // Load immediate, symbol, or spilled value. |
|
| 1119 | 1119 | loadVal(s, dst, args[i]); |
|
| 1120 | 1120 | } |
|
| 1121 | - | found = true; |
|
| 1122 | - | pending[i] = false; |
|
| 1123 | - | numPending -= 1; |
|
| 1121 | + | set found = true; |
|
| 1122 | + | set pending[i] = false; |
|
| 1123 | + | set numPending -= 1; |
|
| 1124 | 1124 | ||
| 1125 | 1125 | break; |
|
| 1126 | 1126 | } |
|
| 1127 | 1127 | } |
|
| 1128 | 1128 | } |
| 1136 | 1136 | // Save this source to scratch. |
|
| 1137 | 1137 | emitMv(s, super::SCRATCH1, src); |
|
| 1138 | 1138 | // Update all pending moves that use this source. |
|
| 1139 | 1139 | for j in 0..n { |
|
| 1140 | 1140 | if pending[j] and isRegMove[j] and srcRegs[j] == src { |
|
| 1141 | - | srcRegs[j] = super::SCRATCH1; |
|
| 1141 | + | set srcRegs[j] = super::SCRATCH1; |
|
| 1142 | 1142 | } |
|
| 1143 | 1143 | } |
|
| 1144 | 1144 | break; |
|
| 1145 | 1145 | } |
|
| 1146 | 1146 | } |
| 1175 | 1175 | } else { |
|
| 1176 | 1176 | let rs = resolveVal(s, super::SCRATCH1, arg); |
|
| 1177 | 1177 | emit::emitSd(s.e, rs, spillBase(s), spillOffset(s, slot)); |
|
| 1178 | 1178 | } |
|
| 1179 | 1179 | } else { |
|
| 1180 | - | dsts[i] = getReg(s, param); |
|
| 1180 | + | set dsts[i] = getReg(s, param); |
|
| 1181 | 1181 | } |
|
| 1182 | 1182 | } |
|
| 1183 | 1183 | emitParallelMoves(s, &dsts[..], args); |
|
| 1184 | 1184 | } |
|
| 1185 | 1185 |
lib/std/arch/rv64/printer.rad
+1 -1
| 91 | 91 | fn writeMnem(out: *mut sexpr::Output, m: *[u8]) { |
|
| 92 | 92 | write(out, m); |
|
| 93 | 93 | let mut i = m.len; |
|
| 94 | 94 | while i < MNEMONIC_WIDTH { |
|
| 95 | 95 | write(out, " "); |
|
| 96 | - | i += 1; |
|
| 96 | + | set i += 1; |
|
| 97 | 97 | } |
|
| 98 | 98 | } |
|
| 99 | 99 | ||
| 100 | 100 | //////////////////////////////// |
|
| 101 | 101 | // Instruction Format Helpers // |
lib/std/collections/dict.rad
+7 -7
| 23 | 23 | ||
| 24 | 24 | /// Create a dict backed by the given entry storage. |
|
| 25 | 25 | /// The storage length must be a power of two. |
|
| 26 | 26 | export fn init(entries: *mut [Entry]) -> Dict { |
|
| 27 | 27 | for i in 0..entries.len { |
|
| 28 | - | entries[i] = Entry { key: &[], value: 0 }; |
|
| 28 | + | set entries[i] = Entry { key: &[], value: 0 }; |
|
| 29 | 29 | } |
|
| 30 | 30 | return Dict { entries, count: 0 }; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | /// Insert or update a key-value pair. Panics if the table exceeds 50% load. |
| 37 | 37 | ||
| 38 | 38 | loop { |
|
| 39 | 39 | let entry = m.entries[idx]; |
|
| 40 | 40 | if entry.key.len == 0 { |
|
| 41 | 41 | assert m.count < m.entries.len / 2, "dict::insert: table full"; |
|
| 42 | - | m.entries[idx] = Entry { key, value }; |
|
| 43 | - | m.count += 1; |
|
| 42 | + | set m.entries[idx] = Entry { key, value }; |
|
| 43 | + | set m.count += 1; |
|
| 44 | 44 | return; |
|
| 45 | 45 | } |
|
| 46 | 46 | if mem::eq(entry.key, key) { |
|
| 47 | - | m.entries[idx].value = value; |
|
| 47 | + | set m.entries[idx].value = value; |
|
| 48 | 48 | return; |
|
| 49 | 49 | } |
|
| 50 | - | idx = (idx + 1) & mask; |
|
| 50 | + | set idx = (idx + 1) & mask; |
|
| 51 | 51 | } |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | 54 | /// Look up a value by key. Returns `nil` if not found. |
|
| 55 | 55 | export fn get(m: *Dict, key: *[u8]) -> ?i32 { |
| 62 | 62 | return nil; |
|
| 63 | 63 | } |
|
| 64 | 64 | if mem::eq(entry.key, key) { |
|
| 65 | 65 | return entry.value; |
|
| 66 | 66 | } |
|
| 67 | - | idx = (idx + 1) & mask; |
|
| 67 | + | set idx = (idx + 1) & mask; |
|
| 68 | 68 | } |
|
| 69 | 69 | } |
|
| 70 | 70 | ||
| 71 | 71 | /// DJB2 hash function. |
|
| 72 | 72 | export fn hash(str: *[u8]) -> u32 { |
|
| 73 | 73 | let mut h: u32 = 5381; |
|
| 74 | 74 | for b in str { |
|
| 75 | - | h = ((h << 5) + h) + b as u32; |
|
| 75 | + | set h = ((h << 5) + h) + b as u32; |
|
| 76 | 76 | } |
|
| 77 | 77 | return h; |
|
| 78 | 78 | } |
lib/std/fmt.rad
+24 -24
| 19 | 19 | let mut x: u32 = val; |
|
| 20 | 20 | let mut i: u32 = buffer.len; |
|
| 21 | 21 | ||
| 22 | 22 | // Handle the zero case separately to ensure a single '0' is written. |
|
| 23 | 23 | if x == 0 { |
|
| 24 | - | i -= 1; |
|
| 25 | - | buffer[i] = '0'; |
|
| 24 | + | set i -= 1; |
|
| 25 | + | set buffer[i] = '0'; |
|
| 26 | 26 | } else { |
|
| 27 | 27 | // Write digits backwards from the end of the buffer. |
|
| 28 | 28 | while x <> 0 { |
|
| 29 | - | i -= 1; |
|
| 30 | - | buffer[i] = ('0' + (x % 10) as u8); |
|
| 31 | - | x /= 10; |
|
| 29 | + | set i -= 1; |
|
| 30 | + | set buffer[i] = ('0' + (x % 10) as u8); |
|
| 31 | + | set x /= 10; |
|
| 32 | 32 | } |
|
| 33 | 33 | } |
|
| 34 | 34 | // Return the slice from the start of the written number to |
|
| 35 | 35 | // the end of the buffer. |
|
| 36 | 36 | return &buffer[i..]; |
| 43 | 43 | let neg: bool = val < 0; |
|
| 44 | 44 | let mut x: u32 = -val as u32 if neg else val as u32; |
|
| 45 | 45 | let mut i: u32 = buffer.len; |
|
| 46 | 46 | // Handle the zero case separately to ensure a single '0' is written. |
|
| 47 | 47 | if x == 0 { |
|
| 48 | - | i -= 1; |
|
| 49 | - | buffer[i] = '0'; |
|
| 48 | + | set i -= 1; |
|
| 49 | + | set buffer[i] = '0'; |
|
| 50 | 50 | } else { |
|
| 51 | 51 | // Write digits backwards from the end of the buffer. |
|
| 52 | 52 | while x <> 0 { |
|
| 53 | - | i -= 1; |
|
| 54 | - | buffer[i] = '0' + (x % 10) as u8; |
|
| 55 | - | x /= 10; |
|
| 53 | + | set i -= 1; |
|
| 54 | + | set buffer[i] = '0' + (x % 10) as u8; |
|
| 55 | + | set x /= 10; |
|
| 56 | 56 | } |
|
| 57 | 57 | // Add the negative sign if needed. |
|
| 58 | 58 | if neg { |
|
| 59 | - | i -= 1; |
|
| 60 | - | buffer[i] = '-'; |
|
| 59 | + | set i -= 1; |
|
| 60 | + | set buffer[i] = '-'; |
|
| 61 | 61 | } |
|
| 62 | 62 | } |
|
| 63 | 63 | return &buffer[i..]; |
|
| 64 | 64 | } |
|
| 65 | 65 |
| 69 | 69 | ||
| 70 | 70 | let mut x: u64 = val; |
|
| 71 | 71 | let mut i: u32 = buffer.len; |
|
| 72 | 72 | ||
| 73 | 73 | if x == 0 { |
|
| 74 | - | i -= 1; |
|
| 75 | - | buffer[i] = '0'; |
|
| 74 | + | set i -= 1; |
|
| 75 | + | set buffer[i] = '0'; |
|
| 76 | 76 | } else { |
|
| 77 | 77 | while x <> 0 { |
|
| 78 | - | i -= 1; |
|
| 79 | - | buffer[i] = ('0' + (x % 10) as u8); |
|
| 80 | - | x /= 10; |
|
| 78 | + | set i -= 1; |
|
| 79 | + | set buffer[i] = ('0' + (x % 10) as u8); |
|
| 80 | + | set x /= 10; |
|
| 81 | 81 | } |
|
| 82 | 82 | } |
|
| 83 | 83 | return &buffer[i..]; |
|
| 84 | 84 | } |
|
| 85 | 85 |
| 89 | 89 | ||
| 90 | 90 | let neg: bool = val < 0; |
|
| 91 | 91 | let mut x: u64 = -val as u64 if neg else val as u64; |
|
| 92 | 92 | let mut i: u32 = buffer.len; |
|
| 93 | 93 | if x == 0 { |
|
| 94 | - | i -= 1; |
|
| 95 | - | buffer[i] = '0'; |
|
| 94 | + | set i -= 1; |
|
| 95 | + | set buffer[i] = '0'; |
|
| 96 | 96 | } else { |
|
| 97 | 97 | while x <> 0 { |
|
| 98 | - | i -= 1; |
|
| 99 | - | buffer[i] = '0' + (x % 10) as u8; |
|
| 100 | - | x /= 10; |
|
| 98 | + | set i -= 1; |
|
| 99 | + | set buffer[i] = '0' + (x % 10) as u8; |
|
| 100 | + | set x /= 10; |
|
| 101 | 101 | } |
|
| 102 | 102 | if neg { |
|
| 103 | - | i -= 1; |
|
| 104 | - | buffer[i] = '-'; |
|
| 103 | + | set i -= 1; |
|
| 104 | + | set buffer[i] = '-'; |
|
| 105 | 105 | } |
|
| 106 | 106 | } |
|
| 107 | 107 | return &buffer[i..]; |
|
| 108 | 108 | } |
|
| 109 | 109 |
lib/std/io.rad
+2 -2
| 46 | 46 | ||
| 47 | 47 | if n == 0 { |
|
| 48 | 48 | break; |
|
| 49 | 49 | } |
|
| 50 | 50 | if n > chunk.len { |
|
| 51 | - | total = buf.len; |
|
| 51 | + | set total = buf.len; |
|
| 52 | 52 | break; |
|
| 53 | 53 | } |
|
| 54 | - | total += n; |
|
| 54 | + | set total += n; |
|
| 55 | 55 | } |
|
| 56 | 56 | return &buf[..total]; |
|
| 57 | 57 | } |
lib/std/lang/alloc.rad
+4 -4
| 44 | 44 | ||
| 45 | 45 | if newOffset > arena.data.len as u32 { |
|
| 46 | 46 | throw AllocError::OutOfMemory; |
|
| 47 | 47 | } |
|
| 48 | 48 | let base: *mut u8 = &mut arena.data[aligned]; |
|
| 49 | - | arena.offset = newOffset; |
|
| 49 | + | set arena.offset = newOffset; |
|
| 50 | 50 | ||
| 51 | 51 | return base as *mut opaque; |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | 54 | /// Reset the arena, allowing all memory to be reused. |
|
| 55 | 55 | /// |
|
| 56 | 56 | /// Does not zero the memory. |
|
| 57 | 57 | export fn reset(arena: *mut Arena) { |
|
| 58 | - | arena.offset = 0; |
|
| 58 | + | set arena.offset = 0; |
|
| 59 | 59 | } |
|
| 60 | 60 | ||
| 61 | 61 | /// Save the current arena state for later restoration. |
|
| 62 | 62 | export fn save(arena: *Arena) -> u32 { |
|
| 63 | 63 | return arena.offset; |
|
| 64 | 64 | } |
|
| 65 | 65 | ||
| 66 | 66 | /// Restore the arena to a previously saved state, reclaiming all |
|
| 67 | 67 | /// allocations made since that point. |
|
| 68 | 68 | export fn restore(arena: *mut Arena, savedOffset: u32) { |
|
| 69 | - | arena.offset = savedOffset; |
|
| 69 | + | set arena.offset = savedOffset; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | /// Returns the number of bytes currently allocated. |
|
| 73 | 73 | export fn used(arena: *Arena) -> u32 { |
|
| 74 | 74 | return arena.offset; |
| 85 | 85 | } |
|
| 86 | 86 | ||
| 87 | 87 | /// Commits `size` bytes of allocation, advancing the offset. |
|
| 88 | 88 | /// Use after writing to the buffer returned by [`remainingBuf`]. |
|
| 89 | 89 | export fn commit(arena: *mut Arena, size: u32) { |
|
| 90 | - | arena.offset += size; |
|
| 90 | + | set arena.offset += size; |
|
| 91 | 91 | } |
|
| 92 | 92 | ||
| 93 | 93 | /// Allocate a slice of `count` elements, each of `size` bytes with given alignment. |
|
| 94 | 94 | /// |
|
| 95 | 95 | /// Returns a type-erased slice that should be cast to the appropriate `*[T]`. |
lib/std/lang/alloc/tests.rad
+2 -2
| 50 | 50 | let p2 = try! super::alloc(&mut arena, 8, 4); |
|
| 51 | 51 | ||
| 52 | 52 | // Arena is now full, this should fail. |
|
| 53 | 53 | let mut failed = false; |
|
| 54 | 54 | try super::alloc(&mut arena, 1, 1) catch { |
|
| 55 | - | failed = true; |
|
| 55 | + | set failed = true; |
|
| 56 | 56 | }; |
|
| 57 | 57 | try testing::expect(failed); |
|
| 58 | 58 | } |
|
| 59 | 59 | ||
| 60 | 60 | /// Test that reset allows reuse of memory. |
| 97 | 97 | ||
| 98 | 98 | // Try to allocate 16 bytes with 4-byte alignment. |
|
| 99 | 99 | // Aligned offset would be 4, then 4 + 16 = 20 > 16, so should fail. |
|
| 100 | 100 | let mut failed = false; |
|
| 101 | 101 | try super::alloc(&mut arena, 16, 4) catch { |
|
| 102 | - | failed = true; |
|
| 102 | + | set failed = true; |
|
| 103 | 103 | }; |
|
| 104 | 104 | try testing::expect(failed); |
|
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | /// Test the Allocator interface backed by an arena. |
lib/std/lang/ast.rad
+3 -3
| 718 | 718 | ConstDecl(ConstDecl), |
|
| 719 | 719 | /// Static storage declaration. |
|
| 720 | 720 | StaticDecl(StaticDecl), |
|
| 721 | 721 | /// Type signature node. |
|
| 722 | 722 | TypeSig(TypeSig), |
|
| 723 | - | /// Assignment expression. |
|
| 723 | + | /// Assignment statement. |
|
| 724 | 724 | Assign(Assign), |
|
| 725 | 725 | /// Expression statement. |
|
| 726 | 726 | ExprStmt(*Node), |
|
| 727 | 727 | /// Module declaration (`mod`). |
|
| 728 | 728 | Mod(Mod), |
| 833 | 833 | /// Allocate a new AST node from the arena with the given span and value. |
|
| 834 | 834 | export fn allocNode(arena: *mut NodeArena, span: Span, value: NodeValue) -> *mut Node { |
|
| 835 | 835 | let p = try! alloc::alloc(&mut arena.arena, @sizeOf(Node), @alignOf(Node)); |
|
| 836 | 836 | let node = p as *mut Node; |
|
| 837 | 837 | let nodeId = arena.nextId; |
|
| 838 | - | arena.nextId = nodeId + 1; |
|
| 838 | + | set arena.nextId = nodeId + 1; |
|
| 839 | 839 | ||
| 840 | - | *node = Node { id: nodeId, span, value }; |
|
| 840 | + | set *node = Node { id: nodeId, span, value }; |
|
| 841 | 841 | ||
| 842 | 842 | return node; |
|
| 843 | 843 | } |
|
| 844 | 844 | ||
| 845 | 845 | /// Allocate a synthetic AST node with a zero-length span. |
lib/std/lang/ast/printer.rad
+21 -21
| 89 | 89 | case super::TypeSig::Record { fields, .. } => |
|
| 90 | 90 | return sexpr::list(a, "record", nodeListToExprs(a, &fields[..])), |
|
| 91 | 91 | case super::TypeSig::Fn(sig) => { |
|
| 92 | 92 | let mut ret = sexpr::sym("void"); |
|
| 93 | 93 | if let rt = sig.returnType { |
|
| 94 | - | ret = toExpr(a, rt); |
|
| 94 | + | set ret = toExpr(a, rt); |
|
| 95 | 95 | } |
|
| 96 | 96 | return sexpr::list(a, "fn", &[sexpr::list(a, "params", nodeListToExprs(a, &sig.params[..])), ret]); |
|
| 97 | 97 | } |
|
| 98 | 98 | case super::TypeSig::TraitObject { traitName, mutable } => |
|
| 99 | 99 | return sexpr::list(a, "obj", &[sexpr::sym("mut"), toExpr(a, traitName)]) if mutable |
| 106 | 106 | if nodes.len == 0 { |
|
| 107 | 107 | return &[]; |
|
| 108 | 108 | } |
|
| 109 | 109 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 110 | 110 | for node, i in nodes { |
|
| 111 | - | buf[i] = toExpr(a, node); |
|
| 111 | + | set buf[i] = toExpr(a, node); |
|
| 112 | 112 | } |
|
| 113 | 113 | return buf; |
|
| 114 | 114 | } |
|
| 115 | 115 | ||
| 116 | 116 | /// Convert an optional node to an expression, or return placeholder. |
| 144 | 144 | } |
|
| 145 | 145 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 146 | 146 | for prong, i in nodes { |
|
| 147 | 147 | match prong.value { |
|
| 148 | 148 | case super::NodeValue::MatchProng(p) => { |
|
| 149 | - | buf[i] = prongToExpr(a, p); |
|
| 149 | + | set buf[i] = prongToExpr(a, p); |
|
| 150 | 150 | } |
|
| 151 | 151 | else => { |
|
| 152 | - | buf[i] = sexpr::sym("<invalid>"); |
|
| 152 | + | set buf[i] = sexpr::sym("<invalid>"); |
|
| 153 | 153 | } |
|
| 154 | 154 | } |
|
| 155 | 155 | } |
|
| 156 | 156 | return buf; |
|
| 157 | 157 | } |
| 194 | 194 | } |
|
| 195 | 195 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 196 | 196 | for node, i in nodes { |
|
| 197 | 197 | match node.value { |
|
| 198 | 198 | case super::NodeValue::RecordField { field, type, value } => { |
|
| 199 | - | buf[i] = fieldToExpr(a, field, type, value); |
|
| 199 | + | set buf[i] = fieldToExpr(a, field, type, value); |
|
| 200 | 200 | } |
|
| 201 | 201 | else => { |
|
| 202 | - | buf[i] = sexpr::sym("<invalid>"); |
|
| 202 | + | set buf[i] = sexpr::sym("<invalid>"); |
|
| 203 | 203 | } |
|
| 204 | 204 | } |
|
| 205 | 205 | } |
|
| 206 | 206 | return buf; |
|
| 207 | 207 | } |
| 218 | 218 | } |
|
| 219 | 219 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 220 | 220 | for node, i in nodes { |
|
| 221 | 221 | match node.value { |
|
| 222 | 222 | case super::NodeValue::UnionDeclVariant(v) => { |
|
| 223 | - | buf[i] = variantToExpr(a, v.name, v.type); |
|
| 223 | + | set buf[i] = variantToExpr(a, v.name, v.type); |
|
| 224 | 224 | } |
|
| 225 | 225 | else => { |
|
| 226 | - | buf[i] = sexpr::sym("<invalid>"); |
|
| 226 | + | set buf[i] = sexpr::sym("<invalid>"); |
|
| 227 | 227 | } |
|
| 228 | 228 | } |
|
| 229 | 229 | } |
|
| 230 | 230 | return buf; |
|
| 231 | 231 | } |
| 255 | 255 | return sexpr::list(a, binOpName(b.op), &[toExpr(a, b.left), toExpr(a, b.right)]), |
|
| 256 | 256 | case super::NodeValue::UnOp(u) => |
|
| 257 | 257 | return sexpr::list(a, unOpName(u.op), &[toExpr(a, u.value)]), |
|
| 258 | 258 | case super::NodeValue::Call(c) => { |
|
| 259 | 259 | let buf = try! sexpr::allocExprs(a, c.args.len as u32 + 1); |
|
| 260 | - | buf[0] = toExpr(a, c.callee); |
|
| 261 | - | for arg, i in c.args { buf[i + 1] = toExpr(a, arg); } |
|
| 260 | + | set buf[0] = toExpr(a, c.callee); |
|
| 261 | + | for arg, i in c.args { set buf[i + 1] = toExpr(a, arg); } |
|
| 262 | 262 | return sexpr::Expr::List { head: "call", tail: buf, multiline: false }; |
|
| 263 | 263 | } |
|
| 264 | 264 | case super::NodeValue::BuiltinCall { kind, args } => |
|
| 265 | 265 | return sexpr::list(a, builtinName(kind), nodeListToExprs(a, &args[..])), |
|
| 266 | 266 | case super::NodeValue::Subscript { container, index } => |
| 281 | 281 | case super::NodeValue::ArrayRepeatLit(rep) => |
|
| 282 | 282 | return sexpr::list(a, "array-repeat", &[toExpr(a, rep.item), toExpr(a, rep.count)]), |
|
| 283 | 283 | case super::NodeValue::RecordLit(lit) => { |
|
| 284 | 284 | let mut total: u32 = lit.fields.len as u32; |
|
| 285 | 285 | if let _ = lit.typeName { |
|
| 286 | - | total += 1; |
|
| 286 | + | set total += 1; |
|
| 287 | 287 | } |
|
| 288 | 288 | let buf = try! sexpr::allocExprs(a, total); |
|
| 289 | 289 | let mut idx: u32 = 0; |
|
| 290 | 290 | if let tn = lit.typeName { |
|
| 291 | - | buf[idx] = toExpr(a, tn); idx = idx + 1; |
|
| 291 | + | set buf[idx] = toExpr(a, tn); set idx = idx + 1; |
|
| 292 | 292 | } |
|
| 293 | 293 | for field, i in lit.fields { |
|
| 294 | - | buf[idx + i] = toExpr(a, field); |
|
| 294 | + | set buf[idx + i] = toExpr(a, field); |
|
| 295 | 295 | } |
|
| 296 | 296 | return sexpr::Expr::List { head: "record-lit", tail: buf, multiline: lit.fields.len > 2 }; |
|
| 297 | 297 | } |
|
| 298 | 298 | case super::NodeValue::RecordLitField(f) => |
|
| 299 | 299 | return sexpr::list(a, "field", &[toExprOpt(a, f.label), toExpr(a, f.value)]), |
| 309 | 309 | case super::Attribute::Intrinsic => return sexpr::sym("@intrinsic"), |
|
| 310 | 310 | } |
|
| 311 | 311 | } |
|
| 312 | 312 | case super::NodeValue::Try(t) => { |
|
| 313 | 313 | let mut head = "try"; |
|
| 314 | - | if t.shouldPanic { head = "try!"; } |
|
| 314 | + | if t.shouldPanic { set head = "try!"; } |
|
| 315 | 315 | if t.catches.len > 0 { |
|
| 316 | 316 | let catches = nodeListToExprs(a, &t.catches[..]); |
|
| 317 | 317 | return sexpr::list(a, head, &[toExpr(a, t.expr), sexpr::block(a, "catches", &[], catches)]); |
|
| 318 | 318 | } |
|
| 319 | 319 | return sexpr::list(a, head, &[toExpr(a, t.expr)]); |
| 321 | 321 | case super::NodeValue::CatchClause(clause) => { |
|
| 322 | 322 | let mut head = "catch"; |
|
| 323 | 323 | let mut children: [sexpr::Expr; 3] = undefined; |
|
| 324 | 324 | let mut len: u32 = 0; |
|
| 325 | 325 | if let b = clause.binding { |
|
| 326 | - | children[len] = toExpr(a, b); |
|
| 327 | - | len += 1; |
|
| 326 | + | set children[len] = toExpr(a, b); |
|
| 327 | + | set len += 1; |
|
| 328 | 328 | } |
|
| 329 | 329 | if let t = clause.typeNode { |
|
| 330 | - | children[len] = toExpr(a, t); |
|
| 331 | - | len += 1; |
|
| 330 | + | set children[len] = toExpr(a, t); |
|
| 331 | + | set len += 1; |
|
| 332 | 332 | } |
|
| 333 | - | children[len] = toExpr(a, clause.body); |
|
| 334 | - | len += 1; |
|
| 333 | + | set children[len] = toExpr(a, clause.body); |
|
| 334 | + | set len += 1; |
|
| 335 | 335 | return sexpr::list(a, head, &children[..len]); |
|
| 336 | 336 | } |
|
| 337 | 337 | case super::NodeValue::Block(blk) => { |
|
| 338 | 338 | let children = nodeListToExprs(a, &blk.statements[..]); |
|
| 339 | 339 | return sexpr::block(a, "block", &[], children); |
|
| 340 | 340 | } |
|
| 341 | 341 | case super::NodeValue::Let(decl) => { |
|
| 342 | 342 | let mut head = "let"; |
|
| 343 | - | if decl.mutable { head = "let-mut"; } |
|
| 343 | + | if decl.mutable { set head = "let-mut"; } |
|
| 344 | 344 | return sexpr::list(a, head, &[ |
|
| 345 | 345 | toExpr(a, decl.ident), |
|
| 346 | 346 | toExprOrNull(a, decl.type), |
|
| 347 | 347 | toExpr(a, decl.value) |
|
| 348 | 348 | ]); |
lib/std/lang/gen/bitset.rad
+17 -17
| 41 | 41 | } |
|
| 42 | 42 | ||
| 43 | 43 | /// Create a new bitset backed by the given storage, zeroing it first. |
|
| 44 | 44 | export fn init(bits: *mut [u32]) -> Bitset { |
|
| 45 | 45 | for i in 0..bits.len { |
|
| 46 | - | bits[i] = 0; |
|
| 46 | + | set bits[i] = 0; |
|
| 47 | 47 | } |
|
| 48 | 48 | return new(bits); |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | /// Create a bitset from arena allocation. |
| 62 | 62 | return; |
|
| 63 | 63 | } |
|
| 64 | 64 | let word = n / 32; |
|
| 65 | 65 | let b = n % 32; |
|
| 66 | 66 | ||
| 67 | - | bs.bits[word] |= (1 << b); |
|
| 67 | + | set bs.bits[word] |= (1 << b); |
|
| 68 | 68 | } |
|
| 69 | 69 | ||
| 70 | 70 | /// Clear bit `n` in the bitset. |
|
| 71 | 71 | export fn clear(bs: *mut Bitset, n: u32) { |
|
| 72 | 72 | if n >= bs.len { |
|
| 73 | 73 | return; |
|
| 74 | 74 | } |
|
| 75 | 75 | let word = n / 32; |
|
| 76 | 76 | let b = n % 32; |
|
| 77 | 77 | ||
| 78 | - | bs.bits[word] &= ~(1 << b); |
|
| 78 | + | set bs.bits[word] &= ~(1 << b); |
|
| 79 | 79 | } |
|
| 80 | 80 | ||
| 81 | 81 | /// Check if bit `n` is set. |
|
| 82 | 82 | export fn contains(bs: *Bitset, n: u32) -> bool { |
|
| 83 | 83 | if n >= bs.len { |
| 94 | 94 | let mut total: u32 = 0; |
|
| 95 | 95 | let numWords = bs.bits.len; |
|
| 96 | 96 | for i in 0..numWords { |
|
| 97 | 97 | let word = bs.bits[i]; |
|
| 98 | 98 | if word <> 0 { |
|
| 99 | - | total += popCount(word); |
|
| 99 | + | set total += popCount(word); |
|
| 100 | 100 | } |
|
| 101 | 101 | } |
|
| 102 | 102 | return total; |
|
| 103 | 103 | } |
|
| 104 | 104 | ||
| 105 | 105 | /// Population count for a 32-bit word. |
|
| 106 | 106 | fn popCount(x: u32) -> u32 { |
|
| 107 | 107 | let mut n = x; |
|
| 108 | - | n -= ((n >> 1) & 0x55555555); |
|
| 109 | - | n = (n & 0x33333333) + ((n >> 2) & 0x33333333); |
|
| 110 | - | n = (n + (n >> 4)) & 0x0F0F0F0F; |
|
| 111 | - | n += (n >> 8); |
|
| 112 | - | n += (n >> 16); |
|
| 108 | + | set n -= ((n >> 1) & 0x55555555); |
|
| 109 | + | set n = (n & 0x33333333) + ((n >> 2) & 0x33333333); |
|
| 110 | + | set n = (n + (n >> 4)) & 0x0F0F0F0F; |
|
| 111 | + | set n += (n >> 8); |
|
| 112 | + | set n += (n >> 16); |
|
| 113 | 113 | ||
| 114 | 114 | return n & 0x3F; |
|
| 115 | 115 | } |
|
| 116 | 116 | ||
| 117 | 117 | /// Union: `dst = dst | src`. |
|
| 118 | 118 | export fn union_(dst: *mut Bitset, src: *Bitset) { |
|
| 119 | 119 | let numWords = dst.bits.len; |
|
| 120 | 120 | let srcWords = src.bits.len; |
|
| 121 | 121 | let minWords = min(numWords, srcWords); |
|
| 122 | 122 | for i in 0..minWords { |
|
| 123 | - | dst.bits[i] |= src.bits[i]; |
|
| 123 | + | set dst.bits[i] |= src.bits[i]; |
|
| 124 | 124 | } |
|
| 125 | 125 | } |
|
| 126 | 126 | ||
| 127 | 127 | /// Subtract: `dst = dst - src`. |
|
| 128 | 128 | export fn subtract(dst: *mut Bitset, src: *Bitset) { |
|
| 129 | 129 | let numWords = dst.bits.len; |
|
| 130 | 130 | let srcWords = src.bits.len; |
|
| 131 | 131 | let minWords = min(numWords, srcWords); |
|
| 132 | 132 | for i in 0..minWords { |
|
| 133 | - | dst.bits[i] &= ~src.bits[i]; |
|
| 133 | + | set dst.bits[i] &= ~src.bits[i]; |
|
| 134 | 134 | } |
|
| 135 | 135 | } |
|
| 136 | 136 | ||
| 137 | 137 | /// Check if two bitsets are equal. |
|
| 138 | 138 | export fn eq(a: *Bitset, b: *Bitset) -> bool { |
| 155 | 155 | let numWords = dst.bits.len; |
|
| 156 | 156 | let srcWords = src.bits.len; |
|
| 157 | 157 | let minWords = min(numWords, srcWords); |
|
| 158 | 158 | ||
| 159 | 159 | for i in 0..minWords { |
|
| 160 | - | dst.bits[i] = src.bits[i]; |
|
| 160 | + | set dst.bits[i] = src.bits[i]; |
|
| 161 | 161 | } |
|
| 162 | 162 | // Clear remaining words if destination is larger. |
|
| 163 | 163 | for i in minWords..numWords { |
|
| 164 | - | dst.bits[i] = 0; |
|
| 164 | + | set dst.bits[i] = 0; |
|
| 165 | 165 | } |
|
| 166 | 166 | } |
|
| 167 | 167 | ||
| 168 | 168 | /// Clear all bits. |
|
| 169 | 169 | export fn clearAll(bs: *mut Bitset) { |
|
| 170 | 170 | let numWords = bs.bits.len; |
|
| 171 | 171 | for i in 0..numWords { |
|
| 172 | - | bs.bits[i] = 0; |
|
| 172 | + | set bs.bits[i] = 0; |
|
| 173 | 173 | } |
|
| 174 | 174 | } |
|
| 175 | 175 | ||
| 176 | 176 | /// Iterator state for iterating set bits. |
|
| 177 | 177 | export record BitIter { |
| 192 | 192 | /// Get the next set bit, or nil if none remain. |
|
| 193 | 193 | export fn iterNext(it: *mut BitIter) -> ?u32 { |
|
| 194 | 194 | let numWords = it.bs.bits.len; |
|
| 195 | 195 | // Skip to next non-zero word. |
|
| 196 | 196 | while it.remaining == 0 { |
|
| 197 | - | it.wordIdx += 1; |
|
| 197 | + | set it.wordIdx += 1; |
|
| 198 | 198 | if it.wordIdx >= numWords { |
|
| 199 | 199 | return nil; |
|
| 200 | 200 | } |
|
| 201 | - | it.remaining = it.bs.bits[it.wordIdx]; |
|
| 201 | + | set it.remaining = it.bs.bits[it.wordIdx]; |
|
| 202 | 202 | } |
|
| 203 | 203 | // Find lowest set bit position using de Bruijn sequence. |
|
| 204 | 204 | let b = ctz(it.remaining); |
|
| 205 | 205 | let n = it.wordIdx * 32 + b; |
|
| 206 | 206 | if n >= it.bs.len { |
|
| 207 | 207 | return nil; |
|
| 208 | 208 | } |
|
| 209 | 209 | // Clear the lowest set bit. |
|
| 210 | - | it.remaining &= it.remaining - 1; |
|
| 210 | + | set it.remaining &= it.remaining - 1; |
|
| 211 | 211 | ||
| 212 | 212 | return n; |
|
| 213 | 213 | } |
|
| 214 | 214 | ||
| 215 | 215 | /// Count trailing zeros in a 32-bit value. |
lib/std/lang/gen/bitset/tests.rad
+2 -2
| 186 | 186 | let mut it = super::iter(&bs); |
|
| 187 | 187 | let mut count: u32 = 0; |
|
| 188 | 188 | let mut sum: u32 = 0; |
|
| 189 | 189 | ||
| 190 | 190 | while let n = super::iterNext(&mut it) { |
|
| 191 | - | count += 1; |
|
| 192 | - | sum += n; |
|
| 191 | + | set count += 1; |
|
| 192 | + | set sum += n; |
|
| 193 | 193 | } |
|
| 194 | 194 | ||
| 195 | 195 | try testing::expect(count == 4); |
|
| 196 | 196 | try testing::expect(sum == 3 + 31 + 32 + 50); |
|
| 197 | 197 | } |
lib/std/lang/gen/data.rad
+15 -15
| 46 | 46 | ||
| 47 | 47 | // Initialized data first. |
|
| 48 | 48 | for i in 0..program.data.len { |
|
| 49 | 49 | let data = &program.data[i]; |
|
| 50 | 50 | if data.readOnly == readOnly and not data.isUndefined { |
|
| 51 | - | offset = mem::alignUp(offset, data.alignment); |
|
| 52 | - | syms[*count] = DataSym { name: data.name, addr: base + offset }; |
|
| 53 | - | *count += 1; |
|
| 54 | - | offset += data.size; |
|
| 51 | + | set offset = mem::alignUp(offset, data.alignment); |
|
| 52 | + | set syms[*count] = DataSym { name: data.name, addr: base + offset }; |
|
| 53 | + | set *count += 1; |
|
| 54 | + | set offset += data.size; |
|
| 55 | 55 | } |
|
| 56 | 56 | } |
|
| 57 | 57 | // Uninitialized data after. |
|
| 58 | 58 | for i in 0..program.data.len { |
|
| 59 | 59 | let data = &program.data[i]; |
|
| 60 | 60 | if data.readOnly == readOnly and data.isUndefined { |
|
| 61 | - | offset = mem::alignUp(offset, data.alignment); |
|
| 62 | - | syms[*count] = DataSym { name: data.name, addr: base + offset }; |
|
| 63 | - | *count += 1; |
|
| 64 | - | offset += data.size; |
|
| 61 | + | set offset = mem::alignUp(offset, data.alignment); |
|
| 62 | + | set syms[*count] = DataSym { name: data.name, addr: base + offset }; |
|
| 63 | + | set *count += 1; |
|
| 64 | + | set offset += data.size; |
|
| 65 | 65 | } |
|
| 66 | 66 | } |
|
| 67 | 67 | return offset; |
|
| 68 | 68 | } |
|
| 69 | 69 |
| 81 | 81 | let mut offset: u32 = 0; |
|
| 82 | 82 | ||
| 83 | 83 | for i in 0..program.data.len { |
|
| 84 | 84 | let data = &program.data[i]; |
|
| 85 | 85 | if data.readOnly == readOnly and not data.isUndefined { |
|
| 86 | - | offset = mem::alignUp(offset, data.alignment); |
|
| 86 | + | set offset = mem::alignUp(offset, data.alignment); |
|
| 87 | 87 | assert offset + data.size <= buf.len, "emitSection: buffer overflow"; |
|
| 88 | 88 | for j in 0..data.values.len { |
|
| 89 | 89 | let v = &data.values[j]; |
|
| 90 | 90 | for _ in 0..v.count { |
|
| 91 | 91 | match v.item { |
|
| 92 | 92 | case il::DataItem::Val { typ, val } => { |
|
| 93 | 93 | let size = il::typeSize(typ); |
|
| 94 | 94 | let valPtr = &val as *u8; |
|
| 95 | 95 | try! mem::copy(&mut buf[offset..], @sliceOf(valPtr, size)); |
|
| 96 | - | offset += size; |
|
| 96 | + | set offset += size; |
|
| 97 | 97 | }, |
|
| 98 | 98 | case il::DataItem::Sym(name) => { |
|
| 99 | 99 | let addr = lookupAddr(dataSymMap, name) else { |
|
| 100 | 100 | panic "emitSection: data symbol not found"; |
|
| 101 | 101 | }; |
|
| 102 | 102 | let addr64: u64 = addr as u64; |
|
| 103 | 103 | let addrPtr = &addr64 as *u8; |
|
| 104 | 104 | ||
| 105 | 105 | try! mem::copy(&mut buf[offset..], @sliceOf(addrPtr, 8)); |
|
| 106 | 106 | ||
| 107 | - | offset += 8; |
|
| 107 | + | set offset += 8; |
|
| 108 | 108 | }, |
|
| 109 | 109 | case il::DataItem::Fn(name) => { |
|
| 110 | 110 | let addr = codeBase + labels::funcOffset(fnLabels, name) as u32; |
|
| 111 | 111 | let addr64: u64 = addr as u64; |
|
| 112 | 112 | let addrPtr = &addr64 as *u8; |
|
| 113 | 113 | ||
| 114 | 114 | try! mem::copy(&mut buf[offset..], @sliceOf(addrPtr, 8)); |
|
| 115 | 115 | ||
| 116 | - | offset += 8; |
|
| 116 | + | set offset += 8; |
|
| 117 | 117 | }, |
|
| 118 | 118 | case il::DataItem::Str(s) => { |
|
| 119 | 119 | try! mem::copy(&mut buf[offset..], s); |
|
| 120 | - | offset += s.len; |
|
| 120 | + | set offset += s.len; |
|
| 121 | 121 | }, |
|
| 122 | 122 | case il::DataItem::Undef => { |
|
| 123 | - | buf[offset] = 0; |
|
| 124 | - | offset += 1; |
|
| 123 | + | set buf[offset] = 0; |
|
| 124 | + | set offset += 1; |
|
| 125 | 125 | }, |
|
| 126 | 126 | } |
|
| 127 | 127 | } |
|
| 128 | 128 | } |
|
| 129 | 129 | } |
lib/std/lang/gen/labels.rad
+3 -3
| 31 | 31 | }; |
|
| 32 | 32 | } |
|
| 33 | 33 | ||
| 34 | 34 | /// Reset block count for a new function. |
|
| 35 | 35 | export fn resetBlocks(l: *mut Labels) { |
|
| 36 | - | l.blockCount = 0; |
|
| 36 | + | set l.blockCount = 0; |
|
| 37 | 37 | } |
|
| 38 | 38 | ||
| 39 | 39 | /// Record a block's code offset by its index. O(1). |
|
| 40 | 40 | export fn recordBlock(l: *mut Labels, blockIdx: u32, offset: i32) { |
|
| 41 | 41 | assert blockIdx < l.blockOffsets.len, "recordBlock: block index out of range"; |
|
| 42 | - | l.blockOffsets[blockIdx] = offset; |
|
| 43 | - | l.blockCount += 1; |
|
| 42 | + | set l.blockOffsets[blockIdx] = offset; |
|
| 43 | + | set l.blockCount += 1; |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | /// Look up a block's byte offset by index. O(1). |
|
| 47 | 47 | export fn blockOffset(l: *Labels, blockIdx: u32) -> i32 { |
|
| 48 | 48 | assert blockIdx < l.blockCount, "blockOffset: block not recorded"; |
lib/std/lang/gen/regalloc/assign.rad
+21 -21
| 69 | 69 | } |
|
| 70 | 70 | ||
| 71 | 71 | // Allocate output structures. |
|
| 72 | 72 | let assignments = try alloc::allocSlice(arena, @sizeOf(?gen::Reg), @alignOf(?gen::Reg), maxReg) as *mut [?gen::Reg]; |
|
| 73 | 73 | for i in 0..maxReg { |
|
| 74 | - | assignments[i] = nil; |
|
| 74 | + | set assignments[i] = nil; |
|
| 75 | 75 | } |
|
| 76 | 76 | // Pre-assign function parameters to argument registers. |
|
| 77 | 77 | // Cross-call params are NOT pre-assigned here; they will be allocated |
|
| 78 | 78 | // to callee-saved registers by the normal path, and isel emits moves |
|
| 79 | 79 | // from the arg register to the assigned register at function entry. |
|
| 80 | 80 | for param, i in func.params { |
|
| 81 | 81 | if i < config.argRegs.len { |
|
| 82 | 82 | if not bitset::contains(&spillInfo.calleeClass, param.value.n) { |
|
| 83 | - | assignments[param.value.n] = config.argRegs[i]; |
|
| 83 | + | set assignments[param.value.n] = config.argRegs[i]; |
|
| 84 | 84 | } |
|
| 85 | 85 | } |
|
| 86 | 86 | } |
|
| 87 | 87 | let blkEnd = try alloc::allocSlice(arena, @sizeOf(RegMap), @alignOf(RegMap), blockCount) as *mut [RegMap]; |
|
| 88 | 88 | for i in 0..blockCount { |
|
| 89 | - | blkEnd[i] = try createRegMap(arena); |
|
| 89 | + | set blkEnd[i] = try createRegMap(arena); |
|
| 90 | 90 | } |
|
| 91 | 91 | // Allocate used registers bitset (32 physical registers per 32-bit word). |
|
| 92 | 92 | let usedRegsBits = try alloc::allocSlice(arena, @sizeOf(u32), @alignOf(u32), 1) as *mut [u32]; |
|
| 93 | 93 | let mut usedRegs = bitset::init(usedRegsBits); |
|
| 94 | 94 |
| 98 | 98 | // Phase 2: Linear scan allocation. |
|
| 99 | 99 | for b in 0..blockCount { |
|
| 100 | 100 | let block = &func.blocks[b]; |
|
| 101 | 101 | ||
| 102 | 102 | // Reset for new block. |
|
| 103 | - | current.n = 0; |
|
| 103 | + | set current.n = 0; |
|
| 104 | 104 | bitset::clearAll(&mut usedRegs); |
|
| 105 | 105 | ||
| 106 | 106 | // Initialize from predecessor if single predecessor. |
|
| 107 | 107 | // Only copy values that are live-in to this block. |
|
| 108 | 108 | if block.preds.len == 1 { |
|
| 109 | 109 | let pred = &blkEnd[block.preds[0]]; |
|
| 110 | 110 | for k in 0..pred.n { |
|
| 111 | 111 | if bitset::contains(&live.liveIn[b], pred.virtRegs[k]) { |
|
| 112 | - | current.virtRegs[current.n] = pred.virtRegs[k]; |
|
| 113 | - | current.physRegs[current.n] = pred.physRegs[k]; |
|
| 114 | - | current.n += 1; |
|
| 112 | + | set current.virtRegs[current.n] = pred.virtRegs[k]; |
|
| 113 | + | set current.physRegs[current.n] = pred.physRegs[k]; |
|
| 114 | + | set current.n += 1; |
|
| 115 | 115 | bitset::put(&mut usedRegs, *pred.physRegs[k] as u32); |
|
| 116 | 116 | } |
|
| 117 | 117 | } |
|
| 118 | 118 | } |
|
| 119 | 119 |
| 132 | 132 | // Also track in current mapping for block-end state. |
|
| 133 | 133 | if rmapFind(¤t, ssaReg) == nil { |
|
| 134 | 134 | rmapSet(&mut current, ssaReg, phys); |
|
| 135 | 135 | } |
|
| 136 | 136 | } else { |
|
| 137 | - | assignments[ssaReg] = rallocReg(&mut current, &mut usedRegs, ssaReg, allocatable, config.calleeSaved, spillInfo); |
|
| 137 | + | set assignments[ssaReg] = rallocReg(&mut current, &mut usedRegs, ssaReg, allocatable, config.calleeSaved, spillInfo); |
|
| 138 | 138 | } |
|
| 139 | 139 | } |
|
| 140 | 140 | } |
|
| 141 | 141 | ||
| 142 | 142 | // Allocate block parameters. |
|
| 143 | 143 | for p in block.params { |
|
| 144 | 144 | if p.value.n < maxReg and not spill::isSpilled(spillInfo, p.value) { |
|
| 145 | - | assignments[p.value.n] = rallocReg(&mut current, &mut usedRegs, p.value.n, allocatable, config.calleeSaved, spillInfo); |
|
| 145 | + | set assignments[p.value.n] = rallocReg(&mut current, &mut usedRegs, p.value.n, allocatable, config.calleeSaved, spillInfo); |
|
| 146 | 146 | } |
|
| 147 | 147 | } |
|
| 148 | 148 | ||
| 149 | 149 | // Process each instruction. |
|
| 150 | 150 | for instr, i in block.instrs { |
| 163 | 163 | il::forEachReg(instr, processInstrRegCb, &mut ctx as *mut opaque); |
|
| 164 | 164 | ||
| 165 | 165 | // Allocate destination. |
|
| 166 | 166 | if let dst = il::instrDst(instr) { |
|
| 167 | 167 | if dst.n < maxReg and not spill::isSpilled(spillInfo, dst) { |
|
| 168 | - | assignments[dst.n] = rallocReg(&mut current, &mut usedRegs, dst.n, allocatable, config.calleeSaved, spillInfo); |
|
| 168 | + | set assignments[dst.n] = rallocReg(&mut current, &mut usedRegs, dst.n, allocatable, config.calleeSaved, spillInfo); |
|
| 169 | 169 | } |
|
| 170 | 170 | } |
|
| 171 | 171 | } |
|
| 172 | 172 | // Save block-end state. |
|
| 173 | - | blkEnd[b].n = current.n; |
|
| 173 | + | set blkEnd[b].n = current.n; |
|
| 174 | 174 | for ri in 0..current.n { |
|
| 175 | - | blkEnd[b].virtRegs[ri] = current.virtRegs[ri]; |
|
| 176 | - | blkEnd[b].physRegs[ri] = current.physRegs[ri]; |
|
| 175 | + | set blkEnd[b].virtRegs[ri] = current.virtRegs[ri]; |
|
| 176 | + | set blkEnd[b].physRegs[ri] = current.physRegs[ri]; |
|
| 177 | 177 | } |
|
| 178 | 178 | } |
|
| 179 | 179 | // Compute bitmask of used callee-saved registers. |
|
| 180 | 180 | let mut usedCalleeSaved: u32 = 0; |
|
| 181 | 181 | for i in 0..maxReg { |
|
| 182 | 182 | if let phys = assignments[i] { |
|
| 183 | 183 | for saved, j in config.calleeSaved { |
|
| 184 | 184 | if *phys == *saved { |
|
| 185 | - | usedCalleeSaved |= (1 << j); |
|
| 185 | + | set usedCalleeSaved |= (1 << j); |
|
| 186 | 186 | } |
|
| 187 | 187 | } |
|
| 188 | 188 | } |
|
| 189 | 189 | } |
|
| 190 | 190 |
| 213 | 213 | } |
|
| 214 | 214 | ||
| 215 | 215 | /// Add a mapping to the register map. |
|
| 216 | 216 | fn rmapSet(rmap: *mut RegMap, virtReg: u32, physReg: gen::Reg) { |
|
| 217 | 217 | assert rmap.n < MAX_ACTIVE, "rmapSet: register map overflow"; |
|
| 218 | - | rmap.virtRegs[rmap.n] = virtReg; |
|
| 219 | - | rmap.physRegs[rmap.n] = physReg; |
|
| 220 | - | rmap.n += 1; |
|
| 218 | + | set rmap.virtRegs[rmap.n] = virtReg; |
|
| 219 | + | set rmap.physRegs[rmap.n] = physReg; |
|
| 220 | + | set rmap.n += 1; |
|
| 221 | 221 | } |
|
| 222 | 222 | ||
| 223 | 223 | /// Remove a mapping from register map. |
|
| 224 | 224 | fn rmapRemove(rmap: *mut RegMap, virtReg: u32) { |
|
| 225 | 225 | for i in 0..rmap.n { |
|
| 226 | 226 | if rmap.virtRegs[i] == virtReg { |
|
| 227 | 227 | // Swap with last and decrement. |
|
| 228 | - | rmap.n -= 1; |
|
| 228 | + | set rmap.n -= 1; |
|
| 229 | 229 | if i < rmap.n { |
|
| 230 | - | rmap.virtRegs[i] = rmap.virtRegs[rmap.n]; |
|
| 231 | - | rmap.physRegs[i] = rmap.physRegs[rmap.n]; |
|
| 230 | + | set rmap.virtRegs[i] = rmap.virtRegs[rmap.n]; |
|
| 231 | + | set rmap.physRegs[i] = rmap.physRegs[rmap.n]; |
|
| 232 | 232 | } |
|
| 233 | 233 | return; |
|
| 234 | 234 | } |
|
| 235 | 235 | } |
|
| 236 | 236 | panic "rmapRemove: register not found"; |
| 290 | 290 | assert reg.n < ctx.assignments.len, "processInstrRegCb: register out of bounds"; |
|
| 291 | 291 | if spill::isSpilled(ctx.spillInfo, reg) { |
|
| 292 | 292 | return; // Spilled values don't get physical registers. |
|
| 293 | 293 | } |
|
| 294 | 294 | if ctx.assignments[reg.n] == nil { |
|
| 295 | - | ctx.assignments[reg.n] = rallocReg( |
|
| 295 | + | set ctx.assignments[reg.n] = rallocReg( |
|
| 296 | 296 | ctx.current, ctx.usedRegs, reg.n, ctx.allocatable, |
|
| 297 | 297 | ctx.calleeSaved, ctx.spillInfo |
|
| 298 | 298 | ); |
|
| 299 | 299 | } |
|
| 300 | 300 | } |
lib/std/lang/gen/regalloc/liveness.rad
+15 -15
| 74 | 74 | } |
|
| 75 | 75 | ||
| 76 | 76 | // Find max register number. |
|
| 77 | 77 | let mut maxReg: u32 = 0; |
|
| 78 | 78 | for p in func.params { |
|
| 79 | - | maxReg = maxRegNum(p.value.n, maxReg); |
|
| 79 | + | set maxReg = maxRegNum(p.value.n, maxReg); |
|
| 80 | 80 | } |
|
| 81 | 81 | for b in 0..blockCount { |
|
| 82 | 82 | let block = &func.blocks[b]; |
|
| 83 | 83 | for p in block.params { |
|
| 84 | - | maxReg = maxRegNum(p.value.n, maxReg); |
|
| 84 | + | set maxReg = maxRegNum(p.value.n, maxReg); |
|
| 85 | 85 | } |
|
| 86 | 86 | for i in 0..block.instrs.len { |
|
| 87 | 87 | il::forEachReg(block.instrs[i], maxRegCallback, &mut maxReg as *mut opaque); |
|
| 88 | 88 | if let dst = il::instrDst(block.instrs[i]) { |
|
| 89 | - | maxReg = maxRegNum(dst.n, maxReg); |
|
| 89 | + | set maxReg = maxRegNum(dst.n, maxReg); |
|
| 90 | 90 | } |
|
| 91 | 91 | } |
|
| 92 | 92 | } |
|
| 93 | 93 | assert maxReg <= MAX_SSA_REGS, "analyze: maximum SSA registers exceeded"; |
|
| 94 | 94 | // Allocate per-block bitsets. |
| 96 | 96 | let liveOut = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 97 | 97 | let defs = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 98 | 98 | let uses = try alloc::allocSlice(arena, @sizeOf(bitset::Bitset), @alignOf(bitset::Bitset), blockCount) as *mut [bitset::Bitset]; |
|
| 99 | 99 | ||
| 100 | 100 | for b in 0..blockCount { |
|
| 101 | - | liveIn[b] = try bitset::allocate(arena, maxReg); |
|
| 102 | - | liveOut[b] = try bitset::allocate(arena, maxReg); |
|
| 103 | - | defs[b] = try bitset::allocate(arena, maxReg); |
|
| 104 | - | uses[b] = try bitset::allocate(arena, maxReg); |
|
| 101 | + | set liveIn[b] = try bitset::allocate(arena, maxReg); |
|
| 102 | + | set liveOut[b] = try bitset::allocate(arena, maxReg); |
|
| 103 | + | set defs[b] = try bitset::allocate(arena, maxReg); |
|
| 104 | + | set uses[b] = try bitset::allocate(arena, maxReg); |
|
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | // Compute local defs and uses for each block. |
|
| 108 | 108 | for b in 0..blockCount { |
|
| 109 | 109 | computeLocalDefsUses(&func.blocks[b], &mut defs[b], &mut uses[b]); |
| 111 | 111 | // Iterative dataflow analysis. |
|
| 112 | 112 | let mut changed = true; |
|
| 113 | 113 | let mut scratch = try bitset::allocate(arena, maxReg); |
|
| 114 | 114 | ||
| 115 | 115 | while changed { |
|
| 116 | - | changed = false; |
|
| 116 | + | set changed = false; |
|
| 117 | 117 | ||
| 118 | 118 | // Process blocks in reverse order (approximates post-order). |
|
| 119 | 119 | let mut b = blockCount; |
|
| 120 | 120 | while b > 0 { |
|
| 121 | - | b -= 1; |
|
| 121 | + | set b -= 1; |
|
| 122 | 122 | let block = &func.blocks[b]; |
|
| 123 | 123 | ||
| 124 | 124 | // Compute new `liveOut` as union of successor `liveIn` sets. |
|
| 125 | 125 | bitset::clearAll(&mut scratch); |
|
| 126 | 126 | addSuccessorLiveIn(func, block, liveIn, &mut scratch); |
|
| 127 | 127 | ||
| 128 | 128 | if not bitset::eq(&liveOut[b], &scratch) { |
|
| 129 | 129 | bitset::copy(&mut liveOut[b], &scratch); |
|
| 130 | - | changed = true; |
|
| 130 | + | set changed = true; |
|
| 131 | 131 | } |
|
| 132 | 132 | if computeAndUpdateLiveIn(&mut liveIn[b], &liveOut[b], &defs[b], &uses[b]) { |
|
| 133 | - | changed = true; |
|
| 133 | + | set changed = true; |
|
| 134 | 134 | } |
|
| 135 | 135 | } |
|
| 136 | 136 | } |
|
| 137 | 137 | return LiveInfo { liveIn, liveOut, defs, uses, blockCount, maxReg }; |
|
| 138 | 138 | } |
| 148 | 148 | let numWords = dst.bits.len; |
|
| 149 | 149 | let mut changed = false; |
|
| 150 | 150 | for i in 0..numWords { |
|
| 151 | 151 | let newWord = uses.bits[i] | (liveOut.bits[i] & ~defs.bits[i]); |
|
| 152 | 152 | if dst.bits[i] <> newWord { |
|
| 153 | - | dst.bits[i] = newWord; |
|
| 154 | - | changed = true; |
|
| 153 | + | set dst.bits[i] = newWord; |
|
| 154 | + | set changed = true; |
|
| 155 | 155 | } |
|
| 156 | 156 | } |
|
| 157 | 157 | return changed; |
|
| 158 | 158 | } |
|
| 159 | 159 |
| 182 | 182 | } |
|
| 183 | 183 | ||
| 184 | 184 | /// Callback for [`il::forEachReg`]: updates max register number. |
|
| 185 | 185 | fn maxRegCallback(reg: il::Reg, ctx: *mut opaque) { |
|
| 186 | 186 | let max = ctx as *mut u32; |
|
| 187 | - | *max = maxRegNum(reg.n, *max); |
|
| 187 | + | set *max = maxRegNum(reg.n, *max); |
|
| 188 | 188 | } |
|
| 189 | 189 | ||
| 190 | 190 | /// Return the larger of n+1 and current. |
|
| 191 | 191 | fn maxRegNum(n: u32, current: u32) -> u32 { |
|
| 192 | 192 | if n + 1 > current { |
| 252 | 252 | ||
| 253 | 253 | /// Callback for [`il::forEachReg`]: sets found if register matches target. |
|
| 254 | 254 | fn findRegCallback(reg: il::Reg, ctx: *mut opaque) { |
|
| 255 | 255 | let c = ctx as *mut FindCtx; |
|
| 256 | 256 | if reg.n == c.target { |
|
| 257 | - | c.found = true; |
|
| 257 | + | set c.found = true; |
|
| 258 | 258 | } |
|
| 259 | 259 | } |
lib/std/lang/gen/regalloc/spill.rad
+15 -15
| 98 | 98 | }; |
|
| 99 | 99 | } |
|
| 100 | 100 | // Allocate spill slots array. |
|
| 101 | 101 | let slots = try alloc::allocSlice(arena, @sizeOf(i32), @alignOf(i32), maxReg) as *mut [i32]; |
|
| 102 | 102 | for i in 0..maxReg { |
|
| 103 | - | slots[i] = -1; |
|
| 103 | + | set slots[i] = -1; |
|
| 104 | 104 | } |
|
| 105 | 105 | // Allocate cost array. |
|
| 106 | 106 | let costs = try alloc::allocSlice(arena, @sizeOf(SpillCost), @alignOf(SpillCost), maxReg) as *mut [SpillCost]; |
|
| 107 | 107 | for i in 0..maxReg { |
|
| 108 | - | costs[i] = SpillCost { defs: 0, uses: 0 }; |
|
| 108 | + | set costs[i] = SpillCost { defs: 0, uses: 0 }; |
|
| 109 | 109 | } |
|
| 110 | 110 | // Phase 1: Calculate spill costs. |
|
| 111 | 111 | fillCosts(func, costs); |
|
| 112 | 112 | ||
| 113 | 113 | // Phase 2: Find values that exceed register pressure. |
| 122 | 122 | bitset::copy(&mut scratch, &live.liveOut[b]); |
|
| 123 | 123 | ||
| 124 | 124 | // Walk instructions backwards. |
|
| 125 | 125 | let mut i = block.instrs.len; |
|
| 126 | 126 | while i > 0 { |
|
| 127 | - | i -= 1; |
|
| 127 | + | set i -= 1; |
|
| 128 | 128 | let instr = block.instrs[i]; |
|
| 129 | 129 | ||
| 130 | 130 | // Limit register pressure before processing this instruction. |
|
| 131 | 131 | limitPressure(&mut scratch, &mut spilled, costs, numRegs); |
|
| 132 | 132 |
| 166 | 166 | // Phase 4: Assign stack slots to spilled values. |
|
| 167 | 167 | let mut frameSize: i32 = 0; |
|
| 168 | 168 | let mut it = bitset::iter(&spilled); |
|
| 169 | 169 | ||
| 170 | 170 | while let n = bitset::iterNext(&mut it) { |
|
| 171 | - | slots[n] = frameSize; |
|
| 172 | - | frameSize += slotSize as i32; |
|
| 171 | + | set slots[n] = frameSize; |
|
| 172 | + | set frameSize += slotSize as i32; |
|
| 173 | 173 | } |
|
| 174 | 174 | return SpillInfo { slots, frameSize, calleeClass, maxReg }; |
|
| 175 | 175 | } |
|
| 176 | 176 | ||
| 177 | 177 | /// Calculate spill costs for all registers, weighted by loop depth. |
| 184 | 184 | let weight: u32 = 1 << depth; |
|
| 185 | 185 | ||
| 186 | 186 | // Count block parameter definitions. |
|
| 187 | 187 | for p in block.params { |
|
| 188 | 188 | if p.value.n < costs.len { |
|
| 189 | - | costs[p.value.n].defs = costs[p.value.n].defs + weight; |
|
| 189 | + | set costs[p.value.n].defs = costs[p.value.n].defs + weight; |
|
| 190 | 190 | } |
|
| 191 | 191 | } |
|
| 192 | 192 | // Count instruction defs and uses. |
|
| 193 | 193 | for i in 0..block.instrs.len { |
|
| 194 | 194 | let instr = block.instrs[i]; |
|
| 195 | 195 | ||
| 196 | 196 | // Count definition. |
|
| 197 | 197 | if let dst = il::instrDst(instr) { |
|
| 198 | 198 | if dst.n < costs.len { |
|
| 199 | - | costs[dst.n].defs = costs[dst.n].defs + weight; |
|
| 199 | + | set costs[dst.n].defs = costs[dst.n].defs + weight; |
|
| 200 | 200 | } |
|
| 201 | 201 | } |
|
| 202 | 202 | // Count uses. |
|
| 203 | 203 | let mut ctx = CountCtx { costs, weight }; |
|
| 204 | 204 | il::forEachReg(instr, countRegUseCallback, &mut ctx as *mut opaque); |
| 217 | 217 | // Insertion sort ascending by cost. |
|
| 218 | 218 | for i in 1..c.n { |
|
| 219 | 219 | let key = c.entries[i]; |
|
| 220 | 220 | let mut j: u32 = i; |
|
| 221 | 221 | while j > 0 and c.entries[j - 1].cost > key.cost { |
|
| 222 | - | c.entries[j] = c.entries[j - 1]; |
|
| 223 | - | j -= 1; |
|
| 222 | + | set c.entries[j] = c.entries[j - 1]; |
|
| 223 | + | set j -= 1; |
|
| 224 | 224 | } |
|
| 225 | - | c.entries[j] = key; |
|
| 225 | + | set c.entries[j] = key; |
|
| 226 | 226 | } |
|
| 227 | 227 | let toSpill = c.n if excess > c.n else excess; |
|
| 228 | 228 | for i in 0..toSpill { |
|
| 229 | 229 | bitset::put(spilled, c.entries[i].reg); |
|
| 230 | 230 | bitset::clear(source, c.entries[i].reg); |
| 236 | 236 | let mut c = Candidates { entries: undefined, n: 0 }; |
|
| 237 | 237 | let mut it = bitset::iter(bs); |
|
| 238 | 238 | while let reg = bitset::iterNext(&mut it) { |
|
| 239 | 239 | assert c.n < MAX_CANDIDATES, "collectCandidates: too many live values"; |
|
| 240 | 240 | if reg < costs.len { |
|
| 241 | - | c.entries[c.n] = CostEntry { reg, cost: costs[reg].defs + costs[reg].uses }; |
|
| 242 | - | c.n += 1; |
|
| 241 | + | set c.entries[c.n] = CostEntry { reg, cost: costs[reg].defs + costs[reg].uses }; |
|
| 242 | + | set c.n += 1; |
|
| 243 | 243 | } |
|
| 244 | 244 | } |
|
| 245 | 245 | return c; |
|
| 246 | 246 | } |
|
| 247 | 247 |
| 285 | 285 | let mut candidates: [CostEntry; 256] = undefined; |
|
| 286 | 286 | let mut numCandidates: u32 = 0; |
|
| 287 | 287 | let mut it = bitset::iter(live); |
|
| 288 | 288 | while let n = bitset::iterNext(&mut it) { |
|
| 289 | 289 | if not isCallDst(callDst, n) and n < costs.len { |
|
| 290 | - | candidates[numCandidates] = CostEntry { |
|
| 290 | + | set candidates[numCandidates] = CostEntry { |
|
| 291 | 291 | reg: n, |
|
| 292 | 292 | cost: costs[n].defs + costs[n].uses, |
|
| 293 | 293 | }; |
|
| 294 | - | numCandidates += 1; |
|
| 294 | + | set numCandidates += 1; |
|
| 295 | 295 | } |
|
| 296 | 296 | } |
|
| 297 | 297 | // Spill cheapest candidates if crossing count exceeds callee-saved capacity. |
|
| 298 | 298 | if numCandidates > numCalleeSaved { |
|
| 299 | 299 | let mut c = Candidates { entries: candidates, n: numCandidates }; |
| 310 | 310 | ||
| 311 | 311 | /// Callback for [`il::forEachReg`]: increments use count for register. |
|
| 312 | 312 | fn countRegUseCallback(reg: il::Reg, ctxPtr: *mut opaque) { |
|
| 313 | 313 | let ctx = ctxPtr as *mut CountCtx; |
|
| 314 | 314 | assert reg.n < ctx.costs.len, "countRegUseCallback: register out of bounds"; |
|
| 315 | - | ctx.costs[reg.n].uses = ctx.costs[reg.n].uses + ctx.weight; |
|
| 315 | + | set ctx.costs[reg.n].uses = ctx.costs[reg.n].uses + ctx.weight; |
|
| 316 | 316 | } |
|
| 317 | 317 | ||
| 318 | 318 | /// Callback for [`il::forEachReg`]: adds register to live set. |
|
| 319 | 319 | fn addRegToSetCallback(reg: il::Reg, ctx: *mut opaque) { |
|
| 320 | 320 | bitset::put(ctx as *mut bitset::Bitset, reg.n); |
lib/std/lang/il.rad
+3 -3
| 83 | 83 | ||
| 84 | 84 | /// Format a qualified symbol name: `pkg::mod::path::name`. |
|
| 85 | 85 | export fn formatQualifiedName(arena: *mut alloc::Arena, path: *[*[u8]], name: *[u8]) -> *[u8] { |
|
| 86 | 86 | let mut totalLen: u32 = name.len; |
|
| 87 | 87 | for segment in path { |
|
| 88 | - | totalLen += segment.len + PATH_SEPARATOR.len; |
|
| 88 | + | set totalLen += segment.len + PATH_SEPARATOR.len; |
|
| 89 | 89 | } |
|
| 90 | 90 | let buf = try! alloc::allocSlice(arena, 1, 1, totalLen) as *mut [u8]; |
|
| 91 | 91 | let mut pos: u32 = 0; |
|
| 92 | 92 | ||
| 93 | 93 | for segment in path { |
|
| 94 | - | pos += try! mem::copy(&mut buf[pos..], segment); |
|
| 95 | - | pos += try! mem::copy(&mut buf[pos..], PATH_SEPARATOR); |
|
| 94 | + | set pos += try! mem::copy(&mut buf[pos..], segment); |
|
| 95 | + | set pos += try! mem::copy(&mut buf[pos..], PATH_SEPARATOR); |
|
| 96 | 96 | } |
|
| 97 | 97 | try! mem::copy(&mut buf[pos..], name); |
|
| 98 | 98 | ||
| 99 | 99 | return &buf[..totalLen]; |
|
| 100 | 100 | } |
lib/std/lang/il/printer.rad
+1 -1
| 37 | 37 | /// Concatenate prefix and string in the arena. |
|
| 38 | 38 | fn prefixStr(a: *mut alloc::Arena, prefix: u8, str: *[u8]) -> *[u8] { |
|
| 39 | 39 | let len = str.len + 1; |
|
| 40 | 40 | let ptr = try! alloc::allocSlice(a, 1, 1, len); |
|
| 41 | 41 | let slice = ptr as *mut [u8]; |
|
| 42 | - | slice[0] = prefix; |
|
| 42 | + | set slice[0] = prefix; |
|
| 43 | 43 | try! mem::copy(&mut slice[1..], str); |
|
| 44 | 44 | ||
| 45 | 45 | return slice; |
|
| 46 | 46 | } |
|
| 47 | 47 |
lib/std/lang/lower.rad
+227 -236
| 305 | 305 | fn maxErrSize(throwList: *[*resolver::Type]) -> u32 { |
|
| 306 | 306 | let mut maxSize: u32 = 0; |
|
| 307 | 307 | for ty in throwList { |
|
| 308 | 308 | let size = resolver::getTypeLayout(*ty).size; |
|
| 309 | 309 | if size > maxSize { |
|
| 310 | - | maxSize = size; |
|
| 310 | + | set maxSize = size; |
|
| 311 | 311 | } |
|
| 312 | 312 | } |
|
| 313 | 313 | return maxSize; |
|
| 314 | 314 | } |
|
| 315 | 315 |
| 321 | 321 | return entry.tag; |
|
| 322 | 322 | } |
|
| 323 | 323 | } |
|
| 324 | 324 | let tag = self.errTagCounter; |
|
| 325 | 325 | ||
| 326 | - | self.errTagCounter += 1; |
|
| 326 | + | set self.errTagCounter += 1; |
|
| 327 | 327 | self.errTags.append(ErrTagEntry { ty: errType, tag }, self.allocator); |
|
| 328 | 328 | ||
| 329 | 329 | return tag; |
|
| 330 | 330 | } |
|
| 331 | 331 |
| 351 | 351 | /// Append a data value to the builder. |
|
| 352 | 352 | fn dataBuilderPush(b: *mut DataValueBuilder, value: il::DataValue) { |
|
| 353 | 353 | b.values.append(value, b.allocator); |
|
| 354 | 354 | ||
| 355 | 355 | if value.item <> il::DataItem::Undef { |
|
| 356 | - | b.allUndef = false; |
|
| 356 | + | set b.allUndef = false; |
|
| 357 | 357 | } |
|
| 358 | 358 | } |
|
| 359 | 359 | ||
| 360 | 360 | /// Return the accumulated values. |
|
| 361 | 361 | fn dataBuilderFinish(b: *DataValueBuilder) -> ConstDataResult { |
| 737 | 737 | low: *mut Lowerer, |
|
| 738 | 738 | moduleId: u16, |
|
| 739 | 739 | root: *ast::Node, |
|
| 740 | 740 | isRoot: bool |
|
| 741 | 741 | ) -> ?u32 throws (LowerError) { |
|
| 742 | - | low.currentMod = moduleId; |
|
| 742 | + | set low.currentMod = moduleId; |
|
| 743 | 743 | return try lowerDecls(low, root, isRoot); |
|
| 744 | 744 | } |
|
| 745 | 745 | ||
| 746 | 746 | /// Lower all top-level declarations in a block. |
|
| 747 | 747 | fn lowerDecls(low: *mut Lowerer, root: *ast::Node, isRoot: bool) -> ?u32 throws (LowerError) { |
| 754 | 754 | for node in stmtsList { |
|
| 755 | 755 | match node.value { |
|
| 756 | 756 | case ast::NodeValue::FnDecl(decl) => { |
|
| 757 | 757 | if let f = try lowerFnDecl(low, node, decl) { |
|
| 758 | 758 | if isRoot and checkAttr(decl.attrs, ast::Attribute::Default) { |
|
| 759 | - | defaultFnIdx = low.fns.len; |
|
| 759 | + | set defaultFnIdx = low.fns.len; |
|
| 760 | 760 | } |
|
| 761 | 761 | low.fns.append(f, low.allocator); |
|
| 762 | 762 | } |
|
| 763 | 763 | } |
|
| 764 | 764 | case ast::NodeValue::ConstDecl(decl) => { |
| 800 | 800 | let graph = self.moduleGraph else { |
|
| 801 | 801 | return &[]; |
|
| 802 | 802 | }; |
|
| 803 | 803 | let mut id = modId; |
|
| 804 | 804 | if id == nil { |
|
| 805 | - | id = self.currentMod; |
|
| 805 | + | set id = self.currentMod; |
|
| 806 | 806 | } |
|
| 807 | 807 | let actualId = id else { |
|
| 808 | 808 | return &[]; |
|
| 809 | 809 | }; |
|
| 810 | 810 | let entry = module::get(graph, actualId) else { |
| 845 | 845 | } |
|
| 846 | 846 | ||
| 847 | 847 | /// Set the package context for lowering. |
|
| 848 | 848 | /// Called before lowering each package. |
|
| 849 | 849 | export fn setPackage(self: *mut Lowerer, graph: *module::ModuleGraph, pkgName: *[u8]) { |
|
| 850 | - | self.moduleGraph = graph; |
|
| 851 | - | self.pkgName = pkgName; |
|
| 852 | - | self.currentMod = nil; |
|
| 850 | + | set self.moduleGraph = graph; |
|
| 851 | + | set self.pkgName = pkgName; |
|
| 852 | + | set self.currentMod = nil; |
|
| 853 | 853 | } |
|
| 854 | 854 | ||
| 855 | 855 | /// Create a new function lowerer for a given function type and name. |
|
| 856 | 856 | fn fnLowerer( |
|
| 857 | 857 | self: *mut Lowerer, |
| 882 | 882 | }; |
|
| 883 | 883 | if self.options.debug { |
|
| 884 | 884 | let modId = self.currentMod else { |
|
| 885 | 885 | panic "fnLowerer: debug enabled but no current module"; |
|
| 886 | 886 | }; |
|
| 887 | - | fnLow.srcLoc = il::SrcLoc { |
|
| 887 | + | set fnLow.srcLoc = il::SrcLoc { |
|
| 888 | 888 | moduleId: modId, |
|
| 889 | 889 | offset: node.span.offset, |
|
| 890 | 890 | }; |
|
| 891 | 891 | } |
|
| 892 | 892 | return fnLow; |
| 923 | 923 | ||
| 924 | 924 | // If the function returns an aggregate or is throwing, prepend a hidden |
|
| 925 | 925 | // return parameter. The caller allocates the buffer and passes it |
|
| 926 | 926 | // as the first argument; the callee writes the return value into it. |
|
| 927 | 927 | if requiresReturnParam(fnType) and not isExtern { |
|
| 928 | - | fnLow.returnReg = nextReg(&mut fnLow); |
|
| 928 | + | set fnLow.returnReg = nextReg(&mut fnLow); |
|
| 929 | 929 | } |
|
| 930 | 930 | let lowParams = try lowerParams(&mut fnLow, *fnType, decl.sig.params, nil); |
|
| 931 | 931 | let func = try! alloc::alloc(self.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn; |
|
| 932 | 932 | ||
| 933 | - | *func = il::Fn { |
|
| 933 | + | set *func = il::Fn { |
|
| 934 | 934 | name: qualName, |
|
| 935 | 935 | params: lowParams, |
|
| 936 | 936 | returnType: undefined, |
|
| 937 | 937 | isExtern, |
|
| 938 | 938 | isLeaf: true, |
| 941 | 941 | // Throwing functions return a result aggregate (word-sized pointer). |
|
| 942 | 942 | // TODO: The resolver should set an appropriate type that takes into account |
|
| 943 | 943 | // the throws list. It shouldn't set the return type to the "success" |
|
| 944 | 944 | // value only. |
|
| 945 | 945 | if fnType.throwList.len > 0 { |
|
| 946 | - | func.returnType = il::Type::W64; |
|
| 946 | + | set func.returnType = il::Type::W64; |
|
| 947 | 947 | } else { |
|
| 948 | - | func.returnType = ilType(self, *fnType.returnType); |
|
| 948 | + | set func.returnType = ilType(self, *fnType.returnType); |
|
| 949 | 949 | } |
|
| 950 | 950 | let body = decl.body else { |
|
| 951 | 951 | // Extern functions have no body. |
|
| 952 | 952 | assert isExtern; |
|
| 953 | 953 | return func; |
|
| 954 | 954 | }; |
|
| 955 | - | func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 956 | - | func.isLeaf = fnLow.isLeaf; |
|
| 955 | + | set func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 956 | + | set func.isLeaf = fnLow.isLeaf; |
|
| 957 | 957 | ||
| 958 | 958 | return func; |
|
| 959 | 959 | } |
|
| 960 | 960 | ||
| 961 | 961 | /// Build a qualified name of the form "Type::method". |
| 963 | 963 | let sepLen: u32 = 2; // "::" |
|
| 964 | 964 | let totalLen = typeName.len + sepLen + methodName.len; |
|
| 965 | 965 | let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8]; |
|
| 966 | 966 | let mut pos: u32 = 0; |
|
| 967 | 967 | ||
| 968 | - | pos += try! mem::copy(&mut buf[pos..], typeName); |
|
| 969 | - | pos += try! mem::copy(&mut buf[pos..], "::"); |
|
| 970 | - | pos += try! mem::copy(&mut buf[pos..], methodName); |
|
| 968 | + | set pos += try! mem::copy(&mut buf[pos..], typeName); |
|
| 969 | + | set pos += try! mem::copy(&mut buf[pos..], "::"); |
|
| 970 | + | set pos += try! mem::copy(&mut buf[pos..], methodName); |
|
| 971 | 971 | assert pos == totalLen; |
|
| 972 | 972 | ||
| 973 | 973 | return qualifyName(self, modId, &buf[..totalLen]); |
|
| 974 | 974 | } |
|
| 975 | 975 |
| 979 | 979 | let sepLen: u32 = 2; // "::" |
|
| 980 | 980 | let totalLen = prefix.len + typeName.len + sepLen + traitName.len; |
|
| 981 | 981 | let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8]; |
|
| 982 | 982 | let mut pos: u32 = 0; |
|
| 983 | 983 | ||
| 984 | - | pos += try! mem::copy(&mut buf[pos..], prefix); |
|
| 985 | - | pos += try! mem::copy(&mut buf[pos..], typeName); |
|
| 986 | - | pos += try! mem::copy(&mut buf[pos..], "::"); |
|
| 987 | - | pos += try! mem::copy(&mut buf[pos..], traitName); |
|
| 984 | + | set pos += try! mem::copy(&mut buf[pos..], prefix); |
|
| 985 | + | set pos += try! mem::copy(&mut buf[pos..], typeName); |
|
| 986 | + | set pos += try! mem::copy(&mut buf[pos..], "::"); |
|
| 987 | + | set pos += try! mem::copy(&mut buf[pos..], traitName); |
|
| 988 | 988 | assert pos == totalLen; |
|
| 989 | 989 | ||
| 990 | 990 | return qualifyName(self, modId, &buf[..totalLen]); |
|
| 991 | 991 | } |
|
| 992 | 992 |
| 1035 | 1035 | self.fns.append(func, self.allocator); |
|
| 1036 | 1036 | ||
| 1037 | 1037 | let method = resolver::findTraitMethod(traitInfo, mName) |
|
| 1038 | 1038 | else panic "lowerInstanceDecl: method not found in trait"; |
|
| 1039 | 1039 | ||
| 1040 | - | methodNames[method.index] = qualName; |
|
| 1041 | - | methodNameSet[method.index] = true; |
|
| 1040 | + | set methodNames[method.index] = qualName; |
|
| 1041 | + | set methodNameSet[method.index] = true; |
|
| 1042 | 1042 | } |
|
| 1043 | 1043 | ||
| 1044 | 1044 | // Fill inherited method slots from supertraits. |
|
| 1045 | 1045 | // These methods were already lowered as part of the supertrait instance |
|
| 1046 | 1046 | // declarations and use the same `Type::method` qualified name. |
|
| 1047 | 1047 | for method, i in traitInfo.methods { |
|
| 1048 | 1048 | if not methodNameSet[i] { |
|
| 1049 | - | methodNames[i] = instanceMethodName(self, nil, typeName, method.name); |
|
| 1049 | + | set methodNames[i] = instanceMethodName(self, nil, typeName, method.name); |
|
| 1050 | 1050 | } |
|
| 1051 | 1051 | } |
|
| 1052 | 1052 | ||
| 1053 | 1053 | // Create v-table in data section, used for dynamic dispatch. |
|
| 1054 | 1054 | let vName = vtableName(self, nil, typeName, tName); |
|
| 1055 | 1055 | let values = try! alloc::allocSlice( |
|
| 1056 | 1056 | self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), traitInfo.methods.len as u32 |
|
| 1057 | 1057 | ) as *mut [il::DataValue]; |
|
| 1058 | 1058 | ||
| 1059 | 1059 | for i in 0..traitInfo.methods.len { |
|
| 1060 | - | values[i] = il::DataValue { |
|
| 1060 | + | set values[i] = il::DataValue { |
|
| 1061 | 1061 | item: il::DataItem::Fn(methodNames[i]), |
|
| 1062 | 1062 | count: 1, |
|
| 1063 | 1063 | }; |
|
| 1064 | 1064 | } |
|
| 1065 | 1065 | self.data.append(il::Data { |
| 1089 | 1089 | let sym = data.sym else throw LowerError::MissingSymbol(node); |
|
| 1090 | 1090 | registerFnSym(self, sym, qualName); |
|
| 1091 | 1091 | ||
| 1092 | 1092 | let mut fnLow = fnLowerer(self, node, fnType, qualName); |
|
| 1093 | 1093 | if requiresReturnParam(fnType) { |
|
| 1094 | - | fnLow.returnReg = nextReg(&mut fnLow); |
|
| 1094 | + | set fnLow.returnReg = nextReg(&mut fnLow); |
|
| 1095 | 1095 | } |
|
| 1096 | 1096 | let lowParams = try lowerParams(&mut fnLow, *fnType, sig.params, receiverName); |
|
| 1097 | 1097 | let func = try! alloc::alloc(self.arena, @sizeOf(il::Fn), @alignOf(il::Fn)) as *mut il::Fn; |
|
| 1098 | 1098 | ||
| 1099 | - | *func = il::Fn { |
|
| 1099 | + | set *func = il::Fn { |
|
| 1100 | 1100 | name: qualName, |
|
| 1101 | 1101 | params: lowParams, |
|
| 1102 | 1102 | returnType: ilType(self, *fnType.returnType), |
|
| 1103 | 1103 | isExtern: false, |
|
| 1104 | 1104 | isLeaf: true, |
|
| 1105 | 1105 | blocks: &[], |
|
| 1106 | 1106 | }; |
|
| 1107 | 1107 | if fnType.throwList.len > 0 { |
|
| 1108 | - | func.returnType = il::Type::W64; |
|
| 1108 | + | set func.returnType = il::Type::W64; |
|
| 1109 | 1109 | } |
|
| 1110 | - | func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 1111 | - | func.isLeaf = fnLow.isLeaf; |
|
| 1110 | + | set func.blocks = try lowerFnBody(&mut fnLow, body); |
|
| 1111 | + | set func.isLeaf = fnLow.isLeaf; |
|
| 1112 | 1112 | ||
| 1113 | 1113 | return func; |
|
| 1114 | 1114 | } |
|
| 1115 | 1115 | ||
| 1116 | 1116 | /// Lower a standalone method declaration. |
| 1165 | 1165 | } |
|
| 1166 | 1166 | ||
| 1167 | 1167 | /// Generate a unique label by appending the global counter to the base. |
|
| 1168 | 1168 | fn nextLabel(self: *mut FnLowerer, base: *[u8]) -> *[u8] throws (LowerError) { |
|
| 1169 | 1169 | let idx = self.labelCounter; |
|
| 1170 | - | self.labelCounter += 1; |
|
| 1170 | + | set self.labelCounter += 1; |
|
| 1171 | 1171 | ||
| 1172 | 1172 | return try labelWithSuffix(self, base, idx); |
|
| 1173 | 1173 | } |
|
| 1174 | 1174 | ||
| 1175 | 1175 | /////////////////////////////// |
| 1210 | 1210 | return il::DataItem::Str(s); |
|
| 1211 | 1211 | } |
|
| 1212 | 1212 | // Bool and char are byte-sized; integer uses the declared type. |
|
| 1213 | 1213 | let mut irTyp = il::Type::W8; |
|
| 1214 | 1214 | if let case resolver::ConstValue::Int(_) = val { |
|
| 1215 | - | irTyp = ilType(self, typ); |
|
| 1215 | + | set irTyp = ilType(self, typ); |
|
| 1216 | 1216 | } |
|
| 1217 | 1217 | return il::DataItem::Val { typ: irTyp, val: constToScalar(val) }; |
|
| 1218 | 1218 | } |
|
| 1219 | 1219 | ||
| 1220 | 1220 | /// Lower a constant or static declaration to the data section. |
| 1291 | 1291 | let backing = dataBuilderFinish(&nested); |
|
| 1292 | 1292 | let readOnly = not mutable; |
|
| 1293 | 1293 | let mut dataName: *[u8] = undefined; |
|
| 1294 | 1294 | if readOnly { |
|
| 1295 | 1295 | if let found = findConstData(self, backing.values, layout.alignment) { |
|
| 1296 | - | dataName = found; |
|
| 1296 | + | set dataName = found; |
|
| 1297 | 1297 | } else { |
|
| 1298 | - | dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1298 | + | set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1299 | 1299 | } |
|
| 1300 | 1300 | } else { |
|
| 1301 | - | dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1301 | + | set dataName = try pushDeclData(self, layout.size, layout.alignment, readOnly, backing.values, dataPrefix); |
|
| 1302 | 1302 | } |
|
| 1303 | 1303 | dataSliceHeader(b, dataName, arrInfo.length); |
|
| 1304 | 1304 | } |
|
| 1305 | 1305 | ||
| 1306 | 1306 | /// Lower a constant expression into a builder, padding to slotSize. |
| 1485 | 1485 | ) throws (LowerError) { |
|
| 1486 | 1486 | let layout = recInfo.layout; |
|
| 1487 | 1487 | for argNode, i in args { |
|
| 1488 | 1488 | let mut valueNode = argNode; |
|
| 1489 | 1489 | if let case ast::NodeValue::RecordLitField(fieldLit) = argNode.value { |
|
| 1490 | - | valueNode = fieldLit.value; |
|
| 1490 | + | set valueNode = fieldLit.value; |
|
| 1491 | 1491 | } |
|
| 1492 | 1492 | let fieldInfo = recInfo.fields[i]; |
|
| 1493 | 1493 | let fieldOffset = fieldInfo.offset as u32; |
|
| 1494 | 1494 | ||
| 1495 | 1495 | // Slot extends to the next field's offset, |
| 1582 | 1582 | let suffixStart = prefix.len + 1; |
|
| 1583 | 1583 | let totalLen = suffixStart + suffix.len; |
|
| 1584 | 1584 | let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8]; |
|
| 1585 | 1585 | ||
| 1586 | 1586 | try! mem::copy(&mut buf[..prefix.len], prefix); |
|
| 1587 | - | buf[prefix.len] = '$'; |
|
| 1587 | + | set buf[prefix.len] = '$'; |
|
| 1588 | 1588 | try! mem::copy(&mut buf[suffixStart..], suffix); |
|
| 1589 | 1589 | ||
| 1590 | 1590 | return &buf[..totalLen]; |
|
| 1591 | 1591 | } |
|
| 1592 | 1592 |
| 1616 | 1616 | } |
|
| 1617 | 1617 | let values = try! alloc::allocSlice( |
|
| 1618 | 1618 | self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), 1 |
|
| 1619 | 1619 | ) as *mut [il::DataValue]; |
|
| 1620 | 1620 | ||
| 1621 | - | values[0] = il::DataValue { |
|
| 1621 | + | set values[0] = il::DataValue { |
|
| 1622 | 1622 | item: il::DataItem::Str(s), |
|
| 1623 | 1623 | count: 1 |
|
| 1624 | 1624 | }; |
|
| 1625 | 1625 | return try pushDeclData(self, s.len, 1, true, &values[..1], dataPrefix); |
|
| 1626 | 1626 | } |
| 1716 | 1716 | let elemLayout = resolver::getTypeLayout(*elemTy); |
|
| 1717 | 1717 | let size = elemLayout.size * length; |
|
| 1718 | 1718 | let mut dataName: *[u8] = undefined; |
|
| 1719 | 1719 | if readOnly { |
|
| 1720 | 1720 | if let found = findConstData(self.low, values, alignment) { |
|
| 1721 | - | dataName = found; |
|
| 1721 | + | set dataName = found; |
|
| 1722 | 1722 | } else { |
|
| 1723 | - | dataName = try nextDataName(self); |
|
| 1723 | + | set dataName = try nextDataName(self); |
|
| 1724 | 1724 | self.low.data.append(il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values }, self.low.allocator); |
|
| 1725 | 1725 | } |
|
| 1726 | 1726 | } else { |
|
| 1727 | - | dataName = try nextDataName(self); |
|
| 1727 | + | set dataName = try nextDataName(self); |
|
| 1728 | 1728 | self.low.data.append(il::Data { name: dataName, size, alignment, readOnly, isUndefined: false, values }, self.low.allocator); |
|
| 1729 | 1729 | } |
|
| 1730 | 1730 | ||
| 1731 | 1731 | // Get data address. |
|
| 1732 | 1732 | let ptrReg = nextReg(self); |
| 1738 | 1738 | } |
|
| 1739 | 1739 | ||
| 1740 | 1740 | /// Generate a unique data name for inline literals, eg. `fnName/N` |
|
| 1741 | 1741 | fn nextDataName(self: *mut FnLowerer) -> *[u8] throws (LowerError) { |
|
| 1742 | 1742 | let counter = self.dataCounter; |
|
| 1743 | - | self.dataCounter += 1; |
|
| 1743 | + | set self.dataCounter += 1; |
|
| 1744 | 1744 | return try labelWithSuffix(self, self.fnName, counter); |
|
| 1745 | 1745 | } |
|
| 1746 | 1746 | ||
| 1747 | 1747 | /// Get the next available SSA register. |
|
| 1748 | 1748 | fn nextReg(self: *mut FnLowerer) -> il::Reg { |
|
| 1749 | 1749 | let reg = il::Reg { n: self.regCounter }; |
|
| 1750 | - | self.regCounter += 1; |
|
| 1750 | + | set self.regCounter += 1; |
|
| 1751 | 1751 | return reg; |
|
| 1752 | 1752 | } |
|
| 1753 | 1753 | ||
| 1754 | 1754 | /// Look up the resolved type of an AST node, or throw `MissingType`. |
|
| 1755 | 1755 | fn typeOf(self: *mut FnLowerer, node: *ast::Node) -> resolver::Type throws (LowerError) { |
| 1769 | 1769 | /// Used when detecting a trivial phi that can be eliminated. |
|
| 1770 | 1770 | fn removeLastBlockParam(self: *mut FnLowerer, block: BlockId) { |
|
| 1771 | 1771 | let blk = getBlockMut(self, block); |
|
| 1772 | 1772 | if blk.params.len > 0 { |
|
| 1773 | 1773 | // TODO: Use `pop`? |
|
| 1774 | - | blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap); |
|
| 1774 | + | set blk.params = @sliceOf(blk.params.ptr, blk.params.len - 1, blk.params.cap); |
|
| 1775 | 1775 | } |
|
| 1776 | 1776 | if blk.paramVars.len > 0 { |
|
| 1777 | 1777 | // TODO: Use `pop`? |
|
| 1778 | - | blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap); |
|
| 1778 | + | set blk.paramVars = @sliceOf(blk.paramVars.ptr, blk.paramVars.len - 1, blk.paramVars.cap); |
|
| 1779 | 1779 | } |
|
| 1780 | 1780 | } |
|
| 1781 | 1781 | ||
| 1782 | 1782 | /// Rewrite cached SSA values for a variable across all blocks, and also |
|
| 1783 | 1783 | /// rewrite any terminator arguments that reference the provisional register. |
| 1786 | 1786 | /// found to be trivial. |
|
| 1787 | 1787 | fn rewriteCachedVarValue(self: *mut FnLowerer, v: Var, from: il::Val, to: il::Val) { |
|
| 1788 | 1788 | for i in 0..self.blockData.len { |
|
| 1789 | 1789 | let blk = getBlockMut(self, BlockId(i)); |
|
| 1790 | 1790 | if blk.vars[*v] == from { |
|
| 1791 | - | blk.vars[*v] = to; |
|
| 1791 | + | set blk.vars[*v] = to; |
|
| 1792 | 1792 | } |
|
| 1793 | 1793 | if blk.instrs.len > 0 { |
|
| 1794 | 1794 | let ix = blk.instrs.len - 1; |
|
| 1795 | 1795 | match &mut blk.instrs[ix] { |
|
| 1796 | 1796 | case il::Instr::Jmp { args, .. } => |
| 1813 | 1813 | ||
| 1814 | 1814 | /// Replace all occurrences of `from` with `to` in an args slice. |
|
| 1815 | 1815 | fn rewriteValInSlice(args: *mut [il::Val], from: il::Val, to: il::Val) { |
|
| 1816 | 1816 | for i in 0..args.len { |
|
| 1817 | 1817 | if args[i] == from { |
|
| 1818 | - | args[i] = to; |
|
| 1818 | + | set args[i] = to; |
|
| 1819 | 1819 | } |
|
| 1820 | 1820 | } |
|
| 1821 | 1821 | } |
|
| 1822 | 1822 | ||
| 1823 | 1823 | //////////////////////////// |
| 1846 | 1846 | let id = BlockId(self.blockData.len); |
|
| 1847 | 1847 | let varCount = self.fnType.localCount; |
|
| 1848 | 1848 | let vars = try! alloc::allocSlice(self.low.arena, @sizeOf(?il::Val), @alignOf(?il::Val), varCount) as *mut [?il::Val]; |
|
| 1849 | 1849 | ||
| 1850 | 1850 | for i in 0..varCount { |
|
| 1851 | - | vars[i] = nil; |
|
| 1851 | + | set vars[i] = nil; |
|
| 1852 | 1852 | } |
|
| 1853 | 1853 | self.blockData.append(BlockData { |
|
| 1854 | 1854 | label, |
|
| 1855 | 1855 | params: &mut [], |
|
| 1856 | 1856 | paramVars: &mut [], |
| 1879 | 1879 | } |
|
| 1880 | 1880 | ||
| 1881 | 1881 | /// Switch to building a different block. |
|
| 1882 | 1882 | /// All subsequent `emit` calls will add instructions to this block. |
|
| 1883 | 1883 | fn switchToBlock(self: *mut FnLowerer, block: BlockId) { |
|
| 1884 | - | self.currentBlock = block; |
|
| 1884 | + | set self.currentBlock = block; |
|
| 1885 | 1885 | } |
|
| 1886 | 1886 | ||
| 1887 | 1887 | /// Seal a block, indicating all predecessor edges are now known. |
|
| 1888 | 1888 | /// |
|
| 1889 | 1889 | /// Sealing enables SSA construction to resolve variable uses by looking up |
| 1892 | 1892 | fn sealBlock(self: *mut FnLowerer, block: BlockId) throws (LowerError) { |
|
| 1893 | 1893 | let blk = getBlockMut(self, block); |
|
| 1894 | 1894 | let case Sealed::No { incompleteVars } = blk.sealState else { |
|
| 1895 | 1895 | return; // Already sealed. |
|
| 1896 | 1896 | }; |
|
| 1897 | - | blk.sealState = Sealed::Yes; |
|
| 1897 | + | set blk.sealState = Sealed::Yes; |
|
| 1898 | 1898 | ||
| 1899 | 1899 | // Complete all incomplete block parameters. |
|
| 1900 | 1900 | for varId in incompleteVars { |
|
| 1901 | 1901 | try resolveBlockArgs(self, block, Var(varId)); |
|
| 1902 | 1902 | } |
| 1937 | 1937 | ||
| 1938 | 1938 | // Track whether this function is a leaf. |
|
| 1939 | 1939 | if self.isLeaf { |
|
| 1940 | 1940 | match instr { |
|
| 1941 | 1941 | case il::Instr::Call { .. }, |
|
| 1942 | - | il::Instr::Ecall { .. } => self.isLeaf = false, |
|
| 1942 | + | il::Instr::Ecall { .. } => set self.isLeaf = false, |
|
| 1943 | 1943 | else => {}, |
|
| 1944 | 1944 | } |
|
| 1945 | 1945 | } |
|
| 1946 | 1946 | // Record source location alongside instruction when enabled. |
|
| 1947 | 1947 | if self.low.options.debug { |
| 2230 | 2230 | if unionInfo.isAllVoid { |
|
| 2231 | 2231 | let mut tagVal = subject.val; |
|
| 2232 | 2232 | match subject.by { |
|
| 2233 | 2233 | case resolver::MatchBy::Ref, resolver::MatchBy::MutRef => { |
|
| 2234 | 2234 | let base = emitValToReg(self, subject.val); |
|
| 2235 | - | tagVal = loadTag(self, base, 0, il::Type::W8); |
|
| 2235 | + | set tagVal = loadTag(self, base, 0, il::Type::W8); |
|
| 2236 | 2236 | } |
|
| 2237 | 2237 | case resolver::MatchBy::Value => {} |
|
| 2238 | 2238 | } |
|
| 2239 | 2239 | try emitBrCmp(self, il::CmpOp::Eq, il::Type::W8, tagVal, il::Val::Imm(variantTag as i64), matchBlock, fallthrough); |
|
| 2240 | 2240 | } else { |
| 2355 | 2355 | /// In the above example, the merge block stays `nil`, and no code is generated |
|
| 2356 | 2356 | /// after the `if`. The merge block is created on first use. |
|
| 2357 | 2357 | fn emitMergeIfUnterminated(self: *mut FnLowerer, mergeBlock: *mut ?BlockId) throws (LowerError) { |
|
| 2358 | 2358 | if not blockHasTerminator(self) { |
|
| 2359 | 2359 | if *mergeBlock == nil { |
|
| 2360 | - | *mergeBlock = try createBlock(self, "merge"); |
|
| 2360 | + | set *mergeBlock = try createBlock(self, "merge"); |
|
| 2361 | 2361 | } |
|
| 2362 | 2362 | let target = *mergeBlock else { throw LowerError::MissingTarget; }; |
|
| 2363 | 2363 | try emitJmp(self, target); |
|
| 2364 | 2364 | } |
|
| 2365 | 2365 | } |
| 2389 | 2389 | ) as *mut [il::Block]; |
|
| 2390 | 2390 | ||
| 2391 | 2391 | for i in 0..self.blockData.len { |
|
| 2392 | 2392 | let data = &self.blockData[i]; |
|
| 2393 | 2393 | ||
| 2394 | - | blocks[i] = il::Block { |
|
| 2394 | + | set blocks[i] = il::Block { |
|
| 2395 | 2395 | label: data.label, |
|
| 2396 | 2396 | params: &data.params[..], |
|
| 2397 | 2397 | instrs: data.instrs, |
|
| 2398 | 2398 | locs: &data.locs[..], |
|
| 2399 | 2399 | preds: &data.preds[..], |
| 2411 | 2411 | /// `continueBlock` is `nil` when the continue target is created lazily. |
|
| 2412 | 2412 | fn enterLoop(self: *mut FnLowerer, breakBlock: BlockId, continueBlock: ?BlockId) { |
|
| 2413 | 2413 | assert self.loopDepth < self.loopStack.len, "enterLoop: loop depth overflow"; |
|
| 2414 | 2414 | let slot = &mut self.loopStack[self.loopDepth]; |
|
| 2415 | 2415 | ||
| 2416 | - | slot.breakTarget = breakBlock; |
|
| 2417 | - | slot.continueTarget = continueBlock; |
|
| 2418 | - | self.loopDepth += 1; |
|
| 2416 | + | set slot.breakTarget = breakBlock; |
|
| 2417 | + | set slot.continueTarget = continueBlock; |
|
| 2418 | + | set self.loopDepth += 1; |
|
| 2419 | 2419 | } |
|
| 2420 | 2420 | ||
| 2421 | 2421 | /// Exit the current loop context. |
|
| 2422 | 2422 | fn exitLoop(self: *mut FnLowerer) { |
|
| 2423 | 2423 | assert self.loopDepth <> 0, "exitLoop: loopDepth is zero"; |
|
| 2424 | - | self.loopDepth -= 1; |
|
| 2424 | + | set self.loopDepth -= 1; |
|
| 2425 | 2425 | } |
|
| 2426 | 2426 | ||
| 2427 | 2427 | /// Get the current loop context. |
|
| 2428 | 2428 | fn currentLoop(self: *mut FnLowerer) -> ?*mut LoopCtx { |
|
| 2429 | 2429 | if self.loopDepth == 0 { |
| 2439 | 2439 | }; |
|
| 2440 | 2440 | if let block = ctx.continueTarget { |
|
| 2441 | 2441 | return block; |
|
| 2442 | 2442 | } |
|
| 2443 | 2443 | let block = try createBlock(self, "step"); |
|
| 2444 | - | ctx.continueTarget = block; |
|
| 2444 | + | set ctx.continueTarget = block; |
|
| 2445 | 2445 | return block; |
|
| 2446 | 2446 | } |
|
| 2447 | 2447 | ||
| 2448 | 2448 | /// Allocate a slice of values in the lowering arena. |
|
| 2449 | 2449 | fn allocVals(self: *mut FnLowerer, len: u32) -> *mut [il::Val] throws (LowerError) { |
| 2451 | 2451 | } |
|
| 2452 | 2452 | ||
| 2453 | 2453 | /// Allocate a single-value slice in the lowering arena. |
|
| 2454 | 2454 | fn allocVal(self: *mut FnLowerer, val: il::Val) -> *mut [il::Val] throws (LowerError) { |
|
| 2455 | 2455 | let args = try allocVals(self, 1); |
|
| 2456 | - | args[0] = val; |
|
| 2456 | + | set args[0] = val; |
|
| 2457 | 2457 | return args; |
|
| 2458 | 2458 | } |
|
| 2459 | 2459 | ||
| 2460 | 2460 | //////////////////////// |
|
| 2461 | 2461 | // SSA Var Management // |
| 2568 | 2568 | /// current block. Called when a variable is assigned or initialized (`let` |
|
| 2569 | 2569 | /// bindings, assignments, loop updates). When [`useVar`] is later called, |
|
| 2570 | 2570 | /// it will retrieve this value. |
|
| 2571 | 2571 | fn defVar(self: *mut FnLowerer, v: Var, val: il::Val) { |
|
| 2572 | 2572 | assert *v < self.vars.len; |
|
| 2573 | - | getBlockMut(self, currentBlock(self)).vars[*v] = val; |
|
| 2573 | + | set getBlockMut(self, currentBlock(self)).vars[*v] = val; |
|
| 2574 | 2574 | } |
|
| 2575 | 2575 | ||
| 2576 | 2576 | /// Use (read) the current value of a variable in the current block. |
|
| 2577 | 2577 | /// May insert block parameters if the value must come from predecessors. |
|
| 2578 | 2578 | fn useVar(self: *mut FnLowerer, v: Var) -> il::Val throws (LowerError) { |
| 2606 | 2606 | // available without a block parameter. |
|
| 2607 | 2607 | if blk.preds.len == 1 { |
|
| 2608 | 2608 | let pred = BlockId(blk.preds[0]); |
|
| 2609 | 2609 | if *pred <> *block { |
|
| 2610 | 2610 | let val = try useVarInBlock(self, pred, v); |
|
| 2611 | - | blk.vars[*v] = val; // Cache. |
|
| 2611 | + | set blk.vars[*v] = val; // Cache. |
|
| 2612 | 2612 | return val; |
|
| 2613 | 2613 | } |
|
| 2614 | 2614 | } |
|
| 2615 | 2615 | } |
|
| 2616 | 2616 | // Multiple predecessors or unsealed block: need a block parameter to merge |
| 2621 | 2621 | /// Look up a variable by name in the current scope. |
|
| 2622 | 2622 | /// Searches from most recently declared to first, enabling shadowing. |
|
| 2623 | 2623 | fn lookupVarByName(self: *FnLowerer, name: *[u8]) -> ?Var { |
|
| 2624 | 2624 | let mut id = self.vars.len; |
|
| 2625 | 2625 | while id > 0 { |
|
| 2626 | - | id -= 1; |
|
| 2626 | + | set id -= 1; |
|
| 2627 | 2627 | if let varName = self.vars[id].name { |
|
| 2628 | 2628 | // Names are interned strings, so pointer comparison suffices. |
|
| 2629 | 2629 | if varName == name { |
|
| 2630 | 2630 | return Var(id); |
|
| 2631 | 2631 | } |
| 2647 | 2647 | return self.vars.len; |
|
| 2648 | 2648 | } |
|
| 2649 | 2649 | ||
| 2650 | 2650 | /// Restore lexical variable scope depth. |
|
| 2651 | 2651 | fn exitVarScope(self: *mut FnLowerer, savedVarsLen: u32) { |
|
| 2652 | - | self.vars = @sliceOf(self.vars.ptr, savedVarsLen, self.vars.cap); |
|
| 2652 | + | set self.vars = @sliceOf(self.vars.ptr, savedVarsLen, self.vars.cap); |
|
| 2653 | 2653 | } |
|
| 2654 | 2654 | ||
| 2655 | 2655 | /// Get the metadata for a variable. |
|
| 2656 | 2656 | fn getVar(self: *FnLowerer, v: Var) -> *VarData { |
|
| 2657 | 2657 | assert *v < self.vars.len; |
| 2687 | 2687 | blk.params.append(param, self.allocator); |
|
| 2688 | 2688 | blk.paramVars.append(*v, self.allocator); // Associate variable with parameter. |
|
| 2689 | 2689 | ||
| 2690 | 2690 | // Record that this variable's value in this block is now the parameter register. |
|
| 2691 | 2691 | // This must happen before the predecessor loop to handle self-referential loops. |
|
| 2692 | - | blk.vars[*v] = il::Val::Reg(reg); |
|
| 2692 | + | set blk.vars[*v] = il::Val::Reg(reg); |
|
| 2693 | 2693 | ||
| 2694 | 2694 | match &mut blk.sealState { |
|
| 2695 | 2695 | case Sealed::No { incompleteVars } => { |
|
| 2696 | 2696 | // Block unsealed: defer until sealing. |
|
| 2697 | 2697 | incompleteVars.append(*v, self.allocator); |
| 2702 | 2702 | // just created and use that value directly. |
|
| 2703 | 2703 | if let trivial = try getTrivialPhiVal(self, block, v) { |
|
| 2704 | 2704 | let provisional = il::Val::Reg(reg); |
|
| 2705 | 2705 | removeLastBlockParam(self, block); |
|
| 2706 | 2706 | rewriteCachedVarValue(self, v, provisional, trivial); |
|
| 2707 | - | getBlockMut(self, block).vars[*v] = trivial; |
|
| 2707 | + | set getBlockMut(self, block).vars[*v] = trivial; |
|
| 2708 | 2708 | return trivial; |
|
| 2709 | 2709 | } |
|
| 2710 | 2710 | // Non-trivial phi: patch predecessors to pass their values. |
|
| 2711 | 2711 | try resolveBlockArgs(self, block, v); |
|
| 2712 | 2712 | }, |
| 2731 | 2731 | // Find the parameter index corresponding to this variable. |
|
| 2732 | 2732 | // Each variable that needs merging gets its own block parameter slot. |
|
| 2733 | 2733 | let mut paramIdx: u32 = 0; |
|
| 2734 | 2734 | for i in 0..blk.paramVars.len { |
|
| 2735 | 2735 | if blk.paramVars[i] == *v { |
|
| 2736 | - | paramIdx = i; |
|
| 2736 | + | set paramIdx = i; |
|
| 2737 | 2737 | break; |
|
| 2738 | 2738 | } |
|
| 2739 | 2739 | } |
|
| 2740 | 2740 | ||
| 2741 | 2741 | // For each predecessor, recursively look up the variable's reaching definition |
| 2774 | 2774 | if val <> sv { |
|
| 2775 | 2775 | // Multiple different values, not trivial. |
|
| 2776 | 2776 | return nil; |
|
| 2777 | 2777 | } |
|
| 2778 | 2778 | } else { |
|
| 2779 | - | sameVal = val; |
|
| 2779 | + | set sameVal = val; |
|
| 2780 | 2780 | } |
|
| 2781 | 2781 | } else { // No param reg set yet, can't be trivial. |
|
| 2782 | 2782 | return nil; |
|
| 2783 | 2783 | } |
|
| 2784 | 2784 | } |
| 2799 | 2799 | ||
| 2800 | 2800 | // TODO: We shouldn't need to use a mutable subscript here, given that the |
|
| 2801 | 2801 | // fields are already mutable. |
|
| 2802 | 2802 | match &mut data.instrs[ix] { |
|
| 2803 | 2803 | case il::Instr::Jmp { args, .. } => { |
|
| 2804 | - | *args = growArgs(self, *args, paramIdx + 1); |
|
| 2805 | - | args[paramIdx] = val; |
|
| 2804 | + | set *args = growArgs(self, *args, paramIdx + 1); |
|
| 2805 | + | set args[paramIdx] = val; |
|
| 2806 | 2806 | } |
|
| 2807 | 2807 | case il::Instr::Br { thenTarget, thenArgs, elseTarget, elseArgs, .. } => { |
|
| 2808 | 2808 | // Nb. both branches could target the same block (e.g. `if cond { x } else { x }`). |
|
| 2809 | 2809 | if *thenTarget == target { |
|
| 2810 | - | *thenArgs = growArgs(self, *thenArgs, paramIdx + 1); |
|
| 2811 | - | thenArgs[paramIdx] = val; |
|
| 2810 | + | set *thenArgs = growArgs(self, *thenArgs, paramIdx + 1); |
|
| 2811 | + | set thenArgs[paramIdx] = val; |
|
| 2812 | 2812 | } |
|
| 2813 | 2813 | if *elseTarget == target { |
|
| 2814 | - | *elseArgs = growArgs(self, *elseArgs, paramIdx + 1); |
|
| 2815 | - | elseArgs[paramIdx] = val; |
|
| 2814 | + | set *elseArgs = growArgs(self, *elseArgs, paramIdx + 1); |
|
| 2815 | + | set elseArgs[paramIdx] = val; |
|
| 2816 | 2816 | } |
|
| 2817 | 2817 | } |
|
| 2818 | 2818 | case il::Instr::Switch { defaultTarget, defaultArgs, cases, .. } => { |
|
| 2819 | 2819 | if *defaultTarget == target { |
|
| 2820 | - | *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1); |
|
| 2821 | - | defaultArgs[paramIdx] = val; |
|
| 2820 | + | set *defaultArgs = growArgs(self, *defaultArgs, paramIdx + 1); |
|
| 2821 | + | set defaultArgs[paramIdx] = val; |
|
| 2822 | 2822 | } |
|
| 2823 | 2823 | let idx = paramIdx + 1; |
|
| 2824 | 2824 | for ci in 0..cases.len { |
|
| 2825 | 2825 | if cases[ci].target == target { |
|
| 2826 | - | cases[ci].args = growArgs(self, cases[ci].args, idx); |
|
| 2827 | - | cases[ci].args[paramIdx] = val; |
|
| 2826 | + | set cases[ci].args = growArgs(self, cases[ci].args, idx); |
|
| 2827 | + | set cases[ci].args[paramIdx] = val; |
|
| 2828 | 2828 | } |
|
| 2829 | 2829 | } |
|
| 2830 | 2830 | } |
|
| 2831 | 2831 | else => { |
|
| 2832 | 2832 | // Other terminators (e.g. `Ret`, `Unreachable`) don't have successor blocks. |
| 2842 | 2842 | let newArgs = try! alloc::allocSlice( |
|
| 2843 | 2843 | self.low.arena, @sizeOf(il::Val), @alignOf(il::Val), capacity |
|
| 2844 | 2844 | ) as *mut [il::Val]; |
|
| 2845 | 2845 | ||
| 2846 | 2846 | for arg, i in args { |
|
| 2847 | - | newArgs[i] = arg; |
|
| 2847 | + | set newArgs[i] = arg; |
|
| 2848 | 2848 | } |
|
| 2849 | 2849 | for i in args.len..capacity { |
|
| 2850 | - | newArgs[i] = il::Val::Undef; |
|
| 2850 | + | set newArgs[i] = il::Val::Undef; |
|
| 2851 | 2851 | } |
|
| 2852 | 2852 | return newArgs; |
|
| 2853 | 2853 | } |
|
| 2854 | 2854 | ||
| 2855 | 2855 | /// Extract the parameter name from an [`FnParam`] AST node value. |
| 2881 | 2881 | let params = try! alloc::allocSlice( |
|
| 2882 | 2882 | self.low.arena, @sizeOf(il::Param), @alignOf(il::Param), totalLen |
|
| 2883 | 2883 | ) as *mut [il::Param]; |
|
| 2884 | 2884 | ||
| 2885 | 2885 | if let reg = self.returnReg { |
|
| 2886 | - | params[0] = il::Param { value: reg, type: il::Type::W64 }; |
|
| 2886 | + | set params[0] = il::Param { value: reg, type: il::Type::W64 }; |
|
| 2887 | 2887 | } |
|
| 2888 | 2888 | for i in 0..fnType.paramTypes.len as u32 { |
|
| 2889 | 2889 | let type = ilType(self.low, *fnType.paramTypes[i]); |
|
| 2890 | 2890 | let reg = nextReg(self); |
|
| 2891 | 2891 | ||
| 2892 | - | params[i + offset] = il::Param { value: reg, type }; |
|
| 2892 | + | set params[i + offset] = il::Param { value: reg, type }; |
|
| 2893 | 2893 | ||
| 2894 | 2894 | // Declare the parameter variable. For the receiver, the name comes |
|
| 2895 | 2895 | // from the receiver node. |
|
| 2896 | 2896 | // For all other parameters, the name comes from the AST params. |
|
| 2897 | 2897 | let mut name: *[u8] = undefined; |
|
| 2898 | 2898 | if let recNode = receiverName { |
|
| 2899 | 2899 | if i == 0 { |
|
| 2900 | 2900 | let case ast::NodeValue::Ident(recName) = recNode.value else { |
|
| 2901 | 2901 | throw LowerError::ExpectedIdentifier; |
|
| 2902 | 2902 | }; |
|
| 2903 | - | name = recName; |
|
| 2903 | + | set name = recName; |
|
| 2904 | 2904 | } else { |
|
| 2905 | - | name = try paramName(&astParams[i - 1].value); |
|
| 2905 | + | set name = try paramName(&astParams[i - 1].value); |
|
| 2906 | 2906 | } |
|
| 2907 | 2907 | } else { |
|
| 2908 | - | name = try paramName(&astParams[i].value); |
|
| 2908 | + | set name = try paramName(&astParams[i].value); |
|
| 2909 | 2909 | } |
|
| 2910 | 2910 | let v = newVar(self, name, type, false, il::Val::Undef); |
|
| 2911 | 2911 | ||
| 2912 | 2912 | self.params.append(FnParamBinding { var: v, reg }, self.allocator); |
|
| 2913 | 2913 | } |
| 2923 | 2923 | // When matching an aggregate by value, copy it to a fresh stack slot so |
|
| 2924 | 2924 | // that bindings are independent of the original memory. Without this, |
|
| 2925 | 2925 | // the lowerer returns a pointer into the source and mutations to the |
|
| 2926 | 2926 | // source silently corrupt the bound variables. |
|
| 2927 | 2927 | if unwrapped.by == resolver::MatchBy::Value and isAggregateType(unwrapped.effectiveTy) { |
|
| 2928 | - | val = try emitStackVal(self, unwrapped.effectiveTy, val); |
|
| 2928 | + | set val = try emitStackVal(self, unwrapped.effectiveTy, val); |
|
| 2929 | 2929 | } |
|
| 2930 | 2930 | ||
| 2931 | 2931 | let mut bindType = unwrapped.effectiveTy; |
|
| 2932 | 2932 | if let case resolver::Type::Optional(inner) = unwrapped.effectiveTy { |
|
| 2933 | - | bindType = *inner; |
|
| 2933 | + | set bindType = *inner; |
|
| 2934 | 2934 | } |
|
| 2935 | 2935 | let ilType = ilType(self.low, unwrapped.effectiveTy); |
|
| 2936 | 2936 | let kind = matchSubjectKind(unwrapped.effectiveTy); |
|
| 2937 | 2937 | ||
| 2938 | 2938 | return MatchSubject { val, type: unwrapped.effectiveTy, ilType, bindType, kind, by: unwrapped.by }; |
| 3030 | 3030 | let base = emitValToReg(self, subjectVal); |
|
| 3031 | 3031 | let mut payload: il::Val = undefined; |
|
| 3032 | 3032 | ||
| 3033 | 3033 | match matchBy { |
|
| 3034 | 3034 | case resolver::MatchBy::Value => |
|
| 3035 | - | payload = tvalPayloadVal(self, base, bindType, valOffset), |
|
| 3035 | + | set payload = tvalPayloadVal(self, base, bindType, valOffset), |
|
| 3036 | 3036 | case resolver::MatchBy::Ref, resolver::MatchBy::MutRef => |
|
| 3037 | - | payload = tvalPayloadAddr(self, base, valOffset), |
|
| 3037 | + | set payload = tvalPayloadAddr(self, base, valOffset), |
|
| 3038 | 3038 | }; |
|
| 3039 | 3039 | return newVar(self, name, ilType(self.low, bindType), mutable, payload); |
|
| 3040 | 3040 | } |
|
| 3041 | 3041 | ||
| 3042 | 3042 | fn bindMatchVariable( |
| 3198 | 3198 | let mut derefType = fieldInfo.fieldType; |
|
| 3199 | 3199 | let mut nestedBase = emitPtrOffset(self, base, fieldInfo.offset); |
|
| 3200 | 3200 | if let case resolver::Type::Pointer { target, .. } = fieldInfo.fieldType { |
|
| 3201 | 3201 | let ptrReg = nextReg(self); |
|
| 3202 | 3202 | emitLoadW64At(self, ptrReg, nestedBase, 0); |
|
| 3203 | - | nestedBase = ptrReg; |
|
| 3204 | - | derefType = *target; |
|
| 3203 | + | set nestedBase = ptrReg; |
|
| 3204 | + | set derefType = *target; |
|
| 3205 | 3205 | } |
|
| 3206 | 3206 | let recInfo = resolver::getRecord(derefType) |
|
| 3207 | 3207 | else throw LowerError::ExpectedRecord; |
|
| 3208 | 3208 | ||
| 3209 | 3209 | try bindNestedRecordFields(self, nestedBase, lit, recInfo, matchBy, failBlock); |
| 3235 | 3235 | let mut derefBase: ?il::Reg = nil; |
|
| 3236 | 3236 | if let case resolver::Type::Pointer { target, .. } = fieldType { |
|
| 3237 | 3237 | if resolver::isDestructuringPattern(pattern) { |
|
| 3238 | 3238 | let ptrReg = nextReg(self); |
|
| 3239 | 3239 | emitLoadW64At(self, ptrReg, fieldPtr, 0); |
|
| 3240 | - | derefBase = ptrReg; |
|
| 3241 | - | fieldType = *target; |
|
| 3240 | + | set derefBase = ptrReg; |
|
| 3241 | + | set fieldType = *target; |
|
| 3242 | 3242 | } |
|
| 3243 | 3243 | } |
|
| 3244 | 3244 | // Build a MatchSubject for the nested field. |
|
| 3245 | 3245 | let ilTy = ilType(self.low, fieldType); |
|
| 3246 | 3246 | let kind = matchSubjectKind(fieldType); |
|
| 3247 | 3247 | ||
| 3248 | 3248 | // Determine the subject value. |
|
| 3249 | 3249 | let mut val: il::Val = undefined; |
|
| 3250 | 3250 | if let reg = derefBase { |
|
| 3251 | 3251 | // Auto-deref: the loaded pointer is the address of the target value. |
|
| 3252 | - | val = il::Val::Reg(reg); |
|
| 3252 | + | set val = il::Val::Reg(reg); |
|
| 3253 | 3253 | } else if isAggregateType(fieldType) { |
|
| 3254 | 3254 | // Aggregate: use the pointer. |
|
| 3255 | - | val = il::Val::Reg(fieldPtr); |
|
| 3255 | + | set val = il::Val::Reg(fieldPtr); |
|
| 3256 | 3256 | } else { |
|
| 3257 | 3257 | // Scalar: load the value. |
|
| 3258 | - | val = emitRead(self, base, fieldInfo.offset, fieldType); |
|
| 3258 | + | set val = emitRead(self, base, fieldInfo.offset, fieldType); |
|
| 3259 | 3259 | } |
|
| 3260 | 3260 | let nestedSubject = MatchSubject { |
|
| 3261 | 3261 | val, |
|
| 3262 | 3262 | type: fieldType, |
|
| 3263 | 3263 | ilType: ilTy, |
| 3302 | 3302 | ||
| 3303 | 3303 | /// Lower function body to a list of basic blocks. |
|
| 3304 | 3304 | fn lowerFnBody(self: *mut FnLowerer, body: *ast::Node) -> *[il::Block] throws (LowerError) { |
|
| 3305 | 3305 | // Create and switch to entry block. |
|
| 3306 | 3306 | let entry = try createBlock(self, "entry"); |
|
| 3307 | - | self.entryBlock = entry; |
|
| 3307 | + | set self.entryBlock = entry; |
|
| 3308 | 3308 | switchToBlock(self, entry); |
|
| 3309 | 3309 | ||
| 3310 | 3310 | /// Bind parameter registers to variables in the entry block. |
|
| 3311 | 3311 | for def in self.params { |
|
| 3312 | 3312 | defVar(self, def.var, il::Val::Reg(def.reg)); |
| 3344 | 3344 | let case ast::NodeValue::MatchProng(prong) = p.value |
|
| 3345 | 3345 | else throw LowerError::UnexpectedNodeValue(p); |
|
| 3346 | 3346 | ||
| 3347 | 3347 | match prong.arm { |
|
| 3348 | 3348 | case ast::ProngArm::Binding(_), ast::ProngArm::Else => { |
|
| 3349 | - | blocks[i] = try createBlock(self, "default"); |
|
| 3350 | - | defaultIdx = i; |
|
| 3349 | + | set blocks[i] = try createBlock(self, "default"); |
|
| 3350 | + | set defaultIdx = i; |
|
| 3351 | 3351 | } |
|
| 3352 | 3352 | case ast::ProngArm::Case(pats) => { |
|
| 3353 | - | blocks[i] = try createBlock(self, "case"); |
|
| 3353 | + | set blocks[i] = try createBlock(self, "case"); |
|
| 3354 | 3354 | for pat in pats { |
|
| 3355 | 3355 | let cv = resolver::constValueEntry(self.low.resolver, pat) |
|
| 3356 | 3356 | else throw LowerError::MissingConst(pat); |
|
| 3357 | 3357 | ||
| 3358 | 3358 | cases.append(il::SwitchCase { |
| 3469 | 3469 | // The guard block must be created before the body block so that |
|
| 3470 | 3470 | // block indices are in reverse post-order (RPO), which the register |
|
| 3471 | 3471 | // allocator requires. |
|
| 3472 | 3472 | let mut entryBlock: BlockId = undefined; |
|
| 3473 | 3473 | if hasGuard { |
|
| 3474 | - | entryBlock = try createBlock(self, "guard"); |
|
| 3474 | + | set entryBlock = try createBlock(self, "guard"); |
|
| 3475 | 3475 | } |
|
| 3476 | 3476 | // Body block: where the case body lives. |
|
| 3477 | 3477 | let mut bodyLabel = "case"; |
|
| 3478 | 3478 | if prong.arm == ast::ProngArm::Else { |
|
| 3479 | - | bodyLabel = "else"; |
|
| 3479 | + | set bodyLabel = "else"; |
|
| 3480 | 3480 | } |
|
| 3481 | 3481 | let mut bodyBlock = try createBlock(self, bodyLabel); |
|
| 3482 | 3482 | if not hasGuard { |
|
| 3483 | - | entryBlock = bodyBlock; |
|
| 3483 | + | set entryBlock = bodyBlock; |
|
| 3484 | 3484 | } |
|
| 3485 | 3485 | // Fallthrough block: jumped to when pattern or guard fails. |
|
| 3486 | 3486 | let nextArm = try createBlock(self, "arm"); |
|
| 3487 | 3487 | ||
| 3488 | 3488 | // Emit pattern test: branch to entry block on match, next arm on fail. |
| 3513 | 3513 | if let g = prong.guard { |
|
| 3514 | 3514 | try emitCondBranch(self, g, bodyBlock, nextArm); |
|
| 3515 | 3515 | } else if *currentBlock(self) <> *bodyBlock { |
|
| 3516 | 3516 | // Nested tests changed the current block. Create a new body block |
|
| 3517 | 3517 | // after the nest blocks to maintain RPO ordering, and jump to it. |
|
| 3518 | - | bodyBlock = try createBlock(self, bodyLabel); |
|
| 3518 | + | set bodyBlock = try createBlock(self, bodyLabel); |
|
| 3519 | 3519 | try emitJmp(self, bodyBlock); |
|
| 3520 | 3520 | } |
|
| 3521 | 3521 | // Lower prong body and jump to merge if unterminated. |
|
| 3522 | 3522 | try switchToAndSeal(self, bodyBlock); |
|
| 3523 | 3523 | try lowerNode(self, prong.body); |
| 3544 | 3544 | fn lowerIfLet(self: *mut FnLowerer, cond: ast::IfLet) throws (LowerError) { |
|
| 3545 | 3545 | let savedVarsLen = enterVarScope(self); |
|
| 3546 | 3546 | let subject = try lowerMatchSubject(self, cond.pattern.scrutinee); |
|
| 3547 | 3547 | let mut thenBlock: BlockId = undefined; |
|
| 3548 | 3548 | if cond.pattern.guard == nil { |
|
| 3549 | - | thenBlock = try createBlock(self, "then"); |
|
| 3549 | + | set thenBlock = try createBlock(self, "then"); |
|
| 3550 | 3550 | } |
|
| 3551 | 3551 | let elseBlock = try createBlock(self, "else"); |
|
| 3552 | 3552 | let mut mergeBlock: ?BlockId = nil; |
|
| 3553 | 3553 | ||
| 3554 | 3554 | // Pattern match: jump to @then on success, @else on failure. |
| 3587 | 3587 | // If guard present, pattern match jumps to @guard, then guard evaluation |
|
| 3588 | 3588 | // jumps to `successBlock` or `failBlock`. Otherwise, jump directly to |
|
| 3589 | 3589 | // `successBlock`. |
|
| 3590 | 3590 | let mut targetBlock: BlockId = undefined; |
|
| 3591 | 3591 | if pat.guard <> nil { |
|
| 3592 | - | targetBlock = try createBlock(self, "guard"); |
|
| 3593 | - | *successBlock = try createBlock(self, successLabel); |
|
| 3592 | + | set targetBlock = try createBlock(self, "guard"); |
|
| 3593 | + | set *successBlock = try createBlock(self, successLabel); |
|
| 3594 | 3594 | } else { |
|
| 3595 | - | targetBlock = *successBlock; |
|
| 3595 | + | set targetBlock = *successBlock; |
|
| 3596 | 3596 | } |
|
| 3597 | 3597 | match pat.kind { |
|
| 3598 | 3598 | case ast::PatternKind::Case => { |
|
| 3599 | 3599 | let patterns: *mut [*ast::Node] = &mut [pat.pattern]; |
|
| 3600 | 3600 | // Jump to `targetBlock` if the pattern matches, `failBlock` otherwise. |
| 3618 | 3618 | try emitCondBranch(self, g, *successBlock, failBlock); |
|
| 3619 | 3619 | try switchToAndSeal(self, *successBlock); |
|
| 3620 | 3620 | } else if *currentBlock(self) <> *targetBlock { |
|
| 3621 | 3621 | // Nested tests changed the current block. Create a new success block |
|
| 3622 | 3622 | // after the nest blocks to maintain RPO ordering, and jump to it. |
|
| 3623 | - | *successBlock = try createBlock(self, successLabel); |
|
| 3623 | + | set *successBlock = try createBlock(self, successLabel); |
|
| 3624 | 3624 | ||
| 3625 | 3625 | try emitJmp(self, *successBlock); |
|
| 3626 | 3626 | try switchToAndSeal(self, *successBlock); |
|
| 3627 | 3627 | } |
|
| 3628 | 3628 | } |
| 3630 | 3630 | /// Lower a `let-else` statement. |
|
| 3631 | 3631 | fn lowerLetElse(self: *mut FnLowerer, letElse: ast::LetElse) throws (LowerError) { |
|
| 3632 | 3632 | let subject = try lowerMatchSubject(self, letElse.pattern.scrutinee); |
|
| 3633 | 3633 | let mut mergeBlock: BlockId = undefined; |
|
| 3634 | 3634 | if letElse.pattern.guard == nil { |
|
| 3635 | - | mergeBlock = try createBlock(self, "merge"); |
|
| 3635 | + | set mergeBlock = try createBlock(self, "merge"); |
|
| 3636 | 3636 | } |
|
| 3637 | 3637 | // Else branch executes when the pattern fails to match. |
|
| 3638 | 3638 | let elseBlock = try createBlock(self, "else"); |
|
| 3639 | 3639 | ||
| 3640 | 3640 | // Evaluate pattern and jump to @end or @else. |
| 3653 | 3653 | // Create control flow blocks: loop header, body (created lazily when |
|
| 3654 | 3654 | // there's a guard), and exit. |
|
| 3655 | 3655 | let whileBlock = try createBlock(self, "while"); |
|
| 3656 | 3656 | let mut bodyBlock: BlockId = undefined; |
|
| 3657 | 3657 | if w.pattern.guard == nil { |
|
| 3658 | - | bodyBlock = try createBlock(self, "body"); |
|
| 3658 | + | set bodyBlock = try createBlock(self, "body"); |
|
| 3659 | 3659 | } |
|
| 3660 | 3660 | let endBlock = try createBlock(self, "merge"); |
|
| 3661 | 3661 | ||
| 3662 | 3662 | // Enter loop context and jump to loop header. |
|
| 3663 | 3663 | enterLoop(self, endBlock, whileBlock); |
| 3681 | 3681 | /////////////////// |
|
| 3682 | 3682 | ||
| 3683 | 3683 | /// Lower an AST node. |
|
| 3684 | 3684 | fn lowerNode(self: *mut FnLowerer, node: *ast::Node) throws (LowerError) { |
|
| 3685 | 3685 | if self.low.options.debug { |
|
| 3686 | - | self.srcLoc.offset = node.span.offset; |
|
| 3686 | + | set self.srcLoc.offset = node.span.offset; |
|
| 3687 | 3687 | } |
|
| 3688 | 3688 | match node.value { |
|
| 3689 | 3689 | case ast::NodeValue::Block(_) => { |
|
| 3690 | 3690 | try lowerBlock(self, node); |
|
| 3691 | 3691 | } |
| 3885 | 3885 | return nil; |
|
| 3886 | 3886 | } |
|
| 3887 | 3887 | return index as i64; |
|
| 3888 | 3888 | } |
|
| 3889 | 3889 | ||
| 3890 | - | /// Check if an expression has persistent storage, ie. is an "lvalue". |
|
| 3891 | - | /// Such expressions need to be copied when used to initialize a variable, |
|
| 3892 | - | /// since their storage continues to exist independently. Temporaries (literals, |
|
| 3893 | - | /// call results) can be adopted directly without copying. |
|
| 3894 | - | fn hasStorage(node: *ast::Node) -> bool { |
|
| 3895 | - | match node.value { |
|
| 3896 | - | case ast::NodeValue::Ident(_), |
|
| 3897 | - | ast::NodeValue::FieldAccess(_), |
|
| 3898 | - | ast::NodeValue::Subscript { .. }, |
|
| 3899 | - | ast::NodeValue::Deref(_) => return true, |
|
| 3900 | - | else => return false, |
|
| 3901 | - | } |
|
| 3902 | - | } |
|
| 3903 | - | ||
| 3904 | 3890 | /// Reserve stack storage for a value of the given type. |
|
| 3905 | 3891 | fn emitReserve(self: *mut FnLowerer, typ: resolver::Type) -> il::Reg throws (LowerError) { |
|
| 3906 | 3892 | let layout = resolver::getTypeLayout(typ); |
|
| 3907 | 3893 | return emitReserveLayout(self, layout); |
|
| 3908 | 3894 | } |
| 4159 | 4145 | let reg = emitValToReg(self, val); |
|
| 4160 | 4146 | ||
| 4161 | 4147 | // For all-void unions, the value *is* the tag, not a pointer. |
|
| 4162 | 4148 | let mut tag: il::Val = undefined; |
|
| 4163 | 4149 | if resolver::isVoidUnion(valType) { |
|
| 4164 | - | tag = il::Val::Reg(reg); |
|
| 4150 | + | set tag = il::Val::Reg(reg); |
|
| 4165 | 4151 | } else { |
|
| 4166 | - | tag = loadTag(self, reg, TVAL_TAG_OFFSET, il::Type::W8); |
|
| 4152 | + | set tag = loadTag(self, reg, TVAL_TAG_OFFSET, il::Type::W8); |
|
| 4167 | 4153 | } |
|
| 4168 | 4154 | let binOp = il::BinOp::Eq if op == ast::BinaryOp::Eq else il::BinOp::Ne; |
|
| 4169 | 4155 | return emitTypedBinOp(self, binOp, il::Type::W8, tag, il::Val::Imm(tagIdx)); |
|
| 4170 | 4156 | } |
|
| 4171 | 4157 |
| 4213 | 4199 | let mut result: ?il::Val = nil; |
|
| 4214 | 4200 | ||
| 4215 | 4201 | for field in recInfo.fields { |
|
| 4216 | 4202 | let cmp = try emitEqAtOffset(self, a, b, offset + field.offset, field.fieldType); |
|
| 4217 | 4203 | ||
| 4218 | - | result = emitLogicalAnd(self, result, cmp); |
|
| 4204 | + | set result = emitLogicalAnd(self, result, cmp); |
|
| 4219 | 4205 | } |
|
| 4220 | 4206 | if let r = result { |
|
| 4221 | 4207 | return r; |
|
| 4222 | 4208 | } |
|
| 4223 | 4209 | return il::Val::Imm(1); |
| 4267 | 4253 | // Unions and nested optionals may contain uninitialized payload bytes |
|
| 4268 | 4254 | // when nil, so they need a guarded comparison. |
|
| 4269 | 4255 | let isUnion = unionInfoFromType(inner) <> nil; |
|
| 4270 | 4256 | let mut isOptional = false; |
|
| 4271 | 4257 | if let case resolver::Type::Optional(_) = inner { |
|
| 4272 | - | isOptional = true; |
|
| 4258 | + | set isOptional = true; |
|
| 4273 | 4259 | } |
|
| 4274 | 4260 | if not isUnion and not isOptional { |
|
| 4275 | 4261 | let tagEq = emitTypedBinOp(self, il::BinOp::Eq, il::Type::W8, tagA, tagB); |
|
| 4276 | 4262 | let tagNil = emitTypedBinOp(self, il::BinOp::Eq, il::Type::W8, tagA, il::Val::Imm(0)); |
|
| 4277 | 4263 | let payloadEq = try emitEqAtOffset(self, a, b, offset + valOffset, inner); |
| 4390 | 4376 | ) as *mut [il::SwitchCase]; |
|
| 4391 | 4377 | ||
| 4392 | 4378 | let mut caseBlocks: [?BlockId; resolver::MAX_UNION_VARIANTS] = undefined; |
|
| 4393 | 4379 | for variant, i in unionInfo.variants { |
|
| 4394 | 4380 | if variant.valueType == resolver::Type::Void { |
|
| 4395 | - | cases[i] = il::SwitchCase { |
|
| 4381 | + | set cases[i] = il::SwitchCase { |
|
| 4396 | 4382 | value: i as i64, |
|
| 4397 | 4383 | target: *mergeBlock, |
|
| 4398 | 4384 | args: trueArgs |
|
| 4399 | 4385 | }; |
|
| 4400 | - | caseBlocks[i] = nil; |
|
| 4386 | + | set caseBlocks[i] = nil; |
|
| 4401 | 4387 | } else { |
|
| 4402 | 4388 | let payloadBlock = try createBlock(self, "eq#payload"); |
|
| 4403 | - | cases[i] = il::SwitchCase { |
|
| 4389 | + | set cases[i] = il::SwitchCase { |
|
| 4404 | 4390 | value: i as i64, |
|
| 4405 | 4391 | target: *payloadBlock, |
|
| 4406 | 4392 | args: &mut [] |
|
| 4407 | 4393 | }; |
|
| 4408 | - | caseBlocks[i] = payloadBlock; |
|
| 4394 | + | set caseBlocks[i] = payloadBlock; |
|
| 4409 | 4395 | } |
|
| 4410 | 4396 | } |
|
| 4411 | 4397 | ||
| 4412 | 4398 | // Emit switch in @tag block. Default arm is unreachable since we cover all variants. |
|
| 4413 | 4399 | let unreachableBlock = try createBlock(self, "eq#unreachable"); |
| 4461 | 4447 | let mut result: ?il::Val = nil; |
|
| 4462 | 4448 | ||
| 4463 | 4449 | for i in 0..arr.length { |
|
| 4464 | 4450 | let elemOffset = offset + (i as i32) * stride; |
|
| 4465 | 4451 | let cmp = try emitEqAtOffset(self, a, b, elemOffset, *arr.item); |
|
| 4466 | - | result = emitLogicalAnd(self, result, cmp); |
|
| 4452 | + | set result = emitLogicalAnd(self, result, cmp); |
|
| 4467 | 4453 | } |
|
| 4468 | 4454 | if let r = result { |
|
| 4469 | 4455 | return r; |
|
| 4470 | 4456 | } |
|
| 4471 | 4457 | // Empty arrays are always equal. |
| 4558 | 4544 | let mut fieldIdx: u32 = i; |
|
| 4559 | 4545 | if recInfo.labeled { |
|
| 4560 | 4546 | let idx = resolver::recordFieldIndexFor(self.low.resolver, fieldNode) else { |
|
| 4561 | 4547 | throw LowerError::MissingMetadata; |
|
| 4562 | 4548 | }; |
|
| 4563 | - | fieldIdx = idx; |
|
| 4549 | + | set fieldIdx = idx; |
|
| 4564 | 4550 | } |
|
| 4565 | 4551 | // Skip `undefined` fields, they need no initialization. |
|
| 4566 | 4552 | // Emitting a blit from an uninitialised reserve produces a |
|
| 4567 | 4553 | // phantom SSA source value that the backend cannot handle. |
|
| 4568 | 4554 | if not isUndef(field.value) { |
| 4654 | 4640 | let mut payloadVal: ?il::Val = nil; |
|
| 4655 | 4641 | if payloadType <> resolver::Type::Void { |
|
| 4656 | 4642 | let case resolver::Type::Nominal(payloadNominal) = payloadType else { |
|
| 4657 | 4643 | throw LowerError::MissingMetadata; |
|
| 4658 | 4644 | }; |
|
| 4659 | - | payloadVal = try lowerRecordCtor(self, payloadNominal, call.args); |
|
| 4645 | + | set payloadVal = try lowerRecordCtor(self, payloadNominal, call.args); |
|
| 4660 | 4646 | } |
|
| 4661 | 4647 | return try buildTagged(self, resolver::getTypeLayout(unionTy), index as i64, payloadVal, payloadType, 1, valOffset); |
|
| 4662 | 4648 | } |
|
| 4663 | 4649 | ||
| 4664 | 4650 | /// Lower a field access into a pointer to the field. |
| 4701 | 4687 | ||
| 4702 | 4688 | // Extract data pointer and container length. |
|
| 4703 | 4689 | let mut dataReg = baseReg; |
|
| 4704 | 4690 | let mut containerLen: il::Val = undefined; |
|
| 4705 | 4691 | if let cap = info.capacity { // Slice from array. |
|
| 4706 | - | containerLen = il::Val::Imm(cap as i64); |
|
| 4692 | + | set containerLen = il::Val::Imm(cap as i64); |
|
| 4707 | 4693 | } else { // Slice from slice. |
|
| 4708 | - | dataReg = loadSlicePtr(self, baseReg); |
|
| 4709 | - | containerLen = loadSliceLen(self, baseReg); |
|
| 4694 | + | set dataReg = loadSlicePtr(self, baseReg); |
|
| 4695 | + | set containerLen = loadSliceLen(self, baseReg); |
|
| 4710 | 4696 | } |
|
| 4711 | 4697 | ||
| 4712 | 4698 | // Compute range bounds. |
|
| 4713 | 4699 | let mut startVal: il::Val = il::Val::Imm(0); |
|
| 4714 | 4700 | if let start = range.start { |
|
| 4715 | - | startVal = try lowerExpr(self, start); |
|
| 4701 | + | set startVal = try lowerExpr(self, start); |
|
| 4716 | 4702 | } |
|
| 4717 | 4703 | let mut endVal = containerLen; |
|
| 4718 | 4704 | if let end = range.end { |
|
| 4719 | - | endVal = try lowerExpr(self, end); |
|
| 4705 | + | set endVal = try lowerExpr(self, end); |
|
| 4720 | 4706 | } |
|
| 4721 | 4707 | ||
| 4722 | 4708 | // If the start value is known to be zero, the count is just the end |
|
| 4723 | 4709 | // value. Otherwise, we have to compute it. |
|
| 4724 | 4710 | let mut count = endVal; |
|
| 4725 | 4711 | ||
| 4726 | 4712 | // Only compute range offset and count if the start value is not |
|
| 4727 | 4713 | // statically known to be zero. |
|
| 4728 | 4714 | if startVal <> il::Val::Imm(0) { |
|
| 4729 | 4715 | // Offset the data pointer by the start value. |
|
| 4730 | - | dataReg = emitElem( |
|
| 4716 | + | set dataReg = emitElem( |
|
| 4731 | 4717 | self, resolver::getTypeLayout(*info.itemType).size, dataReg, startVal |
|
| 4732 | 4718 | ); |
|
| 4733 | 4719 | // Compute the count as `end - start`. |
|
| 4734 | 4720 | let lenReg = nextReg(self); |
|
| 4735 | 4721 | emit(self, il::Instr::BinOp { |
| 4737 | 4723 | typ: il::Type::W32, |
|
| 4738 | 4724 | dst: lenReg, |
|
| 4739 | 4725 | a: endVal, |
|
| 4740 | 4726 | b: startVal, |
|
| 4741 | 4727 | }); |
|
| 4742 | - | count = il::Val::Reg(lenReg); |
|
| 4728 | + | set count = il::Val::Reg(lenReg); |
|
| 4743 | 4729 | } |
|
| 4744 | 4730 | return SliceRangeResult { dataReg, count }; |
|
| 4745 | 4731 | } |
|
| 4746 | 4732 | ||
| 4747 | 4733 | /// Lower a slice range expression into a slice header value. |
| 4798 | 4784 | let layout = resolver::getLayout(self.low.resolver, addr.target, typ); |
|
| 4799 | 4785 | let slot = emitReserveLayout(self, layout); |
|
| 4800 | 4786 | try emitStore(self, slot, 0, typ, val); |
|
| 4801 | 4787 | let stackVal = il::Val::Reg(slot); |
|
| 4802 | 4788 | ||
| 4803 | - | self.vars[*v].addressTaken = true; |
|
| 4789 | + | set self.vars[*v].addressTaken = true; |
|
| 4804 | 4790 | defVar(self, v, stackVal); |
|
| 4805 | 4791 | ||
| 4806 | 4792 | return stackVal; |
|
| 4807 | 4793 | } |
|
| 4808 | 4794 | // Fall back to symbol lookup for constants/statics. |
| 4912 | 4898 | let mut dataReg = baseReg; |
|
| 4913 | 4899 | let mut elemType: resolver::Type = undefined; |
|
| 4914 | 4900 | ||
| 4915 | 4901 | match subjectTy { |
|
| 4916 | 4902 | case resolver::Type::Slice { item, .. } => { |
|
| 4917 | - | elemType = *item; |
|
| 4903 | + | set elemType = *item; |
|
| 4918 | 4904 | let sliceLen = loadSliceLen(self, baseReg); |
|
| 4919 | 4905 | // Runtime safety check: index must be strictly less than slice length. |
|
| 4920 | 4906 | try emitTrapUnlessCmp(self, il::CmpOp::Ult, il::Type::W32, indexVal, sliceLen); |
|
| 4921 | 4907 | ||
| 4922 | - | dataReg = loadSlicePtr(self, baseReg); |
|
| 4908 | + | set dataReg = loadSlicePtr(self, baseReg); |
|
| 4923 | 4909 | } |
|
| 4924 | 4910 | case resolver::Type::Array(arrInfo) => { |
|
| 4925 | - | elemType = *arrInfo.item; |
|
| 4911 | + | set elemType = *arrInfo.item; |
|
| 4926 | 4912 | // Runtime safety check: index must be strictly less than array length. |
|
| 4927 | 4913 | // Skip when the index is a compile-time constant, since we check |
|
| 4928 | 4914 | // that in the resolver. |
|
| 4929 | 4915 | if not resolver::isConstExpr(self.low.resolver, index) { |
|
| 4930 | 4916 | let arrLen = il::Val::Imm(arrInfo.length as i64); |
| 4981 | 4967 | // Temporaries such as literals or call results can be adopted directly. |
|
| 4982 | 4968 | // This is because aggregates are represented as memory addresses |
|
| 4983 | 4969 | // internally, even though they have value semantics, so without an explicit |
|
| 4984 | 4970 | // copy, only the address is is written. Function calls on the other hand |
|
| 4985 | 4971 | // reserve their own local stack space, so copying would be redundant. |
|
| 4986 | - | if isAggregateType(typ) and hasStorage(l.value) { |
|
| 4987 | - | varVal = try emitStackVal(self, typ, val); |
|
| 4972 | + | // Void variant literals (e.g. `Option::None`) use scope access syntax and |
|
| 4973 | + | // are flagged as place expressions, but they are freshly constructed |
|
| 4974 | + | // temporaries with no persistent storage. |
|
| 4975 | + | if isAggregateType(typ) and |
|
| 4976 | + | ast::isPlaceExpr(l.value) and |
|
| 4977 | + | voidVariantIndex(self.low.resolver, l.value) == nil { |
|
| 4978 | + | set varVal = try emitStackVal(self, typ, val); |
|
| 4988 | 4979 | } |
|
| 4989 | 4980 | ||
| 4990 | 4981 | // If the resolver determined that this variable's address is taken |
|
| 4991 | 4982 | // anywhere in the function, allocate a stack slot immediately so the |
|
| 4992 | 4983 | // SSA value is always a pointer. This avoids mixing integer and pointer |
| 4997 | 4988 | let layout = resolver::getLayout(self.low.resolver, node, typ); |
|
| 4998 | 4989 | let slot = emitReserveLayout(self, layout); |
|
| 4999 | 4990 | try emitStore(self, slot, 0, typ, varVal); |
|
| 5000 | 4991 | ||
| 5001 | 4992 | let v = newVar(self, name, ilType, l.mutable, il::Val::Reg(slot)); |
|
| 5002 | - | self.vars[*v].addressTaken = true; |
|
| 4993 | + | set self.vars[*v].addressTaken = true; |
|
| 5003 | 4994 | ||
| 5004 | 4995 | return; |
|
| 5005 | 4996 | } |
|
| 5006 | 4997 | } |
|
| 5007 | 4998 | } |
| 5378 | 5369 | let endExpr = range.end else { |
|
| 5379 | 5370 | throw LowerError::MissingMetadata; |
|
| 5380 | 5371 | }; |
|
| 5381 | 5372 | let mut startVal = il::Val::Imm(0); |
|
| 5382 | 5373 | if let start = range.start { |
|
| 5383 | - | startVal = try lowerExpr(self, start); |
|
| 5374 | + | set startVal = try lowerExpr(self, start); |
|
| 5384 | 5375 | } |
|
| 5385 | 5376 | let endVal = try lowerExpr(self, endExpr); |
|
| 5386 | 5377 | let iterType = ilType(self.low, *valType); |
|
| 5387 | 5378 | let valVar = newVar(self, bindingName, iterType, false, startVal); |
|
| 5388 | 5379 | ||
| 5389 | 5380 | let mut indexVar: ?Var = nil; |
|
| 5390 | 5381 | if indexName <> nil { // Optional index always starts at zero. |
|
| 5391 | - | indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0)); |
|
| 5382 | + | set indexVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0)); |
|
| 5392 | 5383 | } |
|
| 5393 | 5384 | let iter = ForIter::Range { |
|
| 5394 | 5385 | valVar, indexVar, endVal, valType: iterType, |
|
| 5395 | 5386 | unsigned: isUnsignedType(*valType), |
|
| 5396 | 5387 | }; |
| 5402 | 5393 | let containerReg = emitValToReg(self, containerVal); |
|
| 5403 | 5394 | ||
| 5404 | 5395 | let mut dataReg = containerReg; |
|
| 5405 | 5396 | let mut lengthVal: il::Val = undefined; |
|
| 5406 | 5397 | if let len = length { // Array (length is known). |
|
| 5407 | - | lengthVal = il::Val::Imm(len as i64); |
|
| 5398 | + | set lengthVal = il::Val::Imm(len as i64); |
|
| 5408 | 5399 | } else { // Slice (length must be loaded). |
|
| 5409 | - | lengthVal = loadSliceLen(self, containerReg); |
|
| 5410 | - | dataReg = loadSlicePtr(self, containerReg); |
|
| 5400 | + | set lengthVal = loadSliceLen(self, containerReg); |
|
| 5401 | + | set dataReg = loadSlicePtr(self, containerReg); |
|
| 5411 | 5402 | } |
|
| 5412 | 5403 | // Declare index value binidng. |
|
| 5413 | 5404 | let idxVar = newVar(self, indexName, il::Type::W32, false, il::Val::Imm(0)); |
|
| 5414 | 5405 | ||
| 5415 | 5406 | // Declare element value binding. |
|
| 5416 | 5407 | let mut valVar: ?Var = nil; |
|
| 5417 | 5408 | if bindingName <> nil { |
|
| 5418 | - | valVar = newVar( |
|
| 5409 | + | set valVar = newVar( |
|
| 5419 | 5410 | self, |
|
| 5420 | 5411 | bindingName, |
|
| 5421 | 5412 | ilType(self.low, *elemType), |
|
| 5422 | 5413 | false, |
|
| 5423 | 5414 | il::Val::Undef |
| 5472 | 5463 | ||
| 5473 | 5464 | /// Lower a return statement. |
|
| 5474 | 5465 | fn lowerReturnStmt(self: *mut FnLowerer, node: *ast::Node, value: ?*ast::Node) throws (LowerError) { |
|
| 5475 | 5466 | let mut val = il::Val::Undef; |
|
| 5476 | 5467 | if let expr = value { |
|
| 5477 | - | val = try lowerExpr(self, expr); |
|
| 5468 | + | set val = try lowerExpr(self, expr); |
|
| 5478 | 5469 | } |
|
| 5479 | - | val = try applyCoercion(self, node, val); |
|
| 5470 | + | set val = try applyCoercion(self, node, val); |
|
| 5480 | 5471 | try emitRetVal(self, val); |
|
| 5481 | 5472 | } |
|
| 5482 | 5473 | ||
| 5483 | 5474 | /// Lower a throw statement. |
|
| 5484 | 5475 | fn lowerThrowStmt(self: *mut FnLowerer, expr: *ast::Node) throws (LowerError) { |
| 5570 | 5561 | // Result when short-circuiting (`0` or `1`). |
|
| 5571 | 5562 | let mut shortCircuitVal: i64 = undefined; |
|
| 5572 | 5563 | ||
| 5573 | 5564 | match op { |
|
| 5574 | 5565 | case LogicalOp::And => { |
|
| 5575 | - | shortCircuitBlock = elseBlock; |
|
| 5576 | - | evalBlock = thenBlock; |
|
| 5577 | - | shortCircuitVal = 0; |
|
| 5566 | + | set shortCircuitBlock = elseBlock; |
|
| 5567 | + | set evalBlock = thenBlock; |
|
| 5568 | + | set shortCircuitVal = 0; |
|
| 5578 | 5569 | } |
|
| 5579 | 5570 | case LogicalOp::Or => { |
|
| 5580 | - | shortCircuitBlock = thenBlock; |
|
| 5581 | - | evalBlock = elseBlock; |
|
| 5582 | - | shortCircuitVal = 1; |
|
| 5571 | + | set shortCircuitBlock = thenBlock; |
|
| 5572 | + | set evalBlock = elseBlock; |
|
| 5573 | + | set shortCircuitVal = 1; |
|
| 5583 | 5574 | } |
|
| 5584 | 5575 | } |
|
| 5585 | 5576 | // Emit short-circuit branch: jump to merge with constant result. |
|
| 5586 | 5577 | try switchToAndSeal(self, shortCircuitBlock); |
|
| 5587 | 5578 | try emitJmpWithArg(self, mergeBlock, il::Val::Imm(shortCircuitVal)); |
| 5700 | 5691 | // Aggregate types require element-wise comparison. |
|
| 5701 | 5692 | // When comparing `?T` with `T`, wrap the scalar side. |
|
| 5702 | 5693 | if isAggregateType(leftTy) { |
|
| 5703 | 5694 | let mut rhs = b; |
|
| 5704 | 5695 | if not isAggregateType(rightTy) { |
|
| 5705 | - | rhs = try wrapInOptional(self, rhs, leftTy); |
|
| 5696 | + | set rhs = try wrapInOptional(self, rhs, leftTy); |
|
| 5706 | 5697 | } |
|
| 5707 | 5698 | return try emitAggregateEqOp(self, binop.op, leftTy, a, rhs); |
|
| 5708 | 5699 | } |
|
| 5709 | 5700 | if isAggregateType(rightTy) { |
|
| 5710 | 5701 | let lhs = try wrapInOptional(self, a, rightTy); |
|
| 5711 | 5702 | return try emitAggregateEqOp(self, binop.op, rightTy, lhs, b); |
|
| 5712 | 5703 | } |
|
| 5713 | - | resultTy = leftTy; |
|
| 5704 | + | set resultTy = leftTy; |
|
| 5714 | 5705 | } |
|
| 5715 | 5706 | return emitScalarBinOp(self, binop.op, ilType(self.low, resultTy), a, b, isUnsignedType(resultTy)); |
|
| 5716 | 5707 | } |
|
| 5717 | 5708 | ||
| 5718 | 5709 | /// Emit an aggregate equality or inequality comparison. |
| 5745 | 5736 | let dst = nextReg(self); |
|
| 5746 | 5737 | let mut needsExt: bool = false; |
|
| 5747 | 5738 | match op { |
|
| 5748 | 5739 | case ast::BinaryOp::Add => { |
|
| 5749 | 5740 | emit(self, il::Instr::BinOp { op: il::BinOp::Add, typ, dst, a, b }); |
|
| 5750 | - | needsExt = true; |
|
| 5741 | + | set needsExt = true; |
|
| 5751 | 5742 | } |
|
| 5752 | 5743 | case ast::BinaryOp::Sub => { |
|
| 5753 | 5744 | emit(self, il::Instr::BinOp { op: il::BinOp::Sub, typ, dst, a, b }); |
|
| 5754 | - | needsExt = true; |
|
| 5745 | + | set needsExt = true; |
|
| 5755 | 5746 | } |
|
| 5756 | 5747 | case ast::BinaryOp::Mul => { |
|
| 5757 | 5748 | emit(self, il::Instr::BinOp { op: il::BinOp::Mul, typ, dst, a, b }); |
|
| 5758 | - | needsExt = true; |
|
| 5749 | + | set needsExt = true; |
|
| 5759 | 5750 | } |
|
| 5760 | 5751 | case ast::BinaryOp::Div => { |
|
| 5761 | 5752 | let op = il::BinOp::Udiv if unsigned else il::BinOp::Sdiv; |
|
| 5762 | 5753 | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5763 | - | needsExt = true; |
|
| 5754 | + | set needsExt = true; |
|
| 5764 | 5755 | } |
|
| 5765 | 5756 | case ast::BinaryOp::Mod => { |
|
| 5766 | 5757 | let op = il::BinOp::Urem if unsigned else il::BinOp::Srem; |
|
| 5767 | 5758 | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5768 | - | needsExt = true; |
|
| 5759 | + | set needsExt = true; |
|
| 5769 | 5760 | } |
|
| 5770 | 5761 | case ast::BinaryOp::BitAnd => emit(self, il::Instr::BinOp { op: il::BinOp::And, typ, dst, a, b }), |
|
| 5771 | 5762 | case ast::BinaryOp::BitOr => emit(self, il::Instr::BinOp { op: il::BinOp::Or, typ, dst, a, b }), |
|
| 5772 | 5763 | case ast::BinaryOp::BitXor => emit(self, il::Instr::BinOp { op: il::BinOp::Xor, typ, dst, a, b }), |
|
| 5773 | 5764 | case ast::BinaryOp::Shl => { |
|
| 5774 | 5765 | emit(self, il::Instr::BinOp { op: il::BinOp::Shl, typ, dst, a, b }); |
|
| 5775 | - | needsExt = true; |
|
| 5766 | + | set needsExt = true; |
|
| 5776 | 5767 | } |
|
| 5777 | 5768 | case ast::BinaryOp::Shr => { |
|
| 5778 | 5769 | let op = il::BinOp::Ushr if unsigned else il::BinOp::Sshr; |
|
| 5779 | 5770 | emit(self, il::Instr::BinOp { op, typ, dst, a, b }); |
|
| 5780 | 5771 | } |
| 5836 | 5827 | case ast::UnaryOp::Not => { |
|
| 5837 | 5828 | emit(self, il::Instr::BinOp { op: il::BinOp::Eq, typ, dst, a: val, b: il::Val::Imm(0) }); |
|
| 5838 | 5829 | } |
|
| 5839 | 5830 | case ast::UnaryOp::Neg => { |
|
| 5840 | 5831 | emit(self, il::Instr::UnOp { op: il::UnOp::Neg, typ, dst, a: val }); |
|
| 5841 | - | needsExt = true; |
|
| 5832 | + | set needsExt = true; |
|
| 5842 | 5833 | } |
|
| 5843 | 5834 | case ast::UnaryOp::BitNot => { |
|
| 5844 | 5835 | emit(self, il::Instr::UnOp { op: il::UnOp::Not, typ, dst, a: val }); |
|
| 5845 | - | needsExt = true; |
|
| 5836 | + | set needsExt = true; |
|
| 5846 | 5837 | } |
|
| 5847 | 5838 | } |
|
| 5848 | 5839 | if needsExt { |
|
| 5849 | 5840 | return normalizeSubword(self, typ, isUnsignedType(t), il::Val::Reg(dst)); |
|
| 5850 | 5841 | } |
| 5893 | 5884 | // Build the string data value. |
|
| 5894 | 5885 | let ptr = try! alloc::alloc( |
|
| 5895 | 5886 | self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue) |
|
| 5896 | 5887 | ) as *mut il::DataValue; |
|
| 5897 | 5888 | ||
| 5898 | - | *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 }; |
|
| 5889 | + | set *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 }; |
|
| 5899 | 5890 | ||
| 5900 | 5891 | return try lowerConstDataAsSlice(self, @sliceOf(ptr, 1), 1, true, item, mutable, s.len); |
|
| 5901 | 5892 | } |
|
| 5902 | 5893 | ||
| 5903 | 5894 | /// Lower a builtin call expression. |
| 5924 | 5915 | }; |
|
| 5925 | 5916 | let ptrVal = try lowerExpr(self, args[0]); |
|
| 5926 | 5917 | let lenVal = try lowerExpr(self, args[1]); |
|
| 5927 | 5918 | let mut capVal = lenVal; |
|
| 5928 | 5919 | if args.len == 3 { |
|
| 5929 | - | capVal = try lowerExpr(self, args[2]); |
|
| 5920 | + | set capVal = try lowerExpr(self, args[2]); |
|
| 5930 | 5921 | } |
|
| 5931 | 5922 | return try buildSliceValue(self, item, mutable, ptrVal, lenVal, capVal); |
|
| 5932 | 5923 | } |
|
| 5933 | 5924 | ||
| 5934 | 5925 | /// Lower a `try` expression. |
| 5949 | 5940 | let mut resVal: il::Val = undefined; |
|
| 5950 | 5941 | let callNodeExtra = resolver::nodeData(self.low.resolver, t.expr).extra; |
|
| 5951 | 5942 | if let case resolver::NodeExtra::TraitMethodCall { |
|
| 5952 | 5943 | traitInfo, methodIndex |
|
| 5953 | 5944 | } = callNodeExtra { |
|
| 5954 | - | resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex); |
|
| 5945 | + | set resVal = try lowerTraitMethodCall(self, t.expr, callExpr, traitInfo, methodIndex); |
|
| 5955 | 5946 | } else if let case resolver::NodeExtra::MethodCall { method } = callNodeExtra { |
|
| 5956 | - | resVal = try lowerMethodCall(self, t.expr, callExpr, method); |
|
| 5947 | + | set resVal = try lowerMethodCall(self, t.expr, callExpr, method); |
|
| 5957 | 5948 | } else { |
|
| 5958 | - | resVal = try lowerCall(self, t.expr, callExpr); |
|
| 5949 | + | set resVal = try lowerCall(self, t.expr, callExpr); |
|
| 5959 | 5950 | } |
|
| 5960 | 5951 | let base = emitValToReg(self, resVal); // The result value. |
|
| 5961 | 5952 | let tagReg = resultTagReg(self, base); // The result tag. |
|
| 5962 | 5953 | ||
| 5963 | 5954 | let okBlock = try createBlock(self, "ok"); // Block if success. |
| 5968 | 5959 | ||
| 5969 | 5960 | // Check if the `try` returns a success value or not. If so, reserve |
|
| 5970 | 5961 | // space for it. |
|
| 5971 | 5962 | let isVoid = tryExprTy == resolver::Type::Void; |
|
| 5972 | 5963 | if not isVoid { |
|
| 5973 | - | resultSlot = try emitReserve(self, tryExprTy); |
|
| 5964 | + | set resultSlot = try emitReserve(self, tryExprTy); |
|
| 5974 | 5965 | } |
|
| 5975 | 5966 | // Branch on tag: zero means ok, non-zero means error. |
|
| 5976 | 5967 | try emitBr(self, tagReg, errBlock, okBlock); |
|
| 5977 | 5968 | ||
| 5978 | 5969 | // We can now seal the blocks since all predecessors are known. |
| 5988 | 5979 | // type (e.g. `try?` wrapping `T` into `?T`), wrap the value. |
|
| 5989 | 5980 | let payloadVal = tvalPayloadVal(self, base, okValueTy, RESULT_VAL_OFFSET); |
|
| 5990 | 5981 | let mut okVal = payloadVal; |
|
| 5991 | 5982 | ||
| 5992 | 5983 | if t.returnsOptional and tryExprTy <> okValueTy { |
|
| 5993 | - | okVal = try wrapInOptional(self, payloadVal, tryExprTy); |
|
| 5984 | + | set okVal = try wrapInOptional(self, payloadVal, tryExprTy); |
|
| 5994 | 5985 | } |
|
| 5995 | 5986 | try emitStore(self, slot, 0, tryExprTy, okVal); |
|
| 5996 | 5987 | } |
|
| 5997 | 5988 | // Jump to merge block if unterminated. |
|
| 5998 | 5989 | try emitMergeIfUnterminated(self, &mut mergeBlock); |
| 6094 | 6085 | ||
| 6095 | 6086 | for clauseNode, i in catches { |
|
| 6096 | 6087 | let case ast::NodeValue::CatchClause(clause) = clauseNode.value |
|
| 6097 | 6088 | else panic "lowerMultiCatch: expected CatchClause"; |
|
| 6098 | 6089 | ||
| 6099 | - | blocks[i] = try createBlock(self, "catch"); |
|
| 6090 | + | set blocks[i] = try createBlock(self, "catch"); |
|
| 6100 | 6091 | addPredecessor(self, blocks[i], entry); |
|
| 6101 | 6092 | ||
| 6102 | 6093 | if let typeNode = clause.typeNode { |
|
| 6103 | 6094 | let errTy = try typeOf(self, typeNode); |
|
| 6104 | - | errTypes[i] = errTy; |
|
| 6095 | + | set errTypes[i] = errTy; |
|
| 6105 | 6096 | ||
| 6106 | 6097 | cases.append(il::SwitchCase { |
|
| 6107 | 6098 | value: getOrAssignErrorTag(self.low, errTy) as i64, |
|
| 6108 | 6099 | target: *blocks[i], |
|
| 6109 | 6100 | args: &mut [] |
|
| 6110 | 6101 | }, self.allocator); |
|
| 6111 | 6102 | } else { |
|
| 6112 | - | errTypes[i] = nil; |
|
| 6113 | - | defaultIdx = i; |
|
| 6103 | + | set errTypes[i] = nil; |
|
| 6104 | + | set defaultIdx = i; |
|
| 6114 | 6105 | } |
|
| 6115 | 6106 | } |
|
| 6116 | 6107 | ||
| 6117 | 6108 | // Emit switch. Default target is the catch-all block, or an unreachable block. |
|
| 6118 | 6109 | let mut defaultTarget: BlockId = undefined; |
|
| 6119 | 6110 | if let idx = defaultIdx { |
|
| 6120 | - | defaultTarget = blocks[idx]; |
|
| 6111 | + | set defaultTarget = blocks[idx]; |
|
| 6121 | 6112 | } else { |
|
| 6122 | - | defaultTarget = try createBlock(self, "unreachable"); |
|
| 6113 | + | set defaultTarget = try createBlock(self, "unreachable"); |
|
| 6123 | 6114 | addPredecessor(self, defaultTarget, entry); |
|
| 6124 | 6115 | } |
|
| 6125 | 6116 | emit(self, il::Instr::Switch { |
|
| 6126 | 6117 | val: il::Val::Reg(tagReg), |
|
| 6127 | 6118 | defaultTarget: *defaultTarget, |
| 6265 | 6256 | emitLoadW64At(self, allocCtxReg, allocReg, 8); |
|
| 6266 | 6257 | ||
| 6267 | 6258 | let byteSize = emitTypedBinOp(self, il::BinOp::Mul, il::Type::W32, newCapVal, il::Val::Imm(stride as i64)); |
|
| 6268 | 6259 | let args = try allocVals(self, 3); |
|
| 6269 | 6260 | ||
| 6270 | - | args[0] = il::Val::Reg(allocCtxReg); |
|
| 6271 | - | args[1] = byteSize; |
|
| 6272 | - | args[2] = il::Val::Imm(alignment as i64); |
|
| 6261 | + | set args[0] = il::Val::Reg(allocCtxReg); |
|
| 6262 | + | set args[1] = byteSize; |
|
| 6263 | + | set args[2] = il::Val::Imm(alignment as i64); |
|
| 6273 | 6264 | ||
| 6274 | 6265 | let newPtrReg = nextReg(self); |
|
| 6275 | 6266 | emit(self, il::Instr::Call { |
|
| 6276 | 6267 | retTy: il::Type::W64, |
|
| 6277 | 6268 | dst: newPtrReg, |
| 6437 | 6428 | let methodFnType = traitInfo.methods[methodIndex].fnType; |
|
| 6438 | 6429 | ||
| 6439 | 6430 | // Build args: optional return param slot + data pointer (receiver) + user args. |
|
| 6440 | 6431 | let argOffset: u32 = 1 if requiresReturnParam(methodFnType) else 0; |
|
| 6441 | 6432 | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 6442 | - | args[argOffset] = il::Val::Reg(dataReg); |
|
| 6433 | + | set args[argOffset] = il::Val::Reg(dataReg); |
|
| 6443 | 6434 | ||
| 6444 | 6435 | for arg, i in call.args { |
|
| 6445 | - | args[i + 1 + argOffset] = try lowerExpr(self, arg); |
|
| 6436 | + | set args[i + 1 + argOffset] = try lowerExpr(self, arg); |
|
| 6446 | 6437 | } |
|
| 6447 | 6438 | return try emitCallValue(self, il::Val::Reg(fnPtrReg), methodFnType, args); |
|
| 6448 | 6439 | } |
|
| 6449 | 6440 | ||
| 6450 | 6441 | /// Emit a function call with return-parameter and small-aggregate handling. |
| 6462 | 6453 | let retTy = *fnInfo.returnType; |
|
| 6463 | 6454 | ||
| 6464 | 6455 | if requiresReturnParam(fnInfo) { |
|
| 6465 | 6456 | if fnInfo.throwList.len > 0 { |
|
| 6466 | 6457 | let layout = resolver::getResultLayout(retTy, fnInfo.throwList); |
|
| 6467 | - | args[0] = il::Val::Reg(emitReserveLayout(self, layout)); |
|
| 6458 | + | set args[0] = il::Val::Reg(emitReserveLayout(self, layout)); |
|
| 6468 | 6459 | } else { |
|
| 6469 | - | args[0] = il::Val::Reg(try emitReserve(self, retTy)); |
|
| 6460 | + | set args[0] = il::Val::Reg(try emitReserve(self, retTy)); |
|
| 6470 | 6461 | } |
|
| 6471 | 6462 | let dst = nextReg(self); |
|
| 6472 | 6463 | ||
| 6473 | 6464 | emit(self, il::Instr::Call { |
|
| 6474 | 6465 | retTy: il::Type::W64, |
| 6478 | 6469 | }); |
|
| 6479 | 6470 | return il::Val::Reg(dst); |
|
| 6480 | 6471 | } |
|
| 6481 | 6472 | let mut dst: ?il::Reg = nil; |
|
| 6482 | 6473 | if retTy <> resolver::Type::Void { |
|
| 6483 | - | dst = nextReg(self); |
|
| 6474 | + | set dst = nextReg(self); |
|
| 6484 | 6475 | } |
|
| 6485 | 6476 | emit(self, il::Instr::Call { |
|
| 6486 | 6477 | retTy: ilType(self.low, retTy), |
|
| 6487 | 6478 | dst, |
|
| 6488 | 6479 | func: callee, |
| 6558 | 6549 | else panic "lowerMethodCall: expected Fn type on method symbol"; |
|
| 6559 | 6550 | ||
| 6560 | 6551 | // Build args: optional return param slot + receiver + user args. |
|
| 6561 | 6552 | let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0; |
|
| 6562 | 6553 | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 6563 | - | args[argOffset] = receiverVal; |
|
| 6554 | + | set args[argOffset] = receiverVal; |
|
| 6564 | 6555 | for arg, i in call.args { |
|
| 6565 | - | args[i + 1 + argOffset] = try lowerExpr(self, arg); |
|
| 6556 | + | set args[i + 1 + argOffset] = try lowerExpr(self, arg); |
|
| 6566 | 6557 | } |
|
| 6567 | 6558 | return try emitCallValue(self, il::Val::FnAddr(qualName), fnInfo, args); |
|
| 6568 | 6559 | } |
|
| 6569 | 6560 | ||
| 6570 | 6561 | /// Check if a call is to a compiler intrinsic and lower it directly. |
| 6649 | 6640 | }; |
|
| 6650 | 6641 | let callee = try lowerCallee(self, call.callee); |
|
| 6651 | 6642 | let offset: u32 = 1 if requiresReturnParam(fnInfo) else 0; |
|
| 6652 | 6643 | let args = try allocVals(self, call.args.len + offset); |
|
| 6653 | 6644 | for arg, i in call.args { |
|
| 6654 | - | args[i + offset] = try lowerExpr(self, arg); |
|
| 6645 | + | set args[i + offset] = try lowerExpr(self, arg); |
|
| 6655 | 6646 | } |
|
| 6656 | 6647 | ||
| 6657 | 6648 | return try emitCallValue(self, callee, fnInfo, args); |
|
| 6658 | 6649 | } |
|
| 6659 | 6650 |
| 6809 | 6800 | ||
| 6810 | 6801 | /// Lower an expression AST node to an IL value. |
|
| 6811 | 6802 | /// This is the main expression dispatch, all expression nodes go through here. |
|
| 6812 | 6803 | fn lowerExpr(self: *mut FnLowerer, node: *ast::Node) -> il::Val throws (LowerError) { |
|
| 6813 | 6804 | if self.low.options.debug { |
|
| 6814 | - | self.srcLoc.offset = node.span.offset; |
|
| 6805 | + | set self.srcLoc.offset = node.span.offset; |
|
| 6815 | 6806 | } |
|
| 6816 | 6807 | let mut val: il::Val = undefined; |
|
| 6817 | 6808 | ||
| 6818 | 6809 | match node.value { |
|
| 6819 | 6810 | case ast::NodeValue::Ident(_) => { |
|
| 6820 | 6811 | // First try local variable lookup. |
|
| 6821 | 6812 | // Otherwise fall back to global symbol lookup. |
|
| 6822 | 6813 | if let v = lookupLocalVar(self, node) { |
|
| 6823 | - | val = try useVar(self, v); |
|
| 6814 | + | set val = try useVar(self, v); |
|
| 6824 | 6815 | if self.vars[*v].addressTaken { |
|
| 6825 | 6816 | let typ = try typeOf(self, node); |
|
| 6826 | 6817 | let ptr = emitValToReg(self, val); |
|
| 6827 | - | val = emitRead(self, ptr, 0, typ); |
|
| 6818 | + | set val = emitRead(self, ptr, 0, typ); |
|
| 6828 | 6819 | } |
|
| 6829 | 6820 | } else { |
|
| 6830 | - | val = try lowerGlobalSymbol(self, node); |
|
| 6821 | + | set val = try lowerGlobalSymbol(self, node); |
|
| 6831 | 6822 | } |
|
| 6832 | 6823 | } |
|
| 6833 | 6824 | case ast::NodeValue::ScopeAccess(_) => { |
|
| 6834 | - | val = try lowerScopeAccess(self, node); |
|
| 6825 | + | set val = try lowerScopeAccess(self, node); |
|
| 6835 | 6826 | } |
|
| 6836 | 6827 | case ast::NodeValue::Number(lit) => { |
|
| 6837 | 6828 | let mag = -(lit.magnitude as i64) if lit.negative else lit.magnitude as i64; |
|
| 6838 | - | val = il::Val::Imm(mag); |
|
| 6829 | + | set val = il::Val::Imm(mag); |
|
| 6839 | 6830 | } |
|
| 6840 | 6831 | case ast::NodeValue::Bool(b) => { |
|
| 6841 | - | val = il::Val::Imm(1) if b else il::Val::Imm(0); |
|
| 6832 | + | set val = il::Val::Imm(1) if b else il::Val::Imm(0); |
|
| 6842 | 6833 | } |
|
| 6843 | 6834 | case ast::NodeValue::Char(c) => { |
|
| 6844 | - | val = il::Val::Imm(c as i64); |
|
| 6835 | + | set val = il::Val::Imm(c as i64); |
|
| 6845 | 6836 | } |
|
| 6846 | 6837 | case ast::NodeValue::Nil => { |
|
| 6847 | 6838 | let typ = try typeOf(self, node); |
|
| 6848 | 6839 | if let case resolver::Type::Optional(_) = typ { |
|
| 6849 | - | val = try buildNilOptional(self, typ); |
|
| 6840 | + | set val = try buildNilOptional(self, typ); |
|
| 6850 | 6841 | } else if let case resolver::Type::Nil = typ { |
|
| 6851 | 6842 | // Standalone `nil` without a concrete optional type. We can't |
|
| 6852 | 6843 | // generate a proper value representation. |
|
| 6853 | 6844 | throw LowerError::MissingType(node); |
|
| 6854 | 6845 | } else { |
|
| 6855 | 6846 | throw LowerError::NilInNonOptional; |
|
| 6856 | 6847 | } |
|
| 6857 | 6848 | } |
|
| 6858 | 6849 | case ast::NodeValue::RecordLit(lit) => { |
|
| 6859 | - | val = try lowerRecordLit(self, node, lit); |
|
| 6850 | + | set val = try lowerRecordLit(self, node, lit); |
|
| 6860 | 6851 | } |
|
| 6861 | 6852 | case ast::NodeValue::AddressOf(addr) => { |
|
| 6862 | - | val = try lowerAddressOf(self, node, addr); |
|
| 6853 | + | set val = try lowerAddressOf(self, node, addr); |
|
| 6863 | 6854 | } |
|
| 6864 | 6855 | case ast::NodeValue::Deref(target) => { |
|
| 6865 | - | val = try lowerDeref(self, node, target); |
|
| 6856 | + | set val = try lowerDeref(self, node, target); |
|
| 6866 | 6857 | } |
|
| 6867 | 6858 | case ast::NodeValue::BinOp(binop) => { |
|
| 6868 | - | val = try lowerBinOp(self, node, binop); |
|
| 6859 | + | set val = try lowerBinOp(self, node, binop); |
|
| 6869 | 6860 | } |
|
| 6870 | 6861 | case ast::NodeValue::UnOp(unop) => { |
|
| 6871 | - | val = try lowerUnOp(self, node, unop); |
|
| 6862 | + | set val = try lowerUnOp(self, node, unop); |
|
| 6872 | 6863 | } |
|
| 6873 | 6864 | case ast::NodeValue::Subscript { container, index } => { |
|
| 6874 | - | val = try lowerSubscript(self, node, container, index); |
|
| 6865 | + | set val = try lowerSubscript(self, node, container, index); |
|
| 6875 | 6866 | } |
|
| 6876 | 6867 | case ast::NodeValue::BuiltinCall { kind, args } => { |
|
| 6877 | - | val = try lowerBuiltinCall(self, node, kind, args); |
|
| 6868 | + | set val = try lowerBuiltinCall(self, node, kind, args); |
|
| 6878 | 6869 | } |
|
| 6879 | 6870 | case ast::NodeValue::Call(call) => { |
|
| 6880 | - | val = try lowerCallOrCtor(self, node, call); |
|
| 6871 | + | set val = try lowerCallOrCtor(self, node, call); |
|
| 6881 | 6872 | } |
|
| 6882 | 6873 | case ast::NodeValue::Try(t) => { |
|
| 6883 | - | val = try lowerTry(self, node, t); |
|
| 6874 | + | set val = try lowerTry(self, node, t); |
|
| 6884 | 6875 | } |
|
| 6885 | 6876 | case ast::NodeValue::FieldAccess(access) => { |
|
| 6886 | 6877 | // Check for compile-time constant (e.g., `arr.len` on fixed-size arrays). |
|
| 6887 | 6878 | if let constVal = resolver::constValueEntry(self.low.resolver, node) { |
|
| 6888 | 6879 | match constVal { |
|
| 6889 | 6880 | // TODO: Handle `u32` values that don't fit in an `i32`. |
|
| 6890 | 6881 | // Perhaps just store the `ConstInt`. |
|
| 6891 | - | case resolver::ConstValue::Int(i) => val = il::Val::Imm(constIntToI64(i)), |
|
| 6892 | - | else => val = try lowerFieldAccess(self, access), |
|
| 6882 | + | case resolver::ConstValue::Int(i) => set val = il::Val::Imm(constIntToI64(i)), |
|
| 6883 | + | else => set val = try lowerFieldAccess(self, access), |
|
| 6893 | 6884 | } |
|
| 6894 | 6885 | } else { |
|
| 6895 | - | val = try lowerFieldAccess(self, access); |
|
| 6886 | + | set val = try lowerFieldAccess(self, access); |
|
| 6896 | 6887 | } |
|
| 6897 | 6888 | } |
|
| 6898 | 6889 | case ast::NodeValue::ArrayLit(elements) => { |
|
| 6899 | - | val = try lowerArrayLit(self, node, elements); |
|
| 6890 | + | set val = try lowerArrayLit(self, node, elements); |
|
| 6900 | 6891 | } |
|
| 6901 | 6892 | case ast::NodeValue::ArrayRepeatLit(repeat) => { |
|
| 6902 | - | val = try lowerArrayRepeatLit(self, node, repeat); |
|
| 6893 | + | set val = try lowerArrayRepeatLit(self, node, repeat); |
|
| 6903 | 6894 | } |
|
| 6904 | 6895 | case ast::NodeValue::As(cast) => { |
|
| 6905 | - | val = try lowerCast(self, node, cast); |
|
| 6896 | + | set val = try lowerCast(self, node, cast); |
|
| 6906 | 6897 | } |
|
| 6907 | 6898 | case ast::NodeValue::CondExpr(cond) => { |
|
| 6908 | - | val = try lowerCondExpr(self, node, cond); |
|
| 6899 | + | set val = try lowerCondExpr(self, node, cond); |
|
| 6909 | 6900 | } |
|
| 6910 | 6901 | case ast::NodeValue::String(s) => { |
|
| 6911 | - | val = try lowerStringLit(self, node, s); |
|
| 6902 | + | set val = try lowerStringLit(self, node, s); |
|
| 6912 | 6903 | } |
|
| 6913 | 6904 | case ast::NodeValue::Undef => { |
|
| 6914 | 6905 | let typ = try typeOf(self, node); |
|
| 6915 | 6906 | if isAggregateType(typ) { |
|
| 6916 | 6907 | // When `undefined` appears as a stand-alone expression, |
|
| 6917 | 6908 | /// we need a stack slot for reads and writes. |
|
| 6918 | 6909 | let slot = try emitReserve(self, typ); |
|
| 6919 | - | val = il::Val::Reg(slot); |
|
| 6910 | + | set val = il::Val::Reg(slot); |
|
| 6920 | 6911 | } else { |
|
| 6921 | - | val = il::Val::Undef; |
|
| 6912 | + | set val = il::Val::Undef; |
|
| 6922 | 6913 | } |
|
| 6923 | 6914 | } |
|
| 6924 | 6915 | case ast::NodeValue::Panic { .. } => { |
|
| 6925 | 6916 | // Panic in expression context (e.g. match arm). Emit unreachable |
|
| 6926 | 6917 | // and return a dummy value since control won't continue. |
|
| 6927 | 6918 | emit(self, il::Instr::Unreachable); |
|
| 6928 | - | val = il::Val::Undef; |
|
| 6919 | + | set val = il::Val::Undef; |
|
| 6929 | 6920 | } |
|
| 6930 | 6921 | case ast::NodeValue::Assert { .. } => { |
|
| 6931 | 6922 | // Assert in expression context. Lower as statement, return `void`. |
|
| 6932 | 6923 | try lowerNode(self, node); |
|
| 6933 | - | val = il::Val::Undef; |
|
| 6924 | + | set val = il::Val::Undef; |
|
| 6934 | 6925 | } |
|
| 6935 | 6926 | case ast::NodeValue::Block(_) => { |
|
| 6936 | 6927 | try lowerBlock(self, node); |
|
| 6937 | - | val = il::Val::Undef; |
|
| 6928 | + | set val = il::Val::Undef; |
|
| 6938 | 6929 | } |
|
| 6939 | 6930 | case ast::NodeValue::ExprStmt(expr) => { |
|
| 6940 | 6931 | let _ = expr; |
|
| 6941 | - | val = il::Val::Undef; |
|
| 6932 | + | set val = il::Val::Undef; |
|
| 6942 | 6933 | } |
|
| 6943 | 6934 | // Lower these as statements. |
|
| 6944 | 6935 | case ast::NodeValue::ConstDecl(decl) => { |
|
| 6945 | 6936 | try lowerDataDecl(self.low, node, decl.value, true); |
|
| 6946 | - | val = il::Val::Undef; |
|
| 6937 | + | set val = il::Val::Undef; |
|
| 6947 | 6938 | } |
|
| 6948 | 6939 | case ast::NodeValue::StaticDecl(decl) => { |
|
| 6949 | 6940 | try lowerDataDecl(self.low, node, decl.value, false); |
|
| 6950 | - | val = il::Val::Undef; |
|
| 6941 | + | set val = il::Val::Undef; |
|
| 6951 | 6942 | } |
|
| 6952 | 6943 | case ast::NodeValue::Throw { .. }, |
|
| 6953 | 6944 | ast::NodeValue::Return { .. }, |
|
| 6954 | 6945 | ast::NodeValue::Continue, |
|
| 6955 | 6946 | ast::NodeValue::Break => { |
|
| 6956 | 6947 | try lowerNode(self, node); |
|
| 6957 | - | val = il::Val::Undef; |
|
| 6948 | + | set val = il::Val::Undef; |
|
| 6958 | 6949 | } |
|
| 6959 | 6950 | else => { |
|
| 6960 | 6951 | panic "lowerExpr: node is not an expression"; |
|
| 6961 | 6952 | } |
|
| 6962 | 6953 | } |
lib/std/lang/module.rad
+22 -22
| 121 | 121 | filePath: *[u8] |
|
| 122 | 122 | ) -> u16 throws (ModuleError) { |
|
| 123 | 123 | let m = try allocModule(graph, packageId, name, filePath); |
|
| 124 | 124 | try appendPathSegment(m, m.name); |
|
| 125 | 125 | ||
| 126 | - | m.state = ModuleState::Registered; |
|
| 126 | + | set m.state = ModuleState::Registered; |
|
| 127 | 127 | ||
| 128 | 128 | return m.id; |
|
| 129 | 129 | } |
|
| 130 | 130 | ||
| 131 | 131 | /// Register a child module. |
| 147 | 147 | return child.id; |
|
| 148 | 148 | } |
|
| 149 | 149 | // Inherit packageId from parent. |
|
| 150 | 150 | let m = try allocModule(graph, parent.packageId, name, filePath); |
|
| 151 | 151 | ||
| 152 | - | m.dirLen = dirLength(m.filePath); |
|
| 153 | - | m.state = ModuleState::Registered; |
|
| 154 | - | m.parent = parentId; |
|
| 152 | + | set m.dirLen = dirLength(m.filePath); |
|
| 153 | + | set m.state = ModuleState::Registered; |
|
| 154 | + | set m.parent = parentId; |
|
| 155 | 155 | ||
| 156 | 156 | // Inherit path prefix from parent. |
|
| 157 | 157 | for p in moduleQualifiedPath(parent) { |
|
| 158 | 158 | try appendPathSegment(m, p); |
|
| 159 | 159 | } |
| 204 | 204 | } |
|
| 205 | 205 | ||
| 206 | 206 | /// Record the parsed AST root for `id`. |
|
| 207 | 207 | export fn setAst(graph: *mut ModuleGraph, id: u16, root: *mut ast::Node) throws (ModuleError) { |
|
| 208 | 208 | let m = getMut(graph, id) else throw ModuleError::NotFound(id); |
|
| 209 | - | m.ast = root; |
|
| 210 | - | m.state = ModuleState::Parsed; |
|
| 209 | + | set m.ast = root; |
|
| 210 | + | set m.state = ModuleState::Parsed; |
|
| 211 | 211 | } |
|
| 212 | 212 | ||
| 213 | 213 | /// Set the source text for a module. |
|
| 214 | 214 | export fn setSource(graph: *mut ModuleGraph, id: u16, source: *[u8]) throws (ModuleError) { |
|
| 215 | 215 | let m = getMut(graph, id) else throw ModuleError::NotFound(id); |
|
| 216 | - | m.source = source; |
|
| 216 | + | set m.source = source; |
|
| 217 | 217 | } |
|
| 218 | 218 | ||
| 219 | 219 | /// Look up a child module by name under the given parent. |
|
| 220 | 220 | export fn findChild(graph: *ModuleGraph, name: *[u8], parentId: u16) -> ?*ModuleEntry { |
|
| 221 | 221 | assert isValidId(graph, parentId), "findChild: parent identifier is valid"; |
| 241 | 241 | // Split on '/' to extract all but the last component. |
|
| 242 | 242 | for i in 0..filePath.len { |
|
| 243 | 243 | if filePath[i] == PATH_SEP { |
|
| 244 | 244 | if i > last { |
|
| 245 | 245 | assert count < components.len, "parsePath: output slice is large enough"; |
|
| 246 | - | components[count] = &filePath[last..i]; |
|
| 247 | - | count += 1; |
|
| 246 | + | set components[count] = &filePath[last..i]; |
|
| 247 | + | set count += 1; |
|
| 248 | 248 | } |
|
| 249 | - | last = i + 1; |
|
| 249 | + | set last = i + 1; |
|
| 250 | 250 | } |
|
| 251 | 251 | } |
|
| 252 | 252 | if last >= filePath.len { |
|
| 253 | 253 | return nil; // Path ends with separator or is empty. |
|
| 254 | 254 | } |
|
| 255 | 255 | ||
| 256 | 256 | // Handle the last component by removing extension. |
|
| 257 | 257 | assert count < components.len, "parsePath: output slice is large enough"; |
|
| 258 | 258 | if let name = trimExtension(&filePath[last..]) { |
|
| 259 | - | components[count] = name; |
|
| 259 | + | set components[count] = name; |
|
| 260 | 260 | } else { |
|
| 261 | 261 | return nil; |
|
| 262 | 262 | }; |
|
| 263 | - | count += 1; |
|
| 263 | + | set count += 1; |
|
| 264 | 264 | ||
| 265 | 265 | return count; |
|
| 266 | 266 | } |
|
| 267 | 267 | ||
| 268 | 268 | /// Register a module from a file path, creating the full hierarchy as needed. |
| 306 | 306 | let mut parentId = root; |
|
| 307 | 307 | for part in &childPath[..childPath.len - 1] { |
|
| 308 | 308 | let child = findChild(graph, part, parentId) else { |
|
| 309 | 309 | throw ModuleError::MissingParent; |
|
| 310 | 310 | }; |
|
| 311 | - | parentId = child.id; |
|
| 311 | + | set parentId = child.id; |
|
| 312 | 312 | } |
|
| 313 | 313 | return try registerChild(graph, parentId, childName, filePath); |
|
| 314 | 314 | } |
|
| 315 | 315 | ||
| 316 | 316 | /// Allocate a fresh entry in the graph. |
|
| 317 | 317 | fn allocModule(graph: *mut ModuleGraph, packageId: u16, name: *[u8], filePath: *[u8]) -> *mut ModuleEntry throws (ModuleError) { |
|
| 318 | 318 | if graph.entriesLen >= graph.entries.len { |
|
| 319 | 319 | throw ModuleError::CapacityExceeded; |
|
| 320 | 320 | } |
|
| 321 | 321 | let idx = graph.entriesLen; |
|
| 322 | - | graph.entriesLen += 1; |
|
| 322 | + | set graph.entriesLen += 1; |
|
| 323 | 323 | ||
| 324 | 324 | // TODO: This is a common pattern that needs better syntax. |
|
| 325 | 325 | let m = &mut graph.entries[idx]; |
|
| 326 | - | *m = ModuleEntry { |
|
| 326 | + | set *m = ModuleEntry { |
|
| 327 | 327 | id: idx as u16, |
|
| 328 | 328 | packageId, |
|
| 329 | 329 | parent: nil, |
|
| 330 | 330 | filePath, |
|
| 331 | 331 | dirLen: 0, |
| 336 | 336 | children: undefined, |
|
| 337 | 337 | childrenLen: 0, |
|
| 338 | 338 | ast: nil, |
|
| 339 | 339 | source: nil, |
|
| 340 | 340 | }; |
|
| 341 | - | m.dirLen = dirLength(m.filePath); |
|
| 341 | + | set m.dirLen = dirLength(m.filePath); |
|
| 342 | 342 | ||
| 343 | 343 | return m; |
|
| 344 | 344 | } |
|
| 345 | 345 | ||
| 346 | 346 | /// Append a logical path segment (module identifier) to the entry. |
|
| 347 | 347 | fn appendPathSegment(entry: *mut ModuleEntry, segment: *[u8]) throws (ModuleError) { |
|
| 348 | 348 | if entry.pathDepth >= entry.path.len { |
|
| 349 | 349 | throw ModuleError::PathTooDeep; |
|
| 350 | 350 | } |
|
| 351 | - | entry.path[entry.pathDepth] = segment; |
|
| 352 | - | entry.pathDepth += 1; |
|
| 351 | + | set entry.path[entry.pathDepth] = segment; |
|
| 352 | + | set entry.pathDepth += 1; |
|
| 353 | 353 | } |
|
| 354 | 354 | ||
| 355 | 355 | /// Append a child identifier to the parent's child list. |
|
| 356 | 356 | fn addChild(parent: *mut ModuleEntry, childId: u16) -> u16 throws (ModuleError) { |
|
| 357 | 357 | if parent.childrenLen >= parent.children.len { |
|
| 358 | 358 | throw ModuleError::CapacityExceeded; |
|
| 359 | 359 | } |
|
| 360 | - | parent.children[parent.childrenLen] = childId; |
|
| 361 | - | parent.childrenLen += 1; |
|
| 360 | + | set parent.children[parent.childrenLen] = childId; |
|
| 361 | + | set parent.childrenLen += 1; |
|
| 362 | 362 | ||
| 363 | 363 | return childId; |
|
| 364 | 364 | } |
|
| 365 | 365 | ||
| 366 | 366 | /// Check if `id` points at an allocated entry. |
| 374 | 374 | return 0; |
|
| 375 | 375 | } |
|
| 376 | 376 | let mut last: i32 = -1; |
|
| 377 | 377 | for i in 0..path.len { |
|
| 378 | 378 | if path[i] == PATH_SEP { |
|
| 379 | - | last = i as i32; |
|
| 379 | + | set last = i as i32; |
|
| 380 | 380 | } |
|
| 381 | 381 | } |
|
| 382 | 382 | if last < 0 { |
|
| 383 | 383 | return 0; |
|
| 384 | 384 | } |
| 397 | 397 | /// Find the byte offset immediately following the last separator. |
|
| 398 | 398 | fn basenameStart(path: *[u8]) -> u32 { |
|
| 399 | 399 | let mut start: u32 = 0; |
|
| 400 | 400 | for i in 0..path.len { |
|
| 401 | 401 | if path[i] == PATH_SEP { |
|
| 402 | - | start = i + 1; |
|
| 402 | + | set start = i + 1; |
|
| 403 | 403 | } |
|
| 404 | 404 | } |
|
| 405 | 405 | return start; |
|
| 406 | 406 | } |
|
| 407 | 407 |
lib/std/lang/module/printer.rad
+4 -4
| 37 | 37 | let idText = formatId(a, entry.id as u32); |
|
| 38 | 38 | let path = super::moduleQualifiedPath(entry); |
|
| 39 | 39 | let mut pathBuf: *[sexpr::Expr] = &[]; |
|
| 40 | 40 | if path.len > 0 { |
|
| 41 | 41 | let buf = try! sexpr::allocExprs(a, path.len); |
|
| 42 | - | for seg, i in path { buf[i] = sexpr::sym(seg); } |
|
| 43 | - | pathBuf = buf; |
|
| 42 | + | for seg, i in path { set buf[i] = sexpr::sym(seg); } |
|
| 43 | + | set pathBuf = buf; |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | let mut childBuf: *[sexpr::Expr] = &[]; |
|
| 47 | 47 | if entry.childrenLen > 0 { |
|
| 48 | 48 | let buf = try! sexpr::allocExprs(a, entry.childrenLen); |
|
| 49 | 49 | for i in 0..entry.childrenLen { |
|
| 50 | 50 | if let child = super::get(graph, entry.children[i]) { |
|
| 51 | - | buf[i] = subtreeToExpr(a, graph, child); |
|
| 51 | + | set buf[i] = subtreeToExpr(a, graph, child); |
|
| 52 | 52 | } |
|
| 53 | 53 | } |
|
| 54 | - | childBuf = buf; |
|
| 54 | + | set childBuf = buf; |
|
| 55 | 55 | } |
|
| 56 | 56 | ||
| 57 | 57 | return sexpr::block(a, "module", &[ |
|
| 58 | 58 | sexpr::sym(entry.name), |
|
| 59 | 59 | sexpr::list(a, "id", &[sexpr::sym(idText)]), |
lib/std/lang/package.rad
+4 -4
| 24 | 24 | pkg: *mut Package, |
|
| 25 | 25 | id: u16, |
|
| 26 | 26 | name: *[u8], |
|
| 27 | 27 | pool: *mut strings::Pool |
|
| 28 | 28 | ) -> *mut Package { |
|
| 29 | - | pkg.id = id; |
|
| 30 | - | pkg.name = strings::intern(pool, name); |
|
| 31 | - | pkg.rootModuleId = nil; |
|
| 29 | + | set pkg.id = id; |
|
| 30 | + | set pkg.name = strings::intern(pool, name); |
|
| 31 | + | set pkg.rootModuleId = nil; |
|
| 32 | 32 | ||
| 33 | 33 | return pkg; |
|
| 34 | 34 | } |
|
| 35 | 35 | ||
| 36 | 36 | /// Register a module described by the file path. |
| 38 | 38 | throws (module::ModuleError) |
|
| 39 | 39 | { |
|
| 40 | 40 | let modId = try module::registerFromPath(graph, pkg.id, pkg.rootModuleId, filePath); |
|
| 41 | 41 | // First registered module becomes the root. |
|
| 42 | 42 | if pkg.rootModuleId == nil { |
|
| 43 | - | pkg.rootModuleId = modId; |
|
| 43 | + | set pkg.rootModuleId = modId; |
|
| 44 | 44 | } |
|
| 45 | 45 | return modId; |
|
| 46 | 46 | } |
lib/std/lang/parser.rad
+124 -129
| 177 | 177 | ||
| 178 | 178 | // Default to an out-of-range value so non-digits fall through to `nil`. |
|
| 179 | 179 | let mut value: u32 = 36; |
|
| 180 | 180 | ||
| 181 | 181 | if ch >= '0' and ch <= '9' { |
|
| 182 | - | value = (ch - '0') as u32; |
|
| 182 | + | set value = (ch - '0') as u32; |
|
| 183 | 183 | } else if radix > 10 { |
|
| 184 | 184 | // Mask to convert ASCII letters to uppercase. |
|
| 185 | 185 | let upper = ch & 0xDF; |
|
| 186 | 186 | if upper >= 'A' and upper <= 'Z' { |
|
| 187 | - | value = (upper - 'A') as u32 + 10; |
|
| 187 | + | set value = (upper - 'A') as u32 + 10; |
|
| 188 | 188 | } |
|
| 189 | 189 | } |
|
| 190 | 190 | if value < radix { |
|
| 191 | 191 | return value; |
|
| 192 | 192 | } |
| 207 | 207 | let mut start: u32 = 0; |
|
| 208 | 208 | let mut radix: u32 = 10; |
|
| 209 | 209 | let mut radixType = ast::Radix::Decimal; |
|
| 210 | 210 | ||
| 211 | 211 | if signed { |
|
| 212 | - | start = 1; |
|
| 212 | + | set start = 1; |
|
| 213 | 213 | if start >= text.len { |
|
| 214 | 214 | throw failParsing(p, "integer literal requires digits after sign"); |
|
| 215 | 215 | } |
|
| 216 | 216 | } |
|
| 217 | 217 | if start + 1 < text.len and text[start] == '0' { |
|
| 218 | 218 | let prefix = text[start + 1]; |
|
| 219 | 219 | if prefix == 'x' or prefix == 'X' { |
|
| 220 | - | radix = 16; |
|
| 221 | - | radixType = ast::Radix::Hex; |
|
| 222 | - | start += 2; |
|
| 220 | + | set radix = 16; |
|
| 221 | + | set radixType = ast::Radix::Hex; |
|
| 222 | + | set start += 2; |
|
| 223 | 223 | } else if prefix == 'b' or prefix == 'B' { |
|
| 224 | - | radix = 2; |
|
| 225 | - | radixType = ast::Radix::Binary; |
|
| 226 | - | start += 2; |
|
| 224 | + | set radix = 2; |
|
| 225 | + | set radixType = ast::Radix::Binary; |
|
| 226 | + | set start += 2; |
|
| 227 | 227 | } |
|
| 228 | 228 | if start >= text.len { |
|
| 229 | 229 | throw failParsing(p, "integer literal prefix must be followed by digits"); |
|
| 230 | 230 | } |
|
| 231 | 231 | } |
| 237 | 237 | throw failParsing(p, "invalid digit in integer literal"); |
|
| 238 | 238 | }; |
|
| 239 | 239 | if value > (U64_MAX / radix64) { |
|
| 240 | 240 | throw failParsing(p, "integer literal overflow"); |
|
| 241 | 241 | } |
|
| 242 | - | value *= radix64; |
|
| 242 | + | set value *= radix64; |
|
| 243 | 243 | ||
| 244 | 244 | if value > U64_MAX - (digit as u64) { |
|
| 245 | 245 | throw failParsing(p, "integer literal overflow"); |
|
| 246 | 246 | } |
|
| 247 | - | value += (digit as u64); |
|
| 247 | + | set value += (digit as u64); |
|
| 248 | 248 | } |
|
| 249 | 249 | return ast::IntLiteral { |
|
| 250 | 250 | text, magnitude: value, radix: radixType, signed, negative, |
|
| 251 | 251 | }; |
|
| 252 | 252 | } |
| 275 | 275 | let mut j: u32 = 0; |
|
| 276 | 276 | ||
| 277 | 277 | while i < raw.len { |
|
| 278 | 278 | if raw[i] == '\\' and i + 1 < raw.len { |
|
| 279 | 279 | match raw[i + 1] { |
|
| 280 | - | case 'n' => dst[j] = '\n', |
|
| 281 | - | case 't' => dst[j] = '\t', |
|
| 282 | - | case 'r' => dst[j] = '\r', |
|
| 283 | - | case '\\' => dst[j] = '\\', |
|
| 284 | - | case '"' => dst[j] = '"', |
|
| 285 | - | case '0' => dst[j] = 0, |
|
| 286 | - | else => dst[j] = raw[i + 1], |
|
| 280 | + | case 'n' => set dst[j] = '\n', |
|
| 281 | + | case 't' => set dst[j] = '\t', |
|
| 282 | + | case 'r' => set dst[j] = '\r', |
|
| 283 | + | case '\\' => set dst[j] = '\\', |
|
| 284 | + | case '"' => set dst[j] = '"', |
|
| 285 | + | case '0' => set dst[j] = 0, |
|
| 286 | + | else => set dst[j] = raw[i + 1], |
|
| 287 | 287 | } |
|
| 288 | - | i += 2; |
|
| 288 | + | set i += 2; |
|
| 289 | 289 | } else { |
|
| 290 | - | dst[j] = raw[i]; |
|
| 291 | - | i += 1; |
|
| 290 | + | set dst[j] = raw[i]; |
|
| 291 | + | set i += 1; |
|
| 292 | 292 | } |
|
| 293 | - | j += 1; |
|
| 293 | + | set j += 1; |
|
| 294 | 294 | } |
|
| 295 | 295 | return j; |
|
| 296 | 296 | } |
|
| 297 | 297 | ||
| 298 | 298 | /// Emit a single attribute node. |
| 310 | 310 | throws (ParseError) |
|
| 311 | 311 | { |
|
| 312 | 312 | try expect(p, scanner::TokenKind::LParen, "expected `(`"); |
|
| 313 | 313 | ||
| 314 | 314 | let saved = p.context; |
|
| 315 | - | p.context = Context::Normal; |
|
| 315 | + | set p.context = Context::Normal; |
|
| 316 | 316 | let expr = try parseExpr(p); |
|
| 317 | - | p.context = saved; |
|
| 317 | + | set p.context = saved; |
|
| 318 | 318 | ||
| 319 | 319 | try expect(p, scanner::TokenKind::RParen, "expected `)`"); |
|
| 320 | 320 | ||
| 321 | 321 | return expr; |
|
| 322 | 322 | } |
| 375 | 375 | let mut result = expr; |
|
| 376 | 376 | ||
| 377 | 377 | while consume(p, scanner::TokenKind::As) { |
|
| 378 | 378 | let target = try parseType(p); |
|
| 379 | 379 | ||
| 380 | - | result = node(p, ast::NodeValue::As( |
|
| 380 | + | set result = node(p, ast::NodeValue::As( |
|
| 381 | 381 | ast::As { value: result, type: target } |
|
| 382 | 382 | )); |
|
| 383 | 383 | } |
|
| 384 | 384 | return result; |
|
| 385 | 385 | } |
| 419 | 419 | ||
| 420 | 420 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 421 | 421 | // Either `..` or `..end`. |
|
| 422 | 422 | let mut endExpr: ?*ast::Node = nil; |
|
| 423 | 423 | if not check(p, scanner::TokenKind::RBracket) { |
|
| 424 | - | endExpr = try parseExpr(p); |
|
| 424 | + | set endExpr = try parseExpr(p); |
|
| 425 | 425 | } |
|
| 426 | - | index = node(p, ast::NodeValue::Range( |
|
| 426 | + | set index = node(p, ast::NodeValue::Range( |
|
| 427 | 427 | ast::Range { start: nil, end: endExpr } |
|
| 428 | 428 | )); |
|
| 429 | 429 | } else { |
|
| 430 | 430 | // Either `n`, `n..` or `n..end`. |
|
| 431 | 431 | let startExpr = try parseExpr(p); |
|
| 432 | 432 | ||
| 433 | 433 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 434 | 434 | // Either `n..` or `n..end`. |
|
| 435 | 435 | let mut endExpr: ?*ast::Node = nil; |
|
| 436 | 436 | if not check(p, scanner::TokenKind::RBracket) { |
|
| 437 | - | endExpr = try parseExpr(p); |
|
| 437 | + | set endExpr = try parseExpr(p); |
|
| 438 | 438 | } |
|
| 439 | - | index = node(p, ast::NodeValue::Range( |
|
| 439 | + | set index = node(p, ast::NodeValue::Range( |
|
| 440 | 440 | ast::Range { start: startExpr, end: endExpr } |
|
| 441 | 441 | )); |
|
| 442 | 442 | } else { |
|
| 443 | 443 | // Just `n` - regular indexing. |
|
| 444 | - | index = startExpr; |
|
| 444 | + | set index = startExpr; |
|
| 445 | 445 | } |
|
| 446 | 446 | } |
|
| 447 | 447 | try expect(p, scanner::TokenKind::RBracket, "expected `]` after array index"); |
|
| 448 | 448 | ||
| 449 | 449 | return node(p, ast::NodeValue::Subscript { container, index }); |
| 459 | 459 | match p.current.kind { |
|
| 460 | 460 | case scanner::TokenKind::Dot => { |
|
| 461 | 461 | advance(p); |
|
| 462 | 462 | ||
| 463 | 463 | let field = try parseIdent(p, "expected field name after `.`"); |
|
| 464 | - | result = node(p, ast::NodeValue::FieldAccess( |
|
| 464 | + | set result = node(p, ast::NodeValue::FieldAccess( |
|
| 465 | 465 | ast::Access { parent: result, child: field } |
|
| 466 | 466 | )); |
|
| 467 | 467 | } |
|
| 468 | 468 | case scanner::TokenKind::ColonColon => { |
|
| 469 | 469 | advance(p); |
|
| 470 | 470 | ||
| 471 | 471 | let ident = try parseIdent(p, "expected identifier after `::`"); |
|
| 472 | - | result = node(p, ast::NodeValue::ScopeAccess( |
|
| 472 | + | set result = node(p, ast::NodeValue::ScopeAccess( |
|
| 473 | 473 | ast::Access { parent: result, child: ident } |
|
| 474 | 474 | )); |
|
| 475 | 475 | } |
|
| 476 | 476 | case scanner::TokenKind::LBracket => { |
|
| 477 | - | result = try parseSubscriptOrSlice(p, result); |
|
| 477 | + | set result = try parseSubscriptOrSlice(p, result); |
|
| 478 | 478 | } |
|
| 479 | 479 | case scanner::TokenKind::LParen => { |
|
| 480 | - | result = try parseCall(p, result); |
|
| 480 | + | set result = try parseCall(p, result); |
|
| 481 | 481 | } |
|
| 482 | 482 | case scanner::TokenKind::LBrace if p.context <> Context::Condition => { |
|
| 483 | - | result = try parseRecordLit(p, result); |
|
| 483 | + | set result = try parseRecordLit(p, result); |
|
| 484 | 484 | } |
|
| 485 | 485 | else => { |
|
| 486 | 486 | break; |
|
| 487 | 487 | } |
|
| 488 | 488 | } |
| 491 | 491 | } |
|
| 492 | 492 | ||
| 493 | 493 | /// Parse a conditional expression. |
|
| 494 | 494 | export fn parseCond(p: *mut Parser) -> *ast::Node throws (ParseError) { |
|
| 495 | 495 | let saved = p.context; |
|
| 496 | - | p.context = Context::Condition; |
|
| 496 | + | set p.context = Context::Condition; |
|
| 497 | 497 | let expr = try parseExpr(p); |
|
| 498 | - | p.context = saved; |
|
| 498 | + | set p.context = saved; |
|
| 499 | 499 | ||
| 500 | 500 | return expr; |
|
| 501 | 501 | } |
|
| 502 | 502 | ||
| 503 | 503 | /// Parse unary expression followed by optional `as` cast. |
| 579 | 579 | { |
|
| 580 | 580 | let mut endExpr: ?*ast::Node = nil; |
|
| 581 | 581 | ||
| 582 | 582 | if not isRangeTerminator(p.current.kind) { |
|
| 583 | 583 | let right = try parseUnary(p); |
|
| 584 | - | endExpr = try parseBinary(p, right, -1); |
|
| 584 | + | set endExpr = try parseBinary(p, right, -1); |
|
| 585 | 585 | } |
|
| 586 | 586 | return node(p, ast::NodeValue::Range( |
|
| 587 | 587 | ast::Range { start, end: endExpr } |
|
| 588 | 588 | )); |
|
| 589 | 589 | } |
| 595 | 595 | let mut result = left; |
|
| 596 | 596 | ||
| 597 | 597 | loop { |
|
| 598 | 598 | if p.current.kind == scanner::TokenKind::DotDot { |
|
| 599 | 599 | advance(p); |
|
| 600 | - | result = try parseRangeExpr(p, result); |
|
| 600 | + | set result = try parseRangeExpr(p, result); |
|
| 601 | 601 | } else { |
|
| 602 | 602 | let opInfo = findNextOp(p.current.kind, minPrec) else break; |
|
| 603 | 603 | advance(p); |
|
| 604 | 604 | ||
| 605 | 605 | let mut right = try parseUnary(p); |
|
| 606 | 606 | ||
| 607 | 607 | while let _ = findNextOp(p.current.kind, opInfo.prec) { |
|
| 608 | - | right = try parseBinary(p, right, opInfo.prec); |
|
| 608 | + | set right = try parseBinary(p, right, opInfo.prec); |
|
| 609 | 609 | } |
|
| 610 | - | result = node(p, ast::NodeValue::BinOp(ast::BinOp { |
|
| 610 | + | set result = node(p, ast::NodeValue::BinOp(ast::BinOp { |
|
| 611 | 611 | op: opInfo.op, left: result, right, |
|
| 612 | 612 | })); |
|
| 613 | 613 | } |
|
| 614 | 614 | } |
|
| 615 | 615 | return result; |
| 630 | 630 | return true, |
|
| 631 | 631 | else => |
|
| 632 | 632 | return false, |
|
| 633 | 633 | } |
|
| 634 | 634 | } |
|
| 635 | - | ||
| 636 | 635 | /// Check if a statement requires a semicolon after it. |
|
| 637 | 636 | /// |
|
| 638 | 637 | /// Statements that end with blocks don't require semicolons. |
|
| 639 | 638 | /// All other statements do. |
|
| 640 | 639 | fn expectsSemicolon(stmt: *ast::Node) -> bool { |
| 702 | 701 | let src = p.previous.source; |
|
| 703 | 702 | let mut ch: u8 = 0; |
|
| 704 | 703 | ||
| 705 | 704 | if src[1] == '\\' { // Handle escape sequences. |
|
| 706 | 705 | match src[2] { |
|
| 707 | - | case 'n' => { ch = '\n'; } |
|
| 708 | - | case 't' => { ch = '\t'; } |
|
| 709 | - | case 'r' => { ch = '\r'; } |
|
| 710 | - | case '\'' => { ch = '\''; } |
|
| 711 | - | case '\\' => { ch = '\\'; } |
|
| 712 | - | else => { ch = src[2]; } |
|
| 706 | + | case 'n' => { set ch = '\n'; } |
|
| 707 | + | case 't' => { set ch = '\t'; } |
|
| 708 | + | case 'r' => { set ch = '\r'; } |
|
| 709 | + | case '\'' => { set ch = '\''; } |
|
| 710 | + | case '\\' => { set ch = '\\'; } |
|
| 711 | + | else => { set ch = src[2]; } |
|
| 713 | 712 | } |
|
| 714 | 713 | } else { |
|
| 715 | - | ch = src[1]; |
|
| 714 | + | set ch = src[1]; |
|
| 716 | 715 | } |
|
| 717 | 716 | return node(p, ast::NodeValue::Char(ch)); |
|
| 718 | 717 | } |
|
| 719 | 718 | case scanner::TokenKind::String => { |
|
| 720 | 719 | advance(p); |
| 773 | 772 | advance(p); |
|
| 774 | 773 | ||
| 775 | 774 | let mut kind: ast::Builtin = undefined; |
|
| 776 | 775 | // TODO: Use `match`. |
|
| 777 | 776 | if ident == "@sizeOf" { |
|
| 778 | - | kind = ast::Builtin::SizeOf; |
|
| 777 | + | set kind = ast::Builtin::SizeOf; |
|
| 779 | 778 | } else if ident == "@alignOf" { |
|
| 780 | - | kind = ast::Builtin::AlignOf; |
|
| 779 | + | set kind = ast::Builtin::AlignOf; |
|
| 781 | 780 | } else if ident == "@sliceOf" { |
|
| 782 | - | kind = ast::Builtin::SliceOf; |
|
| 781 | + | set kind = ast::Builtin::SliceOf; |
|
| 783 | 782 | } else { |
|
| 784 | 783 | throw failParsing(p, "unknown builtin"); |
|
| 785 | 784 | } |
|
| 786 | 785 | try expect(p, scanner::TokenKind::LParen, "expected `(` after builtin name"); |
|
| 787 | 786 |
| 838 | 837 | /// Parse an expression statement. |
|
| 839 | 838 | export fn parseExprStmt(p: *mut Parser) -> *ast::Node |
|
| 840 | 839 | throws (ParseError) |
|
| 841 | 840 | { |
|
| 842 | 841 | let expr = try parseExpr(p); |
|
| 842 | + | return node(p, ast::NodeValue::ExprStmt(expr)); |
|
| 843 | + | } |
|
| 843 | 844 | ||
| 845 | + | /// Parse a `set` statement assignment. |
|
| 846 | + | fn parseSetStmt(p: *mut Parser) -> *ast::Node |
|
| 847 | + | throws (ParseError) |
|
| 848 | + | { |
|
| 849 | + | let target = try parseUnary(p); |
|
| 850 | + | if not ast::isPlaceExpr(target) { |
|
| 851 | + | throw failParsing(p, "invalid assignment target"); |
|
| 852 | + | } |
|
| 844 | 853 | if consume(p, scanner::TokenKind::Equal) { |
|
| 845 | - | if not isAssignableTarget(expr) { |
|
| 846 | - | throw failParsing(p, "invalid assignment target"); |
|
| 847 | - | } |
|
| 848 | 854 | let value = try parseExpr(p); |
|
| 849 | - | ||
| 850 | 855 | return node(p, ast::NodeValue::Assign( |
|
| 851 | - | ast::Assign { left: expr, right: value } |
|
| 856 | + | ast::Assign { left: target, right: value } |
|
| 852 | 857 | )); |
|
| 853 | 858 | } |
|
| 854 | - | // Compound assignment: desugar `x <op>= y` into `x = x <op> y`. |
|
| 855 | - | // The left-hand side node is shared between the assignment target and the |
|
| 856 | - | // binary operand. This is safe because the resolver caches results by node |
|
| 857 | - | // and returns the same type on repeated visits. |
|
| 859 | + | // Compound assignment: desugar `set x <op>= y` into `set x = x <op> y`. |
|
| 860 | + | // The target node is shared with the binary operand. |
|
| 858 | 861 | if let op = tryCompoundAssignOp(p) { |
|
| 859 | - | if not isAssignableTarget(expr) { |
|
| 860 | - | throw failParsing(p, "invalid compound assignment target"); |
|
| 861 | - | } |
|
| 862 | 862 | let rhs = try parseExpr(p); |
|
| 863 | 863 | let binop = node(p, ast::NodeValue::BinOp( |
|
| 864 | - | ast::BinOp { op, left: expr, right: rhs } |
|
| 864 | + | ast::BinOp { op, left: target, right: rhs } |
|
| 865 | 865 | )); |
|
| 866 | - | ||
| 867 | 866 | return node(p, ast::NodeValue::Assign( |
|
| 868 | - | ast::Assign { left: expr, right: binop } |
|
| 867 | + | ast::Assign { left: target, right: binop } |
|
| 869 | 868 | )); |
|
| 870 | 869 | } |
|
| 871 | - | return node(p, ast::NodeValue::ExprStmt(expr)); |
|
| 870 | + | throw failParsing(p, "expected assignment after `set`"); |
|
| 872 | 871 | } |
|
| 873 | 872 | ||
| 874 | 873 | /// Parse leading attributes attached to the next declaration statement. |
|
| 875 | 874 | fn parseAttributes(p: *mut Parser) -> ?ast::Attributes { |
|
| 876 | 875 | let mut attrs = ast::nodeSlice(p.arena, 4); |
| 988 | 987 | } |
|
| 989 | 988 | return try parseLet(p, false); |
|
| 990 | 989 | } |
|
| 991 | 990 | case scanner::TokenKind::Set => { |
|
| 992 | 991 | advance(p); |
|
| 993 | - | let stmt = try parseExprStmt(p); |
|
| 994 | - | if let case ast::NodeValue::Assign(_) = stmt.value { |
|
| 995 | - | return stmt; |
|
| 996 | - | } |
|
| 997 | - | throw failParsing(p, "expected assignment after `set`"); |
|
| 992 | + | return try parseSetStmt(p); |
|
| 998 | 993 | } |
|
| 999 | 994 | case scanner::TokenKind::Constant => { |
|
| 1000 | 995 | return try parseConst(p, attrs); |
|
| 1001 | 996 | } |
|
| 1002 | 997 | case scanner::TokenKind::Static => { |
| 1112 | 1107 | fn finishSpan(p: *mut Parser, node: *mut ast::Node) { |
|
| 1113 | 1108 | let start: u32 = node.span.offset; |
|
| 1114 | 1109 | let mut end: u32 = p.previous.offset + p.previous.source.len; |
|
| 1115 | 1110 | ||
| 1116 | 1111 | if end >= start { |
|
| 1117 | - | node.span.length = end - start; |
|
| 1112 | + | set node.span.length = end - start; |
|
| 1118 | 1113 | } else { |
|
| 1119 | - | node.span.length = 0; |
|
| 1114 | + | set node.span.length = 0; |
|
| 1120 | 1115 | } |
|
| 1121 | 1116 | } |
|
| 1122 | 1117 | ||
| 1123 | 1118 | /// Save parser state for speculative parsing. |
|
| 1124 | 1119 | fn saveState(p: *Parser) -> SavedState { |
| 1130 | 1125 | } |
|
| 1131 | 1126 | ||
| 1132 | 1127 | /// Restore parser state from a snapshot, fully undoing any |
|
| 1133 | 1128 | /// side effects of a failed speculative parse. |
|
| 1134 | 1129 | fn restoreState(p: *mut Parser, s: *SavedState) { |
|
| 1135 | - | *p = s.parser; |
|
| 1130 | + | set *p = s.parser; |
|
| 1136 | 1131 | alloc::restore(&mut p.arena.arena, s.arena); |
|
| 1137 | - | p.arena.nextId = s.nextId; |
|
| 1132 | + | set p.arena.nextId = s.nextId; |
|
| 1138 | 1133 | } |
|
| 1139 | 1134 | ||
| 1140 | 1135 | /// Report a parser error. |
|
| 1141 | 1136 | fn reportError(p: *mut Parser, token: scanner::Token, message: *[u8]) { |
|
| 1142 | 1137 | assert message.len > 0; |
|
| 1143 | 1138 | ||
| 1144 | 1139 | // Ignore errors once the error list is full. |
|
| 1145 | 1140 | if p.errors.count < p.errors.list.len { |
|
| 1146 | - | p.errors.list[p.errors.count] = Error { message, token }; |
|
| 1147 | - | p.errors.count += 1; |
|
| 1141 | + | set p.errors.list[p.errors.count] = Error { message, token }; |
|
| 1142 | + | set p.errors.count += 1; |
|
| 1148 | 1143 | } |
|
| 1149 | 1144 | } |
|
| 1150 | 1145 | ||
| 1151 | 1146 | /// Fail the parsing process with the given error. |
|
| 1152 | 1147 | fn failParsing(p: *mut Parser, err: *[u8]) -> ParseError { |
| 1190 | 1185 | return p.current.kind == kind; |
|
| 1191 | 1186 | } |
|
| 1192 | 1187 | ||
| 1193 | 1188 | /// Advance the parser by one token. |
|
| 1194 | 1189 | export fn advance(p: *mut Parser) { |
|
| 1195 | - | p.previous = p.current; |
|
| 1196 | - | p.current = scanner::next(&mut p.scanner); |
|
| 1190 | + | set p.previous = p.current; |
|
| 1191 | + | set p.current = scanner::next(&mut p.scanner); |
|
| 1197 | 1192 | } |
|
| 1198 | 1193 | ||
| 1199 | 1194 | /// Parse an `if let` pattern matching statement. |
|
| 1200 | 1195 | /// |
|
| 1201 | 1196 | /// Syntax: `if let binding = scrutinee { ... }` |
| 1207 | 1202 | let mut pattern: *ast::Node = undefined; |
|
| 1208 | 1203 | let mut kind = ast::PatternKind::Binding; |
|
| 1209 | 1204 | let mut mutable = false; |
|
| 1210 | 1205 | ||
| 1211 | 1206 | if consume(p, scanner::TokenKind::Case) { |
|
| 1212 | - | pattern = try parseMatchPattern(p); |
|
| 1213 | - | kind = ast::PatternKind::Case; |
|
| 1207 | + | set pattern = try parseMatchPattern(p); |
|
| 1208 | + | set kind = ast::PatternKind::Case; |
|
| 1214 | 1209 | } else { |
|
| 1215 | - | mutable = consume(p, scanner::TokenKind::Mut); |
|
| 1216 | - | pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
|
| 1210 | + | set mutable = consume(p, scanner::TokenKind::Mut); |
|
| 1211 | + | set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
|
| 1217 | 1212 | } |
|
| 1218 | 1213 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
|
| 1219 | 1214 | ||
| 1220 | 1215 | let scrutinee = try parseCond(p); |
|
| 1221 | 1216 | let mut guard: ?*ast::Node = nil; |
|
| 1222 | 1217 | ||
| 1223 | 1218 | if consume(p, scanner::TokenKind::Semicolon) { |
|
| 1224 | - | guard = try parseCond(p); |
|
| 1219 | + | set guard = try parseCond(p); |
|
| 1225 | 1220 | } |
|
| 1226 | 1221 | let thenBranch = try parseBlock(p); |
|
| 1227 | 1222 | let mut elseBranch: ?*ast::Node = nil; |
|
| 1228 | 1223 | ||
| 1229 | 1224 | if consume(p, scanner::TokenKind::Else) { |
|
| 1230 | 1225 | if check(p, scanner::TokenKind::If) { |
|
| 1231 | - | elseBranch = node(p, ast::NodeValue::Block( |
|
| 1226 | + | set elseBranch = node(p, ast::NodeValue::Block( |
|
| 1232 | 1227 | mkBlockWith(p, try parseIf(p)) |
|
| 1233 | 1228 | )); |
|
| 1234 | 1229 | } else { |
|
| 1235 | - | elseBranch = try parseBlock(p); |
|
| 1230 | + | set elseBranch = try parseBlock(p); |
|
| 1236 | 1231 | } |
|
| 1237 | 1232 | } |
|
| 1238 | 1233 | ||
| 1239 | 1234 | return node(p, ast::NodeValue::IfLet(ast::IfLet { |
|
| 1240 | 1235 | pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable }, |
| 1252 | 1247 | // Parse pattern: either `case <pattern>`, `mut <ident>`, or simple `<ident>`. |
|
| 1253 | 1248 | let mut pattern: *ast::Node = undefined; |
|
| 1254 | 1249 | let mut kind = ast::PatternKind::Binding; |
|
| 1255 | 1250 | let mut mutable = false; |
|
| 1256 | 1251 | if consume(p, scanner::TokenKind::Case) { |
|
| 1257 | - | pattern = try parseMatchPattern(p); |
|
| 1258 | - | kind = ast::PatternKind::Case; |
|
| 1252 | + | set pattern = try parseMatchPattern(p); |
|
| 1253 | + | set kind = ast::PatternKind::Case; |
|
| 1259 | 1254 | } else { |
|
| 1260 | - | mutable = consume(p, scanner::TokenKind::Mut); |
|
| 1261 | - | pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
|
| 1255 | + | set mutable = consume(p, scanner::TokenKind::Mut); |
|
| 1256 | + | set pattern = try parseIdentOrPlaceholder(p, "expected `case`, `mut`, or identifier after `let`"); |
|
| 1262 | 1257 | } |
|
| 1263 | 1258 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
|
| 1264 | 1259 | ||
| 1265 | 1260 | let scrutinee = try parseCond(p); |
|
| 1266 | 1261 | let mut guard: ?*ast::Node = nil; |
|
| 1267 | 1262 | ||
| 1268 | 1263 | if consume(p, scanner::TokenKind::Semicolon) { |
|
| 1269 | - | guard = try parseCond(p); |
|
| 1264 | + | set guard = try parseCond(p); |
|
| 1270 | 1265 | } |
|
| 1271 | 1266 | let body = try parseBlock(p); |
|
| 1272 | 1267 | let mut elseBranch: ?*ast::Node = nil; |
|
| 1273 | 1268 | ||
| 1274 | 1269 | if consume(p, scanner::TokenKind::Else) { |
|
| 1275 | - | elseBranch = try parseBlock(p); |
|
| 1270 | + | set elseBranch = try parseBlock(p); |
|
| 1276 | 1271 | } |
|
| 1277 | 1272 | return node(p, ast::NodeValue::WhileLet(ast::WhileLet { |
|
| 1278 | 1273 | pattern: ast::PatternMatch { pattern, scrutinee, guard, kind, mutable }, |
|
| 1279 | 1274 | body, |
|
| 1280 | 1275 | elseBranch, |
| 1294 | 1289 | let condition = try parseCond(p); |
|
| 1295 | 1290 | let body = try parseBlock(p); |
|
| 1296 | 1291 | let mut elseBranch: ?*ast::Node = nil; |
|
| 1297 | 1292 | ||
| 1298 | 1293 | if consume(p, scanner::TokenKind::Else) { |
|
| 1299 | - | elseBranch = try parseBlock(p); |
|
| 1294 | + | set elseBranch = try parseBlock(p); |
|
| 1300 | 1295 | } |
|
| 1301 | 1296 | return node(p, ast::NodeValue::While(ast::While { |
|
| 1302 | 1297 | condition, body, elseBranch, |
|
| 1303 | 1298 | })); |
|
| 1304 | 1299 | } |
| 1321 | 1316 | ||
| 1322 | 1317 | let binding = try parseIdentOrPlaceholder(p, "expected identifier or `_`"); |
|
| 1323 | 1318 | let mut index: ?*ast::Node = nil; |
|
| 1324 | 1319 | ||
| 1325 | 1320 | if consume(p, scanner::TokenKind::Comma) { |
|
| 1326 | - | index = try parseIdentOrPlaceholder(p, "expected index identifier or `_` after `,`"); |
|
| 1321 | + | set index = try parseIdentOrPlaceholder(p, "expected index identifier or `_` after `,`"); |
|
| 1327 | 1322 | } |
|
| 1328 | 1323 | try expect(p, scanner::TokenKind::In, "expected `in`"); |
|
| 1329 | 1324 | ||
| 1330 | 1325 | let iterable = try parseCond(p); |
|
| 1331 | 1326 | let body = try parseBlock(p); |
|
| 1332 | 1327 | let mut elseBranch: ?*ast::Node = nil; |
|
| 1333 | 1328 | ||
| 1334 | 1329 | if consume(p, scanner::TokenKind::Else) { |
|
| 1335 | - | elseBranch = try parseBlock(p); |
|
| 1330 | + | set elseBranch = try parseBlock(p); |
|
| 1336 | 1331 | } |
|
| 1337 | 1332 | return node(p, ast::NodeValue::For(ast::For { |
|
| 1338 | 1333 | binding, index, iterable, body, elseBranch, |
|
| 1339 | 1334 | })); |
|
| 1340 | 1335 | } |
| 1397 | 1392 | try expect(p, scanner::TokenKind::Assert, "expected `assert`"); |
|
| 1398 | 1393 | ||
| 1399 | 1394 | // `assert { expr }` block form or `assert <expr>`. |
|
| 1400 | 1395 | let mut condition: *ast::Node = undefined; |
|
| 1401 | 1396 | if consume(p, scanner::TokenKind::LBrace) { |
|
| 1402 | - | condition = try parseExpr(p); |
|
| 1397 | + | set condition = try parseExpr(p); |
|
| 1403 | 1398 | try expect(p, scanner::TokenKind::RBrace, "expected closing `}` after expression"); |
|
| 1404 | 1399 | } else { |
|
| 1405 | - | condition = try parseExpr(p); |
|
| 1400 | + | set condition = try parseExpr(p); |
|
| 1406 | 1401 | } |
|
| 1407 | 1402 | let mut message: ?*ast::Node = nil; |
|
| 1408 | 1403 | if consume(p, scanner::TokenKind::Comma) { |
|
| 1409 | - | message = try parseExpr(p); |
|
| 1404 | + | set message = try parseExpr(p); |
|
| 1410 | 1405 | } |
|
| 1411 | 1406 | return node(p, ast::NodeValue::Assert { condition, message }); |
|
| 1412 | 1407 | } |
|
| 1413 | 1408 | ||
| 1414 | 1409 | /// Parse a `try` expression with optional `catch` clause(s). |
| 1427 | 1422 | let mut typeNode: ?*ast::Node = nil; |
|
| 1428 | 1423 | ||
| 1429 | 1424 | // Check for optional error binding: `catch ident { ... }` or |
|
| 1430 | 1425 | // `catch ident as Type { ... }`. |
|
| 1431 | 1426 | if check(p, scanner::TokenKind::Ident) { |
|
| 1432 | - | binding = try parseIdent(p, "expected identifier after `catch`"); |
|
| 1427 | + | set binding = try parseIdent(p, "expected identifier after `catch`"); |
|
| 1433 | 1428 | if consume(p, scanner::TokenKind::As) { |
|
| 1434 | - | typeNode = try parseType(p); |
|
| 1429 | + | set typeNode = try parseType(p); |
|
| 1435 | 1430 | } |
|
| 1436 | 1431 | } |
|
| 1437 | 1432 | if not check(p, scanner::TokenKind::LBrace) { |
|
| 1438 | 1433 | throw failParsing(p, "expected `{` after `catch`"); |
|
| 1439 | 1434 | } |
| 1499 | 1494 | ||
| 1500 | 1495 | if consume(p, scanner::TokenKind::Else) { |
|
| 1501 | 1496 | // Check for `else if` construct. |
|
| 1502 | 1497 | if check(p, scanner::TokenKind::If) { |
|
| 1503 | 1498 | // Set the else branch to a block containing the nested if. |
|
| 1504 | - | elseBranch = node(p, ast::NodeValue::Block( |
|
| 1499 | + | set elseBranch = node(p, ast::NodeValue::Block( |
|
| 1505 | 1500 | mkBlockWith(p, try parseIf(p)) |
|
| 1506 | 1501 | )); |
|
| 1507 | 1502 | } else { |
|
| 1508 | 1503 | // Regular else clause. |
|
| 1509 | - | elseBranch = try parseBlock(p); |
|
| 1504 | + | set elseBranch = try parseBlock(p); |
|
| 1510 | 1505 | } |
|
| 1511 | 1506 | } |
|
| 1512 | 1507 | return node(p, ast::NodeValue::If(ast::If { |
|
| 1513 | 1508 | condition: cond, thenBranch, elseBranch, |
|
| 1514 | 1509 | })); |
| 1559 | 1554 | if check(p, scanner::TokenKind::Case) or check(p, scanner::TokenKind::Else) { |
|
| 1560 | 1555 | throw failParsing(p, "unexpected keyword after `,` in case pattern list"); |
|
| 1561 | 1556 | } |
|
| 1562 | 1557 | } |
|
| 1563 | 1558 | if consume(p, scanner::TokenKind::If) { |
|
| 1564 | - | guard = try parseCond(p); |
|
| 1559 | + | set guard = try parseCond(p); |
|
| 1565 | 1560 | } |
|
| 1566 | 1561 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after case pattern"); |
|
| 1567 | 1562 | let body = try parseStmt(p); |
|
| 1568 | 1563 | ||
| 1569 | 1564 | return node(p, ast::NodeValue::MatchProng( |
| 1571 | 1566 | )); |
|
| 1572 | 1567 | } |
|
| 1573 | 1568 | // Else prong: `else if <guard> => <body>`. |
|
| 1574 | 1569 | if consume(p, scanner::TokenKind::Else) { |
|
| 1575 | 1570 | if consume(p, scanner::TokenKind::If) { |
|
| 1576 | - | guard = try parseCond(p); |
|
| 1571 | + | set guard = try parseCond(p); |
|
| 1577 | 1572 | } |
|
| 1578 | 1573 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after else"); |
|
| 1579 | 1574 | let body = try parseStmt(p); |
|
| 1580 | 1575 | ||
| 1581 | 1576 | return node(p, ast::NodeValue::MatchProng( |
| 1584 | 1579 | } |
|
| 1585 | 1580 | // Binding prong: `<ident> if <guard> => <body>` or `_ if <guard> => <body>`. |
|
| 1586 | 1581 | let binding = try parseIdentOrPlaceholder(p, "expected `case`, `else`, or identifier"); |
|
| 1587 | 1582 | ||
| 1588 | 1583 | if consume(p, scanner::TokenKind::If) { |
|
| 1589 | - | guard = try parseCond(p); |
|
| 1584 | + | set guard = try parseCond(p); |
|
| 1590 | 1585 | } |
|
| 1591 | 1586 | try expect(p, scanner::TokenKind::FatArrow, "expected `=>` after binding"); |
|
| 1592 | 1587 | let body = try parseStmt(p); |
|
| 1593 | 1588 | ||
| 1594 | 1589 | return node(p, ast::NodeValue::MatchProng( |
| 1600 | 1595 | /// Uses `Pattern` context to allow record literals but not conditional expressions. |
|
| 1601 | 1596 | fn parseMatchPattern(p: *mut Parser) -> *ast::Node |
|
| 1602 | 1597 | throws (ParseError) |
|
| 1603 | 1598 | { |
|
| 1604 | 1599 | let saved = p.context; |
|
| 1605 | - | p.context = Context::Pattern; |
|
| 1600 | + | set p.context = Context::Pattern; |
|
| 1606 | 1601 | let pattern = try parseExpr(p); |
|
| 1607 | - | p.context = saved; |
|
| 1602 | + | set p.context = saved; |
|
| 1608 | 1603 | ||
| 1609 | 1604 | return pattern; |
|
| 1610 | 1605 | } |
|
| 1611 | 1606 | ||
| 1612 | 1607 | /// Parse an identifier. |
| 1666 | 1661 | throw failParsing(p, "record fields cannot specify alignment"); |
|
| 1667 | 1662 | } |
|
| 1668 | 1663 | if field.value <> nil and mode <> RecordFieldMode::Labeled { |
|
| 1669 | 1664 | throw failParsing(p, "record fields cannot have initializers"); |
|
| 1670 | 1665 | } |
|
| 1671 | - | recordField = ast::NodeValue::RecordField { |
|
| 1666 | + | set recordField = ast::NodeValue::RecordField { |
|
| 1672 | 1667 | field: field.name, type, value: field.value, |
|
| 1673 | 1668 | }; |
|
| 1674 | 1669 | } |
|
| 1675 | 1670 | case RecordFieldMode::Unlabeled => { |
|
| 1676 | 1671 | let type = try parseType(p); |
|
| 1677 | - | recordField = ast::NodeValue::RecordField { |
|
| 1672 | + | set recordField = ast::NodeValue::RecordField { |
|
| 1678 | 1673 | field: nil, type, value: nil, |
|
| 1679 | 1674 | }; |
|
| 1680 | 1675 | } |
|
| 1681 | 1676 | } |
|
| 1682 | 1677 | fields.append(node(p, recordField), p.allocator); |
| 1738 | 1733 | try expect(p, scanner::TokenKind::LBrace, "expected `{` to begin record literal"); |
|
| 1739 | 1734 | ||
| 1740 | 1735 | while not check(p, scanner::TokenKind::RBrace) { |
|
| 1741 | 1736 | // Check for `..` to ignore remaining fields. |
|
| 1742 | 1737 | if consume(p, scanner::TokenKind::DotDot) { |
|
| 1743 | - | ignoreRest = true; |
|
| 1738 | + | set ignoreRest = true; |
|
| 1744 | 1739 | break; |
|
| 1745 | 1740 | } |
|
| 1746 | 1741 | let field = try parseRecordLitField(p); |
|
| 1747 | 1742 | fields.append(field, p.allocator); |
|
| 1748 | 1743 |
| 1803 | 1798 | let mut payloadType: ?*ast::Node = nil; |
|
| 1804 | 1799 | let mut explicitValue: ?*ast::Node = nil; |
|
| 1805 | 1800 | ||
| 1806 | 1801 | if consume(p, scanner::TokenKind::LParen) { // `Variant(T, U)`. |
|
| 1807 | 1802 | let fields = try parseRecordFields(p, RecordFieldMode::Unlabeled); |
|
| 1808 | - | payloadType = node(p, ast::NodeValue::TypeSig( |
|
| 1803 | + | set payloadType = node(p, ast::NodeValue::TypeSig( |
|
| 1809 | 1804 | ast::TypeSig::Record { fields, labeled: false } |
|
| 1810 | 1805 | )); |
|
| 1811 | 1806 | } else if consume(p, scanner::TokenKind::LBrace) { // `Variant { x: T, y: T }`. |
|
| 1812 | 1807 | let fields = try parseRecordFields(p, RecordFieldMode::Labeled); |
|
| 1813 | - | payloadType = node(p, ast::NodeValue::TypeSig( |
|
| 1808 | + | set payloadType = node(p, ast::NodeValue::TypeSig( |
|
| 1814 | 1809 | ast::TypeSig::Record { fields, labeled: true } |
|
| 1815 | 1810 | )); |
|
| 1816 | 1811 | } else if consume(p, scanner::TokenKind::Equal) { |
|
| 1817 | 1812 | // TODO: Support constant expressions. |
|
| 1818 | 1813 | try expect(p, scanner::TokenKind::Number, "expected integer literal after `=`"); |
|
| 1819 | 1814 | let literal = try parseIntLiteral(p, p.previous.source); |
|
| 1820 | - | explicitValue = nodeNumber(p, literal); |
|
| 1815 | + | set explicitValue = nodeNumber(p, literal); |
|
| 1821 | 1816 | } |
|
| 1822 | 1817 | ||
| 1823 | 1818 | let variant = node(p, ast::NodeValue::UnionDeclVariant( |
|
| 1824 | 1819 | ast::UnionDeclVariant { |
|
| 1825 | 1820 | name: variantName, index: variants.len as u32, value: explicitValue, type: payloadType, |
| 1878 | 1873 | parseType |
|
| 1879 | 1874 | ); |
|
| 1880 | 1875 | let mut returnType: ?*ast::Node = nil; |
|
| 1881 | 1876 | ||
| 1882 | 1877 | if consume(p, scanner::TokenKind::Arrow) { |
|
| 1883 | - | returnType = try parseType(p); |
|
| 1878 | + | set returnType = try parseType(p); |
|
| 1884 | 1879 | } |
|
| 1885 | 1880 | let throwList = try parseThrowList(p); |
|
| 1886 | 1881 | let sig = ast::FnSig { params, returnType, throwList }; |
|
| 1887 | 1882 | return node(p, ast::NodeValue::TypeSig( |
|
| 1888 | 1883 | ast::TypeSig::Fn(sig) |
| 1906 | 1901 | } |
|
| 1907 | 1902 | try expect(p, scanner::TokenKind::RParen, "expected `)` after function parameters"); |
|
| 1908 | 1903 | ||
| 1909 | 1904 | let mut returnType: ?*ast::Node = nil; |
|
| 1910 | 1905 | if consume(p, scanner::TokenKind::Arrow) { |
|
| 1911 | - | returnType = try parseType(p); |
|
| 1906 | + | set returnType = try parseType(p); |
|
| 1912 | 1907 | } |
|
| 1913 | 1908 | let throwList = try parseThrowList(p); |
|
| 1914 | 1909 | ||
| 1915 | 1910 | return ast::FnSig { params, returnType, throwList }; |
|
| 1916 | 1911 | } |
| 1940 | 1935 | list.append(a.list[i], p.allocator); |
|
| 1941 | 1936 | } |
|
| 1942 | 1937 | } |
|
| 1943 | 1938 | let attrNode = nodeAttribute(p, ast::Attribute::Extern); |
|
| 1944 | 1939 | list.append(attrNode, p.allocator); |
|
| 1945 | - | fnAttrs = ast::Attributes { list }; |
|
| 1940 | + | set fnAttrs = ast::Attributes { list }; |
|
| 1946 | 1941 | } |
|
| 1947 | 1942 | } else { |
|
| 1948 | - | body = try parseBlock(p); |
|
| 1943 | + | set body = try parseBlock(p); |
|
| 1949 | 1944 | } |
|
| 1950 | 1945 | return node(p, ast::NodeValue::FnDecl( |
|
| 1951 | 1946 | ast::FnDecl { name, sig, body, attrs: fnAttrs } |
|
| 1952 | 1947 | )); |
|
| 1953 | 1948 | } |
| 2012 | 2007 | throws (ParseError) |
|
| 2013 | 2008 | { |
|
| 2014 | 2009 | let mut path: *ast::Node = undefined; |
|
| 2015 | 2010 | if p.current.kind == scanner::TokenKind::Super { |
|
| 2016 | 2011 | advance(p); |
|
| 2017 | - | path = nodeSuper(p); |
|
| 2012 | + | set path = nodeSuper(p); |
|
| 2018 | 2013 | } else { |
|
| 2019 | - | path = try parseIdent(p, "expected type identifier"); |
|
| 2014 | + | set path = try parseIdent(p, "expected type identifier"); |
|
| 2020 | 2015 | } |
|
| 2021 | 2016 | while consume(p, scanner::TokenKind::ColonColon) { |
|
| 2022 | 2017 | let part = try parseIdent(p, "expected identifier after `::`"); |
|
| 2023 | - | path = node(p, ast::NodeValue::ScopeAccess( |
|
| 2018 | + | set path = node(p, ast::NodeValue::ScopeAccess( |
|
| 2024 | 2019 | ast::Access { parent: path, child: part } |
|
| 2025 | 2020 | )); |
|
| 2026 | 2021 | } |
|
| 2027 | 2022 | return path; |
|
| 2028 | 2023 | } |
| 2113 | 2108 | let mut type: ?*ast::Node = nil; |
|
| 2114 | 2109 | let mut alignment: ?*ast::Node = nil; |
|
| 2115 | 2110 | let mut value: ?*ast::Node = nil; |
|
| 2116 | 2111 | ||
| 2117 | 2112 | if consume(p, scanner::TokenKind::Colon) { |
|
| 2118 | - | type = try parseType(p); |
|
| 2113 | + | set type = try parseType(p); |
|
| 2119 | 2114 | ||
| 2120 | 2115 | if check(p, scanner::TokenKind::Align) { |
|
| 2121 | - | alignment = try parseAlign(p); |
|
| 2116 | + | set alignment = try parseAlign(p); |
|
| 2122 | 2117 | } |
|
| 2123 | 2118 | } |
|
| 2124 | 2119 | if consume(p, scanner::TokenKind::Equal) { |
|
| 2125 | - | value = try parseExpr(p); |
|
| 2120 | + | set value = try parseExpr(p); |
|
| 2126 | 2121 | } |
|
| 2127 | 2122 | return NameTypeValue { name, type, value, alignment }; |
|
| 2128 | 2123 | } |
|
| 2129 | 2124 | ||
| 2130 | 2125 | /// Parse a constant declaration. |
| 2172 | 2167 | try expect(p, scanner::TokenKind::Use, "expected `use`"); |
|
| 2173 | 2168 | ||
| 2174 | 2169 | // Allow `super` or identifier as the first part of the path. |
|
| 2175 | 2170 | let mut path: *ast::Node = undefined; |
|
| 2176 | 2171 | if consume(p, scanner::TokenKind::Super) { |
|
| 2177 | - | path = nodeSuper(p); |
|
| 2172 | + | set path = nodeSuper(p); |
|
| 2178 | 2173 | } else { |
|
| 2179 | - | path = try parseIdent(p, "expected module name or `super` after `use`"); |
|
| 2174 | + | set path = try parseIdent(p, "expected module name or `super` after `use`"); |
|
| 2180 | 2175 | } |
|
| 2181 | 2176 | while consume(p, scanner::TokenKind::ColonColon) { |
|
| 2182 | 2177 | // Check for wildcard import (e.g., `use parser::*`) |
|
| 2183 | 2178 | if consume(p, scanner::TokenKind::Star) { |
|
| 2184 | 2179 | return node(p, ast::NodeValue::Use( |
|
| 2185 | 2180 | ast::Use { path, wildcard: true, attrs } |
|
| 2186 | 2181 | )); |
|
| 2187 | 2182 | } |
|
| 2188 | 2183 | let part = try parseIdent(p, "expected identifier or `*` after `::`"); |
|
| 2189 | - | path = node(p, ast::NodeValue::ScopeAccess( |
|
| 2184 | + | set path = node(p, ast::NodeValue::ScopeAccess( |
|
| 2190 | 2185 | ast::Access { parent: path, child: part } |
|
| 2191 | 2186 | )); |
|
| 2192 | 2187 | } |
|
| 2193 | 2188 | return node(p, ast::NodeValue::Use( |
|
| 2194 | 2189 | ast::Use { path, wildcard: false, attrs } |
| 2219 | 2214 | try expect(p, scanner::TokenKind::Equal, "expected `=` after pattern"); |
|
| 2220 | 2215 | let expr = try parseCond(p); |
|
| 2221 | 2216 | ||
| 2222 | 2217 | let mut guard: ?*ast::Node = nil; |
|
| 2223 | 2218 | if consume(p, scanner::TokenKind::If) { |
|
| 2224 | - | guard = try parseCond(p); |
|
| 2219 | + | set guard = try parseCond(p); |
|
| 2225 | 2220 | } |
|
| 2226 | 2221 | ||
| 2227 | 2222 | try expect(p, scanner::TokenKind::Else, "expected `else` after pattern"); |
|
| 2228 | 2223 | let elseBranch = try parseLetElseBranch(p); |
|
| 2229 | 2224 |
lib/std/lang/parser/tests.rad
+22 -4
| 2186 | 2186 | } |
|
| 2187 | 2187 | ||
| 2188 | 2188 | /// Test parsing assignment expressions. |
|
| 2189 | 2189 | @test fn testParseAssignment() throws (testing::TestError) { |
|
| 2190 | 2190 | { |
|
| 2191 | - | let assign = try! parseStmtStr("x = 1;"); |
|
| 2191 | + | let assign = try! parseStmtStr("set x = 1;"); |
|
| 2192 | 2192 | let case ast::NodeValue::Assign(node) = assign.value |
|
| 2193 | 2193 | else throw testing::TestError::Failed; |
|
| 2194 | 2194 | try expectIdent(node.left, "x"); |
|
| 2195 | 2195 | let case ast::NodeValue::Number(_) = node.right.value |
|
| 2196 | 2196 | else throw testing::TestError::Failed; |
|
| 2197 | 2197 | } |
|
| 2198 | 2198 | { |
|
| 2199 | - | let assign = try! parseStmtStr("obj.field = value;"); |
|
| 2199 | + | let assign = try! parseStmtStr("set obj.field = value;"); |
|
| 2200 | 2200 | let case ast::NodeValue::Assign(node) = assign.value |
|
| 2201 | 2201 | else throw testing::TestError::Failed; |
|
| 2202 | 2202 | let case ast::NodeValue::FieldAccess(access) = node.left.value |
|
| 2203 | 2203 | else throw testing::TestError::Failed; |
|
| 2204 | 2204 | try expectIdent(access.parent, "obj"); |
|
| 2205 | 2205 | try expectIdent(access.child, "field"); |
|
| 2206 | 2206 | try expectIdent(node.right, "value"); |
|
| 2207 | 2207 | } |
|
| 2208 | 2208 | { |
|
| 2209 | - | let assign = try! parseStmtStr("*ptr = rhs;"); |
|
| 2209 | + | let assign = try! parseStmtStr("set *ptr = rhs;"); |
|
| 2210 | 2210 | let case ast::NodeValue::Assign(node) = assign.value |
|
| 2211 | 2211 | else throw testing::TestError::Failed; |
|
| 2212 | 2212 | let case ast::NodeValue::Deref(target) = node.left.value |
|
| 2213 | 2213 | else throw testing::TestError::Failed; |
|
| 2214 | 2214 | try expectIdent(target, "ptr"); |
|
| 2215 | 2215 | try expectIdent(node.right, "rhs"); |
|
| 2216 | 2216 | } |
|
| 2217 | 2217 | { |
|
| 2218 | - | let assign = try! parseStmtStr("x = 1 + 2;"); |
|
| 2218 | + | let assign = try! parseStmtStr("set x = 1 + 2;"); |
|
| 2219 | 2219 | let case ast::NodeValue::Assign(node) = assign.value |
|
| 2220 | 2220 | else throw testing::TestError::Failed; |
|
| 2221 | 2221 | let case ast::NodeValue::BinOp(bin) = node.right.value |
|
| 2222 | 2222 | else throw testing::TestError::Failed; |
|
| 2223 | 2223 | try testing::expect(bin.op == ast::BinaryOp::Add); |
| 2231 | 2231 | try expectIdent(access.parent, "module"); |
|
| 2232 | 2232 | try expectIdent(access.child, "VAR"); |
|
| 2233 | 2233 | } |
|
| 2234 | 2234 | } |
|
| 2235 | 2235 | ||
| 2236 | + | /// Test that assignment syntax requires the `set` statement. |
|
| 2237 | + | @test fn testAssignmentRequiresSetKeyword() throws (testing::TestError) { |
|
| 2238 | + | let assign: ?*ast::Node = try? parseStmtStr("x = 1;"); |
|
| 2239 | + | try testing::expect(assign == nil); |
|
| 2240 | + | ||
| 2241 | + | let compoundAssign: ?*ast::Node = try? parseStmtStr("x += 1;"); |
|
| 2242 | + | try testing::expect(compoundAssign == nil); |
|
| 2243 | + | } |
|
| 2244 | + | ||
| 2245 | + | /// Test that `set` requires an assignable target. |
|
| 2246 | + | @test fn testSetRequiresAssignableTarget() throws (testing::TestError) { |
|
| 2247 | + | let binTarget: ?*ast::Node = try? parseStmtStr("set x + y = 1;"); |
|
| 2248 | + | try testing::expect(binTarget == nil); |
|
| 2249 | + | ||
| 2250 | + | let condTarget: ?*ast::Node = try? parseStmtStr("set x if ok else y = 1;"); |
|
| 2251 | + | try testing::expect(condTarget == nil); |
|
| 2252 | + | } |
|
| 2253 | + | ||
| 2236 | 2254 | /// Test parsing basic arithmetic binary operators (+, -, *, /, %). |
|
| 2237 | 2255 | @test fn testParseBinOpArithmetic() throws (testing::TestError) { |
|
| 2238 | 2256 | let add = try! parseExprStr("a + b"); |
|
| 2239 | 2257 | let case ast::NodeValue::BinOp(op1) = add.value |
|
| 2240 | 2258 | else throw testing::TestError::Failed; |
lib/std/lang/resolver.rad
+176 -176
| 789 | 789 | let mut cursor = self.types; |
|
| 790 | 790 | while let node = cursor { |
|
| 791 | 791 | if node.ty == ty { |
|
| 792 | 792 | return &node.ty; |
|
| 793 | 793 | } |
|
| 794 | - | cursor = node.next; |
|
| 794 | + | set cursor = node.next; |
|
| 795 | 795 | } |
|
| 796 | 796 | // Allocate a new type node from the arena. |
|
| 797 | 797 | let node = try! alloc::alloc( |
|
| 798 | 798 | &mut self.arena, @sizeOf(TypeNode), @alignOf(TypeNode) |
|
| 799 | 799 | ) as *mut TypeNode; |
|
| 800 | 800 | ||
| 801 | - | *node = TypeNode { ty, next: self.types }; |
|
| 802 | - | self.types = node; |
|
| 801 | + | set *node = TypeNode { ty, next: self.types }; |
|
| 802 | + | set self.types = node; |
|
| 803 | 803 | ||
| 804 | 804 | return &node.ty; |
|
| 805 | 805 | } |
|
| 806 | 806 | ||
| 807 | 807 | /// Allocate a nominal type descriptor and return a pointer to it. |
| 811 | 811 | // placeholder entries when binding symbols. |
|
| 812 | 812 | let entry = try! alloc::alloc( |
|
| 813 | 813 | &mut self.arena, @sizeOf(NominalType), @alignOf(NominalType) |
|
| 814 | 814 | ) as *mut NominalType; |
|
| 815 | 815 | ||
| 816 | - | *entry = info; |
|
| 816 | + | set *entry = info; |
|
| 817 | 817 | ||
| 818 | 818 | return entry; |
|
| 819 | 819 | } |
|
| 820 | 820 | ||
| 821 | 821 | /// Allocate a function type descriptor and return a pointer to it. |
|
| 822 | 822 | fn allocFnType(self: *mut Resolver, info: FnType) -> *FnType { |
|
| 823 | 823 | let entry = try! alloc::alloc( |
|
| 824 | 824 | &mut self.arena, @sizeOf(FnType), @alignOf(FnType) |
|
| 825 | 825 | ) as *mut FnType; |
|
| 826 | 826 | ||
| 827 | - | *entry = info; |
|
| 827 | + | set *entry = info; |
|
| 828 | 828 | ||
| 829 | 829 | return entry; |
|
| 830 | 830 | } |
|
| 831 | 831 | ||
| 832 | 832 | /// Returns an error, if any, associated with the given node. |
| 870 | 870 | &mut arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), MAX_MODULE_SYMBOLS |
|
| 871 | 871 | ) as *mut [*mut Symbol]; |
|
| 872 | 872 | ||
| 873 | 873 | // Initialize the root scope. |
|
| 874 | 874 | // TODO: Set this up when declaring `PKG_SCOPE`, not here. |
|
| 875 | - | *storage.pkgScope = Scope { |
|
| 875 | + | set *storage.pkgScope = Scope { |
|
| 876 | 876 | owner: nil, |
|
| 877 | 877 | parent: nil, |
|
| 878 | 878 | moduleId: nil, |
|
| 879 | 879 | symbols, |
|
| 880 | 880 | symbolsLen: 0, |
|
| 881 | 881 | }; |
|
| 882 | 882 | ||
| 883 | 883 | // Clear all node semantic metadata to sentinel values. |
|
| 884 | 884 | // TODO: Use array repeat literal? |
|
| 885 | 885 | for i in 0..storage.nodeData.len { |
|
| 886 | - | storage.nodeData[i] = NodeData { |
|
| 886 | + | set storage.nodeData[i] = NodeData { |
|
| 887 | 887 | ty: Type::Unknown, |
|
| 888 | 888 | coercion: Coercion::Identity, |
|
| 889 | 889 | sym: nil, |
|
| 890 | 890 | constValue: nil, |
|
| 891 | 891 | scope: nil, |
| 894 | 894 | } |
|
| 895 | 895 | ||
| 896 | 896 | let mut moduleScopes: [?*mut Scope; module::MAX_MODULES] = undefined; |
|
| 897 | 897 | // TODO: Simplify. |
|
| 898 | 898 | for i in 0..moduleScopes.len { |
|
| 899 | - | moduleScopes[i] = nil; |
|
| 899 | + | set moduleScopes[i] = nil; |
|
| 900 | 900 | } |
|
| 901 | 901 | return Resolver { |
|
| 902 | 902 | scope: storage.pkgScope, |
|
| 903 | 903 | pkgScope: storage.pkgScope, |
|
| 904 | 904 | loopStack: undefined, |
| 942 | 942 | // Don't record more than one error per node. |
|
| 943 | 943 | if let n = node; errorForNode(self, n) <> nil { |
|
| 944 | 944 | return ResolveError::Failure; |
|
| 945 | 945 | } |
|
| 946 | 946 | let idx = self.errors.len; |
|
| 947 | - | self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap); |
|
| 948 | - | self.errors[idx] = Error { kind, node, moduleId: self.currentMod }; |
|
| 947 | + | set self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap); |
|
| 948 | + | set self.errors[idx] = Error { kind, node, moduleId: self.currentMod }; |
|
| 949 | 949 | ||
| 950 | 950 | return ResolveError::Failure; |
|
| 951 | 951 | } |
|
| 952 | 952 | ||
| 953 | 953 | /// Like [`emitError`], but for type mismatches specifically. |
| 969 | 969 | // Allocate symbols from the arena. |
|
| 970 | 970 | let symbols = try! alloc::allocSlice( |
|
| 971 | 971 | &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), capacity |
|
| 972 | 972 | ) as *mut [*mut Symbol]; |
|
| 973 | 973 | ||
| 974 | - | *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 }; |
|
| 975 | - | self.nodeData.entries[owner.id].scope = entry; |
|
| 974 | + | set *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 }; |
|
| 975 | + | set self.nodeData.entries[owner.id].scope = entry; |
|
| 976 | 976 | ||
| 977 | 977 | return entry; |
|
| 978 | 978 | } |
|
| 979 | 979 | ||
| 980 | 980 | /// Enter a new local scope that is the child of the current scope. |
|
| 981 | 981 | /// This creates a parent/child relationship that means that lookups in the |
|
| 982 | 982 | /// child scope can recurse upwards. |
|
| 983 | 983 | export fn enterScope(self: *mut Resolver, owner: *ast::Node) -> *Scope { |
|
| 984 | 984 | let scope = allocScope(self, owner, MAX_LOCAL_SYMBOLS); |
|
| 985 | - | scope.parent = self.scope; |
|
| 986 | - | self.scope = scope; |
|
| 985 | + | set scope.parent = self.scope; |
|
| 986 | + | set self.scope = scope; |
|
| 987 | 987 | return scope; |
|
| 988 | 988 | } |
|
| 989 | 989 | ||
| 990 | 990 | /// Enter a module scope. Returns an object that can be used to exit the scope. |
|
| 991 | 991 | export fn enterModuleScope(self: *mut Resolver, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope { |
|
| 992 | 992 | let prevScope = self.scope; |
|
| 993 | 993 | let prevMod = self.currentMod; |
|
| 994 | 994 | let scope = allocScope(self, owner, MAX_MODULE_SYMBOLS); |
|
| 995 | 995 | ||
| 996 | - | self.scope = scope; |
|
| 997 | - | self.scope.moduleId = module.id; |
|
| 998 | - | self.currentMod = module.id; |
|
| 996 | + | set self.scope = scope; |
|
| 997 | + | set self.scope.moduleId = module.id; |
|
| 998 | + | set self.currentMod = module.id; |
|
| 999 | 999 | // TODO: Allow any unsigned integer to index an array. |
|
| 1000 | - | self.moduleScopes[module.id as u32] = scope; |
|
| 1000 | + | set self.moduleScopes[module.id as u32] = scope; |
|
| 1001 | 1001 | ||
| 1002 | 1002 | return ModuleScope { root: owner, entry: module, newScope: scope, prevScope, prevMod }; |
|
| 1003 | 1003 | } |
|
| 1004 | 1004 | ||
| 1005 | 1005 | /// Enter a sub-module. Changes the current scope into that of the sub-module. |
| 1012 | 1012 | return enterModuleScope(self, modRoot, modEntry); |
|
| 1013 | 1013 | } |
|
| 1014 | 1014 | ||
| 1015 | 1015 | /// Exit a module scope, given the object returned by `enterModuleScope`. |
|
| 1016 | 1016 | export fn exitModuleScope(self: *mut Resolver, entry: ModuleScope) { |
|
| 1017 | - | self.scope = entry.prevScope; |
|
| 1018 | - | self.currentMod = entry.prevMod; |
|
| 1017 | + | set self.scope = entry.prevScope; |
|
| 1018 | + | set self.currentMod = entry.prevMod; |
|
| 1019 | 1019 | } |
|
| 1020 | 1020 | ||
| 1021 | 1021 | /// Exit the most recent scope. |
|
| 1022 | 1022 | export fn exitScope(self: *mut Resolver) { |
|
| 1023 | 1023 | let parent = self.scope.parent else { |
|
| 1024 | 1024 | // TODO: This should be a panic, but one of the tests hits this |
|
| 1025 | 1025 | // clause, which might be a bug in the generator. |
|
| 1026 | 1026 | return; |
|
| 1027 | 1027 | }; |
|
| 1028 | - | self.scope = parent; |
|
| 1028 | + | set self.scope = parent; |
|
| 1029 | 1029 | } |
|
| 1030 | 1030 | ||
| 1031 | 1031 | /// Visit the body of a loop while tracking nesting depth. |
|
| 1032 | 1032 | fn visitLoop(self: *mut Resolver, body: *ast::Node) -> Type |
|
| 1033 | 1033 | throws (ResolveError) |
|
| 1034 | 1034 | { |
|
| 1035 | 1035 | assert self.loopDepth < MAX_LOOP_DEPTH, "visitLoop: loop nesting depth exceeded"; |
|
| 1036 | - | self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false }; |
|
| 1037 | - | self.loopDepth += 1; |
|
| 1036 | + | set self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false }; |
|
| 1037 | + | set self.loopDepth += 1; |
|
| 1038 | 1038 | ||
| 1039 | 1039 | let ty = try infer(self, body) catch { |
|
| 1040 | 1040 | assert self.loopDepth <> 0, "visitLoop: loop depth underflow"; |
|
| 1041 | - | self.loopDepth -= 1; |
|
| 1041 | + | set self.loopDepth -= 1; |
|
| 1042 | 1042 | throw ResolveError::Failure; |
|
| 1043 | 1043 | }; |
|
| 1044 | 1044 | // Pop and check if break was encountered. |
|
| 1045 | - | self.loopDepth -= 1; |
|
| 1045 | + | set self.loopDepth -= 1; |
|
| 1046 | 1046 | ||
| 1047 | 1047 | if self.loopStack[self.loopDepth].hasBreak { |
|
| 1048 | 1048 | return Type::Void; |
|
| 1049 | 1049 | } |
|
| 1050 | 1050 | return Type::Never; |
| 1073 | 1073 | } |
|
| 1074 | 1074 | ||
| 1075 | 1075 | /// Set the expected return type for a new function body. |
|
| 1076 | 1076 | fn enterFn(self: *mut Resolver, node: *ast::Node, ty: *FnType) { |
|
| 1077 | 1077 | assert self.currentFn == nil, "enterFn: already in a function"; |
|
| 1078 | - | self.currentFn = ty; |
|
| 1078 | + | set self.currentFn = ty; |
|
| 1079 | 1079 | enterScope(self, node); |
|
| 1080 | 1080 | } |
|
| 1081 | 1081 | ||
| 1082 | 1082 | /// Clear the expected return type when leaving a function body. |
|
| 1083 | 1083 | fn exitFn(self: *mut Resolver) { |
|
| 1084 | 1084 | if self.currentFn == nil { |
|
| 1085 | 1085 | // TODO: This should be a panic, but one of the tests hits this |
|
| 1086 | 1086 | // clause, which might be a bug in the generator. |
|
| 1087 | 1087 | return; |
|
| 1088 | 1088 | } |
|
| 1089 | - | self.currentFn = nil; |
|
| 1089 | + | set self.currentFn = nil; |
|
| 1090 | 1090 | exitScope(self); |
|
| 1091 | 1091 | } |
|
| 1092 | 1092 | ||
| 1093 | 1093 | /// Extract the identifier text from a node. |
|
| 1094 | 1094 | fn nodeName(self: *mut Resolver, node: *ast::Node) -> *[u8] |
| 1102 | 1102 | /// Associate a resolved symbol with an AST node. |
|
| 1103 | 1103 | fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) { |
|
| 1104 | 1104 | if let existingSym = self.nodeData.entries[node.id].sym { |
|
| 1105 | 1105 | panic "setNodeSymbol: a symbol is already associated with this node"; |
|
| 1106 | 1106 | } |
|
| 1107 | - | self.nodeData.entries[node.id].sym = symbol; |
|
| 1107 | + | set self.nodeData.entries[node.id].sym = symbol; |
|
| 1108 | 1108 | } |
|
| 1109 | 1109 | ||
| 1110 | 1110 | /// Associate a resolved type with an AST node and return it. |
|
| 1111 | 1111 | fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type { |
|
| 1112 | 1112 | if ty == Type::Unknown { |
|
| 1113 | 1113 | // In this case, we simply don't associate a type. |
|
| 1114 | 1114 | return ty; |
|
| 1115 | 1115 | } |
|
| 1116 | - | self.nodeData.entries[node.id].ty = ty; |
|
| 1116 | + | set self.nodeData.entries[node.id].ty = ty; |
|
| 1117 | 1117 | ||
| 1118 | 1118 | return ty; |
|
| 1119 | 1119 | } |
|
| 1120 | 1120 | ||
| 1121 | 1121 | /// Unify the types of two branches for control flow. Returns `never` only if |
| 1133 | 1133 | /// Associate a coercion plan with an AST node. |
|
| 1134 | 1134 | fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion { |
|
| 1135 | 1135 | if coercion == Coercion::Identity { |
|
| 1136 | 1136 | return coercion; |
|
| 1137 | 1137 | } |
|
| 1138 | - | self.nodeData.entries[node.id].coercion = coercion; |
|
| 1138 | + | set self.nodeData.entries[node.id].coercion = coercion; |
|
| 1139 | 1139 | ||
| 1140 | 1140 | return coercion; |
|
| 1141 | 1141 | } |
|
| 1142 | 1142 | ||
| 1143 | 1143 | /// Associate a constant value with an AST node. |
|
| 1144 | 1144 | fn setNodeConstValue(self: *mut Resolver, node: *ast::Node, value: ConstValue) { |
|
| 1145 | - | self.nodeData.entries[node.id].constValue = value; |
|
| 1145 | + | set self.nodeData.entries[node.id].constValue = value; |
|
| 1146 | 1146 | } |
|
| 1147 | 1147 | ||
| 1148 | 1148 | /// Associate a record field index with a record literal field node. |
|
| 1149 | 1149 | fn setRecordFieldIndex(self: *mut Resolver, node: *ast::Node, index: u32) { |
|
| 1150 | - | self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index }; |
|
| 1150 | + | set self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index }; |
|
| 1151 | 1151 | } |
|
| 1152 | 1152 | ||
| 1153 | 1153 | /// Associate slice range metadata with a subscript expression. |
|
| 1154 | 1154 | fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) { |
|
| 1155 | - | self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info); |
|
| 1155 | + | set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info); |
|
| 1156 | 1156 | } |
|
| 1157 | 1157 | ||
| 1158 | 1158 | /// Associate union variant metadata with a pattern or constructor node. |
|
| 1159 | 1159 | fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) { |
|
| 1160 | - | self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag }; |
|
| 1160 | + | set self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag }; |
|
| 1161 | 1161 | } |
|
| 1162 | 1162 | ||
| 1163 | 1163 | /// Associate trait method call metadata with a call node. |
|
| 1164 | 1164 | fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) { |
|
| 1165 | - | self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex }; |
|
| 1165 | + | set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex }; |
|
| 1166 | 1166 | } |
|
| 1167 | 1167 | ||
| 1168 | 1168 | /// Associate for-loop metadata with a for-loop node. |
|
| 1169 | 1169 | fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) { |
|
| 1170 | - | self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info); |
|
| 1170 | + | set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info); |
|
| 1171 | 1171 | } |
|
| 1172 | 1172 | ||
| 1173 | 1173 | /// Retrieve the constant value associated with a node, if any. |
|
| 1174 | 1174 | export fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue { |
|
| 1175 | 1175 | return self.nodeData.entries[node.id].constValue; |
| 1199 | 1199 | return nil; |
|
| 1200 | 1200 | } |
|
| 1201 | 1201 | ||
| 1202 | 1202 | /// Associate match prong metadata with a match prong node. |
|
| 1203 | 1203 | fn setProngCatchAll(self: *mut Resolver, node: *ast::Node, catchAll: bool) { |
|
| 1204 | - | self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll }; |
|
| 1204 | + | set self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll }; |
|
| 1205 | 1205 | } |
|
| 1206 | 1206 | ||
| 1207 | 1207 | /// Check if a prong is catch-all. |
|
| 1208 | 1208 | export fn isProngCatchAll(self: *Resolver, node: *ast::Node) -> bool { |
|
| 1209 | 1209 | if let case NodeExtra::MatchProng { catchAll } = self.nodeData.entries[node.id].extra { |
| 1212 | 1212 | return false; |
|
| 1213 | 1213 | } |
|
| 1214 | 1214 | ||
| 1215 | 1215 | /// Set match metadata. |
|
| 1216 | 1216 | fn setMatchConst(self: *mut Resolver, node: *ast::Node, isConst: bool) { |
|
| 1217 | - | self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst }; |
|
| 1217 | + | set self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst }; |
|
| 1218 | 1218 | } |
|
| 1219 | 1219 | ||
| 1220 | 1220 | /// Check if a match has all constant patterns. |
|
| 1221 | 1221 | export fn isMatchConst(self: *Resolver, node: *ast::Node) -> bool { |
|
| 1222 | 1222 | if let case NodeExtra::Match { isConst } = self.nodeData.entries[node.id].extra { |
| 1297 | 1297 | } |
|
| 1298 | 1298 | ||
| 1299 | 1299 | /// Allocate a new symbol, and return a reference to it. |
|
| 1300 | 1300 | fn allocSymbol(self: *mut Resolver, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *mut Symbol { |
|
| 1301 | 1301 | let sym = try! alloc::alloc(&mut self.arena, @sizeOf(Symbol), @alignOf(Symbol)) as *mut Symbol; |
|
| 1302 | - | *sym = Symbol { name, data, attrs, node, moduleId: nil }; |
|
| 1302 | + | set *sym = Symbol { name, data, attrs, node, moduleId: nil }; |
|
| 1303 | 1303 | ||
| 1304 | 1304 | return sym; |
|
| 1305 | 1305 | } |
|
| 1306 | 1306 | ||
| 1307 | 1307 | /// Check that a type is boolean, otherwise throw an error. |
| 1371 | 1371 | let mut layout = getTypeLayout(ty); |
|
| 1372 | 1372 | // Check for symbol-specific alignment override. |
|
| 1373 | 1373 | if let sym = symbolFor(self, node) { |
|
| 1374 | 1374 | if let case SymbolData::Value { alignment, .. } = sym.data { |
|
| 1375 | 1375 | if alignment > 0 { |
|
| 1376 | - | layout.alignment = alignment; |
|
| 1376 | + | set layout.alignment = alignment; |
|
| 1377 | 1377 | } |
|
| 1378 | 1378 | } |
|
| 1379 | 1379 | } |
|
| 1380 | 1380 | return layout; |
|
| 1381 | 1381 | } |
| 1468 | 1468 | let mut maxSize = payloadLayout.size; |
|
| 1469 | 1469 | let mut maxAlign = payloadLayout.alignment; |
|
| 1470 | 1470 | ||
| 1471 | 1471 | for errType in throwList { |
|
| 1472 | 1472 | let errLayout = getTypeLayout(*errType); |
|
| 1473 | - | maxSize = max(maxSize, errLayout.size); |
|
| 1474 | - | maxAlign = max(maxAlign, errLayout.alignment); |
|
| 1473 | + | set maxSize = max(maxSize, errLayout.size); |
|
| 1474 | + | set maxAlign = max(maxAlign, errLayout.alignment); |
|
| 1475 | 1475 | } |
|
| 1476 | 1476 | return Layout { |
|
| 1477 | 1477 | size: PTR_SIZE + maxSize, |
|
| 1478 | 1478 | alignment: max(PTR_SIZE, maxAlign), |
|
| 1479 | 1479 | }; |
| 1486 | 1486 | let mut maxVarAlign: u32 = 1; |
|
| 1487 | 1487 | let mut isAllVoid: bool = true; |
|
| 1488 | 1488 | ||
| 1489 | 1489 | for variant in variants { |
|
| 1490 | 1490 | if variant.valueType <> Type::Void { |
|
| 1491 | - | isAllVoid = false; |
|
| 1491 | + | set isAllVoid = false; |
|
| 1492 | 1492 | let payloadLayout = getTypeLayout(variant.valueType); |
|
| 1493 | - | maxVarSize = max(maxVarSize, payloadLayout.size); |
|
| 1494 | - | maxVarAlign = max(maxVarAlign, payloadLayout.alignment); |
|
| 1493 | + | set maxVarSize = max(maxVarSize, payloadLayout.size); |
|
| 1494 | + | set maxVarAlign = max(maxVarAlign, payloadLayout.alignment); |
|
| 1495 | 1495 | } |
|
| 1496 | 1496 | } |
|
| 1497 | 1497 | let unionAlignment: u32 = max(1, maxVarAlign); |
|
| 1498 | 1498 | let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign); |
|
| 1499 | 1499 | let unionLayout = Layout { |
| 1508 | 1508 | fn variantTag(variantDecl: ast::UnionDeclVariant, iota: *mut u32) -> u32 { |
|
| 1509 | 1509 | let mut tag: u32 = *iota; |
|
| 1510 | 1510 | if let valueNode = variantDecl.value { |
|
| 1511 | 1511 | let case ast::NodeValue::Number(lit) = valueNode.value |
|
| 1512 | 1512 | else panic "variantTag: expected number literal"; |
|
| 1513 | - | tag = lit.magnitude as u32; |
|
| 1513 | + | set tag = lit.magnitude as u32; |
|
| 1514 | 1514 | } |
|
| 1515 | - | *iota = tag + 1; |
|
| 1515 | + | set *iota = tag + 1; |
|
| 1516 | 1516 | return tag; |
|
| 1517 | 1517 | } |
|
| 1518 | 1518 | ||
| 1519 | 1519 | /// Check if a type is a union without payloads. |
|
| 1520 | 1520 | export fn isVoidUnion(ty: Type) -> bool { |
| 1619 | 1619 | ||
| 1620 | 1620 | if let sym = symbolFor(self, declNode) { |
|
| 1621 | 1621 | if let mid = sym.moduleId { |
|
| 1622 | 1622 | if (mid as u32) < self.moduleScopes.len { |
|
| 1623 | 1623 | if let ms = self.moduleScopes[mid as u32] { |
|
| 1624 | - | self.scope = ms; |
|
| 1625 | - | self.currentMod = mid; |
|
| 1624 | + | set self.scope = ms; |
|
| 1625 | + | set self.currentMod = mid; |
|
| 1626 | 1626 | } |
|
| 1627 | 1627 | } |
|
| 1628 | 1628 | } |
|
| 1629 | 1629 | } |
|
| 1630 | 1630 |
| 1635 | 1635 | case ast::NodeValue::UnionDecl(decl) => { |
|
| 1636 | 1636 | try resolveUnionBody(self, declNode, decl); |
|
| 1637 | 1637 | } |
|
| 1638 | 1638 | else => {}, |
|
| 1639 | 1639 | } |
|
| 1640 | - | self.scope = prevScope; |
|
| 1641 | - | self.currentMod = prevMod; |
|
| 1640 | + | set self.scope = prevScope; |
|
| 1641 | + | set self.currentMod = prevMod; |
|
| 1642 | 1642 | } |
|
| 1643 | 1643 | } |
|
| 1644 | 1644 | ||
| 1645 | 1645 | /// Check if all elements in a node list are assignable to the target type. |
|
| 1646 | 1646 | fn isListAssignable(self: *mut Resolver, targetType: Type, items: *mut [*ast::Node]) -> bool { |
| 2012 | 2012 | if scope.symbolsLen >= scope.symbols.len { |
|
| 2013 | 2013 | throw emitError(self, site, ErrorKind::SymbolOverflow); |
|
| 2014 | 2014 | } |
|
| 2015 | 2015 | // Propagate module ID to the symbol for fast lookup. |
|
| 2016 | 2016 | if let modId = scope.moduleId { |
|
| 2017 | - | sym.moduleId = modId; |
|
| 2017 | + | set sym.moduleId = modId; |
|
| 2018 | 2018 | } |
|
| 2019 | - | scope.symbols[scope.symbolsLen] = sym; |
|
| 2020 | - | scope.symbolsLen += 1; |
|
| 2019 | + | set scope.symbols[scope.symbolsLen] = sym; |
|
| 2020 | + | set scope.symbolsLen += 1; |
|
| 2021 | 2021 | } |
|
| 2022 | 2022 | ||
| 2023 | 2023 | /// Bind a value identifier in the current scope. |
|
| 2024 | 2024 | /// Returns `nil` if the identifier is a placeholder (`_`). |
|
| 2025 | 2025 | fn bindValueIdent( |
| 2041 | 2041 | setNodeType(self, owner, type); |
|
| 2042 | 2042 | setNodeType(self, ident, type); |
|
| 2043 | 2043 | ||
| 2044 | 2044 | // Track number of local bindings for lowering stage. |
|
| 2045 | 2045 | if let mut fnType = self.currentFn { |
|
| 2046 | - | fnType.localCount += 1; |
|
| 2046 | + | set fnType.localCount += 1; |
|
| 2047 | 2047 | } |
|
| 2048 | 2048 | return sym; |
|
| 2049 | 2049 | } |
|
| 2050 | 2050 | ||
| 2051 | 2051 | /// Bind a constant identifier in the current scope. |
| 2137 | 2137 | loop { |
|
| 2138 | 2138 | if let sym = findInScope(curr, name, predicate) { |
|
| 2139 | 2139 | return sym; |
|
| 2140 | 2140 | } |
|
| 2141 | 2141 | if let parent = curr.parent { |
|
| 2142 | - | curr = parent; |
|
| 2142 | + | set curr = parent; |
|
| 2143 | 2143 | } else { |
|
| 2144 | 2144 | break; |
|
| 2145 | 2145 | } |
|
| 2146 | 2146 | } |
|
| 2147 | 2147 | return nil; |
| 2178 | 2178 | let mut out: *[*[u8]] = &[]; |
|
| 2179 | 2179 | ||
| 2180 | 2180 | match node.value { |
|
| 2181 | 2181 | case ast::NodeValue::Ident(name) if name.len > 0 => { |
|
| 2182 | 2182 | assert buf.len >= 1, "flattenPath: invalid output buffer size"; |
|
| 2183 | - | buf[0] = name; |
|
| 2184 | - | out = &buf[..1]; |
|
| 2183 | + | set buf[0] = name; |
|
| 2184 | + | set out = &buf[..1]; |
|
| 2185 | 2185 | } |
|
| 2186 | 2186 | case ast::NodeValue::ScopeAccess(access) => { |
|
| 2187 | 2187 | // Recursively flatten parent path. |
|
| 2188 | 2188 | let parent = try flattenPath(self, access.parent, buf); |
|
| 2189 | 2189 | assert parent.len < buf.len, "flattenPath: invalid output buffer size"; |
|
| 2190 | 2190 | let child = try nodeName(self, access.child); |
|
| 2191 | - | buf[parent.len] = child; |
|
| 2192 | - | out = &buf[..parent.len + 1]; |
|
| 2191 | + | set buf[parent.len] = child; |
|
| 2192 | + | set out = &buf[..parent.len + 1]; |
|
| 2193 | 2193 | } |
|
| 2194 | 2194 | case ast::NodeValue::Super => { |
|
| 2195 | 2195 | // `super` is handled by scope adjustment in `checkSuperAccess`. |
|
| 2196 | 2196 | // Return empty prefix so the path continues from the next segment. |
|
| 2197 | - | out = &buf[..0]; |
|
| 2197 | + | set out = &buf[..0]; |
|
| 2198 | 2198 | return out; |
|
| 2199 | 2199 | } |
|
| 2200 | 2200 | else => { |
|
| 2201 | 2201 | // Fallthrough to error. |
|
| 2202 | 2202 | } |
| 2214 | 2214 | loop { |
|
| 2215 | 2215 | if let id = s.moduleId { |
|
| 2216 | 2216 | return id; |
|
| 2217 | 2217 | } |
|
| 2218 | 2218 | if let parent = s.parent { |
|
| 2219 | - | s = parent; |
|
| 2219 | + | set s = parent; |
|
| 2220 | 2220 | } else { |
|
| 2221 | 2221 | return nil; |
|
| 2222 | 2222 | } |
|
| 2223 | 2223 | } |
|
| 2224 | 2224 | } |
| 2289 | 2289 | ) -> *mut Symbol throws (ResolveError) { |
|
| 2290 | 2290 | // Handle `super` access by adjusting scope and node. |
|
| 2291 | 2291 | let mut startScope = scope; |
|
| 2292 | 2292 | let mut pathNode = node; |
|
| 2293 | 2293 | if let superAccess = try checkSuperAccess(self, node) { |
|
| 2294 | - | startScope = superAccess.scope; |
|
| 2295 | - | pathNode = superAccess.child; |
|
| 2294 | + | set startScope = superAccess.scope; |
|
| 2295 | + | set pathNode = superAccess.child; |
|
| 2296 | 2296 | } |
|
| 2297 | 2297 | // TODO: It doesn't make sense that `flattenPath` handles identifiers and scope access, |
|
| 2298 | 2298 | // while this function requires a scope access. |
|
| 2299 | 2299 | let mut buffer: [*[u8]; 32] = undefined; |
|
| 2300 | 2300 | let path = try flattenPath(self, pathNode, &mut buffer[..]); |
| 2363 | 2363 | let mut startScope = self.scope; |
|
| 2364 | 2364 | let mut pathNode = module; |
|
| 2365 | 2365 | ||
| 2366 | 2366 | // Handle `super` access. |
|
| 2367 | 2367 | if let superAccess = try checkSuperAccess(self, module) { |
|
| 2368 | - | startScope = superAccess.scope; |
|
| 2369 | - | pathNode = superAccess.child; |
|
| 2368 | + | set startScope = superAccess.scope; |
|
| 2369 | + | set pathNode = superAccess.child; |
|
| 2370 | 2370 | } |
|
| 2371 | 2371 | let mut pathBuf: [*[u8]; 16] = undefined; |
|
| 2372 | 2372 | let path = try flattenPath(self, pathNode, &mut pathBuf[..]); |
|
| 2373 | 2373 | if path.len == 0 { |
|
| 2374 | 2374 | throw emitError(self, module, ErrorKind::UnresolvedSymbol("")); |
| 2589 | 2589 | return setNodeType(self, node, loopType); |
|
| 2590 | 2590 | }, |
|
| 2591 | 2591 | case ast::NodeValue::Break => { |
|
| 2592 | 2592 | try ensureInsideLoop(self, node); |
|
| 2593 | 2593 | // Mark that the current loop has a reachable break. |
|
| 2594 | - | self.loopStack[self.loopDepth - 1].hasBreak = true; |
|
| 2594 | + | set self.loopStack[self.loopDepth - 1].hasBreak = true; |
|
| 2595 | 2595 | ||
| 2596 | 2596 | return setNodeType(self, node, Type::Never); |
|
| 2597 | 2597 | }, |
|
| 2598 | 2598 | case ast::NodeValue::Continue => { |
|
| 2599 | 2599 | try ensureInsideLoop(self, node); |
| 2702 | 2702 | throws (ResolveError) |
|
| 2703 | 2703 | { |
|
| 2704 | 2704 | let mut diverges = false; |
|
| 2705 | 2705 | for item in list { |
|
| 2706 | 2706 | if try infer(self, item) == Type::Never { |
|
| 2707 | - | diverges = true; |
|
| 2707 | + | set diverges = true; |
|
| 2708 | 2708 | } |
|
| 2709 | 2709 | } |
|
| 2710 | 2710 | if diverges { |
|
| 2711 | 2711 | return Type::Never; |
|
| 2712 | 2712 | } |
| 2720 | 2720 | let mut mask: u32 = 0; |
|
| 2721 | 2721 | ||
| 2722 | 2722 | for node in attrNodes { |
|
| 2723 | 2723 | let case ast::NodeValue::Attribute(attr) = node.value |
|
| 2724 | 2724 | else panic "resolveAttributes: invalid attribute node"; |
|
| 2725 | - | mask |= (attr as u32); |
|
| 2725 | + | set mask |= (attr as u32); |
|
| 2726 | 2726 | } |
|
| 2727 | 2727 | return mask; |
|
| 2728 | 2728 | } |
|
| 2729 | 2729 | ||
| 2730 | 2730 | /// Ensure the `default` attribute is only applied to functions. |
| 2762 | 2762 | let mut bindingTy = Type::Unknown; |
|
| 2763 | 2763 | ||
| 2764 | 2764 | // Check type. |
|
| 2765 | 2765 | if let declTy = try visitOptional(self, decl.type, Type::Unknown) { |
|
| 2766 | 2766 | let _coercion = try checkAssignable(self, decl.value, declTy); |
|
| 2767 | - | bindingTy = declTy; |
|
| 2767 | + | set bindingTy = declTy; |
|
| 2768 | 2768 | } else { |
|
| 2769 | - | bindingTy = try infer(self, decl.value); |
|
| 2769 | + | set bindingTy = try infer(self, decl.value); |
|
| 2770 | 2770 | ||
| 2771 | 2771 | if not isTypeInferrable(bindingTy) { |
|
| 2772 | 2772 | throw emitError(self, decl.value, ErrorKind::CannotInferType); |
|
| 2773 | 2773 | } |
|
| 2774 | 2774 | } |
| 2782 | 2782 | } |
|
| 2783 | 2783 | // Check alignment. |
|
| 2784 | 2784 | if let a = decl.alignment { |
|
| 2785 | 2785 | let case ast::NodeValue::Align { value } = a.value |
|
| 2786 | 2786 | else panic "resolveLet: expected Align node"; |
|
| 2787 | - | alignment = try checkSizeInt(self, value); |
|
| 2787 | + | set alignment = try checkSizeInt(self, value); |
|
| 2788 | 2788 | } |
|
| 2789 | 2789 | assert bindingTy <> Type::Unknown; |
|
| 2790 | 2790 | ||
| 2791 | 2791 | // Alignment must be zero or a power of two. |
|
| 2792 | 2792 | if alignment <> 0 and (alignment & (alignment - 1)) <> 0 { |
| 3013 | 3013 | throws (ResolveError) |
|
| 3014 | 3014 | { |
|
| 3015 | 3015 | let attrMask = resolveAttributes(self, decl.attrs); |
|
| 3016 | 3016 | let mut retTy = Type::Void; |
|
| 3017 | 3017 | if let retNode = decl.sig.returnType { |
|
| 3018 | - | retTy = try infer(self, retNode); |
|
| 3018 | + | set retTy = try infer(self, retNode); |
|
| 3019 | 3019 | } |
|
| 3020 | 3020 | let a = alloc::arenaAllocator(&mut self.arena); |
|
| 3021 | 3021 | let mut paramTypes: *mut [*Type] = &mut []; |
|
| 3022 | 3022 | let mut throwList: *mut [*Type] = &mut []; |
|
| 3023 | 3023 | let mut fnType = FnType { |
| 3057 | 3057 | throw e; |
|
| 3058 | 3058 | }; |
|
| 3059 | 3059 | throwList.append(allocType(self, throwTy), a); |
|
| 3060 | 3060 | } |
|
| 3061 | 3061 | exitFn(self); |
|
| 3062 | - | fnType.paramTypes = ¶mTypes[..]; |
|
| 3063 | - | fnType.throwList = &throwList[..]; |
|
| 3062 | + | set fnType.paramTypes = ¶mTypes[..]; |
|
| 3063 | + | set fnType.throwList = &throwList[..]; |
|
| 3064 | 3064 | ||
| 3065 | 3065 | // Bind the function name. |
|
| 3066 | 3066 | let ty = Type::Fn(allocFnType(self, fnType)); |
|
| 3067 | 3067 | let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask) |
|
| 3068 | 3068 | else throw emitError(self, node, ErrorKind::ExpectedIdentifier); |
| 3144 | 3144 | // Get field name for labeled records. |
|
| 3145 | 3145 | let mut fieldName: ?*[u8] = nil; |
|
| 3146 | 3146 | if labeled { |
|
| 3147 | 3147 | let n = fieldNode |
|
| 3148 | 3148 | else panic "resolveRecordFields: labeled record field missing name"; |
|
| 3149 | - | fieldName = try nodeName(self, n); |
|
| 3149 | + | set fieldName = try nodeName(self, n); |
|
| 3150 | 3150 | } |
|
| 3151 | 3151 | let fieldType = typeFor(self, typeNode) |
|
| 3152 | 3152 | else throw emitError(self, typeNode, ErrorKind::CannotInferType); |
|
| 3153 | 3153 | ||
| 3154 | 3154 | // Ensure field type is fully resolved before computing layout. |
|
| 3155 | 3155 | try ensureTypeResolved(self, fieldType, typeNode); |
|
| 3156 | 3156 | ||
| 3157 | 3157 | // Compute field offset by aligning to field's alignment. |
|
| 3158 | 3158 | let fieldLayout = getTypeLayout(fieldType); |
|
| 3159 | - | currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment); |
|
| 3159 | + | set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment); |
|
| 3160 | 3160 | ||
| 3161 | 3161 | result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a); |
|
| 3162 | 3162 | ||
| 3163 | 3163 | // Advance offset past this field. |
|
| 3164 | - | currentOffset += fieldLayout.size; |
|
| 3164 | + | set currentOffset += fieldLayout.size; |
|
| 3165 | 3165 | ||
| 3166 | 3166 | // Track max alignment for record layout. |
|
| 3167 | - | maxAlignment = max(maxAlignment, fieldLayout.alignment); |
|
| 3167 | + | set maxAlignment = max(maxAlignment, fieldLayout.alignment); |
|
| 3168 | 3168 | } |
|
| 3169 | 3169 | // Compute cached layout. |
|
| 3170 | 3170 | let recordLayout = Layout { |
|
| 3171 | 3171 | size: mem::alignUp(currentOffset, maxAlignment), |
|
| 3172 | 3172 | alignment: maxAlignment |
| 3190 | 3190 | return; |
|
| 3191 | 3191 | } |
|
| 3192 | 3192 | try visitList(self, decl.derives); |
|
| 3193 | 3193 | let recordType = try resolveRecordFields(self, node, decl.fields, decl.labeled); |
|
| 3194 | 3194 | ||
| 3195 | - | *nominalTy = NominalType::Record(recordType); |
|
| 3195 | + | set *nominalTy = NominalType::Record(recordType); |
|
| 3196 | 3196 | } |
|
| 3197 | 3197 | ||
| 3198 | 3198 | /// Bind a type name. |
|
| 3199 | 3199 | fn bindTypeName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol |
|
| 3200 | 3200 | throws (ResolveError) |
| 3211 | 3211 | ||
| 3212 | 3212 | /// Allocate a trait type descriptor and return a pointer to it. |
|
| 3213 | 3213 | fn allocTraitType(self: *mut Resolver, name: *[u8]) -> *mut TraitType { |
|
| 3214 | 3214 | let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType)); |
|
| 3215 | 3215 | let entry = p as *mut TraitType; |
|
| 3216 | - | *entry = TraitType { name, methods: &mut [], supertraits: &mut [] }; |
|
| 3216 | + | set *entry = TraitType { name, methods: &mut [], supertraits: &mut [] }; |
|
| 3217 | 3217 | ||
| 3218 | 3218 | return entry; |
|
| 3219 | 3219 | } |
|
| 3220 | 3220 | ||
| 3221 | 3221 | /// Bind a trait name in the current scope. |
| 3331 | 3331 | for paramNode in sig.params { |
|
| 3332 | 3332 | let paramTy = try infer(self, paramNode); |
|
| 3333 | 3333 | paramTypes.append(allocType(self, paramTy), a); |
|
| 3334 | 3334 | } |
|
| 3335 | 3335 | if let ret = sig.returnType { |
|
| 3336 | - | retType = allocType(self, try infer(self, ret)); |
|
| 3336 | + | set retType = allocType(self, try infer(self, ret)); |
|
| 3337 | 3337 | } |
|
| 3338 | 3338 | // Resolve throws list. |
|
| 3339 | 3339 | if sig.throwList.len > MAX_FN_THROWS { |
|
| 3340 | 3340 | throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch { |
|
| 3341 | 3341 | expected: MAX_FN_THROWS, |
| 3494 | 3494 | }); |
|
| 3495 | 3495 | } |
|
| 3496 | 3496 | } |
|
| 3497 | 3497 | let mut instanceRetTy = Type::Void; |
|
| 3498 | 3498 | if let retNode = sig.returnType { |
|
| 3499 | - | instanceRetTy = try resolveValueType(self, retNode); |
|
| 3499 | + | set instanceRetTy = try resolveValueType(self, retNode); |
|
| 3500 | 3500 | } |
|
| 3501 | 3501 | if not typesEqual(instanceRetTy, *tm.fnType.returnType) { |
|
| 3502 | 3502 | throw emitTypeMismatch(self, methodNode, TypeMismatch { |
|
| 3503 | 3503 | expected: *tm.fnType.returnType, |
|
| 3504 | 3504 | actual: instanceRetTy, |
| 3548 | 3548 | setNodeSymbol(self, methodNode, sym); |
|
| 3549 | 3549 | setNodeType(self, methodNode, fnTy); |
|
| 3550 | 3550 | setNodeType(self, name, fnTy); |
|
| 3551 | 3551 | ||
| 3552 | 3552 | // Store in instance entry at the matching v-table slot. |
|
| 3553 | - | entry.methods[tm.index] = sym; |
|
| 3554 | - | covered[tm.index] = true; |
|
| 3553 | + | set entry.methods[tm.index] = sym; |
|
| 3554 | + | set covered[tm.index] = true; |
|
| 3555 | 3555 | } |
|
| 3556 | 3556 | ||
| 3557 | 3557 | // Fill inherited method slots from supertrait instances. |
|
| 3558 | 3558 | for superTrait in traitInfo.supertraits { |
|
| 3559 | 3559 | let superInst = findInstance(self, superTrait, concreteType) |
|
| 3560 | 3560 | else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name)); |
|
| 3561 | 3561 | for superMethod, mi in superTrait.methods { |
|
| 3562 | 3562 | let merged = findTraitMethod(traitInfo, superMethod.name) |
|
| 3563 | 3563 | else panic "resolveInstanceDecl: inherited method not found"; |
|
| 3564 | 3564 | if not covered[merged.index] { |
|
| 3565 | - | entry.methods[merged.index] = superInst.methods[mi]; |
|
| 3566 | - | covered[merged.index] = true; |
|
| 3565 | + | set entry.methods[merged.index] = superInst.methods[mi]; |
|
| 3566 | + | set covered[merged.index] = true; |
|
| 3567 | 3567 | } |
|
| 3568 | 3568 | } |
|
| 3569 | 3569 | } |
|
| 3570 | 3570 | ||
| 3571 | 3571 | // Check that all trait methods are implemented. |
|
| 3572 | 3572 | for method, i in traitInfo.methods { |
|
| 3573 | 3573 | if not covered[i] { |
|
| 3574 | 3574 | throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name)); |
|
| 3575 | 3575 | } |
|
| 3576 | 3576 | } |
|
| 3577 | - | self.instances[self.instancesLen] = entry; |
|
| 3578 | - | self.instancesLen += 1; |
|
| 3577 | + | set self.instances[self.instancesLen] = entry; |
|
| 3578 | + | set self.instancesLen += 1; |
|
| 3579 | 3579 | ||
| 3580 | 3580 | setNodeType(self, node, Type::Void); |
|
| 3581 | 3581 | } |
|
| 3582 | 3582 | ||
| 3583 | 3583 | /// Resolve instance method bodies. |
| 3703 | 3703 | } |
|
| 3704 | 3704 | ||
| 3705 | 3705 | // Resolve return type. |
|
| 3706 | 3706 | let mut returnType = Type::Void; |
|
| 3707 | 3707 | if let retNode = sig.returnType { |
|
| 3708 | - | returnType = try resolveValueType(self, retNode); |
|
| 3708 | + | set returnType = try resolveValueType(self, retNode); |
|
| 3709 | 3709 | } |
|
| 3710 | 3710 | ||
| 3711 | 3711 | // Resolve throw list. |
|
| 3712 | 3712 | let mut throwTypes: *mut [*Type] = &mut []; |
|
| 3713 | 3713 | for throwNode in sig.throwList { |
| 3732 | 3732 | // Compute attribute mask. |
|
| 3733 | 3733 | let mut attrMask: u32 = 0; |
|
| 3734 | 3734 | if let a = attrs { |
|
| 3735 | 3735 | for attrNode in a.list { |
|
| 3736 | 3736 | if let case ast::NodeValue::Attribute(attr) = attrNode.value { |
|
| 3737 | - | attrMask = attrMask | (attr as u32); |
|
| 3737 | + | set attrMask = attrMask | (attr as u32); |
|
| 3738 | 3738 | } |
|
| 3739 | 3739 | } |
|
| 3740 | 3740 | } |
|
| 3741 | 3741 | ||
| 3742 | 3742 | // Create a symbol for the method without binding it into the module scope. |
| 3750 | 3750 | ||
| 3751 | 3751 | // Register in the method table. |
|
| 3752 | 3752 | if self.methodsLen >= MAX_METHODS { |
|
| 3753 | 3753 | throw emitError(self, node, ErrorKind::Internal); |
|
| 3754 | 3754 | } |
|
| 3755 | - | self.methods[self.methodsLen] = MethodEntry { |
|
| 3755 | + | set self.methods[self.methodsLen] = MethodEntry { |
|
| 3756 | 3756 | concreteType, |
|
| 3757 | 3757 | concreteTypeName: typeName, |
|
| 3758 | 3758 | name: methodName, |
|
| 3759 | 3759 | fnType: allocFnType(self, checkFnType), |
|
| 3760 | 3760 | mutable: receiverMut, |
|
| 3761 | 3761 | symbol: sym, |
|
| 3762 | 3762 | }; |
|
| 3763 | - | self.methodsLen += 1; |
|
| 3763 | + | set self.methodsLen += 1; |
|
| 3764 | 3764 | } |
|
| 3765 | 3765 | ||
| 3766 | 3766 | /// Look up an instance entry by trait and concrete type. |
|
| 3767 | 3767 | fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry { |
|
| 3768 | 3768 | for i in 0..self.instancesLen { |
| 3816 | 3816 | let mut variants: *mut [UnionVariant] = &mut []; |
|
| 3817 | 3817 | ||
| 3818 | 3818 | // Create a temporary nominal type to replace the placeholder.This prevents infinite recursion |
|
| 3819 | 3819 | // when a variant references this union type (e.g. record payloads with `*[Self]`). |
|
| 3820 | 3820 | // TODO: It would be best to have a resolving state eg. `Visiting` for this situation. |
|
| 3821 | - | *nominalTy = NominalType::Union(UnionType { |
|
| 3821 | + | set *nominalTy = NominalType::Union(UnionType { |
|
| 3822 | 3822 | variants: &[], |
|
| 3823 | 3823 | layout: Layout { size: 0, alignment: 0 }, |
|
| 3824 | 3824 | valOffset: 0, |
|
| 3825 | 3825 | isAllVoid: true |
|
| 3826 | 3826 | }); |
| 3834 | 3834 | else panic "resolveUnionBody: invalid union variant"; |
|
| 3835 | 3835 | let variantName = try nodeName(self, variantDecl.name); |
|
| 3836 | 3836 | // Resolve the variant's payload type if present. |
|
| 3837 | 3837 | let mut variantType = Type::Void; |
|
| 3838 | 3838 | if let ty = try visitOptional(self, variantDecl.type, Type::Unknown) { |
|
| 3839 | - | variantType = ty; |
|
| 3839 | + | set variantType = ty; |
|
| 3840 | 3840 | } |
|
| 3841 | 3841 | // Process the variant's explicit discriminant value if present. |
|
| 3842 | 3842 | try visitOptional(self, variantDecl.value, variantType); |
|
| 3843 | 3843 | let tag = variantTag(variantDecl, &mut iota); |
|
| 3844 | 3844 | // Create a symbol for this variant. |
| 3852 | 3852 | }, a); |
|
| 3853 | 3853 | } |
|
| 3854 | 3854 | let info = computeUnionLayout(&variants[..]); |
|
| 3855 | 3855 | ||
| 3856 | 3856 | // Update the nominal type with the resolved variants. |
|
| 3857 | - | *nominalTy = NominalType::Union(UnionType { |
|
| 3857 | + | set *nominalTy = NominalType::Union(UnionType { |
|
| 3858 | 3858 | variants: &variants[..], |
|
| 3859 | 3859 | layout: info.layout, |
|
| 3860 | 3860 | valOffset: info.valOffset, |
|
| 3861 | 3861 | isAllVoid: info.isAllVoid, |
|
| 3862 | 3862 | }); |
| 4121 | 4121 | let iterableTy = try infer(self, forStmt.iterable); |
|
| 4122 | 4122 | ||
| 4123 | 4123 | // Extract binding names for the lowerer. |
|
| 4124 | 4124 | let mut bindingName: ?*[u8] = nil; |
|
| 4125 | 4125 | if let case ast::NodeValue::Ident(name) = forStmt.binding.value { |
|
| 4126 | - | bindingName = name; |
|
| 4126 | + | set bindingName = name; |
|
| 4127 | 4127 | } |
|
| 4128 | 4128 | let mut indexName: ?*[u8] = nil; |
|
| 4129 | 4129 | if let idx = forStmt.index { |
|
| 4130 | 4130 | if let case ast::NodeValue::Ident(name) = idx.value { |
|
| 4131 | - | indexName = name; |
|
| 4131 | + | set indexName = name; |
|
| 4132 | 4132 | } |
|
| 4133 | 4133 | } |
|
| 4134 | 4134 | // Extract item type and store pre-computed loop metadata for the lowerer. |
|
| 4135 | 4135 | let mut itemTy: Type = undefined; |
|
| 4136 | 4136 | match iterableTy { |
| 4141 | 4141 | throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable); |
|
| 4142 | 4142 | }; |
|
| 4143 | 4143 | let case ast::NodeValue::Range(range) = forStmt.iterable.value else { |
|
| 4144 | 4144 | throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable); |
|
| 4145 | 4145 | }; |
|
| 4146 | - | itemTy = *valType; |
|
| 4146 | + | set itemTy = *valType; |
|
| 4147 | 4147 | ||
| 4148 | 4148 | setForLoopInfo(self, node, ForLoopInfo::Range { |
|
| 4149 | 4149 | valType, range, bindingName, indexName |
|
| 4150 | 4150 | }); |
|
| 4151 | 4151 | } |
|
| 4152 | 4152 | case Type::Array(arrayInfo) => { |
|
| 4153 | - | itemTy = *arrayInfo.item; |
|
| 4153 | + | set itemTy = *arrayInfo.item; |
|
| 4154 | 4154 | setForLoopInfo(self, node, ForLoopInfo::Collection { |
|
| 4155 | 4155 | elemType: arrayInfo.item, |
|
| 4156 | 4156 | length: arrayInfo.length, |
|
| 4157 | 4157 | bindingName, |
|
| 4158 | 4158 | indexName, |
|
| 4159 | 4159 | }); |
|
| 4160 | 4160 | } |
|
| 4161 | 4161 | case Type::Slice { item, .. } => { |
|
| 4162 | - | itemTy = *item; |
|
| 4162 | + | set itemTy = *item; |
|
| 4163 | 4163 | setForLoopInfo(self, node, ForLoopInfo::Collection { |
|
| 4164 | 4164 | elemType: item, length: nil, bindingName, indexName |
|
| 4165 | 4165 | }); |
|
| 4166 | 4166 | } |
|
| 4167 | 4167 | else => throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable), |
| 4173 | 4173 | try bindForLoopPattern(self, pat, Type::U32, false); |
|
| 4174 | 4174 | } |
|
| 4175 | 4175 | // The lowerer always creates at least one internal variable for iteration, |
|
| 4176 | 4176 | // even when the binding is a placeholder or no explicit index is given. |
|
| 4177 | 4177 | if let mut fnType = self.currentFn { |
|
| 4178 | - | fnType.localCount += 1; |
|
| 4178 | + | set fnType.localCount += 1; |
|
| 4179 | 4179 | } |
|
| 4180 | 4180 | try visitLoop(self, forStmt.body); |
|
| 4181 | 4181 | exitScope(self); |
|
| 4182 | 4182 | ||
| 4183 | 4183 | try visitOptional(self, forStmt.elseBranch, Type::Void); |
| 4325 | 4325 | ) -> Type throws (ResolveError) { |
|
| 4326 | 4326 | // Whether this prong is catch-all. |
|
| 4327 | 4327 | let mut isCatchAll = false; |
|
| 4328 | 4328 | ||
| 4329 | 4329 | if prong.guard <> nil { |
|
| 4330 | - | state.isConst = false; |
|
| 4330 | + | set state.isConst = false; |
|
| 4331 | 4331 | } else { |
|
| 4332 | 4332 | match prong.arm { |
|
| 4333 | 4333 | case ast::ProngArm::Binding(_), |
|
| 4334 | - | ast::ProngArm::Else => isCatchAll = true, |
|
| 4335 | - | case ast::ProngArm::Case(patterns) => isCatchAll = hasWildcardPattern(patterns), |
|
| 4334 | + | ast::ProngArm::Else => set isCatchAll = true, |
|
| 4335 | + | case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns), |
|
| 4336 | 4336 | } |
|
| 4337 | 4337 | } |
|
| 4338 | 4338 | if isCatchAll { |
|
| 4339 | 4339 | if state.catchAll { |
|
| 4340 | 4340 | throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll); |
|
| 4341 | 4341 | } |
|
| 4342 | - | state.catchAll = true; |
|
| 4342 | + | set state.catchAll = true; |
|
| 4343 | 4343 | } |
|
| 4344 | 4344 | setProngCatchAll(self, prongNode, isCatchAll); |
|
| 4345 | 4345 | ||
| 4346 | 4346 | return try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy); |
|
| 4347 | 4347 | } |
| 4394 | 4394 | // Only `else` without a guard is a true catch-all. |
|
| 4395 | 4395 | if prong.arm == ast::ProngArm::Else and prong.guard == nil { |
|
| 4396 | 4396 | if catchAll { |
|
| 4397 | 4397 | throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll); |
|
| 4398 | 4398 | } |
|
| 4399 | - | catchAll = true; |
|
| 4399 | + | set catchAll = true; |
|
| 4400 | 4400 | } |
|
| 4401 | 4401 | ||
| 4402 | 4402 | let mut isCatchAll = false; |
|
| 4403 | 4403 | if prong.guard == nil { |
|
| 4404 | 4404 | match prong.arm { |
|
| 4405 | - | case ast::ProngArm::Else => isCatchAll = true, |
|
| 4406 | - | case ast::ProngArm::Case(patterns) => isCatchAll = hasWildcardPattern(patterns), |
|
| 4405 | + | case ast::ProngArm::Else => set isCatchAll = true, |
|
| 4406 | + | case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns), |
|
| 4407 | 4407 | case ast::ProngArm::Binding(_) => { |
|
| 4408 | 4408 | // For optionals, a binding does *not* always match. |
|
| 4409 | 4409 | } |
|
| 4410 | 4410 | } |
|
| 4411 | 4411 | } |
|
| 4412 | 4412 | setProngCatchAll(self, prongNode, isCatchAll); |
|
| 4413 | - | matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, MatchBy::Value); |
|
| 4413 | + | set matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, MatchBy::Value); |
|
| 4414 | 4414 | ||
| 4415 | 4415 | // Track coverage. Guarded prongs don't count as covering a case. |
|
| 4416 | 4416 | if prong.guard == nil { |
|
| 4417 | 4417 | if let case ast::ProngArm::Binding(_) = prong.arm { |
|
| 4418 | 4418 | if hasValue { |
|
| 4419 | 4419 | throw emitError(self, prongNode, ErrorKind::DuplicateMatchPattern); |
|
| 4420 | 4420 | } |
|
| 4421 | - | hasValue = true; |
|
| 4421 | + | set hasValue = true; |
|
| 4422 | 4422 | } else if let case ast::ProngArm::Case(patterns) = prong.arm { |
|
| 4423 | 4423 | for pat in patterns { |
|
| 4424 | 4424 | if let case ast::NodeValue::Nil = pat.value { |
|
| 4425 | 4425 | if hasNil { |
|
| 4426 | 4426 | throw emitError(self, pat, ErrorKind::DuplicateMatchPattern); |
|
| 4427 | 4427 | } |
|
| 4428 | - | hasNil = true; |
|
| 4428 | + | set hasNil = true; |
|
| 4429 | 4429 | } |
|
| 4430 | 4430 | } |
|
| 4431 | 4431 | } |
|
| 4432 | 4432 | } |
|
| 4433 | 4433 | } |
| 4463 | 4463 | ||
| 4464 | 4464 | for prongNode in prongs { |
|
| 4465 | 4465 | let case ast::NodeValue::MatchProng(prong) = prongNode.value |
|
| 4466 | 4466 | else panic "resolveMatchUnion: expected match prong"; |
|
| 4467 | 4467 | ||
| 4468 | - | matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy); |
|
| 4468 | + | set matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy); |
|
| 4469 | 4469 | ||
| 4470 | 4470 | // Guarded prongs don't count as covering. Patterns with nested |
|
| 4471 | 4471 | // refining sub-patterns (e.g. matching different inner union variants) |
|
| 4472 | 4472 | // don't count as duplicates or as fully covering. |
|
| 4473 | 4473 | if prong.guard == nil { |
| 4476 | 4476 | if let case NodeExtra::UnionVariant { ordinal: ix, .. } = self.nodeData.entries[pattern.id].extra { |
|
| 4477 | 4477 | if not hasNestedRefiningPattern(self, pattern) { |
|
| 4478 | 4478 | if covered[ix] { |
|
| 4479 | 4479 | throw emitError(self, pattern, ErrorKind::DuplicateMatchPattern); |
|
| 4480 | 4480 | } |
|
| 4481 | - | covered[ix] = true; |
|
| 4482 | - | coveredCount += 1; |
|
| 4481 | + | set covered[ix] = true; |
|
| 4482 | + | set coveredCount += 1; |
|
| 4483 | 4483 | } |
|
| 4484 | 4484 | } |
|
| 4485 | 4485 | } |
|
| 4486 | 4486 | } |
|
| 4487 | 4487 | } |
| 4515 | 4515 | ||
| 4516 | 4516 | for prongNode in prongs { |
|
| 4517 | 4517 | let case ast::NodeValue::MatchProng(prong) = prongNode.value |
|
| 4518 | 4518 | else panic "resolveMatchGeneric: expected match prong"; |
|
| 4519 | 4519 | ||
| 4520 | - | matchType = try resolveMatchProng( |
|
| 4520 | + | set matchType = try resolveMatchProng( |
|
| 4521 | 4521 | self, prongNode, prong, subjectTy, &mut state, matchType, MatchBy::Value |
|
| 4522 | 4522 | ); |
|
| 4523 | 4523 | // Track boolean coverage. Guarded prongs don't count as covering. |
|
| 4524 | 4524 | if let case ast::ProngArm::Case(patterns) = prong.arm { |
|
| 4525 | 4525 | for p in patterns { |
| 4527 | 4527 | if let case ast::NodeValue::Bool(val) = p.value { |
|
| 4528 | 4528 | if (val and hasTrue) or (not val and hasFalse) { |
|
| 4529 | 4529 | throw emitError(self, p, ErrorKind::DuplicateMatchPattern); |
|
| 4530 | 4530 | } |
|
| 4531 | 4531 | if val { |
|
| 4532 | - | hasTrue = true; |
|
| 4532 | + | set hasTrue = true; |
|
| 4533 | 4533 | } else { |
|
| 4534 | - | hasFalse = true; |
|
| 4534 | + | set hasFalse = true; |
|
| 4535 | 4535 | } |
|
| 4536 | 4536 | } |
|
| 4537 | 4537 | } |
|
| 4538 | 4538 | // Scalar constant patterns allow the match to be lowered |
|
| 4539 | 4539 | // to a switch instruction. |
|
| 4540 | 4540 | if let c = constValueEntry(self, p) { |
|
| 4541 | 4541 | match c { |
|
| 4542 | 4542 | case ConstValue::Bool(_), ConstValue::Char(_), ConstValue::Int(_) => |
|
| 4543 | - | hasConstCase = true, |
|
| 4543 | + | set hasConstCase = true, |
|
| 4544 | 4544 | else => |
|
| 4545 | - | state.isConst = false, |
|
| 4545 | + | set state.isConst = false, |
|
| 4546 | 4546 | } |
|
| 4547 | 4547 | } |
|
| 4548 | 4548 | } |
|
| 4549 | 4549 | } |
|
| 4550 | 4550 | } |
| 4601 | 4601 | match prong.arm { |
|
| 4602 | 4602 | case ast::ProngArm::Binding(pat) => { |
|
| 4603 | 4603 | // For optionals, bind the unwrapped inner type. |
|
| 4604 | 4604 | let mut bindTy = subjectTy; |
|
| 4605 | 4605 | if let case Type::Optional(inner) = subjectTy { |
|
| 4606 | - | bindTy = *inner; |
|
| 4606 | + | set bindTy = *inner; |
|
| 4607 | 4607 | } |
|
| 4608 | 4608 | try bindPatternVar(self, pat, bindTy, matchBy); |
|
| 4609 | 4609 | } |
|
| 4610 | 4610 | case ast::ProngArm::Case(patterns) => { |
|
| 4611 | 4611 | for pattern in patterns { |
| 4696 | 4696 | throws (ResolveError) |
|
| 4697 | 4697 | { |
|
| 4698 | 4698 | let mut bindTy = ty; |
|
| 4699 | 4699 | match matchBy { |
|
| 4700 | 4700 | case MatchBy::Value => {} |
|
| 4701 | - | case MatchBy::Ref => bindTy = Type::Pointer { target: allocType(self, ty), mutable: false }, |
|
| 4702 | - | case MatchBy::MutRef => bindTy = Type::Pointer { target: allocType(self, ty), mutable: true }, |
|
| 4701 | + | case MatchBy::Ref => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: false }, |
|
| 4702 | + | case MatchBy::MutRef => set bindTy = Type::Pointer { target: allocType(self, ty), mutable: true }, |
|
| 4703 | 4703 | } |
|
| 4704 | 4704 | match binding.value { |
|
| 4705 | 4705 | case ast::NodeValue::Placeholder => { |
|
| 4706 | 4706 | // Nothing to do. |
|
| 4707 | 4707 | } |
| 4896 | 4896 | ||
| 4897 | 4897 | // Evaluate the built-in. |
|
| 4898 | 4898 | let mut value: u32 = undefined; |
|
| 4899 | 4899 | match kind { |
|
| 4900 | 4900 | case ast::Builtin::SizeOf => { |
|
| 4901 | - | value = layout.size; |
|
| 4901 | + | set value = layout.size; |
|
| 4902 | 4902 | }, |
|
| 4903 | 4903 | case ast::Builtin::AlignOf => { |
|
| 4904 | - | value = layout.alignment; |
|
| 4904 | + | set value = layout.alignment; |
|
| 4905 | 4905 | }, |
|
| 4906 | 4906 | case ast::Builtin::SliceOf => { |
|
| 4907 | 4907 | panic "unreachable: @sliceOf handled above"; |
|
| 4908 | 4908 | } |
|
| 4909 | 4909 | } |
| 4984 | 4984 | ||
| 4985 | 4985 | // Check if we have a trait method call, ie. callee is a trait object. |
|
| 4986 | 4986 | if let case ast::NodeValue::FieldAccess(access) = call.callee.value { |
|
| 4987 | 4987 | let mut parentTy = Type::Unknown; |
|
| 4988 | 4988 | if let t = typeFor(self, access.parent) { |
|
| 4989 | - | parentTy = t; |
|
| 4989 | + | set parentTy = t; |
|
| 4990 | 4990 | } |
|
| 4991 | 4991 | let subjectTy = autoDeref(parentTy); |
|
| 4992 | 4992 | ||
| 4993 | 4993 | if let case Type::TraitObject { traitInfo, mutable: objMutable } = subjectTy { |
|
| 4994 | 4994 | let methodName = try nodeName(self, access.child); |
| 5013 | 5013 | // If the parent is already a mutable pointer, the receiver is fine. |
|
| 5014 | 5014 | // Otherwise, check that the parent can yield a mutable borrow. |
|
| 5015 | 5015 | if method.mutable { |
|
| 5016 | 5016 | let mut isMutPtr = false; |
|
| 5017 | 5017 | if let case Type::Pointer { mutable, .. } = parentTy { |
|
| 5018 | - | isMutPtr = mutable; |
|
| 5018 | + | set isMutPtr = mutable; |
|
| 5019 | 5019 | } |
|
| 5020 | 5020 | if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) { |
|
| 5021 | 5021 | throw emitError(self, access.parent, ErrorKind::ImmutableBinding); |
|
| 5022 | 5022 | } |
|
| 5023 | 5023 | } |
|
| 5024 | 5024 | // Check arguments (excluding receiver). |
|
| 5025 | 5025 | try checkCallArgs(self, node, call, method.fnType, ctx); |
|
| 5026 | - | self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method }; |
|
| 5026 | + | set self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method }; |
|
| 5027 | 5027 | ||
| 5028 | 5028 | return setNodeType(self, node, *method.fnType.returnType); |
|
| 5029 | 5029 | } |
|
| 5030 | 5030 | } |
|
| 5031 | 5031 | } |
| 5065 | 5065 | // First argument must be assignable to the element type. |
|
| 5066 | 5066 | try checkAssignable(self, args[0], *elemType); |
|
| 5067 | 5067 | // Second argument: the allocator. We accept any type -- the lowerer |
|
| 5068 | 5068 | // reads `.func` and `.ctx` at fixed offsets. |
|
| 5069 | 5069 | try visit(self, args[1], Type::Unknown); |
|
| 5070 | - | self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType }; |
|
| 5070 | + | set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType }; |
|
| 5071 | 5071 | ||
| 5072 | 5072 | // Return the parent's type so the caller can rebind: |
|
| 5073 | 5073 | return setNodeType(self, node, parentType); |
|
| 5074 | 5074 | } |
|
| 5075 | 5075 |
| 5090 | 5090 | expected: 1, |
|
| 5091 | 5091 | actual: args.len as u32, |
|
| 5092 | 5092 | })); |
|
| 5093 | 5093 | } |
|
| 5094 | 5094 | try checkAssignable(self, args[0], Type::U32); |
|
| 5095 | - | self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType }; |
|
| 5095 | + | set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType }; |
|
| 5096 | 5096 | ||
| 5097 | 5097 | return setNodeType(self, node, Type::Void); |
|
| 5098 | 5098 | } |
|
| 5099 | 5099 | ||
| 5100 | 5100 | /// Analyze an assignment expression. |
| 5116 | 5116 | let mut capacity: ?u32 = nil; |
|
| 5117 | 5117 | ||
| 5118 | 5118 | match subjectTy { |
|
| 5119 | 5119 | case Type::Array(a) => { |
|
| 5120 | 5120 | try validateArraySliceBounds(self, range, a.length, node); |
|
| 5121 | - | item = a.item; |
|
| 5122 | - | capacity = a.length; |
|
| 5121 | + | set item = a.item; |
|
| 5122 | + | set capacity = a.length; |
|
| 5123 | 5123 | } |
|
| 5124 | 5124 | case Type::Slice { item: i, mutable } => { |
|
| 5125 | 5125 | if not mutable { throw emitError(self, container, ErrorKind::ImmutableBinding); } |
|
| 5126 | - | item = i; |
|
| 5126 | + | set item = i; |
|
| 5127 | 5127 | } |
|
| 5128 | 5128 | else => throw emitError(self, container, ErrorKind::ExpectedIndexable), |
|
| 5129 | 5129 | } |
|
| 5130 | 5130 | // RHS is either a fill value or a source slice. |
|
| 5131 | 5131 | let rhsTy = try infer(self, assign.right); |
| 5168 | 5168 | let mut startVal: ?u32 = nil; |
|
| 5169 | 5169 | let mut endVal: ?u32 = length; |
|
| 5170 | 5170 | ||
| 5171 | 5171 | if let startNode = range.start { |
|
| 5172 | 5172 | if let val = constSliceIndex(self, startNode) { |
|
| 5173 | - | startVal = val; |
|
| 5173 | + | set startVal = val; |
|
| 5174 | 5174 | } |
|
| 5175 | 5175 | } |
|
| 5176 | 5176 | if let endNode = range.end { |
|
| 5177 | 5177 | if let val = constSliceIndex(self, endNode) { |
|
| 5178 | - | endVal = val; |
|
| 5178 | + | set endVal = val; |
|
| 5179 | 5179 | } |
|
| 5180 | 5180 | } |
|
| 5181 | 5181 | if let val = startVal; val >= length { |
|
| 5182 | 5182 | throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds); |
|
| 5183 | 5183 | } |
| 5410 | 5410 | throws (ResolveError) |
|
| 5411 | 5411 | { |
|
| 5412 | 5412 | // Unwrap optional hint to get the inner record type. |
|
| 5413 | 5413 | let mut innerHint = hint; |
|
| 5414 | 5414 | if let case Type::Optional(inner) = hint { |
|
| 5415 | - | innerHint = *inner; |
|
| 5415 | + | set innerHint = *inner; |
|
| 5416 | 5416 | } |
|
| 5417 | 5417 | let mut hintInfo: ?RecordType = nil; |
|
| 5418 | 5418 | if let case Type::Nominal(info) = innerHint { |
|
| 5419 | 5419 | try ensureNominalResolved(self, info, node); |
|
| 5420 | 5420 | if let case NominalType::Record(s) = *info { |
|
| 5421 | - | hintInfo = s; |
|
| 5421 | + | set hintInfo = s; |
|
| 5422 | 5422 | } |
|
| 5423 | 5423 | } |
|
| 5424 | 5424 | let targetInfo = hintInfo else { |
|
| 5425 | 5425 | throw emitError(self, node, ErrorKind::CannotInferType); |
|
| 5426 | 5426 | }; |
| 5469 | 5469 | { |
|
| 5470 | 5470 | let length = items.len; |
|
| 5471 | 5471 | let mut expectedTy: Type = Type::Unknown; |
|
| 5472 | 5472 | ||
| 5473 | 5473 | if let case Type::Array(ary) = hint { |
|
| 5474 | - | expectedTy = *ary.item; |
|
| 5474 | + | set expectedTy = *ary.item; |
|
| 5475 | 5475 | } else if let case Type::Optional(inner) = hint { |
|
| 5476 | 5476 | if let case Type::Array(ary) = *inner { |
|
| 5477 | - | expectedTy = *ary.item; |
|
| 5477 | + | set expectedTy = *ary.item; |
|
| 5478 | 5478 | } |
|
| 5479 | 5479 | }; |
|
| 5480 | 5480 | for itemNode in items { |
|
| 5481 | 5481 | let itemTy = try visit(self, itemNode, expectedTy); |
|
| 5482 | 5482 | assert itemTy <> Type::Unknown; |
|
| 5483 | 5483 | ||
| 5484 | 5484 | // Set the expected type to the first type we encounter. |
|
| 5485 | 5485 | if expectedTy == Type::Unknown { |
|
| 5486 | - | expectedTy = itemTy; |
|
| 5486 | + | set expectedTy = itemTy; |
|
| 5487 | 5487 | } else { |
|
| 5488 | 5488 | try expectAssignable(self, expectedTy, itemTy, itemNode); |
|
| 5489 | 5489 | } |
|
| 5490 | 5490 | } |
|
| 5491 | 5491 | if expectedTy == Type::Unknown { |
| 5499 | 5499 | fn resolveArrayRepeat(self: *mut Resolver, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type |
|
| 5500 | 5500 | throws (ResolveError) |
|
| 5501 | 5501 | { |
|
| 5502 | 5502 | let mut itemHint = hint; |
|
| 5503 | 5503 | if let case Type::Array(ary) = hint { |
|
| 5504 | - | itemHint = *ary.item; |
|
| 5504 | + | set itemHint = *ary.item; |
|
| 5505 | 5505 | } else if let case Type::Optional(inner) = hint { |
|
| 5506 | 5506 | if let case Type::Array(ary) = *inner { |
|
| 5507 | - | itemHint = *ary.item; |
|
| 5507 | + | set itemHint = *ary.item; |
|
| 5508 | 5508 | } |
|
| 5509 | 5509 | } |
|
| 5510 | 5510 | let valueTy = try visit(self, lit.item, itemHint); |
|
| 5511 | 5511 | let count = try checkSizeInt(self, lit.count); |
|
| 5512 | 5512 | let arrayTy = Type::Array(ArrayType { |
| 5552 | 5552 | let mut ty: Type = undefined; |
|
| 5553 | 5553 | ||
| 5554 | 5554 | match sym.data { |
|
| 5555 | 5555 | case SymbolData::Value { type, .. } => { |
|
| 5556 | 5556 | setNodeSymbol(self, node, sym); |
|
| 5557 | - | ty = type; |
|
| 5557 | + | set ty = type; |
|
| 5558 | 5558 | } |
|
| 5559 | 5559 | case SymbolData::Constant { type, value } => { |
|
| 5560 | 5560 | // Propagate the constant value. |
|
| 5561 | 5561 | if let val = value { |
|
| 5562 | 5562 | setNodeConstValue(self, node, val); |
|
| 5563 | 5563 | } |
|
| 5564 | 5564 | setNodeSymbol(self, node, sym); |
|
| 5565 | - | ty = type; |
|
| 5565 | + | set ty = type; |
|
| 5566 | 5566 | } |
|
| 5567 | 5567 | case SymbolData::Type(t) => { |
|
| 5568 | 5568 | setNodeSymbol(self, node, sym); |
|
| 5569 | - | ty = Type::Nominal(t); |
|
| 5569 | + | set ty = Type::Nominal(t); |
|
| 5570 | 5570 | } |
|
| 5571 | 5571 | case SymbolData::Variant { index, .. } => { |
|
| 5572 | 5572 | let ty = typeFor(self, node) |
|
| 5573 | 5573 | else throw emitError(self, node, ErrorKind::Internal); |
|
| 5574 | 5574 | // For unions without payload, store the variant index as a constant. |
| 5781 | 5781 | let mut capacity: ?u32 = nil; |
|
| 5782 | 5782 | ||
| 5783 | 5783 | match subjectTy { |
|
| 5784 | 5784 | case Type::Array(arrayInfo) => { |
|
| 5785 | 5785 | try validateArraySliceBounds(self, range, arrayInfo.length, node); |
|
| 5786 | - | item = arrayInfo.item; |
|
| 5787 | - | capacity = arrayInfo.length; |
|
| 5786 | + | set item = arrayInfo.item; |
|
| 5787 | + | set capacity = arrayInfo.length; |
|
| 5788 | 5788 | } |
|
| 5789 | 5789 | case Type::Slice { item: sliceItem, mutable } => { |
|
| 5790 | 5790 | if addr.mutable and not mutable { |
|
| 5791 | 5791 | throw emitError(self, addr.target, ErrorKind::ImmutableBinding); |
|
| 5792 | 5792 | } |
|
| 5793 | - | item = sliceItem; |
|
| 5793 | + | set item = sliceItem; |
|
| 5794 | 5794 | } |
|
| 5795 | 5795 | else => { |
|
| 5796 | 5796 | throw emitError(self, container, ErrorKind::ExpectedIndexable); |
|
| 5797 | 5797 | } |
|
| 5798 | 5798 | } |
| 5808 | 5808 | } |
|
| 5809 | 5809 | } |
|
| 5810 | 5810 | // Derive a hint for the target type from the slice hint. |
|
| 5811 | 5811 | let mut targetHint: Type = Type::Unknown; |
|
| 5812 | 5812 | if let case Type::Slice { item, .. } = hint { |
|
| 5813 | - | targetHint = Type::Array(ArrayType { item, length: 0 }); |
|
| 5813 | + | set targetHint = Type::Array(ArrayType { item, length: 0 }); |
|
| 5814 | 5814 | } |
|
| 5815 | 5815 | let targetTy = try visit(self, addr.target, targetHint); |
|
| 5816 | 5816 | ||
| 5817 | 5817 | // Mark local variable symbols as address-taken so the lowerer |
|
| 5818 | 5818 | // allocates a stack slot eagerly. |
|
| 5819 | 5819 | if let case ast::NodeValue::Ident(name) = addr.target.value { |
|
| 5820 | 5820 | if let sym = findValueSymbol(self.scope, name) { |
|
| 5821 | 5821 | match &mut sym.data { |
|
| 5822 | 5822 | case SymbolData::Value { addressTaken, .. } => { |
|
| 5823 | - | *addressTaken = true; |
|
| 5823 | + | set *addressTaken = true; |
|
| 5824 | 5824 | } |
|
| 5825 | 5825 | else => {} |
|
| 5826 | 5826 | } |
|
| 5827 | 5827 | } |
|
| 5828 | 5828 | } |
| 5981 | 5981 | let mut resolvedTy = startTy; |
|
| 5982 | 5982 | ||
| 5983 | 5983 | // Infer unsuffixed integer literals from the opposite bound. |
|
| 5984 | 5984 | if startTy == Type::Int and endTy <> Type::Int { |
|
| 5985 | 5985 | let _ = try checkAssignable(self, s, endTy); |
|
| 5986 | - | resolvedTy = endTy; |
|
| 5986 | + | set resolvedTy = endTy; |
|
| 5987 | 5987 | } else if endTy == Type::Int and startTy <> Type::Int { |
|
| 5988 | 5988 | let _ = try checkAssignable(self, e, startTy); |
|
| 5989 | - | resolvedTy = startTy; |
|
| 5989 | + | set resolvedTy = startTy; |
|
| 5990 | 5990 | } else { |
|
| 5991 | 5991 | let _ = try checkAssignable(self, e, startTy); |
|
| 5992 | 5992 | } |
|
| 5993 | - | start = allocType(self, resolvedTy); |
|
| 5994 | - | end = allocType(self, resolvedTy); |
|
| 5993 | + | set start = allocType(self, resolvedTy); |
|
| 5994 | + | set end = allocType(self, resolvedTy); |
|
| 5995 | 5995 | } else { |
|
| 5996 | - | start = allocType(self, startTy); |
|
| 5996 | + | set start = allocType(self, startTy); |
|
| 5997 | 5997 | } |
|
| 5998 | 5998 | } else if let e = range.end { |
|
| 5999 | - | end = allocType(self, try checkNumeric(self, e)); |
|
| 5999 | + | set end = allocType(self, try checkNumeric(self, e)); |
|
| 6000 | 6000 | } |
|
| 6001 | 6001 | return setNodeType(self, node, Type::Range { start, end }); |
|
| 6002 | 6002 | } |
|
| 6003 | 6003 | ||
| 6004 | 6004 | /// Analyze a `try` expression and its handlers. |
| 6028 | 6028 | if tryExpr.returnsOptional { |
|
| 6029 | 6029 | // `try?` converts errors to `nil` and wraps the result in an optional. |
|
| 6030 | 6030 | if let case Type::Optional(_) = resultTy { |
|
| 6031 | 6031 | // Already optional, no wrapping needed. |
|
| 6032 | 6032 | } else { |
|
| 6033 | - | tryResultTy = Type::Optional(allocType(self, resultTy)); |
|
| 6033 | + | set tryResultTy = Type::Optional(allocType(self, resultTy)); |
|
| 6034 | 6034 | } |
|
| 6035 | 6035 | } else if tryExpr.catches.len > 0 { |
|
| 6036 | 6036 | // `try ... catch` -- one or more catch clauses. |
|
| 6037 | - | tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint); |
|
| 6037 | + | set tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint); |
|
| 6038 | 6038 | } else if not tryExpr.shouldPanic { |
|
| 6039 | 6039 | let fnInfo = self.currentFn |
|
| 6040 | 6040 | else throw emitError(self, node, ErrorKind::TryRequiresThrows); |
|
| 6041 | 6041 | if fnInfo.throwList.len == 0 { |
|
| 6042 | 6042 | throw emitError(self, node, ErrorKind::TryRequiresThrows); |
| 6046 | 6046 | for throwTy in calleeInfo.throwList { |
|
| 6047 | 6047 | let mut found = false; |
|
| 6048 | 6048 | ||
| 6049 | 6049 | for callerThrowTy in fnInfo.throwList { |
|
| 6050 | 6050 | if callerThrowTy == throwTy { |
|
| 6051 | - | found = true; |
|
| 6051 | + | set found = true; |
|
| 6052 | 6052 | break; |
|
| 6053 | 6053 | } |
|
| 6054 | 6054 | } |
|
| 6055 | 6055 | if not found { |
|
| 6056 | 6056 | throw emitError(self, node, ErrorKind::TryIncompatibleError); |
| 6136 | 6136 | let errTy = try infer(self, typeNode); |
|
| 6137 | 6137 | let mut foundIdx: ?u32 = nil; |
|
| 6138 | 6138 | ||
| 6139 | 6139 | for throwType, j in calleeInfo.throwList { |
|
| 6140 | 6140 | if errTy == *throwType { |
|
| 6141 | - | foundIdx = j; |
|
| 6141 | + | set foundIdx = j; |
|
| 6142 | 6142 | break; |
|
| 6143 | 6143 | } |
|
| 6144 | 6144 | } |
|
| 6145 | 6145 | let idx = foundIdx else { |
|
| 6146 | 6146 | throw emitError(self, typeNode, ErrorKind::TryIncompatibleError); |
|
| 6147 | 6147 | }; |
|
| 6148 | 6148 | if covered[idx] { |
|
| 6149 | 6149 | throw emitError(self, typeNode, ErrorKind::TryCatchDuplicateType); |
|
| 6150 | 6150 | } |
|
| 6151 | - | covered[idx] = true; |
|
| 6151 | + | set covered[idx] = true; |
|
| 6152 | 6152 | ||
| 6153 | 6153 | // Bind the error variable if present. |
|
| 6154 | 6154 | if let binding = clause.binding { |
|
| 6155 | 6155 | enterScope(self, clauseNode); |
|
| 6156 | 6156 | try bindValueIdent(self, binding, binding, errTy, false, 0, 0); |
|
| 6157 | 6157 | } |
|
| 6158 | 6158 | } else { |
|
| 6159 | 6159 | // Catch-all clause with no type annotation or binding. |
|
| 6160 | - | hasCatchAll = true; |
|
| 6160 | + | set hasCatchAll = true; |
|
| 6161 | 6161 | } |
|
| 6162 | 6162 | // Resolve the catch body and check assignability. |
|
| 6163 | 6163 | try visit(self, clause.body, resultTy); |
|
| 6164 | 6164 | // Only typed clauses can have bindings. |
|
| 6165 | 6165 | if let _ = clause.binding { |
| 6250 | 6250 | /// Returns the resulting constant value if successful. |
|
| 6251 | 6251 | fn foldIntBinOp(op: ast::BinaryOp, left: ConstInt, right: ConstInt) -> ?ConstValue { |
|
| 6252 | 6252 | // Use the wider bit width and propagate signedness. |
|
| 6253 | 6253 | let mut bits = left.bits; |
|
| 6254 | 6254 | if right.bits > bits { |
|
| 6255 | - | bits = right.bits; |
|
| 6255 | + | set bits = right.bits; |
|
| 6256 | 6256 | } |
|
| 6257 | 6257 | let signed = left.signed or right.signed; |
|
| 6258 | 6258 | let l = constIntToSigned(left); |
|
| 6259 | 6259 | let r = constIntToSigned(right); |
|
| 6260 | 6260 |
| 6343 | 6343 | ast::BinaryOp::Xor => |
|
| 6344 | 6344 | { |
|
| 6345 | 6345 | try checkBoolean(self, binop.left); |
|
| 6346 | 6346 | try checkBoolean(self, binop.right); |
|
| 6347 | 6347 | ||
| 6348 | - | resultTy = Type::Bool; |
|
| 6348 | + | set resultTy = Type::Bool; |
|
| 6349 | 6349 | }, |
|
| 6350 | 6350 | case ast::BinaryOp::Eq, |
|
| 6351 | 6351 | ast::BinaryOp::Ne => |
|
| 6352 | 6352 | { |
|
| 6353 | 6353 | let leftTy = try infer(self, binop.left); |
| 6371 | 6371 | setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy)); |
|
| 6372 | 6372 | } |
|
| 6373 | 6373 | } else if let case Type::Optional(_) = rightTy { |
|
| 6374 | 6374 | setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy)); |
|
| 6375 | 6375 | } |
|
| 6376 | - | resultTy = Type::Bool; |
|
| 6376 | + | set resultTy = Type::Bool; |
|
| 6377 | 6377 | }, |
|
| 6378 | 6378 | else => { |
|
| 6379 | 6379 | // Check for pointer arithmetic before numeric check. |
|
| 6380 | 6380 | if binop.op == ast::BinaryOp::Add or binop.op == ast::BinaryOp::Sub { |
|
| 6381 | 6381 | let leftTy = try infer(self, binop.left); |
| 6403 | 6403 | ||
| 6404 | 6404 | // Ordering comparisons return `bool`, not the operand type. |
|
| 6405 | 6405 | match binop.op { |
|
| 6406 | 6406 | case ast::BinaryOp::Lt, ast::BinaryOp::Gt, |
|
| 6407 | 6407 | ast::BinaryOp::Lte, ast::BinaryOp::Gte => { |
|
| 6408 | - | resultTy = Type::Bool; |
|
| 6408 | + | set resultTy = Type::Bool; |
|
| 6409 | 6409 | } else => { |
|
| 6410 | 6410 | if leftTy == rightTy { |
|
| 6411 | - | resultTy = leftTy; |
|
| 6411 | + | set resultTy = leftTy; |
|
| 6412 | 6412 | } else if leftTy == Type::Int { |
|
| 6413 | - | resultTy = rightTy; |
|
| 6413 | + | set resultTy = rightTy; |
|
| 6414 | 6414 | } else if rightTy == Type::Int { |
|
| 6415 | - | resultTy = leftTy; |
|
| 6415 | + | set resultTy = leftTy; |
|
| 6416 | 6416 | } else { |
|
| 6417 | 6417 | throw emitTypeMismatch(self, binop.right, TypeMismatch { |
|
| 6418 | 6418 | expected: leftTy, |
|
| 6419 | 6419 | actual: rightTy, |
|
| 6420 | 6420 | }); |
| 6436 | 6436 | { |
|
| 6437 | 6437 | let mut resultTy = Type::Unknown; |
|
| 6438 | 6438 | ||
| 6439 | 6439 | match unop.op { |
|
| 6440 | 6440 | case ast::UnaryOp::Not => { |
|
| 6441 | - | resultTy = try checkBoolean(self, unop.value); |
|
| 6441 | + | set resultTy = try checkBoolean(self, unop.value); |
|
| 6442 | 6442 | if let value = constValueEntry(self, unop.value) { |
|
| 6443 | 6443 | if let case ConstValue::Bool(val) = value { |
|
| 6444 | 6444 | setNodeConstValue(self, node, ConstValue::Bool(not val)); |
|
| 6445 | 6445 | } |
|
| 6446 | 6446 | } |
|
| 6447 | 6447 | }, |
|
| 6448 | 6448 | case ast::UnaryOp::Neg => { |
|
| 6449 | 6449 | // TODO: Check that we're allowed to use `-` here? Should negation |
|
| 6450 | 6450 | // only be valid for signed integers? |
|
| 6451 | - | resultTy = try checkNumeric(self, unop.value); |
|
| 6451 | + | set resultTy = try checkNumeric(self, unop.value); |
|
| 6452 | 6452 | if let value = constValueEntry(self, unop.value) { |
|
| 6453 | 6453 | // Get the constant expression for the value, flip the sign, |
|
| 6454 | 6454 | // and store that new expression on the unary op node. |
|
| 6455 | 6455 | if let case ConstValue::Int(intVal) = value { |
|
| 6456 | 6456 | setNodeConstValue( |
| 6460 | 6460 | ); |
|
| 6461 | 6461 | } |
|
| 6462 | 6462 | } |
|
| 6463 | 6463 | }, |
|
| 6464 | 6464 | case ast::UnaryOp::BitNot => { |
|
| 6465 | - | resultTy = try checkNumeric(self, unop.value); |
|
| 6465 | + | set resultTy = try checkNumeric(self, unop.value); |
|
| 6466 | 6466 | if let value = constValueEntry(self, unop.value) { |
|
| 6467 | 6467 | if let case ConstValue::Int(intVal) = value { |
|
| 6468 | 6468 | let signed = constIntToSigned(intVal); |
|
| 6469 | 6469 | let inverted = constIntFromSigned(-(signed + 1), intVal.bits, intVal.signed); |
|
| 6470 | 6470 | setNodeConstValue(self, node, ConstValue::Int(inverted)); |
| 6569 | 6569 | let throwTy = try infer(self, tyNode); |
|
| 6570 | 6570 | throwList.append(allocType(self, throwTy), a); |
|
| 6571 | 6571 | } |
|
| 6572 | 6572 | let mut retType = allocType(self, Type::Void); |
|
| 6573 | 6573 | if let ret = t.returnType { |
|
| 6574 | - | retType = allocType(self, try infer(self, ret)); |
|
| 6574 | + | set retType = allocType(self, try infer(self, ret)); |
|
| 6575 | 6575 | } |
|
| 6576 | 6576 | let fnType = FnType { |
|
| 6577 | 6577 | paramTypes: ¶mTypes[..], |
|
| 6578 | 6578 | returnType: retType, |
|
| 6579 | 6579 | throwList: &throwList[..], |
| 6775 | 6775 | } |
|
| 6776 | 6776 | } |
|
| 6777 | 6777 | ||
| 6778 | 6778 | /// Resolve all packages. |
|
| 6779 | 6779 | export fn resolve(self: *mut Resolver, graph: *module::ModuleGraph, packages: *[Pkg]) -> Diagnostics throws (ResolveError) { |
|
| 6780 | - | self.moduleGraph = graph; |
|
| 6780 | + | set self.moduleGraph = graph; |
|
| 6781 | 6781 | ||
| 6782 | 6782 | // 1. Bind all package roots to enable cross-package references. |
|
| 6783 | 6783 | for i in 0..packages.len { |
|
| 6784 | 6784 | let pkg = &packages[i]; |
|
| 6785 | 6785 | // Enter a new scope for the module. |
| 6805 | 6805 | let rootId = rootEntry.id; |
|
| 6806 | 6806 | let scope = self.moduleScopes[rootId as u32] |
|
| 6807 | 6807 | else panic "resolvePackage: module scope not found"; |
|
| 6808 | 6808 | ||
| 6809 | 6809 | // Set up the module scope for this package. |
|
| 6810 | - | self.scope = scope; |
|
| 6811 | - | self.currentMod = rootId; |
|
| 6810 | + | set self.scope = scope; |
|
| 6811 | + | set self.currentMod = rootId; |
|
| 6812 | 6812 | ||
| 6813 | 6813 | let case ast::NodeValue::Block(block) = node.value |
|
| 6814 | 6814 | else panic "resolvePackage: expected block for module root"; |
|
| 6815 | 6815 | ||
| 6816 | 6816 | // Module graph analysis phase: bind all module name symbols and scopes. |
lib/std/lang/resolver/tests.rad
+41 -41
| 54 | 54 | for i in 0..LITERALS.len { |
|
| 55 | 55 | strings::intern(&mut STRING_POOL, LITERALS[i]); |
|
| 56 | 56 | } |
|
| 57 | 57 | // TODO: Use local static for this. |
|
| 58 | 58 | // Reset the module graph for each test. |
|
| 59 | - | MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]); |
|
| 60 | - | MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut STRING_POOL, &mut MODULE_ARENA); |
|
| 59 | + | set MODULE_ARENA = ast::nodeArena(&mut MODULE_ARENA_STORAGE[..]); |
|
| 60 | + | set MODULE_GRAPH = module::moduleGraph(&mut MODULE_ENTRIES[..], &mut STRING_POOL, &mut MODULE_ARENA); |
|
| 61 | 61 | let config = super::Config { buildTest: true }; |
|
| 62 | 62 | let res = super::resolver(testStorage(), config); |
|
| 63 | 63 | ||
| 64 | 64 | return res; |
|
| 65 | 65 | } |
| 151 | 151 | arena: *mut ast::NodeArena |
|
| 152 | 152 | ) -> u16 throws (testing::TestError) { |
|
| 153 | 153 | let filePath = "<test>"; |
|
| 154 | 154 | let mut modId: u16 = undefined; |
|
| 155 | 155 | if let parent = parentId { |
|
| 156 | - | modId = try module::registerChild(graph, parent, name, filePath) catch { |
|
| 156 | + | set modId = try module::registerChild(graph, parent, name, filePath) catch { |
|
| 157 | 157 | throw testing::TestError::Failed; |
|
| 158 | 158 | }; |
|
| 159 | 159 | } else { |
|
| 160 | - | modId = try module::registerRootWithName(graph, 0, name, filePath) catch { |
|
| 160 | + | set modId = try module::registerRootWithName(graph, 0, name, filePath) catch { |
|
| 161 | 161 | throw testing::TestError::Failed; |
|
| 162 | 162 | }; |
|
| 163 | 163 | } |
|
| 164 | 164 | let root = try parser::parse(scanner::SourceLoc::String, code, arena, &mut STRING_POOL) catch { |
|
| 165 | 165 | panic "registerModule: parsing failed"; |
| 1719 | 1719 | } |
|
| 1720 | 1720 | ||
| 1721 | 1721 | @test fn testResolveAssign() throws (testing::TestError) { |
|
| 1722 | 1722 | { |
|
| 1723 | 1723 | let mut a = testResolver(); |
|
| 1724 | - | let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; x = 1;"); |
|
| 1724 | + | let result = try resolveProgramStr(&mut a, "let mut x: i32 = 0; set x = 1;"); |
|
| 1725 | 1725 | try expectNoErrors(&result); |
|
| 1726 | 1726 | } { |
|
| 1727 | 1727 | let mut a = testResolver(); |
|
| 1728 | - | let result = try resolveProgramStr(&mut a, "let x: i32 = 0; x = 1;"); |
|
| 1728 | + | let result = try resolveProgramStr(&mut a, "let x: i32 = 0; set x = 1;"); |
|
| 1729 | 1729 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 1730 | 1730 | } { |
|
| 1731 | 1731 | let mut a = testResolver(); |
|
| 1732 | - | let result = try resolveProgramStr(&mut a, "let mut x: bool = false; x = 1;"); |
|
| 1732 | + | let result = try resolveProgramStr(&mut a, "let mut x: bool = false; set x = 1;"); |
|
| 1733 | 1733 | let err = try expectError(&result); |
|
| 1734 | 1734 | try expectTypeMismatch(err, super::Type::Bool, super::Type::Int); |
|
| 1735 | 1735 | } { |
|
| 1736 | 1736 | let mut a = testResolver(); |
|
| 1737 | - | let result = try resolveProgramStr(&mut a, "x = 1;"); |
|
| 1737 | + | let result = try resolveProgramStr(&mut a, "set x = 1;"); |
|
| 1738 | 1738 | try expectErrorKind(&result, super::ErrorKind::UnresolvedSymbol("x")); |
|
| 1739 | 1739 | } { |
|
| 1740 | 1740 | let mut a = testResolver(); |
|
| 1741 | - | let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = 1;"); |
|
| 1741 | + | let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = 1;"); |
|
| 1742 | 1742 | try expectNoErrors(&result); |
|
| 1743 | 1743 | } { |
|
| 1744 | 1744 | let mut a = testResolver(); |
|
| 1745 | - | let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; x = nil;"); |
|
| 1745 | + | let result = try resolveProgramStr(&mut a, "let mut x: ?i32 = 0; set x = nil;"); |
|
| 1746 | 1746 | try expectNoErrors(&result); |
|
| 1747 | 1747 | } |
|
| 1748 | 1748 | } |
|
| 1749 | 1749 | ||
| 1750 | 1750 | @test fn testResolveAssignSubscript() throws (testing::TestError) { |
|
| 1751 | 1751 | { |
|
| 1752 | 1752 | let mut a = testResolver(); |
|
| 1753 | - | let program = "let mut xs: [u8; 2] = [0, 1]; xs[0] = 9;"; |
|
| 1753 | + | let program = "let mut xs: [u8; 2] = [0, 1]; set xs[0] = 9;"; |
|
| 1754 | 1754 | let result = try resolveProgramStr(&mut a, program); |
|
| 1755 | 1755 | try expectNoErrors(&result); |
|
| 1756 | 1756 | } |
|
| 1757 | 1757 | { |
|
| 1758 | 1758 | let mut a = testResolver(); |
|
| 1759 | - | let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; slice[0] = 1;"; |
|
| 1759 | + | let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *mut [u8] = &mut xs[..]; set slice[0] = 1;"; |
|
| 1760 | 1760 | let result = try resolveProgramStr(&mut a, program); |
|
| 1761 | 1761 | try expectNoErrors(&result); |
|
| 1762 | 1762 | } |
|
| 1763 | 1763 | { |
|
| 1764 | 1764 | let mut a = testResolver(); |
|
| 1765 | - | let program = "let mut xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; slice[0] = 1;"; |
|
| 1765 | + | let program = "let mut xs: [u8; 2] = [0, 1]; let mut slice: *[u8] = &xs[..]; set slice[0] = 1;"; |
|
| 1766 | 1766 | let result = try resolveProgramStr(&mut a, program); |
|
| 1767 | 1767 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 1768 | 1768 | } |
|
| 1769 | 1769 | { |
|
| 1770 | 1770 | let mut a = testResolver(); |
|
| 1771 | - | let program = "let xs: [u8; 2] = [0, 1]; xs[0] = 9;"; |
|
| 1771 | + | let program = "let xs: [u8; 2] = [0, 1]; set xs[0] = 9;"; |
|
| 1772 | 1772 | let result = try resolveProgramStr(&mut a, program); |
|
| 1773 | 1773 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 1774 | 1774 | } |
|
| 1775 | 1775 | { |
|
| 1776 | 1776 | let mut a = testResolver(); |
|
| 1777 | - | let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; slice[0] = 1;"; |
|
| 1777 | + | let program = "let mut xs: [u8; 2] = [0, 1]; let slice: *[u8] = &xs[..]; set slice[0] = 1;"; |
|
| 1778 | 1778 | let result = try resolveProgramStr(&mut a, program); |
|
| 1779 | 1779 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 1780 | 1780 | } |
|
| 1781 | 1781 | } |
|
| 1782 | 1782 |
| 2096 | 2096 | let mut a = testResolver(); |
|
| 2097 | 2097 | let result = try resolveBlockStr(&mut a, "let count: i32 = undefined;"); |
|
| 2098 | 2098 | try expectNoErrors(&result); |
|
| 2099 | 2099 | } { |
|
| 2100 | 2100 | let mut a = testResolver(); |
|
| 2101 | - | let program = "let mut value: i32 = 0; value = undefined;"; |
|
| 2101 | + | let program = "let mut value: i32 = 0; set value = undefined;"; |
|
| 2102 | 2102 | let result = try resolveProgramStr(&mut a, program); |
|
| 2103 | 2103 | try expectNoErrors(&result); |
|
| 2104 | 2104 | } { |
|
| 2105 | 2105 | let mut a = testResolver(); |
|
| 2106 | 2106 | let program = "fn f(x: i32) {} fn g() { f(undefined); }"; |
| 2200 | 2200 | } |
|
| 2201 | 2201 | ||
| 2202 | 2202 | /// Test that `if let mut` produces a mutable binding. |
|
| 2203 | 2203 | @test fn testResolveIfLetMut() throws (testing::TestError) { |
|
| 2204 | 2204 | let mut a = testResolver(); |
|
| 2205 | - | let program = "let opt: ?i32 = 42; if let mut v = opt { v = v + 1; }"; |
|
| 2205 | + | let program = "let opt: ?i32 = 42; if let mut v = opt { set v = v + 1; }"; |
|
| 2206 | 2206 | let result = try resolveProgramStr(&mut a, program); |
|
| 2207 | 2207 | try expectNoErrors(&result); |
|
| 2208 | 2208 | } |
|
| 2209 | 2209 | ||
| 2210 | 2210 | /// Test that `if let` (without mut) rejects assignment. |
|
| 2211 | 2211 | @test fn testResolveIfLetImmutable() throws (testing::TestError) { |
|
| 2212 | 2212 | let mut a = testResolver(); |
|
| 2213 | - | let program = "let opt: ?i32 = 42; if let v = opt { v = 1; }"; |
|
| 2213 | + | let program = "let opt: ?i32 = 42; if let v = opt { set v = 1; }"; |
|
| 2214 | 2214 | let result = try resolveProgramStr(&mut a, program); |
|
| 2215 | 2215 | let err = try expectError(&result); |
|
| 2216 | 2216 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 2217 | 2217 | } |
|
| 2218 | 2218 | ||
| 2219 | 2219 | /// Test that `let mut ... else` produces a mutable binding. |
|
| 2220 | 2220 | @test fn testResolveLetMutElse() throws (testing::TestError) { |
|
| 2221 | 2221 | let mut a = testResolver(); |
|
| 2222 | - | let program = "let opt: ?i32 = 42; let mut v = opt else panic; v = v + 1;"; |
|
| 2222 | + | let program = "let opt: ?i32 = 42; let mut v = opt else panic; set v = v + 1;"; |
|
| 2223 | 2223 | let result = try resolveProgramStr(&mut a, program); |
|
| 2224 | 2224 | try expectNoErrors(&result); |
|
| 2225 | 2225 | } |
|
| 2226 | 2226 | ||
| 2227 | 2227 | /// Test that `let ... else` (without mut) rejects assignment. |
|
| 2228 | 2228 | @test fn testResolveLetElseImmutable() throws (testing::TestError) { |
|
| 2229 | 2229 | let mut a = testResolver(); |
|
| 2230 | - | let program = "let opt: ?i32 = 42; let v = opt else panic; v = 1;"; |
|
| 2230 | + | let program = "let opt: ?i32 = 42; let v = opt else panic; set v = 1;"; |
|
| 2231 | 2231 | let result = try resolveProgramStr(&mut a, program); |
|
| 2232 | 2232 | let err = try expectError(&result); |
|
| 2233 | 2233 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 2234 | 2234 | } |
|
| 2235 | 2235 |
| 2703 | 2703 | } |
|
| 2704 | 2704 | ||
| 2705 | 2705 | @test fn testResolveAssignDeref() throws (testing::TestError) { |
|
| 2706 | 2706 | { |
|
| 2707 | 2707 | let mut a = testResolver(); |
|
| 2708 | - | let program = "let mut x: i32 = 0; let ptr: *mut i32 = &mut x; *ptr = 42;"; |
|
| 2708 | + | let program = "let mut x: i32 = 0; let ptr: *mut i32 = &mut x; set *ptr = 42;"; |
|
| 2709 | 2709 | let result = try resolveProgramStr(&mut a, program); |
|
| 2710 | 2710 | try expectNoErrors(&result); |
|
| 2711 | 2711 | } { |
|
| 2712 | 2712 | let mut a = testResolver(); |
|
| 2713 | - | let program = "let mut x: i32 = 0; let ptr: *i32 = &x; *ptr = 42;"; |
|
| 2713 | + | let program = "let mut x: i32 = 0; let ptr: *i32 = &x; set *ptr = 42;"; |
|
| 2714 | 2714 | let result = try resolveProgramStr(&mut a, program); |
|
| 2715 | 2715 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 2716 | 2716 | } { |
|
| 2717 | 2717 | let mut a = testResolver(); |
|
| 2718 | - | let program = "let mut x: i32 = 0; let mut ptr: *i32 = &x; *ptr = 42;"; |
|
| 2718 | + | let program = "let mut x: i32 = 0; let mut ptr: *i32 = &x; set *ptr = 42;"; |
|
| 2719 | 2719 | let result = try resolveProgramStr(&mut a, program); |
|
| 2720 | 2720 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 2721 | 2721 | } { |
|
| 2722 | 2722 | let mut a = testResolver(); |
|
| 2723 | - | let program = "let mut x: u8 = 0; let mut ptr: *mut u8 = &mut x; *ptr = 255;"; |
|
| 2723 | + | let program = "let mut x: u8 = 0; let mut ptr: *mut u8 = &mut x; set *ptr = 255;"; |
|
| 2724 | 2724 | let result = try resolveProgramStr(&mut a, program); |
|
| 2725 | 2725 | try expectNoErrors(&result); |
|
| 2726 | 2726 | } |
|
| 2727 | 2727 | } |
|
| 2728 | 2728 |
| 3422 | 3422 | let mut a = testResolver(); |
|
| 3423 | 3423 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 3424 | 3424 | ||
| 3425 | 3425 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod statics; mod app;", &mut arena); |
|
| 3426 | 3426 | let staticsId = try registerModule(&mut MODULE_GRAPH, rootId, "statics", "export static COUNTER: i32 = 0;", &mut arena); |
|
| 3427 | - | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() { let p: *mut i32 = &mut statics::COUNTER; *p = 7; }", &mut arena); |
|
| 3427 | + | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::statics; fn main() { let p: *mut i32 = &mut statics::COUNTER; set *p = 7; }", &mut arena); |
|
| 3428 | 3428 | ||
| 3429 | 3429 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 3430 | 3430 | try expectNoErrors(&result); |
|
| 3431 | 3431 | } |
|
| 3432 | 3432 |
| 3435 | 3435 | let mut a = testResolver(); |
|
| 3436 | 3436 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 3437 | 3437 | ||
| 3438 | 3438 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena); |
|
| 3439 | 3439 | let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant LIMIT: i32 = 7;", &mut arena); |
|
| 3440 | - | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() { let p: *mut i32 = &mut consts::LIMIT; *p = 9; }", &mut arena); |
|
| 3440 | + | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; fn main() { let p: *mut i32 = &mut consts::LIMIT; set *p = 9; }", &mut arena); |
|
| 3441 | 3441 | ||
| 3442 | 3442 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 3443 | 3443 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 3444 | 3444 | } |
|
| 3445 | 3445 |
| 3455 | 3455 | /// Test that mutable pointer to immutable slice cannot be assigned through index. |
|
| 3456 | 3456 | /// This tests the case where we have `*mut *[T]`; the outer pointer is mutable but |
|
| 3457 | 3457 | /// the inner slice is immutable, so we shouldn't be able to mutate the elements. |
|
| 3458 | 3458 | @test fn testAssignThroughMutablePointerToImmutableSlice() throws (testing::TestError) { |
|
| 3459 | 3459 | let mut a = testResolver(); |
|
| 3460 | - | let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; p[0] = 1; }"; |
|
| 3460 | + | let program = "fn f(slice: *[i32]) { let p: *mut *[i32] = &mut slice; set p[0] = 1; }"; |
|
| 3461 | 3461 | let result = try resolveProgramStr(&mut a, program); |
|
| 3462 | 3462 | ||
| 3463 | 3463 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 3464 | 3464 | } |
|
| 3465 | 3465 | ||
| 3466 | 3466 | /// Test that mutable slice parameters can be assigned through index. |
|
| 3467 | 3467 | @test fn testAssignThroughMutableSliceParam() throws (testing::TestError) { |
|
| 3468 | 3468 | { |
|
| 3469 | 3469 | // Mutable slice param: direct assignment should work |
|
| 3470 | 3470 | let mut a = testResolver(); |
|
| 3471 | - | let program = "fn f(slice: *mut [i32]) { slice[0] = 1; }"; |
|
| 3471 | + | let program = "fn f(slice: *mut [i32]) { set slice[0] = 1; }"; |
|
| 3472 | 3472 | let result = try resolveProgramStr(&mut a, program); |
|
| 3473 | 3473 | try expectNoErrors(&result); |
|
| 3474 | 3474 | } { |
|
| 3475 | 3475 | // Immutable slice param: direct assignment should fail |
|
| 3476 | 3476 | let mut a = testResolver(); |
|
| 3477 | - | let program = "fn f(slice: *[i32]) { slice[0] = 1; }"; |
|
| 3477 | + | let program = "fn f(slice: *[i32]) { set slice[0] = 1; }"; |
|
| 3478 | 3478 | let result = try resolveProgramStr(&mut a, program); |
|
| 3479 | 3479 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 3480 | 3480 | } |
|
| 3481 | 3481 | } |
|
| 3482 | 3482 |
| 3545 | 3545 | } |
|
| 3546 | 3546 | ||
| 3547 | 3547 | /// Test that record fields can be assigned if the record binding is mutable. |
|
| 3548 | 3548 | @test fn testMutableAssignToMutableRecordBinding() throws (testing::TestError) { |
|
| 3549 | 3549 | let mut a = testResolver(); |
|
| 3550 | - | let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; s.x = 2; }"; |
|
| 3550 | + | let program = "record S { x: i32 } fn f() { let mut s = S { x: 1 }; set s.x = 2; }"; |
|
| 3551 | 3551 | let result = try resolveProgramStr(&mut a, program); |
|
| 3552 | 3552 | try expectNoErrors(&result); |
|
| 3553 | 3553 | } |
|
| 3554 | 3554 | ||
| 3555 | 3555 | /// Test that record fields cannot be assigned if the record binding is immutable. |
|
| 3556 | 3556 | @test fn testMutableAssignToImmutableRecordBinding() throws (testing::TestError) { |
|
| 3557 | 3557 | let mut a = testResolver(); |
|
| 3558 | - | let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; s.x = 2; }"; |
|
| 3558 | + | let program = "record S { x: i32 } fn f() { let s = S { x: 1 }; set s.x = 2; }"; |
|
| 3559 | 3559 | let result = try resolveProgramStr(&mut a, program); |
|
| 3560 | 3560 | let err = try expectError(&result); |
|
| 3561 | 3561 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 3562 | 3562 | } |
|
| 3563 | 3563 | ||
| 3564 | 3564 | /// Test that record fields can be assigned through a mutable pointer. |
|
| 3565 | 3565 | @test fn testMutableAssignToMutablePointerToRecord() throws (testing::TestError) { |
|
| 3566 | 3566 | let mut a = testResolver(); |
|
| 3567 | - | let program = "record S { x: i32 } fn f(p: *mut S) { p.x = 2; }"; |
|
| 3567 | + | let program = "record S { x: i32 } fn f(p: *mut S) { set p.x = 2; }"; |
|
| 3568 | 3568 | let result = try resolveProgramStr(&mut a, program); |
|
| 3569 | 3569 | try expectNoErrors(&result); |
|
| 3570 | 3570 | } |
|
| 3571 | 3571 | ||
| 3572 | 3572 | /// Test that record fields cannot be assigned through an immutable pointer. |
|
| 3573 | 3573 | @test fn testMutableAssignToImmutablePointerToRecord() throws (testing::TestError) { |
|
| 3574 | 3574 | let mut a = testResolver(); |
|
| 3575 | - | let program = "record S { x: i32 } fn f(p: *S) { p.x = 2; }"; |
|
| 3575 | + | let program = "record S { x: i32 } fn f(p: *S) { set p.x = 2; }"; |
|
| 3576 | 3576 | let result = try resolveProgramStr(&mut a, program); |
|
| 3577 | 3577 | let err = try expectError(&result); |
|
| 3578 | 3578 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 3579 | 3579 | } |
|
| 3580 | 3580 | ||
| 3581 | 3581 | // Opaque pointer tests. |
|
| 3582 | 3582 | ||
| 3583 | 3583 | /// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast. |
|
| 3584 | 3584 | @test fn testOpaquePointerAutoCoercion() throws (testing::TestError) { |
|
| 3585 | 3585 | let mut a = testResolver(); |
|
| 3586 | - | let result = try resolveProgramStr(&mut a, "fn f(x: i32) { let mut ptr: *i32 = &x; let o: *opaque = ptr; ptr = o as *i32; }"); |
|
| 3586 | + | let result = try resolveProgramStr(&mut a, "fn f(x: i32) { let mut ptr: *i32 = &x; let o: *opaque = ptr; set ptr = o as *i32; }"); |
|
| 3587 | 3587 | try expectNoErrors(&result); |
|
| 3588 | 3588 | } |
|
| 3589 | 3589 | ||
| 3590 | 3590 | /// You cannot assign an opaque pointer to a non-opaque pointer without a cast. |
|
| 3591 | 3591 | @test fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) { |
| 4766 | 4766 | ||
| 4767 | 4767 | /// Trait declares immutable receiver (*Trait) but instance uses mutable (*mut Type). |
|
| 4768 | 4768 | /// The instance method could mutate through what was originally an immutable pointer. |
|
| 4769 | 4769 | @test fn testResolveInstanceMutReceiverOnImmutableTrait() throws (testing::TestError) { |
|
| 4770 | 4770 | let mut a = testResolver(); |
|
| 4771 | - | let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { c.value = c.value + 1; return c.value; } }"; |
|
| 4771 | + | let program = "record Counter { value: i32 } trait Reader { fn (*Reader) read() -> i32; } instance Reader for Counter { fn (c: *mut Counter) read() -> i32 { set c.value = c.value + 1; return c.value; } }"; |
|
| 4772 | 4772 | let result = try resolveProgramStr(&mut a, program); |
|
| 4773 | 4773 | // Should reject: instance declares *mut receiver but trait only requires immutable. |
|
| 4774 | 4774 | try expectErrorKind(&result, super::ErrorKind::ReceiverMutabilityMismatch); |
|
| 4775 | 4775 | } |
|
| 4776 | 4776 | ||
| 4777 | 4777 | /// Instance method declares different parameter types than the trait. |
|
| 4778 | 4778 | /// The resolver should reject the mismatch rather than silently using the trait's types. |
|
| 4779 | 4779 | @test fn testResolveInstanceParamTypeMismatch() throws (testing::TestError) { |
|
| 4780 | 4780 | let mut a = testResolver(); |
|
| 4781 | - | let program = "record Acc { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Acc { fn (a: *mut Acc) add(n: u8) -> i32 { a.value = a.value + n as i32; return a.value; } }"; |
|
| 4781 | + | let program = "record Acc { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Acc { fn (a: *mut Acc) add(n: u8) -> i32 { set a.value = a.value + n as i32; return a.value; } }"; |
|
| 4782 | 4782 | let result = try resolveProgramStr(&mut a, program); |
|
| 4783 | 4783 | // Should reject: instance param type u8 doesn't match trait param type i32. |
|
| 4784 | 4784 | let err = try expectError(&result); |
|
| 4785 | 4785 | let case super::ErrorKind::TypeMismatch(_) = err.kind |
|
| 4786 | 4786 | else throw testing::TestError::Failed; |
|
| 4787 | 4787 | } |
|
| 4788 | 4788 | ||
| 4789 | 4789 | /// Duplicate instance declarations for the same (trait, type) pair should be rejected. |
|
| 4790 | 4790 | @test fn testResolveInstanceDuplicateRejected() throws (testing::TestError) { |
|
| 4791 | 4791 | let mut a = testResolver(); |
|
| 4792 | - | let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n + 100; return c.value; } }"; |
|
| 4792 | + | let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n + 100; return c.value; } }"; |
|
| 4793 | 4793 | let result = try resolveProgramStr(&mut a, program); |
|
| 4794 | 4794 | // Should reject: duplicate instance for (Adder, Counter). |
|
| 4795 | 4795 | try expectErrorKind(&result, super::ErrorKind::DuplicateInstance); |
|
| 4796 | 4796 | } |
|
| 4797 | 4797 |
| 4815 | 4815 | @test fn testResolveTraitCrossModuleCoercion() throws (testing::TestError) { |
|
| 4816 | 4816 | let mut a = testResolver(); |
|
| 4817 | 4817 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 4818 | 4818 | ||
| 4819 | 4819 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; mod app;", &mut arena); |
|
| 4820 | - | let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } }", &mut arena); |
|
| 4820 | + | let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena); |
|
| 4821 | 4821 | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena); |
|
| 4822 | 4822 | ||
| 4823 | 4823 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 4824 | 4824 | try expectNoErrors(&result); |
|
| 4825 | 4825 | } |
| 4829 | 4829 | let mut a = testResolver(); |
|
| 4830 | 4830 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 4831 | 4831 | ||
| 4832 | 4832 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod defs; export mod impls; mod app;", &mut arena); |
|
| 4833 | 4833 | let defsId = try registerModule(&mut MODULE_GRAPH, rootId, "defs", "export record Counter { value: i32 } export trait Adder { fn (*mut Adder) add(n: i32) -> i32; }", &mut arena); |
|
| 4834 | - | let implsId = try registerModule(&mut MODULE_GRAPH, rootId, "impls", "use root::defs; instance defs::Adder for defs::Counter { fn (c: *mut defs::Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } }", &mut arena); |
|
| 4834 | + | let implsId = try registerModule(&mut MODULE_GRAPH, rootId, "impls", "use root::defs; instance defs::Adder for defs::Counter { fn (c: *mut defs::Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } }", &mut arena); |
|
| 4835 | 4835 | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::defs; fn test() -> i32 { let mut c = defs::Counter { value: 10 }; let a: *mut opaque defs::Adder = &mut c; return a.add(5); }", &mut arena); |
|
| 4836 | 4836 | ||
| 4837 | 4837 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 4838 | 4838 | try expectNoErrors(&result); |
|
| 4839 | 4839 | } |
|
| 4840 | 4840 | ||
| 4841 | 4841 | /// Calling a mutable-receiver trait method on an immutable trait object |
|
| 4842 | 4842 | /// must be rejected. |
|
| 4843 | 4843 | @test fn testResolveTraitMutMethodOnImmutableObject() throws (testing::TestError) { |
|
| 4844 | 4844 | let mut a = testResolver(); |
|
| 4845 | - | let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }"; |
|
| 4845 | + | let program = "record Counter { value: i32 } trait Adder { fn (*mut Adder) add(n: i32) -> i32; } instance Adder for Counter { fn (c: *mut Counter) add(n: i32) -> i32 { set c.value = c.value + n; return c.value; } } fn caller(a: *opaque Adder) -> i32 { return a.add(1); }"; |
|
| 4846 | 4846 | let result = try resolveProgramStr(&mut a, program); |
|
| 4847 | 4847 | try expectErrorKind(&result, super::ErrorKind::ImmutableBinding); |
|
| 4848 | 4848 | } |
|
| 4849 | 4849 | ||
| 4850 | 4850 | /// Immutable methods on an immutable trait object should be accepted. |
| 4856 | 4856 | } |
|
| 4857 | 4857 | ||
| 4858 | 4858 | /// Both mutable and immutable methods on a mutable trait object should work. |
|
| 4859 | 4859 | @test fn testResolveTraitMixedMethodsOnMutableObject() throws (testing::TestError) { |
|
| 4860 | 4860 | let mut a = testResolver(); |
|
| 4861 | - | let program = "record Counter { value: i32 } trait Ops { fn (*mut Ops) inc(); fn (*Ops) get() -> i32; } instance Ops for Counter { fn (c: *mut Counter) inc() { c.value = c.value + 1; } fn (c: *Counter) get() -> i32 { return c.value; } } fn caller(o: *mut opaque Ops) -> i32 { o.inc(); return o.get(); }"; |
|
| 4861 | + | let program = "record Counter { value: i32 } trait Ops { fn (*mut Ops) inc(); fn (*Ops) get() -> i32; } instance Ops for Counter { fn (c: *mut Counter) inc() { set c.value = c.value + 1; } fn (c: *Counter) get() -> i32 { return c.value; } } fn caller(o: *mut opaque Ops) -> i32 { o.inc(); return o.get(); }"; |
|
| 4862 | 4862 | let result = try resolveProgramStr(&mut a, program); |
|
| 4863 | 4863 | try expectNoErrors(&result); |
|
| 4864 | 4864 | } |
|
| 4865 | 4865 | ||
| 4866 | 4866 | /// Instance method body type must match the trait return type. |
lib/std/lang/scanner.rad
+7 -7
| 256 | 256 | return s.source[s.cursor + 1]; |
|
| 257 | 257 | } |
|
| 258 | 258 | ||
| 259 | 259 | /// Advance scanner and return the character that was consumed. |
|
| 260 | 260 | fn advance(s: *mut Scanner) -> u8 { |
|
| 261 | - | s.cursor += 1; |
|
| 261 | + | set s.cursor += 1; |
|
| 262 | 262 | return s.source[s.cursor - 1]; |
|
| 263 | 263 | } |
|
| 264 | 264 | ||
| 265 | 265 | /// Consume the expected character if it matches the current position. |
|
| 266 | 266 | fn consume(s: *mut Scanner, expected: u8) -> bool { |
| 417 | 417 | let mid = left + ((right - left) / 2); |
|
| 418 | 418 | let kw = KEYWORDS[mid]; |
|
| 419 | 419 | let cmp = mem::cmp(src, kw.name); |
|
| 420 | 420 | ||
| 421 | 421 | match cmp { |
|
| 422 | - | case -1 => right = mid, |
|
| 423 | - | case 1 => left = mid + 1, |
|
| 422 | + | case -1 => set right = mid, |
|
| 423 | + | case 1 => set left = mid + 1, |
|
| 424 | 424 | else => return kw.tok, |
|
| 425 | 425 | } |
|
| 426 | 426 | } |
|
| 427 | 427 | return TokenKind::Ident; |
|
| 428 | 428 | } |
| 443 | 443 | } |
|
| 444 | 444 | ||
| 445 | 445 | /// Scan the next token. |
|
| 446 | 446 | export fn next(s: *mut Scanner) -> Token { |
|
| 447 | 447 | skipWhitespace(s); // Skip any whitespace between tokens. |
|
| 448 | - | s.token = s.cursor; // Token starts at current position. |
|
| 448 | + | set s.token = s.cursor; // Token starts at current position. |
|
| 449 | 449 | ||
| 450 | 450 | if isEof(s) { |
|
| 451 | 451 | return tok(s, TokenKind::Eof); |
|
| 452 | 452 | } |
|
| 453 | 453 | let c: u8 = advance(s); |
| 613 | 613 | if offset >= source.len { |
|
| 614 | 614 | return nil; |
|
| 615 | 615 | } |
|
| 616 | 616 | for ch in &source[..offset] { |
|
| 617 | 617 | if ch == '\n' { |
|
| 618 | - | c = 1; |
|
| 619 | - | l += 1; |
|
| 618 | + | set c = 1; |
|
| 619 | + | set l += 1; |
|
| 620 | 620 | } else { |
|
| 621 | - | c += 1; |
|
| 621 | + | set c += 1; |
|
| 622 | 622 | } |
|
| 623 | 623 | } |
|
| 624 | 624 | return Location { source: sourceLoc, line: l, col: c }; |
|
| 625 | 625 | } |
lib/std/lang/scanner/tests.rad
+11 -11
| 84 | 84 | let mut t: super::Token = super::next(&mut s); |
|
| 85 | 85 | try testing::expect(t.kind == super::TokenKind::String); |
|
| 86 | 86 | try testing::expect(t.source.len == 14); // Includes quotes. |
|
| 87 | 87 | try testing::expect(mem::eq(t.source, "\"Hello World!\"")); |
|
| 88 | 88 | ||
| 89 | - | t = super::next(&mut s); |
|
| 89 | + | set t = super::next(&mut s); |
|
| 90 | 90 | try testing::expect(t.kind == super::TokenKind::String); |
|
| 91 | 91 | try testing::expect(t.source.len == 4); |
|
| 92 | 92 | try testing::expect(mem::eq(t.source, "\"\\\"\"")); |
|
| 93 | 93 | } |
|
| 94 | 94 |
| 104 | 104 | try testing::expect(loc.line == 1); |
|
| 105 | 105 | try testing::expect(loc.col == 1); |
|
| 106 | 106 | } else { |
|
| 107 | 107 | try testing::expect(false); |
|
| 108 | 108 | } |
|
| 109 | - | tok = super::next(&mut s); |
|
| 109 | + | set tok = super::next(&mut s); |
|
| 110 | 110 | try testing::expect(tok.kind == super::TokenKind::Ident); |
|
| 111 | 111 | try testing::expect(tok.source.len == 3); |
|
| 112 | 112 | ||
| 113 | 113 | if let loc = super::getLocation(s.sourceLoc, s.source, tok.offset) { |
|
| 114 | 114 | try testing::expect(loc.line == 2); |
|
| 115 | 115 | try testing::expect(loc.col == 3); |
|
| 116 | 116 | } else { |
|
| 117 | 117 | try testing::expect(false); |
|
| 118 | 118 | } |
|
| 119 | - | tok = super::next(&mut s); |
|
| 119 | + | set tok = super::next(&mut s); |
|
| 120 | 120 | try testing::expect(tok.kind == super::TokenKind::Ident); |
|
| 121 | 121 | try testing::expect(tok.source.len == 3); |
|
| 122 | 122 | ||
| 123 | 123 | if let loc = super::getLocation(s.sourceLoc, s.source, tok.offset) { |
|
| 124 | 124 | try testing::expect(loc.line == 3); |
| 187 | 187 | ); |
|
| 188 | 188 | let mut tok: super::Token = super::next(&mut s); |
|
| 189 | 189 | try testing::expect(tok.kind == super::TokenKind::Ident); |
|
| 190 | 190 | try testing::expect(tok.source.len == 3); |
|
| 191 | 191 | ||
| 192 | - | tok = super::next(&mut s); |
|
| 192 | + | set tok = super::next(&mut s); |
|
| 193 | 193 | try testing::expect(tok.kind == super::TokenKind::Ident); |
|
| 194 | 194 | try testing::expect(tok.source.len == 6); |
|
| 195 | 195 | ||
| 196 | - | tok = super::next(&mut s); |
|
| 196 | + | set tok = super::next(&mut s); |
|
| 197 | 197 | try testing::expect(tok.kind == super::TokenKind::Ident); |
|
| 198 | 198 | try testing::expect(tok.source.len == 7); |
|
| 199 | 199 | } |
|
| 200 | 200 | ||
| 201 | 201 | @test fn testScanNumbers() throws (testing::TestError) { |
| 205 | 205 | let mut tok: super::Token = super::next(&mut s); |
|
| 206 | 206 | try testing::expect(tok.kind == super::TokenKind::Number); |
|
| 207 | 207 | try testing::expect(mem::eq(tok.source, "9841029")); |
|
| 208 | 208 | try testing::expect(tok.source.len == 7); |
|
| 209 | 209 | ||
| 210 | - | tok = super::next(&mut s); |
|
| 210 | + | set tok = super::next(&mut s); |
|
| 211 | 211 | try testing::expect(tok.kind == super::TokenKind::Number); |
|
| 212 | 212 | try testing::expect(tok.source.len == 5); |
|
| 213 | 213 | ||
| 214 | - | tok = super::next(&mut s); |
|
| 214 | + | set tok = super::next(&mut s); |
|
| 215 | 215 | try testing::expect(tok.kind == super::TokenKind::Number); |
|
| 216 | 216 | try testing::expect(mem::eq(tok.source, "-128")); |
|
| 217 | 217 | try testing::expect(tok.source.len == 4); |
|
| 218 | 218 | ||
| 219 | - | tok = super::next(&mut s); |
|
| 219 | + | set tok = super::next(&mut s); |
|
| 220 | 220 | try testing::expect(tok.kind == super::TokenKind::Number); |
|
| 221 | 221 | try testing::expect(mem::eq(tok.source, "+0x2A")); |
|
| 222 | 222 | try testing::expect(tok.source.len == 5); |
|
| 223 | 223 | ||
| 224 | - | tok = super::next(&mut s); |
|
| 224 | + | set tok = super::next(&mut s); |
|
| 225 | 225 | try testing::expect(tok.kind == super::TokenKind::Number); |
|
| 226 | 226 | try testing::expect(mem::eq(tok.source, "+0b11")); |
|
| 227 | 227 | try testing::expect(tok.source.len == 5); |
|
| 228 | 228 | } |
|
| 229 | 229 |
| 271 | 271 | ); |
|
| 272 | 272 | let mut tok: super::Token = super::next(&mut s); |
|
| 273 | 273 | try testing::expect(tok.kind == super::TokenKind::Invalid); |
|
| 274 | 274 | try testing::expect(tok.offset == 0); |
|
| 275 | 275 | ||
| 276 | - | tok = super::next(&mut s); |
|
| 276 | + | set tok = super::next(&mut s); |
|
| 277 | 277 | try testing::expect(tok.kind == super::TokenKind::Invalid); |
|
| 278 | 278 | try testing::expect(tok.offset == 1); |
|
| 279 | 279 | ||
| 280 | - | tok = super::next(&mut s); |
|
| 280 | + | set tok = super::next(&mut s); |
|
| 281 | 281 | try testing::expect(tok.kind == super::TokenKind::Invalid); |
|
| 282 | 282 | try testing::expect(tok.offset == 2); |
|
| 283 | 283 | } |
|
| 284 | 284 | ||
| 285 | 285 | @test fn testScanUnterminatedString() throws (testing::TestError) { |
lib/std/lang/sexpr.rad
+4 -4
| 46 | 46 | if items.len == 0 { |
|
| 47 | 47 | return &[]; |
|
| 48 | 48 | } |
|
| 49 | 49 | let buf = try! allocExprs(a, items.len); |
|
| 50 | 50 | for item, i in items { |
|
| 51 | - | buf[i] = item; |
|
| 51 | + | set buf[i] = item; |
|
| 52 | 52 | } |
|
| 53 | 53 | return buf; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | /// Shorthand for creating a symbol. |
| 84 | 84 | case Output::Stdout => io::print(s), |
|
| 85 | 85 | case Output::Buffer { buf, pos } => { |
|
| 86 | 86 | let remaining = buf.len - *pos; |
|
| 87 | 87 | let toWrite = remaining if s.len > remaining else s.len; |
|
| 88 | 88 | for i in 0..toWrite { |
|
| 89 | - | buf[*pos] = s[i]; |
|
| 90 | - | *pos += 1; |
|
| 89 | + | set buf[*pos] = s[i]; |
|
| 90 | + | set *pos += 1; |
|
| 91 | 91 | } |
|
| 92 | 92 | } |
|
| 93 | 93 | } |
|
| 94 | 94 | } |
|
| 95 | 95 |
| 149 | 149 | } else { |
|
| 150 | 150 | let mut first = head.len == 0; |
|
| 151 | 151 | for i in 0..tail.len { |
|
| 152 | 152 | if tail[i] <> Expr::Null { |
|
| 153 | 153 | if first { |
|
| 154 | - | first = false; |
|
| 154 | + | set first = false; |
|
| 155 | 155 | } else { |
|
| 156 | 156 | write(out, " "); |
|
| 157 | 157 | } |
|
| 158 | 158 | printTo(tail[i], depth, out); |
|
| 159 | 159 | } |
lib/std/lang/strings.rad
+3 -3
| 39 | 39 | let entry = sp.table[idx]; |
|
| 40 | 40 | if entry.len > 0 { |
|
| 41 | 41 | if mem::eq(entry, str) { |
|
| 42 | 42 | return Lookup::Found(entry); |
|
| 43 | 43 | } |
|
| 44 | - | idx = (idx + 1) & (TABLE_SIZE - 1); |
|
| 44 | + | set idx = (idx + 1) & (TABLE_SIZE - 1); |
|
| 45 | 45 | } else { |
|
| 46 | 46 | return Lookup::Empty(idx); |
|
| 47 | 47 | } |
|
| 48 | 48 | } |
|
| 49 | 49 | } |
| 64 | 64 | export fn intern(sp: *mut Pool, str: *[u8]) -> *[u8] { |
|
| 65 | 65 | match lookup(sp, str) { |
|
| 66 | 66 | case Lookup::Found(entry) => return entry, |
|
| 67 | 67 | case Lookup::Empty(idx) => { |
|
| 68 | 68 | assert sp.count < TABLE_SIZE / 2, "intern: string pool is full"; |
|
| 69 | - | sp.table[idx] = str; |
|
| 70 | - | sp.count += 1; |
|
| 69 | + | set sp.table[idx] = str; |
|
| 70 | + | set sp.count += 1; |
|
| 71 | 71 | ||
| 72 | 72 | return str; |
|
| 73 | 73 | } |
|
| 74 | 74 | } |
|
| 75 | 75 | } |
lib/std/mem.rad
+3 -3
| 8 | 8 | export fn copy(into: *mut [u8], from: *[u8]) -> u32 throws (MemoryError) { |
|
| 9 | 9 | if into.len < from.len { |
|
| 10 | 10 | throw MemoryError::BufferTooSmall; |
|
| 11 | 11 | } |
|
| 12 | 12 | for x, i in from { |
|
| 13 | - | into[i] = x; |
|
| 13 | + | set into[i] = x; |
|
| 14 | 14 | } |
|
| 15 | 15 | return from.len; |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | /// Strip a byte-level prefix from the input, and return the suffix. |
| 45 | 45 | /// Count number of set bits in a 32-bit value. |
|
| 46 | 46 | export fn popCount(x: u32) -> i32 { |
|
| 47 | 47 | let mut n = x; |
|
| 48 | 48 | let mut count: i32 = 0; |
|
| 49 | 49 | while n <> 0 { |
|
| 50 | - | count += (n & 1) as i32; |
|
| 51 | - | n >>= 1; |
|
| 50 | + | set count += (n & 1) as i32; |
|
| 51 | + | set n >>= 1; |
|
| 52 | 52 | } |
|
| 53 | 53 | return count; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | /// Check whether two byte slices have the same length and contents. |
lib/std/sys/unix.rad
+2 -2
| 60 | 60 | return n; |
|
| 61 | 61 | } |
|
| 62 | 62 | if n == 0 { |
|
| 63 | 63 | break; |
|
| 64 | 64 | } |
|
| 65 | - | total += n as u32; |
|
| 65 | + | set total += n as u32; |
|
| 66 | 66 | } |
|
| 67 | 67 | return total as i64; |
|
| 68 | 68 | } |
|
| 69 | 69 | ||
| 70 | 70 | /// Writes to a file descriptor from the provided buffer. |
| 117 | 117 | let n = write(fd, chunk); |
|
| 118 | 118 | if n <= 0 { |
|
| 119 | 119 | close(fd); |
|
| 120 | 120 | return false; |
|
| 121 | 121 | } |
|
| 122 | - | written += n as u32; |
|
| 122 | + | set written += n as u32; |
|
| 123 | 123 | } |
|
| 124 | 124 | close(fd); |
|
| 125 | 125 | ||
| 126 | 126 | return true; |
|
| 127 | 127 | } |
lib/std/testing.rad
+3 -3
| 57 | 57 | io::print(name); |
|
| 58 | 58 | io::print(" ... "); |
|
| 59 | 59 | ||
| 60 | 60 | let mut success = true; |
|
| 61 | 61 | try testFn() catch { |
|
| 62 | - | success = false; |
|
| 62 | + | set success = false; |
|
| 63 | 63 | }; |
|
| 64 | 64 | if success { |
|
| 65 | 65 | io::printLn("ok"); |
|
| 66 | - | ctx.passed += 1; |
|
| 66 | + | set ctx.passed += 1; |
|
| 67 | 67 | } else { |
|
| 68 | 68 | io::printLn("FAILED"); |
|
| 69 | - | ctx.failed += 1; |
|
| 69 | + | set ctx.failed += 1; |
|
| 70 | 70 | } |
|
| 71 | 71 | } |
|
| 72 | 72 | ||
| 73 | 73 | fn printTestSummary(ctx: *Ctx) { |
|
| 74 | 74 | if (ctx.failed > 0) { |
lib/std/tests.rad
+1 -1
| 134 | 134 | let mut xs: [u8; 2] = [1, 2]; |
|
| 135 | 135 | let ys: [u8; 3] = [4, 5, 6]; |
|
| 136 | 136 | ||
| 137 | 137 | let mut threw = false; |
|
| 138 | 138 | try mem::copy(&mut xs[..], &ys[..]) catch { |
|
| 139 | - | threw = true; |
|
| 139 | + | set threw = true; |
|
| 140 | 140 | }; |
|
| 141 | 141 | try testing::expect(threw); |
|
| 142 | 142 | } |
|
| 143 | 143 | ||
| 144 | 144 | @test fn testStripPrefixMatch() throws (testing::TestError) { |
lib/std/vec.rad
+4 -4
| 42 | 42 | return vec.data.len / vec.stride; |
|
| 43 | 43 | } |
|
| 44 | 44 | ||
| 45 | 45 | /// Reset the vector to empty (does not clear memory). |
|
| 46 | 46 | export fn reset(vec: *mut RawVec) { |
|
| 47 | - | vec.len = 0; |
|
| 47 | + | set vec.len = 0; |
|
| 48 | 48 | } |
|
| 49 | 49 | ||
| 50 | 50 | /// Get a pointer to the element at the given index. |
|
| 51 | 51 | /// |
|
| 52 | 52 | /// Returns nil if index is out of bounds. |
| 70 | 70 | let off: u32 = vec.len * vec.stride; |
|
| 71 | 71 | let dst: *mut u8 = &mut vec.data[off]; |
|
| 72 | 72 | let src: *u8 = elem as *u8; |
|
| 73 | 73 | ||
| 74 | 74 | copyBytes(dst, src, vec.stride); |
|
| 75 | - | vec.len += 1; |
|
| 75 | + | set vec.len += 1; |
|
| 76 | 76 | ||
| 77 | 77 | return true; |
|
| 78 | 78 | } |
|
| 79 | 79 | ||
| 80 | 80 | /// Pop an element from the end of the vector. |
| 83 | 83 | /// Returns false if the vector is empty. |
|
| 84 | 84 | export fn pop(vec: *mut RawVec, out: *mut opaque) -> bool { |
|
| 85 | 85 | if vec.len == 0 { |
|
| 86 | 86 | return false; |
|
| 87 | 87 | } |
|
| 88 | - | vec.len -= 1; |
|
| 88 | + | set vec.len -= 1; |
|
| 89 | 89 | ||
| 90 | 90 | let off: u32 = vec.len * vec.stride; |
|
| 91 | 91 | let src: *u8 = &vec.data[off]; |
|
| 92 | 92 | let dst: *mut u8 = out as *mut u8; |
|
| 93 | 93 |
| 113 | 113 | } |
|
| 114 | 114 | ||
| 115 | 115 | /// Copy bytes from source to destination. |
|
| 116 | 116 | fn copyBytes(dst: *mut u8, src: *u8, count: u32) { |
|
| 117 | 117 | for i in 0..count { |
|
| 118 | - | *(dst + i) = *(src + i); |
|
| 118 | + | set *(dst + i) = *(src + i); |
|
| 119 | 119 | } |
|
| 120 | 120 | } |
test/runner.rad
+11 -11
| 53 | 53 | let mut end: u32 = 0; |
|
| 54 | 54 | let mut i: u32 = 0; |
|
| 55 | 55 | ||
| 56 | 56 | while i < line.len and line[i] <> ';' { |
|
| 57 | 57 | if line[i] <> ' ' and line[i] <> '\t' { |
|
| 58 | - | end = i + 1; |
|
| 58 | + | set end = i + 1; |
|
| 59 | 59 | } |
|
| 60 | - | i += 1; |
|
| 60 | + | set i += 1; |
|
| 61 | 61 | } |
|
| 62 | 62 | return &line[..end]; |
|
| 63 | 63 | } |
|
| 64 | 64 | ||
| 65 | 65 | /// Get next line from string at offset. Returns the line and updates offset past newline. |
|
| 66 | 66 | fn nextLine(s: *[u8], offset: *mut u32) -> *[u8] { |
|
| 67 | 67 | let start = *offset; |
|
| 68 | 68 | let mut i = start; |
|
| 69 | 69 | ||
| 70 | 70 | while i < s.len and s[i] <> '\n' { |
|
| 71 | - | i += 1; |
|
| 71 | + | set i += 1; |
|
| 72 | 72 | } |
|
| 73 | 73 | let line = &s[start..i]; |
|
| 74 | 74 | if i < s.len { |
|
| 75 | - | *offset = i + 1; |
|
| 75 | + | set *offset = i + 1; |
|
| 76 | 76 | } else { |
|
| 77 | - | *offset = i; |
|
| 77 | + | set *offset = i; |
|
| 78 | 78 | } |
|
| 79 | 79 | return line; |
|
| 80 | 80 | } |
|
| 81 | 81 | ||
| 82 | 82 | /// Compare two strings ignoring comments, line by line. |
| 85 | 85 | let mut bi: u32 = 0; |
|
| 86 | 86 | ||
| 87 | 87 | while ai < a.len or bi < b.len { |
|
| 88 | 88 | let mut aLine = ""; |
|
| 89 | 89 | while ai < a.len and aLine.len == 0 { |
|
| 90 | - | aLine = stripLine(nextLine(a, &mut ai)); |
|
| 90 | + | set aLine = stripLine(nextLine(a, &mut ai)); |
|
| 91 | 91 | } |
|
| 92 | 92 | let mut bLine = ""; |
|
| 93 | 93 | while bi < b.len and bLine.len == 0 { |
|
| 94 | - | bLine = stripLine(nextLine(b, &mut bi)); |
|
| 94 | + | set bLine = stripLine(nextLine(b, &mut bi)); |
|
| 95 | 95 | } |
|
| 96 | 96 | if not mem::eq(aLine, bLine) { |
|
| 97 | 97 | return false; |
|
| 98 | 98 | } |
|
| 99 | 99 | } |
| 130 | 130 | try mem::copy(buf, sourcePath) catch { |
|
| 131 | 131 | return nil; |
|
| 132 | 132 | }; |
|
| 133 | 133 | // TODO: Rewrite this once we fix the compiler bug and add support for |
|
| 134 | 134 | // additions in ranges. |
|
| 135 | - | buf[len - 3] = 'r'; |
|
| 136 | - | buf[len - 2] = 'i'; |
|
| 137 | - | buf[len - 1] = 'l'; |
|
| 138 | - | buf[len] = 0; |
|
| 135 | + | set buf[len - 3] = 'r'; |
|
| 136 | + | set buf[len - 2] = 'i'; |
|
| 137 | + | set buf[len - 1] = 'l'; |
|
| 138 | + | set buf[len] = 0; |
|
| 139 | 139 | ||
| 140 | 140 | return &buf[..len]; |
|
| 141 | 141 | } |
|
| 142 | 142 | ||
| 143 | 143 | /// Run a single IL snapshot test case. Returns `true` on success. |
test/tests/aggregate.return.rad
+4 -4
| 61 | 61 | fn testMutateReturnedAggregate() -> i32 { |
|
| 62 | 62 | let before: u32 = 42; |
|
| 63 | 63 | let mut p: Pair = makePair(10, 20); |
|
| 64 | 64 | let after: u32 = 99; |
|
| 65 | 65 | ||
| 66 | - | p.a = 100; |
|
| 67 | - | p.b = 200; |
|
| 66 | + | set p.a = 100; |
|
| 67 | + | set p.b = 200; |
|
| 68 | 68 | ||
| 69 | 69 | assert before == 42; |
|
| 70 | 70 | assert after == 99; |
|
| 71 | 71 | assert p.a == 100; |
|
| 72 | 72 | assert p.b == 200; |
| 77 | 77 | fn testAggregateReturnInLoop() -> i32 { |
|
| 78 | 78 | let mut total: u32 = 0; |
|
| 79 | 79 | let mut idx: u32 = 0; |
|
| 80 | 80 | while idx < 5 { |
|
| 81 | 81 | let p: Pair = makePair(idx, idx + 10); |
|
| 82 | - | total += p.a + p.b; |
|
| 83 | - | idx += 1; |
|
| 82 | + | set total += p.a + p.b; |
|
| 83 | + | set idx += 1; |
|
| 84 | 84 | } |
|
| 85 | 85 | // total = sum(i + i+10 for i in 0..5) = sum(2i+10) = 2*(0+1+2+3+4) + 50 = 20 + 50 = 70 |
|
| 86 | 86 | assert total == 70; |
|
| 87 | 87 | return 0; |
|
| 88 | 88 | } |
test/tests/arith.assignment.rad
+9 -9
| 4 | 4 | let mut b: i32 = 3; |
|
| 5 | 5 | let mut c: i32 = 0; |
|
| 6 | 6 | let mut d: i32 = 0; |
|
| 7 | 7 | ||
| 8 | 8 | // Test addition. |
|
| 9 | - | c = a + b; // c = 9 |
|
| 9 | + | set c = a + b; // c = 9 |
|
| 10 | 10 | ||
| 11 | 11 | // Test subtraction. |
|
| 12 | - | c -= b; // c = 6 |
|
| 12 | + | set c -= b; // c = 6 |
|
| 13 | 13 | ||
| 14 | 14 | // Test multiplication. |
|
| 15 | - | c *= b; // c = 18 |
|
| 15 | + | set c *= b; // c = 18 |
|
| 16 | 16 | ||
| 17 | 17 | // Test division. |
|
| 18 | - | c /= b; // c = 6 |
|
| 18 | + | set c /= b; // c = 6 |
|
| 19 | 19 | ||
| 20 | 20 | // Test mixed operations. |
|
| 21 | - | d = a * b + c / b; // d = 18 + 2 = 20 |
|
| 22 | - | d += a * b / a; // d = 20 + 3 = 23 |
|
| 23 | - | d += (b * a - c); // d = 23 + (18 - 6) = 35 |
|
| 24 | - | d += (c - a / b); // d = 35 + (6 - 2) = 39 |
|
| 25 | - | d += 3; // d = 42 |
|
| 21 | + | set d = a * b + c / b; // d = 18 + 2 = 20 |
|
| 22 | + | set d += a * b / a; // d = 20 + 3 = 23 |
|
| 23 | + | set d += (b * a - c); // d = 23 + (18 - 6) = 35 |
|
| 24 | + | set d += (c - a / b); // d = 35 + (6 - 2) = 39 |
|
| 25 | + | set d += 3; // d = 42 |
|
| 26 | 26 | ||
| 27 | 27 | return (d) - 42; |
|
| 28 | 28 | } |
test/tests/array.assign.rad
+1 -1
| 3 | 3 | ||
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut a: [i32; 5] = [1, 2, 3, 4, 5]; |
|
| 6 | 6 | let mut b: [i32; 5] = [8, 9, 7, 6, 0]; |
|
| 7 | 7 | ||
| 8 | - | b = a; |
|
| 8 | + | set b = a; |
|
| 9 | 9 | ||
| 10 | 10 | return b[0] + b[3] - b[2]; |
|
| 11 | 11 | } |
test/tests/array.index.assign.rad
+10 -10
| 2 | 2 | //! Test array index assignment and reading. |
|
| 3 | 3 | ||
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut arr: [i32; 5] = [1, 2, 3, 4, 5]; |
|
| 6 | 6 | ||
| 7 | - | arr[0] = 10; |
|
| 8 | - | arr[1] = 20; |
|
| 9 | - | arr[2] = 30; |
|
| 10 | - | arr[3] = 40; |
|
| 11 | - | arr[4] = 50; |
|
| 7 | + | set arr[0] = 10; |
|
| 8 | + | set arr[1] = 20; |
|
| 9 | + | set arr[2] = 30; |
|
| 10 | + | set arr[3] = 40; |
|
| 11 | + | set arr[4] = 50; |
|
| 12 | 12 | ||
| 13 | 13 | let mut sum: i32 = 0; |
|
| 14 | 14 | ||
| 15 | - | sum += arr[0]; |
|
| 16 | - | sum += arr[1]; |
|
| 17 | - | sum += arr[2]; |
|
| 18 | - | sum += arr[3]; |
|
| 19 | - | sum -= arr[4]; |
|
| 15 | + | set sum += arr[0]; |
|
| 16 | + | set sum += arr[1]; |
|
| 17 | + | set sum += arr[2]; |
|
| 18 | + | set sum += arr[3]; |
|
| 19 | + | set sum -= arr[4]; |
|
| 20 | 20 | ||
| 21 | 21 | assert sum == 50; |
|
| 22 | 22 | return 0; |
|
| 23 | 23 | } |
test/tests/array.index.rad
+4 -4
| 3 | 3 | ||
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut arr: [i32; 4] = [10, 20, 30, 40]; |
|
| 6 | 6 | let mut sum: i32 = 0; |
|
| 7 | 7 | ||
| 8 | - | sum += arr[0]; |
|
| 9 | - | sum += arr[1]; |
|
| 10 | - | sum += arr[2]; |
|
| 11 | - | sum += arr[3]; |
|
| 8 | + | set sum += arr[0]; |
|
| 9 | + | set sum += arr[1]; |
|
| 10 | + | set sum += arr[2]; |
|
| 11 | + | set sum += arr[3]; |
|
| 12 | 12 | ||
| 13 | 13 | return (sum) - 100; |
|
| 14 | 14 | } |
test/tests/array.length.rad
+2 -2
| 5 | 5 | let mut ary: [i32; 7] = [1, 2, 3, 4, 5, 6, 7]; |
|
| 6 | 6 | let mut sum: i32 = 0; |
|
| 7 | 7 | let mut i: u32 = 0; |
|
| 8 | 8 | ||
| 9 | 9 | while (i < ary.len) { |
|
| 10 | - | sum += ary[i]; |
|
| 11 | - | i += 1; |
|
| 10 | + | set sum += ary[i]; |
|
| 11 | + | set i += 1; |
|
| 12 | 12 | } |
|
| 13 | 13 | return (sum) - 28; |
|
| 14 | 14 | } |
test/tests/array.math.rad
+5 -5
| 3 | 3 | ||
| 4 | 4 | fn sumMatrix(mat: [[i32; 3]; 2]) -> i32 { |
|
| 5 | 5 | let mut sum: i32 = 0; |
|
| 6 | 6 | for vec in mat { |
|
| 7 | 7 | for x in vec { |
|
| 8 | - | sum += x; |
|
| 8 | + | set sum += x; |
|
| 9 | 9 | } |
|
| 10 | 10 | } |
|
| 11 | 11 | return sum; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn sumMatrixTransposed(mat: [[i32; 2]; 3]) -> i32 { |
|
| 15 | 15 | let mut sum: i32 = 0; |
|
| 16 | 16 | for vec in (mat) { |
|
| 17 | 17 | for x in (vec) { |
|
| 18 | - | sum += x; |
|
| 18 | + | set sum += x; |
|
| 19 | 19 | } |
|
| 20 | 20 | } |
|
| 21 | 21 | return sum; |
|
| 22 | 22 | } |
|
| 23 | 23 |
| 26 | 26 | let mut i: u32 = 0; |
|
| 27 | 27 | ||
| 28 | 28 | while (i < matrix.len) { |
|
| 29 | 29 | let mut j: u32 = 0; |
|
| 30 | 30 | while (j < matrix[i].len) { |
|
| 31 | - | result[j][i] = matrix[i][j]; |
|
| 32 | - | j += 1; |
|
| 31 | + | set result[j][i] = matrix[i][j]; |
|
| 32 | + | set j += 1; |
|
| 33 | 33 | } |
|
| 34 | - | i += 1; |
|
| 34 | + | set i += 1; |
|
| 35 | 35 | } |
|
| 36 | 36 | return result; |
|
| 37 | 37 | } |
|
| 38 | 38 | ||
| 39 | 39 | @default fn main() -> i32 { |
test/tests/array.nested.assign.rad
+2 -2
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut m: [[i32; 3]; 2] = [ |
|
| 6 | 6 | [1, 2, 3], |
|
| 7 | 7 | [4, 5, 6] |
|
| 8 | 8 | ]; |
|
| 9 | - | m[1][1] = 7; |
|
| 10 | - | m[0][2] = 4; |
|
| 9 | + | set m[1][1] = 7; |
|
| 10 | + | set m[0][2] = 4; |
|
| 11 | 11 | ||
| 12 | 12 | return |
|
| 13 | 13 | m[0][0] + |
|
| 14 | 14 | m[0][1] + |
|
| 15 | 15 | m[0][2] + |
test/tests/array.record.elements.rad
+8 -8
| 8 | 8 | ||
| 9 | 9 | fn calculateDistance(p1: Point, p2: Point) -> i32 { |
|
| 10 | 10 | // Simple Manhattan distance |
|
| 11 | 11 | let mut dx: i32 = p2.x - p1.x; |
|
| 12 | 12 | if (dx < 0) { |
|
| 13 | - | dx = -dx; |
|
| 13 | + | set dx = -dx; |
|
| 14 | 14 | } |
|
| 15 | 15 | let mut dy: i32 = p2.y - p1.y; |
|
| 16 | 16 | if (dy < 0) { |
|
| 17 | - | dy = -dy; |
|
| 17 | + | set dy = -dy; |
|
| 18 | 18 | } |
|
| 19 | 19 | return dx + dy; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn sumPoints(points: [Point; 4]) -> i32 { |
|
| 23 | 23 | let mut sum: i32 = 0; |
|
| 24 | 24 | let mut i: u32 = 0; |
|
| 25 | 25 | ||
| 26 | 26 | while (i < 4) { |
|
| 27 | - | sum += points[i].x + points[i].y; |
|
| 28 | - | i += 1; |
|
| 27 | + | set sum += points[i].x + points[i].y; |
|
| 28 | + | set i += 1; |
|
| 29 | 29 | } |
|
| 30 | 30 | return sum; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | fn shiftPoints(points: [Point; 4], dx: i32, dy: i32) -> [Point; 4] { |
| 37 | 37 | Point { x: 0, y: 0 }, |
|
| 38 | 38 | Point { x: 0, y: 0 } |
|
| 39 | 39 | ]; |
|
| 40 | 40 | let mut i: u32 = 0; |
|
| 41 | 41 | while (i < 4) { |
|
| 42 | - | result[i] = Point { |
|
| 42 | + | set result[i] = Point { |
|
| 43 | 43 | x: points[i].x + dx, |
|
| 44 | 44 | y: points[i].y + dy |
|
| 45 | 45 | }; |
|
| 46 | - | i += 1; |
|
| 46 | + | set i += 1; |
|
| 47 | 47 | } |
|
| 48 | 48 | return result; |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | @default fn main() -> i32 { |
| 63 | 63 | let mut shifted: [Point; 4] = shiftPoints(points, 1, 1); |
|
| 64 | 64 | // Calculate distance between original and shifted array elements. |
|
| 65 | 65 | let mut distance: i32 = 0; |
|
| 66 | 66 | let mut i: u32 = 0; |
|
| 67 | 67 | while (i < points.len) { |
|
| 68 | - | distance += calculateDistance(points[i], shifted[i]); |
|
| 69 | - | i += 1; |
|
| 68 | + | set distance += calculateDistance(points[i], shifted[i]); |
|
| 69 | + | set i += 1; |
|
| 70 | 70 | } |
|
| 71 | 71 | return total + distance + shifted[3].x - points[0].y; |
|
| 72 | 72 | } |
test/tests/assign.loop.rad
+2 -2
| 1 | 1 | /// Assignment in a loop, accumulating a value. |
|
| 2 | 2 | fn assignLoop(n: i32) -> i32 { |
|
| 3 | 3 | let mut sum: i32 = 0; |
|
| 4 | 4 | let mut i: i32 = 0; |
|
| 5 | 5 | while i < n { |
|
| 6 | - | sum += i; |
|
| 7 | - | i += 1; |
|
| 6 | + | set sum += i; |
|
| 7 | + | set i += 1; |
|
| 8 | 8 | } |
|
| 9 | 9 | return sum; |
|
| 10 | 10 | } |
test/tests/assign.multi.var.rad
+3 -3
| 1 | 1 | /// Multiple variables with interleaved assignments. |
|
| 2 | 2 | fn assignMultiVar() -> i32 { |
|
| 3 | 3 | let mut a: i32 = 1; |
|
| 4 | 4 | let mut b: i32 = 2; |
|
| 5 | - | a = 10; |
|
| 6 | - | b = 20; |
|
| 7 | - | a += b; |
|
| 5 | + | set a = 10; |
|
| 6 | + | set b = 20; |
|
| 7 | + | set a += b; |
|
| 8 | 8 | return a; |
|
| 9 | 9 | } |
test/tests/assign.mutable.rad
+46 -46
| 15 | 15 | /// Basic variable aliasing and mutation. |
|
| 16 | 16 | fn testBasicAliasing() -> i32 { |
|
| 17 | 17 | let mut x: i32 = 10; |
|
| 18 | 18 | let mut y: i32 = x; // y aliases x's value |
|
| 19 | 19 | ||
| 20 | - | x = 20; // Modify x |
|
| 21 | - | y += 5; // Modify y independently |
|
| 20 | + | set x = 20; // Modify x |
|
| 21 | + | set y += 5; // Modify y independently |
|
| 22 | 22 | ||
| 23 | 23 | return x + y; // Should be 20 + 15 = 35 |
|
| 24 | 24 | } |
|
| 25 | 25 | ||
| 26 | 26 | /// Struct aliasing and field mutation. |
|
| 27 | 27 | fn testStructAliasing() -> i32 { |
|
| 28 | 28 | let mut p1: Person = Person { age: 25, score: 100 }; |
|
| 29 | 29 | let mut p2: Person = p1; // Copy record |
|
| 30 | 30 | ||
| 31 | - | p1.age = 30; // Modify original |
|
| 32 | - | p2.score = 0; // Modify copy |
|
| 31 | + | set p1.age = 30; // Modify original |
|
| 32 | + | set p2.score = 0; // Modify copy |
|
| 33 | 33 | ||
| 34 | 34 | return p1.age + p1.score + p2.age + p2.score; // 30+100+25+0 = 155 |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | /// Array aliasing and element mutation. |
|
| 38 | 38 | fn testArrayAliasing() -> i32 { |
|
| 39 | 39 | let mut arr1: [i32; 3] = [1, 2, 3]; |
|
| 40 | 40 | let mut arr2: [i32; 3] = arr1; // Copy array |
|
| 41 | - | arr1[0] = 10; // Modify original |
|
| 42 | - | arr2[1] = 20; // Modify copy |
|
| 41 | + | set arr1[0] = 10; // Modify original |
|
| 42 | + | set arr2[1] = 20; // Modify copy |
|
| 43 | 43 | // Arrays should be independent |
|
| 44 | 44 | return arr1[0] + arr1[1] + arr2[0] + arr2[1]; // 10+2+1+20 = 33 |
|
| 45 | 45 | } |
|
| 46 | 46 | ||
| 47 | 47 | /// Test 4: Nested record with array mutation. |
| 50 | 50 | values: [1, 2, 3], |
|
| 51 | 51 | count: 3 |
|
| 52 | 52 | }; |
|
| 53 | 53 | let mut container2: Container = container1; // Copy entire record |
|
| 54 | 54 | ||
| 55 | - | container1.values[0] = 50; // Modify nested array in original |
|
| 56 | - | container1.count = 5; // Modify field in original |
|
| 55 | + | set container1.values[0] = 50; // Modify nested array in original |
|
| 56 | + | set container1.count = 5; // Modify field in original |
|
| 57 | 57 | ||
| 58 | - | container2.values[2] = 60; // Modify nested array in copy |
|
| 59 | - | container2.count = 7; // Modify field in copy |
|
| 58 | + | set container2.values[2] = 60; // Modify nested array in copy |
|
| 59 | + | set container2.count = 7; // Modify field in copy |
|
| 60 | 60 | ||
| 61 | 61 | return container1.values[0] + container1.count + |
|
| 62 | 62 | container2.values[2] + container2.count; // 50+5+60+7 = 122 |
|
| 63 | 63 | } |
|
| 64 | 64 | ||
| 65 | 65 | /// Variable overwriting with different types/scopes. |
|
| 66 | 66 | fn testVariableOverwriting() -> i32 { |
|
| 67 | 67 | let mut result: i32 = 0; |
|
| 68 | 68 | let mut temp: i32 = 10; |
|
| 69 | - | result = temp; // First assignment |
|
| 69 | + | set result = temp; // First assignment |
|
| 70 | 70 | ||
| 71 | - | temp = 20; // Overwrite temp |
|
| 72 | - | result += temp; // result = 10 + 20 = 30 |
|
| 71 | + | set temp = 20; // Overwrite temp |
|
| 72 | + | set result += temp; // result = 10 + 20 = 30 |
|
| 73 | 73 | ||
| 74 | 74 | // Create new scope with same variable name |
|
| 75 | 75 | if true { |
|
| 76 | 76 | let mut temp: i32 = 50; // Shadow outer temp |
|
| 77 | - | result += temp; // result = 30 + 50 = 80 |
|
| 78 | - | temp = 60; // Modify inner temp |
|
| 79 | - | result += temp; // result = 80 + 60 = 140 |
|
| 77 | + | set result += temp; // result = 30 + 50 = 80 |
|
| 78 | + | set temp = 60; // Modify inner temp |
|
| 79 | + | set result += temp; // result = 80 + 60 = 140 |
|
| 80 | 80 | } |
|
| 81 | - | result += temp; // Should use outer temp (20) |
|
| 81 | + | set result += temp; // Should use outer temp (20) |
|
| 82 | 82 | ||
| 83 | 83 | return result; // 140 + 20 = 160 |
|
| 84 | 84 | } |
|
| 85 | 85 | ||
| 86 | 86 | /// Array of structs with aliasing. |
| 89 | 89 | Person { age: 10, score: 20 }, |
|
| 90 | 90 | Person { age: 15, score: 25 } |
|
| 91 | 91 | ]; |
|
| 92 | 92 | let mut backup: [Person; 2] = people; // Copy array of structs |
|
| 93 | 93 | ||
| 94 | - | people[0].age = 12; // Modify original |
|
| 95 | - | people[1].score = 30; // Modify original |
|
| 94 | + | set people[0].age = 12; // Modify original |
|
| 95 | + | set people[1].score = 30; // Modify original |
|
| 96 | 96 | ||
| 97 | - | backup[0].score = 22; // Modify copy |
|
| 98 | - | backup[1].age = 18; // Modify copy |
|
| 97 | + | set backup[0].score = 22; // Modify copy |
|
| 98 | + | set backup[1].age = 18; // Modify copy |
|
| 99 | 99 | ||
| 100 | 100 | return people[0].age + people[0].score + people[1].age + people[1].score + |
|
| 101 | 101 | backup[0].age + backup[0].score + backup[1].age + backup[1].score; |
|
| 102 | 102 | } |
|
| 103 | 103 |
| 105 | 105 | fn testMutationChain() -> i32 { |
|
| 106 | 106 | let mut a: i32 = 1; |
|
| 107 | 107 | let mut b: i32 = 2; |
|
| 108 | 108 | let mut c: i32 = 3; |
|
| 109 | 109 | ||
| 110 | - | a = b; // a = 2 |
|
| 111 | - | b = c; // b = 3 |
|
| 112 | - | c = a + b; // c = 2 + 3 = 5 |
|
| 113 | - | a = c - b; // a = 5 - 3 = 2 |
|
| 114 | - | b = a * c; // b = 2 * 5 = 10 |
|
| 110 | + | set a = b; // a = 2 |
|
| 111 | + | set b = c; // b = 3 |
|
| 112 | + | set c = a + b; // c = 2 + 3 = 5 |
|
| 113 | + | set a = c - b; // a = 5 - 3 = 2 |
|
| 114 | + | set b = a * c; // b = 2 * 5 = 10 |
|
| 115 | 115 | ||
| 116 | 116 | return a + b + c; // 2 + 10 + 5 = 17 |
|
| 117 | 117 | } |
|
| 118 | 118 | ||
| 119 | 119 | /// Struct field reassignment with aliasing. |
| 121 | 121 | let mut original: Person = Person { age: 30, score: 40 }; |
|
| 122 | 122 | let mut copied: Person = original; |
|
| 123 | 123 | ||
| 124 | 124 | // Swap fields in original |
|
| 125 | 125 | let mut temp: i32 = original.age; |
|
| 126 | - | original.age = original.score; |
|
| 127 | - | original.score = temp; |
|
| 126 | + | set original.age = original.score; |
|
| 127 | + | set original.score = temp; |
|
| 128 | 128 | ||
| 129 | 129 | // Different swap in copy |
|
| 130 | - | temp = copied.score; |
|
| 131 | - | copied.score = copied.age; |
|
| 132 | - | copied.age = temp; |
|
| 130 | + | set temp = copied.score; |
|
| 131 | + | set copied.score = copied.age; |
|
| 132 | + | set copied.age = temp; |
|
| 133 | 133 | ||
| 134 | 134 | return original.age + original.score + copied.age + copied.score; |
|
| 135 | 135 | // 40+30 + 40+30 = 140 |
|
| 136 | 136 | } |
|
| 137 | 137 |
| 140 | 140 | let mut indices: [u32; 3] = [0, 1, 2]; |
|
| 141 | 141 | let mut values: [i32; 3] = [10, 20, 30]; |
|
| 142 | 142 | let mut backup: [i32; 3] = values; |
|
| 143 | 143 | ||
| 144 | 144 | // Use indices to modify values |
|
| 145 | - | values[indices[0]] = 25; // values[0] = 25 |
|
| 146 | - | values[indices[1]] = 35; // values[1] = 35 |
|
| 145 | + | set values[indices[0]] = 25; // values[0] = 25 |
|
| 146 | + | set values[indices[1]] = 35; // values[1] = 35 |
|
| 147 | 147 | ||
| 148 | 148 | // Modify indices |
|
| 149 | - | indices[0] = 2; |
|
| 150 | - | indices[2] = 0; |
|
| 149 | + | set indices[0] = 2; |
|
| 150 | + | set indices[2] = 0; |
|
| 151 | 151 | ||
| 152 | 152 | // Use new indices on backup |
|
| 153 | - | backup[indices[0]] = 40; // backup[2] = 40 |
|
| 154 | - | backup[indices[2]] = 45; // backup[0] = 45 |
|
| 153 | + | set backup[indices[0]] = 40; // backup[2] = 40 |
|
| 154 | + | set backup[indices[2]] = 45; // backup[0] = 45 |
|
| 155 | 155 | ||
| 156 | 156 | return values[0] + values[1] + values[2] + |
|
| 157 | 157 | backup[0] + backup[1] + backup[2]; |
|
| 158 | 158 | // 25+35+30 + 45+20+40 = 195 |
|
| 159 | 159 | } |
| 164 | 164 | let mut level2: Person = level1; |
|
| 165 | 165 | let mut level3: Person = level2; |
|
| 166 | 166 | let mut level4: Person = level3; |
|
| 167 | 167 | ||
| 168 | 168 | // Modify each level |
|
| 169 | - | level1.age = 11; |
|
| 170 | - | level2.age = 12; |
|
| 171 | - | level3.age = 13; |
|
| 172 | - | level4.age = 14; |
|
| 173 | - | ||
| 174 | - | level1.score = 21; |
|
| 175 | - | level2.score = 22; |
|
| 176 | - | level3.score = 23; |
|
| 177 | - | level4.score = 24; |
|
| 169 | + | set level1.age = 11; |
|
| 170 | + | set level2.age = 12; |
|
| 171 | + | set level3.age = 13; |
|
| 172 | + | set level4.age = 14; |
|
| 173 | + | ||
| 174 | + | set level1.score = 21; |
|
| 175 | + | set level2.score = 22; |
|
| 176 | + | set level3.score = 23; |
|
| 177 | + | set level4.score = 24; |
|
| 178 | 178 | ||
| 179 | 179 | return (level1.age + level1.score) + |
|
| 180 | 180 | (level2.age + level2.score) + |
|
| 181 | 181 | (level3.age + level3.score) + |
|
| 182 | 182 | (level4.age + level4.score); |
test/tests/assign.param.rad
+2 -2
| 1 | 1 | /// Assignment overwriting a parameter value. |
|
| 2 | 2 | fn assignParam(x: i32) -> i32 { |
|
| 3 | 3 | let mut y: i32 = x; |
|
| 4 | - | y += 1; |
|
| 5 | - | y *= 2; |
|
| 4 | + | set y += 1; |
|
| 5 | + | set y *= 2; |
|
| 6 | 6 | return y; |
|
| 7 | 7 | } |
test/tests/assign.rad
+3 -3
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let mut i: i32 = 36; |
|
| 4 | - | i += 1; // 37 |
|
| 5 | - | i += 2; // 39 |
|
| 6 | - | i += 3; // 42 |
|
| 4 | + | set i += 1; // 37 |
|
| 5 | + | set i += 2; // 39 |
|
| 6 | + | set i += 3; // 42 |
|
| 7 | 7 | ||
| 8 | 8 | return i - 42; |
|
| 9 | 9 | } |
test/tests/assign.self.ref.rad
+2 -2
| 1 | 1 | /// Assignment where the new value depends on the old value. |
|
| 2 | 2 | fn assignSelfRef() -> i32 { |
|
| 3 | 3 | let mut x: i32 = 1; |
|
| 4 | - | x += x; |
|
| 5 | - | x *= x; |
|
| 4 | + | set x += x; |
|
| 5 | + | set x *= x; |
|
| 6 | 6 | return x; |
|
| 7 | 7 | } |
test/tests/assign.sequential.rad
+2 -2
| 1 | 1 | /// Sequential assignments where the final value is returned. |
|
| 2 | 2 | fn assignSequential() -> i32 { |
|
| 3 | 3 | let mut x: i32 = 1; |
|
| 4 | - | x = 2; |
|
| 5 | - | x = 3; |
|
| 4 | + | set x = 2; |
|
| 5 | + | set x = 3; |
|
| 6 | 6 | return x; |
|
| 7 | 7 | } |
test/tests/assign.shadow.mutable.rad
+7 -7
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | ||
| 3 | 3 | fn shadowedMutation() -> i32 { |
|
| 4 | 4 | let mut result: i32 = 0; |
|
| 5 | 5 | let mut temp: i32 = 10; |
|
| 6 | - | result = temp; |
|
| 6 | + | set result = temp; |
|
| 7 | 7 | ||
| 8 | - | temp = 20; |
|
| 9 | - | result += temp; |
|
| 8 | + | set temp = 20; |
|
| 9 | + | set result += temp; |
|
| 10 | 10 | ||
| 11 | 11 | if true { |
|
| 12 | 12 | let mut temp: i32 = 50; |
|
| 13 | - | result += temp; |
|
| 14 | - | temp = 60; |
|
| 15 | - | result += temp; |
|
| 13 | + | set result += temp; |
|
| 14 | + | set temp = 60; |
|
| 15 | + | set result += temp; |
|
| 16 | 16 | } |
|
| 17 | 17 | // Must refer to outer `temp` (20), not inner shadowed `temp` (60). |
|
| 18 | - | result += temp; |
|
| 18 | + | set result += temp; |
|
| 19 | 19 | ||
| 20 | 20 | return result; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | @default fn main() -> i32 { |
test/tests/assign.use.intermediate.rad
+1 -1
| 1 | 1 | /// Sequential assignments with intermediate value used in computation. |
|
| 2 | 2 | fn assignUseIntermediate() -> i32 { |
|
| 3 | 3 | let mut x: i32 = 1; |
|
| 4 | 4 | let y: i32 = x + 1; |
|
| 5 | - | x = 5; |
|
| 5 | + | set x = 5; |
|
| 6 | 6 | return x + y; |
|
| 7 | 7 | } |
test/tests/average.rad
+1 -1
| 1 | 1 | /// Compute the sum of a list of numbers. |
|
| 2 | 2 | fn average(numbers: *[u32]) -> u32 { |
|
| 3 | 3 | let mut sum: u32 = 0; |
|
| 4 | 4 | ||
| 5 | 5 | for i in numbers { |
|
| 6 | - | sum += i; |
|
| 6 | + | set sum += i; |
|
| 7 | 7 | } |
|
| 8 | 8 | return sum / numbers.len; |
|
| 9 | 9 | } |
test/tests/bool.short.circuit.rad
+1 -1
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | //! Test short-circuiting behavior of 'and' and 'or' operators. |
|
| 3 | 3 | fn modify(counter: *mut i32, ret: bool) -> bool { |
|
| 4 | - | *counter += 1; |
|
| 4 | + | set *counter += 1; |
|
| 5 | 5 | return ret; |
|
| 6 | 6 | } |
|
| 7 | 7 | ||
| 8 | 8 | @default fn main() -> i32 { |
|
| 9 | 9 | // Test 'and' short-circuits when first operand is false. |
test/tests/builtin.sliceof.mut.rad
+8 -8
| 9 | 9 | ||
| 10 | 10 | // Create a mutable slice from the pointer and length |
|
| 11 | 11 | let slice: *mut [i32] = @sliceOf(ptr, 4); |
|
| 12 | 12 | ||
| 13 | 13 | // Double each element via the slice |
|
| 14 | - | slice[0] *= 2; |
|
| 15 | - | slice[1] *= 2; |
|
| 16 | - | slice[2] *= 2; |
|
| 17 | - | slice[3] *= 2; |
|
| 14 | + | set slice[0] *= 2; |
|
| 15 | + | set slice[1] *= 2; |
|
| 16 | + | set slice[2] *= 2; |
|
| 17 | + | set slice[3] *= 2; |
|
| 18 | 18 | ||
| 19 | 19 | // Sum the modified elements |
|
| 20 | 20 | let mut sum: i32 = 0; |
|
| 21 | - | sum += slice[0]; |
|
| 22 | - | sum += slice[1]; |
|
| 23 | - | sum += slice[2]; |
|
| 24 | - | sum += slice[3]; |
|
| 21 | + | set sum += slice[0]; |
|
| 22 | + | set sum += slice[1]; |
|
| 23 | + | set sum += slice[2]; |
|
| 24 | + | set sum += slice[3]; |
|
| 25 | 25 | ||
| 26 | 26 | return (sum) - 200; |
|
| 27 | 27 | } |
test/tests/builtin.sliceof.rad
+4 -4
| 10 | 10 | // Create a slice from the pointer and length |
|
| 11 | 11 | let slice: *[i32] = @sliceOf(ptr, 4); |
|
| 12 | 12 | ||
| 13 | 13 | // Access elements via the slice and sum them |
|
| 14 | 14 | let mut sum: i32 = 0; |
|
| 15 | - | sum += slice[0]; |
|
| 16 | - | sum += slice[1]; |
|
| 17 | - | sum += slice[2]; |
|
| 18 | - | sum += slice[3]; |
|
| 15 | + | set sum += slice[0]; |
|
| 16 | + | set sum += slice[1]; |
|
| 17 | + | set sum += slice[2]; |
|
| 18 | + | set sum += slice[3]; |
|
| 19 | 19 | ||
| 20 | 20 | return sum; |
|
| 21 | 21 | } |
test/tests/byte.load.store.rad
+2 -2
| 3 | 3 | fn loadByte(ptr: *u8) -> u8 { |
|
| 4 | 4 | return *ptr; |
|
| 5 | 5 | } |
|
| 6 | 6 | ||
| 7 | 7 | fn storeByte(ptr: *mut u8, val: u8) { |
|
| 8 | - | *ptr = val; |
|
| 8 | + | set *ptr = val; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | fn loadStoreByte(src: *u8, dst: *mut u8) { |
|
| 12 | - | *dst = *src; |
|
| 12 | + | set *dst = *src; |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | fn byteArrayAccess(arr: [u8; 4], idx: u32) -> u8 { |
|
| 16 | 16 | return arr[idx]; |
|
| 17 | 17 | } |
test/tests/call.clobber.rad
+1 -1
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | //! Test that values live across function calls are not clobbered. |
|
| 3 | 3 | fn modify(counter: *mut i32, ret: bool) -> bool { |
|
| 4 | - | *counter += 1; |
|
| 4 | + | set *counter += 1; |
|
| 5 | 5 | return ret; |
|
| 6 | 6 | } |
|
| 7 | 7 | ||
| 8 | 8 | @default fn main() -> i32 { |
|
| 9 | 9 | let mut x: i32 = 0; |
test/tests/casting.numbers.rad
+2 -2
| 2 | 2 | //! Test integer casting: zero-extension, sign-extension, truncation. |
|
| 3 | 3 | ||
| 4 | 4 | fn zeroExtension() -> bool { |
|
| 5 | 5 | let x: u8 = 9; |
|
| 6 | 6 | let mut y: i32 = 42424242; |
|
| 7 | - | y = x as i32; |
|
| 7 | + | set y = x as i32; |
|
| 8 | 8 | let z: u8 = y as u8; |
|
| 9 | 9 | ||
| 10 | 10 | return y == 9 and z == 9; |
|
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | fn casting() -> bool { |
|
| 14 | 14 | let x: u8 = 5; |
|
| 15 | 15 | let y: i16 = 10; |
|
| 16 | 16 | let mut z: i32 = y as i32; |
|
| 17 | 17 | ||
| 18 | - | z = 11 as i32 + z; |
|
| 18 | + | set z = 11 as i32 + z; |
|
| 19 | 19 | ||
| 20 | 20 | return ((x as i32) + z) == 26; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | fn signedCasting() -> bool { |
test/tests/compound.assign.field.rad
+3 -3
| 6 | 6 | } |
|
| 7 | 7 | ||
| 8 | 8 | @default fn main() -> i32 { |
|
| 9 | 9 | let mut p = Point { x: 10, y: 20 }; |
|
| 10 | 10 | ||
| 11 | - | p.x += 5; |
|
| 11 | + | set p.x += 5; |
|
| 12 | 12 | assert p.x == 15; |
|
| 13 | 13 | ||
| 14 | - | p.y -= 3; |
|
| 14 | + | set p.y -= 3; |
|
| 15 | 15 | assert p.y == 17; |
|
| 16 | 16 | ||
| 17 | - | p.x *= 2; |
|
| 17 | + | set p.x *= 2; |
|
| 18 | 18 | assert p.x == 30; |
|
| 19 | 19 | ||
| 20 | 20 | return 0; |
|
| 21 | 21 | } |
test/tests/compound.assign.rad
+15 -15
| 2 | 2 | /// Test compound assignment operators (+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=). |
|
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut a: i32 = 10; |
|
| 5 | 5 | ||
| 6 | 6 | // Test += |
|
| 7 | - | a += 5; |
|
| 7 | + | set a += 5; |
|
| 8 | 8 | assert a == 15; |
|
| 9 | 9 | ||
| 10 | 10 | // Test -= |
|
| 11 | - | a -= 3; |
|
| 11 | + | set a -= 3; |
|
| 12 | 12 | assert a == 12; |
|
| 13 | 13 | ||
| 14 | 14 | // Test *= |
|
| 15 | - | a *= 2; |
|
| 15 | + | set a *= 2; |
|
| 16 | 16 | assert a == 24; |
|
| 17 | 17 | ||
| 18 | 18 | // Test /= |
|
| 19 | - | a /= 4; |
|
| 19 | + | set a /= 4; |
|
| 20 | 20 | assert a == 6; |
|
| 21 | 21 | ||
| 22 | 22 | // Test %= |
|
| 23 | - | a %= 4; |
|
| 23 | + | set a %= 4; |
|
| 24 | 24 | assert a == 2; |
|
| 25 | 25 | ||
| 26 | 26 | // Test &= |
|
| 27 | 27 | let mut b: i32 = 0xFF; |
|
| 28 | - | b &= 0x0F; |
|
| 28 | + | set b &= 0x0F; |
|
| 29 | 29 | assert b == 0x0F; |
|
| 30 | 30 | ||
| 31 | 31 | // Test |= |
|
| 32 | - | b |= 0xF0; |
|
| 32 | + | set b |= 0xF0; |
|
| 33 | 33 | assert b == 0xFF; |
|
| 34 | 34 | ||
| 35 | 35 | // Test ^= |
|
| 36 | - | b ^= 0x0F; |
|
| 36 | + | set b ^= 0x0F; |
|
| 37 | 37 | assert b == 0xF0; |
|
| 38 | 38 | ||
| 39 | 39 | // Test <<= |
|
| 40 | 40 | let mut c: i32 = 1; |
|
| 41 | - | c <<= 4; |
|
| 41 | + | set c <<= 4; |
|
| 42 | 42 | assert c == 16; |
|
| 43 | 43 | ||
| 44 | 44 | // Test >>= |
|
| 45 | - | c >>= 2; |
|
| 45 | + | set c >>= 2; |
|
| 46 | 46 | assert c == 4; |
|
| 47 | 47 | ||
| 48 | 48 | // Test compound assignment with array subscript. |
|
| 49 | 49 | let mut arr: [i32; 3] = [10, 20, 30]; |
|
| 50 | - | arr[1] += 5; |
|
| 50 | + | set arr[1] += 5; |
|
| 51 | 51 | assert arr[1] == 25; |
|
| 52 | 52 | ||
| 53 | 53 | // Test compound assignment with pointer dereference. |
|
| 54 | 54 | let mut val: i32 = 100; |
|
| 55 | 55 | let p: *mut i32 = &mut val; |
|
| 56 | - | *p += 50; |
|
| 56 | + | set *p += 50; |
|
| 57 | 57 | assert val == 150; |
|
| 58 | 58 | ||
| 59 | 59 | // Test chained compound assignments. |
|
| 60 | 60 | let mut x: i32 = 1; |
|
| 61 | - | x += 2; |
|
| 62 | - | x *= 3; |
|
| 63 | - | x -= 1; |
|
| 61 | + | set x += 2; |
|
| 62 | + | set x *= 3; |
|
| 63 | + | set x -= 1; |
|
| 64 | 64 | assert x == 8; |
|
| 65 | 65 | ||
| 66 | 66 | return 0; |
|
| 67 | 67 | } |
test/tests/cond.assign.merge.basic.rad
+2 -2
| 1 | 1 | /// Return a value assigned from either branch of a conditional. |
|
| 2 | 2 | fn condAssignMergeBasic(flag: bool) -> i32 { |
|
| 3 | 3 | let mut x: i32 = 0; |
|
| 4 | 4 | if flag { |
|
| 5 | - | x = 1; |
|
| 5 | + | set x = 1; |
|
| 6 | 6 | } else { |
|
| 7 | - | x = 2; |
|
| 7 | + | set x = 2; |
|
| 8 | 8 | } |
|
| 9 | 9 | return x; |
|
| 10 | 10 | } |
test/tests/cond.assign.merge.rad
+2 -2
| 1 | 1 | /// Returns a value assigned from either branch of a conditional. |
|
| 2 | 2 | fn condAssignMerge(x: i32) -> i32 { |
|
| 3 | 3 | let mut y: i32 = 0; |
|
| 4 | 4 | if x > 0 { |
|
| 5 | - | y = 1; |
|
| 5 | + | set y = 1; |
|
| 6 | 6 | } else { |
|
| 7 | - | y = 2; |
|
| 7 | + | set y = 2; |
|
| 8 | 8 | } |
|
| 9 | 9 | return y; |
|
| 10 | 10 | } |
test/tests/cond.assign.rad
+7 -7
| 6 | 6 | @default fn main() -> i32 { |
|
| 7 | 7 | // Simple `if-else` with variable assignment. |
|
| 8 | 8 | let t: bool = true; |
|
| 9 | 9 | let mut x: i32 = 0; |
|
| 10 | 10 | if t { |
|
| 11 | - | x = 1; |
|
| 11 | + | set x = 1; |
|
| 12 | 12 | } else { |
|
| 13 | - | x = 2; |
|
| 13 | + | set x = 2; |
|
| 14 | 14 | } |
|
| 15 | 15 | assert x == 1; |
|
| 16 | 16 | ||
| 17 | 17 | // `if-else` with `false` condition. |
|
| 18 | 18 | let f: bool = false; |
|
| 19 | 19 | if f { |
|
| 20 | - | x = 10; |
|
| 20 | + | set x = 10; |
|
| 21 | 21 | } else { |
|
| 22 | - | x = 20; |
|
| 22 | + | set x = 20; |
|
| 23 | 23 | } |
|
| 24 | 24 | assert x == 20; |
|
| 25 | 25 | ||
| 26 | 26 | // `if-else` chain. |
|
| 27 | 27 | let a: i32 = 5; |
|
| 28 | 28 | if a == 3 { |
|
| 29 | - | x = 100; |
|
| 29 | + | set x = 100; |
|
| 30 | 30 | } else if a == 5 { |
|
| 31 | - | x = 200; |
|
| 31 | + | set x = 200; |
|
| 32 | 32 | } else { |
|
| 33 | - | x = 300; |
|
| 33 | + | set x = 300; |
|
| 34 | 34 | } |
|
| 35 | 35 | assert x == 200; |
|
| 36 | 36 | return 0; |
|
| 37 | 37 | } |
test/tests/cond.for.else.break.rad
+2 -2
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut i: i32 = 0; |
|
| 5 | 5 | let xs: [i32; 7] = [1, 2, 3, 4, 5, 6, 7]; |
|
| 6 | 6 | ||
| 7 | 7 | for x in (xs) { |
|
| 8 | - | i += x; |
|
| 8 | + | set i += x; |
|
| 9 | 9 | if (i >= 10) { |
|
| 10 | 10 | break; // This should skip the else clause. |
|
| 11 | 11 | } |
|
| 12 | 12 | } else { |
|
| 13 | - | i += 100; // This should NOT run because we break. |
|
| 13 | + | set i += 100; // This should NOT run because we break. |
|
| 14 | 14 | } |
|
| 15 | 15 | return (i) - 10; |
|
| 16 | 16 | } |
test/tests/cond.for.indexed.rad
+1 -1
| 3 | 3 | @default fn main() -> u32 { |
|
| 4 | 4 | let arr: [u32; 3] = [10, 20, 30]; |
|
| 5 | 5 | let mut sum: u32 = 0; |
|
| 6 | 6 | ||
| 7 | 7 | for value, index in arr { |
|
| 8 | - | sum += value + index; |
|
| 8 | + | set sum += value + index; |
|
| 9 | 9 | } |
|
| 10 | 10 | return (sum) - 63; |
|
| 11 | 11 | // (10+0) + (20+1) + (30+2) = 10 + 21 + 32 = 63 |
|
| 12 | 12 | } |
test/tests/cond.for.rad
+1 -1
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut i: i32 = 0; |
|
| 5 | 5 | let xs: [i32; 7] = [1, 2, 3, 4, 5, 6, 7]; |
|
| 6 | 6 | ||
| 7 | 7 | for x in (xs) { |
|
| 8 | - | i += x; |
|
| 8 | + | set i += x; |
|
| 9 | 9 | } |
|
| 10 | 10 | return (i) - 28; |
|
| 11 | 11 | } |
test/tests/cond.for.range.indexed.rad
+2 -2
| 6 | 6 | // Test range iteration with index. |
|
| 7 | 7 | // val: 5, 6, 7, 8 |
|
| 8 | 8 | // idx: 0, 1, 2, 3 |
|
| 9 | 9 | // sum: (5+0) + (6+1) + (7+2) + (8+3) = 5 + 7 + 9 + 11 = 32 |
|
| 10 | 10 | for val, idx in 5..9 { |
|
| 11 | - | sum += val + idx as i32; |
|
| 11 | + | set sum += val + idx as i32; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | // Test that value starts from a non-zero offset while index starts at 0. |
|
| 15 | 15 | // val: 10, 11 |
|
| 16 | 16 | // idx: 0, 1 |
|
| 17 | 17 | // sum: 32 + (10-0) + (11-1) = 32 + 10 + 10 = 52 |
|
| 18 | 18 | for v, i in 10..12 { |
|
| 19 | - | sum += v - i as i32; |
|
| 19 | + | set sum += v - i as i32; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | return (sum) - 52; |
|
| 23 | 23 | } |
test/tests/cond.for.range.rad
+1 -1
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let xs: [i32; 4] = [3, 4, 5, 6]; |
|
| 5 | 5 | let mut sum: i32 = 0; |
|
| 6 | 6 | ||
| 7 | 7 | for i in 0..xs.len { |
|
| 8 | - | sum += xs[i]; |
|
| 8 | + | set sum += xs[i]; |
|
| 9 | 9 | } |
|
| 10 | 10 | return (sum) - 18; |
|
| 11 | 11 | } |
test/tests/cond.for.unsigned.range.rad
+3 -3
| 4 | 4 | let start: u32 = 2147483647; |
|
| 5 | 5 | let end: u32 = 2147483648; |
|
| 6 | 6 | let mut count: i32 = 0; |
|
| 7 | 7 | ||
| 8 | 8 | for i in start..end { |
|
| 9 | - | count += 1; |
|
| 9 | + | set count += 1; |
|
| 10 | 10 | } |
|
| 11 | 11 | assert count == 1; |
|
| 12 | 12 | ||
| 13 | 13 | // Unsigned range above signed boundary. |
|
| 14 | 14 | let start2: u32 = 2147483648; |
|
| 15 | 15 | let end2: u32 = 2147483651; |
|
| 16 | 16 | let mut count2: i32 = 0; |
|
| 17 | 17 | ||
| 18 | 18 | for i in start2..end2 { |
|
| 19 | - | count2 += 1; |
|
| 19 | + | set count2 += 1; |
|
| 20 | 20 | } |
|
| 21 | 21 | assert count2 == 3; |
|
| 22 | 22 | ||
| 23 | 23 | // Signed range still uses signed ordering. |
|
| 24 | 24 | let mut sum: i32 = 0; |
|
| 25 | 25 | for i in -2..2 { |
|
| 26 | - | sum += i; |
|
| 26 | + | set sum += i; |
|
| 27 | 27 | } |
|
| 28 | 28 | assert sum == -2; |
|
| 29 | 29 | ||
| 30 | 30 | return 0; |
|
| 31 | 31 | } |
test/tests/cond.forever.break.continue.rad
+1 -1
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let mut i: i32 = 0; |
|
| 4 | 4 | ||
| 5 | 5 | loop { |
|
| 6 | 6 | if (i < 42) { |
|
| 7 | - | i += 1; |
|
| 7 | + | set i += 1; |
|
| 8 | 8 | continue; |
|
| 9 | 9 | } |
|
| 10 | 10 | break; |
|
| 11 | 11 | } |
|
| 12 | 12 | return (i) - 42; |
test/tests/cond.forever.break.rad
+2 -2
| 5 | 5 | loop { |
|
| 6 | 6 | loop { |
|
| 7 | 7 | if (i > 39) { |
|
| 8 | 8 | break; |
|
| 9 | 9 | } |
|
| 10 | - | i += 1; |
|
| 10 | + | set i += 1; |
|
| 11 | 11 | } |
|
| 12 | - | i += 2; |
|
| 12 | + | set i += 2; |
|
| 13 | 13 | break; |
|
| 14 | 14 | } |
|
| 15 | 15 | return (i) - 42; |
|
| 16 | 16 | } |
test/tests/cond.if.else.rad
+1 -1
| 3 | 3 | let mut i: i32 = 41; |
|
| 4 | 4 | ||
| 5 | 5 | if (i == 42) { |
|
| 6 | 6 | return (1) - 42; |
|
| 7 | 7 | } else { |
|
| 8 | - | i += 1; |
|
| 8 | + | set i += 1; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | if (i == 42) { |
|
| 12 | 12 | return (42) - 42; |
|
| 13 | 13 | } else { |
test/tests/cond.if.elseif.rad
+2 -2
| 5 | 5 | if (i == 42) { |
|
| 6 | 6 | return (1) - 42; |
|
| 7 | 7 | } else if (i == 41) { |
|
| 8 | 8 | return (1) - 42; |
|
| 9 | 9 | } else if (i == 40) { |
|
| 10 | - | i += 2; |
|
| 10 | + | set i += 2; |
|
| 11 | 11 | } else { |
|
| 12 | - | i += 1; |
|
| 12 | + | set i += 1; |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | if (i == 42) { |
|
| 16 | 16 | return (42) - 42; |
|
| 17 | 17 | } else if (i == 41) { |
test/tests/cond.if.noelse.rad
+1 -1
| 2 | 2 | ||
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut x: i32 = 10; |
|
| 5 | 5 | ||
| 6 | 6 | if (x == 11) { |
|
| 7 | - | x = 20; |
|
| 7 | + | set x = 20; |
|
| 8 | 8 | } |
|
| 9 | 9 | ||
| 10 | 10 | return (x) - 10; |
|
| 11 | 11 | } |
test/tests/cond.iflet.mut.rad
+1 -1
| 1 | 1 | //! `if let mut` binding with mutation of the bound variable. |
|
| 2 | 2 | fn ifLetMut(p: ?i32) -> i32 { |
|
| 3 | 3 | if let mut x = p { |
|
| 4 | - | x = x + 1; |
|
| 4 | + | set x = x + 1; |
|
| 5 | 5 | return x; |
|
| 6 | 6 | } else { |
|
| 7 | 7 | return 0; |
|
| 8 | 8 | } |
|
| 9 | 9 | } |
test/tests/cond.letelse.mut.rad
+1 -1
| 1 | 1 | //! `let mut ... else` binding with mutation of the bound variable. |
|
| 2 | 2 | fn letMutElse(p: ?i32) -> i32 { |
|
| 3 | 3 | let mut x = p else { |
|
| 4 | 4 | return 0; |
|
| 5 | 5 | }; |
|
| 6 | - | x = x + 1; |
|
| 6 | + | set x = x + 1; |
|
| 7 | 7 | return x; |
|
| 8 | 8 | } |
test/tests/cond.match.fallthrough.rad
+1 -1
| 4 | 4 | let mut x: i32 = 1; |
|
| 5 | 5 | ||
| 6 | 6 | match (x) { |
|
| 7 | 7 | case 1 => { |
|
| 8 | 8 | // This case matches, changes x to 2 and should jump to end. |
|
| 9 | - | x = 2; |
|
| 9 | + | set x = 2; |
|
| 10 | 10 | }, |
|
| 11 | 11 | case 2 => { return (2) - 42; }, |
|
| 12 | 12 | else => { return (0) - 42; } |
|
| 13 | 13 | } |
|
| 14 | 14 | return (42) - 42; |
test/tests/cond.match.guard.rad
+4 -4
| 8 | 8 | ||
| 9 | 9 | fn checkStmt(value: OptionNum) -> i32 { |
|
| 10 | 10 | let mut result: i32 = -100; |
|
| 11 | 11 | match value { |
|
| 12 | 12 | case OptionNum::Some(payload) if payload == 5 => { |
|
| 13 | - | result = payload; |
|
| 13 | + | set result = payload; |
|
| 14 | 14 | } |
|
| 15 | 15 | case OptionNum::Some(payload) => { |
|
| 16 | - | result = -payload; |
|
| 16 | + | set result = -payload; |
|
| 17 | 17 | } |
|
| 18 | 18 | case OptionNum::Other(payload) if payload == 7 => { |
|
| 19 | - | result = payload * 2; |
|
| 19 | + | set result = payload * 2; |
|
| 20 | 20 | } |
|
| 21 | 21 | else => { |
|
| 22 | - | result = 0; |
|
| 22 | + | set result = 0; |
|
| 23 | 23 | } |
|
| 24 | 24 | } |
|
| 25 | 25 | return result; |
|
| 26 | 26 | } |
|
| 27 | 27 |
test/tests/cond.match.guard.regalloc.rad
+3 -3
| 23 | 23 | fn getPath(node: *Node, buf: *mut [*[u8]]) -> *[*[u8]] { |
|
| 24 | 24 | let mut out: *[*[u8]] = &[]; |
|
| 25 | 25 | ||
| 26 | 26 | match node.kind { |
|
| 27 | 27 | case Kind::Name(name) if name.len > 0 => { |
|
| 28 | - | buf[0] = name; |
|
| 29 | - | out = &buf[..1]; |
|
| 28 | + | set buf[0] = name; |
|
| 29 | + | set out = &buf[..1]; |
|
| 30 | 30 | } |
|
| 31 | 31 | case Kind::Pair { a, b } => { |
|
| 32 | - | out = &buf[..1]; |
|
| 32 | + | set out = &buf[..1]; |
|
| 33 | 33 | } |
|
| 34 | 34 | else => {} |
|
| 35 | 35 | } |
|
| 36 | 36 | return out; |
|
| 37 | 37 | } |
test/tests/cond.while.else.break.rad
+2 -2
| 2 | 2 | ||
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut i: i32 = 0; |
|
| 5 | 5 | ||
| 6 | 6 | while (i < 100) { |
|
| 7 | - | i += 1; |
|
| 7 | + | set i += 1; |
|
| 8 | 8 | if (i == 42) { |
|
| 9 | 9 | break; // This should skip the else clause. |
|
| 10 | 10 | } |
|
| 11 | 11 | } else { |
|
| 12 | - | i += 100; // This should NOT run because we break. |
|
| 12 | + | set i += 100; // This should NOT run because we break. |
|
| 13 | 13 | } |
|
| 14 | 14 | return (i) - 42; |
|
| 15 | 15 | } |
test/tests/cond.while.rad
+1 -1
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let mut i: i32 = 0; |
|
| 4 | 4 | ||
| 5 | 5 | while (i < 42) { |
|
| 6 | - | i += 1; |
|
| 6 | + | set i += 1; |
|
| 7 | 7 | } |
|
| 8 | 8 | return (i) - 42; |
|
| 9 | 9 | } |
test/tests/const.array.copy.mutate.rad
+2 -2
| 4 | 4 | constant SEED: [i32; 4] = [1, 2, 3, 4]; |
|
| 5 | 5 | ||
| 6 | 6 | fn crunch() -> i32 { |
|
| 7 | 7 | let mut working: [i32; 4] = SEED; |
|
| 8 | 8 | ||
| 9 | - | working[0] += 5; |
|
| 10 | - | working[3] = working[1] + working[2]; |
|
| 9 | + | set working[0] += 5; |
|
| 10 | + | set working[3] = working[1] + working[2]; |
|
| 11 | 11 | ||
| 12 | 12 | return working[0] + working[3]; |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | @default fn main() -> i32 { |
test/tests/const.array.rad
+1 -1
| 4 | 4 | constant NUMBERS: [i32; 4] = [1, 2, 3, 4]; |
|
| 5 | 5 | ||
| 6 | 6 | @default fn main() -> i32 { |
|
| 7 | 7 | let mut sum: i32 = 0; |
|
| 8 | 8 | for n in (NUMBERS) { |
|
| 9 | - | sum += n; |
|
| 9 | + | set sum += n; |
|
| 10 | 10 | } |
|
| 11 | 11 | return (sum) - 10; |
|
| 12 | 12 | } |
test/tests/const.record.array.rad
+1 -1
| 15 | 15 | ||
| 16 | 16 | fn sumPoints(points: [Point; 3]) -> i32 { |
|
| 17 | 17 | let mut sum: i32 = 0; |
|
| 18 | 18 | ||
| 19 | 19 | for p in (points) { |
|
| 20 | - | sum += p.x + p.y; |
|
| 20 | + | set sum += p.x + p.y; |
|
| 21 | 21 | } |
|
| 22 | 22 | return sum; |
|
| 23 | 23 | } |
|
| 24 | 24 | ||
| 25 | 25 | // Array of structs as a function parameter |
test/tests/const.record.array.simple.rad
+3 -3
| 15 | 15 | ||
| 16 | 16 | @default fn main() -> i32 { |
|
| 17 | 17 | let mut sum: i32 = 0; |
|
| 18 | 18 | ||
| 19 | 19 | // Add all points' x and y values |
|
| 20 | - | sum += POINTS[0].x + POINTS[0].y; // 1 + 2 = 3 |
|
| 21 | - | sum += POINTS[1].x + POINTS[1].y; // 3 + 4 = 7 |
|
| 22 | - | sum += POINTS[2].x + POINTS[2].y; // 5 + 6 = 11 |
|
| 20 | + | set sum += POINTS[0].x + POINTS[0].y; // 1 + 2 = 3 |
|
| 21 | + | set sum += POINTS[1].x + POINTS[1].y; // 3 + 4 = 7 |
|
| 22 | + | set sum += POINTS[2].x + POINTS[2].y; // 5 + 6 = 11 |
|
| 23 | 23 | ||
| 24 | 24 | return (sum) - 21; // 3 + 7 + 11 = 21 |
|
| 25 | 25 | } |
test/tests/const.record.mutcopy.rad
+1 -1
| 8 | 8 | ||
| 9 | 9 | /// Returns a scratch register, avoiding the one already used by `rs`. |
|
| 10 | 10 | fn test(rs: Reg) -> Reg { |
|
| 11 | 11 | let mut scratch = SCRATCH1; |
|
| 12 | 12 | if rs.n == SCRATCH1.n { |
|
| 13 | - | scratch = SCRATCH2; |
|
| 13 | + | set scratch = SCRATCH2; |
|
| 14 | 14 | } |
|
| 15 | 15 | return scratch; |
|
| 16 | 16 | } |
test/tests/edge.cases.4.rad
+2 -2
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | fn node(nodes: *mut Node, count: *mut u32, value: NodeValue) -> *Node { |
|
| 24 | 24 | let index = *count; |
|
| 25 | 25 | let slot = nodes + index; |
|
| 26 | - | *slot = Node { value }; |
|
| 27 | - | *count = index + 1; |
|
| 26 | + | set *slot = Node { value }; |
|
| 27 | + | set *count = index + 1; |
|
| 28 | 28 | return slot; |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | fn nodeTypeInt(nodes: *mut Node, count: *mut u32, width: u8, sign: Signedness) -> *Node { |
|
| 32 | 32 | return node(nodes, count, NodeValue::TypeSig( |
test/tests/edge.cases.6.rad
+4 -4
| 58 | 58 | t: 0x1234560F, |
|
| 59 | 59 | }; |
|
| 60 | 60 | static ANALYZER: Analyzer = undefined; |
|
| 61 | 61 | ||
| 62 | 62 | fn fillEntry(out: *mut Entry) { |
|
| 63 | - | *out = DEFAULT_ENTRY; |
|
| 63 | + | set *out = DEFAULT_ENTRY; |
|
| 64 | 64 | } |
|
| 65 | 65 | ||
| 66 | 66 | fn mkEntry() -> Entry { |
|
| 67 | 67 | return DEFAULT_ENTRY; |
|
| 68 | 68 | } |
| 73 | 73 | } |
|
| 74 | 74 | return mkEntry(); |
|
| 75 | 75 | } |
|
| 76 | 76 | ||
| 77 | 77 | fn init(entries: *mut [Entry]) { |
|
| 78 | - | ANALYZER = Analyzer { |
|
| 78 | + | set ANALYZER = Analyzer { |
|
| 79 | 79 | pad0: 0xDEADAAA0, |
|
| 80 | 80 | pad1: 0xDEADAAA1, |
|
| 81 | 81 | entries, |
|
| 82 | 82 | len: 0, |
|
| 83 | 83 | }; |
| 86 | 86 | fn add() { |
|
| 87 | 87 | let idx = ANALYZER.len; |
|
| 88 | 88 | let entry = mkOptEntry(true) else { |
|
| 89 | 89 | return; |
|
| 90 | 90 | }; |
|
| 91 | - | ANALYZER.entries[idx] = entry; |
|
| 92 | - | ANALYZER.len = idx + 1; |
|
| 91 | + | set ANALYZER.entries[idx] = entry; |
|
| 92 | + | set ANALYZER.len = idx + 1; |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | 95 | fn checkHeader(expected: *[Entry]) -> i32 { |
|
| 96 | 96 | if ANALYZER.entries.ptr <> expected.ptr or ANALYZER.entries.len <> expected.len { |
|
| 97 | 97 | // Slice header got clobbered instead of the backing storage. |
test/tests/edge.cases.7.addr.bug.rad
+2 -2
| 6 | 6 | ||
| 7 | 7 | static target: i32 = 10; |
|
| 8 | 8 | static holder: PtrHolder = undefined; |
|
| 9 | 9 | ||
| 10 | 10 | @default fn main() -> i32 { |
|
| 11 | - | holder.ptr = &mut target; |
|
| 12 | - | *holder.ptr = 42; |
|
| 11 | + | set holder.ptr = &mut target; |
|
| 12 | + | set *holder.ptr = 42; |
|
| 13 | 13 | ||
| 14 | 14 | return target; |
|
| 15 | 15 | } |
test/tests/edge.cases.8.bug.rad
+1 -1
| 17 | 17 | fn readInner(i: Inner) -> i32 { |
|
| 18 | 18 | return i.value; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | @default fn main() -> i32 { |
|
| 22 | - | global = Outer { padding: 0, inner: Inner { value: 42 } }; |
|
| 22 | + | set global = Outer { padding: 0, inner: Inner { value: 42 } }; |
|
| 23 | 23 | ||
| 24 | 24 | assert readInner(global.inner) == 42; |
|
| 25 | 25 | return 0; |
|
| 26 | 26 | } |
test/tests/error.catch.rad
+1 -1
| 13 | 13 | assert val2 == 21; |
|
| 14 | 14 | ||
| 15 | 15 | // Catch block that discards error |
|
| 16 | 16 | let mut flag: u32 = 0; |
|
| 17 | 17 | try returnsErr() catch {}; |
|
| 18 | - | flag = 1; |
|
| 18 | + | set flag = 1; |
|
| 19 | 19 | assert flag == 1; |
|
| 20 | 20 | ||
| 21 | 21 | // Catch block with return in function |
|
| 22 | 22 | let val3: u32 = returnsEarly(); |
|
| 23 | 23 | assert val3 == 42; |
test/tests/error.multi.basic.rad
+3 -3
| 18 | 18 | ||
| 19 | 19 | @default fn main() -> i32 { |
|
| 20 | 20 | // Test throwing ErrA. |
|
| 21 | 21 | let mut caught: i32 = 0; |
|
| 22 | 22 | try failA() catch { |
|
| 23 | - | caught = 1; |
|
| 23 | + | set caught = 1; |
|
| 24 | 24 | }; |
|
| 25 | 25 | assert caught == 1; |
|
| 26 | 26 | ||
| 27 | 27 | // Test throwing ErrB. |
|
| 28 | - | caught = 0; |
|
| 28 | + | set caught = 0; |
|
| 29 | 29 | try failB() catch { |
|
| 30 | - | caught = 2; |
|
| 30 | + | set caught = 2; |
|
| 31 | 31 | }; |
|
| 32 | 32 | assert caught == 2; |
|
| 33 | 33 | ||
| 34 | 34 | // Test success path. |
|
| 35 | 35 | let val = try succeed() catch { |
test/tests/error.multi.catch.rad
+5 -5
| 18 | 18 | ||
| 19 | 19 | @default fn main() -> i32 { |
|
| 20 | 20 | // Catch ErrA without binding. |
|
| 21 | 21 | let mut handled: i32 = 0; |
|
| 22 | 22 | try failA() catch { |
|
| 23 | - | handled = 1; |
|
| 23 | + | set handled = 1; |
|
| 24 | 24 | }; |
|
| 25 | 25 | assert handled == 1; |
|
| 26 | 26 | ||
| 27 | 27 | // Catch ErrB without binding. |
|
| 28 | - | handled = 0; |
|
| 28 | + | set handled = 0; |
|
| 29 | 29 | try failB() catch { |
|
| 30 | - | handled = 2; |
|
| 30 | + | set handled = 2; |
|
| 31 | 31 | }; |
|
| 32 | 32 | assert handled == 2; |
|
| 33 | 33 | ||
| 34 | 34 | // Success path should not trigger catch. |
|
| 35 | - | handled = 0; |
|
| 35 | + | set handled = 0; |
|
| 36 | 36 | let val = try succeed() catch { |
|
| 37 | - | handled = 99; |
|
| 37 | + | set handled = 99; |
|
| 38 | 38 | }; |
|
| 39 | 39 | assert handled == 0; |
|
| 40 | 40 | assert val == 99; |
|
| 41 | 41 | return 0; |
|
| 42 | 42 | } |
test/tests/error.multi.catch.typed.binding.rad
+3 -3
| 17 | 17 | let mut got: i32 = 0; |
|
| 18 | 18 | try failA(100) catch e as ErrA { |
|
| 19 | 19 | let case ErrA::A(v) = e else { |
|
| 20 | 20 | return 1; |
|
| 21 | 21 | }; |
|
| 22 | - | got = v; |
|
| 22 | + | set got = v; |
|
| 23 | 23 | } catch e as ErrB { |
|
| 24 | 24 | return 2; |
|
| 25 | 25 | }; |
|
| 26 | 26 | assert got == 100; |
|
| 27 | 27 | ||
| 28 | 28 | // Extract ErrB payload. |
|
| 29 | - | got = 0; |
|
| 29 | + | set got = 0; |
|
| 30 | 30 | try failB(200) catch e as ErrA { |
|
| 31 | 31 | return 4; |
|
| 32 | 32 | } catch e as ErrB { |
|
| 33 | 33 | let case ErrB::B(v) = e else { |
|
| 34 | 34 | return 5; |
|
| 35 | 35 | }; |
|
| 36 | - | got = v; |
|
| 36 | + | set got = v; |
|
| 37 | 37 | }; |
|
| 38 | 38 | assert got == 200; |
|
| 39 | 39 | return 0; |
|
| 40 | 40 | } |
test/tests/error.multi.catch.typed.catchall.rad
+4 -4
| 22 | 22 | let mut result: i32 = 0; |
|
| 23 | 23 | try failA() catch e as ErrA { |
|
| 24 | 24 | let case ErrA::A(v) = e else { |
|
| 25 | 25 | return 10; |
|
| 26 | 26 | }; |
|
| 27 | - | result = v; |
|
| 27 | + | set result = v; |
|
| 28 | 28 | } catch { |
|
| 29 | 29 | return 1; |
|
| 30 | 30 | }; |
|
| 31 | 31 | assert result == 10; |
|
| 32 | 32 | ||
| 33 | 33 | // ErrB should fall into catch-all. |
|
| 34 | 34 | let mut caughtAll: i32 = 0; |
|
| 35 | 35 | try failB() catch e as ErrA { |
|
| 36 | 36 | return 3; |
|
| 37 | 37 | } catch { |
|
| 38 | - | caughtAll = 1; |
|
| 38 | + | set caughtAll = 1; |
|
| 39 | 39 | }; |
|
| 40 | 40 | assert caughtAll == 1; |
|
| 41 | 41 | ||
| 42 | 42 | // ErrC should also fall into catch-all. |
|
| 43 | - | caughtAll = 0; |
|
| 43 | + | set caughtAll = 0; |
|
| 44 | 44 | try failC() catch e as ErrA { |
|
| 45 | 45 | return 5; |
|
| 46 | 46 | } catch { |
|
| 47 | - | caughtAll = 1; |
|
| 47 | + | set caughtAll = 1; |
|
| 48 | 48 | }; |
|
| 49 | 49 | assert caughtAll == 1; |
|
| 50 | 50 | return 0; |
|
| 51 | 51 | } |
test/tests/error.multi.catch.typed.rad
+3 -3
| 21 | 21 | let mut result: i32 = 0; |
|
| 22 | 22 | let val1 = try failA() catch e as ErrA { |
|
| 23 | 23 | let case ErrA::A(v) = e else { |
|
| 24 | 24 | return 10; |
|
| 25 | 25 | }; |
|
| 26 | - | result = v; |
|
| 26 | + | set result = v; |
|
| 27 | 27 | 0 |
|
| 28 | 28 | } catch e as ErrB { |
|
| 29 | 29 | return 1; |
|
| 30 | 30 | }; |
|
| 31 | 31 | assert result == 10; |
|
| 32 | 32 | ||
| 33 | 33 | // Catch ErrB specifically with typed binding. |
|
| 34 | - | result = 0; |
|
| 34 | + | set result = 0; |
|
| 35 | 35 | let val2 = try failB() catch e as ErrA { |
|
| 36 | 36 | return 3; |
|
| 37 | 37 | } catch e as ErrB { |
|
| 38 | 38 | let case ErrB::B(v) = e else { |
|
| 39 | 39 | return 11; |
|
| 40 | 40 | }; |
|
| 41 | - | result = v; |
|
| 41 | + | set result = v; |
|
| 42 | 42 | 0 |
|
| 43 | 43 | }; |
|
| 44 | 44 | assert result == 20; |
|
| 45 | 45 | ||
| 46 | 46 | // Success path should skip all catches. |
test/tests/error.multi.propagate.multi.rad
+5 -5
| 21 | 21 | ||
| 22 | 22 | @default fn main() -> i32 { |
|
| 23 | 23 | // Propagate ErrA through outer. |
|
| 24 | 24 | let mut result: i32 = 0; |
|
| 25 | 25 | try outer(1) catch e as ErrA { |
|
| 26 | - | result = 10; |
|
| 26 | + | set result = 10; |
|
| 27 | 27 | } catch e as ErrB { |
|
| 28 | - | result = 20; |
|
| 28 | + | set result = 20; |
|
| 29 | 29 | }; |
|
| 30 | 30 | assert result == 10; |
|
| 31 | 31 | ||
| 32 | 32 | // Propagate ErrB through outer. |
|
| 33 | - | result = 0; |
|
| 33 | + | set result = 0; |
|
| 34 | 34 | try outer(2) catch e as ErrA { |
|
| 35 | - | result = 10; |
|
| 35 | + | set result = 10; |
|
| 36 | 36 | } catch e as ErrB { |
|
| 37 | - | result = 20; |
|
| 37 | + | set result = 20; |
|
| 38 | 38 | }; |
|
| 39 | 39 | assert result == 20; |
|
| 40 | 40 | ||
| 41 | 41 | // Success path. |
|
| 42 | 42 | let val = try outer(0) catch e as ErrA { |
test/tests/error.multi.propagate.rad
+3 -3
| 24 | 24 | ||
| 25 | 25 | @default fn main() -> i32 { |
|
| 26 | 26 | // Propagate ErrA through middle. |
|
| 27 | 27 | let mut caught: i32 = 0; |
|
| 28 | 28 | try middle(1) catch { |
|
| 29 | - | caught = 1; |
|
| 29 | + | set caught = 1; |
|
| 30 | 30 | }; |
|
| 31 | 31 | assert caught == 1; |
|
| 32 | 32 | ||
| 33 | 33 | // Propagate ErrB through middle. |
|
| 34 | - | caught = 0; |
|
| 34 | + | set caught = 0; |
|
| 35 | 35 | try middle(2) catch { |
|
| 36 | - | caught = 2; |
|
| 36 | + | set caught = 2; |
|
| 37 | 37 | }; |
|
| 38 | 38 | assert caught == 2; |
|
| 39 | 39 | ||
| 40 | 40 | // Success path. |
|
| 41 | 41 | let val = try middle(0) catch { |
test/tests/error.try.catch.binding.rad
+7 -7
| 5 | 5 | @default fn main() -> u32 { |
|
| 6 | 6 | // Test catching and using the error value. |
|
| 7 | 7 | let mut caught: u32 = 0; |
|
| 8 | 8 | try failWithBoom() catch e { |
|
| 9 | 9 | if (e == TestError::Boom) { |
|
| 10 | - | caught = 1; |
|
| 10 | + | set caught = 1; |
|
| 11 | 11 | } else { |
|
| 12 | - | caught = 2; |
|
| 12 | + | set caught = 2; |
|
| 13 | 13 | } |
|
| 14 | 14 | }; |
|
| 15 | 15 | assert caught == 1; |
|
| 16 | 16 | ||
| 17 | 17 | // Test catching a different error variant. |
|
| 18 | - | caught = 0; |
|
| 18 | + | set caught = 0; |
|
| 19 | 19 | try failWithBust() catch e { |
|
| 20 | 20 | if (e == TestError::Bust) { |
|
| 21 | - | caught = 10; |
|
| 21 | + | set caught = 10; |
|
| 22 | 22 | } else { |
|
| 23 | - | caught = 20; |
|
| 23 | + | set caught = 20; |
|
| 24 | 24 | } |
|
| 25 | 25 | }; |
|
| 26 | 26 | assert caught == 10; |
|
| 27 | 27 | ||
| 28 | 28 | // Test that success path doesn't execute catch block. |
|
| 29 | - | caught = 0; |
|
| 29 | + | set caught = 0; |
|
| 30 | 30 | try succeed() catch e { |
|
| 31 | - | caught = 99; |
|
| 31 | + | set caught = 99; |
|
| 32 | 32 | }; |
|
| 33 | 33 | assert caught == 0; |
|
| 34 | 34 | ||
| 35 | 35 | // Test catch block that returns early from function. |
|
| 36 | 36 | let early: u32 = testCatchReturn(); |
test/tests/error.try.optional.rad
+2 -2
| 79 | 79 | ||
| 80 | 80 | // Test 7: try? in while-let loop |
|
| 81 | 81 | let mut count: u32 = 0; |
|
| 82 | 82 | let mut iter: u32 = 0; |
|
| 83 | 83 | while let value = try? maybeValue(iter) { |
|
| 84 | - | count += value; |
|
| 85 | - | iter += 1; |
|
| 84 | + | set count += value; |
|
| 85 | + | set iter += 1; |
|
| 86 | 86 | } |
|
| 87 | 87 | assert count == 6; |
|
| 88 | 88 | ||
| 89 | 89 | return 0; |
|
| 90 | 90 | } |
test/tests/error.try.rad
+13 -13
| 38 | 38 | ||
| 39 | 39 | fn shortCircuit(flag: bool) -> u32 throws (TestError) { |
|
| 40 | 40 | let mut counter: u32 = 1; |
|
| 41 | 41 | ||
| 42 | 42 | if flag { |
|
| 43 | - | counter += try returnsErr(2); |
|
| 43 | + | set counter += try returnsErr(2); |
|
| 44 | 44 | } else { |
|
| 45 | 45 | try returnsErr(0); |
|
| 46 | - | counter += 100; |
|
| 46 | + | set counter += 100; |
|
| 47 | 47 | } |
|
| 48 | 48 | return counter; |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | fn aggregateTwo() -> u32 throws (TestError) { |
| 74 | 74 | ||
| 75 | 75 | fn catchReturn(flag: *mut u32, fail: bool) -> bool { |
|
| 76 | 76 | let value: u32 = try maybeReturn(fail) catch { |
|
| 77 | 77 | return true; |
|
| 78 | 78 | }; |
|
| 79 | - | *flag = value; |
|
| 79 | + | set *flag = value; |
|
| 80 | 80 | return false; |
|
| 81 | 81 | } |
|
| 82 | 82 | ||
| 83 | 83 | fn accumulateSteps(failMid: bool) -> u32 throws (TestError) { |
|
| 84 | 84 | let mut total: u32 = 0; |
|
| 85 | 85 | let mut idx: u32 = 0; |
|
| 86 | 86 | while idx < 3 { |
|
| 87 | 87 | if failMid { |
|
| 88 | 88 | if idx == 1 { |
|
| 89 | - | total += try returnsErr(0); |
|
| 89 | + | set total += try returnsErr(0); |
|
| 90 | 90 | } else { |
|
| 91 | - | total += try returnsErr(2); |
|
| 91 | + | set total += try returnsErr(2); |
|
| 92 | 92 | } |
|
| 93 | 93 | } else { |
|
| 94 | - | total += try returnsErr(2); |
|
| 94 | + | set total += try returnsErr(2); |
|
| 95 | 95 | } |
|
| 96 | - | idx += 1; |
|
| 96 | + | set idx += 1; |
|
| 97 | 97 | } |
|
| 98 | 98 | return total; |
|
| 99 | 99 | } |
|
| 100 | 100 | ||
| 101 | 101 | fn structSuccess(state: *mut ResultSink) -> u32 throws (TestError) { |
|
| 102 | 102 | let value: u32 = try returnsOk(); |
|
| 103 | - | state.last = value; |
|
| 104 | - | state.count += 1; |
|
| 103 | + | set state.last = value; |
|
| 104 | + | set state.count += 1; |
|
| 105 | 105 | return value; |
|
| 106 | 106 | } |
|
| 107 | 107 | ||
| 108 | 108 | fn structFailure(state: *mut ResultSink) -> u32 throws (TestError) { |
|
| 109 | 109 | try returnsErr(1); |
|
| 110 | - | state.last = 999; |
|
| 110 | + | set state.last = 999; |
|
| 111 | 111 | return 999; |
|
| 112 | 112 | } |
|
| 113 | 113 | ||
| 114 | 114 | @default fn main() -> i32 { |
|
| 115 | 115 | let mut sumFlag: u32 = 0; |
|
| 116 | 116 | let total: u32 = try! sumThree(); |
|
| 117 | 117 | assert total == 39; |
|
| 118 | - | sumFlag = total; |
|
| 118 | + | set sumFlag = total; |
|
| 119 | 119 | ||
| 120 | 120 | let mut scOkFlag: u32 = 0; |
|
| 121 | 121 | let scVal: u32 = try! shortCircuit(true); |
|
| 122 | 122 | assert scVal == 10; |
|
| 123 | - | scOkFlag = scVal; |
|
| 123 | + | set scOkFlag = scVal; |
|
| 124 | 124 | ||
| 125 | 125 | let mut scErrFlag: u32 = 0; |
|
| 126 | 126 | try shortCircuit(false) catch {}; |
|
| 127 | 127 | assert scErrFlag == 0; |
|
| 128 | 128 |
| 156 | 156 | try structFailure(&mut sink) catch {}; |
|
| 157 | 157 | assert sink.count == 2; |
|
| 158 | 158 | ||
| 159 | 159 | let mut voidOkFlag: u32 = 0; |
|
| 160 | 160 | try! returnsOkVoid(); |
|
| 161 | - | voidOkFlag = 77; |
|
| 161 | + | set voidOkFlag = 77; |
|
| 162 | 162 | assert voidOkFlag == 77; |
|
| 163 | 163 | ||
| 164 | 164 | let mut voidErrFlag: u32 = 0; |
|
| 165 | 165 | try returnsErrVoid() catch {}; |
|
| 166 | 166 | assert voidErrFlag == 0; |
test/tests/fn.callback.nested.rad
+1 -1
| 17 | 17 | return current; |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | fn maxRegCallback(reg: Reg, ctx: *mut opaque) { |
|
| 21 | 21 | let max = ctx as *mut u32; |
|
| 22 | - | *max = maxRegNum(reg.n, *max); |
|
| 22 | + | set *max = maxRegNum(reg.n, *max); |
|
| 23 | 23 | } |
|
| 24 | 24 | ||
| 25 | 25 | fn withReg(val: Val, callback: fn(Reg, *mut opaque), ctx: *mut opaque) { |
|
| 26 | 26 | if let case Val::Reg(r) = val { |
|
| 27 | 27 | callback(r, ctx); |
test/tests/for.else.continue.rad
+5 -5
| 12 | 12 | else continue; |
|
| 13 | 13 | if name.len == target.len { |
|
| 14 | 14 | let mut eq = true; |
|
| 15 | 15 | for j in 0..name.len { |
|
| 16 | 16 | if name[j] <> target[j] { |
|
| 17 | - | eq = false; |
|
| 17 | + | set eq = false; |
|
| 18 | 18 | } |
|
| 19 | 19 | } |
|
| 20 | 20 | if eq { |
|
| 21 | 21 | return fields[i].value; |
|
| 22 | 22 | } |
| 25 | 25 | return nil; |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | @default fn main() -> i32 { |
|
| 29 | 29 | let mut fields: [Field; 4] = undefined; |
|
| 30 | - | fields[0] = Field { name: nil, value: 10 }; |
|
| 31 | - | fields[1] = Field { name: "foo", value: 20 }; |
|
| 32 | - | fields[2] = Field { name: nil, value: 30 }; |
|
| 33 | - | fields[3] = Field { name: "bar", value: 40 }; |
|
| 30 | + | set fields[0] = Field { name: nil, value: 10 }; |
|
| 31 | + | set fields[1] = Field { name: "foo", value: 20 }; |
|
| 32 | + | set fields[2] = Field { name: nil, value: 30 }; |
|
| 33 | + | set fields[3] = Field { name: "bar", value: 40 }; |
|
| 34 | 34 | ||
| 35 | 35 | let v1 = findField(&fields[..], "foo") else { |
|
| 36 | 36 | return 1; |
|
| 37 | 37 | }; |
|
| 38 | 38 | assert v1 == 20; |
test/tests/frame.large.rad
+1 -1
| 14 | 14 | return arr[0] + arr[1] + arr[3]; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | fn bigFrame3() -> i32 { |
|
| 18 | 18 | let mut ary: [u8; 4096] = undefined; |
|
| 19 | - | ary[4091] = 192; |
|
| 19 | + | set ary[4091] = 192; |
|
| 20 | 20 | ||
| 21 | 21 | return ary[4091] as i32; |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | 24 | @default fn main() -> i32 { |
test/tests/if-let-mut.rad
+4 -4
| 10 | 10 | ||
| 11 | 11 | fn testIfLetMut() -> i32 { |
|
| 12 | 12 | let opt = getOptional(10); |
|
| 13 | 13 | ||
| 14 | 14 | if let mut v = opt { |
|
| 15 | - | v = v + 5; |
|
| 15 | + | set v = v + 5; |
|
| 16 | 16 | if v <> 15 { |
|
| 17 | 17 | return 1; |
|
| 18 | 18 | } |
|
| 19 | 19 | } else { |
|
| 20 | 20 | return 2; |
| 24 | 24 | ||
| 25 | 25 | fn testIfLetMutNil() -> i32 { |
|
| 26 | 26 | let opt = getOptional(0); |
|
| 27 | 27 | ||
| 28 | 28 | if let mut v = opt { |
|
| 29 | - | v = v + 1; |
|
| 29 | + | set v = v + 1; |
|
| 30 | 30 | return 3; |
|
| 31 | 31 | } |
|
| 32 | 32 | return 0; |
|
| 33 | 33 | } |
|
| 34 | 34 |
| 36 | 36 | let opt = getOptional(42); |
|
| 37 | 37 | ||
| 38 | 38 | let mut v = opt else { |
|
| 39 | 39 | return 4; |
|
| 40 | 40 | }; |
|
| 41 | - | v = v + 8; |
|
| 41 | + | set v = v + 8; |
|
| 42 | 42 | if v <> 50 { |
|
| 43 | 43 | return 5; |
|
| 44 | 44 | } |
|
| 45 | 45 | return 0; |
|
| 46 | 46 | } |
| 49 | 49 | let opt = getOptional(0); |
|
| 50 | 50 | ||
| 51 | 51 | let mut v = opt else { |
|
| 52 | 52 | return 0; |
|
| 53 | 53 | }; |
|
| 54 | - | v = v + 1; |
|
| 54 | + | set v = v + 1; |
|
| 55 | 55 | return 6; |
|
| 56 | 56 | } |
|
| 57 | 57 | ||
| 58 | 58 | @default fn main() -> i32 { |
|
| 59 | 59 | let r1 = testIfLetMut(); |
test/tests/large.blit.store.rad
+11 -11
| 21 | 21 | /// Store at offset 2200 (> MAX_IMM) into a record field. |
|
| 22 | 22 | /// Generates `store w32 <imm> %0 2200` in IL, which triggers the |
|
| 23 | 23 | /// SCRATCH1 aliasing bug when adjustOffset clobbers the value. |
|
| 24 | 24 | fn storeLargeOffset() -> i32 { |
|
| 25 | 25 | let mut b: Big = undefined; |
|
| 26 | - | b.tag = 42; |
|
| 26 | + | set b.tag = 42; |
|
| 27 | 27 | assert b.tag == 42; |
|
| 28 | - | b.tag = 99; |
|
| 28 | + | set b.tag = 99; |
|
| 29 | 29 | assert b.tag == 99; |
|
| 30 | 30 | return 0; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | /// Copy a >2047 byte struct (triggers blit offset overflow). |
|
| 34 | 34 | fn copyBig() -> i32 { |
|
| 35 | 35 | let mut src: Big = undefined; |
|
| 36 | - | src.a[0] = 10; |
|
| 37 | - | src.a[1000] = 20; |
|
| 38 | - | src.a[2199] = 30; |
|
| 39 | - | src.tag = 77; |
|
| 36 | + | set src.a[0] = 10; |
|
| 37 | + | set src.a[1000] = 20; |
|
| 38 | + | set src.a[2199] = 30; |
|
| 39 | + | set src.tag = 77; |
|
| 40 | 40 | ||
| 41 | 41 | let mut dst: Big = src; |
|
| 42 | 42 | ||
| 43 | 43 | assert dst.a[0] == 10; |
|
| 44 | 44 | assert dst.a[1000] == 20; |
| 48 | 48 | } |
|
| 49 | 49 | ||
| 50 | 50 | /// Mutate a copy to ensure the blit produced an independent copy. |
|
| 51 | 51 | fn copyIndependence() -> i32 { |
|
| 52 | 52 | let mut a: Big = undefined; |
|
| 53 | - | a.a[0] = 1; |
|
| 54 | - | a.a[2199] = 2; |
|
| 55 | - | a.tag = 100; |
|
| 53 | + | set a.a[0] = 1; |
|
| 54 | + | set a.a[2199] = 2; |
|
| 55 | + | set a.tag = 100; |
|
| 56 | 56 | ||
| 57 | 57 | let mut b: Big = a; |
|
| 58 | - | b.a[0] = 99; |
|
| 59 | - | b.tag = 200; |
|
| 58 | + | set b.a[0] = 99; |
|
| 59 | + | set b.tag = 200; |
|
| 60 | 60 | ||
| 61 | 61 | assert a.a[0] == 1; |
|
| 62 | 62 | assert a.tag == 100; |
|
| 63 | 63 | assert b.a[0] == 99; |
|
| 64 | 64 | assert b.a[2199] == 2; |
test/tests/loc.addr.offset.bug.rad
+1 -1
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | static outer: Outer = undefined; |
|
| 15 | 15 | ||
| 16 | 16 | @default fn main() -> i32 { |
|
| 17 | - | outer.inner.value = 42; |
|
| 17 | + | set outer.inner.value = 42; |
|
| 18 | 18 | ||
| 19 | 19 | let ptr: *Inner = &outer.inner; |
|
| 20 | 20 | ||
| 21 | 21 | assert (*ptr).value == 42; |
|
| 22 | 22 | return 0; |
test/tests/loc.addr.opt.to.opt.rad
+1 -1
| 10 | 10 | static container: Container = undefined; |
|
| 11 | 11 | ||
| 12 | 12 | @default fn main() -> i32 { |
|
| 13 | 13 | let sourceOpt: ?i32 = 42; |
|
| 14 | 14 | ||
| 15 | - | container.opt = sourceOpt; |
|
| 15 | + | set container.opt = sourceOpt; |
|
| 16 | 16 | ||
| 17 | 17 | if let val = container.opt { |
|
| 18 | 18 | assert val == 42; |
|
| 19 | 19 | return 0; |
|
| 20 | 20 | } else { |
test/tests/loc.addr.optional.assign.rad
+1 -1
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | static container: Container = undefined; |
|
| 10 | 10 | ||
| 11 | 11 | @default fn main() -> i32 { |
|
| 12 | - | container.opt = 42; |
|
| 12 | + | set container.opt = 42; |
|
| 13 | 13 | ||
| 14 | 14 | if let val = container.opt { |
|
| 15 | 15 | assert val == 42; |
|
| 16 | 16 | return 0; |
|
| 17 | 17 | } else { |
test/tests/loc.addr.record.assign.rad
+2 -2
| 13 | 13 | ||
| 14 | 14 | static outer: Outer = undefined; |
|
| 15 | 15 | static source: Inner = undefined; |
|
| 16 | 16 | ||
| 17 | 17 | @default fn main() -> i32 { |
|
| 18 | - | source.value = 42; |
|
| 18 | + | set source.value = 42; |
|
| 19 | 19 | ||
| 20 | - | outer.inner = source; |
|
| 20 | + | set outer.inner = source; |
|
| 21 | 21 | ||
| 22 | 22 | assert outer.inner.value == 42; |
|
| 23 | 23 | return 0; |
|
| 24 | 24 | } |
test/tests/local.mut.rad
+1 -1
| 1 | 1 | fn localMut() -> i32 { |
|
| 2 | 2 | let mut x: i32 = 5; |
|
| 3 | - | x = 10; |
|
| 3 | + | set x = 10; |
|
| 4 | 4 | return x; |
|
| 5 | 5 | } |
test/tests/loop.break.rad
+1 -1
| 2 | 2 | let mut i: i32 = 0; |
|
| 3 | 3 | loop { |
|
| 4 | 4 | if i >= n { |
|
| 5 | 5 | break; |
|
| 6 | 6 | } |
|
| 7 | - | i += 1; |
|
| 7 | + | set i += 1; |
|
| 8 | 8 | } |
|
| 9 | 9 | return i; |
|
| 10 | 10 | } |
test/tests/loop.complex.flow.rad
+3 -3
| 25 | 25 | let val = i - 2; // -2, -1, 0, 1, 2, 3 |
|
| 26 | 26 | let result = maybeAdd(sum, val); |
|
| 27 | 27 | ||
| 28 | 28 | match result { |
|
| 29 | 29 | case Result::Ok(v) => { |
|
| 30 | - | sum = v; |
|
| 30 | + | set sum = v; |
|
| 31 | 31 | }, |
|
| 32 | 32 | case Result::Err(e) => { |
|
| 33 | - | errCount += 1; |
|
| 33 | + | set errCount += 1; |
|
| 34 | 34 | }, |
|
| 35 | 35 | } |
|
| 36 | - | i += 1; |
|
| 36 | + | set i += 1; |
|
| 37 | 37 | } |
|
| 38 | 38 | ||
| 39 | 39 | // val sequence: -2, -1, 0, 1, 2, 3 |
|
| 40 | 40 | // Err for val <= 0: errCount = 3 (for -2, -1, 0) |
|
| 41 | 41 | // Ok for val > 0: sum = 0 + 1 + 2 + 3 = 6 |
test/tests/loop.continue.rad
+2 -2
| 1 | 1 | fn loopContinue(n: i32) -> i32 { |
|
| 2 | 2 | let mut i: i32 = 0; |
|
| 3 | 3 | let mut sum: i32 = 0; |
|
| 4 | 4 | while i < n { |
|
| 5 | - | i += 1; |
|
| 5 | + | set i += 1; |
|
| 6 | 6 | if i == 3 { |
|
| 7 | 7 | continue; |
|
| 8 | 8 | } |
|
| 9 | - | sum += i; |
|
| 9 | + | set sum += i; |
|
| 10 | 10 | } |
|
| 11 | 11 | return sum; |
|
| 12 | 12 | } |
test/tests/loop.for.array.rad
+1 -1
| 1 | 1 | /// Iterates over an array with index binding and sums elements. |
|
| 2 | 2 | fn forArrayIndexed(arr: [i32; 3]) -> i32 { |
|
| 3 | 3 | let mut sum: i32 = 0; |
|
| 4 | 4 | for elem, idx in arr { |
|
| 5 | - | sum += elem + idx as i32; |
|
| 5 | + | set sum += elem + idx as i32; |
|
| 6 | 6 | } |
|
| 7 | 7 | return sum; |
|
| 8 | 8 | } |
test/tests/loop.for.continue.rad
+2 -2
| 4 | 4 | let mut sum: u32 = 0; |
|
| 5 | 5 | for i in 0..n { |
|
| 6 | 6 | if i == 2 { |
|
| 7 | 7 | continue; |
|
| 8 | 8 | } |
|
| 9 | - | sum += i; |
|
| 9 | + | set sum += i; |
|
| 10 | 10 | } |
|
| 11 | 11 | return sum; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn forContinueArray(arr: [i32; 4]) -> i32 { |
|
| 15 | 15 | let mut sum: i32 = 0; |
|
| 16 | 16 | for elem in arr { |
|
| 17 | 17 | if elem == 0 { |
|
| 18 | 18 | continue; |
|
| 19 | 19 | } |
|
| 20 | - | sum += elem; |
|
| 20 | + | set sum += elem; |
|
| 21 | 21 | } |
|
| 22 | 22 | return sum; |
|
| 23 | 23 | } |
test/tests/loop.for.indexed.rad
+1 -1
| 1 | 1 | fn loopForIndexed(n: i32) -> i32 { |
|
| 2 | 2 | let mut sum: i32 = 0; |
|
| 3 | 3 | for val, idx in 0..n { |
|
| 4 | - | sum += val + idx as i32; |
|
| 4 | + | set sum += val + idx as i32; |
|
| 5 | 5 | } |
|
| 6 | 6 | return sum; |
|
| 7 | 7 | } |
test/tests/loop.for.placeholder.rad
+2 -2
| 1 | 1 | // Test for loop with placeholder binding |
|
| 2 | 2 | ||
| 3 | 3 | fn forPlaceholder(n: u32) -> u32 { |
|
| 4 | 4 | let mut count: u32 = 0; |
|
| 5 | 5 | for _ in 0..n { |
|
| 6 | - | count += 1; |
|
| 6 | + | set count += 1; |
|
| 7 | 7 | } |
|
| 8 | 8 | return count; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | fn forPlaceholderArray(arr: [i32; 4]) -> i32 { |
|
| 12 | 12 | let mut count: i32 = 0; |
|
| 13 | 13 | for _ in arr { |
|
| 14 | - | count += 1; |
|
| 14 | + | set count += 1; |
|
| 15 | 15 | } |
|
| 16 | 16 | return count; |
|
| 17 | 17 | } |
test/tests/loop.for.rad
+1 -1
| 1 | 1 | fn loopFor(n: i32) -> i32 { |
|
| 2 | 2 | let mut sum: i32 = 0; |
|
| 3 | 3 | for i in 0..n { |
|
| 4 | - | sum += i; |
|
| 4 | + | set sum += i; |
|
| 5 | 5 | } |
|
| 6 | 6 | return sum; |
|
| 7 | 7 | } |
test/tests/loop.for.slice.rad
+1 -1
| 1 | 1 | /// Iterates over a slice with index binding and sums elements. |
|
| 2 | 2 | fn forSliceIndexed(s: *[i32]) -> i32 { |
|
| 3 | 3 | let mut sum: i32 = 0; |
|
| 4 | 4 | for elem, idx in s { |
|
| 5 | - | sum += elem + idx as i32; |
|
| 5 | + | set sum += elem + idx as i32; |
|
| 6 | 6 | } |
|
| 7 | 7 | return sum; |
|
| 8 | 8 | } |
test/tests/loop.for.unsigned.range.rad
+2 -2
| 1 | 1 | fn loopForUnsignedRange(start: u32, end: u32) -> u32 { |
|
| 2 | 2 | let mut count: u32 = 0; |
|
| 3 | 3 | for _ in start..end { |
|
| 4 | - | count += 1; |
|
| 4 | + | set count += 1; |
|
| 5 | 5 | } |
|
| 6 | 6 | return count; |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | fn loopForSignedRange(start: i32, end: i32) -> i32 { |
|
| 10 | 10 | let mut count: i32 = 0; |
|
| 11 | 11 | for _ in start..end { |
|
| 12 | - | count += 1; |
|
| 12 | + | set count += 1; |
|
| 13 | 13 | } |
|
| 14 | 14 | return count; |
|
| 15 | 15 | } |
test/tests/loop.mutable.rad
+1 -1
| 8 | 8 | ||
| 9 | 9 | /// Computes the maximum alignment from a slice of alignment values. |
|
| 10 | 10 | fn computeMaxAlign(items: *[u32]) -> u32 { |
|
| 11 | 11 | let mut maxAlign: u32 = 1; |
|
| 12 | 12 | for i in 0..items.len { |
|
| 13 | - | maxAlign = max(maxAlign, items[i]); |
|
| 13 | + | set maxAlign = max(maxAlign, items[i]); |
|
| 14 | 14 | } |
|
| 15 | 15 | return maxAlign; |
|
| 16 | 16 | } |
test/tests/loop.nested.break.rad
+3 -3
| 5 | 5 | let mut i: i32 = 0; |
|
| 6 | 6 | ||
| 7 | 7 | loop { |
|
| 8 | 8 | let mut j: i32 = 0; |
|
| 9 | 9 | loop { |
|
| 10 | - | result += 1; |
|
| 11 | - | j += 1; |
|
| 10 | + | set result += 1; |
|
| 11 | + | set j += 1; |
|
| 12 | 12 | if j >= n { |
|
| 13 | 13 | break; |
|
| 14 | 14 | } |
|
| 15 | 15 | } |
|
| 16 | - | i += 1; |
|
| 16 | + | set i += 1; |
|
| 17 | 17 | if i >= n { |
|
| 18 | 18 | break; |
|
| 19 | 19 | } |
|
| 20 | 20 | } |
|
| 21 | 21 | return result; |
test/tests/loop.nested.continue.rad
+3 -3
| 3 | 3 | fn nestedContinue(n: i32) -> i32 { |
|
| 4 | 4 | let mut result: i32 = 0; |
|
| 5 | 5 | let mut i: i32 = 0; |
|
| 6 | 6 | ||
| 7 | 7 | while i < n { |
|
| 8 | - | i += 1; |
|
| 8 | + | set i += 1; |
|
| 9 | 9 | if i == 2 { |
|
| 10 | 10 | continue; |
|
| 11 | 11 | } |
|
| 12 | 12 | let mut j: i32 = 0; |
|
| 13 | 13 | while j < n { |
|
| 14 | - | j += 1; |
|
| 14 | + | set j += 1; |
|
| 15 | 15 | if j == 1 { |
|
| 16 | 16 | continue; |
|
| 17 | 17 | } |
|
| 18 | - | result += 1; |
|
| 18 | + | set result += 1; |
|
| 19 | 19 | } |
|
| 20 | 20 | } |
|
| 21 | 21 | return result; |
|
| 22 | 22 | } |
test/tests/loop.return.rad
+1 -1
| 1 | 1 | fn loopReturn() -> i32 { |
|
| 2 | 2 | let mut i: i32 = 0; |
|
| 3 | 3 | loop { |
|
| 4 | - | i += 1; |
|
| 4 | + | set i += 1; |
|
| 5 | 5 | if i == 10 { |
|
| 6 | 6 | return i; |
|
| 7 | 7 | } |
|
| 8 | 8 | } |
|
| 9 | 9 | } |
test/tests/loop.sealblock.rad
+4 -4
| 7 | 7 | @default fn main() -> i32 { |
|
| 8 | 8 | // Simple loop with mutable variable. |
|
| 9 | 9 | let mut sum: i32 = 0; |
|
| 10 | 10 | let mut i: i32 = 0; |
|
| 11 | 11 | while i < 5 { |
|
| 12 | - | sum += i; |
|
| 13 | - | i += 1; |
|
| 12 | + | set sum += i; |
|
| 13 | + | set i += 1; |
|
| 14 | 14 | } |
|
| 15 | 15 | // sum = 0 + 1 + 2 + 3 + 4 = 10 |
|
| 16 | 16 | assert sum == 10; |
|
| 17 | 17 | ||
| 18 | 18 | // For loop with mutable variable. |
|
| 19 | 19 | let mut count: i32 = 0; |
|
| 20 | 20 | for j in 0..4 { |
|
| 21 | - | count += 1; |
|
| 21 | + | set count += 1; |
|
| 22 | 22 | } |
|
| 23 | 23 | assert count == 4; |
|
| 24 | 24 | ||
| 25 | 25 | // Nested pattern: mutable var with function call in loop. |
|
| 26 | 26 | let mut total: i32 = 0; |
|
| 27 | 27 | for k in 0..3 { |
|
| 28 | - | total += addOne(k); |
|
| 28 | + | set total += addOne(k); |
|
| 29 | 29 | } |
|
| 30 | 30 | // total = 1 + 2 + 3 = 6 |
|
| 31 | 31 | assert total == 6; |
|
| 32 | 32 | ||
| 33 | 33 | return 0; |
test/tests/loop.while.nested.shortcircuit.rad
+3 -3
| 11 | 11 | let mut outer: i32 = 0; |
|
| 12 | 12 | let mut total: i32 = 0; |
|
| 13 | 13 | while outer < n { |
|
| 14 | 14 | let mut inner: i32 = outer; |
|
| 15 | 15 | while inner > 0 and inner < 100 { |
|
| 16 | - | inner -= 1; |
|
| 16 | + | set inner -= 1; |
|
| 17 | 17 | } |
|
| 18 | - | total += outer; |
|
| 19 | - | outer += 1; |
|
| 18 | + | set total += outer; |
|
| 19 | + | set outer += 1; |
|
| 20 | 20 | } |
|
| 21 | 21 | return total; |
|
| 22 | 22 | } |
test/tests/loop.while.rad
+2 -2
| 1 | 1 | fn loopWhile(n: i32) -> i32 { |
|
| 2 | 2 | let mut i: i32 = 0; |
|
| 3 | 3 | let mut sum: i32 = 0; |
|
| 4 | 4 | while i < n { |
|
| 5 | - | sum += i; |
|
| 6 | - | i += 1; |
|
| 5 | + | set sum += i; |
|
| 6 | + | set i += 1; |
|
| 7 | 7 | } |
|
| 8 | 8 | return sum; |
|
| 9 | 9 | } |
test/tests/loop.whilelet.case.rad
+2 -2
| 1 | 1 | // Returns the number of loop iterations when the input starts at zero. |
|
| 2 | 2 | fn whileLetCase(x: i32) -> i32 { |
|
| 3 | 3 | let mut cur: i32 = x; |
|
| 4 | 4 | let mut steps: i32 = 0; |
|
| 5 | 5 | while let case 0 = cur { |
|
| 6 | - | cur = 1; |
|
| 7 | - | steps += 1; |
|
| 6 | + | set cur = 1; |
|
| 7 | + | set steps += 1; |
|
| 8 | 8 | } |
|
| 9 | 9 | return steps; |
|
| 10 | 10 | } |
test/tests/loop.whilelet.guard.rad
+2 -2
| 1 | 1 | // Loops while the input matches case 0 and passes the guard. |
|
| 2 | 2 | fn whileLetCaseGuard(x: i32) -> i32 { |
|
| 3 | 3 | let mut cur: i32 = x; |
|
| 4 | 4 | let mut steps: i32 = 0; |
|
| 5 | 5 | while let case 0 = cur; steps < 3 { |
|
| 6 | - | cur = 0; |
|
| 7 | - | steps += 1; |
|
| 6 | + | set cur = 0; |
|
| 7 | + | set steps += 1; |
|
| 8 | 8 | } |
|
| 9 | 9 | return steps; |
|
| 10 | 10 | } |
test/tests/loop.whilelet.optional.rad
+1 -1
| 1 | 1 | // Returns the iteration count for a single guarded loop. |
|
| 2 | 2 | fn whileLetOptional(p: ?*i32) -> i32 { |
|
| 3 | 3 | let mut steps: i32 = 0; |
|
| 4 | 4 | while let _ = p { |
|
| 5 | - | steps += 1; |
|
| 5 | + | set steps += 1; |
|
| 6 | 6 | break; |
|
| 7 | 7 | } |
|
| 8 | 8 | return steps; |
|
| 9 | 9 | } |
test/tests/loop.whilelet.union.rad
+2 -2
| 4 | 4 | /// Sum values from a linked iteration using while-let case with binding. |
|
| 5 | 5 | fn sumWhileLet(x: Option) -> u32 { |
|
| 6 | 6 | let mut opt = x; |
|
| 7 | 7 | let mut sum: u32 = 0; |
|
| 8 | 8 | while let case Option::Some(val) = opt { |
|
| 9 | - | sum += val; |
|
| 10 | - | opt = Option::None; |
|
| 9 | + | set sum += val; |
|
| 10 | + | set opt = Option::None; |
|
| 11 | 11 | } |
|
| 12 | 12 | return sum; |
|
| 13 | 13 | } |
test/tests/match.more.rad
+1 -1
| 23 | 23 | ||
| 24 | 24 | // Returns 1 when the input matches, otherwise returns 0. |
|
| 25 | 25 | fn matchNoElse(x: i32) -> i32 { |
|
| 26 | 26 | let mut y: i32 = 0; |
|
| 27 | 27 | match x { |
|
| 28 | - | case 1 => y = 1, |
|
| 28 | + | case 1 => set y = 1, |
|
| 29 | 29 | else => {}, |
|
| 30 | 30 | } |
|
| 31 | 31 | return y; |
|
| 32 | 32 | } |
test/tests/match.mutref.push.rad
+3 -3
| 10 | 10 | No { items: U32List }, |
|
| 11 | 11 | Yes, |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn pushItem(list: *mut U32List, value: u32) { |
|
| 15 | - | list.data[list.len] = value; |
|
| 16 | - | list.len += 1; |
|
| 15 | + | set list.data[list.len] = value; |
|
| 16 | + | set list.len += 1; |
|
| 17 | 17 | } |
|
| 18 | 18 | ||
| 19 | 19 | fn addToUnsealedBlock(state: *mut Sealed, value: u32) -> bool { |
|
| 20 | 20 | match state { |
|
| 21 | 21 | case Sealed::No { items } => { |
| 28 | 28 | } |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | @default fn main() -> i32 { |
|
| 32 | 32 | let mut buf: [u32; 8] = undefined; |
|
| 33 | - | buf[0] = 0; |
|
| 33 | + | set buf[0] = 0; |
|
| 34 | 34 | let mut state = Sealed::No { items: U32List { data: &mut buf[0..8], len: 0 } }; |
|
| 35 | 35 | ||
| 36 | 36 | assert addToUnsealedBlock(&mut state, 42); |
|
| 37 | 37 | assert addToUnsealedBlock(&mut state, 99); |
|
| 38 | 38 |
test/tests/match.mutref.union.rad
+1 -1
| 14 | 14 | ||
| 15 | 15 | fn process(d: *mut Data) -> u32 { |
|
| 16 | 16 | match &mut d.state { |
|
| 17 | 17 | case State::A { count } => { |
|
| 18 | 18 | let c = *count; |
|
| 19 | - | *count = c + 1; |
|
| 19 | + | set *count = c + 1; |
|
| 20 | 20 | return c; |
|
| 21 | 21 | }, |
|
| 22 | 22 | case State::B => { |
|
| 23 | 23 | return 0; |
|
| 24 | 24 | }, |
test/tests/match.nested.whilelet.rad
+6 -6
| 21 | 21 | /// While-let with nested record destructuring. |
|
| 22 | 22 | fn sumPairs(items: *[Opt]) -> i32 { |
|
| 23 | 23 | let mut sum: i32 = 0; |
|
| 24 | 24 | let mut i: u32 = 0; |
|
| 25 | 25 | while let case Opt::Some { pair: Pair { a, b } } = get(items, i) { |
|
| 26 | - | sum = sum + a + b; |
|
| 27 | - | i = i + 1; |
|
| 26 | + | set sum = sum + a + b; |
|
| 27 | + | set i = i + 1; |
|
| 28 | 28 | } |
|
| 29 | 29 | return sum; |
|
| 30 | 30 | } |
|
| 31 | 31 | ||
| 32 | 32 | /// While-let with nested record and guard. |
|
| 33 | 33 | fn sumPositive(items: *[Opt]) -> i32 { |
|
| 34 | 34 | let mut sum: i32 = 0; |
|
| 35 | 35 | let mut i: u32 = 0; |
|
| 36 | 36 | while let case Opt::Some { pair: Pair { a, b } } = get(items, i); a > 0 { |
|
| 37 | - | sum = sum + a + b; |
|
| 38 | - | i = i + 1; |
|
| 37 | + | set sum = sum + a + b; |
|
| 38 | + | set i = i + 1; |
|
| 39 | 39 | } |
|
| 40 | 40 | return sum; |
|
| 41 | 41 | } |
|
| 42 | 42 | ||
| 43 | 43 | union Dir { North, South } |
| 57 | 57 | /// While-let with nested union variant pattern. |
|
| 58 | 58 | fn sumNorthSpeeds(items: *[Command]) -> i32 { |
|
| 59 | 59 | let mut sum: i32 = 0; |
|
| 60 | 60 | let mut i: u32 = 0; |
|
| 61 | 61 | while let case Command::Move { dir: Dir::North, speed } = getCmd(items, i) { |
|
| 62 | - | sum = sum + speed; |
|
| 63 | - | i = i + 1; |
|
| 62 | + | set sum = sum + speed; |
|
| 63 | + | set i = i + 1; |
|
| 64 | 64 | } |
|
| 65 | 65 | return sum; |
|
| 66 | 66 | } |
|
| 67 | 67 | ||
| 68 | 68 | @default fn main() -> i32 { |
test/tests/match.value.copy.rad
+3 -3
| 31 | 31 | ||
| 32 | 32 | let case Data::Some { pair } = b.data else { |
|
| 33 | 33 | return 1; |
|
| 34 | 34 | }; |
|
| 35 | 35 | // Overwrite the source - binding should be unaffected. |
|
| 36 | - | b.data = Data::None; |
|
| 36 | + | set b.data = Data::None; |
|
| 37 | 37 | ||
| 38 | 38 | assert pair.a == 10; |
|
| 39 | 39 | assert pair.b == 20; |
|
| 40 | 40 | return 0; |
|
| 41 | 41 | } |
| 45 | 45 | let mut b = Box { |
|
| 46 | 46 | data: Data::Some { pair: Pair { a: 30, b: 40 } }, |
|
| 47 | 47 | }; |
|
| 48 | 48 | ||
| 49 | 49 | if let case Data::Some { pair } = b.data { |
|
| 50 | - | b.data = Data::None; |
|
| 50 | + | set b.data = Data::None; |
|
| 51 | 51 | assert pair.a == 30; |
|
| 52 | 52 | assert pair.b == 40; |
|
| 53 | 53 | } else { |
|
| 54 | 54 | return 4; |
|
| 55 | 55 | } |
| 62 | 62 | data: Data::Some { pair: Pair { a: 50, b: 60 } }, |
|
| 63 | 63 | }; |
|
| 64 | 64 | ||
| 65 | 65 | match b.data { |
|
| 66 | 66 | case Data::Some { pair } => { |
|
| 67 | - | b.data = Data::None; |
|
| 67 | + | set b.data = Data::None; |
|
| 68 | 68 | assert pair.a == 50; |
|
| 69 | 69 | assert pair.b == 60; |
|
| 70 | 70 | } |
|
| 71 | 71 | case Data::None => { |
|
| 72 | 72 | return 7; |
test/tests/memzero.result.bug.rad
+2 -2
| 17 | 17 | // Place the return slot and a guard back-to-back on the stack. |
|
| 18 | 18 | let mut guard: u32 = 0; |
|
| 19 | 19 | ||
| 20 | 20 | // Success return should write only the small payload. |
|
| 21 | 21 | try fallible(false) catch { |
|
| 22 | - | guard = 0xDEAD; |
|
| 22 | + | set guard = 0xDEAD; |
|
| 23 | 23 | }; |
|
| 24 | - | guard = 0xDEADBEEF; |
|
| 24 | + | set guard = 0xDEADBEEF; |
|
| 25 | 25 | ||
| 26 | 26 | if guard <> 0xDEADBEEF { |
|
| 27 | 27 | return 1; // Guard was clobbered by an overzealous memzero. |
|
| 28 | 28 | } |
|
| 29 | 29 | return 0; |
test/tests/memzero.union.bug.rad
+2 -2
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | @default fn main() -> i32 { |
|
| 16 | 16 | let mut f: Frame = Frame { guard1: 0xDEAD, val: undefined, guard2: 0xDEADBEEF }; |
|
| 17 | 17 | ||
| 18 | - | f.val = Payload::Small(7); |
|
| 19 | - | f.val = Payload::Big([1, 2, 3]); |
|
| 18 | + | set f.val = Payload::Small(7); |
|
| 19 | + | set f.val = Payload::Big([1, 2, 3]); |
|
| 20 | 20 | ||
| 21 | 21 | if f.guard1 == 0xDEAD and f.guard2 == 0xDEADBEEF { |
|
| 22 | 22 | return 0; |
|
| 23 | 23 | } else { |
|
| 24 | 24 | return 1; |
test/tests/method.basic.rad
+2 -2
| 9 | 9 | fn (p: *Point) sum() -> i32 { |
|
| 10 | 10 | return p.x + p.y; |
|
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | fn (p: *mut Point) translate(dx: i32, dy: i32) { |
|
| 14 | - | p.x = p.x + dx; |
|
| 15 | - | p.y = p.y + dy; |
|
| 14 | + | set p.x = p.x + dx; |
|
| 15 | + | set p.y = p.y + dy; |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | @default fn main() -> i32 { |
|
| 19 | 19 | let mut pt = Point { x: 3, y: 4 }; |
|
| 20 | 20 |
test/tests/method.chain.rad
+2 -2
| 5 | 5 | x: i32, |
|
| 6 | 6 | y: i32, |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | fn (b: *mut Builder) setX(x: i32) -> *mut Builder { |
|
| 10 | - | b.x = x; |
|
| 10 | + | set b.x = x; |
|
| 11 | 11 | return b; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn (b: *mut Builder) setY(y: i32) -> *mut Builder { |
|
| 15 | - | b.y = y; |
|
| 15 | + | set b.y = y; |
|
| 16 | 16 | return b; |
|
| 17 | 17 | } |
|
| 18 | 18 | ||
| 19 | 19 | fn (b: *Builder) sum() -> i32 { |
|
| 20 | 20 | return b.x + b.y; |
test/tests/method.multiple.rad
+4 -4
| 13 | 13 | fn (v: *Vec2) dot(other: *Vec2) -> i32 { |
|
| 14 | 14 | return v.x * other.x + v.y * other.y; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | fn (v: *mut Vec2) add(other: *Vec2) { |
|
| 18 | - | v.x = v.x + other.x; |
|
| 19 | - | v.y = v.y + other.y; |
|
| 18 | + | set v.x = v.x + other.x; |
|
| 19 | + | set v.y = v.y + other.y; |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn (v: *mut Vec2) scale(factor: i32) { |
|
| 23 | - | v.x = v.x * factor; |
|
| 24 | - | v.y = v.y * factor; |
|
| 23 | + | set v.x = v.x * factor; |
|
| 24 | + | set v.y = v.y * factor; |
|
| 25 | 25 | } |
|
| 26 | 26 | ||
| 27 | 27 | @default fn main() -> i32 { |
|
| 28 | 28 | let mut a = Vec2 { x: 3, y: 4 }; |
|
| 29 | 29 | let b = Vec2 { x: 1, y: 2 }; |
test/tests/method.ptr.rad
+1 -1
| 8 | 8 | fn (c: *Counter) get() -> i32 { |
|
| 9 | 9 | return c.value; |
|
| 10 | 10 | } |
|
| 11 | 11 | ||
| 12 | 12 | fn (c: *mut Counter) inc() { |
|
| 13 | - | c.value = c.value + 1; |
|
| 13 | + | set c.value = c.value + 1; |
|
| 14 | 14 | } |
|
| 15 | 15 | ||
| 16 | 16 | @default fn main() -> i32 { |
|
| 17 | 17 | let mut c = Counter { value: 0 }; |
|
| 18 | 18 |
test/tests/method.throws.rad
+2 -2
| 12 | 12 | ||
| 13 | 13 | fn (p: *mut Parser) advance() throws (ParseError) { |
|
| 14 | 14 | if p.pos >= p.len { |
|
| 15 | 15 | throw ParseError::Invalid; |
|
| 16 | 16 | } |
|
| 17 | - | p.pos = p.pos + 1; |
|
| 17 | + | set p.pos = p.pos + 1; |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | fn (p: *Parser) remaining() -> i32 { |
|
| 21 | 21 | return p.len - p.pos; |
|
| 22 | 22 | } |
| 37 | 37 | assert parser.remaining() == 0; |
|
| 38 | 38 | ||
| 39 | 39 | // Advance past end -- should throw. |
|
| 40 | 40 | let mut threw = false; |
|
| 41 | 41 | try parser.advance() catch { |
|
| 42 | - | threw = true; |
|
| 42 | + | set threw = true; |
|
| 43 | 43 | }; |
|
| 44 | 44 | assert threw; |
|
| 45 | 45 | ||
| 46 | 46 | return 0; |
|
| 47 | 47 | } |
test/tests/multi.throw.catch.typed.rad
+2 -2
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | fn caller(flag: i32) -> i32 { |
|
| 16 | 16 | let mut r: i32 = 0; |
|
| 17 | 17 | try fallible(flag) catch e as ErrA { |
|
| 18 | - | r = 1; |
|
| 18 | + | set r = 1; |
|
| 19 | 19 | } catch e as ErrB { |
|
| 20 | - | r = 2; |
|
| 20 | + | set r = 2; |
|
| 21 | 21 | }; |
|
| 22 | 22 | return r; |
|
| 23 | 23 | } |
test/tests/mutref.call.result.rad
added
+20 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | //! Mutable borrow through a field access on a call result. |
|
| 3 | + | ||
| 4 | + | record Box { |
|
| 5 | + | x: i32, |
|
| 6 | + | } |
|
| 7 | + | ||
| 8 | + | fn idBox(b: *mut Box) -> *mut Box { |
|
| 9 | + | return b; |
|
| 10 | + | } |
|
| 11 | + | ||
| 12 | + | @default fn main() -> i32 { |
|
| 13 | + | let mut b = Box { x: 1 }; |
|
| 14 | + | ||
| 15 | + | let px: *mut i32 = &mut idBox(&mut b).x; |
|
| 16 | + | set *px = 9; |
|
| 17 | + | ||
| 18 | + | assert b.x == 9; |
|
| 19 | + | return 0; |
|
| 20 | + | } |
test/tests/mutref.loop.bug.rad
+4 -4
| 9 | 9 | //! The critical case is when the loop executes zero iterations: the merge |
|
| 10 | 10 | //! block tries to `load` through the initial integer value (not a valid |
|
| 11 | 11 | //! pointer), crashing the program. |
|
| 12 | 12 | ||
| 13 | 13 | fn store(ptr: *mut u32, val: u32) { |
|
| 14 | - | *ptr = val; |
|
| 14 | + | set *ptr = val; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | /// Zero-iteration loop with &mut inside the body. |
|
| 18 | 18 | /// Without the fix, `val` starts as integer 42 in SSA, but the post-loop |
|
| 19 | 19 | /// merge tries to `load` through it as if it were a pointer. |
|
| 20 | 20 | fn testZeroIter(n: u32) -> u32 { |
|
| 21 | 21 | let mut val: u32 = 42; |
|
| 22 | 22 | let mut i: u32 = 0; |
|
| 23 | 23 | while i < n { |
|
| 24 | 24 | store(&mut val, val + 1); |
|
| 25 | - | i += 1; |
|
| 25 | + | set i += 1; |
|
| 26 | 26 | } |
|
| 27 | 27 | return val; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | /// Multiple iterations: accumulate via &mut pointer in a loop. |
|
| 31 | 31 | fn testMultiIter() -> u32 { |
|
| 32 | 32 | let mut acc: u32 = 0; |
|
| 33 | 33 | let mut i: u32 = 0; |
|
| 34 | 34 | while i < 5 { |
|
| 35 | 35 | store(&mut acc, acc + i); |
|
| 36 | - | i += 1; |
|
| 36 | + | set i += 1; |
|
| 37 | 37 | } |
|
| 38 | 38 | return acc; |
|
| 39 | 39 | } |
|
| 40 | 40 | ||
| 41 | 41 | /// Multiple address-taken variables in the same loop. |
| 44 | 44 | let mut b: u32 = 100; |
|
| 45 | 45 | let mut i: u32 = 0; |
|
| 46 | 46 | while i < 3 { |
|
| 47 | 47 | store(&mut a, a + 1); |
|
| 48 | 48 | store(&mut b, b - 1); |
|
| 49 | - | i += 1; |
|
| 49 | + | set i += 1; |
|
| 50 | 50 | } |
|
| 51 | 51 | return a + b; |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | 54 | @default fn main() -> i32 { |
test/tests/mutref.loop.rad
+2 -2
| 1 | 1 | fn callback(val: u32, ctx: *mut opaque) { |
|
| 2 | 2 | let max = ctx as *mut u32; |
|
| 3 | - | *max = val; |
|
| 3 | + | set *max = val; |
|
| 4 | 4 | } |
|
| 5 | 5 | ||
| 6 | 6 | fn test() -> i32 { |
|
| 7 | 7 | let mut maxReg: u32 = 0; |
|
| 8 | 8 | let mut i: u32 = 0; |
|
| 9 | 9 | while i < 3 { |
|
| 10 | 10 | callback(i, &mut maxReg as *mut opaque); |
|
| 11 | - | i += 1; |
|
| 11 | + | set i += 1; |
|
| 12 | 12 | } |
|
| 13 | 13 | return maxReg as i32; |
|
| 14 | 14 | } |
test/tests/mutref.scalar.rad
+1 -1
| 1 | 1 | fn modify(counter: *mut i32, ret: bool) -> bool { |
|
| 2 | - | *counter += 1; |
|
| 2 | + | set *counter += 1; |
|
| 3 | 3 | return ret; |
|
| 4 | 4 | } |
|
| 5 | 5 | ||
| 6 | 6 | fn test() -> i32 { |
|
| 7 | 7 | let mut x: i32 = 0; |
test/tests/opt.assignment.bug.rad
+4 -4
| 12 | 12 | /// Test assigning via if-let pattern. |
|
| 13 | 13 | fn testIfLetPattern() -> bool { |
|
| 14 | 14 | let mut result: ?i32 = nil; |
|
| 15 | 15 | ||
| 16 | 16 | if let val = returnOptional(true) { |
|
| 17 | - | result = val; |
|
| 17 | + | set result = val; |
|
| 18 | 18 | } |
|
| 19 | 19 | if let r = result { |
|
| 20 | 20 | return r == 99; |
|
| 21 | 21 | } |
|
| 22 | 22 | return false; |
| 24 | 24 | ||
| 25 | 25 | /// Test direct assignment from function. |
|
| 26 | 26 | fn testDirectAssignment() -> bool { |
|
| 27 | 27 | let mut result: ?i32 = nil; |
|
| 28 | 28 | ||
| 29 | - | result = returnOptional(true); |
|
| 29 | + | set result = returnOptional(true); |
|
| 30 | 30 | ||
| 31 | 31 | if let r = result { |
|
| 32 | 32 | return r == 99; |
|
| 33 | 33 | } |
|
| 34 | 34 | return false; |
| 37 | 37 | /// Test if-let pattern with nil return. |
|
| 38 | 38 | fn testIfLetPatternNil() -> bool { |
|
| 39 | 39 | let mut result: ?i32 = nil; |
|
| 40 | 40 | ||
| 41 | 41 | if let val = returnOptional(false) { |
|
| 42 | - | result = val; |
|
| 42 | + | set result = val; |
|
| 43 | 43 | } |
|
| 44 | 44 | if let r = result { |
|
| 45 | 45 | return false; |
|
| 46 | 46 | } |
|
| 47 | 47 | return true; |
| 49 | 49 | ||
| 50 | 50 | /// Test direct assignment with nil return. |
|
| 51 | 51 | fn testDirectAssignmentNil() -> bool { |
|
| 52 | 52 | let mut result: ?i32 = nil; |
|
| 53 | 53 | ||
| 54 | - | result = returnOptional(false); |
|
| 54 | + | set result = returnOptional(false); |
|
| 55 | 55 | ||
| 56 | 56 | if let r = result { |
|
| 57 | 57 | return false; |
|
| 58 | 58 | } |
|
| 59 | 59 | return true; |
test/tests/opt.bug.test.rad
+2 -2
| 16 | 16 | fn testManualPattern() -> bool { |
|
| 17 | 17 | let mut result: ?i32 = nil; |
|
| 18 | 18 | let opt: ?i32 = 42; |
|
| 19 | 19 | ||
| 20 | 20 | if let val = opt { |
|
| 21 | - | result = inner(val); |
|
| 21 | + | set result = inner(val); |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | 24 | if let r = result { |
|
| 25 | 25 | return r == 43; |
|
| 26 | 26 | } |
| 42 | 42 | fn testManualPatternNil() -> bool { |
|
| 43 | 43 | let mut result: ?i32 = nil; |
|
| 44 | 44 | let opt: ?i32 = nil; |
|
| 45 | 45 | ||
| 46 | 46 | if let val = opt { |
|
| 47 | - | result = inner(val); |
|
| 47 | + | set result = inner(val); |
|
| 48 | 48 | } |
|
| 49 | 49 | ||
| 50 | 50 | if let r = result { |
|
| 51 | 51 | return false; // Should be nil |
|
| 52 | 52 | } |
test/tests/opt.if.let.complex.rad
+5 -5
| 113 | 113 | fn testMultipleNilAssignments() -> bool { |
|
| 114 | 114 | let mut opt: ?i32 = 42; |
|
| 115 | 115 | ||
| 116 | 116 | if let x = opt { |
|
| 117 | 117 | if x == 42 { |
|
| 118 | - | opt = nil; |
|
| 118 | + | set opt = nil; |
|
| 119 | 119 | if let y = opt { |
|
| 120 | 120 | return false; // Should not reach here after nil assignment |
|
| 121 | 121 | } else { |
|
| 122 | - | opt = 100; |
|
| 122 | + | set opt = 100; |
|
| 123 | 123 | if let z = opt { |
|
| 124 | 124 | return z == 100; |
|
| 125 | 125 | } else { |
|
| 126 | 126 | return false; |
|
| 127 | 127 | } |
| 242 | 242 | ||
| 243 | 243 | if let x = opt { |
|
| 244 | 244 | return false; |
|
| 245 | 245 | } |
|
| 246 | 246 | ||
| 247 | - | opt = 10; |
|
| 247 | + | set opt = 10; |
|
| 248 | 248 | if let x = opt; x == 10 { |
|
| 249 | - | opt = 20; |
|
| 249 | + | set opt = 20; |
|
| 250 | 250 | if let y = opt; y == 20 { |
|
| 251 | - | opt = nil; |
|
| 251 | + | set opt = nil; |
|
| 252 | 252 | if let z = opt { |
|
| 253 | 253 | return false; |
|
| 254 | 254 | } else { |
|
| 255 | 255 | return true; |
|
| 256 | 256 | } |
test/tests/opt.record.eq.rad
+3 -3
| 26 | 26 | let mut optA: ?Outer = nil; |
|
| 27 | 27 | let mut optB: ?Outer = nil; |
|
| 28 | 28 | let mut optDiff: ?Outer = nil; |
|
| 29 | 29 | let mut optNil: ?Outer = nil; |
|
| 30 | 30 | ||
| 31 | - | optA = outerA; |
|
| 32 | - | optB = outerB; |
|
| 33 | - | optDiff = outerC; |
|
| 31 | + | set optA = outerA; |
|
| 32 | + | set optB = outerB; |
|
| 33 | + | set optDiff = outerC; |
|
| 34 | 34 | ||
| 35 | 35 | if optA <> optB { |
|
| 36 | 36 | return false; |
|
| 37 | 37 | } |
|
| 38 | 38 | if optA == optDiff { |
test/tests/opt.record.rad
+3 -3
| 18 | 18 | return 0; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | @default fn main() -> i32 { |
|
| 22 | 22 | let mut v: ?Vector = nil; |
|
| 23 | - | v = Vector { x: 3, y: 4, z: 5 }; |
|
| 23 | + | set v = Vector { x: 3, y: 4, z: 5 }; |
|
| 24 | 24 | ||
| 25 | 25 | let mut total: i32 = 0; |
|
| 26 | 26 | ||
| 27 | 27 | if let w = v { |
|
| 28 | - | total = w.x + w.y + w.z; |
|
| 28 | + | set total = w.x + w.y + w.z; |
|
| 29 | 29 | } else { |
|
| 30 | 30 | return 0; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | let wrapper = Wrapper { opt: 7 }; |
|
| 34 | 34 | if let value = wrapper.opt { |
|
| 35 | - | total += value; |
|
| 35 | + | set total += value; |
|
| 36 | 36 | } else { |
|
| 37 | 37 | return 0; |
|
| 38 | 38 | } |
|
| 39 | 39 | ||
| 40 | 40 | let call = takeOptional(9); |
test/tests/opt.type.rad
+3 -3
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let optSome: ?i32 = 42; |
|
| 4 | 4 | let optNone: ?i32 = nil; |
|
| 5 | 5 | ||
| 6 | 6 | let mut optMaybe: ?i32 = nil; |
|
| 7 | - | optMaybe = optSome; |
|
| 8 | - | optMaybe = 42; |
|
| 9 | - | optMaybe = nil; |
|
| 7 | + | set optMaybe = optSome; |
|
| 8 | + | set optMaybe = 42; |
|
| 9 | + | set optMaybe = nil; |
|
| 10 | 10 | ||
| 11 | 11 | return 0; |
|
| 12 | 12 | } |
test/tests/opt.while.let.complex.rad
+2 -2
| 12 | 12 | @default fn main() -> i32 { |
|
| 13 | 13 | let mut cur: u32 = 7; |
|
| 14 | 14 | let mut sum: u32 = 0; |
|
| 15 | 15 | ||
| 16 | 16 | while let x = decr(cur); x > 1 { |
|
| 17 | - | sum += x; |
|
| 18 | - | cur = x; |
|
| 17 | + | set sum += x; |
|
| 18 | + | set cur = x; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | // sum should be 6 + 5 + 4 + 3 + 2 = 20 |
|
| 22 | 22 | assert sum == 20; |
|
| 23 | 23 | return 0; |
test/tests/placeholder.comprehensive.rad
+1 -1
| 20 | 20 | ||
| 21 | 21 | // Test 4: for loop with placeholder for value |
|
| 22 | 22 | let arr: [i32; 3] = [1, 2, 3]; |
|
| 23 | 23 | let mut count: i32 = 0; |
|
| 24 | 24 | for _ in &arr[..] { |
|
| 25 | - | count += 1; |
|
| 25 | + | set count += 1; |
|
| 26 | 26 | } |
|
| 27 | 27 | assert count == 3; |
|
| 28 | 28 | return 0; |
|
| 29 | 29 | } |
test/tests/pointer.copy.edge.case.rad
+5 -5
| 19 | 19 | count: u32, |
|
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn makeNode(p: *mut Parser, kind: NodeKind) -> *mut Node { |
|
| 23 | 23 | let idx: u32 = p.count; |
|
| 24 | - | p.nodes[idx] = Node { |
|
| 24 | + | set p.nodes[idx] = Node { |
|
| 25 | 25 | span: Span { length: 0 }, |
|
| 26 | 26 | kind, |
|
| 27 | 27 | }; |
|
| 28 | - | p.count = idx + 1; |
|
| 28 | + | set p.count = idx + 1; |
|
| 29 | 29 | return &mut p.nodes[idx]; |
|
| 30 | 30 | } |
|
| 31 | 31 | ||
| 32 | 32 | fn setLen(n: *mut Node, len: u32) { |
|
| 33 | - | n.span.length = len; |
|
| 33 | + | set n.span.length = len; |
|
| 34 | 34 | } |
|
| 35 | 35 | ||
| 36 | 36 | @default fn main() -> i32 { |
|
| 37 | 37 | let mut parser: Parser = Parser { |
|
| 38 | 38 | nodes: [Node { |
| 40 | 40 | kind: NodeKind::Placeholder, |
|
| 41 | 41 | }; 1], |
|
| 42 | 42 | count: 0, |
|
| 43 | 43 | }; |
|
| 44 | 44 | ||
| 45 | - | parser.count = 0; |
|
| 46 | - | parser.nodes[0] = Node { |
|
| 45 | + | set parser.count = 0; |
|
| 46 | + | set parser.nodes[0] = Node { |
|
| 47 | 47 | span: Span { length: 0 }, |
|
| 48 | 48 | kind: NodeKind::Placeholder, |
|
| 49 | 49 | }; |
|
| 50 | 50 | ||
| 51 | 51 | let node: *mut Node = makeNode(&mut parser, NodeKind::Bool(true)); |
test/tests/pointer.slice.store.rad
+5 -5
| 21 | 21 | static STORAGE: [Entry; 2] = undefined; |
|
| 22 | 22 | static TABLE: Table = undefined; |
|
| 23 | 23 | static HOLDER: PtrBox = undefined; |
|
| 24 | 24 | ||
| 25 | 25 | @default fn main() -> i32 { |
|
| 26 | - | TABLE.entries = &mut STORAGE[..]; |
|
| 27 | - | TABLE.len = 0; |
|
| 26 | + | set TABLE.entries = &mut STORAGE[..]; |
|
| 27 | + | set TABLE.len = 0; |
|
| 28 | 28 | ||
| 29 | - | HOLDER.ptr = &mut TABLE.entries; |
|
| 29 | + | set HOLDER.ptr = &mut TABLE.entries; |
|
| 30 | 30 | ||
| 31 | - | HOLDER.ptr[0] = Entry { a: 1, b: 2, c: 3, d: 4, e: 5 }; |
|
| 31 | + | set HOLDER.ptr[0] = Entry { a: 1, b: 2, c: 3, d: 4, e: 5 }; |
|
| 32 | 32 | ||
| 33 | 33 | assert TABLE.entries.len == 2 and TABLE.entries.ptr == &STORAGE[0]; |
|
| 34 | 34 | assert STORAGE[0].a == 1 and STORAGE[0].e == 5; |
|
| 35 | 35 | ||
| 36 | - | HOLDER.ptr[1] = Entry { a: 10, b: 20, c: 30, d: 40, e: 50 }; |
|
| 36 | + | set HOLDER.ptr[1] = Entry { a: 10, b: 20, c: 30, d: 40, e: 50 }; |
|
| 37 | 37 | ||
| 38 | 38 | assert TABLE.entries.len == 2 and TABLE.entries.ptr == &STORAGE[0]; |
|
| 39 | 39 | assert STORAGE[1].c == 30 and STORAGE[1].d == 40; |
|
| 40 | 40 | return 0; |
|
| 41 | 41 | } |
test/tests/prog.ackermann.rad
+16 -16
| 40 | 40 | if m == 3 { |
|
| 41 | 41 | // 2^(n+3) - 3 |
|
| 42 | 42 | let mut power: i32 = 1; |
|
| 43 | 43 | let mut i: u32 = 0; |
|
| 44 | 44 | while i < n + 3 { |
|
| 45 | - | power *= 2; |
|
| 46 | - | i += 1; |
|
| 45 | + | set power *= 2; |
|
| 46 | + | set i += 1; |
|
| 47 | 47 | } |
|
| 48 | 48 | return power - 3; |
|
| 49 | 49 | } |
|
| 50 | 50 | // For m >= 4, fall back to recursion (only safe for very small n). |
|
| 51 | 51 | if n == 0 { |
| 57 | 57 | /// Power of 2 helper. |
|
| 58 | 58 | fn pow2(exp: u32) -> i32 { |
|
| 59 | 59 | let mut result: i32 = 1; |
|
| 60 | 60 | let mut i: u32 = 0; |
|
| 61 | 61 | while i < exp { |
|
| 62 | - | result *= 2; |
|
| 63 | - | i += 1; |
|
| 62 | + | set result *= 2; |
|
| 63 | + | set i += 1; |
|
| 64 | 64 | } |
|
| 65 | 65 | return result; |
|
| 66 | 66 | } |
|
| 67 | 67 | ||
| 68 | 68 | /// Test known small values using the recursive implementation. |
| 99 | 99 | // Verify m=0 row. |
|
| 100 | 100 | let mut n: u32 = 0; |
|
| 101 | 101 | while n < 50 { |
|
| 102 | 102 | let expected: i32 = n as i32 + 1; |
|
| 103 | 103 | assert ackMemo(0, n) == expected; |
|
| 104 | - | n += 1; |
|
| 104 | + | set n += 1; |
|
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | // Verify m=1 row. |
|
| 108 | - | n = 0; |
|
| 108 | + | set n = 0; |
|
| 109 | 109 | while n < 50 { |
|
| 110 | 110 | let expected: i32 = n as i32 + 2; |
|
| 111 | 111 | assert ackMemo(1, n) == expected; |
|
| 112 | - | n += 1; |
|
| 112 | + | set n += 1; |
|
| 113 | 113 | } |
|
| 114 | 114 | ||
| 115 | 115 | // Verify m=2 row. |
|
| 116 | - | n = 0; |
|
| 116 | + | set n = 0; |
|
| 117 | 117 | while n < 50 { |
|
| 118 | 118 | let expected: i32 = (2 * n + 3) as i32; |
|
| 119 | 119 | assert ackMemo(2, n) == expected; |
|
| 120 | - | n += 1; |
|
| 120 | + | set n += 1; |
|
| 121 | 121 | } |
|
| 122 | 122 | ||
| 123 | 123 | // Verify m=3 row for small n. |
|
| 124 | 124 | // A(3,0)=5, A(3,1)=13, A(3,2)=29, A(3,3)=61, A(3,4)=125 |
|
| 125 | 125 | assert ackMemo(3, 0) == 5; |
| 141 | 141 | while m <= 3 { |
|
| 142 | 142 | let mut n: u32 = 0; |
|
| 143 | 143 | // Limit n to keep recursion tractable. |
|
| 144 | 144 | let mut limit: u32 = 4; |
|
| 145 | 145 | if m <= 2 { |
|
| 146 | - | limit = 8; |
|
| 146 | + | set limit = 8; |
|
| 147 | 147 | } |
|
| 148 | 148 | while n <= limit { |
|
| 149 | 149 | let r: i32 = ack(m, n); |
|
| 150 | 150 | let memoR: i32 = ackMemo(m, n); |
|
| 151 | 151 | if r <> memoR { |
|
| 152 | 152 | return (m * 20 + n) as i32 + 1; |
|
| 153 | 153 | } |
|
| 154 | - | n += 1; |
|
| 154 | + | set n += 1; |
|
| 155 | 155 | } |
|
| 156 | - | m += 1; |
|
| 156 | + | set m += 1; |
|
| 157 | 157 | } |
|
| 158 | 158 | return 0; |
|
| 159 | 159 | } |
|
| 160 | 160 | ||
| 161 | 161 | /// Test the Ackermann inverse property: A(m, n) > n for all m, n. |
| 167 | 167 | let val: i32 = ackMemo(m, n); |
|
| 168 | 168 | assert val > n as i32; |
|
| 169 | 169 | // A(m, n) < A(m, n+1) (strictly increasing in n). |
|
| 170 | 170 | let valNext: i32 = ackMemo(m, n + 1); |
|
| 171 | 171 | assert valNext > val; |
|
| 172 | - | n += 1; |
|
| 172 | + | set n += 1; |
|
| 173 | 173 | } |
|
| 174 | - | m += 1; |
|
| 174 | + | set m += 1; |
|
| 175 | 175 | } |
|
| 176 | 176 | ||
| 177 | 177 | // A(m, n) < A(m+1, n) (strictly increasing in m). |
|
| 178 | 178 | let mut m2: u32 = 0; |
|
| 179 | 179 | while m2 < 3 { |
|
| 180 | 180 | let mut n2: u32 = 0; |
|
| 181 | 181 | while n2 < 10 { |
|
| 182 | 182 | let lower: i32 = ackMemo(m2, n2); |
|
| 183 | 183 | let upper: i32 = ackMemo(m2 + 1, n2); |
|
| 184 | 184 | assert upper > lower; |
|
| 185 | - | n2 += 1; |
|
| 185 | + | set n2 += 1; |
|
| 186 | 186 | } |
|
| 187 | - | m2 += 1; |
|
| 187 | + | set m2 += 1; |
|
| 188 | 188 | } |
|
| 189 | 189 | ||
| 190 | 190 | return 0; |
|
| 191 | 191 | } |
|
| 192 | 192 |
test/tests/prog.bignum.rad
+62 -62
| 7 | 7 | /// Number of limbs per big number (128 bits = 4 x 32-bit words). |
|
| 8 | 8 | constant LIMBS: u32 = 4; |
|
| 9 | 9 | ||
| 10 | 10 | /// Set a big number to a u32 value. |
|
| 11 | 11 | fn bnFromU32(dst: *mut [u32], val: u32) { |
|
| 12 | - | dst[0] = val; |
|
| 12 | + | set dst[0] = val; |
|
| 13 | 13 | let mut i: u32 = 1; |
|
| 14 | 14 | while i < LIMBS { |
|
| 15 | - | dst[i] = 0; |
|
| 16 | - | i += 1; |
|
| 15 | + | set dst[i] = 0; |
|
| 16 | + | set i += 1; |
|
| 17 | 17 | } |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | /// Set a big number to zero. |
|
| 21 | 21 | fn bnZero(dst: *mut [u32]) { |
|
| 22 | 22 | let mut i: u32 = 0; |
|
| 23 | 23 | while i < LIMBS { |
|
| 24 | - | dst[i] = 0; |
|
| 25 | - | i += 1; |
|
| 24 | + | set dst[i] = 0; |
|
| 25 | + | set i += 1; |
|
| 26 | 26 | } |
|
| 27 | 27 | } |
|
| 28 | 28 | ||
| 29 | 29 | /// Copy src to dst. |
|
| 30 | 30 | fn bnCopy(dst: *mut [u32], src: *[u32]) { |
|
| 31 | 31 | let mut i: u32 = 0; |
|
| 32 | 32 | while i < LIMBS { |
|
| 33 | - | dst[i] = src[i]; |
|
| 34 | - | i += 1; |
|
| 33 | + | set dst[i] = src[i]; |
|
| 34 | + | set i += 1; |
|
| 35 | 35 | } |
|
| 36 | 36 | } |
|
| 37 | 37 | ||
| 38 | 38 | /// Compare two big numbers. Returns 0 if equal, 1 if a > b, -1 if a < b. |
|
| 39 | 39 | fn bnCmp(a: *[u32], b: *[u32]) -> i32 { |
| 46 | 46 | return -1; |
|
| 47 | 47 | } |
|
| 48 | 48 | if i == 0 { |
|
| 49 | 49 | break; |
|
| 50 | 50 | } |
|
| 51 | - | i -= 1; |
|
| 51 | + | set i -= 1; |
|
| 52 | 52 | } |
|
| 53 | 53 | return 0; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | /// Add two big numbers: dst = a + b. Returns carry (0 or 1). |
| 59 | 59 | let mut i: u32 = 0; |
|
| 60 | 60 | while i < LIMBS { |
|
| 61 | 61 | let sumLo: u32 = a[i] + b[i]; |
|
| 62 | 62 | let mut carry1: u32 = 0; |
|
| 63 | 63 | if sumLo < a[i] { |
|
| 64 | - | carry1 = 1; |
|
| 64 | + | set carry1 = 1; |
|
| 65 | 65 | } |
|
| 66 | 66 | let sum: u32 = sumLo + carry; |
|
| 67 | 67 | let mut carry2: u32 = 0; |
|
| 68 | 68 | if sum < sumLo { |
|
| 69 | - | carry2 = 1; |
|
| 69 | + | set carry2 = 1; |
|
| 70 | 70 | } |
|
| 71 | - | dst[i] = sum; |
|
| 72 | - | carry = carry1 + carry2; |
|
| 73 | - | i += 1; |
|
| 71 | + | set dst[i] = sum; |
|
| 72 | + | set carry = carry1 + carry2; |
|
| 73 | + | set i += 1; |
|
| 74 | 74 | } |
|
| 75 | 75 | return carry; |
|
| 76 | 76 | } |
|
| 77 | 77 | ||
| 78 | 78 | /// Subtract two big numbers: dst = a - b. Returns borrow (0 or 1). |
| 81 | 81 | let mut i: u32 = 0; |
|
| 82 | 82 | while i < LIMBS { |
|
| 83 | 83 | let diff: u32 = a[i] - b[i]; |
|
| 84 | 84 | let mut borrow1: u32 = 0; |
|
| 85 | 85 | if diff > a[i] { |
|
| 86 | - | borrow1 = 1; |
|
| 86 | + | set borrow1 = 1; |
|
| 87 | 87 | } |
|
| 88 | 88 | let result: u32 = diff - borrow; |
|
| 89 | 89 | let mut borrow2: u32 = 0; |
|
| 90 | 90 | if result > diff { |
|
| 91 | - | borrow2 = 1; |
|
| 91 | + | set borrow2 = 1; |
|
| 92 | 92 | } |
|
| 93 | - | dst[i] = result; |
|
| 94 | - | borrow = borrow1 + borrow2; |
|
| 95 | - | i += 1; |
|
| 93 | + | set dst[i] = result; |
|
| 94 | + | set borrow = borrow1 + borrow2; |
|
| 95 | + | set i += 1; |
|
| 96 | 96 | } |
|
| 97 | 97 | return borrow; |
|
| 98 | 98 | } |
|
| 99 | 99 | ||
| 100 | 100 | /// Multiply two LIMBS-word numbers, producing a 2*LIMBS-word result in wide. |
|
| 101 | 101 | fn bnMul(wide: *mut [u32], a: *[u32], b: *[u32]) { |
|
| 102 | 102 | let mut i: u32 = 0; |
|
| 103 | 103 | while i < LIMBS * 2 { |
|
| 104 | - | wide[i] = 0; |
|
| 105 | - | i += 1; |
|
| 104 | + | set wide[i] = 0; |
|
| 105 | + | set i += 1; |
|
| 106 | 106 | } |
|
| 107 | 107 | ||
| 108 | - | i = 0; |
|
| 108 | + | set i = 0; |
|
| 109 | 109 | while i < LIMBS { |
|
| 110 | 110 | let mut carry: u32 = 0; |
|
| 111 | 111 | let mut j: u32 = 0; |
|
| 112 | 112 | while j < LIMBS { |
|
| 113 | 113 | let al: u32 = a[i] & 0xFFFF; |
| 121 | 121 | let hh: u32 = ah * bh; |
|
| 122 | 122 | ||
| 123 | 123 | let mid: u32 = lh + hl; |
|
| 124 | 124 | let mut midCarry: u32 = 0; |
|
| 125 | 125 | if mid < lh { |
|
| 126 | - | midCarry = 1; |
|
| 126 | + | set midCarry = 1; |
|
| 127 | 127 | } |
|
| 128 | 128 | ||
| 129 | 129 | let lo: u32 = ll + (mid << 16); |
|
| 130 | 130 | let mut loCarry: u32 = 0; |
|
| 131 | 131 | if lo < ll { |
|
| 132 | - | loCarry = 1; |
|
| 132 | + | set loCarry = 1; |
|
| 133 | 133 | } |
|
| 134 | 134 | let hi: u32 = hh + (mid >> 16) + (midCarry << 16) + loCarry; |
|
| 135 | 135 | ||
| 136 | 136 | let sum1: u32 = wide[i + j] + lo; |
|
| 137 | 137 | let mut c1: u32 = 0; |
|
| 138 | 138 | if sum1 < wide[i + j] { |
|
| 139 | - | c1 = 1; |
|
| 139 | + | set c1 = 1; |
|
| 140 | 140 | } |
|
| 141 | 141 | let sum2: u32 = sum1 + carry; |
|
| 142 | 142 | let mut c2: u32 = 0; |
|
| 143 | 143 | if sum2 < sum1 { |
|
| 144 | - | c2 = 1; |
|
| 144 | + | set c2 = 1; |
|
| 145 | 145 | } |
|
| 146 | - | wide[i + j] = sum2; |
|
| 147 | - | carry = hi + c1 + c2; |
|
| 146 | + | set wide[i + j] = sum2; |
|
| 147 | + | set carry = hi + c1 + c2; |
|
| 148 | 148 | ||
| 149 | - | j += 1; |
|
| 149 | + | set j += 1; |
|
| 150 | 150 | } |
|
| 151 | - | wide[i + LIMBS] += carry; |
|
| 152 | - | i += 1; |
|
| 151 | + | set wide[i + LIMBS] += carry; |
|
| 152 | + | set i += 1; |
|
| 153 | 153 | } |
|
| 154 | 154 | } |
|
| 155 | 155 | ||
| 156 | 156 | /// Left shift a big number by 1 bit. |
|
| 157 | 157 | fn bnShl1(dst: *mut [u32], src: *[u32]) { |
|
| 158 | 158 | let mut carry: u32 = 0; |
|
| 159 | 159 | let mut i: u32 = 0; |
|
| 160 | 160 | while i < LIMBS { |
|
| 161 | 161 | let newCarry: u32 = src[i] >> 31; |
|
| 162 | - | dst[i] = (src[i] << 1) | carry; |
|
| 163 | - | carry = newCarry; |
|
| 164 | - | i += 1; |
|
| 162 | + | set dst[i] = (src[i] << 1) | carry; |
|
| 163 | + | set carry = newCarry; |
|
| 164 | + | set i += 1; |
|
| 165 | 165 | } |
|
| 166 | 166 | } |
|
| 167 | 167 | ||
| 168 | 168 | /// Right shift a big number by 1 bit. |
|
| 169 | 169 | fn bnShr1(dst: *mut [u32], src: *[u32]) { |
|
| 170 | 170 | let mut carry: u32 = 0; |
|
| 171 | 171 | let mut i: u32 = LIMBS; |
|
| 172 | 172 | while i > 0 { |
|
| 173 | - | i -= 1; |
|
| 173 | + | set i -= 1; |
|
| 174 | 174 | let newCarry: u32 = src[i] & 1; |
|
| 175 | - | dst[i] = (src[i] >> 1) | (carry << 31); |
|
| 176 | - | carry = newCarry; |
|
| 175 | + | set dst[i] = (src[i] >> 1) | (carry << 31); |
|
| 176 | + | set carry = newCarry; |
|
| 177 | 177 | } |
|
| 178 | 178 | } |
|
| 179 | 179 | ||
| 180 | 180 | /// Test basic addition. |
|
| 181 | 181 | fn testAdd() -> i32 { |
| 206 | 206 | let mut a: [u32; 4] = [0; 4]; |
|
| 207 | 207 | let mut b: [u32; 4] = [0; 4]; |
|
| 208 | 208 | let mut c: [u32; 4] = [0; 4]; |
|
| 209 | 209 | ||
| 210 | 210 | bnZero(&mut a[..]); |
|
| 211 | - | a[1] = 1; |
|
| 211 | + | set a[1] = 1; |
|
| 212 | 212 | bnFromU32(&mut b[..], 1); |
|
| 213 | 213 | let borrow: u32 = bnSub(&mut c[..], &a[..], &b[..]); |
|
| 214 | 214 | ||
| 215 | 215 | assert borrow == 0; |
|
| 216 | 216 | assert c[0] == 0xFFFFFFFF; |
| 247 | 247 | let mut a: [u32; 4] = [0; 4]; |
|
| 248 | 248 | let mut b: [u32; 4] = [0; 4]; |
|
| 249 | 249 | let mut c: [u32; 4] = [0; 4]; |
|
| 250 | 250 | let mut d: [u32; 4] = [0; 4]; |
|
| 251 | 251 | ||
| 252 | - | a[0] = 0x12345678; |
|
| 253 | - | a[1] = 0xABCDEF01; |
|
| 254 | - | a[2] = 0x9876FEDC; |
|
| 255 | - | a[3] = 0x01020304; |
|
| 252 | + | set a[0] = 0x12345678; |
|
| 253 | + | set a[1] = 0xABCDEF01; |
|
| 254 | + | set a[2] = 0x9876FEDC; |
|
| 255 | + | set a[3] = 0x01020304; |
|
| 256 | 256 | ||
| 257 | - | b[0] = 0xFEDCBA98; |
|
| 258 | - | b[1] = 0x76543210; |
|
| 259 | - | b[2] = 0x11223344; |
|
| 260 | - | b[3] = 0x00AABB00; |
|
| 257 | + | set b[0] = 0xFEDCBA98; |
|
| 258 | + | set b[1] = 0x76543210; |
|
| 259 | + | set b[2] = 0x11223344; |
|
| 260 | + | set b[3] = 0x00AABB00; |
|
| 261 | 261 | ||
| 262 | 262 | bnAdd(&mut c[..], &a[..], &b[..]); |
|
| 263 | 263 | bnSub(&mut d[..], &c[..], &b[..]); |
|
| 264 | 264 | ||
| 265 | 265 | assert bnCmp(&d[..], &a[..]) == 0; |
| 296 | 296 | fn testLargeMultiply() -> i32 { |
|
| 297 | 297 | let mut a: [u32; 4] = [0; 4]; |
|
| 298 | 298 | let mut b: [u32; 4] = [0; 4]; |
|
| 299 | 299 | let mut wide: [u32; 8] = [0; 8]; |
|
| 300 | 300 | ||
| 301 | - | a[0] = 0xFFFFFFFF; |
|
| 302 | - | a[1] = 0xFFFFFFFF; |
|
| 303 | - | a[2] = 0; |
|
| 304 | - | a[3] = 0; |
|
| 301 | + | set a[0] = 0xFFFFFFFF; |
|
| 302 | + | set a[1] = 0xFFFFFFFF; |
|
| 303 | + | set a[2] = 0; |
|
| 304 | + | set a[3] = 0; |
|
| 305 | 305 | ||
| 306 | 306 | bnFromU32(&mut b[..], 1); |
|
| 307 | 307 | bnMul(&mut wide[..], &a[..], &b[..]); |
|
| 308 | 308 | assert wide[0] == 0xFFFFFFFF; |
|
| 309 | 309 | assert wide[1] == 0xFFFFFFFF; |
|
| 310 | 310 | assert wide[2] == 0; |
|
| 311 | 311 | ||
| 312 | 312 | bnZero(&mut a[..]); |
|
| 313 | - | a[1] = 1; |
|
| 313 | + | set a[1] = 1; |
|
| 314 | 314 | bnZero(&mut b[..]); |
|
| 315 | - | b[1] = 1; |
|
| 315 | + | set b[1] = 1; |
|
| 316 | 316 | bnMul(&mut wide[..], &a[..], &b[..]); |
|
| 317 | 317 | assert wide[0] == 0; |
|
| 318 | 318 | assert wide[1] == 0; |
|
| 319 | 319 | assert wide[2] == 1; |
|
| 320 | 320 | assert wide[3] == 0; |
| 326 | 326 | fn testFibonacci() -> i32 { |
|
| 327 | 327 | let mut fibA: [u32; 4] = [0; 4]; |
|
| 328 | 328 | let mut fibB: [u32; 4] = [0; 4]; |
|
| 329 | 329 | let mut fibC: [u32; 4] = [0; 4]; |
|
| 330 | 330 | ||
| 331 | - | fibA[0] = 0; |
|
| 332 | - | fibB[0] = 1; |
|
| 331 | + | set fibA[0] = 0; |
|
| 332 | + | set fibB[0] = 1; |
|
| 333 | 333 | ||
| 334 | 334 | let mut i: u32 = 2; |
|
| 335 | 335 | while i <= 48 { |
|
| 336 | 336 | bnAdd(&mut fibC[..], &fibA[..], &fibB[..]); |
|
| 337 | 337 | bnCopy(&mut fibA[..], &fibB[..]); |
|
| 338 | 338 | bnCopy(&mut fibB[..], &fibC[..]); |
|
| 339 | - | i += 1; |
|
| 339 | + | set i += 1; |
|
| 340 | 340 | } |
|
| 341 | 341 | ||
| 342 | 342 | assert fibB[0] == 0x1E8D0A40; |
|
| 343 | 343 | assert fibB[1] == 0x01; |
|
| 344 | 344 | ||
| 345 | 345 | let mut fa: [u32; 4] = [0; 4]; |
|
| 346 | 346 | let mut fb: [u32; 4] = [0; 4]; |
|
| 347 | 347 | let mut fc: [u32; 4] = [0; 4]; |
|
| 348 | - | fa[0] = 0; |
|
| 349 | - | fb[0] = 1; |
|
| 350 | - | i = 2; |
|
| 348 | + | set fa[0] = 0; |
|
| 349 | + | set fb[0] = 1; |
|
| 350 | + | set i = 2; |
|
| 351 | 351 | while i <= 47 { |
|
| 352 | 352 | bnAdd(&mut fc[..], &fa[..], &fb[..]); |
|
| 353 | 353 | bnCopy(&mut fa[..], &fb[..]); |
|
| 354 | 354 | bnCopy(&mut fb[..], &fc[..]); |
|
| 355 | - | i += 1; |
|
| 355 | + | set i += 1; |
|
| 356 | 356 | } |
|
| 357 | 357 | bnAdd(&mut fc[..], &fa[..], &fb[..]); |
|
| 358 | 358 | assert bnCmp(&fc[..], &fibB[..]) == 0; |
|
| 359 | 359 | ||
| 360 | 360 | return 0; |
| 372 | 372 | assert bnCmp(&b[..], &a[..]) == 1; |
|
| 373 | 373 | assert bnCmp(&a[..], &a[..]) == 0; |
|
| 374 | 374 | ||
| 375 | 375 | bnZero(&mut a[..]); |
|
| 376 | 376 | bnZero(&mut b[..]); |
|
| 377 | - | a[3] = 1; |
|
| 378 | - | b[0] = 0xFFFFFFFF; |
|
| 379 | - | b[1] = 0xFFFFFFFF; |
|
| 380 | - | b[2] = 0xFFFFFFFF; |
|
| 377 | + | set a[3] = 1; |
|
| 378 | + | set b[0] = 0xFFFFFFFF; |
|
| 379 | + | set b[1] = 0xFFFFFFFF; |
|
| 380 | + | set b[2] = 0xFFFFFFFF; |
|
| 381 | 381 | assert bnCmp(&a[..], &b[..]) == 1; |
|
| 382 | 382 | ||
| 383 | 383 | return 0; |
|
| 384 | 384 | } |
|
| 385 | 385 |
test/tests/prog.binsearch.rad
+2 -2
| 12 | 12 | let val: i32 = data[mid as u32]; |
|
| 13 | 13 | ||
| 14 | 14 | if val == target { |
|
| 15 | 15 | return mid as u32; |
|
| 16 | 16 | } else if val < target { |
|
| 17 | - | lo = mid + 1; |
|
| 17 | + | set lo = mid + 1; |
|
| 18 | 18 | } else { |
|
| 19 | - | hi = mid - 1; |
|
| 19 | + | set hi = mid - 1; |
|
| 20 | 20 | } |
|
| 21 | 21 | } |
|
| 22 | 22 | return nil; |
|
| 23 | 23 | } |
|
| 24 | 24 |
test/tests/prog.bubblesort.rad
+7 -7
| 9 | 9 | let mut swapped: bool = false; |
|
| 10 | 10 | let mut i: u32 = 0; |
|
| 11 | 11 | while i < n - 1 { |
|
| 12 | 12 | if data[i] > data[i + 1] { |
|
| 13 | 13 | let tmp: i32 = data[i]; |
|
| 14 | - | data[i] = data[i + 1]; |
|
| 15 | - | data[i + 1] = tmp; |
|
| 16 | - | swapped = true; |
|
| 14 | + | set data[i] = data[i + 1]; |
|
| 15 | + | set data[i + 1] = tmp; |
|
| 16 | + | set swapped = true; |
|
| 17 | 17 | } |
|
| 18 | - | i += 1; |
|
| 18 | + | set i += 1; |
|
| 19 | 19 | } |
|
| 20 | 20 | if not swapped { |
|
| 21 | 21 | // Already sorted, early exit. |
|
| 22 | 22 | return; |
|
| 23 | 23 | } |
|
| 24 | - | n -= 1; |
|
| 24 | + | set n -= 1; |
|
| 25 | 25 | } |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | /// Verify the array is sorted in ascending order. |
|
| 29 | 29 | fn isSorted(data: *[i32]) -> bool { |
| 32 | 32 | if let p = prev { |
|
| 33 | 33 | if p > val { |
|
| 34 | 34 | return false; |
|
| 35 | 35 | } |
|
| 36 | 36 | } |
|
| 37 | - | prev = val; |
|
| 37 | + | set prev = val; |
|
| 38 | 38 | } |
|
| 39 | 39 | return true; |
|
| 40 | 40 | } |
|
| 41 | 41 | ||
| 42 | 42 | /// Compute the sum of all elements. |
|
| 43 | 43 | fn sum(data: *[i32]) -> i32 { |
|
| 44 | 44 | let mut total: i32 = 0; |
|
| 45 | 45 | for val in data { |
|
| 46 | - | total += val; |
|
| 46 | + | set total += val; |
|
| 47 | 47 | } |
|
| 48 | 48 | return total; |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | /// Verify specific positions in the sorted output. |
test/tests/prog.cordic.rad
+13 -13
| 38 | 38 | while i < ITERATIONS { |
|
| 39 | 39 | let dx: i32 = x >> i as i32; |
|
| 40 | 40 | let dy: i32 = y >> i as i32; |
|
| 41 | 41 | ||
| 42 | 42 | if z >= 0 { |
|
| 43 | - | x -= dy; |
|
| 44 | - | y += dx; |
|
| 45 | - | z -= atanTable[i]; |
|
| 43 | + | set x -= dy; |
|
| 44 | + | set y += dx; |
|
| 45 | + | set z -= atanTable[i]; |
|
| 46 | 46 | } else { |
|
| 47 | - | x += dy; |
|
| 48 | - | y -= dx; |
|
| 49 | - | z += atanTable[i]; |
|
| 47 | + | set x += dy; |
|
| 48 | + | set y -= dx; |
|
| 49 | + | set z += atanTable[i]; |
|
| 50 | 50 | } |
|
| 51 | - | i += 1; |
|
| 51 | + | set i += 1; |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | 54 | return CosSin { cos: x, sin: y }; |
|
| 55 | 55 | } |
|
| 56 | 56 |
| 58 | 58 | fn cosSin(angle: i32, atanTable: *[i32]) -> CosSin { |
|
| 59 | 59 | let mut a: i32 = angle; |
|
| 60 | 60 | ||
| 61 | 61 | // Reduce to [-pi, pi]. |
|
| 62 | 62 | while a > PI { |
|
| 63 | - | a -= 2 * PI; |
|
| 63 | + | set a -= 2 * PI; |
|
| 64 | 64 | } |
|
| 65 | 65 | while a < 0 - PI { |
|
| 66 | - | a += 2 * PI; |
|
| 66 | + | set a += 2 * PI; |
|
| 67 | 67 | } |
|
| 68 | 68 | ||
| 69 | 69 | // If in [pi/2, pi], use cos(a) = -cos(pi-a), sin(a) = sin(pi-a). |
|
| 70 | 70 | if a > HALF_PI { |
|
| 71 | 71 | let r: CosSin = cordicRotate(PI - a, atanTable); |
| 92 | 92 | fn fpmul(a: i32, b: i32) -> i32 { |
|
| 93 | 93 | // Determine sign and work with magnitudes. |
|
| 94 | 94 | let neg: bool = (a < 0) <> (b < 0); |
|
| 95 | 95 | let mut ua: u32 = a as u32; |
|
| 96 | 96 | if a < 0 { |
|
| 97 | - | ua = (0 - a) as u32; |
|
| 97 | + | set ua = (0 - a) as u32; |
|
| 98 | 98 | } |
|
| 99 | 99 | let mut ub: u32 = b as u32; |
|
| 100 | 100 | if b < 0 { |
|
| 101 | - | ub = (0 - b) as u32; |
|
| 101 | + | set ub = (0 - b) as u32; |
|
| 102 | 102 | } |
|
| 103 | 103 | ||
| 104 | 104 | // Split into 16-bit halves: ua = ah:al, ub = bh:bl. |
|
| 105 | 105 | let al: u32 = ua & 0xFFFF; |
|
| 106 | 106 | let ah: u32 = ua >> 16; |
| 170 | 170 | let sum: i32 = sin2 + cos2; |
|
| 171 | 171 | let err: i32 = abs(sum - SCALE); |
|
| 172 | 172 | ||
| 173 | 173 | // Allow ~2% error due to fixed-point precision. |
|
| 174 | 174 | assert err <= 1311; |
|
| 175 | - | i += step; |
|
| 175 | + | set i += step; |
|
| 176 | 176 | } |
|
| 177 | 177 | return 0; |
|
| 178 | 178 | } |
|
| 179 | 179 | ||
| 180 | 180 | /// Test symmetry: sin(-x) = -sin(x), cos(-x) = cos(x). |
| 190 | 190 | ||
| 191 | 191 | // cos(-x) should equal cos(x). |
|
| 192 | 192 | assert abs(rPos.cos - rNeg.cos) <= 655; |
|
| 193 | 193 | // sin(-x) should equal -sin(x). |
|
| 194 | 194 | assert abs(rPos.sin + rNeg.sin) <= 655; |
|
| 195 | - | i += 1; |
|
| 195 | + | set i += 1; |
|
| 196 | 196 | } |
|
| 197 | 197 | return 0; |
|
| 198 | 198 | } |
|
| 199 | 199 | ||
| 200 | 200 | /// Test specific known value: cos(pi/3) = 0.5, sin(pi/3) = 0.866. |
test/tests/prog.crc32.rad
+9 -9
| 9 | 9 | while i < 256 { |
|
| 10 | 10 | let mut crc: u32 = i; |
|
| 11 | 11 | let mut j: u32 = 0; |
|
| 12 | 12 | while j < 8 { |
|
| 13 | 13 | if crc & 1 == 1 { |
|
| 14 | - | crc = (crc >> 1) ^ 0xEDB88320; |
|
| 14 | + | set crc = (crc >> 1) ^ 0xEDB88320; |
|
| 15 | 15 | } else { |
|
| 16 | - | crc >>= 1; |
|
| 16 | + | set crc >>= 1; |
|
| 17 | 17 | } |
|
| 18 | - | j += 1; |
|
| 18 | + | set j += 1; |
|
| 19 | 19 | } |
|
| 20 | - | table[i] = crc; |
|
| 21 | - | i += 1; |
|
| 20 | + | set table[i] = crc; |
|
| 21 | + | set i += 1; |
|
| 22 | 22 | } |
|
| 23 | 23 | } |
|
| 24 | 24 | ||
| 25 | 25 | /// Compute CRC-32 of a byte slice. |
|
| 26 | 26 | fn crc32(table: *[u32], data: *[u8]) -> u32 { |
|
| 27 | 27 | let mut crc: u32 = 0xFFFFFFFF; |
|
| 28 | 28 | let mut i: u32 = 0; |
|
| 29 | 29 | while i < data.len { |
|
| 30 | 30 | let byte: u8 = data[i]; |
|
| 31 | 31 | let index: u32 = (crc ^ byte as u32) & 0xFF; |
|
| 32 | - | crc = (crc >> 8) ^ table[index]; |
|
| 33 | - | i += 1; |
|
| 32 | + | set crc = (crc >> 8) ^ table[index]; |
|
| 33 | + | set i += 1; |
|
| 34 | 34 | } |
|
| 35 | 35 | return crc ^ 0xFFFFFFFF; |
|
| 36 | 36 | } |
|
| 37 | 37 | ||
| 38 | 38 | /// Test the lookup table has been built correctly. |
| 65 | 65 | fn testIncremental(table: *[u32]) -> i32 { |
|
| 66 | 66 | // Build a 32-byte buffer with values 0..31. |
|
| 67 | 67 | let mut buf: [u8; 32] = [0; 32]; |
|
| 68 | 68 | let mut i: u32 = 0; |
|
| 69 | 69 | while i < 32 { |
|
| 70 | - | buf[i] = i as u8; |
|
| 71 | - | i += 1; |
|
| 70 | + | set buf[i] = i as u8; |
|
| 71 | + | set i += 1; |
|
| 72 | 72 | } |
|
| 73 | 73 | let crcFull = crc32(table, &buf[..]); |
|
| 74 | 74 | ||
| 75 | 75 | // CRC should be non-zero and deterministic. |
|
| 76 | 76 | assert crcFull <> 0; |
test/tests/prog.dijkstra.rad
+39 -39
| 21 | 21 | heapSize: u32, |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | 24 | fn heapSwap(g: *mut Graph, i: u32, j: u32) { |
|
| 25 | 25 | let tmp: HeapEntry = g.heap[i]; |
|
| 26 | - | g.heap[i] = g.heap[j]; |
|
| 27 | - | g.heap[j] = tmp; |
|
| 26 | + | set g.heap[i] = g.heap[j]; |
|
| 27 | + | set g.heap[j] = tmp; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | fn siftUp(g: *mut Graph, pos: u32) { |
|
| 31 | 31 | let mut i: u32 = pos; |
|
| 32 | 32 | while i > 0 { |
|
| 33 | 33 | let parent: u32 = (i - 1) / 2; |
|
| 34 | 34 | if g.heap[i].dist < g.heap[parent].dist { |
|
| 35 | 35 | heapSwap(g, i, parent); |
|
| 36 | - | i = parent; |
|
| 36 | + | set i = parent; |
|
| 37 | 37 | } else { |
|
| 38 | 38 | return; |
|
| 39 | 39 | } |
|
| 40 | 40 | } |
|
| 41 | 41 | } |
| 46 | 46 | let left: u32 = 2 * i + 1; |
|
| 47 | 47 | let right: u32 = 2 * i + 2; |
|
| 48 | 48 | let mut smallest: u32 = i; |
|
| 49 | 49 | ||
| 50 | 50 | if left < g.heapSize and g.heap[left].dist < g.heap[smallest].dist { |
|
| 51 | - | smallest = left; |
|
| 51 | + | set smallest = left; |
|
| 52 | 52 | } |
|
| 53 | 53 | if right < g.heapSize and g.heap[right].dist < g.heap[smallest].dist { |
|
| 54 | - | smallest = right; |
|
| 54 | + | set smallest = right; |
|
| 55 | 55 | } |
|
| 56 | 56 | if smallest == i { |
|
| 57 | 57 | return; |
|
| 58 | 58 | } |
|
| 59 | 59 | heapSwap(g, i, smallest); |
|
| 60 | - | i = smallest; |
|
| 60 | + | set i = smallest; |
|
| 61 | 61 | } |
|
| 62 | 62 | } |
|
| 63 | 63 | ||
| 64 | 64 | fn heapPush(g: *mut Graph, dist: u32, node: u32) { |
|
| 65 | - | g.heap[g.heapSize] = HeapEntry { dist, node }; |
|
| 66 | - | g.heapSize += 1; |
|
| 65 | + | set g.heap[g.heapSize] = HeapEntry { dist, node }; |
|
| 66 | + | set g.heapSize += 1; |
|
| 67 | 67 | siftUp(g, g.heapSize - 1); |
|
| 68 | 68 | } |
|
| 69 | 69 | ||
| 70 | 70 | /// Pop from the heap. Returns nil if the heap is empty. |
|
| 71 | 71 | fn heapPop(g: *mut Graph) -> ?HeapEntry { |
|
| 72 | 72 | if g.heapSize == 0 { |
|
| 73 | 73 | return nil; |
|
| 74 | 74 | } |
|
| 75 | 75 | let result: HeapEntry = g.heap[0]; |
|
| 76 | - | g.heapSize -= 1; |
|
| 77 | - | g.heap[0] = g.heap[g.heapSize]; |
|
| 76 | + | set g.heapSize -= 1; |
|
| 77 | + | set g.heap[0] = g.heap[g.heapSize]; |
|
| 78 | 78 | if g.heapSize > 0 { |
|
| 79 | 79 | siftDown(g, 0); |
|
| 80 | 80 | } |
|
| 81 | 81 | return result; |
|
| 82 | 82 | } |
|
| 83 | 83 | ||
| 84 | 84 | fn addEdge(g: *mut Graph, from: u32, to: u32, weight: u32) { |
|
| 85 | - | g.adj[from][to] = weight; |
|
| 85 | + | set g.adj[from][to] = weight; |
|
| 86 | 86 | } |
|
| 87 | 87 | ||
| 88 | 88 | fn addBidiEdge(g: *mut Graph, from: u32, to: u32, weight: u32) { |
|
| 89 | - | g.adj[from][to] = weight; |
|
| 90 | - | g.adj[to][from] = weight; |
|
| 89 | + | set g.adj[from][to] = weight; |
|
| 90 | + | set g.adj[to][from] = weight; |
|
| 91 | 91 | } |
|
| 92 | 92 | ||
| 93 | 93 | fn resetGraph(g: *mut Graph, n: u32) { |
|
| 94 | - | g.numNodes = n; |
|
| 94 | + | set g.numNodes = n; |
|
| 95 | 95 | let mut i: u32 = 0; |
|
| 96 | 96 | while i < MAX_NODES { |
|
| 97 | 97 | let mut j: u32 = 0; |
|
| 98 | 98 | while j < MAX_NODES { |
|
| 99 | - | g.adj[i][j] = INF; |
|
| 100 | - | j += 1; |
|
| 99 | + | set g.adj[i][j] = INF; |
|
| 100 | + | set j += 1; |
|
| 101 | 101 | } |
|
| 102 | - | g.dist[i] = INF; |
|
| 103 | - | g.prev[i] = -1; |
|
| 104 | - | g.visited[i] = false; |
|
| 105 | - | i += 1; |
|
| 102 | + | set g.dist[i] = INF; |
|
| 103 | + | set g.prev[i] = -1; |
|
| 104 | + | set g.visited[i] = false; |
|
| 105 | + | set i += 1; |
|
| 106 | 106 | } |
|
| 107 | - | g.heapSize = 0; |
|
| 107 | + | set g.heapSize = 0; |
|
| 108 | 108 | } |
|
| 109 | 109 | ||
| 110 | 110 | /// Get the predecessor as an optional; -1 means no predecessor. |
|
| 111 | 111 | fn getPrev(g: *Graph, node: u32) -> ?u32 { |
|
| 112 | 112 | let p = g.prev[node]; |
| 115 | 115 | } |
|
| 116 | 116 | return p as u32; |
|
| 117 | 117 | } |
|
| 118 | 118 | ||
| 119 | 119 | fn dijkstra(g: *mut Graph, source: u32) { |
|
| 120 | - | g.dist[source] = 0; |
|
| 120 | + | set g.dist[source] = 0; |
|
| 121 | 121 | heapPush(g, 0, source); |
|
| 122 | 122 | ||
| 123 | 123 | while let entry = heapPop(g) { |
|
| 124 | 124 | let u: u32 = entry.node; |
|
| 125 | 125 | ||
| 126 | 126 | if g.visited[u] { |
|
| 127 | 127 | continue; |
|
| 128 | 128 | } |
|
| 129 | - | g.visited[u] = true; |
|
| 129 | + | set g.visited[u] = true; |
|
| 130 | 130 | ||
| 131 | 131 | let mut v: u32 = 0; |
|
| 132 | 132 | while v < g.numNodes { |
|
| 133 | 133 | if g.adj[u][v] <> INF and not g.visited[v] { |
|
| 134 | 134 | let newDist: u32 = g.dist[u] + g.adj[u][v]; |
|
| 135 | 135 | if newDist < g.dist[v] { |
|
| 136 | - | g.dist[v] = newDist; |
|
| 137 | - | g.prev[v] = u as i32; |
|
| 136 | + | set g.dist[v] = newDist; |
|
| 137 | + | set g.prev[v] = u as i32; |
|
| 138 | 138 | heapPush(g, newDist, v); |
|
| 139 | 139 | } |
|
| 140 | 140 | } |
|
| 141 | - | v += 1; |
|
| 141 | + | set v += 1; |
|
| 142 | 142 | } |
|
| 143 | 143 | } |
|
| 144 | 144 | } |
|
| 145 | 145 | ||
| 146 | 146 | /// Reconstruct the shortest path from source to target. |
|
| 147 | 147 | fn reconstructPath(g: *Graph, target: u32, path: *mut [u32]) -> u32 { |
|
| 148 | 148 | let mut len: u32 = 0; |
|
| 149 | 149 | ||
| 150 | - | path[len] = target; |
|
| 151 | - | len += 1; |
|
| 150 | + | set path[len] = target; |
|
| 151 | + | set len += 1; |
|
| 152 | 152 | ||
| 153 | 153 | let mut cur: ?u32 = getPrev(g, target); |
|
| 154 | 154 | while let node = cur { |
|
| 155 | - | path[len] = node; |
|
| 156 | - | len += 1; |
|
| 157 | - | cur = getPrev(g, node); |
|
| 155 | + | set path[len] = node; |
|
| 156 | + | set len += 1; |
|
| 157 | + | set cur = getPrev(g, node); |
|
| 158 | 158 | } |
|
| 159 | 159 | ||
| 160 | 160 | // Reverse the path. |
|
| 161 | 161 | let mut a: u32 = 0; |
|
| 162 | 162 | let mut b: u32 = len - 1; |
|
| 163 | 163 | while a < b { |
|
| 164 | 164 | let tmp: u32 = path[a]; |
|
| 165 | - | path[a] = path[b]; |
|
| 166 | - | path[b] = tmp; |
|
| 167 | - | a += 1; |
|
| 168 | - | b -= 1; |
|
| 165 | + | set path[a] = path[b]; |
|
| 166 | + | set path[b] = tmp; |
|
| 167 | + | set a += 1; |
|
| 168 | + | set b -= 1; |
|
| 169 | 169 | } |
|
| 170 | 170 | return len; |
|
| 171 | 171 | } |
|
| 172 | 172 | ||
| 173 | 173 | fn testLinear(g: *mut Graph) -> i32 { |
| 244 | 244 | let mut j: u32 = 0; |
|
| 245 | 245 | while j < 8 { |
|
| 246 | 246 | if i <> j { |
|
| 247 | 247 | let mut diff: u32 = j - i; |
|
| 248 | 248 | if i > j { |
|
| 249 | - | diff = i - j; |
|
| 249 | + | set diff = i - j; |
|
| 250 | 250 | } |
|
| 251 | 251 | addEdge(g, i, j, diff * 3 + 1); |
|
| 252 | 252 | } |
|
| 253 | - | j += 1; |
|
| 253 | + | set j += 1; |
|
| 254 | 254 | } |
|
| 255 | - | i += 1; |
|
| 255 | + | set i += 1; |
|
| 256 | 256 | } |
|
| 257 | 257 | ||
| 258 | 258 | dijkstra(g, 0); |
|
| 259 | 259 | ||
| 260 | 260 | let mut k: u32 = 1; |
|
| 261 | 261 | while k < 8 { |
|
| 262 | 262 | let expected: u32 = k * 3 + 1; |
|
| 263 | 263 | if g.dist[k] <> expected { |
|
| 264 | 264 | return k as i32; |
|
| 265 | 265 | } |
|
| 266 | - | k += 1; |
|
| 266 | + | set k += 1; |
|
| 267 | 267 | } |
|
| 268 | 268 | ||
| 269 | 269 | return 0; |
|
| 270 | 270 | } |
|
| 271 | 271 |
test/tests/prog.eval.rad
+4 -4
| 33 | 33 | } |
|
| 34 | 34 | ||
| 35 | 35 | /// Allocate a new node, returning its index. |
|
| 36 | 36 | fn newNode(pool: *mut Pool, expr: Expr) -> u32 { |
|
| 37 | 37 | let idx = pool.count; |
|
| 38 | - | pool.nodes[idx] = expr; |
|
| 39 | - | pool.count += 1; |
|
| 38 | + | set pool.nodes[idx] = expr; |
|
| 39 | + | set pool.count += 1; |
|
| 40 | 40 | return idx; |
|
| 41 | 41 | } |
|
| 42 | 42 | ||
| 43 | 43 | /// Convenience constructors. |
|
| 44 | 44 | fn num(pool: *mut Pool, n: i32) -> u32 { |
| 120 | 120 | } |
|
| 121 | 121 | } |
|
| 122 | 122 | ||
| 123 | 123 | /// Reset the node pool. |
|
| 124 | 124 | fn reset(pool: *mut Pool) { |
|
| 125 | - | pool.count = 0; |
|
| 125 | + | set pool.count = 0; |
|
| 126 | 126 | } |
|
| 127 | 127 | ||
| 128 | 128 | /// Test 1: Simple addition: 3 + 4 = 7 |
|
| 129 | 129 | fn testSimpleAdd(pool: *mut Pool) -> i32 { |
|
| 130 | 130 | reset(pool); |
| 167 | 167 | fn testDeep(pool: *mut Pool) -> i32 { |
|
| 168 | 168 | reset(pool); |
|
| 169 | 169 | let mut root = num(pool, 1); |
|
| 170 | 170 | let values: [i32; 7] = [2, 3, 4, 5, 6, 7, 8]; |
|
| 171 | 171 | for v in values { |
|
| 172 | - | root = add(pool, root, num(pool, v)); |
|
| 172 | + | set root = add(pool, root, num(pool, v)); |
|
| 173 | 173 | } |
|
| 174 | 174 | assert try! eval(&pool.nodes[..], root) == 36; |
|
| 175 | 175 | assert countNodes(&pool.nodes[..], root) == 15; |
|
| 176 | 176 | return 0; |
|
| 177 | 177 | } |
test/tests/prog.hanoi.rad
+7 -7
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | /// Record a move. |
|
| 24 | 24 | fn recordMove(ml: *mut MoveLog, disk: u32, from: u32, to: u32) { |
|
| 25 | 25 | if ml.count < MAX_MOVES { |
|
| 26 | - | ml.moves[ml.count] = Move { disk, from, to }; |
|
| 27 | - | ml.count += 1; |
|
| 26 | + | set ml.moves[ml.count] = Move { disk, from, to }; |
|
| 27 | + | set ml.count += 1; |
|
| 28 | 28 | } |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | /// Solve Tower of Hanoi recursively. |
|
| 32 | 32 | /// Move `n` disks from peg `from` to peg `to` using `aux` as auxiliary. |
| 78 | 78 | // Check that the top disk is larger than the one being placed. |
|
| 79 | 79 | if pegs.stacks[peg][t - 1] < disk { |
|
| 80 | 80 | return false; |
|
| 81 | 81 | } |
|
| 82 | 82 | } |
|
| 83 | - | pegs.stacks[peg][t] = disk; |
|
| 84 | - | pegs.top[peg] = t + 1; |
|
| 83 | + | set pegs.stacks[peg][t] = disk; |
|
| 84 | + | set pegs.top[peg] = t + 1; |
|
| 85 | 85 | return true; |
|
| 86 | 86 | } |
|
| 87 | 87 | ||
| 88 | 88 | fn pegPop(pegs: *mut Pegs, peg: u32) -> u32 { |
|
| 89 | 89 | let t = pegs.top[peg]; |
|
| 90 | 90 | if t == 0 { |
|
| 91 | 91 | // Should not happen in a valid solution. |
|
| 92 | 92 | return 0; |
|
| 93 | 93 | } |
|
| 94 | - | pegs.top[peg] = t - 1; |
|
| 94 | + | set pegs.top[peg] = t - 1; |
|
| 95 | 95 | return pegs.stacks[peg][t - 1]; |
|
| 96 | 96 | } |
|
| 97 | 97 | ||
| 98 | 98 | /// Simulate the peg state to verify correctness. |
|
| 99 | 99 | /// Replay all moves and check: |
| 110 | 110 | while d >= 1 { |
|
| 111 | 111 | assert pegPush(&mut pegs, 0, d); |
|
| 112 | 112 | if d == 0 { |
|
| 113 | 113 | break; |
|
| 114 | 114 | } |
|
| 115 | - | d -= 1; |
|
| 115 | + | set d -= 1; |
|
| 116 | 116 | } |
|
| 117 | 117 | ||
| 118 | 118 | // Replay all moves. |
|
| 119 | 119 | let mut i: u32 = 0; |
|
| 120 | 120 | while i < ml.count { |
|
| 121 | 121 | let m = ml.moves[i]; |
|
| 122 | 122 | let disk = pegPop(&mut pegs, m.from); |
|
| 123 | 123 | assert disk == m.disk; |
|
| 124 | 124 | assert pegPush(&mut pegs, m.to, disk); |
|
| 125 | - | i += 1; |
|
| 125 | + | set i += 1; |
|
| 126 | 126 | } |
|
| 127 | 127 | ||
| 128 | 128 | // All disks should be on peg 1. |
|
| 129 | 129 | assert pegs.top[0] == 0; |
|
| 130 | 130 | assert pegs.top[1] == NUM_DISKS; |
test/tests/prog.huffman.rad
+39 -39
| 35 | 35 | bitCount: u32, |
|
| 36 | 36 | } |
|
| 37 | 37 | ||
| 38 | 38 | fn newLeaf(s: *mut HuffState, freq: u32, symbol: u32) -> u32 { |
|
| 39 | 39 | let idx: u32 = s.nodeCount; |
|
| 40 | - | s.nodes[idx] = HNode { freq, kind: HNodeKind::Leaf(symbol), left: NIL, right: NIL }; |
|
| 41 | - | s.nodeCount += 1; |
|
| 40 | + | set s.nodes[idx] = HNode { freq, kind: HNodeKind::Leaf(symbol), left: NIL, right: NIL }; |
|
| 41 | + | set s.nodeCount += 1; |
|
| 42 | 42 | return idx; |
|
| 43 | 43 | } |
|
| 44 | 44 | ||
| 45 | 45 | fn newInterior(s: *mut HuffState, freq: u32, left: u32, right: u32) -> u32 { |
|
| 46 | 46 | let idx: u32 = s.nodeCount; |
|
| 47 | - | s.nodes[idx] = HNode { freq, kind: HNodeKind::Interior, left, right }; |
|
| 48 | - | s.nodeCount += 1; |
|
| 47 | + | set s.nodes[idx] = HNode { freq, kind: HNodeKind::Interior, left, right }; |
|
| 48 | + | set s.nodeCount += 1; |
|
| 49 | 49 | return idx; |
|
| 50 | 50 | } |
|
| 51 | 51 | ||
| 52 | 52 | /// Get the symbol from a node, or nil if it's an interior node. |
|
| 53 | 53 | fn nodeSymbol(node: *HNode) -> ?u32 { |
| 61 | 61 | } |
|
| 62 | 62 | } |
|
| 63 | 63 | ||
| 64 | 64 | fn heapSwap(s: *mut HuffState, i: u32, j: u32) { |
|
| 65 | 65 | let tmp: u32 = s.heap[i]; |
|
| 66 | - | s.heap[i] = s.heap[j]; |
|
| 67 | - | s.heap[j] = tmp; |
|
| 66 | + | set s.heap[i] = s.heap[j]; |
|
| 67 | + | set s.heap[j] = tmp; |
|
| 68 | 68 | } |
|
| 69 | 69 | ||
| 70 | 70 | fn heapFreq(s: *HuffState, i: u32) -> u32 { |
|
| 71 | 71 | return s.nodes[s.heap[i]].freq; |
|
| 72 | 72 | } |
| 75 | 75 | let mut i: u32 = pos; |
|
| 76 | 76 | while i > 0 { |
|
| 77 | 77 | let parent: u32 = (i - 1) / 2; |
|
| 78 | 78 | if heapFreq(s, i) < heapFreq(s, parent) { |
|
| 79 | 79 | heapSwap(s, i, parent); |
|
| 80 | - | i = parent; |
|
| 80 | + | set i = parent; |
|
| 81 | 81 | } else { |
|
| 82 | 82 | return; |
|
| 83 | 83 | } |
|
| 84 | 84 | } |
|
| 85 | 85 | } |
| 90 | 90 | let left: u32 = 2 * i + 1; |
|
| 91 | 91 | let right: u32 = 2 * i + 2; |
|
| 92 | 92 | let mut smallest: u32 = i; |
|
| 93 | 93 | ||
| 94 | 94 | if left < s.heapSize and heapFreq(s, left) < heapFreq(s, smallest) { |
|
| 95 | - | smallest = left; |
|
| 95 | + | set smallest = left; |
|
| 96 | 96 | } |
|
| 97 | 97 | if right < s.heapSize and heapFreq(s, right) < heapFreq(s, smallest) { |
|
| 98 | - | smallest = right; |
|
| 98 | + | set smallest = right; |
|
| 99 | 99 | } |
|
| 100 | 100 | if smallest == i { |
|
| 101 | 101 | return; |
|
| 102 | 102 | } |
|
| 103 | 103 | heapSwap(s, i, smallest); |
|
| 104 | - | i = smallest; |
|
| 104 | + | set i = smallest; |
|
| 105 | 105 | } |
|
| 106 | 106 | } |
|
| 107 | 107 | ||
| 108 | 108 | fn heapPush(s: *mut HuffState, nodeIdx: u32) { |
|
| 109 | - | s.heap[s.heapSize] = nodeIdx; |
|
| 110 | - | s.heapSize += 1; |
|
| 109 | + | set s.heap[s.heapSize] = nodeIdx; |
|
| 110 | + | set s.heapSize += 1; |
|
| 111 | 111 | siftUp(s, s.heapSize - 1); |
|
| 112 | 112 | } |
|
| 113 | 113 | ||
| 114 | 114 | fn heapPop(s: *mut HuffState) -> u32 { |
|
| 115 | 115 | let result: u32 = s.heap[0]; |
|
| 116 | - | s.heapSize -= 1; |
|
| 117 | - | s.heap[0] = s.heap[s.heapSize]; |
|
| 116 | + | set s.heapSize -= 1; |
|
| 117 | + | set s.heap[0] = s.heap[s.heapSize]; |
|
| 118 | 118 | if s.heapSize > 0 { |
|
| 119 | 119 | siftDown(s, 0); |
|
| 120 | 120 | } |
|
| 121 | 121 | return result; |
|
| 122 | 122 | } |
|
| 123 | 123 | ||
| 124 | 124 | fn buildTree(s: *mut HuffState, freqs: *[u32]) -> u32 { |
|
| 125 | - | s.nodeCount = 0; |
|
| 126 | - | s.heapSize = 0; |
|
| 125 | + | set s.nodeCount = 0; |
|
| 126 | + | set s.heapSize = 0; |
|
| 127 | 127 | ||
| 128 | 128 | for freq, sym in freqs { |
|
| 129 | 129 | if freq > 0 { |
|
| 130 | 130 | let idx: u32 = newLeaf(s, freq, sym); |
|
| 131 | 131 | heapPush(s, idx); |
| 144 | 144 | } |
|
| 145 | 145 | ||
| 146 | 146 | fn generateCodes(s: *mut HuffState, nodeIdx: u32, code: u32, depth: u32) { |
|
| 147 | 147 | match s.nodes[nodeIdx].kind { |
|
| 148 | 148 | case HNodeKind::Leaf(sym) => { |
|
| 149 | - | s.codeBits[sym] = code; |
|
| 150 | - | s.codeLen[sym] = depth; |
|
| 149 | + | set s.codeBits[sym] = code; |
|
| 150 | + | set s.codeLen[sym] = depth; |
|
| 151 | 151 | } |
|
| 152 | 152 | case HNodeKind::Interior => { |
|
| 153 | 153 | if s.nodes[nodeIdx].left <> NIL { |
|
| 154 | 154 | generateCodes(s, s.nodes[nodeIdx].left, code << 1, depth + 1); |
|
| 155 | 155 | } |
| 162 | 162 | ||
| 163 | 163 | fn writeBit(s: *mut HuffState, bit: u32) { |
|
| 164 | 164 | let byteIdx: u32 = s.bitCount / 8; |
|
| 165 | 165 | let bitIdx: u32 = 7 - (s.bitCount % 8); |
|
| 166 | 166 | if bit == 1 { |
|
| 167 | - | s.bitstream[byteIdx] |= (1 as u8 << bitIdx as u8); |
|
| 167 | + | set s.bitstream[byteIdx] |= (1 as u8 << bitIdx as u8); |
|
| 168 | 168 | } |
|
| 169 | - | s.bitCount += 1; |
|
| 169 | + | set s.bitCount += 1; |
|
| 170 | 170 | } |
|
| 171 | 171 | ||
| 172 | 172 | fn readBit(s: *HuffState, pos: u32) -> u32 { |
|
| 173 | 173 | let byteIdx: u32 = pos / 8; |
|
| 174 | 174 | let bitIdx: u32 = 7 - (pos % 8); |
|
| 175 | 175 | return (s.bitstream[byteIdx] >> bitIdx as u8) as u32 & 1; |
|
| 176 | 176 | } |
|
| 177 | 177 | ||
| 178 | 178 | fn encode(s: *mut HuffState, msg: *[u32]) { |
|
| 179 | - | s.bitCount = 0; |
|
| 179 | + | set s.bitCount = 0; |
|
| 180 | 180 | let mut i: u32 = 0; |
|
| 181 | 181 | while i < MAX_BITS { |
|
| 182 | - | s.bitstream[i] = 0; |
|
| 183 | - | i += 1; |
|
| 182 | + | set s.bitstream[i] = 0; |
|
| 183 | + | set i += 1; |
|
| 184 | 184 | } |
|
| 185 | 185 | ||
| 186 | 186 | for sym in msg { |
|
| 187 | 187 | let bits: u32 = s.codeBits[sym]; |
|
| 188 | 188 | let len: u32 = s.codeLen[sym]; |
|
| 189 | 189 | let mut b: u32 = 0; |
|
| 190 | 190 | while b < len { |
|
| 191 | 191 | let bit: u32 = (bits >> (len - 1 - b)) & 1; |
|
| 192 | 192 | writeBit(s, bit); |
|
| 193 | - | b += 1; |
|
| 193 | + | set b += 1; |
|
| 194 | 194 | } |
|
| 195 | 195 | } |
|
| 196 | 196 | } |
|
| 197 | 197 | ||
| 198 | 198 | fn decode(s: *HuffState, root: u32, numSymbols: u32, out: *mut [u32]) -> u32 { |
| 202 | 202 | while decoded < numSymbols { |
|
| 203 | 203 | let mut cur: u32 = root; |
|
| 204 | 204 | // Walk the tree until we find a leaf. |
|
| 205 | 205 | while nodeSymbol(&s.nodes[cur]) == nil { |
|
| 206 | 206 | let bit: u32 = readBit(s, bitPos); |
|
| 207 | - | bitPos += 1; |
|
| 207 | + | set bitPos += 1; |
|
| 208 | 208 | if bit == 0 { |
|
| 209 | - | cur = s.nodes[cur].left; |
|
| 209 | + | set cur = s.nodes[cur].left; |
|
| 210 | 210 | } else { |
|
| 211 | - | cur = s.nodes[cur].right; |
|
| 211 | + | set cur = s.nodes[cur].right; |
|
| 212 | 212 | } |
|
| 213 | 213 | } |
|
| 214 | 214 | let sym = nodeSymbol(&s.nodes[cur]) else { |
|
| 215 | 215 | return decoded; |
|
| 216 | 216 | }; |
|
| 217 | - | out[decoded] = sym; |
|
| 218 | - | decoded += 1; |
|
| 217 | + | set out[decoded] = sym; |
|
| 218 | + | set decoded += 1; |
|
| 219 | 219 | } |
|
| 220 | 220 | return decoded; |
|
| 221 | 221 | } |
|
| 222 | 222 | ||
| 223 | 223 | fn resetCodes(s: *mut HuffState) { |
|
| 224 | 224 | let mut i: u32 = 0; |
|
| 225 | 225 | while i < MAX_SYMBOLS { |
|
| 226 | - | s.codeBits[i] = 0; |
|
| 227 | - | s.codeLen[i] = 0; |
|
| 228 | - | i += 1; |
|
| 226 | + | set s.codeBits[i] = 0; |
|
| 227 | + | set s.codeLen[i] = 0; |
|
| 228 | + | set i += 1; |
|
| 229 | 229 | } |
|
| 230 | 230 | } |
|
| 231 | 231 | ||
| 232 | 232 | fn testBasic(s: *mut HuffState) -> i32 { |
|
| 233 | 233 | let freqs: [u32; 5] = [5, 9, 12, 13, 16]; |
| 240 | 240 | ||
| 241 | 241 | // All symbols should have non-zero code lengths. |
|
| 242 | 242 | let mut i: u32 = 0; |
|
| 243 | 243 | while i < 5 { |
|
| 244 | 244 | assert s.codeLen[i] <> 0; |
|
| 245 | - | i += 1; |
|
| 245 | + | set i += 1; |
|
| 246 | 246 | } |
|
| 247 | 247 | ||
| 248 | 248 | // No two symbols at the same depth should have the same code. |
|
| 249 | 249 | let mut a: u32 = 0; |
|
| 250 | 250 | while a < 5 { |
|
| 251 | 251 | let mut b: u32 = a + 1; |
|
| 252 | 252 | while b < 5 { |
|
| 253 | 253 | if s.codeLen[a] == s.codeLen[b] { |
|
| 254 | 254 | assert s.codeBits[a] <> s.codeBits[b]; |
|
| 255 | 255 | } |
|
| 256 | - | b += 1; |
|
| 256 | + | set b += 1; |
|
| 257 | 257 | } |
|
| 258 | - | a += 1; |
|
| 258 | + | set a += 1; |
|
| 259 | 259 | } |
|
| 260 | 260 | ||
| 261 | 261 | return 0; |
|
| 262 | 262 | } |
|
| 263 | 263 |
| 297 | 297 | let mut shortestLen: u32 = 100; |
|
| 298 | 298 | let mut shortestSym: u32 = 0; |
|
| 299 | 299 | let mut i: u32 = 0; |
|
| 300 | 300 | while i < 6 { |
|
| 301 | 301 | if s.codeLen[i] > 0 and s.codeLen[i] < shortestLen { |
|
| 302 | - | shortestLen = s.codeLen[i]; |
|
| 303 | - | shortestSym = i; |
|
| 302 | + | set shortestLen = s.codeLen[i]; |
|
| 303 | + | set shortestSym = i; |
|
| 304 | 304 | } |
|
| 305 | - | i += 1; |
|
| 305 | + | set i += 1; |
|
| 306 | 306 | } |
|
| 307 | 307 | assert shortestSym == 0; |
|
| 308 | 308 | ||
| 309 | 309 | let msg: [u32; 12] = [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2]; |
|
| 310 | 310 | encode(s, &msg[..]); |
| 331 | 331 | ||
| 332 | 332 | // All 8 symbols should have code length 3 (8 = 2^3). |
|
| 333 | 333 | let mut i: u32 = 0; |
|
| 334 | 334 | while i < 8 { |
|
| 335 | 335 | assert s.codeLen[i] == 3; |
|
| 336 | - | i += 1; |
|
| 336 | + | set i += 1; |
|
| 337 | 337 | } |
|
| 338 | 338 | ||
| 339 | 339 | let msg: [u32; 8] = [0, 1, 2, 3, 4, 5, 6, 7]; |
|
| 340 | 340 | encode(s, &msg[..]); |
|
| 341 | 341 |
test/tests/prog.hybridsort.rad
+12 -12
| 4 | 4 | //! both produce identical sorted output. |
|
| 5 | 5 | ||
| 6 | 6 | /// Copy `src` into `dst`. |
|
| 7 | 7 | fn copy(dst: *mut [i32], src: *[i32]) { |
|
| 8 | 8 | for val, i in src { |
|
| 9 | - | dst[i] = val; |
|
| 9 | + | set dst[i] = val; |
|
| 10 | 10 | } |
|
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | /// Insertion sort on the given array. |
|
| 14 | 14 | fn insertionSort(data: *mut [i32]) { |
|
| 15 | 15 | let mut i: u32 = 1; |
|
| 16 | 16 | while i < data.len { |
|
| 17 | 17 | let key = data[i]; |
|
| 18 | 18 | let mut j: i32 = i as i32 - 1; |
|
| 19 | 19 | while j >= 0 and data[j as u32] > key { |
|
| 20 | - | data[(j + 1) as u32] = data[j as u32]; |
|
| 21 | - | j -= 1; |
|
| 20 | + | set data[(j + 1) as u32] = data[j as u32]; |
|
| 21 | + | set j -= 1; |
|
| 22 | 22 | } |
|
| 23 | - | data[(j + 1) as u32] = key; |
|
| 24 | - | i += 1; |
|
| 23 | + | set data[(j + 1) as u32] = key; |
|
| 24 | + | set i += 1; |
|
| 25 | 25 | } |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | /// Selection sort on the given array. |
|
| 29 | 29 | fn selectionSort(data: *mut [i32]) { |
| 31 | 31 | while i < data.len - 1 { |
|
| 32 | 32 | let mut minIdx: u32 = i; |
|
| 33 | 33 | let mut j: u32 = i + 1; |
|
| 34 | 34 | while j < data.len { |
|
| 35 | 35 | if data[j] < data[minIdx] { |
|
| 36 | - | minIdx = j; |
|
| 36 | + | set minIdx = j; |
|
| 37 | 37 | } |
|
| 38 | - | j += 1; |
|
| 38 | + | set j += 1; |
|
| 39 | 39 | } |
|
| 40 | 40 | if minIdx <> i { |
|
| 41 | 41 | let tmp = data[i]; |
|
| 42 | - | data[i] = data[minIdx]; |
|
| 43 | - | data[minIdx] = tmp; |
|
| 42 | + | set data[i] = data[minIdx]; |
|
| 43 | + | set data[minIdx] = tmp; |
|
| 44 | 44 | } |
|
| 45 | - | i += 1; |
|
| 45 | + | set i += 1; |
|
| 46 | 46 | } |
|
| 47 | 47 | } |
|
| 48 | 48 | ||
| 49 | 49 | /// Check that an array is sorted in ascending order. |
|
| 50 | 50 | fn isSorted(data: *[i32]) -> bool { |
| 53 | 53 | if let p = prev { |
|
| 54 | 54 | if p > val { |
|
| 55 | 55 | return false; |
|
| 56 | 56 | } |
|
| 57 | 57 | } |
|
| 58 | - | prev = val; |
|
| 58 | + | set prev = val; |
|
| 59 | 59 | } |
|
| 60 | 60 | return true; |
|
| 61 | 61 | } |
|
| 62 | 62 | ||
| 63 | 63 | /// Compute sum of all elements. |
|
| 64 | 64 | fn sum(data: *[i32]) -> i32 { |
|
| 65 | 65 | let mut total: i32 = 0; |
|
| 66 | 66 | for val in data { |
|
| 67 | - | total += val; |
|
| 67 | + | set total += val; |
|
| 68 | 68 | } |
|
| 69 | 69 | return total; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | /// Compare two arrays element by element. |
test/tests/prog.linkedlist.rad
+20 -20
| 17 | 17 | } |
|
| 18 | 18 | ||
| 19 | 19 | /// Allocate a node from the pool. Returns its index. |
|
| 20 | 20 | fn alloc(list: *mut List, value: i32) -> u32 { |
|
| 21 | 21 | let idx = list.free; |
|
| 22 | - | list.free += 1; |
|
| 23 | - | list.pool[idx] = Node { value, next: nil }; |
|
| 22 | + | set list.free += 1; |
|
| 23 | + | set list.pool[idx] = Node { value, next: nil }; |
|
| 24 | 24 | return idx; |
|
| 25 | 25 | } |
|
| 26 | 26 | ||
| 27 | 27 | /// Push a value onto the front of the list. |
|
| 28 | 28 | fn push(list: *mut List, value: i32) { |
|
| 29 | 29 | let idx = alloc(list, value); |
|
| 30 | - | list.pool[idx].next = list.head; |
|
| 31 | - | list.head = idx; |
|
| 30 | + | set list.pool[idx].next = list.head; |
|
| 31 | + | set list.head = idx; |
|
| 32 | 32 | } |
|
| 33 | 33 | ||
| 34 | 34 | /// Pop a value from the front of the list. Returns nil if empty. |
|
| 35 | 35 | fn pop(list: *mut List) -> ?i32 { |
|
| 36 | 36 | let idx = list.head else { |
|
| 37 | 37 | return nil; |
|
| 38 | 38 | }; |
|
| 39 | 39 | let value = list.pool[idx].value; |
|
| 40 | - | list.head = list.pool[idx].next; |
|
| 40 | + | set list.head = list.pool[idx].next; |
|
| 41 | 41 | return value; |
|
| 42 | 42 | } |
|
| 43 | 43 | ||
| 44 | 44 | /// Get the length of the list. |
|
| 45 | 45 | fn length(list: *List) -> u32 { |
|
| 46 | 46 | let mut count: u32 = 0; |
|
| 47 | 47 | let mut cur = list.head; |
|
| 48 | 48 | while let idx = cur { |
|
| 49 | - | count += 1; |
|
| 50 | - | cur = list.pool[idx].next; |
|
| 49 | + | set count += 1; |
|
| 50 | + | set cur = list.pool[idx].next; |
|
| 51 | 51 | } |
|
| 52 | 52 | return count; |
|
| 53 | 53 | } |
|
| 54 | 54 | ||
| 55 | 55 | /// Find a value in the list. Returns the node index if found, or nil. |
| 57 | 57 | let mut cur = list.head; |
|
| 58 | 58 | while let idx = cur { |
|
| 59 | 59 | if list.pool[idx].value == value { |
|
| 60 | 60 | return idx; |
|
| 61 | 61 | } |
|
| 62 | - | cur = list.pool[idx].next; |
|
| 62 | + | set cur = list.pool[idx].next; |
|
| 63 | 63 | } |
|
| 64 | 64 | return nil; |
|
| 65 | 65 | } |
|
| 66 | 66 | ||
| 67 | 67 | /// Get the value at a given index (0-based from head). |
| 70 | 70 | let mut i: u32 = 0; |
|
| 71 | 71 | while let idx = cur { |
|
| 72 | 72 | if i == index { |
|
| 73 | 73 | return list.pool[idx].value; |
|
| 74 | 74 | } |
|
| 75 | - | cur = list.pool[idx].next; |
|
| 76 | - | i += 1; |
|
| 75 | + | set cur = list.pool[idx].next; |
|
| 76 | + | set i += 1; |
|
| 77 | 77 | } |
|
| 78 | 78 | return nil; |
|
| 79 | 79 | } |
|
| 80 | 80 | ||
| 81 | 81 | /// Reverse the linked list in-place. |
|
| 82 | 82 | fn reverse(list: *mut List) { |
|
| 83 | 83 | let mut prev: ?u32 = nil; |
|
| 84 | 84 | let mut cur = list.head; |
|
| 85 | 85 | while let idx = cur { |
|
| 86 | 86 | let next = list.pool[idx].next; |
|
| 87 | - | list.pool[idx].next = prev; |
|
| 88 | - | prev = idx; |
|
| 89 | - | cur = next; |
|
| 87 | + | set list.pool[idx].next = prev; |
|
| 88 | + | set prev = idx; |
|
| 89 | + | set cur = next; |
|
| 90 | 90 | } |
|
| 91 | - | list.head = prev; |
|
| 91 | + | set list.head = prev; |
|
| 92 | 92 | } |
|
| 93 | 93 | ||
| 94 | 94 | /// Compute the sum of all values in the list. |
|
| 95 | 95 | fn sum(list: *List) -> i32 { |
|
| 96 | 96 | let mut total: i32 = 0; |
|
| 97 | 97 | let mut cur = list.head; |
|
| 98 | 98 | while let idx = cur { |
|
| 99 | - | total += list.pool[idx].value; |
|
| 100 | - | cur = list.pool[idx].next; |
|
| 99 | + | set total += list.pool[idx].value; |
|
| 100 | + | set cur = list.pool[idx].next; |
|
| 101 | 101 | } |
|
| 102 | 102 | return total; |
|
| 103 | 103 | } |
|
| 104 | 104 | ||
| 105 | 105 | /// Reset the list to empty. |
|
| 106 | 106 | fn reset(list: *mut List) { |
|
| 107 | - | list.head = nil; |
|
| 108 | - | list.free = 0; |
|
| 107 | + | set list.head = nil; |
|
| 108 | + | set list.free = 0; |
|
| 109 | 109 | } |
|
| 110 | 110 | ||
| 111 | 111 | /// Test basic push and length. |
|
| 112 | 112 | fn testPushLength(list: *mut List) -> i32 { |
|
| 113 | 113 | push(list, 10); |
| 200 | 200 | ||
| 201 | 201 | // Push 32 elements. |
|
| 202 | 202 | let mut i: u32 = 0; |
|
| 203 | 203 | while i < 32 { |
|
| 204 | 204 | push(list, i as i32 * 3); |
|
| 205 | - | i += 1; |
|
| 205 | + | set i += 1; |
|
| 206 | 206 | } |
|
| 207 | 207 | ||
| 208 | 208 | assert length(list) == 32; |
|
| 209 | 209 | ||
| 210 | 210 | // Sum should be 3 * (0 + 1 + ... + 31) = 3 * 496 = 1488 |
| 230 | 230 | let v = pop(list) else { |
|
| 231 | 231 | return 6; |
|
| 232 | 232 | }; |
|
| 233 | 233 | let expected = j as i32 * 3; |
|
| 234 | 234 | assert v == expected; |
|
| 235 | - | j += 1; |
|
| 235 | + | set j += 1; |
|
| 236 | 236 | } |
|
| 237 | 237 | ||
| 238 | 238 | assert length(list) == 0; |
|
| 239 | 239 | ||
| 240 | 240 | // Pop from empty list should return nil. |
test/tests/prog.lzw.rad
+38 -38
| 24 | 24 | decLen: u32, |
|
| 25 | 25 | temp: *mut [u8], |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | fn initEncDict(s: *mut LzwState) { |
|
| 29 | - | s.encDictSize = INIT_DICT; |
|
| 29 | + | set s.encDictSize = INIT_DICT; |
|
| 30 | 30 | let mut i: u32 = 0; |
|
| 31 | 31 | while i < 256 { |
|
| 32 | - | s.encDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 }; |
|
| 33 | - | i += 1; |
|
| 32 | + | set s.encDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 }; |
|
| 33 | + | set i += 1; |
|
| 34 | 34 | } |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | fn initDecDict(s: *mut LzwState) { |
|
| 38 | - | s.decDictSize = INIT_DICT; |
|
| 38 | + | set s.decDictSize = INIT_DICT; |
|
| 39 | 39 | let mut i: u32 = 0; |
|
| 40 | 40 | while i < 256 { |
|
| 41 | - | s.decDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 }; |
|
| 42 | - | i += 1; |
|
| 41 | + | set s.decDict[i] = DictEntry { prefix: 0xFFFF, suffix: i as u8 }; |
|
| 42 | + | set i += 1; |
|
| 43 | 43 | } |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | fn dictLookup(s: *LzwState, prefix: u32, suffix: u8) -> u32 { |
|
| 47 | 47 | let mut i: u32 = 0; |
|
| 48 | 48 | while i < s.encDictSize { |
|
| 49 | 49 | if s.encDict[i].prefix == prefix and s.encDict[i].suffix == suffix { |
|
| 50 | 50 | return i; |
|
| 51 | 51 | } |
|
| 52 | - | i += 1; |
|
| 52 | + | set i += 1; |
|
| 53 | 53 | } |
|
| 54 | 54 | return 0xFFFFFFFF; |
|
| 55 | 55 | } |
|
| 56 | 56 | ||
| 57 | 57 | fn dictAdd(s: *mut LzwState, prefix: u32, suffix: u8) { |
|
| 58 | 58 | if s.encDictSize < MAX_DICT { |
|
| 59 | - | s.encDict[s.encDictSize] = DictEntry { prefix, suffix }; |
|
| 60 | - | s.encDictSize += 1; |
|
| 59 | + | set s.encDict[s.encDictSize] = DictEntry { prefix, suffix }; |
|
| 60 | + | set s.encDictSize += 1; |
|
| 61 | 61 | } |
|
| 62 | 62 | } |
|
| 63 | 63 | ||
| 64 | 64 | fn emitCode(s: *mut LzwState, code: u32) { |
|
| 65 | - | s.encoded[s.encLen] = code; |
|
| 66 | - | s.encLen += 1; |
|
| 65 | + | set s.encoded[s.encLen] = code; |
|
| 66 | + | set s.encLen += 1; |
|
| 67 | 67 | } |
|
| 68 | 68 | ||
| 69 | 69 | fn encode(s: *mut LzwState, data: *[u8]) { |
|
| 70 | 70 | initEncDict(s); |
|
| 71 | - | s.encLen = 0; |
|
| 71 | + | set s.encLen = 0; |
|
| 72 | 72 | ||
| 73 | 73 | if data.len == 0 { |
|
| 74 | 74 | emitCode(s, EOI_CODE); |
|
| 75 | 75 | return; |
|
| 76 | 76 | } |
| 80 | 80 | ||
| 81 | 81 | while i < data.len { |
|
| 82 | 82 | let c: u8 = data[i]; |
|
| 83 | 83 | let wc: u32 = dictLookup(s, w, c); |
|
| 84 | 84 | if wc <> 0xFFFFFFFF { |
|
| 85 | - | w = wc; |
|
| 85 | + | set w = wc; |
|
| 86 | 86 | } else { |
|
| 87 | 87 | emitCode(s, w); |
|
| 88 | 88 | dictAdd(s, w, c); |
|
| 89 | - | w = c as u32; |
|
| 89 | + | set w = c as u32; |
|
| 90 | 90 | } |
|
| 91 | - | i += 1; |
|
| 91 | + | set i += 1; |
|
| 92 | 92 | } |
|
| 93 | 93 | emitCode(s, w); |
|
| 94 | 94 | emitCode(s, EOI_CODE); |
|
| 95 | 95 | } |
|
| 96 | 96 | ||
| 97 | 97 | fn decodeString(s: *mut LzwState, code: u32) -> u32 { |
|
| 98 | 98 | let mut len: u32 = 0; |
|
| 99 | 99 | let mut c: u32 = code; |
|
| 100 | 100 | while c <> 0xFFFF and c < s.decDictSize { |
|
| 101 | - | s.temp[len] = s.decDict[c].suffix; |
|
| 102 | - | len += 1; |
|
| 103 | - | c = s.decDict[c].prefix; |
|
| 101 | + | set s.temp[len] = s.decDict[c].suffix; |
|
| 102 | + | set len += 1; |
|
| 103 | + | set c = s.decDict[c].prefix; |
|
| 104 | 104 | } |
|
| 105 | 105 | let mut a: u32 = 0; |
|
| 106 | 106 | let mut b: u32 = len - 1; |
|
| 107 | 107 | while a < b { |
|
| 108 | 108 | let tmp: u8 = s.temp[a]; |
|
| 109 | - | s.temp[a] = s.temp[b]; |
|
| 110 | - | s.temp[b] = tmp; |
|
| 111 | - | a += 1; |
|
| 112 | - | b -= 1; |
|
| 109 | + | set s.temp[a] = s.temp[b]; |
|
| 110 | + | set s.temp[b] = tmp; |
|
| 111 | + | set a += 1; |
|
| 112 | + | set b -= 1; |
|
| 113 | 113 | } |
|
| 114 | 114 | return len; |
|
| 115 | 115 | } |
|
| 116 | 116 | ||
| 117 | 117 | fn firstByte(s: *LzwState, code: u32) -> u8 { |
|
| 118 | 118 | let mut c: u32 = code; |
|
| 119 | 119 | while s.decDict[c].prefix <> 0xFFFF and s.decDict[c].prefix < s.decDictSize { |
|
| 120 | - | c = s.decDict[c].prefix; |
|
| 120 | + | set c = s.decDict[c].prefix; |
|
| 121 | 121 | } |
|
| 122 | 122 | return s.decDict[c].suffix; |
|
| 123 | 123 | } |
|
| 124 | 124 | ||
| 125 | 125 | fn decDictAdd(s: *mut LzwState, prefix: u32, suffix: u8) { |
|
| 126 | 126 | if s.decDictSize < MAX_DICT { |
|
| 127 | - | s.decDict[s.decDictSize] = DictEntry { prefix, suffix }; |
|
| 128 | - | s.decDictSize += 1; |
|
| 127 | + | set s.decDict[s.decDictSize] = DictEntry { prefix, suffix }; |
|
| 128 | + | set s.decDictSize += 1; |
|
| 129 | 129 | } |
|
| 130 | 130 | } |
|
| 131 | 131 | ||
| 132 | 132 | fn outputByte(s: *mut LzwState, b: u8) { |
|
| 133 | - | s.decoded[s.decLen] = b; |
|
| 134 | - | s.decLen += 1; |
|
| 133 | + | set s.decoded[s.decLen] = b; |
|
| 134 | + | set s.decLen += 1; |
|
| 135 | 135 | } |
|
| 136 | 136 | ||
| 137 | 137 | fn decode(s: *mut LzwState) { |
|
| 138 | 138 | initDecDict(s); |
|
| 139 | - | s.decLen = 0; |
|
| 139 | + | set s.decLen = 0; |
|
| 140 | 140 | ||
| 141 | 141 | if s.encLen == 0 { |
|
| 142 | 142 | return; |
|
| 143 | 143 | } |
|
| 144 | 144 | ||
| 145 | 145 | let mut pos: u32 = 0; |
|
| 146 | 146 | let mut code: u32 = s.encoded[pos]; |
|
| 147 | - | pos += 1; |
|
| 147 | + | set pos += 1; |
|
| 148 | 148 | ||
| 149 | 149 | if code == EOI_CODE { |
|
| 150 | 150 | return; |
|
| 151 | 151 | } |
|
| 152 | 152 | ||
| 153 | 153 | outputByte(s, code as u8); |
|
| 154 | 154 | let mut prevCode: u32 = code; |
|
| 155 | 155 | ||
| 156 | 156 | while pos < s.encLen { |
|
| 157 | - | code = s.encoded[pos]; |
|
| 158 | - | pos += 1; |
|
| 157 | + | set code = s.encoded[pos]; |
|
| 158 | + | set pos += 1; |
|
| 159 | 159 | ||
| 160 | 160 | if code == EOI_CODE { |
|
| 161 | 161 | return; |
|
| 162 | 162 | } |
|
| 163 | 163 | ||
| 164 | 164 | if code < s.decDictSize { |
|
| 165 | 165 | let len: u32 = decodeString(s, code); |
|
| 166 | 166 | let mut i: u32 = 0; |
|
| 167 | 167 | while i < len { |
|
| 168 | 168 | outputByte(s, s.temp[i]); |
|
| 169 | - | i += 1; |
|
| 169 | + | set i += 1; |
|
| 170 | 170 | } |
|
| 171 | 171 | decDictAdd(s, prevCode, s.temp[0]); |
|
| 172 | 172 | } else { |
|
| 173 | 173 | let fb: u8 = firstByte(s, prevCode); |
|
| 174 | 174 | let len: u32 = decodeString(s, prevCode); |
|
| 175 | 175 | let mut i: u32 = 0; |
|
| 176 | 176 | while i < len { |
|
| 177 | 177 | outputByte(s, s.temp[i]); |
|
| 178 | - | i += 1; |
|
| 178 | + | set i += 1; |
|
| 179 | 179 | } |
|
| 180 | 180 | outputByte(s, fb); |
|
| 181 | 181 | decDictAdd(s, prevCode, fb); |
|
| 182 | 182 | } |
|
| 183 | - | prevCode = code; |
|
| 183 | + | set prevCode = code; |
|
| 184 | 184 | } |
|
| 185 | 185 | } |
|
| 186 | 186 | ||
| 187 | 187 | fn testSimple(s: *mut LzwState) -> i32 { |
|
| 188 | 188 | let data: *[u8] = "ABABABABAB"; |
| 193 | 193 | decode(s); |
|
| 194 | 194 | assert s.decLen == 10; |
|
| 195 | 195 | let mut i: u32 = 0; |
|
| 196 | 196 | while i < 10 { |
|
| 197 | 197 | assert s.decoded[i] == data[i]; |
|
| 198 | - | i += 1; |
|
| 198 | + | set i += 1; |
|
| 199 | 199 | } |
|
| 200 | 200 | return 0; |
|
| 201 | 201 | } |
|
| 202 | 202 | ||
| 203 | 203 | fn testDistinct(s: *mut LzwState) -> i32 { |
| 207 | 207 | decode(s); |
|
| 208 | 208 | assert s.decLen == 16; |
|
| 209 | 209 | let mut i: u32 = 0; |
|
| 210 | 210 | while i < 16 { |
|
| 211 | 211 | assert s.decoded[i] == data[i]; |
|
| 212 | - | i += 1; |
|
| 212 | + | set i += 1; |
|
| 213 | 213 | } |
|
| 214 | 214 | return 0; |
|
| 215 | 215 | } |
|
| 216 | 216 | ||
| 217 | 217 | fn testRepetitive(s: *mut LzwState) -> i32 { |
| 223 | 223 | decode(s); |
|
| 224 | 224 | assert s.decLen == 64; |
|
| 225 | 225 | let mut i: u32 = 0; |
|
| 226 | 226 | while i < 64 { |
|
| 227 | 227 | assert s.decoded[i] == 65; |
|
| 228 | - | i += 1; |
|
| 228 | + | set i += 1; |
|
| 229 | 229 | } |
|
| 230 | 230 | return 0; |
|
| 231 | 231 | } |
|
| 232 | 232 | ||
| 233 | 233 | fn testMixed(s: *mut LzwState) -> i32 { |
| 237 | 237 | decode(s); |
|
| 238 | 238 | assert s.decLen == 24; |
|
| 239 | 239 | let mut i: u32 = 0; |
|
| 240 | 240 | while i < 24 { |
|
| 241 | 241 | assert s.decoded[i] == data[i]; |
|
| 242 | - | i += 1; |
|
| 242 | + | set i += 1; |
|
| 243 | 243 | } |
|
| 244 | 244 | ||
| 245 | 245 | assert s.encLen - 1 < 24; |
|
| 246 | 246 | ||
| 247 | 247 | return 0; |
test/tests/prog.matmul.rad
+12 -12
| 17 | 17 | let mut j: u32 = 0; |
|
| 18 | 18 | while j < N { |
|
| 19 | 19 | let mut sum: i32 = 0; |
|
| 20 | 20 | let mut k: u32 = 0; |
|
| 21 | 21 | while k < N { |
|
| 22 | - | sum += a.rows[i][k] * b.rows[k][j]; |
|
| 23 | - | k += 1; |
|
| 22 | + | set sum += a.rows[i][k] * b.rows[k][j]; |
|
| 23 | + | set k += 1; |
|
| 24 | 24 | } |
|
| 25 | - | c.rows[i][j] = sum; |
|
| 26 | - | j += 1; |
|
| 25 | + | set c.rows[i][j] = sum; |
|
| 26 | + | set j += 1; |
|
| 27 | 27 | } |
|
| 28 | - | i += 1; |
|
| 28 | + | set i += 1; |
|
| 29 | 29 | } |
|
| 30 | 30 | } |
|
| 31 | 31 | ||
| 32 | 32 | /// Verify c matches expected. |
|
| 33 | 33 | fn verifyResult(c: *Mat4, expected: *Mat4) -> i32 { |
| 36 | 36 | let mut j: u32 = 0; |
|
| 37 | 37 | while j < N { |
|
| 38 | 38 | if c.rows[i][j] <> expected.rows[i][j] { |
|
| 39 | 39 | return (i * N + j) as i32 + 1; |
|
| 40 | 40 | } |
|
| 41 | - | j += 1; |
|
| 41 | + | set j += 1; |
|
| 42 | 42 | } |
|
| 43 | - | i += 1; |
|
| 43 | + | set i += 1; |
|
| 44 | 44 | } |
|
| 45 | 45 | return 0; |
|
| 46 | 46 | } |
|
| 47 | 47 | ||
| 48 | 48 | /// Compute the trace (sum of diagonal) of a matrix. |
|
| 49 | 49 | fn trace(m: *Mat4) -> i32 { |
|
| 50 | 50 | let mut sum: i32 = 0; |
|
| 51 | 51 | let mut i: u32 = 0; |
|
| 52 | 52 | while i < N { |
|
| 53 | - | sum += m.rows[i][i]; |
|
| 54 | - | i += 1; |
|
| 53 | + | set sum += m.rows[i][i]; |
|
| 54 | + | set i += 1; |
|
| 55 | 55 | } |
|
| 56 | 56 | return sum; |
|
| 57 | 57 | } |
|
| 58 | 58 | ||
| 59 | 59 | /// Zero out a matrix. |
|
| 60 | 60 | fn zero(m: *mut Mat4) { |
|
| 61 | 61 | let mut i: u32 = 0; |
|
| 62 | 62 | while i < N { |
|
| 63 | 63 | let mut j: u32 = 0; |
|
| 64 | 64 | while j < N { |
|
| 65 | - | m.rows[i][j] = 0; |
|
| 66 | - | j += 1; |
|
| 65 | + | set m.rows[i][j] = 0; |
|
| 66 | + | set j += 1; |
|
| 67 | 67 | } |
|
| 68 | - | i += 1; |
|
| 68 | + | set i += 1; |
|
| 69 | 69 | } |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | /// Multiply matrices multiple times to test repeated computation. |
|
| 73 | 73 | fn testRepeatedMultiply(c: *mut Mat4, a: *Mat4, b: *Mat4) -> i32 { |
test/tests/prog.mersenne.rad
+41 -41
| 11 | 11 | mt: *mut [u32], |
|
| 12 | 12 | mti: u32, |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | fn mtInit(s: *mut MtState, seed: u32) { |
|
| 16 | - | s.mt[0] = seed; |
|
| 16 | + | set s.mt[0] = seed; |
|
| 17 | 17 | let mut i: u32 = 1; |
|
| 18 | 18 | while i < N { |
|
| 19 | 19 | let prev: u32 = s.mt[i - 1]; |
|
| 20 | 20 | let xored: u32 = prev ^ (prev >> 30); |
|
| 21 | 21 |
| 28 | 28 | let ll: u32 = clo * lo; |
|
| 29 | 29 | let lh: u32 = clo * hi; |
|
| 30 | 30 | let hl: u32 = chi * lo; |
|
| 31 | 31 | ||
| 32 | 32 | let result: u32 = ll + ((lh + hl) << 16) + i; |
|
| 33 | - | s.mt[i] = result; |
|
| 34 | - | i += 1; |
|
| 33 | + | set s.mt[i] = result; |
|
| 34 | + | set i += 1; |
|
| 35 | 35 | } |
|
| 36 | - | s.mti = N; |
|
| 36 | + | set s.mti = N; |
|
| 37 | 37 | } |
|
| 38 | 38 | ||
| 39 | 39 | fn generateNumbers(s: *mut MtState) { |
|
| 40 | 40 | let mut i: u32 = 0; |
|
| 41 | 41 | ||
| 42 | 42 | while i < N - M { |
|
| 43 | 43 | let y: u32 = (s.mt[i] & UPPER_MASK) | (s.mt[i + 1] & LOWER_MASK); |
|
| 44 | 44 | let mut mag: u32 = 0; |
|
| 45 | 45 | if y & 1 == 1 { |
|
| 46 | - | mag = MATRIX_A; |
|
| 46 | + | set mag = MATRIX_A; |
|
| 47 | 47 | } |
|
| 48 | - | s.mt[i] = s.mt[i + M] ^ (y >> 1) ^ mag; |
|
| 49 | - | i += 1; |
|
| 48 | + | set s.mt[i] = s.mt[i + M] ^ (y >> 1) ^ mag; |
|
| 49 | + | set i += 1; |
|
| 50 | 50 | } |
|
| 51 | 51 | ||
| 52 | 52 | while i < N - 1 { |
|
| 53 | 53 | let y: u32 = (s.mt[i] & UPPER_MASK) | (s.mt[i + 1] & LOWER_MASK); |
|
| 54 | 54 | let mut mag: u32 = 0; |
|
| 55 | 55 | if y & 1 == 1 { |
|
| 56 | - | mag = MATRIX_A; |
|
| 56 | + | set mag = MATRIX_A; |
|
| 57 | 57 | } |
|
| 58 | - | s.mt[i] = s.mt[i + M - N] ^ (y >> 1) ^ mag; |
|
| 59 | - | i += 1; |
|
| 58 | + | set s.mt[i] = s.mt[i + M - N] ^ (y >> 1) ^ mag; |
|
| 59 | + | set i += 1; |
|
| 60 | 60 | } |
|
| 61 | 61 | ||
| 62 | 62 | let y: u32 = (s.mt[N - 1] & UPPER_MASK) | (s.mt[0] & LOWER_MASK); |
|
| 63 | 63 | let mut mag: u32 = 0; |
|
| 64 | 64 | if y & 1 == 1 { |
|
| 65 | - | mag = MATRIX_A; |
|
| 65 | + | set mag = MATRIX_A; |
|
| 66 | 66 | } |
|
| 67 | - | s.mt[N - 1] = s.mt[M - 1] ^ (y >> 1) ^ mag; |
|
| 67 | + | set s.mt[N - 1] = s.mt[M - 1] ^ (y >> 1) ^ mag; |
|
| 68 | 68 | ||
| 69 | - | s.mti = 0; |
|
| 69 | + | set s.mti = 0; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | fn mtNext(s: *mut MtState) -> u32 { |
|
| 73 | 73 | if s.mti >= N { |
|
| 74 | 74 | generateNumbers(s); |
|
| 75 | 75 | } |
|
| 76 | 76 | ||
| 77 | 77 | let mut y: u32 = s.mt[s.mti]; |
|
| 78 | - | s.mti += 1; |
|
| 78 | + | set s.mti += 1; |
|
| 79 | 79 | ||
| 80 | - | y ^= (y >> 11); |
|
| 81 | - | y ^= ((y << 7) & 0x9D2C5680); |
|
| 82 | - | y ^= ((y << 15) & 0xEFC60000); |
|
| 83 | - | y ^= (y >> 18); |
|
| 80 | + | set y ^= (y >> 11); |
|
| 81 | + | set y ^= ((y << 7) & 0x9D2C5680); |
|
| 82 | + | set y ^= ((y << 15) & 0xEFC60000); |
|
| 83 | + | set y ^= (y >> 18); |
|
| 84 | 84 | ||
| 85 | 85 | return y; |
|
| 86 | 86 | } |
|
| 87 | 87 | ||
| 88 | 88 | fn testKnownSequence(s: *mut MtState) -> i32 { |
| 110 | 110 | mtInit(s, 42); |
|
| 111 | 111 | ||
| 112 | 112 | let mut first: [u32; 10] = [0; 10]; |
|
| 113 | 113 | let mut i: u32 = 0; |
|
| 114 | 114 | while i < 10 { |
|
| 115 | - | first[i] = mtNext(s); |
|
| 116 | - | i += 1; |
|
| 115 | + | set first[i] = mtNext(s); |
|
| 116 | + | set i += 1; |
|
| 117 | 117 | } |
|
| 118 | 118 | ||
| 119 | 119 | mtInit(s, 42); |
|
| 120 | 120 | ||
| 121 | - | i = 0; |
|
| 121 | + | set i = 0; |
|
| 122 | 122 | while i < 10 { |
|
| 123 | 123 | let v: u32 = mtNext(s); |
|
| 124 | 124 | if v <> first[i] { return i as i32 + 1; } |
|
| 125 | - | i += 1; |
|
| 125 | + | set i += 1; |
|
| 126 | 126 | } |
|
| 127 | 127 | ||
| 128 | 128 | return 0; |
|
| 129 | 129 | } |
|
| 130 | 130 |
| 156 | 156 | ||
| 157 | 157 | let mut i: u32 = 0; |
|
| 158 | 158 | while i < NUM_SAMPLES { |
|
| 159 | 159 | let val: u32 = mtNext(s); |
|
| 160 | 160 | let bin: u32 = val >> 28; |
|
| 161 | - | bins[bin] += 1; |
|
| 162 | - | i += 1; |
|
| 161 | + | set bins[bin] += 1; |
|
| 162 | + | set i += 1; |
|
| 163 | 163 | } |
|
| 164 | 164 | ||
| 165 | 165 | let mut chi2Scaled: u32 = 0; |
|
| 166 | 166 | let mut b: u32 = 0; |
|
| 167 | 167 | while b < NUM_BINS { |
|
| 168 | 168 | let obs: i32 = bins[b] as i32; |
|
| 169 | 169 | let exp: i32 = EXPECTED as i32; |
|
| 170 | 170 | let diff: i32 = obs - exp; |
|
| 171 | - | chi2Scaled += (diff * diff) as u32; |
|
| 172 | - | b += 1; |
|
| 171 | + | set chi2Scaled += (diff * diff) as u32; |
|
| 172 | + | set b += 1; |
|
| 173 | 173 | } |
|
| 174 | 174 | ||
| 175 | 175 | assert chi2Scaled <= 5000; |
|
| 176 | 176 | ||
| 177 | - | b = 0; |
|
| 177 | + | set b = 0; |
|
| 178 | 178 | while b < NUM_BINS { |
|
| 179 | 179 | assert bins[b] <> 0; |
|
| 180 | - | b += 1; |
|
| 180 | + | set b += 1; |
|
| 181 | 181 | } |
|
| 182 | 182 | ||
| 183 | - | b = 0; |
|
| 183 | + | set b = 0; |
|
| 184 | 184 | while b < NUM_BINS { |
|
| 185 | 185 | assert bins[b] <= NUM_SAMPLES / 2; |
|
| 186 | - | b += 1; |
|
| 186 | + | set b += 1; |
|
| 187 | 187 | } |
|
| 188 | 188 | ||
| 189 | 189 | return 0; |
|
| 190 | 190 | } |
|
| 191 | 191 |
| 193 | 193 | mtInit(s, 7); |
|
| 194 | 194 | ||
| 195 | 195 | let mut last: u32 = 0; |
|
| 196 | 196 | let mut i: u32 = 0; |
|
| 197 | 197 | while i < 700 { |
|
| 198 | - | last = mtNext(s); |
|
| 199 | - | i += 1; |
|
| 198 | + | set last = mtNext(s); |
|
| 199 | + | set i += 1; |
|
| 200 | 200 | } |
|
| 201 | 201 | ||
| 202 | 202 | mtInit(s, 7); |
|
| 203 | 203 | let mut last2: u32 = 0; |
|
| 204 | - | i = 0; |
|
| 204 | + | set i = 0; |
|
| 205 | 205 | while i < 700 { |
|
| 206 | - | last2 = mtNext(s); |
|
| 207 | - | i += 1; |
|
| 206 | + | set last2 = mtNext(s); |
|
| 207 | + | set i += 1; |
|
| 208 | 208 | } |
|
| 209 | 209 | ||
| 210 | 210 | assert last == last2; |
|
| 211 | 211 | ||
| 212 | 212 | let mut more: u32 = 0; |
|
| 213 | - | i = 0; |
|
| 213 | + | set i = 0; |
|
| 214 | 214 | while i < 700 { |
|
| 215 | - | more = mtNext(s); |
|
| 216 | - | i += 1; |
|
| 215 | + | set more = mtNext(s); |
|
| 216 | + | set i += 1; |
|
| 217 | 217 | } |
|
| 218 | 218 | assert more <> 0; |
|
| 219 | 219 | ||
| 220 | 220 | return 0; |
|
| 221 | 221 | } |
| 227 | 227 | let mut andAll: u32 = 0xFFFFFFFF; |
|
| 228 | 228 | ||
| 229 | 229 | let mut i: u32 = 0; |
|
| 230 | 230 | while i < 200 { |
|
| 231 | 231 | let v: u32 = mtNext(s); |
|
| 232 | - | orAll |= v; |
|
| 233 | - | andAll &= v; |
|
| 234 | - | i += 1; |
|
| 232 | + | set orAll |= v; |
|
| 233 | + | set andAll &= v; |
|
| 234 | + | set i += 1; |
|
| 235 | 235 | } |
|
| 236 | 236 | ||
| 237 | 237 | assert orAll == 0xFFFFFFFF; |
|
| 238 | 238 | assert andAll <> 0xFFFFFFFF; |
|
| 239 | 239 | assert andAll == 0; |
test/tests/prog.nqueens.rad
+15 -15
| 21 | 21 | let rowDiff: i32 = row as i32 - i as i32; |
|
| 22 | 22 | let colDiff: i32 = col as i32 - qcol; |
|
| 23 | 23 | if colDiff == rowDiff or colDiff == 0 - rowDiff { |
|
| 24 | 24 | return false; |
|
| 25 | 25 | } |
|
| 26 | - | i += 1; |
|
| 26 | + | set i += 1; |
|
| 27 | 27 | } |
|
| 28 | 28 | return true; |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | fn solve(b: *mut Board, row: u32) { |
|
| 32 | 32 | if row == b.boardSize { |
|
| 33 | - | b.solutionCount += 1; |
|
| 33 | + | set b.solutionCount += 1; |
|
| 34 | 34 | return; |
|
| 35 | 35 | } |
|
| 36 | 36 | let mut col: u32 = 0; |
|
| 37 | 37 | while col < b.boardSize { |
|
| 38 | 38 | if isSafe(b, row, col) { |
|
| 39 | - | b.queens[row] = col as i32; |
|
| 39 | + | set b.queens[row] = col as i32; |
|
| 40 | 40 | solve(b, row + 1); |
|
| 41 | - | b.queens[row] = -1; |
|
| 41 | + | set b.queens[row] = -1; |
|
| 42 | 42 | } |
|
| 43 | - | col += 1; |
|
| 43 | + | set col += 1; |
|
| 44 | 44 | } |
|
| 45 | 45 | } |
|
| 46 | 46 | ||
| 47 | 47 | fn resetBoard(b: *mut Board) { |
|
| 48 | 48 | let mut i: u32 = 0; |
|
| 49 | 49 | while i < MAX_N { |
|
| 50 | - | b.queens[i] = -1; |
|
| 51 | - | i += 1; |
|
| 50 | + | set b.queens[i] = -1; |
|
| 51 | + | set i += 1; |
|
| 52 | 52 | } |
|
| 53 | - | b.solutionCount = 0; |
|
| 53 | + | set b.solutionCount = 0; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | fn solveNQueens(b: *mut Board, n: u32) -> u32 { |
|
| 57 | 57 | resetBoard(b); |
|
| 58 | - | b.boardSize = n; |
|
| 58 | + | set b.boardSize = n; |
|
| 59 | 59 | solve(b, 0); |
|
| 60 | 60 | return b.solutionCount; |
|
| 61 | 61 | } |
|
| 62 | 62 | ||
| 63 | 63 | fn testAllSizes(b: *mut Board) -> i32 { |
| 66 | 66 | while n <= 8 { |
|
| 67 | 67 | let count: u32 = solveNQueens(b, n); |
|
| 68 | 68 | if count <> expected[n] { |
|
| 69 | 69 | return n as i32; |
|
| 70 | 70 | } |
|
| 71 | - | n += 1; |
|
| 71 | + | set n += 1; |
|
| 72 | 72 | } |
|
| 73 | 73 | return 0; |
|
| 74 | 74 | } |
|
| 75 | 75 | ||
| 76 | 76 | fn testKnownSolution() -> i32 { |
| 82 | 82 | while j < 8 { |
|
| 83 | 83 | assert solution[i] <> solution[j]; |
|
| 84 | 84 | let rowDiff: i32 = j as i32 - i as i32; |
|
| 85 | 85 | let colDiff: i32 = solution[j] - solution[i]; |
|
| 86 | 86 | assert colDiff <> rowDiff and colDiff <> 0 - rowDiff; |
|
| 87 | - | j += 1; |
|
| 87 | + | set j += 1; |
|
| 88 | 88 | } |
|
| 89 | - | i += 1; |
|
| 89 | + | set i += 1; |
|
| 90 | 90 | } |
|
| 91 | 91 | ||
| 92 | 92 | let mut used: [bool; 8] = [false; 8]; |
|
| 93 | 93 | let mut k: u32 = 0; |
|
| 94 | 94 | while k < 8 { |
|
| 95 | 95 | let col: u32 = solution[k] as u32; |
|
| 96 | 96 | if used[col] { |
|
| 97 | 97 | return 3; |
|
| 98 | 98 | } |
|
| 99 | - | used[col] = true; |
|
| 100 | - | k += 1; |
|
| 99 | + | set used[col] = true; |
|
| 100 | + | set k += 1; |
|
| 101 | 101 | } |
|
| 102 | 102 | ||
| 103 | 103 | return 0; |
|
| 104 | 104 | } |
|
| 105 | 105 |
| 118 | 118 | let expected: [u32; 9] = [0, 1, 0, 0, 2, 10, 4, 40, 92]; |
|
| 119 | 119 | ||
| 120 | 120 | let mut n: u32 = 4; |
|
| 121 | 121 | while n <= 8 { |
|
| 122 | 122 | assert expected[n] <> 0; |
|
| 123 | - | n += 1; |
|
| 123 | + | set n += 1; |
|
| 124 | 124 | } |
|
| 125 | 125 | ||
| 126 | 126 | assert expected[2] == 0; |
|
| 127 | 127 | assert expected[3] == 0; |
|
| 128 | 128 | assert expected[7] > expected[6]; |
test/tests/prog.rbtree.rad
+62 -62
| 24 | 24 | inorderCount: u32, |
|
| 25 | 25 | } |
|
| 26 | 26 | ||
| 27 | 27 | fn allocNode(t: *mut RBTree, key: i32) -> u32 { |
|
| 28 | 28 | let idx: u32 = t.poolNext; |
|
| 29 | - | t.poolNext += 1; |
|
| 30 | - | t.pool[idx] = RBNode { key, color: RED, left: NIL, right: NIL, parent: NIL }; |
|
| 29 | + | set t.poolNext += 1; |
|
| 30 | + | set t.pool[idx] = RBNode { key, color: RED, left: NIL, right: NIL, parent: NIL }; |
|
| 31 | 31 | return idx; |
|
| 32 | 32 | } |
|
| 33 | 33 | ||
| 34 | 34 | fn rotateLeft(t: *mut RBTree, x: u32) { |
|
| 35 | 35 | let y: u32 = t.pool[x].right; |
|
| 36 | - | t.pool[x].right = t.pool[y].left; |
|
| 36 | + | set t.pool[x].right = t.pool[y].left; |
|
| 37 | 37 | if t.pool[y].left <> NIL { |
|
| 38 | - | t.pool[t.pool[y].left].parent = x; |
|
| 38 | + | set t.pool[t.pool[y].left].parent = x; |
|
| 39 | 39 | } |
|
| 40 | - | t.pool[y].parent = t.pool[x].parent; |
|
| 40 | + | set t.pool[y].parent = t.pool[x].parent; |
|
| 41 | 41 | if t.pool[x].parent == NIL { |
|
| 42 | - | t.root = y; |
|
| 42 | + | set t.root = y; |
|
| 43 | 43 | } else if x == t.pool[t.pool[x].parent].left { |
|
| 44 | - | t.pool[t.pool[x].parent].left = y; |
|
| 44 | + | set t.pool[t.pool[x].parent].left = y; |
|
| 45 | 45 | } else { |
|
| 46 | - | t.pool[t.pool[x].parent].right = y; |
|
| 46 | + | set t.pool[t.pool[x].parent].right = y; |
|
| 47 | 47 | } |
|
| 48 | - | t.pool[y].left = x; |
|
| 49 | - | t.pool[x].parent = y; |
|
| 48 | + | set t.pool[y].left = x; |
|
| 49 | + | set t.pool[x].parent = y; |
|
| 50 | 50 | } |
|
| 51 | 51 | ||
| 52 | 52 | fn rotateRight(t: *mut RBTree, x: u32) { |
|
| 53 | 53 | let y: u32 = t.pool[x].left; |
|
| 54 | - | t.pool[x].left = t.pool[y].right; |
|
| 54 | + | set t.pool[x].left = t.pool[y].right; |
|
| 55 | 55 | if t.pool[y].right <> NIL { |
|
| 56 | - | t.pool[t.pool[y].right].parent = x; |
|
| 56 | + | set t.pool[t.pool[y].right].parent = x; |
|
| 57 | 57 | } |
|
| 58 | - | t.pool[y].parent = t.pool[x].parent; |
|
| 58 | + | set t.pool[y].parent = t.pool[x].parent; |
|
| 59 | 59 | if t.pool[x].parent == NIL { |
|
| 60 | - | t.root = y; |
|
| 60 | + | set t.root = y; |
|
| 61 | 61 | } else if x == t.pool[t.pool[x].parent].right { |
|
| 62 | - | t.pool[t.pool[x].parent].right = y; |
|
| 62 | + | set t.pool[t.pool[x].parent].right = y; |
|
| 63 | 63 | } else { |
|
| 64 | - | t.pool[t.pool[x].parent].left = y; |
|
| 64 | + | set t.pool[t.pool[x].parent].left = y; |
|
| 65 | 65 | } |
|
| 66 | - | t.pool[y].right = x; |
|
| 67 | - | t.pool[x].parent = y; |
|
| 66 | + | set t.pool[y].right = x; |
|
| 67 | + | set t.pool[x].parent = y; |
|
| 68 | 68 | } |
|
| 69 | 69 | ||
| 70 | 70 | fn insertFixup(t: *mut RBTree, zArg: u32) { |
|
| 71 | 71 | let mut z: u32 = zArg; |
|
| 72 | 72 | while t.pool[t.pool[z].parent].color == RED { |
|
| 73 | 73 | if t.pool[z].parent == t.pool[t.pool[t.pool[z].parent].parent].left { |
|
| 74 | 74 | let y: u32 = t.pool[t.pool[t.pool[z].parent].parent].right; |
|
| 75 | 75 | if t.pool[y].color == RED { |
|
| 76 | - | t.pool[t.pool[z].parent].color = BLACK; |
|
| 77 | - | t.pool[y].color = BLACK; |
|
| 78 | - | t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 79 | - | z = t.pool[t.pool[z].parent].parent; |
|
| 76 | + | set t.pool[t.pool[z].parent].color = BLACK; |
|
| 77 | + | set t.pool[y].color = BLACK; |
|
| 78 | + | set t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 79 | + | set z = t.pool[t.pool[z].parent].parent; |
|
| 80 | 80 | } else { |
|
| 81 | 81 | if z == t.pool[t.pool[z].parent].right { |
|
| 82 | - | z = t.pool[z].parent; |
|
| 82 | + | set z = t.pool[z].parent; |
|
| 83 | 83 | rotateLeft(t, z); |
|
| 84 | 84 | } |
|
| 85 | - | t.pool[t.pool[z].parent].color = BLACK; |
|
| 86 | - | t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 85 | + | set t.pool[t.pool[z].parent].color = BLACK; |
|
| 86 | + | set t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 87 | 87 | rotateRight(t, t.pool[t.pool[z].parent].parent); |
|
| 88 | 88 | } |
|
| 89 | 89 | } else { |
|
| 90 | 90 | let y: u32 = t.pool[t.pool[t.pool[z].parent].parent].left; |
|
| 91 | 91 | if t.pool[y].color == RED { |
|
| 92 | - | t.pool[t.pool[z].parent].color = BLACK; |
|
| 93 | - | t.pool[y].color = BLACK; |
|
| 94 | - | t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 95 | - | z = t.pool[t.pool[z].parent].parent; |
|
| 92 | + | set t.pool[t.pool[z].parent].color = BLACK; |
|
| 93 | + | set t.pool[y].color = BLACK; |
|
| 94 | + | set t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 95 | + | set z = t.pool[t.pool[z].parent].parent; |
|
| 96 | 96 | } else { |
|
| 97 | 97 | if z == t.pool[t.pool[z].parent].left { |
|
| 98 | - | z = t.pool[z].parent; |
|
| 98 | + | set z = t.pool[z].parent; |
|
| 99 | 99 | rotateRight(t, z); |
|
| 100 | 100 | } |
|
| 101 | - | t.pool[t.pool[z].parent].color = BLACK; |
|
| 102 | - | t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 101 | + | set t.pool[t.pool[z].parent].color = BLACK; |
|
| 102 | + | set t.pool[t.pool[t.pool[z].parent].parent].color = RED; |
|
| 103 | 103 | rotateLeft(t, t.pool[t.pool[z].parent].parent); |
|
| 104 | 104 | } |
|
| 105 | 105 | } |
|
| 106 | 106 | } |
|
| 107 | - | t.pool[t.root].color = BLACK; |
|
| 107 | + | set t.pool[t.root].color = BLACK; |
|
| 108 | 108 | } |
|
| 109 | 109 | ||
| 110 | 110 | fn insert(t: *mut RBTree, key: i32) { |
|
| 111 | 111 | let z: u32 = allocNode(t, key); |
|
| 112 | 112 | let mut y: u32 = NIL; |
|
| 113 | 113 | let mut x: u32 = t.root; |
|
| 114 | 114 | ||
| 115 | 115 | while x <> NIL { |
|
| 116 | - | y = x; |
|
| 116 | + | set y = x; |
|
| 117 | 117 | if key < t.pool[x].key { |
|
| 118 | - | x = t.pool[x].left; |
|
| 118 | + | set x = t.pool[x].left; |
|
| 119 | 119 | } else { |
|
| 120 | - | x = t.pool[x].right; |
|
| 120 | + | set x = t.pool[x].right; |
|
| 121 | 121 | } |
|
| 122 | 122 | } |
|
| 123 | 123 | ||
| 124 | - | t.pool[z].parent = y; |
|
| 124 | + | set t.pool[z].parent = y; |
|
| 125 | 125 | if y == NIL { |
|
| 126 | - | t.root = z; |
|
| 126 | + | set t.root = z; |
|
| 127 | 127 | } else if key < t.pool[y].key { |
|
| 128 | - | t.pool[y].left = z; |
|
| 128 | + | set t.pool[y].left = z; |
|
| 129 | 129 | } else { |
|
| 130 | - | t.pool[y].right = z; |
|
| 130 | + | set t.pool[y].right = z; |
|
| 131 | 131 | } |
|
| 132 | 132 | ||
| 133 | 133 | insertFixup(t, z); |
|
| 134 | 134 | } |
|
| 135 | 135 |
| 137 | 137 | let mut x: u32 = t.root; |
|
| 138 | 138 | while x <> NIL { |
|
| 139 | 139 | if key == t.pool[x].key { |
|
| 140 | 140 | return true; |
|
| 141 | 141 | } else if key < t.pool[x].key { |
|
| 142 | - | x = t.pool[x].left; |
|
| 142 | + | set x = t.pool[x].left; |
|
| 143 | 143 | } else { |
|
| 144 | - | x = t.pool[x].right; |
|
| 144 | + | set x = t.pool[x].right; |
|
| 145 | 145 | } |
|
| 146 | 146 | } |
|
| 147 | 147 | return false; |
|
| 148 | 148 | } |
|
| 149 | 149 | ||
| 150 | 150 | fn inorderWalk(t: *mut RBTree, x: u32) { |
|
| 151 | 151 | if x == NIL { |
|
| 152 | 152 | return; |
|
| 153 | 153 | } |
|
| 154 | 154 | inorderWalk(t, t.pool[x].left); |
|
| 155 | - | t.inorder[t.inorderCount] = t.pool[x].key; |
|
| 156 | - | t.inorderCount += 1; |
|
| 155 | + | set t.inorder[t.inorderCount] = t.pool[x].key; |
|
| 156 | + | set t.inorderCount += 1; |
|
| 157 | 157 | inorderWalk(t, t.pool[x].right); |
|
| 158 | 158 | } |
|
| 159 | 159 | ||
| 160 | 160 | fn countNodes(t: *RBTree, x: u32) -> u32 { |
|
| 161 | 161 | if x == NIL { |
| 203 | 203 | } |
|
| 204 | 204 | ||
| 205 | 205 | fn resetTree(t: *mut RBTree) { |
|
| 206 | 206 | let mut i: u32 = 0; |
|
| 207 | 207 | while i < POOL_SIZE { |
|
| 208 | - | t.pool[i] = RBNode { key: 0, color: BLACK, left: NIL, right: NIL, parent: NIL }; |
|
| 209 | - | i += 1; |
|
| 208 | + | set t.pool[i] = RBNode { key: 0, color: BLACK, left: NIL, right: NIL, parent: NIL }; |
|
| 209 | + | set i += 1; |
|
| 210 | 210 | } |
|
| 211 | - | t.poolNext = 1; |
|
| 212 | - | t.root = NIL; |
|
| 213 | - | t.inorderCount = 0; |
|
| 211 | + | set t.poolNext = 1; |
|
| 212 | + | set t.root = NIL; |
|
| 213 | + | set t.inorderCount = 0; |
|
| 214 | 214 | } |
|
| 215 | 215 | ||
| 216 | 216 | fn testAscending(t: *mut RBTree) -> i32 { |
|
| 217 | 217 | resetTree(t); |
|
| 218 | 218 | ||
| 219 | 219 | let mut i: i32 = 0; |
|
| 220 | 220 | while i < 32 { |
|
| 221 | 221 | insert(t, i); |
|
| 222 | - | i += 1; |
|
| 222 | + | set i += 1; |
|
| 223 | 223 | } |
|
| 224 | 224 | ||
| 225 | 225 | assert countNodes(t, t.root) == 32; |
|
| 226 | 226 | assert t.pool[t.root].color == BLACK; |
|
| 227 | 227 | ||
| 228 | 228 | let bh: i32 = blackHeight(t, t.root); |
|
| 229 | 229 | assert bh <> -1; |
|
| 230 | 230 | ||
| 231 | 231 | assert noRedRed(t, t.root); |
|
| 232 | 232 | ||
| 233 | - | t.inorderCount = 0; |
|
| 233 | + | set t.inorderCount = 0; |
|
| 234 | 234 | inorderWalk(t, t.root); |
|
| 235 | 235 | assert t.inorderCount == 32; |
|
| 236 | 236 | let mut j: u32 = 0; |
|
| 237 | 237 | while j < 32 { |
|
| 238 | 238 | assert t.inorder[j] == j as i32; |
|
| 239 | - | j += 1; |
|
| 239 | + | set j += 1; |
|
| 240 | 240 | } |
|
| 241 | 241 | ||
| 242 | 242 | return 0; |
|
| 243 | 243 | } |
|
| 244 | 244 |
| 249 | 249 | while i >= 0 { |
|
| 250 | 250 | insert(t, i); |
|
| 251 | 251 | if i == 0 { |
|
| 252 | 252 | break; |
|
| 253 | 253 | } |
|
| 254 | - | i -= 1; |
|
| 254 | + | set i -= 1; |
|
| 255 | 255 | } |
|
| 256 | 256 | ||
| 257 | 257 | assert countNodes(t, t.root) == 32; |
|
| 258 | 258 | assert blackHeight(t, t.root) <> -1; |
|
| 259 | 259 | assert noRedRed(t, t.root); |
|
| 260 | 260 | ||
| 261 | - | t.inorderCount = 0; |
|
| 261 | + | set t.inorderCount = 0; |
|
| 262 | 262 | inorderWalk(t, t.root); |
|
| 263 | 263 | let mut j: u32 = 0; |
|
| 264 | 264 | while j < 32 { |
|
| 265 | 265 | assert t.inorder[j] == j as i32; |
|
| 266 | - | j += 1; |
|
| 266 | + | set j += 1; |
|
| 267 | 267 | } |
|
| 268 | 268 | ||
| 269 | 269 | return 0; |
|
| 270 | 270 | } |
|
| 271 | 271 |
| 275 | 275 | let mut inserted: [bool; 48] = [false; 48]; |
|
| 276 | 276 | let mut seed: u32 = 42; |
|
| 277 | 277 | let mut count: u32 = 0; |
|
| 278 | 278 | ||
| 279 | 279 | while count < 48 { |
|
| 280 | - | seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF; |
|
| 280 | + | set seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF; |
|
| 281 | 281 | let val: u32 = seed % 48; |
|
| 282 | 282 | if not inserted[val] { |
|
| 283 | 283 | insert(t, val as i32); |
|
| 284 | - | inserted[val] = true; |
|
| 285 | - | count += 1; |
|
| 284 | + | set inserted[val] = true; |
|
| 285 | + | set count += 1; |
|
| 286 | 286 | } |
|
| 287 | 287 | } |
|
| 288 | 288 | ||
| 289 | 289 | assert countNodes(t, t.root) == 48; |
|
| 290 | 290 | assert blackHeight(t, t.root) <> -1; |
|
| 291 | 291 | assert noRedRed(t, t.root); |
|
| 292 | 292 | ||
| 293 | 293 | let mut i: i32 = 0; |
|
| 294 | 294 | while i < 48 { |
|
| 295 | 295 | assert search(t, i); |
|
| 296 | - | i += 1; |
|
| 296 | + | set i += 1; |
|
| 297 | 297 | } |
|
| 298 | 298 | ||
| 299 | 299 | assert not search(t, -1); |
|
| 300 | 300 | assert not search(t, 48); |
|
| 301 | 301 | assert not search(t, 100); |
|
| 302 | 302 | ||
| 303 | - | t.inorderCount = 0; |
|
| 303 | + | set t.inorderCount = 0; |
|
| 304 | 304 | inorderWalk(t, t.root); |
|
| 305 | 305 | assert t.inorderCount == 48; |
|
| 306 | 306 | let mut j: u32 = 0; |
|
| 307 | 307 | while j < 48 { |
|
| 308 | 308 | assert t.inorder[j] == j as i32; |
|
| 309 | - | j += 1; |
|
| 309 | + | set j += 1; |
|
| 310 | 310 | } |
|
| 311 | 311 | ||
| 312 | 312 | return 0; |
|
| 313 | 313 | } |
|
| 314 | 314 |
| 316 | 316 | resetTree(t); |
|
| 317 | 317 | ||
| 318 | 318 | let mut i: i32 = 0; |
|
| 319 | 319 | while i < 63 { |
|
| 320 | 320 | insert(t, i); |
|
| 321 | - | i += 1; |
|
| 321 | + | set i += 1; |
|
| 322 | 322 | } |
|
| 323 | 323 | ||
| 324 | 324 | let bh: i32 = blackHeight(t, t.root); |
|
| 325 | 325 | assert bh >= 3; |
|
| 326 | 326 | assert bh <= 7; |
test/tests/prog.regex.rad
+42 -42
| 37 | 37 | fragTop: u32, |
|
| 38 | 38 | } |
|
| 39 | 39 | ||
| 40 | 40 | fn newState(nfa: *mut NfaState) -> u32 { |
|
| 41 | 41 | let s: u32 = nfa.stateCount; |
|
| 42 | - | nfa.stateFirst[s] = NIL; |
|
| 43 | - | nfa.stateCount += 1; |
|
| 42 | + | set nfa.stateFirst[s] = NIL; |
|
| 43 | + | set nfa.stateCount += 1; |
|
| 44 | 44 | return s; |
|
| 45 | 45 | } |
|
| 46 | 46 | ||
| 47 | 47 | fn addTrans(nfa: *mut NfaState, from: u32, kind: u32, ch: u8, to: u32) { |
|
| 48 | 48 | let idx: u32 = nfa.transCount; |
|
| 49 | - | nfa.trans[idx] = Trans { kind, ch, to }; |
|
| 50 | - | nfa.transNext[idx] = nfa.stateFirst[from]; |
|
| 51 | - | nfa.stateFirst[from] = idx; |
|
| 52 | - | nfa.transCount += 1; |
|
| 49 | + | set nfa.trans[idx] = Trans { kind, ch, to }; |
|
| 50 | + | set nfa.transNext[idx] = nfa.stateFirst[from]; |
|
| 51 | + | set nfa.stateFirst[from] = idx; |
|
| 52 | + | set nfa.transCount += 1; |
|
| 53 | 53 | } |
|
| 54 | 54 | ||
| 55 | 55 | fn pushFrag(nfa: *mut NfaState, f: Frag) { |
|
| 56 | - | nfa.fragStack[nfa.fragTop] = f; |
|
| 57 | - | nfa.fragTop += 1; |
|
| 56 | + | set nfa.fragStack[nfa.fragTop] = f; |
|
| 57 | + | set nfa.fragTop += 1; |
|
| 58 | 58 | } |
|
| 59 | 59 | ||
| 60 | 60 | fn popFrag(nfa: *mut NfaState) -> Frag { |
|
| 61 | - | nfa.fragTop -= 1; |
|
| 61 | + | set nfa.fragTop -= 1; |
|
| 62 | 62 | return nfa.fragStack[nfa.fragTop]; |
|
| 63 | 63 | } |
|
| 64 | 64 | ||
| 65 | 65 | fn setEmpty(s: *mut [u32]) { |
|
| 66 | - | s[0] = 0; |
|
| 67 | - | s[1] = 0; |
|
| 68 | - | s[2] = 0; |
|
| 69 | - | s[3] = 0; |
|
| 66 | + | set s[0] = 0; |
|
| 67 | + | set s[1] = 0; |
|
| 68 | + | set s[2] = 0; |
|
| 69 | + | set s[3] = 0; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | fn setAdd(s: *mut [u32], bit: u32) { |
|
| 73 | 73 | let word: u32 = bit / 32; |
|
| 74 | 74 | let pos: u32 = bit % 32; |
|
| 75 | - | s[word] |= (1 << pos); |
|
| 75 | + | set s[word] |= (1 << pos); |
|
| 76 | 76 | } |
|
| 77 | 77 | ||
| 78 | 78 | fn setHas(s: *[u32], bit: u32) -> bool { |
|
| 79 | 79 | let word: u32 = bit / 32; |
|
| 80 | 80 | let pos: u32 = bit % 32; |
| 84 | 84 | fn setIsEmpty(s: *[u32]) -> bool { |
|
| 85 | 85 | return s[0] == 0 and s[1] == 0 and s[2] == 0 and s[3] == 0; |
|
| 86 | 86 | } |
|
| 87 | 87 | ||
| 88 | 88 | fn setCopy(dst: *mut [u32], src: *[u32]) { |
|
| 89 | - | dst[0] = src[0]; |
|
| 90 | - | dst[1] = src[1]; |
|
| 91 | - | dst[2] = src[2]; |
|
| 92 | - | dst[3] = src[3]; |
|
| 89 | + | set dst[0] = src[0]; |
|
| 90 | + | set dst[1] = src[1]; |
|
| 91 | + | set dst[2] = src[2]; |
|
| 92 | + | set dst[3] = src[3]; |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | 95 | fn epsilonClosure(nfa: *mut NfaState, states: *mut [u32]) { |
|
| 96 | 96 | setCopy(nfa.closure, states); |
|
| 97 | 97 | ||
| 98 | 98 | let mut changed: bool = true; |
|
| 99 | 99 | while changed { |
|
| 100 | - | changed = false; |
|
| 100 | + | set changed = false; |
|
| 101 | 101 | let mut s: u32 = 0; |
|
| 102 | 102 | while s < nfa.stateCount { |
|
| 103 | 103 | if setHas(nfa.closure, s) { |
|
| 104 | 104 | let mut t: u32 = nfa.stateFirst[s]; |
|
| 105 | 105 | while t <> NIL { |
|
| 106 | 106 | if nfa.trans[t].kind == TRANS_EPSILON { |
|
| 107 | 107 | if not setHas(nfa.closure, nfa.trans[t].to) { |
|
| 108 | 108 | setAdd(nfa.closure, nfa.trans[t].to); |
|
| 109 | - | changed = true; |
|
| 109 | + | set changed = true; |
|
| 110 | 110 | } |
|
| 111 | 111 | } |
|
| 112 | - | t = nfa.transNext[t]; |
|
| 112 | + | set t = nfa.transNext[t]; |
|
| 113 | 113 | } |
|
| 114 | 114 | } |
|
| 115 | - | s += 1; |
|
| 115 | + | set s += 1; |
|
| 116 | 116 | } |
|
| 117 | 117 | } |
|
| 118 | 118 | ||
| 119 | 119 | setCopy(states, nfa.closure); |
|
| 120 | 120 | } |
|
| 121 | 121 | ||
| 122 | 122 | fn resetNFA(nfa: *mut NfaState) { |
|
| 123 | - | nfa.stateCount = 0; |
|
| 124 | - | nfa.transCount = 0; |
|
| 125 | - | nfa.fragTop = 0; |
|
| 123 | + | set nfa.stateCount = 0; |
|
| 124 | + | set nfa.transCount = 0; |
|
| 125 | + | set nfa.fragTop = 0; |
|
| 126 | 126 | let mut i: u32 = 0; |
|
| 127 | 127 | while i < MAX_STATES { |
|
| 128 | - | nfa.stateFirst[i] = NIL; |
|
| 129 | - | i += 1; |
|
| 128 | + | set nfa.stateFirst[i] = NIL; |
|
| 129 | + | set i += 1; |
|
| 130 | 130 | } |
|
| 131 | - | i = 0; |
|
| 131 | + | set i = 0; |
|
| 132 | 132 | while i < MAX_TRANSITIONS { |
|
| 133 | - | nfa.transNext[i] = NIL; |
|
| 134 | - | i += 1; |
|
| 133 | + | set nfa.transNext[i] = NIL; |
|
| 134 | + | set i += 1; |
|
| 135 | 135 | } |
|
| 136 | 136 | } |
|
| 137 | 137 | ||
| 138 | 138 | fn compile(nfa: *mut NfaState, pattern: *[u8]) -> u32 { |
|
| 139 | 139 | resetNFA(nfa); |
| 158 | 158 | addTrans(nfa, s, TRANS_EPSILON, 0, body); |
|
| 159 | 159 | addTrans(nfa, s, TRANS_EPSILON, 0, e); |
|
| 160 | 160 | addTrans(nfa, body, TRANS_EPSILON, 0, e); |
|
| 161 | 161 | ||
| 162 | 162 | pushFrag(nfa, Frag { start: s, endState: e }); |
|
| 163 | - | i += 2; |
|
| 163 | + | set i += 2; |
|
| 164 | 164 | continue; |
|
| 165 | 165 | } |
|
| 166 | 166 | if nextCh == 43 { |
|
| 167 | 167 | let s: u32 = newState(nfa); |
|
| 168 | 168 | let m: u32 = newState(nfa); |
| 176 | 176 | addTrans(nfa, m, TRANS_CHAR, ch, m); |
|
| 177 | 177 | } |
|
| 178 | 178 | addTrans(nfa, m, TRANS_EPSILON, 0, e); |
|
| 179 | 179 | ||
| 180 | 180 | pushFrag(nfa, Frag { start: s, endState: e }); |
|
| 181 | - | i += 2; |
|
| 181 | + | set i += 2; |
|
| 182 | 182 | continue; |
|
| 183 | 183 | } |
|
| 184 | 184 | if nextCh == 63 { |
|
| 185 | 185 | let s: u32 = newState(nfa); |
|
| 186 | 186 | let m: u32 = newState(nfa); |
| 193 | 193 | } |
|
| 194 | 194 | addTrans(nfa, s, TRANS_EPSILON, 0, e); |
|
| 195 | 195 | addTrans(nfa, m, TRANS_EPSILON, 0, e); |
|
| 196 | 196 | ||
| 197 | 197 | pushFrag(nfa, Frag { start: s, endState: e }); |
|
| 198 | - | i += 2; |
|
| 198 | + | set i += 2; |
|
| 199 | 199 | continue; |
|
| 200 | 200 | } |
|
| 201 | 201 | } |
|
| 202 | 202 | ||
| 203 | 203 | let s: u32 = newState(nfa); |
| 206 | 206 | addTrans(nfa, s, TRANS_DOT, 0, e); |
|
| 207 | 207 | } else { |
|
| 208 | 208 | addTrans(nfa, s, TRANS_CHAR, ch, e); |
|
| 209 | 209 | } |
|
| 210 | 210 | pushFrag(nfa, Frag { start: s, endState: e }); |
|
| 211 | - | i += 1; |
|
| 211 | + | set i += 1; |
|
| 212 | 212 | } |
|
| 213 | 213 | ||
| 214 | 214 | if nfa.fragTop == 0 { |
|
| 215 | 215 | let s: u32 = newState(nfa); |
|
| 216 | - | nfa.acceptState = s; |
|
| 216 | + | set nfa.acceptState = s; |
|
| 217 | 217 | return s; |
|
| 218 | 218 | } |
|
| 219 | 219 | ||
| 220 | 220 | let numFrags: u32 = nfa.fragTop; |
|
| 221 | 221 | let mut frags: [Frag; 64] = [Frag { start: 0, endState: 0 }; 64]; |
|
| 222 | 222 | let mut k: u32 = 0; |
|
| 223 | 223 | while k < numFrags { |
|
| 224 | - | frags[numFrags - 1 - k] = popFrag(nfa); |
|
| 225 | - | k += 1; |
|
| 224 | + | set frags[numFrags - 1 - k] = popFrag(nfa); |
|
| 225 | + | set k += 1; |
|
| 226 | 226 | } |
|
| 227 | 227 | ||
| 228 | 228 | let mut j: u32 = 0; |
|
| 229 | 229 | while j < numFrags - 1 { |
|
| 230 | 230 | addTrans(nfa, frags[j].endState, TRANS_EPSILON, 0, frags[j + 1].start); |
|
| 231 | - | j += 1; |
|
| 231 | + | set j += 1; |
|
| 232 | 232 | } |
|
| 233 | 233 | ||
| 234 | - | nfa.acceptState = frags[numFrags - 1].endState; |
|
| 234 | + | set nfa.acceptState = frags[numFrags - 1].endState; |
|
| 235 | 235 | return frags[0].start; |
|
| 236 | 236 | } |
|
| 237 | 237 | ||
| 238 | 238 | fn nfaMatches(nfa: *mut NfaState, start: u32, input: *[u8]) -> bool { |
|
| 239 | 239 | setEmpty(nfa.current); |
| 253 | 253 | if nfa.trans[t].kind == TRANS_CHAR and nfa.trans[t].ch == ch { |
|
| 254 | 254 | setAdd(nfa.nextSet, nfa.trans[t].to); |
|
| 255 | 255 | } else if nfa.trans[t].kind == TRANS_DOT { |
|
| 256 | 256 | setAdd(nfa.nextSet, nfa.trans[t].to); |
|
| 257 | 257 | } |
|
| 258 | - | t = nfa.transNext[t]; |
|
| 258 | + | set t = nfa.transNext[t]; |
|
| 259 | 259 | } |
|
| 260 | 260 | } |
|
| 261 | - | s += 1; |
|
| 261 | + | set s += 1; |
|
| 262 | 262 | } |
|
| 263 | 263 | ||
| 264 | 264 | epsilonClosure(nfa, nfa.nextSet); |
|
| 265 | 265 | setCopy(nfa.current, nfa.nextSet); |
|
| 266 | 266 | ||
| 267 | 267 | if setIsEmpty(nfa.current) { |
|
| 268 | 268 | return false; |
|
| 269 | 269 | } |
|
| 270 | - | i += 1; |
|
| 270 | + | set i += 1; |
|
| 271 | 271 | } |
|
| 272 | 272 | ||
| 273 | 273 | return setHas(nfa.current, nfa.acceptState); |
|
| 274 | 274 | } |
|
| 275 | 275 |
test/tests/prog.sha256.rad
+35 -35
| 54 | 54 | /// Prepare the message schedule from a 16-word (512-bit) block. |
|
| 55 | 55 | fn prepareSchedule(s: *mut Sha256, block: *[u32]) { |
|
| 56 | 56 | // Copy the first 16 words directly. |
|
| 57 | 57 | let mut i: u32 = 0; |
|
| 58 | 58 | while i < 16 { |
|
| 59 | - | s.w[i] = block[i]; |
|
| 60 | - | i += 1; |
|
| 59 | + | set s.w[i] = block[i]; |
|
| 60 | + | set i += 1; |
|
| 61 | 61 | } |
|
| 62 | 62 | // Extend to 64 words. |
|
| 63 | 63 | while i < 64 { |
|
| 64 | - | s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16]; |
|
| 65 | - | i += 1; |
|
| 64 | + | set s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16]; |
|
| 65 | + | set i += 1; |
|
| 66 | 66 | } |
|
| 67 | 67 | } |
|
| 68 | 68 | ||
| 69 | 69 | /// Run the 64-round compression function. |
|
| 70 | 70 | fn compress(s: *mut Sha256, k: *[u32]) { |
| 79 | 79 | ||
| 80 | 80 | let mut i: u32 = 0; |
|
| 81 | 81 | while i < 64 { |
|
| 82 | 82 | let t1 = hh + bsig1(e) + ch(e, f, g) + k[i] + s.w[i]; |
|
| 83 | 83 | let t2 = bsig0(a) + maj(a, b, c); |
|
| 84 | - | hh = g; |
|
| 85 | - | g = f; |
|
| 86 | - | f = e; |
|
| 87 | - | e = d + t1; |
|
| 88 | - | d = c; |
|
| 89 | - | c = b; |
|
| 90 | - | b = a; |
|
| 91 | - | a = t1 + t2; |
|
| 92 | - | i += 1; |
|
| 84 | + | set hh = g; |
|
| 85 | + | set g = f; |
|
| 86 | + | set f = e; |
|
| 87 | + | set e = d + t1; |
|
| 88 | + | set d = c; |
|
| 89 | + | set c = b; |
|
| 90 | + | set b = a; |
|
| 91 | + | set a = t1 + t2; |
|
| 92 | + | set i += 1; |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | - | s.h[0] += a; |
|
| 96 | - | s.h[1] += b; |
|
| 97 | - | s.h[2] += c; |
|
| 98 | - | s.h[3] += d; |
|
| 99 | - | s.h[4] += e; |
|
| 100 | - | s.h[5] += f; |
|
| 101 | - | s.h[6] += g; |
|
| 102 | - | s.h[7] += hh; |
|
| 95 | + | set s.h[0] += a; |
|
| 96 | + | set s.h[1] += b; |
|
| 97 | + | set s.h[2] += c; |
|
| 98 | + | set s.h[3] += d; |
|
| 99 | + | set s.h[4] += e; |
|
| 100 | + | set s.h[5] += f; |
|
| 101 | + | set s.h[6] += g; |
|
| 102 | + | set s.h[7] += hh; |
|
| 103 | 103 | } |
|
| 104 | 104 | ||
| 105 | 105 | /// Reset hash state to initial values. |
|
| 106 | 106 | fn resetHash(s: *mut Sha256) { |
|
| 107 | 107 | let mut i: u32 = 0; |
|
| 108 | 108 | while i < 8 { |
|
| 109 | - | s.h[i] = INIT_H[i]; |
|
| 110 | - | i += 1; |
|
| 109 | + | set s.h[i] = INIT_H[i]; |
|
| 110 | + | set i += 1; |
|
| 111 | 111 | } |
|
| 112 | 112 | } |
|
| 113 | 113 | ||
| 114 | 114 | /// Pad and hash a short message (up to 55 bytes, fits in one 512-bit block). |
|
| 115 | 115 | fn hashMessage(s: *mut Sha256, k: *[u32], msg: *[u8]) -> i32 { |
| 122 | 122 | let mut blockBytes: [u8; 64] = [0; 64]; |
|
| 123 | 123 | ||
| 124 | 124 | // Copy message. |
|
| 125 | 125 | let mut i: u32 = 0; |
|
| 126 | 126 | while i < msg.len { |
|
| 127 | - | blockBytes[i] = msg[i]; |
|
| 128 | - | i += 1; |
|
| 127 | + | set blockBytes[i] = msg[i]; |
|
| 128 | + | set i += 1; |
|
| 129 | 129 | } |
|
| 130 | 130 | ||
| 131 | 131 | // Append the 1-bit (0x80). |
|
| 132 | - | blockBytes[msg.len] = 0x80; |
|
| 132 | + | set blockBytes[msg.len] = 0x80; |
|
| 133 | 133 | ||
| 134 | 134 | // Append length in bits as big-endian 64-bit integer at the end. |
|
| 135 | 135 | let bitLen: u32 = msg.len * 8; |
|
| 136 | - | blockBytes[60] = (bitLen >> 24) as u8; |
|
| 137 | - | blockBytes[61] = (bitLen >> 16) as u8; |
|
| 138 | - | blockBytes[62] = (bitLen >> 8) as u8; |
|
| 139 | - | blockBytes[63] = bitLen as u8; |
|
| 136 | + | set blockBytes[60] = (bitLen >> 24) as u8; |
|
| 137 | + | set blockBytes[61] = (bitLen >> 16) as u8; |
|
| 138 | + | set blockBytes[62] = (bitLen >> 8) as u8; |
|
| 139 | + | set blockBytes[63] = bitLen as u8; |
|
| 140 | 140 | ||
| 141 | 141 | // Convert bytes to 16 big-endian 32-bit words. |
|
| 142 | 142 | let mut block: [u32; 16] = [0; 16]; |
|
| 143 | 143 | let mut w: u32 = 0; |
|
| 144 | 144 | while w < 16 { |
|
| 145 | 145 | let base = w * 4; |
|
| 146 | - | block[w] = (blockBytes[base] as u32 << 24) |
|
| 147 | - | | (blockBytes[base + 1] as u32 << 16) |
|
| 148 | - | | (blockBytes[base + 2] as u32 << 8) |
|
| 149 | - | | (blockBytes[base + 3] as u32); |
|
| 150 | - | w += 1; |
|
| 146 | + | set block[w] = (blockBytes[base] as u32 << 24) |
|
| 147 | + | | (blockBytes[base + 1] as u32 << 16) |
|
| 148 | + | | (blockBytes[base + 2] as u32 << 8) |
|
| 149 | + | | (blockBytes[base + 3] as u32); |
|
| 150 | + | set w += 1; |
|
| 151 | 151 | } |
|
| 152 | 152 | ||
| 153 | 153 | resetHash(s); |
|
| 154 | 154 | prepareSchedule(s, &block[..]); |
|
| 155 | 155 | compress(s, k); |
test/tests/prog.sieve.rad
+9 -9
| 5 | 5 | ||
| 6 | 6 | /// Mark all multiples of p as composite. |
|
| 7 | 7 | fn markMultiples(sieve: *mut [bool], p: u32) { |
|
| 8 | 8 | let mut i: u32 = p * p; |
|
| 9 | 9 | while i < sieve.len { |
|
| 10 | - | sieve[i] = true; |
|
| 11 | - | i += p; |
|
| 10 | + | set sieve[i] = true; |
|
| 11 | + | set i += p; |
|
| 12 | 12 | } |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | /// Run the sieve algorithm. |
|
| 16 | 16 | fn runSieve(sieve: *mut [bool]) { |
|
| 17 | 17 | // 0 and 1 are not prime. |
|
| 18 | - | sieve[0] = true; |
|
| 19 | - | sieve[1] = true; |
|
| 18 | + | set sieve[0] = true; |
|
| 19 | + | set sieve[1] = true; |
|
| 20 | 20 | ||
| 21 | 21 | let mut p: u32 = 2; |
|
| 22 | 22 | while p * p < sieve.len { |
|
| 23 | 23 | if not sieve[p] { |
|
| 24 | 24 | markMultiples(sieve, p); |
|
| 25 | 25 | } |
|
| 26 | - | p += 1; |
|
| 26 | + | set p += 1; |
|
| 27 | 27 | } |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | /// Count the number of primes found. |
|
| 31 | 31 | fn countPrimes(sieve: *[bool]) -> u32 { |
|
| 32 | 32 | let mut count: u32 = 0; |
|
| 33 | 33 | for composite in sieve { |
|
| 34 | 34 | if not composite { |
|
| 35 | - | count += 1; |
|
| 35 | + | set count += 1; |
|
| 36 | 36 | } |
|
| 37 | 37 | } |
|
| 38 | 38 | return count; |
|
| 39 | 39 | } |
|
| 40 | 40 |
| 42 | 42 | fn collectPrimes(sieve: *[bool], primes: *mut [u32]) -> u32 { |
|
| 43 | 43 | let mut count: u32 = 0; |
|
| 44 | 44 | for composite, idx in sieve { |
|
| 45 | 45 | if not composite { |
|
| 46 | 46 | if count < primes.len { |
|
| 47 | - | primes[count] = idx; |
|
| 48 | - | count += 1; |
|
| 47 | + | set primes[count] = idx; |
|
| 48 | + | set count += 1; |
|
| 49 | 49 | } |
|
| 50 | 50 | } |
|
| 51 | 51 | } |
|
| 52 | 52 | return count; |
|
| 53 | 53 | } |
| 96 | 96 | let mut prev: ?u32 = nil; |
|
| 97 | 97 | for p in collected { |
|
| 98 | 98 | if let prevVal = prev { |
|
| 99 | 99 | assert prevVal < p; |
|
| 100 | 100 | } |
|
| 101 | - | prev = p; |
|
| 101 | + | set prev = p; |
|
| 102 | 102 | } |
|
| 103 | 103 | return 0; |
|
| 104 | 104 | } |
|
| 105 | 105 | ||
| 106 | 106 | @default fn main() -> i32 { |
test/tests/prog.symtab.rad
+28 -28
| 41 | 41 | ||
| 42 | 42 | /// Simple string hash function. |
|
| 43 | 43 | fn hashName(name: *[u8]) -> u32 { |
|
| 44 | 44 | let mut h: u32 = 5381; |
|
| 45 | 45 | for ch in name { |
|
| 46 | - | h = ((h << 5) + h) + ch as u32; |
|
| 46 | + | set h = ((h << 5) + h) + ch as u32; |
|
| 47 | 47 | } |
|
| 48 | 48 | return h; |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | /// Initialize the symbol table. |
|
| 52 | 52 | fn init(tab: *mut SymTab) { |
|
| 53 | - | tab.symbolCount = 0; |
|
| 54 | - | tab.scopeDepth = 0; |
|
| 53 | + | set tab.symbolCount = 0; |
|
| 54 | + | set tab.scopeDepth = 0; |
|
| 55 | 55 | ||
| 56 | 56 | for i in 0..HASH_SIZE { |
|
| 57 | - | tab.buckets[i] = NIL; |
|
| 57 | + | set tab.buckets[i] = NIL; |
|
| 58 | 58 | } |
|
| 59 | 59 | } |
|
| 60 | 60 | ||
| 61 | 61 | /// Push a new scope. |
|
| 62 | 62 | fn pushScope(tab: *mut SymTab) { |
|
| 63 | - | tab.scopes[tab.scopeDepth] = ScopeMarker { symbolCount: tab.symbolCount }; |
|
| 64 | - | tab.scopeDepth += 1; |
|
| 63 | + | set tab.scopes[tab.scopeDepth] = ScopeMarker { symbolCount: tab.symbolCount }; |
|
| 64 | + | set tab.scopeDepth += 1; |
|
| 65 | 65 | } |
|
| 66 | 66 | ||
| 67 | 67 | /// Pop the current scope, removing all symbols defined in it. |
|
| 68 | 68 | fn popScope(tab: *mut SymTab) { |
|
| 69 | 69 | if tab.scopeDepth == 0 { |
|
| 70 | 70 | return; |
|
| 71 | 71 | } |
|
| 72 | - | tab.scopeDepth -= 1; |
|
| 72 | + | set tab.scopeDepth -= 1; |
|
| 73 | 73 | let marker = tab.scopes[tab.scopeDepth]; |
|
| 74 | 74 | ||
| 75 | 75 | // Remove symbols added in this scope (in reverse order). |
|
| 76 | 76 | while tab.symbolCount > marker.symbolCount { |
|
| 77 | - | tab.symbolCount -= 1; |
|
| 77 | + | set tab.symbolCount -= 1; |
|
| 78 | 78 | let sym = tab.symbols[tab.symbolCount]; |
|
| 79 | 79 | let bucket = sym.nameHash % HASH_SIZE; |
|
| 80 | 80 | ||
| 81 | 81 | // Remove from hash chain. |
|
| 82 | - | tab.buckets[bucket] = sym.next; |
|
| 82 | + | set tab.buckets[bucket] = sym.next; |
|
| 83 | 83 | ||
| 84 | 84 | // Restore shadowed symbol if any. |
|
| 85 | 85 | if sym.shadow <> NIL { |
|
| 86 | 86 | // The shadowed symbol is still in the symbols array; |
|
| 87 | 87 | // re-link it into the hash chain. |
|
| 88 | 88 | let shadowIdx = sym.shadow; |
|
| 89 | - | tab.symbols[shadowIdx].next = tab.buckets[bucket]; |
|
| 90 | - | tab.buckets[bucket] = shadowIdx; |
|
| 89 | + | set tab.symbols[shadowIdx].next = tab.buckets[bucket]; |
|
| 90 | + | set tab.buckets[bucket] = shadowIdx; |
|
| 91 | 91 | } |
|
| 92 | 92 | } |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | 95 | /// Define a symbol in the current scope. |
| 102 | 102 | let mut cur = tab.buckets[bucket]; |
|
| 103 | 103 | while cur <> NIL { |
|
| 104 | 104 | if tab.symbols[cur].nameHash == h { |
|
| 105 | 105 | // Found existing symbol with same hash - shadow it. |
|
| 106 | 106 | // Remove it from hash chain first. |
|
| 107 | - | shadowIdx = cur; |
|
| 107 | + | set shadowIdx = cur; |
|
| 108 | 108 | // Remove the shadowed symbol from the bucket chain. |
|
| 109 | 109 | if tab.buckets[bucket] == cur { |
|
| 110 | - | tab.buckets[bucket] = tab.symbols[cur].next; |
|
| 110 | + | set tab.buckets[bucket] = tab.symbols[cur].next; |
|
| 111 | 111 | } |
|
| 112 | 112 | break; |
|
| 113 | 113 | } |
|
| 114 | - | cur = tab.symbols[cur].next; |
|
| 114 | + | set cur = tab.symbols[cur].next; |
|
| 115 | 115 | } |
|
| 116 | 116 | ||
| 117 | 117 | let idx = tab.symbolCount; |
|
| 118 | - | tab.symbols[idx] = Symbol { |
|
| 118 | + | set tab.symbols[idx] = Symbol { |
|
| 119 | 119 | nameHash: h, |
|
| 120 | 120 | value, |
|
| 121 | 121 | depth: tab.scopeDepth, |
|
| 122 | 122 | next: tab.buckets[bucket], |
|
| 123 | 123 | shadow: shadowIdx, |
|
| 124 | 124 | }; |
|
| 125 | - | tab.buckets[bucket] = idx; |
|
| 126 | - | tab.symbolCount += 1; |
|
| 125 | + | set tab.buckets[bucket] = idx; |
|
| 126 | + | set tab.symbolCount += 1; |
|
| 127 | 127 | return idx; |
|
| 128 | 128 | } |
|
| 129 | 129 | ||
| 130 | 130 | /// Look up a symbol by name. Returns the value if found. |
|
| 131 | 131 | fn lookup(tab: *SymTab, name: *[u8]) -> ?i32 { |
| 135 | 135 | ||
| 136 | 136 | while cur <> NIL { |
|
| 137 | 137 | if tab.symbols[cur].nameHash == h { |
|
| 138 | 138 | return tab.symbols[cur].value; |
|
| 139 | 139 | } |
|
| 140 | - | cur = tab.symbols[cur].next; |
|
| 140 | + | set cur = tab.symbols[cur].next; |
|
| 141 | 141 | } |
|
| 142 | 142 | return nil; |
|
| 143 | 143 | } |
|
| 144 | 144 | ||
| 145 | 145 | /// Update a symbol's value. Returns true if the symbol was found. |
| 148 | 148 | let bucket = h % HASH_SIZE; |
|
| 149 | 149 | let mut cur = tab.buckets[bucket]; |
|
| 150 | 150 | ||
| 151 | 151 | while cur <> NIL { |
|
| 152 | 152 | if tab.symbols[cur].nameHash == h { |
|
| 153 | - | tab.symbols[cur].value = newValue; |
|
| 153 | + | set tab.symbols[cur].value = newValue; |
|
| 154 | 154 | return true; |
|
| 155 | 155 | } |
|
| 156 | - | cur = tab.symbols[cur].next; |
|
| 156 | + | set cur = tab.symbols[cur].next; |
|
| 157 | 157 | } |
|
| 158 | 158 | return false; |
|
| 159 | 159 | } |
|
| 160 | 160 | ||
| 161 | 161 | /// Test basic define and lookup. |
| 231 | 231 | // Define x at each of 8 scope levels. |
|
| 232 | 232 | let mut i: u32 = 0; |
|
| 233 | 233 | while i < 8 { |
|
| 234 | 234 | pushScope(tab); |
|
| 235 | 235 | define(tab, "x", i as i32 * 10); |
|
| 236 | - | i += 1; |
|
| 236 | + | set i += 1; |
|
| 237 | 237 | } |
|
| 238 | 238 | ||
| 239 | 239 | // x should be the innermost value. |
|
| 240 | 240 | let x = lookup(tab, "x") else { |
|
| 241 | 241 | return 1; |
|
| 242 | 242 | }; |
|
| 243 | 243 | assert x == 70; |
|
| 244 | 244 | ||
| 245 | 245 | // Pop scopes one by one and check. |
|
| 246 | - | i = 7; |
|
| 246 | + | set i = 7; |
|
| 247 | 247 | while i > 0 { |
|
| 248 | 248 | popScope(tab); |
|
| 249 | 249 | let val = lookup(tab, "x") else { |
|
| 250 | 250 | return 3; |
|
| 251 | 251 | }; |
|
| 252 | 252 | let expected = (i - 1) as i32 * 10; |
|
| 253 | 253 | assert val == expected; |
|
| 254 | - | i -= 1; |
|
| 254 | + | set i -= 1; |
|
| 255 | 255 | } |
|
| 256 | 256 | ||
| 257 | 257 | popScope(tab); |
|
| 258 | 258 | return 0; |
|
| 259 | 259 | } |
| 273 | 273 | ||
| 274 | 274 | // Verify all of them. |
|
| 275 | 275 | let mut sum: i32 = 0; |
|
| 276 | 276 | for name, i in names { |
|
| 277 | 277 | if let val = lookup(tab, name) { |
|
| 278 | - | sum += val; |
|
| 278 | + | set sum += val; |
|
| 279 | 279 | } else { |
|
| 280 | 280 | return 1; |
|
| 281 | 281 | } |
|
| 282 | 282 | } |
|
| 283 | 283 |
| 300 | 300 | while i < 10 { |
|
| 301 | 301 | let cur = lookup(tab, "counter") else { |
|
| 302 | 302 | return 1; |
|
| 303 | 303 | }; |
|
| 304 | 304 | assert update(tab, "counter", cur + 1); |
|
| 305 | - | i += 1; |
|
| 305 | + | set i += 1; |
|
| 306 | 306 | } |
|
| 307 | 307 | ||
| 308 | 308 | let finalVal = lookup(tab, "counter") else { |
|
| 309 | 309 | return 3; |
|
| 310 | 310 | }; |
| 378 | 378 | let result = lookup(tab, name); |
|
| 379 | 379 | if let exp = expected[i] { |
|
| 380 | 380 | // We expect a value. |
|
| 381 | 381 | if let r = result { |
|
| 382 | 382 | if r <> exp { |
|
| 383 | - | failures += 1; |
|
| 383 | + | set failures += 1; |
|
| 384 | 384 | } |
|
| 385 | 385 | } else { |
|
| 386 | - | failures += 1; |
|
| 386 | + | set failures += 1; |
|
| 387 | 387 | } |
|
| 388 | 388 | } else { |
|
| 389 | 389 | // We expect nil. |
|
| 390 | 390 | if let _ = result { |
|
| 391 | - | failures += 1; |
|
| 391 | + | set failures += 1; |
|
| 392 | 392 | } |
|
| 393 | 393 | } |
|
| 394 | 394 | } |
|
| 395 | 395 | ||
| 396 | 396 | if failures <> 0 { |
test/tests/prog.tokenizer.rad
+21 -21
| 86 | 86 | } |
|
| 87 | 87 | ||
| 88 | 88 | /// Advance the lexer by one character. |
|
| 89 | 89 | fn advance(lex: *mut Lexer) { |
|
| 90 | 90 | if lex.pos < lex.source.len { |
|
| 91 | - | lex.pos += 1; |
|
| 91 | + | set lex.pos += 1; |
|
| 92 | 92 | } |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | 95 | /// Skip whitespace characters. |
|
| 96 | 96 | fn skipWhitespace(lex: *mut Lexer) { |
| 101 | 101 | ||
| 102 | 102 | /// Scan a number literal. |
|
| 103 | 103 | fn scanNumber(lex: *mut Lexer) -> i32 { |
|
| 104 | 104 | let mut value: i32 = 0; |
|
| 105 | 105 | while let ch = peek(lex); isDigit(ch) { |
|
| 106 | - | value = value * 10 + (ch - 48) as i32; |
|
| 106 | + | set value = value * 10 + (ch - 48) as i32; |
|
| 107 | 107 | advance(lex); |
|
| 108 | 108 | } |
|
| 109 | 109 | return value; |
|
| 110 | 110 | } |
|
| 111 | 111 |
| 140 | 140 | match tok { |
|
| 141 | 141 | case Token::Invalid(_) => { |
|
| 142 | 142 | return false; |
|
| 143 | 143 | } |
|
| 144 | 144 | case Token::Eof => { |
|
| 145 | - | list.tokens[list.count] = tok; |
|
| 146 | - | list.count += 1; |
|
| 147 | - | done = true; |
|
| 145 | + | set list.tokens[list.count] = tok; |
|
| 146 | + | set list.count += 1; |
|
| 147 | + | set done = true; |
|
| 148 | 148 | } |
|
| 149 | 149 | else => { |
|
| 150 | 150 | if list.count >= list.tokens.len - 1 { |
|
| 151 | 151 | return false; |
|
| 152 | 152 | } |
|
| 153 | - | list.tokens[list.count] = tok; |
|
| 154 | - | list.count += 1; |
|
| 153 | + | set list.tokens[list.count] = tok; |
|
| 154 | + | set list.count += 1; |
|
| 155 | 155 | } |
|
| 156 | 156 | } |
|
| 157 | 157 | } |
|
| 158 | 158 | return true; |
|
| 159 | 159 | } |
|
| 160 | 160 | ||
| 161 | 161 | /// Allocate a new expression node. |
|
| 162 | 162 | fn newExpr(pool: *mut ExprPool, expr: Expr) -> u32 { |
|
| 163 | 163 | let idx = pool.count; |
|
| 164 | - | pool.nodes[idx] = expr; |
|
| 165 | - | pool.count += 1; |
|
| 164 | + | set pool.nodes[idx] = expr; |
|
| 165 | + | set pool.count += 1; |
|
| 166 | 166 | return idx; |
|
| 167 | 167 | } |
|
| 168 | 168 | ||
| 169 | 169 | /// Get the current token in the parser. |
|
| 170 | 170 | fn currentToken(p: *Parser) -> Token { |
| 175 | 175 | } |
|
| 176 | 176 | ||
| 177 | 177 | /// Advance the parser to the next token. |
|
| 178 | 178 | fn advanceParser(p: *mut Parser) { |
|
| 179 | 179 | if p.pos < p.tokenCount { |
|
| 180 | - | p.pos += 1; |
|
| 180 | + | set p.pos += 1; |
|
| 181 | 181 | } |
|
| 182 | 182 | } |
|
| 183 | 183 | ||
| 184 | 184 | /// Parse a primary expression (number, parenthesized expression, or unary minus). |
|
| 185 | 185 | fn parsePrimary(p: *mut Parser) -> ?u32 { |
| 230 | 230 | let tok = currentToken(p); |
|
| 231 | 231 | match tok { |
|
| 232 | 232 | case Token::Star => { |
|
| 233 | 233 | advanceParser(p); |
|
| 234 | 234 | if let right = parsePrimary(p) { |
|
| 235 | - | result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 42, left: result, right })); |
|
| 235 | + | set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 42, left: result, right })); |
|
| 236 | 236 | } else { |
|
| 237 | - | cont = false; |
|
| 237 | + | set cont = false; |
|
| 238 | 238 | } |
|
| 239 | 239 | } |
|
| 240 | 240 | case Token::Slash => { |
|
| 241 | 241 | advanceParser(p); |
|
| 242 | 242 | if let right = parsePrimary(p) { |
|
| 243 | - | result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 47, left: result, right })); |
|
| 243 | + | set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 47, left: result, right })); |
|
| 244 | 244 | } else { |
|
| 245 | - | cont = false; |
|
| 245 | + | set cont = false; |
|
| 246 | 246 | } |
|
| 247 | 247 | } |
|
| 248 | 248 | else => { |
|
| 249 | - | cont = false; |
|
| 249 | + | set cont = false; |
|
| 250 | 250 | } |
|
| 251 | 251 | } |
|
| 252 | 252 | } |
|
| 253 | 253 | return result; |
|
| 254 | 254 | } |
| 263 | 263 | match tok { |
|
| 264 | 264 | case Token::Plus => { |
|
| 265 | 265 | advanceParser(p); |
|
| 266 | 266 | if let right = parsePrimary(p) { |
|
| 267 | 267 | let rhs = parseMulDiv(p, right); |
|
| 268 | - | result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 43, left: result, right: rhs })); |
|
| 268 | + | set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 43, left: result, right: rhs })); |
|
| 269 | 269 | } else { |
|
| 270 | - | cont = false; |
|
| 270 | + | set cont = false; |
|
| 271 | 271 | } |
|
| 272 | 272 | } |
|
| 273 | 273 | case Token::Minus => { |
|
| 274 | 274 | advanceParser(p); |
|
| 275 | 275 | if let right = parsePrimary(p) { |
|
| 276 | 276 | let rhs = parseMulDiv(p, right); |
|
| 277 | - | result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 45, left: result, right: rhs })); |
|
| 277 | + | set result = newExpr(p.pool, Expr::BinOp(BinOpData { op: 45, left: result, right: rhs })); |
|
| 278 | 278 | } else { |
|
| 279 | - | cont = false; |
|
| 279 | + | set cont = false; |
|
| 280 | 280 | } |
|
| 281 | 281 | } |
|
| 282 | 282 | else => { |
|
| 283 | - | cont = false; |
|
| 283 | + | set cont = false; |
|
| 284 | 284 | } |
|
| 285 | 285 | } |
|
| 286 | 286 | } |
|
| 287 | 287 | return result; |
|
| 288 | 288 | } |
| 444 | 444 | let mut numCount: u32 = 0; |
|
| 445 | 445 | let slice = &tokenBuf[0..list.count]; |
|
| 446 | 446 | for tok in slice { |
|
| 447 | 447 | match tok { |
|
| 448 | 448 | case Token::Number(_) => { |
|
| 449 | - | numCount += 1; |
|
| 449 | + | set numCount += 1; |
|
| 450 | 450 | } |
|
| 451 | 451 | else => {} |
|
| 452 | 452 | } |
|
| 453 | 453 | } |
|
| 454 | 454 | assert numCount == 3; |
test/tests/prog.vm.rad
+117 -117
| 85 | 85 | /// Push a value onto the stack. |
|
| 86 | 86 | fn push(vm: *mut VM, value: i32) throws (VmError) { |
|
| 87 | 87 | if vm.sp >= MAX_STACK { |
|
| 88 | 88 | throw VmError::StackOverflow; |
|
| 89 | 89 | } |
|
| 90 | - | vm.stack[vm.sp] = value; |
|
| 91 | - | vm.sp += 1; |
|
| 90 | + | set vm.stack[vm.sp] = value; |
|
| 91 | + | set vm.sp += 1; |
|
| 92 | 92 | } |
|
| 93 | 93 | ||
| 94 | 94 | /// Pop a value from the stack. |
|
| 95 | 95 | fn pop(vm: *mut VM) -> i32 throws (VmError) { |
|
| 96 | 96 | if vm.sp == 0 { |
|
| 97 | 97 | throw VmError::StackUnderflow; |
|
| 98 | 98 | } |
|
| 99 | - | vm.sp -= 1; |
|
| 99 | + | set vm.sp -= 1; |
|
| 100 | 100 | return vm.stack[vm.sp]; |
|
| 101 | 101 | } |
|
| 102 | 102 | ||
| 103 | 103 | /// Peek at the top of the stack without removing. |
|
| 104 | 104 | fn peek(vm: *VM) -> i32 throws (VmError) { |
| 110 | 110 | ||
| 111 | 111 | /// Execute the bytecode program. |
|
| 112 | 112 | fn execute(vm: *mut VM) -> i32 throws (VmError) { |
|
| 113 | 113 | while vm.pc < vm.codeLen { |
|
| 114 | 114 | let instr = vm.code[vm.pc]; |
|
| 115 | - | vm.pc += 1; |
|
| 115 | + | set vm.pc += 1; |
|
| 116 | 116 | ||
| 117 | 117 | match instr { |
|
| 118 | 118 | case Op::Push(val) => { |
|
| 119 | 119 | try push(vm, val); |
|
| 120 | 120 | } |
| 144 | 144 | case Op::Eq => { |
|
| 145 | 145 | let b = try pop(vm); |
|
| 146 | 146 | let a = try pop(vm); |
|
| 147 | 147 | let mut result: i32 = 0; |
|
| 148 | 148 | if a == b { |
|
| 149 | - | result = 1; |
|
| 149 | + | set result = 1; |
|
| 150 | 150 | } |
|
| 151 | 151 | try push(vm, result); |
|
| 152 | 152 | } |
|
| 153 | 153 | case Op::Lt => { |
|
| 154 | 154 | let b = try pop(vm); |
|
| 155 | 155 | let a = try pop(vm); |
|
| 156 | 156 | let mut result: i32 = 0; |
|
| 157 | 157 | if a < b { |
|
| 158 | - | result = 1; |
|
| 158 | + | set result = 1; |
|
| 159 | 159 | } |
|
| 160 | 160 | try push(vm, result); |
|
| 161 | 161 | } |
|
| 162 | 162 | case Op::Gt => { |
|
| 163 | 163 | let b = try pop(vm); |
|
| 164 | 164 | let a = try pop(vm); |
|
| 165 | 165 | let mut result: i32 = 0; |
|
| 166 | 166 | if a > b { |
|
| 167 | - | result = 1; |
|
| 167 | + | set result = 1; |
|
| 168 | 168 | } |
|
| 169 | 169 | try push(vm, result); |
|
| 170 | 170 | } |
|
| 171 | 171 | case Op::Neg => { |
|
| 172 | 172 | let a = try pop(vm); |
| 181 | 181 | } |
|
| 182 | 182 | case Op::Store(idx) => { |
|
| 183 | 183 | let val = try pop(vm); |
|
| 184 | 184 | let mut base: u32 = 0; |
|
| 185 | 185 | if vm.frameCount > 0 { |
|
| 186 | - | base = vm.frames[vm.frameCount - 1].localBase; |
|
| 186 | + | set base = vm.frames[vm.frameCount - 1].localBase; |
|
| 187 | 187 | } |
|
| 188 | - | vm.locals[base + idx] = val; |
|
| 188 | + | set vm.locals[base + idx] = val; |
|
| 189 | 189 | } |
|
| 190 | 190 | case Op::Load(idx) => { |
|
| 191 | 191 | let mut base: u32 = 0; |
|
| 192 | 192 | if vm.frameCount > 0 { |
|
| 193 | - | base = vm.frames[vm.frameCount - 1].localBase; |
|
| 193 | + | set base = vm.frames[vm.frameCount - 1].localBase; |
|
| 194 | 194 | } |
|
| 195 | 195 | let val = vm.locals[base + idx]; |
|
| 196 | 196 | try push(vm, val); |
|
| 197 | 197 | } |
|
| 198 | 198 | case Op::Jump(target) => { |
|
| 199 | - | vm.pc = target; |
|
| 199 | + | set vm.pc = target; |
|
| 200 | 200 | } |
|
| 201 | 201 | case Op::JumpIfZero(target) => { |
|
| 202 | 202 | let cond = try pop(vm); |
|
| 203 | 203 | if cond == 0 { |
|
| 204 | - | vm.pc = target; |
|
| 204 | + | set vm.pc = target; |
|
| 205 | 205 | } |
|
| 206 | 206 | } |
|
| 207 | 207 | case Op::Call(target) => { |
|
| 208 | 208 | if vm.frameCount >= MAX_FRAMES { |
|
| 209 | 209 | throw VmError::CallOverflow; |
|
| 210 | 210 | } |
|
| 211 | 211 | let mut base: u32 = 0; |
|
| 212 | 212 | if vm.frameCount > 0 { |
|
| 213 | - | base = vm.frames[vm.frameCount - 1].localBase + MAX_LOCALS; |
|
| 213 | + | set base = vm.frames[vm.frameCount - 1].localBase + MAX_LOCALS; |
|
| 214 | 214 | } |
|
| 215 | - | vm.frames[vm.frameCount] = Frame { returnAddr: vm.pc, localBase: base }; |
|
| 216 | - | vm.frameCount += 1; |
|
| 217 | - | vm.pc = target; |
|
| 215 | + | set vm.frames[vm.frameCount] = Frame { returnAddr: vm.pc, localBase: base }; |
|
| 216 | + | set vm.frameCount += 1; |
|
| 217 | + | set vm.pc = target; |
|
| 218 | 218 | } |
|
| 219 | 219 | case Op::Ret => { |
|
| 220 | 220 | if vm.frameCount == 0 { |
|
| 221 | 221 | throw VmError::InvalidPC; |
|
| 222 | 222 | } |
|
| 223 | - | vm.frameCount -= 1; |
|
| 224 | - | vm.pc = vm.frames[vm.frameCount].returnAddr; |
|
| 223 | + | set vm.frameCount -= 1; |
|
| 224 | + | set vm.pc = vm.frames[vm.frameCount].returnAddr; |
|
| 225 | 225 | } |
|
| 226 | 226 | case Op::Halt => { |
|
| 227 | 227 | return try pop(vm); |
|
| 228 | 228 | } |
|
| 229 | 229 | } |
| 257 | 257 | } |
|
| 258 | 258 | ||
| 259 | 259 | /// Test basic arithmetic: 3 + 4 * 2 = 11 |
|
| 260 | 260 | fn testArith(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 261 | 261 | let mut code: [Op; 8] = [Op::Halt; 8]; |
|
| 262 | - | code[0] = Op::Push(3); |
|
| 263 | - | code[1] = Op::Push(4); |
|
| 264 | - | code[2] = Op::Push(2); |
|
| 265 | - | code[3] = Op::Mul; |
|
| 266 | - | code[4] = Op::Add; |
|
| 267 | - | code[5] = Op::Halt; |
|
| 262 | + | set code[0] = Op::Push(3); |
|
| 263 | + | set code[1] = Op::Push(4); |
|
| 264 | + | set code[2] = Op::Push(2); |
|
| 265 | + | set code[3] = Op::Mul; |
|
| 266 | + | set code[4] = Op::Add; |
|
| 267 | + | set code[5] = Op::Halt; |
|
| 268 | 268 | ||
| 269 | 269 | let result: i32 = try! runProgram(&code[..], 6, stackBuf, localsBuf, framesBuf); |
|
| 270 | 270 | assert result == 11; |
|
| 271 | 271 | return 0; |
|
| 272 | 272 | } |
|
| 273 | 273 | ||
| 274 | 274 | /// Test local variables: x = 5, y = 7, push x + y. |
|
| 275 | 275 | fn testLocals(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 276 | 276 | let mut code: [Op; 16] = [Op::Halt; 16]; |
|
| 277 | - | code[0] = Op::Push(5); |
|
| 278 | - | code[1] = Op::Store(0); // x = 5 |
|
| 279 | - | code[2] = Op::Push(7); |
|
| 280 | - | code[3] = Op::Store(1); // y = 7 |
|
| 281 | - | code[4] = Op::Load(0); // push x |
|
| 282 | - | code[5] = Op::Load(1); // push y |
|
| 283 | - | code[6] = Op::Add; // x + y |
|
| 284 | - | code[7] = Op::Halt; |
|
| 277 | + | set code[0] = Op::Push(5); |
|
| 278 | + | set code[1] = Op::Store(0); // x = 5 |
|
| 279 | + | set code[2] = Op::Push(7); |
|
| 280 | + | set code[3] = Op::Store(1); // y = 7 |
|
| 281 | + | set code[4] = Op::Load(0); // push x |
|
| 282 | + | set code[5] = Op::Load(1); // push y |
|
| 283 | + | set code[6] = Op::Add; // x + y |
|
| 284 | + | set code[7] = Op::Halt; |
|
| 285 | 285 | ||
| 286 | 286 | let result: i32 = try! runProgram(&code[..], 8, stackBuf, localsBuf, framesBuf); |
|
| 287 | 287 | assert result == 12; |
|
| 288 | 288 | return 0; |
|
| 289 | 289 | } |
|
| 290 | 290 | ||
| 291 | 291 | /// Test conditional jump: if 3 > 2 then push 42 else push 99. |
|
| 292 | 292 | fn testConditional(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 293 | 293 | let mut code: [Op; 16] = [Op::Halt; 16]; |
|
| 294 | - | code[0] = Op::Push(3); |
|
| 295 | - | code[1] = Op::Push(2); |
|
| 296 | - | code[2] = Op::Gt; // 3 > 2 => 1 |
|
| 297 | - | code[3] = Op::JumpIfZero(6); // if false, jump to 6 |
|
| 298 | - | code[4] = Op::Push(42); // true branch |
|
| 299 | - | code[5] = Op::Jump(7); // skip false branch |
|
| 300 | - | code[6] = Op::Push(99); // false branch |
|
| 301 | - | code[7] = Op::Halt; |
|
| 294 | + | set code[0] = Op::Push(3); |
|
| 295 | + | set code[1] = Op::Push(2); |
|
| 296 | + | set code[2] = Op::Gt; // 3 > 2 => 1 |
|
| 297 | + | set code[3] = Op::JumpIfZero(6); // if false, jump to 6 |
|
| 298 | + | set code[4] = Op::Push(42); // true branch |
|
| 299 | + | set code[5] = Op::Jump(7); // skip false branch |
|
| 300 | + | set code[6] = Op::Push(99); // false branch |
|
| 301 | + | set code[7] = Op::Halt; |
|
| 302 | 302 | ||
| 303 | 303 | let result: i32 = try! runProgram(&code[..], 8, stackBuf, localsBuf, framesBuf); |
|
| 304 | 304 | assert result == 42; |
|
| 305 | 305 | return 0; |
|
| 306 | 306 | } |
|
| 307 | 307 | ||
| 308 | 308 | /// Test loop: sum 1..5 using jumps. |
|
| 309 | 309 | /// local[0] = counter (starts at 1), local[1] = sum (starts at 0). |
|
| 310 | 310 | fn testLoop(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 311 | 311 | let mut code: [Op; 32] = [Op::Halt; 32]; |
|
| 312 | - | code[0] = Op::Push(1); |
|
| 313 | - | code[1] = Op::Store(0); // counter = 1 |
|
| 314 | - | code[2] = Op::Push(0); |
|
| 315 | - | code[3] = Op::Store(1); // sum = 0 |
|
| 312 | + | set code[0] = Op::Push(1); |
|
| 313 | + | set code[1] = Op::Store(0); // counter = 1 |
|
| 314 | + | set code[2] = Op::Push(0); |
|
| 315 | + | set code[3] = Op::Store(1); // sum = 0 |
|
| 316 | 316 | // Loop start (pc = 4): |
|
| 317 | - | code[4] = Op::Load(0); // push counter |
|
| 318 | - | code[5] = Op::Push(6); |
|
| 319 | - | code[6] = Op::Lt; // counter < 6 |
|
| 320 | - | code[7] = Op::JumpIfZero(17); // if false, exit loop |
|
| 321 | - | code[8] = Op::Load(1); // push sum |
|
| 322 | - | code[9] = Op::Load(0); // push counter |
|
| 323 | - | code[10] = Op::Add; // sum + counter |
|
| 324 | - | code[11] = Op::Store(1); // sum = sum + counter |
|
| 325 | - | code[12] = Op::Load(0); // push counter |
|
| 326 | - | code[13] = Op::Push(1); |
|
| 327 | - | code[14] = Op::Add; // counter + 1 |
|
| 328 | - | code[15] = Op::Store(0); // counter = counter + 1 |
|
| 329 | - | code[16] = Op::Jump(4); // back to loop start |
|
| 330 | - | code[17] = Op::Load(1); // push sum |
|
| 331 | - | code[18] = Op::Halt; |
|
| 317 | + | set code[4] = Op::Load(0); // push counter |
|
| 318 | + | set code[5] = Op::Push(6); |
|
| 319 | + | set code[6] = Op::Lt; // counter < 6 |
|
| 320 | + | set code[7] = Op::JumpIfZero(17); // if false, exit loop |
|
| 321 | + | set code[8] = Op::Load(1); // push sum |
|
| 322 | + | set code[9] = Op::Load(0); // push counter |
|
| 323 | + | set code[10] = Op::Add; // sum + counter |
|
| 324 | + | set code[11] = Op::Store(1); // sum = sum + counter |
|
| 325 | + | set code[12] = Op::Load(0); // push counter |
|
| 326 | + | set code[13] = Op::Push(1); |
|
| 327 | + | set code[14] = Op::Add; // counter + 1 |
|
| 328 | + | set code[15] = Op::Store(0); // counter = counter + 1 |
|
| 329 | + | set code[16] = Op::Jump(4); // back to loop start |
|
| 330 | + | set code[17] = Op::Load(1); // push sum |
|
| 331 | + | set code[18] = Op::Halt; |
|
| 332 | 332 | ||
| 333 | 333 | let result: i32 = try! runProgram(&code[..], 19, stackBuf, localsBuf, framesBuf); |
|
| 334 | 334 | // sum = 1+2+3+4+5 = 15 |
|
| 335 | 335 | assert result == 15; |
|
| 336 | 336 | return 0; |
| 339 | 339 | /// Test function call: call a function that computes n*2+1 for n=10. |
|
| 340 | 340 | fn testCall(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 341 | 341 | let mut code: [Op; 32] = [Op::Halt; 32]; |
|
| 342 | 342 | ||
| 343 | 343 | // Main: push argument on stack, call function, halt. |
|
| 344 | - | code[0] = Op::Push(10); // push argument |
|
| 345 | - | code[1] = Op::Call(5); // call function at 5 |
|
| 344 | + | set code[0] = Op::Push(10); // push argument |
|
| 345 | + | set code[1] = Op::Call(5); // call function at 5 |
|
| 346 | 346 | // After return, result is on stack. |
|
| 347 | - | code[2] = Op::Halt; |
|
| 348 | - | code[3] = Op::Halt; // padding |
|
| 349 | - | code[4] = Op::Halt; // padding |
|
| 347 | + | set code[2] = Op::Halt; |
|
| 348 | + | set code[3] = Op::Halt; // padding |
|
| 349 | + | set code[4] = Op::Halt; // padding |
|
| 350 | 350 | ||
| 351 | 351 | // Function at pc 5: |
|
| 352 | - | code[5] = Op::Store(0); // pop arg into local[0] |
|
| 353 | - | code[6] = Op::Load(0); // push local[0] |
|
| 354 | - | code[7] = Op::Push(2); |
|
| 355 | - | code[8] = Op::Mul; // n * 2 |
|
| 356 | - | code[9] = Op::Push(1); |
|
| 357 | - | code[10] = Op::Add; // n * 2 + 1 |
|
| 358 | - | code[11] = Op::Ret; // return (result on stack) |
|
| 352 | + | set code[5] = Op::Store(0); // pop arg into local[0] |
|
| 353 | + | set code[6] = Op::Load(0); // push local[0] |
|
| 354 | + | set code[7] = Op::Push(2); |
|
| 355 | + | set code[8] = Op::Mul; // n * 2 |
|
| 356 | + | set code[9] = Op::Push(1); |
|
| 357 | + | set code[10] = Op::Add; // n * 2 + 1 |
|
| 358 | + | set code[11] = Op::Ret; // return (result on stack) |
|
| 359 | 359 | ||
| 360 | 360 | let result: i32 = try! runProgram(&code[..], 12, stackBuf, localsBuf, framesBuf); |
|
| 361 | 361 | // 10 * 2 + 1 = 21 |
|
| 362 | 362 | assert result == 21; |
|
| 363 | 363 | return 0; |
|
| 364 | 364 | } |
|
| 365 | 365 | ||
| 366 | 366 | /// Test division by zero detection using try...catch with error binding. |
|
| 367 | 367 | fn testDivByZero(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 368 | 368 | let mut code: [Op; 8] = [Op::Halt; 8]; |
|
| 369 | - | code[0] = Op::Push(42); |
|
| 370 | - | code[1] = Op::Push(0); |
|
| 371 | - | code[2] = Op::Div; |
|
| 372 | - | code[3] = Op::Halt; |
|
| 369 | + | set code[0] = Op::Push(42); |
|
| 370 | + | set code[1] = Op::Push(0); |
|
| 371 | + | set code[2] = Op::Div; |
|
| 372 | + | set code[3] = Op::Halt; |
|
| 373 | 373 | ||
| 374 | 374 | let mut caught: i32 = 0; |
|
| 375 | 375 | try runProgram(&code[..], 4, stackBuf, localsBuf, framesBuf) catch e { |
|
| 376 | 376 | if e == VmError::DivByZero { |
|
| 377 | - | caught = 1; |
|
| 377 | + | set caught = 1; |
|
| 378 | 378 | } else { |
|
| 379 | - | caught = 2; |
|
| 379 | + | set caught = 2; |
|
| 380 | 380 | } |
|
| 381 | 381 | }; |
|
| 382 | 382 | assert caught == 1; |
|
| 383 | 383 | return 0; |
|
| 384 | 384 | } |
|
| 385 | 385 | ||
| 386 | 386 | /// Test negation and equality. |
|
| 387 | 387 | fn testNegAndEq(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 388 | 388 | let mut code: [Op; 16] = [Op::Halt; 16]; |
|
| 389 | - | code[0] = Op::Push(5); |
|
| 390 | - | code[1] = Op::Neg; // -5 |
|
| 391 | - | code[2] = Op::Push(-5); |
|
| 392 | - | code[3] = Op::Eq; // -5 == -5 => 1 |
|
| 393 | - | code[4] = Op::Halt; |
|
| 389 | + | set code[0] = Op::Push(5); |
|
| 390 | + | set code[1] = Op::Neg; // -5 |
|
| 391 | + | set code[2] = Op::Push(-5); |
|
| 392 | + | set code[3] = Op::Eq; // -5 == -5 => 1 |
|
| 393 | + | set code[4] = Op::Halt; |
|
| 394 | 394 | ||
| 395 | 395 | let result: i32 = try! runProgram(&code[..], 5, stackBuf, localsBuf, framesBuf); |
|
| 396 | 396 | assert result == 1; |
|
| 397 | 397 | return 0; |
|
| 398 | 398 | } |
| 400 | 400 | /// Test factorial using recursive calls: fact(6) = 720. |
|
| 401 | 401 | fn testFactorial(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 402 | 402 | let mut code: [Op; 32] = [Op::Halt; 32]; |
|
| 403 | 403 | ||
| 404 | 404 | // Main: push 6, call fact, halt. |
|
| 405 | - | code[0] = Op::Push(6); |
|
| 406 | - | code[1] = Op::Call(4); // call fact at 4 |
|
| 407 | - | code[2] = Op::Halt; |
|
| 408 | - | code[3] = Op::Halt; // padding |
|
| 405 | + | set code[0] = Op::Push(6); |
|
| 406 | + | set code[1] = Op::Call(4); // call fact at 4 |
|
| 407 | + | set code[2] = Op::Halt; |
|
| 408 | + | set code[3] = Op::Halt; // padding |
|
| 409 | 409 | ||
| 410 | 410 | // fact(n) at pc 4: |
|
| 411 | 411 | // Store arg to local[0] |
|
| 412 | 412 | // If n <= 1, push 1, return |
|
| 413 | 413 | // Else push n, push fact(n-1), multiply, return |
|
| 414 | - | code[4] = Op::Store(0); // local[0] = n |
|
| 415 | - | code[5] = Op::Load(0); // push n |
|
| 416 | - | code[6] = Op::Push(2); |
|
| 417 | - | code[7] = Op::Lt; // n < 2 |
|
| 418 | - | code[8] = Op::JumpIfZero(11); // if n >= 2, skip |
|
| 419 | - | code[9] = Op::Push(1); // base case: push 1 |
|
| 420 | - | code[10] = Op::Ret; |
|
| 414 | + | set code[4] = Op::Store(0); // local[0] = n |
|
| 415 | + | set code[5] = Op::Load(0); // push n |
|
| 416 | + | set code[6] = Op::Push(2); |
|
| 417 | + | set code[7] = Op::Lt; // n < 2 |
|
| 418 | + | set code[8] = Op::JumpIfZero(11); // if n >= 2, skip |
|
| 419 | + | set code[9] = Op::Push(1); // base case: push 1 |
|
| 420 | + | set code[10] = Op::Ret; |
|
| 421 | 421 | ||
| 422 | 422 | // Recursive case: |
|
| 423 | - | code[11] = Op::Load(0); // push n |
|
| 424 | - | code[12] = Op::Push(1); |
|
| 425 | - | code[13] = Op::Sub; // n - 1 |
|
| 426 | - | code[14] = Op::Call(4); // fact(n-1) |
|
| 427 | - | code[15] = Op::Load(0); // push n |
|
| 428 | - | code[16] = Op::Mul; // fact(n-1) * n |
|
| 429 | - | code[17] = Op::Ret; |
|
| 423 | + | set code[11] = Op::Load(0); // push n |
|
| 424 | + | set code[12] = Op::Push(1); |
|
| 425 | + | set code[13] = Op::Sub; // n - 1 |
|
| 426 | + | set code[14] = Op::Call(4); // fact(n-1) |
|
| 427 | + | set code[15] = Op::Load(0); // push n |
|
| 428 | + | set code[16] = Op::Mul; // fact(n-1) * n |
|
| 429 | + | set code[17] = Op::Ret; |
|
| 430 | 430 | ||
| 431 | 431 | let result: i32 = try! runProgram(&code[..], 18, stackBuf, localsBuf, framesBuf); |
|
| 432 | 432 | assert result == 720; |
|
| 433 | 433 | return 0; |
|
| 434 | 434 | } |
|
| 435 | 435 | ||
| 436 | 436 | /// Test dup instruction. |
|
| 437 | 437 | fn testDup(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 438 | 438 | let mut code: [Op; 8] = [Op::Halt; 8]; |
|
| 439 | - | code[0] = Op::Push(7); |
|
| 440 | - | code[1] = Op::Dup; |
|
| 441 | - | code[2] = Op::Add; // 7 + 7 = 14 |
|
| 442 | - | code[3] = Op::Halt; |
|
| 439 | + | set code[0] = Op::Push(7); |
|
| 440 | + | set code[1] = Op::Dup; |
|
| 441 | + | set code[2] = Op::Add; // 7 + 7 = 14 |
|
| 442 | + | set code[3] = Op::Halt; |
|
| 443 | 443 | ||
| 444 | 444 | let result: i32 = try! runProgram(&code[..], 4, stackBuf, localsBuf, framesBuf); |
|
| 445 | 445 | assert result == 14; |
|
| 446 | 446 | return 0; |
|
| 447 | 447 | } |
|
| 448 | 448 | ||
| 449 | 449 | /// Test stack underflow detection using try...catch with error binding. |
|
| 450 | 450 | fn testStackUnderflow(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 451 | 451 | let mut code: [Op; 4] = [Op::Halt; 4]; |
|
| 452 | - | code[0] = Op::Add; // nothing on stack |
|
| 453 | - | code[1] = Op::Halt; |
|
| 452 | + | set code[0] = Op::Add; // nothing on stack |
|
| 453 | + | set code[1] = Op::Halt; |
|
| 454 | 454 | ||
| 455 | 455 | let mut caught: i32 = 0; |
|
| 456 | 456 | try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e { |
|
| 457 | 457 | if e == VmError::StackUnderflow { |
|
| 458 | - | caught = 1; |
|
| 458 | + | set caught = 1; |
|
| 459 | 459 | } else { |
|
| 460 | - | caught = 2; |
|
| 460 | + | set caught = 2; |
|
| 461 | 461 | } |
|
| 462 | 462 | }; |
|
| 463 | 463 | assert caught == 1; |
|
| 464 | 464 | return 0; |
|
| 465 | 465 | } |
|
| 466 | 466 | ||
| 467 | 467 | /// Test that try...catch on success path does not execute catch block. |
|
| 468 | 468 | fn testSuccessNoCatch(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 469 | 469 | let mut code: [Op; 4] = [Op::Halt; 4]; |
|
| 470 | - | code[0] = Op::Push(99); |
|
| 471 | - | code[1] = Op::Halt; |
|
| 470 | + | set code[0] = Op::Push(99); |
|
| 471 | + | set code[1] = Op::Halt; |
|
| 472 | 472 | ||
| 473 | 473 | let mut caught: i32 = 0; |
|
| 474 | 474 | let result: i32 = try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e { |
|
| 475 | - | caught = 1; |
|
| 475 | + | set caught = 1; |
|
| 476 | 476 | return 1; |
|
| 477 | 477 | }; |
|
| 478 | 478 | // Catch block should not have run. |
|
| 479 | 479 | assert caught == 0; |
|
| 480 | 480 | // Should have the success value. |
| 484 | 484 | ||
| 485 | 485 | /// Test call overflow detection by exhausting frames. |
|
| 486 | 486 | fn testCallOverflow(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 487 | 487 | let mut code: [Op; 4] = [Op::Halt; 4]; |
|
| 488 | 488 | // Infinite recursion: function calls itself. |
|
| 489 | - | code[0] = Op::Call(0); |
|
| 490 | - | code[1] = Op::Halt; |
|
| 489 | + | set code[0] = Op::Call(0); |
|
| 490 | + | set code[1] = Op::Halt; |
|
| 491 | 491 | ||
| 492 | 492 | let mut caught: i32 = 0; |
|
| 493 | 493 | try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch e { |
|
| 494 | 494 | if e == VmError::CallOverflow { |
|
| 495 | - | caught = 1; |
|
| 495 | + | set caught = 1; |
|
| 496 | 496 | } else { |
|
| 497 | - | caught = 2; |
|
| 497 | + | set caught = 2; |
|
| 498 | 498 | } |
|
| 499 | 499 | }; |
|
| 500 | 500 | assert caught == 1; |
|
| 501 | 501 | return 0; |
|
| 502 | 502 | } |
|
| 503 | 503 | ||
| 504 | 504 | /// Test that catch with no binding works (discard the error). |
|
| 505 | 505 | fn testCatchNoBinding(stackBuf: *mut [i32], localsBuf: *mut [i32], framesBuf: *mut [Frame]) -> i32 { |
|
| 506 | 506 | let mut code: [Op; 4] = [Op::Halt; 4]; |
|
| 507 | - | code[0] = Op::Pop; // underflow |
|
| 508 | - | code[1] = Op::Halt; |
|
| 507 | + | set code[0] = Op::Pop; // underflow |
|
| 508 | + | set code[1] = Op::Halt; |
|
| 509 | 509 | ||
| 510 | 510 | // Catch without binding - just swallow the error. |
|
| 511 | 511 | try runProgram(&code[..], 2, stackBuf, localsBuf, framesBuf) catch {}; |
|
| 512 | 512 | return 0; |
|
| 513 | 513 | } |
test/tests/ptr.assign.rad
+1 -1
| 1 | 1 | //! returns: 42 |
|
| 2 | 2 | @default fn main() -> i32 { |
|
| 3 | 3 | let mut x: i32 = 1; |
|
| 4 | 4 | let mut ptr: *mut i32 = &mut x; |
|
| 5 | 5 | ||
| 6 | - | *ptr = 42; |
|
| 6 | + | set *ptr = 42; |
|
| 7 | 7 | ||
| 8 | 8 | return x; |
|
| 9 | 9 | } |
test/tests/ptr.mutate.rad
+3 -3
| 1 | 1 | //! returns: 42 |
|
| 2 | 2 | ||
| 3 | 3 | fn mutate1(ptr: *mut i32) { |
|
| 4 | - | *ptr = 39; |
|
| 4 | + | set *ptr = 39; |
|
| 5 | 5 | } |
|
| 6 | 6 | ||
| 7 | 7 | fn mutate2(ptr: *mut i32) { |
|
| 8 | - | *ptr += 2; |
|
| 9 | - | *ptr += 1; |
|
| 8 | + | set *ptr += 2; |
|
| 9 | + | set *ptr += 1; |
|
| 10 | 10 | } |
|
| 11 | 11 | ||
| 12 | 12 | @default fn main() -> i32 { |
|
| 13 | 13 | let mut ptr: i32 = 0; |
|
| 14 | 14 |
test/tests/ptr.opaque.rad
+1 -1
| 37 | 37 | fn testNullableOpaque() -> bool { |
|
| 38 | 38 | let mut opt: ?*opaque = nil; |
|
| 39 | 39 | if opt == nil { |
|
| 40 | 40 | let x: u32 = 42; |
|
| 41 | 41 | let ptr: *u8 = &x as *u8; |
|
| 42 | - | opt = ptr; // Automatic coercion in assignment. |
|
| 42 | + | set opt = ptr; // Automatic coercion in assignment. |
|
| 43 | 43 | ||
| 44 | 44 | if let p = opt { |
|
| 45 | 45 | return p as *u8 == ptr; |
|
| 46 | 46 | } |
|
| 47 | 47 | } |
test/tests/ptr.subscript.assign.rad
+1 -1
| 1 | 1 | /// Writes to a slice element through subscript. |
|
| 2 | 2 | fn subscriptAssign(arr: *mut [i32], idx: u32, val: i32) { |
|
| 3 | - | arr[idx] = val; |
|
| 3 | + | set arr[idx] = val; |
|
| 4 | 4 | } |
test/tests/record.array.elements.rad
+7 -7
| 12 | 12 | fn vectorSum(vec: Vector) -> i32 { |
|
| 13 | 13 | let mut sum: i32 = 0; |
|
| 14 | 14 | let mut i: u32 = 0; |
|
| 15 | 15 | ||
| 16 | 16 | while (i < vec.data.len) { |
|
| 17 | - | sum += vec.data[i]; |
|
| 18 | - | i += 1; |
|
| 17 | + | set sum += vec.data[i]; |
|
| 18 | + | set i += 1; |
|
| 19 | 19 | } |
|
| 20 | 20 | return sum; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | fn vectorScale(vec: Vector, scale: i32) -> Vector { |
|
| 24 | 24 | let mut result: Vector = Vector { data: [0, 0, 0, 0] }; |
|
| 25 | 25 | let mut i: u32 = 0; |
|
| 26 | 26 | ||
| 27 | 27 | while (i < vec.data.len) { |
|
| 28 | - | result.data[i] = vec.data[i] * scale; |
|
| 29 | - | i += 1; |
|
| 28 | + | set result.data[i] = vec.data[i] * scale; |
|
| 29 | + | set i += 1; |
|
| 30 | 30 | } |
|
| 31 | 31 | return result; |
|
| 32 | 32 | } |
|
| 33 | 33 | ||
| 34 | 34 | // Sum of the diagonal elements. |
|
| 35 | 35 | fn matrixTrace(mat: Matrix) -> i32 { |
|
| 36 | 36 | let mut sum: i32 = 0; |
|
| 37 | 37 | let mut i: u32 = 0; |
|
| 38 | 38 | ||
| 39 | 39 | while (i < mat.rows.len) { |
|
| 40 | - | sum += mat.rows[i].data[i]; |
|
| 41 | - | i += 1; |
|
| 40 | + | set sum += mat.rows[i].data[i]; |
|
| 41 | + | set i += 1; |
|
| 42 | 42 | } |
|
| 43 | 43 | return sum; |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | @default fn main() -> i32 { |
| 60 | 60 | // Sum of v2: 2 + 4 + 6 + 8 = 20. |
|
| 61 | 61 | let mut sumV2: i32 = vectorSum(v2); |
|
| 62 | 62 | // Trace of matrix: 10 + 15 + 20 = 45. |
|
| 63 | 63 | let mut trace: i32 = matrixTrace(m1); |
|
| 64 | 64 | // Modify element in the matrix. |
|
| 65 | - | m1.rows[0].data[0] = m1.rows[0].data[0] - 5; // 10 - 5 = 5 |
|
| 65 | + | set m1.rows[0].data[0] = m1.rows[0].data[0] - 5; // 10 - 5 = 5 |
|
| 66 | 66 | // Calculate new trace: 5 + 15 + 20 = 40. |
|
| 67 | 67 | let mut newTrace: i32 = matrixTrace(m1); |
|
| 68 | 68 | ||
| 69 | 69 | // Return combined results: 10 + 20 + 45 + 40 = 115. |
|
| 70 | 70 | return sumV1 + sumV2 + trace + newTrace; |
test/tests/record.assign.blit.rad
+1 -1
| 1 | 1 | record Point { x: i32, y: i32 } |
|
| 2 | 2 | ||
| 3 | 3 | fn copy() { |
|
| 4 | 4 | let p = Point { x: 1, y: 2 }; |
|
| 5 | 5 | let mut q = p; |
|
| 6 | - | q = p; |
|
| 6 | + | set q = p; |
|
| 7 | 7 | } |
test/tests/record.copy.rad
+16 -16
| 15 | 15 | return s; |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | fn func1(s: S) -> i32 { |
|
| 19 | 19 | let mut m: S = s; |
|
| 20 | - | m.x = 112; |
|
| 21 | - | m.y = 582; |
|
| 22 | - | m.z = 281; |
|
| 20 | + | set m.x = 112; |
|
| 21 | + | set m.y = 582; |
|
| 22 | + | set m.z = 281; |
|
| 23 | 23 | ||
| 24 | 24 | assert m.x == 112; |
|
| 25 | 25 | assert m.y == 582; |
|
| 26 | 26 | assert m.z == 281; |
|
| 27 | 27 | return 0; |
| 31 | 31 | let p: i32 = 0; |
|
| 32 | 32 | let mut t: S = s; |
|
| 33 | 33 | let q: i32 = 0; |
|
| 34 | 34 | let mut u: S = s; |
|
| 35 | 35 | ||
| 36 | - | t.x = 12; |
|
| 37 | - | u.x = 13; |
|
| 38 | - | t.y = 52; |
|
| 39 | - | u.y = 54; |
|
| 40 | - | t.z = 21; |
|
| 41 | - | u.z = 25; |
|
| 36 | + | set t.x = 12; |
|
| 37 | + | set u.x = 13; |
|
| 38 | + | set t.y = 52; |
|
| 39 | + | set u.y = 54; |
|
| 40 | + | set t.z = 21; |
|
| 41 | + | set u.z = 25; |
|
| 42 | 42 | ||
| 43 | 43 | assert t.x == 12; |
|
| 44 | 44 | assert t.y == 52; |
|
| 45 | 45 | assert t.z == 21; |
|
| 46 | 46 | assert u.x == 13; |
| 51 | 51 | ||
| 52 | 52 | fn func3(s: S) -> i32 { |
|
| 53 | 53 | let mut a: [S; 4] = [s; 4]; |
|
| 54 | 54 | let mut t: S = s; |
|
| 55 | 55 | ||
| 56 | - | t.x = 12; |
|
| 57 | - | t.y = 13; |
|
| 58 | - | t.z = 52; |
|
| 56 | + | set t.x = 12; |
|
| 57 | + | set t.y = 13; |
|
| 58 | + | set t.z = 52; |
|
| 59 | 59 | ||
| 60 | - | a[1] = t; |
|
| 61 | - | a[3] = a[1]; |
|
| 60 | + | set a[1] = t; |
|
| 61 | + | set a[3] = a[1]; |
|
| 62 | 62 | ||
| 63 | 63 | assert a[0].x == 561; |
|
| 64 | 64 | assert a[0].y == 938; |
|
| 65 | 65 | assert a[0].z == 102; |
|
| 66 | 66 | assert a[1].x == 12; |
| 71 | 71 | return 0; |
|
| 72 | 72 | } |
|
| 73 | 73 | ||
| 74 | 74 | fn func4(s: S) -> i32 { |
|
| 75 | 75 | let mut a: [S; 2] = undefined; |
|
| 76 | - | a[0] = s; |
|
| 76 | + | set a[0] = s; |
|
| 77 | 77 | ||
| 78 | 78 | assert a[0].x == 561; |
|
| 79 | 79 | assert a[0].y == 938; |
|
| 80 | 80 | assert a[0].z == 102; |
|
| 81 | 81 | return 0; |
|
| 82 | 82 | } |
|
| 83 | 83 | ||
| 84 | 84 | fn func5(s: S) -> i32 { |
|
| 85 | 85 | let mut a: [S; 2] = undefined; |
|
| 86 | 86 | let t: S = makeS(s.x, s.y, s.z); |
|
| 87 | - | a[0] = t; |
|
| 87 | + | set a[0] = t; |
|
| 88 | 88 | ||
| 89 | 89 | assert a[0].x == 561; |
|
| 90 | 90 | assert a[0].y == 938; |
|
| 91 | 91 | assert a[0].z == 102; |
|
| 92 | 92 | return 0; |
test/tests/record.field.assign.rad
+3 -3
| 3 | 3 | record Vector { x: i32, y: i32 } |
|
| 4 | 4 | ||
| 5 | 5 | @default fn main() -> i32 { |
|
| 6 | 6 | let mut v: Vector = Vector { x: 3, y: 2 }; |
|
| 7 | 7 | ||
| 8 | - | v.x = 40; |
|
| 9 | - | v.y = 1; |
|
| 10 | - | v.y *= 2; |
|
| 8 | + | set v.x = 40; |
|
| 9 | + | set v.y = 1; |
|
| 10 | + | set v.y *= 2; |
|
| 11 | 11 | ||
| 12 | 12 | return (v.x + v.y) - 42; |
|
| 13 | 13 | } |
test/tests/record.nested.calls.2.rad
+1 -1
| 16 | 16 | ||
| 17 | 17 | @default fn main() -> i32 { |
|
| 18 | 18 | let mut p: Point = Point { x: 3, y: 4 }; |
|
| 19 | 19 | let mut q: Point = Point { x: 5, y: 6 }; |
|
| 20 | 20 | ||
| 21 | - | p = add( |
|
| 21 | + | set p = add( |
|
| 22 | 22 | scale(p, 2), // (6, 8) |
|
| 23 | 23 | scale(q, 2) // (10, 12) |
|
| 24 | 24 | ); // (16, 20) |
|
| 25 | 25 | ||
| 26 | 26 | // p.x + p.y = 16 + 20 = 36 |
test/tests/record.ptr.mutate.rad
+2 -2
| 4 | 4 | x: i32, |
|
| 5 | 5 | y: i32, |
|
| 6 | 6 | } |
|
| 7 | 7 | ||
| 8 | 8 | fn mutate(p: *mut Point) { |
|
| 9 | - | p.x = 4; |
|
| 10 | - | p.y = 38; |
|
| 9 | + | set p.x = 4; |
|
| 10 | + | set p.y = 38; |
|
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | @default fn main() -> i32 { |
|
| 14 | 14 | let mut p: Point = Point { x: 0, y: 0 }; |
|
| 15 | 15 |
test/tests/record.unlabeled.deref.rad
+1 -1
| 71 | 71 | return 9; |
|
| 72 | 72 | } |
|
| 73 | 73 | ||
| 74 | 74 | // Assignment through deref on mutable binding. |
|
| 75 | 75 | let mut m: Wrap = Wrap(0); |
|
| 76 | - | *m = 77; |
|
| 76 | + | set *m = 77; |
|
| 77 | 77 | if *m <> 77 { |
|
| 78 | 78 | return 10; |
|
| 79 | 79 | } |
|
| 80 | 80 | ||
| 81 | 81 | return 0; |
test/tests/ref.if.bug.rad
+1 -1
| 3 | 3 | //! |
|
| 4 | 4 | //! When `&mut var` appears in only one branch of an if/else, the merge |
|
| 5 | 5 | //! block's phi merges the original integer value with a stack pointer. |
|
| 6 | 6 | ||
| 7 | 7 | fn store(ptr: *mut u32, val: u32) { |
|
| 8 | - | *ptr = val; |
|
| 8 | + | set *ptr = val; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | fn testIfBranch(cond: bool) -> u32 { |
|
| 12 | 12 | let mut val: u32 = 42; |
|
| 13 | 13 | if cond { |
test/tests/ref.immut.loop.bug.rad
+1 -1
| 13 | 13 | fn testZeroIter(n: u32) -> u32 { |
|
| 14 | 14 | let val: u32 = 42; |
|
| 15 | 15 | let mut i: u32 = 0; |
|
| 16 | 16 | while i < n { |
|
| 17 | 17 | let _ = read(&val); |
|
| 18 | - | i += 1; |
|
| 18 | + | set i += 1; |
|
| 19 | 19 | } |
|
| 20 | 20 | return val; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | @default fn main() -> i32 { |
test/tests/ref.mut.ptr.rad
+1 -1
| 1 | 1 | //! returns: 84 |
|
| 2 | 2 | //! Test mutable pointer references. |
|
| 3 | 3 | ||
| 4 | 4 | fn store(ptr: *mut i32) { |
|
| 5 | - | *ptr = 42; |
|
| 5 | + | set *ptr = 42; |
|
| 6 | 6 | } |
|
| 7 | 7 | ||
| 8 | 8 | @default fn main() -> i32 { |
|
| 9 | 9 | let mut a: i32 = 0; |
|
| 10 | 10 | let p: *mut i32 = &mut a; |
test/tests/reserve.loop.rad
+2 -2
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut total: i32 = 0; |
|
| 6 | 6 | let mut i: i32 = 0; |
|
| 7 | 7 | while i < 10000 { |
|
| 8 | 8 | let p: Pair = Pair { a: i, b: i + 1 }; |
|
| 9 | - | total += p.a + p.b; |
|
| 10 | - | i += 1; |
|
| 9 | + | set total += p.a + p.b; |
|
| 10 | + | set i += 1; |
|
| 11 | 11 | } |
|
| 12 | 12 | // Expected: sum(i) + sum(i+1) for i=0..9999 |
|
| 13 | 13 | // = 2 * 9999*10000/2 + 10000 = 99990000 + 10000 = 100000000 |
|
| 14 | 14 | assert total == 100000000; |
|
| 15 | 15 | return 0; |
test/tests/result.void.success.rad
+1 -1
| 27 | 27 | return (2) - 42; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | // Try the error path too. |
|
| 31 | 31 | try voidError() catch { |
|
| 32 | - | guard = 99; |
|
| 32 | + | set guard = 99; |
|
| 33 | 33 | }; |
|
| 34 | 34 | ||
| 35 | 35 | if guard <> 99 { |
|
| 36 | 36 | return (3) - 42; |
|
| 37 | 37 | } |
test/tests/slice.alloc.loop.rad
+1 -1
| 13 | 13 | fn initSlice(buf: *mut [u8], count: u32) -> i32 { |
|
| 14 | 14 | let s = makeSlice(buf, count); |
|
| 15 | 15 | ||
| 16 | 16 | // This loop pattern matches createBlock's vars initialization. |
|
| 17 | 17 | for i in 0..s.len { |
|
| 18 | - | s[i] = 0; |
|
| 18 | + | set s[i] = 0; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | return s.len as i32; |
|
| 22 | 22 | } |
|
| 23 | 23 |
test/tests/slice.append.rad
+5 -5
| 16 | 16 | let newOffset = aligned + size; |
|
| 17 | 17 | ||
| 18 | 18 | assert newOffset <= arena.data.len as u32; |
|
| 19 | 19 | ||
| 20 | 20 | let base: *mut u8 = &mut arena.data[aligned]; |
|
| 21 | - | arena.offset = newOffset; |
|
| 21 | + | set arena.offset = newOffset; |
|
| 22 | 22 | ||
| 23 | 23 | return base as *mut opaque; |
|
| 24 | 24 | } |
|
| 25 | 25 | ||
| 26 | 26 | /// Allocator record matching the compiler's expected layout. |
| 119 | 119 | } |
|
| 120 | 120 | ||
| 121 | 121 | // Sum all elements in nums. |
|
| 122 | 122 | let mut sum: i32 = 0; |
|
| 123 | 123 | for n in nums { |
|
| 124 | - | sum += n; |
|
| 124 | + | set sum += n; |
|
| 125 | 125 | } |
|
| 126 | 126 | if sum <> 150 { |
|
| 127 | 127 | return 16; |
|
| 128 | 128 | } |
|
| 129 | 129 |
| 163 | 163 | // Test that .append() returns the slice, allowing rebinding. |
|
| 164 | 164 | let ptr2 = arenaAlloc(&mut arena, @sizeOf(i32) * 2, @alignOf(i32)); |
|
| 165 | 165 | let mut vals = @sliceOf(ptr2 as *mut i32, 0, 2); |
|
| 166 | 166 | ||
| 167 | 167 | // Append within capacity, rebind via return value. |
|
| 168 | - | vals = vals.append(42, a); |
|
| 168 | + | set vals = vals.append(42, a); |
|
| 169 | 169 | assert vals.len == 1; |
|
| 170 | 170 | assert vals[0] == 42; |
|
| 171 | 171 | ||
| 172 | - | vals = vals.append(43, a); |
|
| 172 | + | set vals = vals.append(43, a); |
|
| 173 | 173 | assert vals.len == 2; |
|
| 174 | 174 | ||
| 175 | 175 | // Append past capacity -- triggers growth and returns updated slice. |
|
| 176 | 176 | let oldPtr = &vals[0] as *opaque; |
|
| 177 | - | vals = vals.append(44, a); |
|
| 177 | + | set vals = vals.append(44, a); |
|
| 178 | 178 | assert vals.len == 3; |
|
| 179 | 179 | assert vals.cap == 5; |
|
| 180 | 180 | ||
| 181 | 181 | // After growth, the data pointer should have changed. |
|
| 182 | 182 | let newPtr = &vals[0] as *opaque; |
test/tests/slice.assign.mismatch.rad
+1 -1
| 2 | 2 | //! Test that slice copy with mismatched lengths traps. |
|
| 3 | 3 | ||
| 4 | 4 | @default fn main() -> i32 { |
|
| 5 | 5 | let mut dst: [i32; 4] = [0, 0, 0, 0]; |
|
| 6 | 6 | let src: [i32; 2] = [1, 2]; |
|
| 7 | - | dst[..] = &src[..]; |
|
| 7 | + | set dst[..] = &src[..]; |
|
| 8 | 8 | return 0; |
|
| 9 | 9 | } |
test/tests/slice.assign.rad
+9 -9
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | ||
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | // Fill entire array. |
|
| 5 | 5 | let mut a: [i32; 4] = [1, 2, 3, 4]; |
|
| 6 | - | a[..] = 0; |
|
| 6 | + | set a[..] = 0; |
|
| 7 | 7 | assert a == [0, 0, 0, 0]; |
|
| 8 | 8 | ||
| 9 | 9 | // Fill sub-range of array. |
|
| 10 | 10 | let mut b: [i32; 4] = [1, 2, 3, 4]; |
|
| 11 | - | b[1..3] = 99; |
|
| 11 | + | set b[1..3] = 99; |
|
| 12 | 12 | assert b == [1, 99, 99, 4]; |
|
| 13 | 13 | ||
| 14 | 14 | // Fill mutable slice. |
|
| 15 | 15 | let mut c: [i32; 4] = [10, 20, 30, 40]; |
|
| 16 | 16 | let cs: *mut [i32] = &mut c[..]; |
|
| 17 | - | cs[..] = 7; |
|
| 17 | + | set cs[..] = 7; |
|
| 18 | 18 | assert c == [7, 7, 7, 7]; |
|
| 19 | 19 | ||
| 20 | 20 | // Fill sub-range of mutable slice. |
|
| 21 | 21 | let mut d: [i32; 5] = [1, 2, 3, 4, 5]; |
|
| 22 | 22 | let ds: *mut [i32] = &mut d[..]; |
|
| 23 | - | ds[1..4] = 0; |
|
| 23 | + | set ds[1..4] = 0; |
|
| 24 | 24 | assert d == [1, 0, 0, 0, 5]; |
|
| 25 | 25 | ||
| 26 | 26 | // Copy slice into array. |
|
| 27 | 27 | let mut e: [i32; 3] = [0, 0, 0]; |
|
| 28 | 28 | let src: [i32; 3] = [10, 20, 30]; |
|
| 29 | - | e[..] = &src[..]; |
|
| 29 | + | set e[..] = &src[..]; |
|
| 30 | 30 | assert e == [10, 20, 30]; |
|
| 31 | 31 | ||
| 32 | 32 | // Copy into sub-range. |
|
| 33 | 33 | let mut f: [i32; 5] = [1, 2, 3, 4, 5]; |
|
| 34 | 34 | let src2: [i32; 2] = [88, 99]; |
|
| 35 | - | f[1..3] = &src2[..]; |
|
| 35 | + | set f[1..3] = &src2[..]; |
|
| 36 | 36 | assert f == [1, 88, 99, 4, 5]; |
|
| 37 | 37 | ||
| 38 | 38 | // Empty range is a no-op. |
|
| 39 | 39 | let mut g: [i32; 3] = [1, 2, 3]; |
|
| 40 | - | g[1..1] = 99; |
|
| 40 | + | set g[1..1] = 99; |
|
| 41 | 41 | assert g == [1, 2, 3]; |
|
| 42 | 42 | ||
| 43 | 43 | // Copy between sub-ranges. |
|
| 44 | 44 | let mut i: [i32; 10] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]; |
|
| 45 | 45 | let s: *mut [i32] = &mut i[..]; |
|
| 46 | - | s[1..4] = &s[7..10]; |
|
| 46 | + | set s[1..4] = &s[7..10]; |
|
| 47 | 47 | assert i[1] == 80 and i[2] == 90 and i[3] == 100; |
|
| 48 | 48 | ||
| 49 | 49 | // Fill u8 array. |
|
| 50 | 50 | let mut h: [u8; 4] = [65, 66, 67, 68]; |
|
| 51 | - | h[..] = 0; |
|
| 51 | + | set h[..] = 0; |
|
| 52 | 52 | assert h == [0, 0, 0, 0]; |
|
| 53 | 53 | ||
| 54 | 54 | return 0; |
|
| 55 | 55 | } |
test/tests/slice.mutable.rad
+4 -4
| 1 | 1 | // Test mutable slice operations |
|
| 2 | 2 | ||
| 3 | 3 | fn mutSliceStore(s: *mut [i32], idx: u32, val: i32) { |
|
| 4 | - | s[idx] = val; |
|
| 4 | + | set s[idx] = val; |
|
| 5 | 5 | } |
|
| 6 | 6 | ||
| 7 | 7 | fn mutSliceIncrement(s: *mut [i32], idx: u32) { |
|
| 8 | - | s[idx] += 1; |
|
| 8 | + | set s[idx] += 1; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | fn mutSliceSwap(s: *mut [i32], i: u32, j: u32) { |
|
| 12 | 12 | let tmp = s[i]; |
|
| 13 | - | s[i] = s[j]; |
|
| 14 | - | s[j] = tmp; |
|
| 13 | + | set s[i] = s[j]; |
|
| 14 | + | set s[j] = tmp; |
|
| 15 | 15 | } |
test/tests/spill.blockarg.clobber.rad
+22 -22
| 39 | 39 | } |
|
| 40 | 40 | ||
| 41 | 41 | fn prepareSchedule(s: *mut State, block: *[u32]) { |
|
| 42 | 42 | let mut i: u32 = 0; |
|
| 43 | 43 | while i < 16 { |
|
| 44 | - | s.w[i] = block[i]; |
|
| 45 | - | i += 1; |
|
| 44 | + | set s.w[i] = block[i]; |
|
| 45 | + | set i += 1; |
|
| 46 | 46 | } |
|
| 47 | 47 | while i < 64 { |
|
| 48 | - | s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16]; |
|
| 49 | - | i += 1; |
|
| 48 | + | set s.w[i] = ssig1(s.w[i - 2]) + s.w[i - 7] + ssig0(s.w[i - 15]) + s.w[i - 16]; |
|
| 49 | + | set i += 1; |
|
| 50 | 50 | } |
|
| 51 | 51 | } |
|
| 52 | 52 | ||
| 53 | 53 | /// SHA-256 compression: 64 rounds with 8 rotating working variables. |
|
| 54 | 54 | /// Exercises heavy register pressure and spilled block-argument shuffles. |
| 64 | 64 | ||
| 65 | 65 | let mut i: u32 = 0; |
|
| 66 | 66 | while i < 64 { |
|
| 67 | 67 | let t1 = hh + bsig1(e) + ch(e, f, g) + k[i] + s.w[i]; |
|
| 68 | 68 | let t2 = bsig0(a) + maj(a, b, c); |
|
| 69 | - | hh = g; |
|
| 70 | - | g = f; |
|
| 71 | - | f = e; |
|
| 72 | - | e = d + t1; |
|
| 73 | - | d = c; |
|
| 74 | - | c = b; |
|
| 75 | - | b = a; |
|
| 76 | - | a = t1 + t2; |
|
| 77 | - | i += 1; |
|
| 69 | + | set hh = g; |
|
| 70 | + | set g = f; |
|
| 71 | + | set f = e; |
|
| 72 | + | set e = d + t1; |
|
| 73 | + | set d = c; |
|
| 74 | + | set c = b; |
|
| 75 | + | set b = a; |
|
| 76 | + | set a = t1 + t2; |
|
| 77 | + | set i += 1; |
|
| 78 | 78 | } |
|
| 79 | 79 | ||
| 80 | - | s.h[0] += a; |
|
| 81 | - | s.h[1] += b; |
|
| 82 | - | s.h[2] += c; |
|
| 83 | - | s.h[3] += d; |
|
| 84 | - | s.h[4] += e; |
|
| 85 | - | s.h[5] += f; |
|
| 86 | - | s.h[6] += g; |
|
| 87 | - | s.h[7] += hh; |
|
| 80 | + | set s.h[0] += a; |
|
| 81 | + | set s.h[1] += b; |
|
| 82 | + | set s.h[2] += c; |
|
| 83 | + | set s.h[3] += d; |
|
| 84 | + | set s.h[4] += e; |
|
| 85 | + | set s.h[5] += f; |
|
| 86 | + | set s.h[6] += g; |
|
| 87 | + | set s.h[7] += hh; |
|
| 88 | 88 | } |
|
| 89 | 89 | ||
| 90 | 90 | @default fn main() -> i32 { |
|
| 91 | 91 | let k: [u32; 64] = [ |
|
| 92 | 92 | 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, |
| 113 | 113 | w: [0; 64] |
|
| 114 | 114 | }; |
|
| 115 | 115 | ||
| 116 | 116 | // Padded empty-message block. |
|
| 117 | 117 | let mut block: [u32; 16] = [0; 16]; |
|
| 118 | - | block[0] = 0x80000000; |
|
| 118 | + | set block[0] = 0x80000000; |
|
| 119 | 119 | ||
| 120 | 120 | prepareSchedule(&mut s, &block[..]); |
|
| 121 | 121 | compress(&mut s, &k[..]); |
|
| 122 | 122 | ||
| 123 | 123 | // SHA-256("") = e3b0c442 98fc1c14 ... |
test/tests/spill.loop.rad
+3 -3
| 34 | 34 | fn computeRecordLayout(tags: *[u8]) -> Layout { |
|
| 35 | 35 | let mut currentOffset: u32 = 0; |
|
| 36 | 36 | let mut maxAlignment: u32 = 1; |
|
| 37 | 37 | for i in 0..tags.len { |
|
| 38 | 38 | let layout = getLayout(tags[i]); |
|
| 39 | - | currentOffset = alignUp(currentOffset, layout.alignment); |
|
| 40 | - | currentOffset += layout.size; |
|
| 41 | - | maxAlignment = max(maxAlignment, layout.alignment); |
|
| 39 | + | set currentOffset = alignUp(currentOffset, layout.alignment); |
|
| 40 | + | set currentOffset += layout.size; |
|
| 41 | + | set maxAlignment = max(maxAlignment, layout.alignment); |
|
| 42 | 42 | } |
|
| 43 | 43 | return Layout { |
|
| 44 | 44 | size: alignUp(currentOffset, maxAlignment), |
|
| 45 | 45 | alignment: maxAlignment, |
|
| 46 | 46 | }; |
test/tests/static.array.mutate.rad
+1 -1
| 2 | 2 | //! Test mutating a static array. |
|
| 3 | 3 | ||
| 4 | 4 | static BUFFER: [i32; 3] = [1, 2, 3]; |
|
| 5 | 5 | ||
| 6 | 6 | fn bump(slot: u32, amount: i32) -> i32 { |
|
| 7 | - | BUFFER[slot] += amount; |
|
| 7 | + | set BUFFER[slot] += amount; |
|
| 8 | 8 | return BUFFER[0] + BUFFER[1] + BUFFER[2]; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | @default fn main() -> i32 { |
|
| 12 | 12 | let a: i32 = bump(0, 4); |
test/tests/static.assign.rad
+1 -1
| 1 | 1 | /// Test static variable assignment. |
|
| 2 | 2 | static COUNTER: i32 = 0; |
|
| 3 | 3 | ||
| 4 | 4 | fn increment() -> i32 { |
|
| 5 | - | COUNTER += 1; |
|
| 5 | + | set COUNTER += 1; |
|
| 6 | 6 | return COUNTER; |
|
| 7 | 7 | } |
test/tests/static.basic.rad
+5 -5
| 3 | 3 | static GLOBAL: i32 = 0; |
|
| 4 | 4 | ||
| 5 | 5 | fn updateCounter(i: i32) -> i32 { |
|
| 6 | 6 | static counter: i32 = 0; |
|
| 7 | 7 | ||
| 8 | - | counter += i; |
|
| 9 | - | GLOBAL += i * 10; |
|
| 8 | + | set counter += i; |
|
| 9 | + | set GLOBAL += i * 10; |
|
| 10 | 10 | ||
| 11 | 11 | return counter; |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | @default fn main() -> i32 { |
|
| 15 | 15 | let mut n: i32 = 0; |
|
| 16 | 16 | ||
| 17 | - | n = updateCounter(1); |
|
| 18 | - | n = updateCounter(2); |
|
| 19 | - | n = updateCounter(3); |
|
| 17 | + | set n = updateCounter(1); |
|
| 18 | + | set n = updateCounter(2); |
|
| 19 | + | set n = updateCounter(3); |
|
| 20 | 20 | ||
| 21 | 21 | return n + GLOBAL; |
|
| 22 | 22 | } |
test/tests/static.local.decl.rad
+1 -1
| 1 | 1 | /// Test lowering of function-local static and constant declarations. |
|
| 2 | 2 | fn localStaticAndConst() -> i32 { |
|
| 3 | 3 | static LOCAL: i32 = 7; |
|
| 4 | 4 | constant ADD: i32 = 5; |
|
| 5 | 5 | ||
| 6 | - | LOCAL += ADD; |
|
| 6 | + | set LOCAL += ADD; |
|
| 7 | 7 | return LOCAL; |
|
| 8 | 8 | } |
test/tests/static.record.array.rad
+2 -2
| 10 | 10 | values: [5, 1, 9, 2], |
|
| 11 | 11 | bias: 4, |
|
| 12 | 12 | }; |
|
| 13 | 13 | ||
| 14 | 14 | fn rebalance() -> i32 { |
|
| 15 | - | TABLE.values[0] += TABLE.bias; |
|
| 16 | - | TABLE.values[3] += 1; |
|
| 15 | + | set TABLE.values[0] += TABLE.bias; |
|
| 16 | + | set TABLE.values[3] += 1; |
|
| 17 | 17 | return TABLE.values[0] + TABLE.values[3] + TABLE.bias; |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | @default fn main() -> i32 { |
|
| 21 | 21 | let first: i32 = rebalance(); |
test/tests/static.slice.index.assign.rad
+4 -4
| 10 | 10 | } |
|
| 11 | 11 | ||
| 12 | 12 | static container: Container = undefined; |
|
| 13 | 13 | ||
| 14 | 14 | @default fn main() -> i32 { |
|
| 15 | - | container.items[0].value = 10; |
|
| 16 | - | container.items[1].value = 20; |
|
| 17 | - | container.items[2].value = 30; |
|
| 15 | + | set container.items[0].value = 10; |
|
| 16 | + | set container.items[1].value = 20; |
|
| 17 | + | set container.items[2].value = 30; |
|
| 18 | 18 | ||
| 19 | 19 | let slice: *mut [Inner] = &mut container.items[..]; |
|
| 20 | 20 | ||
| 21 | - | slice[1].value = 42; |
|
| 21 | + | set slice[1].value = 42; |
|
| 22 | 22 | ||
| 23 | 23 | return container.items[1].value; |
|
| 24 | 24 | } |
test/tests/static.slice.offset.rad
+5 -5
| 18 | 18 | Entry { a: 0, b: 0 }, |
|
| 19 | 19 | ]; |
|
| 20 | 20 | static TBL: Table = undefined; |
|
| 21 | 21 | ||
| 22 | 22 | @default fn main() -> i32 { |
|
| 23 | - | TBL.scratch = &mut SCRATCH[..]; |
|
| 24 | - | TBL.entries = &mut STORAGE[..]; |
|
| 25 | - | TBL.len = 0; |
|
| 23 | + | set TBL.scratch = &mut SCRATCH[..]; |
|
| 24 | + | set TBL.entries = &mut STORAGE[..]; |
|
| 25 | + | set TBL.len = 0; |
|
| 26 | 26 | ||
| 27 | - | TBL.entries[TBL.len] = Entry { a: 7, b: 9 }; |
|
| 28 | - | TBL.len += 1; |
|
| 27 | + | set TBL.entries[TBL.len] = Entry { a: 7, b: 9 }; |
|
| 28 | + | set TBL.len += 1; |
|
| 29 | 29 | ||
| 30 | 30 | assert STORAGE[0].a == 7 and STORAGE[0].b == 9; |
|
| 31 | 31 | assert SCRATCH[0].a == 0 and SCRATCH[0].b == 0; |
|
| 32 | 32 | return 0; |
|
| 33 | 33 | } |
test/tests/trait.array.optional.rad
+1 -1
| 30 | 30 | ||
| 31 | 31 | /// Apply a chain of transforms to a value. |
|
| 32 | 32 | fn applyAll(transforms: *[*opaque Transform], value: i32) -> i32 { |
|
| 33 | 33 | let mut result = value; |
|
| 34 | 34 | for i in 0..transforms.len { |
|
| 35 | - | result = transforms[i].apply(result); |
|
| 35 | + | set result = transforms[i].apply(result); |
|
| 36 | 36 | } |
|
| 37 | 37 | return result; |
|
| 38 | 38 | } |
|
| 39 | 39 | ||
| 40 | 40 | /// Apply an optional transform, returning the original value if nil. |
test/tests/trait.basic.rad
+1 -1
| 8 | 8 | fn (*mut Adder) add(n: i32) -> i32; |
|
| 9 | 9 | } |
|
| 10 | 10 | ||
| 11 | 11 | instance Adder for Counter { |
|
| 12 | 12 | fn (c: *mut Counter) add(n: i32) -> i32 { |
|
| 13 | - | c.value = c.value + n; |
|
| 13 | + | set c.value = c.value + n; |
|
| 14 | 14 | return c.value; |
|
| 15 | 15 | } |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | @default fn main() -> i32 { |
test/tests/trait.control.flow.rad
+2 -2
| 14 | 14 | fn (*Stepper) current() -> i32; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | 17 | instance Stepper for Counter { |
|
| 18 | 18 | fn (c: *mut Counter) step() -> i32 { |
|
| 19 | - | c.value = c.value + 1; |
|
| 19 | + | set c.value = c.value + 1; |
|
| 20 | 20 | return c.value; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | fn (c: *Counter) current() -> i32 { |
|
| 24 | 24 | return c.value; |
| 31 | 31 | ||
| 32 | 32 | // Dispatch in a while loop. |
|
| 33 | 33 | let mut i: i32 = 0; |
|
| 34 | 34 | while i < 5 { |
|
| 35 | 35 | s.step(); |
|
| 36 | - | i = i + 1; |
|
| 36 | + | set i = i + 1; |
|
| 37 | 37 | } |
|
| 38 | 38 | assert s.current() == 5; |
|
| 39 | 39 | ||
| 40 | 40 | // Dispatch in a conditional. |
|
| 41 | 41 | if s.current() > 3 { |
test/tests/trait.dispatch.rad
+1 -1
| 11 | 11 | fn (a: *Acc) get() -> i32 { |
|
| 12 | 12 | return a.n; |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | fn (a: *mut Acc) put(n: i32) { |
|
| 16 | - | a.n = n; |
|
| 16 | + | set a.n = n; |
|
| 17 | 17 | } |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | fn dispatch(o: *mut opaque Ops) -> i32 { |
|
| 21 | 21 | o.put(42); |
test/tests/trait.fn.param.rad
+1 -1
| 32 | 32 | } |
|
| 33 | 33 | } |
|
| 34 | 34 | ||
| 35 | 35 | instance Scalable for Circle { |
|
| 36 | 36 | fn (c: *mut Circle) scale(factor: i32) { |
|
| 37 | - | c.radius = c.radius * factor; |
|
| 37 | + | set c.radius = c.radius * factor; |
|
| 38 | 38 | } |
|
| 39 | 39 | } |
|
| 40 | 40 | ||
| 41 | 41 | /// Accept an immutable trait object parameter. |
|
| 42 | 42 | fn getArea(s: *opaque Shape) -> i32 { |
test/tests/trait.multiple.methods.rad
+2 -2
| 15 | 15 | fn (*mut Collector) isEmpty() -> bool; |
|
| 16 | 16 | } |
|
| 17 | 17 | ||
| 18 | 18 | instance Collector for Accumulator { |
|
| 19 | 19 | fn (a: *mut Accumulator) add(n: i32) -> i32 { |
|
| 20 | - | a.total = a.total + n; |
|
| 20 | + | set a.total = a.total + n; |
|
| 21 | 21 | return a.total; |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | 24 | fn (a: *mut Accumulator) clear() { |
|
| 25 | - | a.total = 0; |
|
| 25 | + | set a.total = 0; |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | fn (a: *mut Accumulator) isEmpty() -> bool { |
|
| 29 | 29 | return a.total == 0; |
|
| 30 | 30 | } |
test/tests/trait.multiple.traits.rad
+2 -2
| 18 | 18 | fn (*mut Resettable) isZero() -> bool; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | instance Incrementable for Counter { |
|
| 22 | 22 | fn (c: *mut Counter) inc() -> i32 { |
|
| 23 | - | c.value = c.value + 1; |
|
| 23 | + | set c.value = c.value + 1; |
|
| 24 | 24 | return c.value; |
|
| 25 | 25 | } |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | instance Resettable for Counter { |
|
| 29 | 29 | fn (c: *mut Counter) reset() { |
|
| 30 | - | c.value = 0; |
|
| 30 | + | set c.value = 0; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | fn (c: *mut Counter) isZero() -> bool { |
|
| 34 | 34 | return c.value == 0; |
|
| 35 | 35 | } |
test/tests/trait.object.rad
+1 -1
| 6 | 6 | fn (*mut Adder) add(n: i32) -> i32; |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | instance Adder for Counter { |
|
| 10 | 10 | fn (c: *mut Counter) add(n: i32) -> i32 { |
|
| 11 | - | c.value = c.value + n; |
|
| 11 | + | set c.value = c.value + n; |
|
| 12 | 12 | return c.value; |
|
| 13 | 13 | } |
|
| 14 | 14 | } |
|
| 15 | 15 | ||
| 16 | 16 | fn use_adder() -> i32 { |
test/tests/trait.supertrait.rad
+12 -12
| 30 | 30 | ||
| 31 | 31 | instance Reader for Socket { |
|
| 32 | 32 | fn (s: *mut Socket) read(buf: *mut [u8]) -> i32 { |
|
| 33 | 33 | let mut i: u32 = 0; |
|
| 34 | 34 | while i < buf.len and s.rpos < s.rlen { |
|
| 35 | - | buf[i] = s.rbuf[s.rpos as u32]; |
|
| 36 | - | s.rpos = s.rpos + 1; |
|
| 37 | - | i = i + 1; |
|
| 35 | + | set buf[i] = s.rbuf[s.rpos as u32]; |
|
| 36 | + | set s.rpos = s.rpos + 1; |
|
| 37 | + | set i = i + 1; |
|
| 38 | 38 | } |
|
| 39 | 39 | return i as i32; |
|
| 40 | 40 | } |
|
| 41 | 41 | } |
|
| 42 | 42 |
| 45 | 45 | let mut i: u32 = 0; |
|
| 46 | 46 | while i < data.len { |
|
| 47 | 47 | if s.wpos >= 32 { |
|
| 48 | 48 | return s.wpos; |
|
| 49 | 49 | } |
|
| 50 | - | s.wbuf[s.wpos as u32] = data[i]; |
|
| 51 | - | s.wpos = s.wpos + 1; |
|
| 52 | - | i = i + 1; |
|
| 50 | + | set s.wbuf[s.wpos as u32] = data[i]; |
|
| 51 | + | set s.wpos = s.wpos + 1; |
|
| 52 | + | set i = i + 1; |
|
| 53 | 53 | } |
|
| 54 | 54 | return s.wpos; |
|
| 55 | 55 | } |
|
| 56 | 56 | } |
|
| 57 | 57 | ||
| 58 | 58 | instance ReadWriter for Socket { |
|
| 59 | 59 | fn (s: *mut Socket) flush() -> i32 { |
|
| 60 | 60 | let pos = s.wpos; |
|
| 61 | - | s.wpos = 0; |
|
| 61 | + | set s.wpos = 0; |
|
| 62 | 62 | return pos; |
|
| 63 | 63 | } |
|
| 64 | 64 | } |
|
| 65 | 65 | ||
| 66 | 66 | @default fn main() -> i32 { |
| 70 | 70 | rlen: 5, |
|
| 71 | 71 | wbuf: undefined, |
|
| 72 | 72 | wpos: 0, |
|
| 73 | 73 | }; |
|
| 74 | 74 | // Pre-fill the read buffer with "hello". |
|
| 75 | - | sock.rbuf[0] = 'h' as u8; |
|
| 76 | - | sock.rbuf[1] = 'e' as u8; |
|
| 77 | - | sock.rbuf[2] = 'l' as u8; |
|
| 78 | - | sock.rbuf[3] = 'l' as u8; |
|
| 79 | - | sock.rbuf[4] = 'o' as u8; |
|
| 75 | + | set sock.rbuf[0] = 'h' as u8; |
|
| 76 | + | set sock.rbuf[1] = 'e' as u8; |
|
| 77 | + | set sock.rbuf[2] = 'l' as u8; |
|
| 78 | + | set sock.rbuf[3] = 'l' as u8; |
|
| 79 | + | set sock.rbuf[4] = 'o' as u8; |
|
| 80 | 80 | ||
| 81 | 81 | // Test 1: Use as ReadWriter trait object. |
|
| 82 | 82 | let rw: *mut opaque ReadWriter = &mut sock; |
|
| 83 | 83 | ||
| 84 | 84 | // Test 2: Write through the ReadWriter (dispatches via Writer supertrait). |
test/tests/trait.throws.rad
+3 -3
| 37 | 37 | assert r1 == 10; |
|
| 38 | 38 | ||
| 39 | 39 | // Error path: negative input. |
|
| 40 | 40 | let mut caught = false; |
|
| 41 | 41 | let r2 = try p.parse(-1) catch { |
|
| 42 | - | caught = true; |
|
| 42 | + | set caught = true; |
|
| 43 | 43 | 0 |
|
| 44 | 44 | }; |
|
| 45 | 45 | assert caught; |
|
| 46 | 46 | ||
| 47 | 47 | // Error path: overflow. |
|
| 48 | - | caught = false; |
|
| 48 | + | set caught = false; |
|
| 49 | 49 | let r3 = try p.parse(200) catch { |
|
| 50 | - | caught = true; |
|
| 50 | + | set caught = true; |
|
| 51 | 51 | 0 |
|
| 52 | 52 | }; |
|
| 53 | 53 | assert caught; |
|
| 54 | 54 | ||
| 55 | 55 | return 0; |
test/tests/trait.writer.rad
+4 -4
| 22 | 22 | let mut i: u32 = 0; |
|
| 23 | 23 | while i < data.len { |
|
| 24 | 24 | if w.pos >= 64 { |
|
| 25 | 25 | return w.pos; |
|
| 26 | 26 | } |
|
| 27 | - | w.buf[w.pos as u32] = data[i]; |
|
| 28 | - | w.pos = w.pos + 1; |
|
| 29 | - | i = i + 1; |
|
| 27 | + | set w.buf[w.pos as u32] = data[i]; |
|
| 28 | + | set w.pos = w.pos + 1; |
|
| 29 | + | set i = i + 1; |
|
| 30 | 30 | } |
|
| 31 | 31 | return w.pos; |
|
| 32 | 32 | } |
|
| 33 | 33 | ||
| 34 | 34 | fn (w: *BufferWriter) total() -> i32 { |
| 42 | 42 | count: i32, |
|
| 43 | 43 | } |
|
| 44 | 44 | ||
| 45 | 45 | instance Writer for CountingWriter { |
|
| 46 | 46 | fn (w: *mut CountingWriter) write(data: *[u8]) -> i32 { |
|
| 47 | - | w.count = w.count + data.len as i32; |
|
| 47 | + | set w.count = w.count + data.len as i32; |
|
| 48 | 48 | return w.inner.write(data); |
|
| 49 | 49 | } |
|
| 50 | 50 | ||
| 51 | 51 | fn (w: *CountingWriter) total() -> i32 { |
|
| 52 | 52 | return w.count; |
test/tests/trivial.phi.rad
+2 -2
| 33 | 33 | /// If-else with assignments that both assign the same param value. |
|
| 34 | 34 | /// The merge uses %1 (val param) directly - no block param. |
|
| 35 | 35 | fn condSameParam(cond: bool, val: i32) -> i32 { |
|
| 36 | 36 | let mut result: i32 = 0; |
|
| 37 | 37 | if cond { |
|
| 38 | - | result = val; |
|
| 38 | + | set result = val; |
|
| 39 | 39 | } else { |
|
| 40 | - | result = val; |
|
| 40 | + | set result = val; |
|
| 41 | 41 | } |
|
| 42 | 42 | return result; |
|
| 43 | 43 | } |
test/tests/type.unify.rad
+9 -9
| 24 | 24 | let optComplex: ?i32 = (10 * 2) - 5; |
|
| 25 | 25 | ||
| 26 | 26 | let opt1: ?i32 = 10; |
|
| 27 | 27 | let opt2: ?i32 = 20; |
|
| 28 | 28 | let mut optResult: ?i32 = opt1; |
|
| 29 | - | optResult = opt2; |
|
| 29 | + | set optResult = opt2; |
|
| 30 | 30 | ||
| 31 | 31 | if let a = optExpr { |
|
| 32 | 32 | if let b = optComplex { |
|
| 33 | 33 | return a + b == 20; |
|
| 34 | 34 | } |
| 39 | 39 | /// Verifies assignment compatibility for arrays with identical element types and lengths. |
|
| 40 | 40 | fn testArrayUnification() -> bool { |
|
| 41 | 41 | let arr1: [i32; 3] = [1, 2, 3]; |
|
| 42 | 42 | let arr2: [i32; 3] = [4, 5, 6]; |
|
| 43 | 43 | let mut arrResult: [i32; 3] = arr1; |
|
| 44 | - | arrResult = arr2; |
|
| 44 | + | set arrResult = arr2; |
|
| 45 | 45 | ||
| 46 | 46 | return true; |
|
| 47 | 47 | } |
|
| 48 | 48 | ||
| 49 | 49 | /// Verifies assignment compatibility for pointers with identical target types. |
| 51 | 51 | let x: i32 = 42; |
|
| 52 | 52 | let y: i32 = 24; |
|
| 53 | 53 | let ptr1: *i32 = &x; |
|
| 54 | 54 | let ptr2: *i32 = &y; |
|
| 55 | 55 | let mut ptrResult: *i32 = ptr1; |
|
| 56 | - | ptrResult = ptr2; |
|
| 56 | + | set ptrResult = ptr2; |
|
| 57 | 57 | ||
| 58 | 58 | return true; |
|
| 59 | 59 | } |
|
| 60 | 60 | ||
| 61 | 61 | /// Verifies conversion from array references to slices. |
| 91 | 91 | /// Verifies basic optional assignments between values of the same optional type. |
|
| 92 | 92 | fn testSimpleOptionalValues() -> bool { |
|
| 93 | 93 | let opt1: ?i32 = 10; |
|
| 94 | 94 | let opt2: ?i32 = 20; |
|
| 95 | 95 | let mut result: ?i32 = opt1; |
|
| 96 | - | result = opt2; |
|
| 96 | + | set result = opt2; |
|
| 97 | 97 | ||
| 98 | 98 | return true; |
|
| 99 | 99 | } |
|
| 100 | 100 | ||
| 101 | 101 | /// Verifies coercion from pointer values to optional pointer values. |
| 121 | 121 | /// Verifies optional assignments involving `nil` and concrete values. |
|
| 122 | 122 | fn testNilUnification() -> bool { |
|
| 123 | 123 | let opt1: ?i32 = nil; |
|
| 124 | 124 | let opt2: ?i32 = 42; |
|
| 125 | 125 | let mut result: ?i32 = opt1; |
|
| 126 | - | result = opt2; |
|
| 127 | - | result = nil; |
|
| 126 | + | set result = opt2; |
|
| 127 | + | set result = nil; |
|
| 128 | 128 | ||
| 129 | 129 | return true; |
|
| 130 | 130 | } |
|
| 131 | 131 | ||
| 132 | 132 | /// Verifies that arrays of different lengths remain distinct types. |
| 146 | 146 | let ptr1: *i32 = &value1; |
|
| 147 | 147 | let ptr2: *i32 = &value2; |
|
| 148 | 148 | let ptr3: *i32 = &value3; |
|
| 149 | 149 | ||
| 150 | 150 | let mut result: *i32 = ptr1; |
|
| 151 | - | result = ptr2; |
|
| 152 | - | result = ptr3; |
|
| 151 | + | set result = ptr2; |
|
| 152 | + | set result = ptr3; |
|
| 153 | 153 | ||
| 154 | 154 | return true; |
|
| 155 | 155 | } |
|
| 156 | 156 | ||
| 157 | 157 | /// Verifies assignment compatibility for boolean values. |
|
| 158 | 158 | fn testBoolUnification() -> bool { |
|
| 159 | 159 | let b1: bool = true; |
|
| 160 | 160 | let b2: bool = false; |
|
| 161 | 161 | let mut result: bool = b1; |
|
| 162 | - | result = b2; |
|
| 162 | + | set result = b2; |
|
| 163 | 163 | ||
| 164 | 164 | return true; |
|
| 165 | 165 | } |
|
| 166 | 166 | ||
| 167 | 167 | @default fn main() -> i32 { |
test/tests/undefined.rad
+5 -5
| 3 | 3 | @default fn main() -> i32 { |
|
| 4 | 4 | let mut ary: [u16; 32] = undefined; |
|
| 5 | 5 | let x: u32 = 8; |
|
| 6 | 6 | let y: u32 = 9; |
|
| 7 | 7 | ||
| 8 | - | ary[0] = 1; |
|
| 9 | - | ary[1] = 2; |
|
| 10 | - | ary[2] = 3; |
|
| 11 | - | ary[3] = 4; |
|
| 12 | - | ary[4] = 5; |
|
| 8 | + | set ary[0] = 1; |
|
| 9 | + | set ary[1] = 2; |
|
| 10 | + | set ary[2] = 3; |
|
| 11 | + | set ary[3] = 4; |
|
| 12 | + | set ary[4] = 5; |
|
| 13 | 13 | ||
| 14 | 14 | assert x == 8; |
|
| 15 | 15 | assert y == 9; |
|
| 16 | 16 | assert ary[0] == 1; |
|
| 17 | 17 | assert ary[1] == 2; |
test/tests/union.edge.case.3.rad
+1 -1
| 10 | 10 | record Parser { |
|
| 11 | 11 | root: Node, |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | 14 | fn node(p: *mut Parser, value: Node) -> *Node { |
|
| 15 | - | p.root = value; |
|
| 15 | + | set p.root = value; |
|
| 16 | 16 | return &p.root; |
|
| 17 | 17 | } |
|
| 18 | 18 | ||
| 19 | 19 | fn nodeBool(p: *mut Parser, value: bool) -> *Node { |
|
| 20 | 20 | return node(p, Node::Bool(value)); |
test/tests/union.match.ref.rad
+2 -2
| 31 | 31 | ||
| 32 | 32 | /// While-let on a mutable union reference. |
|
| 33 | 33 | fn whileLetRef(ptr: *mut Option) -> u32 { |
|
| 34 | 34 | let mut sum: u32 = 0; |
|
| 35 | 35 | while let case Option::Some(val) = ptr { |
|
| 36 | - | sum += *val; |
|
| 37 | - | *ptr = Option::None; |
|
| 36 | + | set sum += *val; |
|
| 37 | + | set *ptr = Option::None; |
|
| 38 | 38 | } |
|
| 39 | 39 | return sum; |
|
| 40 | 40 | } |
|
| 41 | 41 | ||
| 42 | 42 | /// Match on an optional reference with binding pattern. |
test/tests/union.mixed.assign.rad
+2 -2
| 11 | 11 | record Holder { |
|
| 12 | 12 | value: Mixed, |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | fn storePayload(holder: *mut Holder, value: i32) { |
|
| 16 | - | holder.value = Mixed::Payload(value); |
|
| 16 | + | set holder.value = Mixed::Payload(value); |
|
| 17 | 17 | } |
|
| 18 | 18 | ||
| 19 | 19 | fn storeFinal(holder: *mut Holder) { |
|
| 20 | - | holder.value = Mixed::Final; |
|
| 20 | + | set holder.value = Mixed::Final; |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | fn checkIfLet(value: Mixed) -> i32 { |
|
| 24 | 24 | if let case Mixed::Payload(v) = value { |
|
| 25 | 25 | return v; |
test/tests/union.payload.mutref.rad
+2 -2
| 20 | 20 | } |
|
| 21 | 21 | ||
| 22 | 22 | fn addItemViaMatchRef(blk: *mut Block, val: u32) -> bool { |
|
| 23 | 23 | match &mut blk.state { |
|
| 24 | 24 | case Sealed::No { items } => { |
|
| 25 | - | items.data[items.len] = val; |
|
| 26 | - | items.len += 1; |
|
| 25 | + | set items.data[items.len] = val; |
|
| 26 | + | set items.len += 1; |
|
| 27 | 27 | return true; |
|
| 28 | 28 | }, |
|
| 29 | 29 | case Sealed::Yes => { |
|
| 30 | 30 | return false; |
|
| 31 | 31 | }, |
test/tests/union.record.forward.rad
+1 -1
| 60 | 60 | ]; |
|
| 61 | 61 | ||
| 62 | 62 | let mut result: u32 = 0; |
|
| 63 | 63 | match wrappers[7] { |
|
| 64 | 64 | case Wrapper::Data(payload) => { |
|
| 65 | - | result = payload.f0 + payload.f15; |
|
| 65 | + | set result = payload.f0 + payload.f15; |
|
| 66 | 66 | } |
|
| 67 | 67 | } |
|
| 68 | 68 | return result; |
|
| 69 | 69 | } |
|
| 70 | 70 |
test/tests/var.infer.rad
+1 -1
| 20 | 20 | @default fn main() -> i32 { |
|
| 21 | 21 | let inferredFlag = alwaysTrue(); |
|
| 22 | 22 | assert inferredFlag; |
|
| 23 | 23 | ||
| 24 | 24 | let mut counter = returnsCount(); |
|
| 25 | - | counter += 1; |
|
| 25 | + | set counter += 1; |
|
| 26 | 26 | assert counter == 6; |
|
| 27 | 27 | ||
| 28 | 28 | let pair = loadPair(); |
|
| 29 | 29 | let left = pair.left; |
|
| 30 | 30 |
test/tests/var.shadow.rad
+2 -2
| 1 | 1 | // Test variable reuse (not true shadowing) |
|
| 2 | 2 | ||
| 3 | 3 | fn reuseVar() -> i32 { |
|
| 4 | 4 | let mut x: i32 = 1; |
|
| 5 | - | x = 2; |
|
| 5 | + | set x = 2; |
|
| 6 | 6 | return x; |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | fn reuseWithComputation() -> i32 { |
|
| 10 | 10 | let mut x: i32 = 10; |
|
| 11 | 11 | let y: i32 = x + 5; |
|
| 12 | - | x = 20; |
|
| 12 | + | set x = 20; |
|
| 13 | 13 | return x + y; |
|
| 14 | 14 | } |