Simplify `for` loops that need the index
43baa2528c0799e6b2e55e10ebc2f637e38ee1d149e742fd4bab5f9841d2e4ad
1 parent
a6d3edee
lib/std/arch/rv64/emit.rad
+2 -2
| 159 | 159 | ); |
|
| 160 | 160 | frame.totalSize = totalSize; |
|
| 161 | 161 | ||
| 162 | 162 | // Build list of callee-saved registers with offsets. |
|
| 163 | 163 | let mut offset = totalSize - (super::DWORD_SIZE * 3); |
|
| 164 | - | for i in 0..super::CALLEE_SAVED.len { |
|
| 164 | + | for reg, i in super::CALLEE_SAVED { |
|
| 165 | 165 | // Check if this register is in use. |
|
| 166 | 166 | if (usedCalleeSaved & (1 << i)) != 0 { |
|
| 167 | 167 | frame.savedRegs[frame.savedRegsLen] = SavedReg { |
|
| 168 | - | reg: super::CALLEE_SAVED[i], |
|
| 168 | + | reg, |
|
| 169 | 169 | offset, |
|
| 170 | 170 | }; |
|
| 171 | 171 | frame.savedRegsLen += 1; |
|
| 172 | 172 | offset -= super::DWORD_SIZE; |
|
| 173 | 173 | } |
lib/std/arch/rv64/isel.rad
+7 -9
| 280 | 280 | ||
| 281 | 281 | // Move function params from arg registers to assigned registers. |
|
| 282 | 282 | // Cross-call params may have been assigned to callee-saved registers |
|
| 283 | 283 | // instead of their natural arg registers. Spilled params are stored |
|
| 284 | 284 | // directly to their spill slots. |
|
| 285 | - | for i in 0..func.params.len { |
|
| 285 | + | for funcParam, i in func.params { |
|
| 286 | 286 | if i < super::ARG_REGS.len { |
|
| 287 | - | let param = func.params[i].value; |
|
| 287 | + | let param = funcParam.value; |
|
| 288 | 288 | let argReg = super::ARG_REGS[i]; |
|
| 289 | 289 | ||
| 290 | 290 | if let slot = regalloc::spill::spillSlot(&ralloc.spill, param) { |
|
| 291 | 291 | // Spilled parameter: store arg register to spill slot. |
|
| 292 | 292 | emit::emitSd(s.e, argReg, super::FP, spillOffset(&s, slot)); |
| 315 | 315 | // By the time we enter the block, the arguments have already been |
|
| 316 | 316 | // moved to the parameter registers by the predecessor's terminator. |
|
| 317 | 317 | ||
| 318 | 318 | // Process each instruction, auto-committing any pending spill after each. |
|
| 319 | 319 | let hasLocs = block.locs.len > 0; |
|
| 320 | - | for i in 0..block.instrs.len { |
|
| 320 | + | for instr, i in block.instrs { |
|
| 321 | 321 | // Record debug location before emitting machine instructions. |
|
| 322 | 322 | if hasLocs { |
|
| 323 | 323 | emit::recordSrcLoc(s.e, block.locs[i]); |
|
| 324 | 324 | } |
|
| 325 | 325 | s.pendingSpill = nil; |
|
| 326 | - | selectInstr(s, blockIdx, block.instrs[i], frame, func); |
|
| 326 | + | selectInstr(s, blockIdx, instr, frame, func); |
|
| 327 | 327 | ||
| 328 | 328 | // Flush the pending spill store, if any. |
|
| 329 | 329 | if let p = s.pendingSpill { |
|
| 330 | 330 | if let slot = regalloc::spill::spillSlot(&s.ralloc.spill, p.ssa) { |
|
| 331 | 331 | emit::emitSd(s.e, p.rd, super::FP, spillOffset(s, slot)); |
| 1000 | 1000 | ||
| 1001 | 1001 | // Destination registers for each arg. |
|
| 1002 | 1002 | // Zero means the destination is spilled or skipped. |
|
| 1003 | 1003 | let mut dsts: [super::Reg; MAX_BLOCK_ARGS] = [super::ZERO; MAX_BLOCK_ARGS]; |
|
| 1004 | 1004 | ||
| 1005 | - | for i in 0..args.len { |
|
| 1005 | + | for arg, i in args { |
|
| 1006 | 1006 | let param = block.params[i].value; |
|
| 1007 | 1007 | ||
| 1008 | 1008 | // Spilled destinations: store directly to spill slot. |
|
| 1009 | 1009 | // These don't participate in the parallel move algorithm. |
|
| 1010 | 1010 | if let slot = regalloc::spill::spillSlot(&s.ralloc.spill, param) { |
|
| 1011 | - | let a = args[i]; |
|
| 1012 | - | ||
| 1013 | - | if let case il::Val::Undef = a { |
|
| 1011 | + | if let case il::Val::Undef = arg { |
|
| 1014 | 1012 | // Undefined values don't need any move. |
|
| 1015 | 1013 | } else { |
|
| 1016 | - | let rs = resolveVal(s, super::SCRATCH1, a); |
|
| 1014 | + | let rs = resolveVal(s, super::SCRATCH1, arg); |
|
| 1017 | 1015 | emit::emitSd(s.e, rs, super::FP, spillOffset(s, slot)); |
|
| 1018 | 1016 | } |
|
| 1019 | 1017 | } else { |
|
| 1020 | 1018 | dsts[i] = getReg(s, param); |
|
| 1021 | 1019 | } |
lib/std/arch/rv64/printer.rad
+4 -4
| 80 | 80 | write(out, ")"); |
|
| 81 | 81 | } |
|
| 82 | 82 | ||
| 83 | 83 | /// Write strings separated by ", ". |
|
| 84 | 84 | fn writeDelim(out: *mut sexpr::Output, parts: *[*[u8]]) { |
|
| 85 | - | for i in 0..parts.len { |
|
| 85 | + | for part, i in parts { |
|
| 86 | 86 | if i > 0 { |
|
| 87 | 87 | write(out, ", "); |
|
| 88 | 88 | } |
|
| 89 | - | write(out, parts[i]); |
|
| 89 | + | write(out, part); |
|
| 90 | 90 | } |
|
| 91 | 91 | } |
|
| 92 | 92 | ||
| 93 | 93 | /// Write mnemonic with padding for alignment. |
|
| 94 | 94 | fn writeMnem(out: *mut sexpr::Output, m: *[u8]) { |
| 313 | 313 | // Package header. |
|
| 314 | 314 | write(out, "# package `"); |
|
| 315 | 315 | write(out, pkgName); |
|
| 316 | 316 | write(out, "`\n\n"); |
|
| 317 | 317 | ||
| 318 | - | for i in 0..code.len { |
|
| 318 | + | for instr, i in code { |
|
| 319 | 319 | if let name = findFunc(funcs, i) { |
|
| 320 | 320 | write(out, "\n# "); |
|
| 321 | 321 | write(out, name); |
|
| 322 | 322 | write(out, "\n\n"); |
|
| 323 | 323 | } |
|
| 324 | - | printInstr(out, arena, code[i]); |
|
| 324 | + | printInstr(out, arena, instr); |
|
| 325 | 325 | write(out, "\n"); |
|
| 326 | 326 | } |
|
| 327 | 327 | } |
|
| 328 | 328 | ||
| 329 | 329 | /// Find function at given instruction index. |
lib/std/lang/ast/printer.rad
+10 -13
| 105 | 105 | fn nodeListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 106 | 106 | if nodes.len == 0 { |
|
| 107 | 107 | return &[]; |
|
| 108 | 108 | } |
|
| 109 | 109 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 110 | - | for i in 0..nodes.len { |
|
| 111 | - | buf[i] = toExpr(a, nodes[i]); |
|
| 110 | + | for node, i in nodes { |
|
| 111 | + | 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. |
| 141 | 141 | fn prongListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 142 | 142 | if nodes.len == 0 { |
|
| 143 | 143 | return &[]; |
|
| 144 | 144 | } |
|
| 145 | 145 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 146 | - | for i in 0..nodes.len { |
|
| 147 | - | let prong = nodes[i]; |
|
| 146 | + | for prong, i in nodes { |
|
| 148 | 147 | match prong.value { |
|
| 149 | 148 | case super::NodeValue::MatchProng(p) => { |
|
| 150 | 149 | buf[i] = prongToExpr(a, p); |
|
| 151 | 150 | } |
|
| 152 | 151 | else => { |
| 192 | 191 | fn fieldListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 193 | 192 | if nodes.len == 0 { |
|
| 194 | 193 | return &[]; |
|
| 195 | 194 | } |
|
| 196 | 195 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 197 | - | for i in 0..nodes.len { |
|
| 198 | - | let node = nodes[i]; |
|
| 196 | + | for node, i in nodes { |
|
| 199 | 197 | match node.value { |
|
| 200 | 198 | case super::NodeValue::RecordField { field, type, value } => { |
|
| 201 | 199 | buf[i] = fieldToExpr(a, field, type, value); |
|
| 202 | 200 | } |
|
| 203 | 201 | else => { |
| 217 | 215 | fn variantListToExprs(a: *mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 218 | 216 | if nodes.len == 0 { |
|
| 219 | 217 | return &[]; |
|
| 220 | 218 | } |
|
| 221 | 219 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 222 | - | for i in 0..nodes.len { |
|
| 223 | - | let node = nodes[i]; |
|
| 220 | + | for node, i in nodes { |
|
| 224 | 221 | match node.value { |
|
| 225 | 222 | case super::NodeValue::UnionDeclVariant(v) => { |
|
| 226 | 223 | buf[i] = variantToExpr(a, v.name, v.type); |
|
| 227 | 224 | } |
|
| 228 | 225 | else => { |
| 259 | 256 | case super::NodeValue::UnOp(u) => |
|
| 260 | 257 | return sexpr::list(a, unOpName(u.op), &[toExpr(a, u.value)]), |
|
| 261 | 258 | case super::NodeValue::Call(c) => { |
|
| 262 | 259 | let buf = try! sexpr::allocExprs(a, c.args.len as u32 + 1); |
|
| 263 | 260 | buf[0] = toExpr(a, c.callee); |
|
| 264 | - | for i in 0..c.args.len { buf[i + 1] = toExpr(a, c.args[i]); } |
|
| 261 | + | for arg, i in c.args { buf[i + 1] = toExpr(a, arg); } |
|
| 265 | 262 | return sexpr::Expr::List { head: "call", tail: buf, multiline: false }; |
|
| 266 | 263 | } |
|
| 267 | 264 | case super::NodeValue::BuiltinCall { kind, args } => |
|
| 268 | 265 | return sexpr::list(a, builtinName(kind), nodeListToExprs(a, &args[..])), |
|
| 269 | 266 | case super::NodeValue::Subscript { container, index } => |
| 291 | 288 | let buf = try! sexpr::allocExprs(a, total); |
|
| 292 | 289 | let mut idx: u32 = 0; |
|
| 293 | 290 | if let tn = lit.typeName { |
|
| 294 | 291 | buf[idx] = toExpr(a, tn); idx = idx + 1; |
|
| 295 | 292 | } |
|
| 296 | - | for i in 0..lit.fields.len { |
|
| 297 | - | buf[idx + i] = toExpr(a, lit.fields[i]); |
|
| 293 | + | for field, i in lit.fields { |
|
| 294 | + | buf[idx + i] = toExpr(a, field); |
|
| 298 | 295 | } |
|
| 299 | 296 | return sexpr::Expr::List { head: "record-lit", tail: buf, multiline: lit.fields.len > 2 }; |
|
| 300 | 297 | } |
|
| 301 | 298 | case super::NodeValue::RecordLitField(f) => |
|
| 302 | 299 | return sexpr::list(a, "field", &[toExprOpt(a, f.label), toExpr(a, f.value)]), |
| 463 | 460 | ||
| 464 | 461 | /// Dump the tree rooted at `root`, using the provided arena for allocation. |
|
| 465 | 462 | pub fn printTree(root: *super::Node, arena: *mut alloc::Arena) { |
|
| 466 | 463 | match root.value { |
|
| 467 | 464 | case super::NodeValue::Block(blk) => { |
|
| 468 | - | for i in 0..blk.statements.len { |
|
| 469 | - | sexpr::print(toExpr(arena, blk.statements[i]), 0); |
|
| 465 | + | for stmt, i in blk.statements { |
|
| 466 | + | sexpr::print(toExpr(arena, stmt), 0); |
|
| 470 | 467 | if i < blk.statements.len - 1 { io::print("\n\n"); } |
|
| 471 | 468 | } |
|
| 472 | 469 | io::print("\n"); |
|
| 473 | 470 | } |
|
| 474 | 471 | else => { |
lib/std/lang/gen/regalloc/assign.rad
+6 -7
| 74 | 74 | } |
|
| 75 | 75 | // Pre-assign function parameters to argument registers. |
|
| 76 | 76 | // Cross-call params are NOT pre-assigned here; they will be allocated |
|
| 77 | 77 | // to callee-saved registers by the normal path, and isel emits moves |
|
| 78 | 78 | // from the arg register to the assigned register at function entry. |
|
| 79 | - | for i in 0..func.params.len { |
|
| 79 | + | for param, i in func.params { |
|
| 80 | 80 | if i < config.argRegs.len { |
|
| 81 | - | if not bitset::contains(&spillInfo.calleeClass, func.params[i].value.n) { |
|
| 82 | - | assignments[func.params[i].value.n] = config.argRegs[i]; |
|
| 81 | + | if not bitset::contains(&spillInfo.calleeClass, param.value.n) { |
|
| 82 | + | assignments[param.value.n] = config.argRegs[i]; |
|
| 83 | 83 | } |
|
| 84 | 84 | } |
|
| 85 | 85 | } |
|
| 86 | 86 | let blkEnd = try alloc::allocSlice(arena, @sizeOf(RegMap), @alignOf(RegMap), blockCount) as *mut [RegMap]; |
|
| 87 | 87 | for i in 0..blockCount { |
| 144 | 144 | assignments[p.value.n] = rallocReg(&mut current, &mut usedRegs, p.value.n, allocatable, config.calleeSaved, spillInfo); |
|
| 145 | 145 | } |
|
| 146 | 146 | } |
|
| 147 | 147 | ||
| 148 | 148 | // Process each instruction. |
|
| 149 | - | for i in 0..block.instrs.len { |
|
| 150 | - | let instr = block.instrs[i]; |
|
| 149 | + | for instr, i in block.instrs { |
|
| 151 | 150 | let mut ctx = InstrCtx { |
|
| 152 | 151 | current: &mut current, |
|
| 153 | 152 | usedRegs: &mut usedRegs, |
|
| 154 | 153 | func, |
|
| 155 | 154 | live, |
| 174 | 173 | } |
|
| 175 | 174 | // Compute bitmask of used callee-saved registers. |
|
| 176 | 175 | let mut usedCalleeSaved: u32 = 0; |
|
| 177 | 176 | for i in 0..maxReg { |
|
| 178 | 177 | if let phys = assignments[i] { |
|
| 179 | - | for j in 0..config.calleeSaved.len { |
|
| 180 | - | if phys == config.calleeSaved[j] { |
|
| 178 | + | for saved, j in config.calleeSaved { |
|
| 179 | + | if phys == saved { |
|
| 181 | 180 | usedCalleeSaved |= (1 << j); |
|
| 182 | 181 | } |
|
| 183 | 182 | } |
|
| 184 | 183 | } |
|
| 185 | 184 | } |
lib/std/lang/il/printer.rad
+8 -8
| 178 | 178 | } |
|
| 179 | 179 | ||
| 180 | 180 | /// Write a comma-separated argument list in parentheses. |
|
| 181 | 181 | fn writeArgs(out: *mut sexpr::Output, a: *mut alloc::Arena, args: *[super::Val]) { |
|
| 182 | 182 | write(out, "("); |
|
| 183 | - | for i in 0..args.len { |
|
| 183 | + | for arg, i in args { |
|
| 184 | 184 | if i > 0 { |
|
| 185 | 185 | write(out, ", "); |
|
| 186 | 186 | } |
|
| 187 | - | writeVal(out, a, args[i]); |
|
| 187 | + | writeVal(out, a, arg); |
|
| 188 | 188 | } |
|
| 189 | 189 | write(out, ")"); |
|
| 190 | 190 | } |
|
| 191 | 191 | ||
| 192 | 192 | /// Write a typed parameter (e.g., `w32 %0`). |
| 196 | 196 | writeReg(out, a, param.value); |
|
| 197 | 197 | } |
|
| 198 | 198 | ||
| 199 | 199 | /// Write a comma-separated parameter list. |
|
| 200 | 200 | fn writeParams(out: *mut sexpr::Output, a: *mut alloc::Arena, params: *[super::Param]) { |
|
| 201 | - | for i in 0..params.len { |
|
| 201 | + | for param, i in params { |
|
| 202 | 202 | if i > 0 { |
|
| 203 | 203 | write(out, ", "); |
|
| 204 | 204 | } |
|
| 205 | - | writeParam(out, a, params[i]); |
|
| 205 | + | writeParam(out, a, param); |
|
| 206 | 206 | } |
|
| 207 | 207 | } |
|
| 208 | 208 | ||
| 209 | 209 | ////////////////////////// |
|
| 210 | 210 | // Instruction printing // |
| 538 | 538 | ////////////////////// |
|
| 539 | 539 | ||
| 540 | 540 | /// Print a program. |
|
| 541 | 541 | pub fn printProgram(out: *mut sexpr::Output, a: *mut alloc::Arena, program: *super::Program) { |
|
| 542 | 542 | // Data declarations. |
|
| 543 | - | for i in 0..program.data.len { |
|
| 544 | - | writeData(out, a, program.data[i]); |
|
| 543 | + | for data, i in program.data { |
|
| 544 | + | writeData(out, a, data); |
|
| 545 | 545 | if i < program.data.len - 1 or program.fns.len > 0 { |
|
| 546 | 546 | write(out, "\n"); |
|
| 547 | 547 | } |
|
| 548 | 548 | } |
|
| 549 | 549 | // Functions. |
|
| 550 | - | for i in 0..program.fns.len { |
|
| 551 | - | writeFn(out, a, program.fns[i]); |
|
| 550 | + | for func, i in program.fns { |
|
| 551 | + | writeFn(out, a, func); |
|
| 552 | 552 | if i < program.fns.len - 1 { |
|
| 553 | 553 | write(out, "\n"); |
|
| 554 | 554 | } |
|
| 555 | 555 | } |
|
| 556 | 556 | } |
lib/std/lang/lower.rad
+22 -33
| 1065 | 1065 | } |
|
| 1066 | 1066 | ||
| 1067 | 1067 | // Fill inherited method slots from supertraits. |
|
| 1068 | 1068 | // These methods were already lowered as part of the supertrait instance |
|
| 1069 | 1069 | // declarations and use the same `Type::method` qualified name. |
|
| 1070 | - | for i in 0..traitInfo.methods.len { |
|
| 1070 | + | for method, i in traitInfo.methods { |
|
| 1071 | 1071 | if not methodNameSet[i] { |
|
| 1072 | - | let mName = traitInfo.methods[i].name; |
|
| 1073 | - | methodNames[i] = instanceMethodName(self, nil, typeName, mName); |
|
| 1072 | + | methodNames[i] = instanceMethodName(self, nil, typeName, method.name); |
|
| 1074 | 1073 | } |
|
| 1075 | 1074 | } |
|
| 1076 | 1075 | ||
| 1077 | 1076 | // Create v-table in data section, used for dynamic dispatch. |
|
| 1078 | 1077 | let vName = vtableName(self, nil, typeName, tName); |
| 1449 | 1448 | recInfo: resolver::RecordType, |
|
| 1450 | 1449 | dataPrefix: *[u8], |
|
| 1451 | 1450 | b: *mut DataValueBuilder |
|
| 1452 | 1451 | ) throws (LowerError) { |
|
| 1453 | 1452 | let layout = recInfo.layout; |
|
| 1454 | - | for i in 0..args.len { |
|
| 1455 | - | let argNode = args[i]; |
|
| 1453 | + | for argNode, i in args { |
|
| 1456 | 1454 | let mut valueNode = argNode; |
|
| 1457 | 1455 | if let case ast::NodeValue::RecordLitField(fieldLit) = argNode.value { |
|
| 1458 | 1456 | valueNode = fieldLit.value; |
|
| 1459 | 1457 | } |
|
| 1460 | 1458 | let fieldInfo = recInfo.fields[i]; |
| 2823 | 2821 | } |
|
| 2824 | 2822 | let newArgs = try! alloc::allocSlice( |
|
| 2825 | 2823 | self.low.arena, @sizeOf(il::Val), @alignOf(il::Val), capacity |
|
| 2826 | 2824 | ) as *mut [il::Val]; |
|
| 2827 | 2825 | ||
| 2828 | - | for i in 0..args.len { |
|
| 2829 | - | newArgs[i] = args[i]; |
|
| 2826 | + | for arg, i in args { |
|
| 2827 | + | newArgs[i] = arg; |
|
| 2830 | 2828 | } |
|
| 2831 | 2829 | for i in args.len..capacity { |
|
| 2832 | 2830 | newArgs[i] = il::Val::Undef; |
|
| 2833 | 2831 | } |
|
| 2834 | 2832 | return newArgs; |
| 3177 | 3175 | let mut blocks: [BlockId; 32] = undefined; |
|
| 3178 | 3176 | let mut cases: *mut [il::SwitchCase] = &mut []; |
|
| 3179 | 3177 | let mut defaultIdx: u32 = 0; |
|
| 3180 | 3178 | let entry = currentBlock(self); |
|
| 3181 | 3179 | ||
| 3182 | - | for i in 0..prongs.len { |
|
| 3183 | - | let p = prongs[i]; |
|
| 3180 | + | for p, i in prongs { |
|
| 3184 | 3181 | let case ast::NodeValue::MatchProng(prong) = p.value |
|
| 3185 | 3182 | else throw LowerError::UnexpectedNodeValue(p); |
|
| 3186 | 3183 | ||
| 3187 | 3184 | match prong.arm { |
|
| 3188 | 3185 | case ast::ProngArm::Binding(_), ast::ProngArm::Else => { |
| 3210 | 3207 | defaultTarget: blocks[defaultIdx].n, |
|
| 3211 | 3208 | defaultArgs: &mut [], |
|
| 3212 | 3209 | cases: &mut cases[..] |
|
| 3213 | 3210 | }); |
|
| 3214 | 3211 | ||
| 3215 | - | for i in 0..prongs.len { |
|
| 3216 | - | let p = prongs[i]; |
|
| 3212 | + | for p, i in prongs { |
|
| 3217 | 3213 | let case ast::NodeValue::MatchProng(prong) = p.value |
|
| 3218 | 3214 | else throw LowerError::UnexpectedNodeValue(p); |
|
| 3219 | 3215 | ||
| 3220 | 3216 | try switchToAndSeal(self, blocks[i]); |
|
| 3221 | 3217 | try lowerNode(self, prong.body); |
| 3295 | 3291 | // Fallback: chained branches. |
|
| 3296 | 3292 | let firstArm = try createBlock(self, "arm"); |
|
| 3297 | 3293 | try emitJmp(self, firstArm); |
|
| 3298 | 3294 | try switchToAndSeal(self, firstArm); |
|
| 3299 | 3295 | ||
| 3300 | - | for i in 0..prongs.len { |
|
| 3296 | + | for prongNode, i in prongs { |
|
| 3301 | 3297 | let prongScope = enterVarScope(self); |
|
| 3302 | - | let prongNode = prongs[i]; |
|
| 3303 | 3298 | let case ast::NodeValue::MatchProng(prong) = prongNode.value |
|
| 3304 | 3299 | else panic "lowerMatch: expected match prong"; |
|
| 3305 | 3300 | ||
| 3306 | 3301 | let isLastArm = i + 1 == prongs.len; |
|
| 3307 | 3302 | let hasGuard = prong.guard != nil; |
| 4215 | 4210 | let cases = try! alloc::allocSlice( |
|
| 4216 | 4211 | self.low.arena, @sizeOf(il::SwitchCase), @alignOf(il::SwitchCase), unionInfo.variants.len as u32 |
|
| 4217 | 4212 | ) as *mut [il::SwitchCase]; |
|
| 4218 | 4213 | ||
| 4219 | 4214 | let mut caseBlocks: [?BlockId; resolver::MAX_UNION_VARIANTS] = undefined; |
|
| 4220 | - | for i in 0..unionInfo.variants.len { |
|
| 4221 | - | if unionInfo.variants[i].valueType == resolver::Type::Void { |
|
| 4215 | + | for variant, i in unionInfo.variants { |
|
| 4216 | + | if variant.valueType == resolver::Type::Void { |
|
| 4222 | 4217 | cases[i] = il::SwitchCase { |
|
| 4223 | 4218 | value: i as i64, |
|
| 4224 | 4219 | target: mergeBlock.n, |
|
| 4225 | 4220 | args: trueArgs |
|
| 4226 | 4221 | }; |
| 4256 | 4251 | } |
|
| 4257 | 4252 | } |
|
| 4258 | 4253 | let valOffset = unionInfo.valOffset as i32; |
|
| 4259 | 4254 | ||
| 4260 | 4255 | // Emit payload comparison blocks for non-void variants. |
|
| 4261 | - | for i in 0..unionInfo.variants.len { |
|
| 4256 | + | for variant, i in unionInfo.variants { |
|
| 4262 | 4257 | if let caseBlock = caseBlocks[i] { |
|
| 4263 | 4258 | try switchToAndSeal(self, caseBlock); |
|
| 4264 | 4259 | let payloadEq = try emitEqAtOffset( |
|
| 4265 | - | self, a, b, offset + valOffset, unionInfo.variants[i].valueType |
|
| 4260 | + | self, a, b, offset + valOffset, variant.valueType |
|
| 4266 | 4261 | ); |
|
| 4267 | 4262 | try emitJmpWithArg(self, mergeBlock, payloadEq); |
|
| 4268 | 4263 | } |
|
| 4269 | 4264 | } |
|
| 4270 | 4265 | // Emit unreachable block. |
| 4395 | 4390 | dst: il::Reg, |
|
| 4396 | 4391 | recInfo: *resolver::RecordType, |
|
| 4397 | 4392 | fields: *mut [*ast::Node], |
|
| 4398 | 4393 | offset: i32 |
|
| 4399 | 4394 | ) throws (LowerError) { |
|
| 4400 | - | for i in 0..fields.len { |
|
| 4401 | - | let fieldNode = fields[i]; |
|
| 4395 | + | for fieldNode, i in fields { |
|
| 4402 | 4396 | let case ast::NodeValue::RecordLitField(field) = fieldNode.value else { |
|
| 4403 | 4397 | throw LowerError::UnexpectedNodeValue(fieldNode); |
|
| 4404 | 4398 | }; |
|
| 4405 | 4399 | let mut fieldIdx: u32 = i; |
|
| 4406 | 4400 | if recInfo.labeled { |
| 4426 | 4420 | throw LowerError::ExpectedRecord; |
|
| 4427 | 4421 | }; |
|
| 4428 | 4422 | let typ = resolver::Type::Nominal(nominal); |
|
| 4429 | 4423 | let dst = try emitReserve(self, typ); |
|
| 4430 | 4424 | ||
| 4431 | - | for i in 0..args.len { |
|
| 4432 | - | let argNode = args[i]; |
|
| 4425 | + | for argNode, i in args { |
|
| 4433 | 4426 | // Skip `undefined` arguments. |
|
| 4434 | 4427 | if not isUndef(argNode) { |
|
| 4435 | 4428 | let fieldTy = recInfo.fields[i].fieldType; |
|
| 4436 | 4429 | let argVal = try lowerExpr(self, argNode); |
|
| 4437 | 4430 | try emitStore(self, dst, recInfo.fields[i].offset, fieldTy, argVal); |
| 4452 | 4445 | }; |
|
| 4453 | 4446 | let elemTy = *arrInfo.item; |
|
| 4454 | 4447 | let elemLayout = resolver::getTypeLayout(elemTy); |
|
| 4455 | 4448 | let dst = try emitReserve(self, typ); |
|
| 4456 | 4449 | ||
| 4457 | - | for i in 0..elements.len { |
|
| 4458 | - | let elemNode = elements[i]; |
|
| 4450 | + | for elemNode, i in elements { |
|
| 4459 | 4451 | let elemVal = try lowerExpr(self, elemNode); |
|
| 4460 | 4452 | let offset = i * elemLayout.size; |
|
| 4461 | 4453 | ||
| 4462 | 4454 | try emitStore(self, dst, offset as i32, elemTy, elemVal); |
|
| 4463 | 4455 | } |
| 4730 | 4722 | dst: arrayReg, |
|
| 4731 | 4723 | size: il::Val::Imm(arraySize as i64), |
|
| 4732 | 4724 | alignment: elemLayout.alignment |
|
| 4733 | 4725 | }); |
|
| 4734 | 4726 | // Store each element. |
|
| 4735 | - | for i in 0..elements.len { |
|
| 4736 | - | let elemNode = elements[i]; |
|
| 4727 | + | for elemNode, i in elements { |
|
| 4737 | 4728 | let elemVal = try lowerExpr(self, elemNode); |
|
| 4738 | 4729 | let offset = i * elemLayout.size; |
|
| 4739 | 4730 | ||
| 4740 | 4731 | try emitStore(self, arrayReg, offset as i32, *elemTy, elemVal); |
|
| 4741 | 4732 | } |
| 5890 | 5881 | let mut blocks: [BlockId; MAX_CATCH_CLAUSES] = undefined; |
|
| 5891 | 5882 | let mut errTypes: [?resolver::Type; MAX_CATCH_CLAUSES] = undefined; |
|
| 5892 | 5883 | let mut cases: *mut [il::SwitchCase] = &mut []; |
|
| 5893 | 5884 | let mut defaultIdx: ?u32 = nil; |
|
| 5894 | 5885 | ||
| 5895 | - | for i in 0..catches.len { |
|
| 5896 | - | let clauseNode = catches[i]; |
|
| 5886 | + | for clauseNode, i in catches { |
|
| 5897 | 5887 | let case ast::NodeValue::CatchClause(clause) = clauseNode.value |
|
| 5898 | 5888 | else panic "lowerMultiCatch: expected CatchClause"; |
|
| 5899 | 5889 | ||
| 5900 | 5890 | blocks[i] = try createBlock(self, "catch"); |
|
| 5901 | 5891 | addPredecessor(self, blocks[i], entry); |
| 5931 | 5921 | defaultArgs: &mut [], |
|
| 5932 | 5922 | cases |
|
| 5933 | 5923 | }); |
|
| 5934 | 5924 | ||
| 5935 | 5925 | // Second pass: emit each catch clause body. |
|
| 5936 | - | for i in 0..catches.len { |
|
| 5937 | - | let clauseNode = catches[i]; |
|
| 5926 | + | for clauseNode, i in catches { |
|
| 5938 | 5927 | let case ast::NodeValue::CatchClause(clause) = clauseNode.value |
|
| 5939 | 5928 | else panic "lowerMultiCatch: expected CatchClause"; |
|
| 5940 | 5929 | ||
| 5941 | 5930 | try switchToAndSeal(self, blocks[i]); |
|
| 5942 | 5931 | let savedVarsLen = enterVarScope(self); |
| 6245 | 6234 | ||
| 6246 | 6235 | // Data pointer is the receiver (first argument after hidden return param). |
|
| 6247 | 6236 | args[argOffset] = il::Val::Reg(dataReg); |
|
| 6248 | 6237 | ||
| 6249 | 6238 | // Lower user arguments. |
|
| 6250 | - | for i in 0..call.args.len { |
|
| 6251 | - | args[i + 1 + argOffset] = try lowerExpr(self, call.args[i]); |
|
| 6239 | + | for arg, i in call.args { |
|
| 6240 | + | args[i + 1 + argOffset] = try lowerExpr(self, arg); |
|
| 6252 | 6241 | } |
|
| 6253 | 6242 | ||
| 6254 | 6243 | // Allocate the return buffer when needed. |
|
| 6255 | 6244 | if returnParam { |
|
| 6256 | 6245 | if methodFnType.throwList.len > 0 { |
| 6397 | 6386 | // Lower function value and arguments, reserving an extra slot for the |
|
| 6398 | 6387 | // hidden return buffer when needed. |
|
| 6399 | 6388 | let callee = try lowerCallee(self, call.callee); |
|
| 6400 | 6389 | let offset: u32 = 1 if returnParam else 0; |
|
| 6401 | 6390 | let args = try allocVals(self, call.args.len + offset); |
|
| 6402 | - | for i in 0..call.args.len { |
|
| 6403 | - | args[i + offset] = try lowerExpr(self, call.args[i]); |
|
| 6391 | + | for arg, i in call.args { |
|
| 6392 | + | args[i + offset] = try lowerExpr(self, arg); |
|
| 6404 | 6393 | } |
|
| 6405 | 6394 | ||
| 6406 | 6395 | // Allocate the return buffer when needed. |
|
| 6407 | 6396 | if returnParam { |
|
| 6408 | 6397 | if fnInfo.throwList.len > 0 { |
lib/std/lang/module.rad
+2 -2
| 430 | 430 | pub fn trimExtension(path: *[u8]) -> ?*[u8] { |
|
| 431 | 431 | if path.len < SOURCE_EXT.len { |
|
| 432 | 432 | return nil; |
|
| 433 | 433 | } |
|
| 434 | 434 | let extStart = path.len - SOURCE_EXT.len; |
|
| 435 | - | for i in 0..SOURCE_EXT.len { |
|
| 436 | - | if path[extStart + i] != SOURCE_EXT[i] { |
|
| 435 | + | for ext, i in SOURCE_EXT { |
|
| 436 | + | if path[extStart + i] != ext { |
|
| 437 | 437 | return nil; |
|
| 438 | 438 | } |
|
| 439 | 439 | } |
|
| 440 | 440 | return &path[..extStart]; |
|
| 441 | 441 | } |
lib/std/lang/module/printer.rad
+1 -1
| 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 i in 0..path.len { buf[i] = sexpr::sym(path[i]); } |
|
| 42 | + | for seg, i in path { buf[i] = sexpr::sym(seg); } |
|
| 43 | 43 | pathBuf = buf; |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | let mut childBuf: *[sexpr::Expr] = &[]; |
|
| 47 | 47 | if entry.childrenLen > 0 { |
lib/std/lang/resolver.rad
+20 -27
| 2978 | 2978 | /// assignable to its corresponding field type. |
|
| 2979 | 2979 | fn checkRecordConstructorArgs(self: *mut Resolver, node: *ast::Node, args: *mut [*ast::Node], recInfo: RecordType) |
|
| 2980 | 2980 | throws (ResolveError) |
|
| 2981 | 2981 | { |
|
| 2982 | 2982 | try checkRecordArity(self, args, recInfo, node); |
|
| 2983 | - | for i in 0..args.len { |
|
| 2984 | - | let arg = args[i]; |
|
| 2983 | + | for arg, i in args { |
|
| 2985 | 2984 | let fieldType = recInfo.fields[i].fieldType; |
|
| 2986 | 2985 | try checkAssignable(self, arg, fieldType); |
|
| 2987 | 2986 | } |
|
| 2988 | 2987 | } |
|
| 2989 | 2988 |
| 3505 | 3504 | throw emitError(self, methodNode, ErrorKind::FnArgCountMismatch(CountMismatch { |
|
| 3506 | 3505 | expected: tm.fnType.paramTypes.len as u32, |
|
| 3507 | 3506 | actual: sig.params.len, |
|
| 3508 | 3507 | })); |
|
| 3509 | 3508 | } |
|
| 3510 | - | for j in 0..sig.params.len { |
|
| 3511 | - | let paramNode = sig.params[j]; |
|
| 3509 | + | for paramNode, j in sig.params { |
|
| 3512 | 3510 | let case ast::NodeValue::FnParam(param) = paramNode.value |
|
| 3513 | 3511 | else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier); |
|
| 3514 | 3512 | let instanceParamTy = try resolveValueType(self, param.type); |
|
| 3515 | 3513 | if not typesEqual(instanceParamTy, *tm.fnType.paramTypes[j]) { |
|
| 3516 | 3514 | throw emitTypeMismatch(self, paramNode, TypeMismatch { |
| 3533 | 3531 | throw emitError(self, methodNode, ErrorKind::FnThrowCountMismatch(CountMismatch { |
|
| 3534 | 3532 | expected: tm.fnType.throwList.len as u32, |
|
| 3535 | 3533 | actual: sig.throwList.len, |
|
| 3536 | 3534 | })); |
|
| 3537 | 3535 | } |
|
| 3538 | - | for j in 0..sig.throwList.len { |
|
| 3539 | - | let instanceThrowTy = try resolveValueType(self, sig.throwList[j]); |
|
| 3536 | + | for throwNode, j in sig.throwList { |
|
| 3537 | + | let instanceThrowTy = try resolveValueType(self, throwNode); |
|
| 3540 | 3538 | if not typesEqual(instanceThrowTy, *tm.fnType.throwList[j]) { |
|
| 3541 | - | throw emitTypeMismatch(self, sig.throwList[j], TypeMismatch { |
|
| 3539 | + | throw emitTypeMismatch(self, throwNode, TypeMismatch { |
|
| 3542 | 3540 | expected: *tm.fnType.throwList[j], |
|
| 3543 | 3541 | actual: instanceThrowTy, |
|
| 3544 | 3542 | }); |
|
| 3545 | 3543 | } |
|
| 3546 | 3544 | } |
| 3581 | 3579 | ||
| 3582 | 3580 | // Fill inherited method slots from supertrait instances. |
|
| 3583 | 3581 | for superTrait in traitInfo.supertraits { |
|
| 3584 | 3582 | let superInst = findInstance(self, superTrait, concreteType) |
|
| 3585 | 3583 | else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name)); |
|
| 3586 | - | for mi in 0..superTrait.methods.len { |
|
| 3587 | - | let merged = findTraitMethod(traitInfo, superTrait.methods[mi].name) |
|
| 3584 | + | for superMethod, mi in superTrait.methods { |
|
| 3585 | + | let merged = findTraitMethod(traitInfo, superMethod.name) |
|
| 3588 | 3586 | else panic "resolveInstanceDecl: inherited method not found"; |
|
| 3589 | 3587 | if not covered[merged.index] { |
|
| 3590 | 3588 | entry.methods[merged.index] = superInst.methods[mi]; |
|
| 3591 | 3589 | covered[merged.index] = true; |
|
| 3592 | 3590 | } |
|
| 3593 | 3591 | } |
|
| 3594 | 3592 | } |
|
| 3595 | 3593 | ||
| 3596 | 3594 | // Check that all trait methods are implemented. |
|
| 3597 | - | for i in 0..traitInfo.methods.len { |
|
| 3595 | + | for method, i in traitInfo.methods { |
|
| 3598 | 3596 | if not covered[i] { |
|
| 3599 | - | throw emitError(self, node, ErrorKind::MissingTraitMethod(traitInfo.methods[i].name)); |
|
| 3597 | + | throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name)); |
|
| 3600 | 3598 | } |
|
| 3601 | 3599 | } |
|
| 3602 | 3600 | self.instances[self.instancesLen] = entry; |
|
| 3603 | 3601 | self.instancesLen += 1; |
|
| 3604 | 3602 |
| 3698 | 3696 | ||
| 3699 | 3697 | if decl.variants.len > MAX_UNION_VARIANTS { |
|
| 3700 | 3698 | panic "resolveUnionBody: maximum union variants exceeded"; |
|
| 3701 | 3699 | } |
|
| 3702 | 3700 | let mut iota: u32 = 0; |
|
| 3703 | - | for i in 0..decl.variants.len { |
|
| 3704 | - | let variantNode = decl.variants[i]; |
|
| 3701 | + | for variantNode, i in decl.variants { |
|
| 3705 | 3702 | let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value |
|
| 3706 | 3703 | else panic "resolveUnionBody: invalid union variant"; |
|
| 3707 | 3704 | let variantName = try nodeName(self, variantDecl.name); |
|
| 3708 | 3705 | // Resolve the variant's payload type if present. |
|
| 3709 | 3706 | let mut variantType = Type::Void; |
| 4216 | 4213 | } |
|
| 4217 | 4214 | } |
|
| 4218 | 4215 | } |
|
| 4219 | 4216 | // Check that all variants are covered. |
|
| 4220 | 4217 | if not state.catchAll { |
|
| 4221 | - | for i in 0..info.variants.len { |
|
| 4218 | + | for variant, i in info.variants { |
|
| 4222 | 4219 | if not covered[i] { |
|
| 4223 | 4220 | throw emitError( |
|
| 4224 | - | self, node, ErrorKind::UnionMatchNonExhaustive(info.variants[i].name) |
|
| 4221 | + | self, node, ErrorKind::UnionMatchNonExhaustive(variant.name) |
|
| 4225 | 4222 | ); |
|
| 4226 | 4223 | } |
|
| 4227 | 4224 | } |
|
| 4228 | 4225 | } else if coveredCount == info.variants.len as u32 { |
|
| 4229 | 4226 | throw emitError(self, node, ErrorKind::UnreachableElse); |
| 4451 | 4448 | match pattern.value { |
|
| 4452 | 4449 | case ast::NodeValue::Call(call) => { |
|
| 4453 | 4450 | // Unlabeled patterns: `S(x, y)`. |
|
| 4454 | 4451 | try checkRecordArity(self, call.args, recInfo, pattern); |
|
| 4455 | 4452 | ||
| 4456 | - | for i in 0..call.args.len { |
|
| 4457 | - | let binding = call.args[i]; |
|
| 4453 | + | for binding, i in call.args { |
|
| 4458 | 4454 | let fieldType = recInfo.fields[i].fieldType; |
|
| 4459 | 4455 | try bindPatternVar(self, binding, fieldType, matchBy); |
|
| 4460 | 4456 | } |
|
| 4461 | 4457 | } |
|
| 4462 | 4458 | case ast::NodeValue::RecordLit(lit) => { |
| 4658 | 4654 | throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch { |
|
| 4659 | 4655 | expected: info.paramTypes.len as u32, |
|
| 4660 | 4656 | actual: call.args.len, |
|
| 4661 | 4657 | })); |
|
| 4662 | 4658 | } |
|
| 4663 | - | for i in 0..call.args.len { |
|
| 4664 | - | let argNode = call.args[i]; |
|
| 4659 | + | for argNode, i in call.args { |
|
| 4665 | 4660 | let expectedTy = *info.paramTypes[i]; |
|
| 4666 | 4661 | ||
| 4667 | 4662 | try checkAssignable(self, argNode, expectedTy); |
|
| 4668 | 4663 | } |
|
| 4669 | 4664 | } |
| 4880 | 4875 | } |
|
| 4881 | 4876 | } |
|
| 4882 | 4877 | ||
| 4883 | 4878 | /// Find a record field by name. |
|
| 4884 | 4879 | fn findRecordField(s: *RecordType, fieldName: *[u8]) -> ?u32 { |
|
| 4885 | - | for i in 0..s.fields.len { |
|
| 4886 | - | if let name = s.fields[i].name { |
|
| 4880 | + | for field, i in s.fields { |
|
| 4881 | + | if let name = field.name { |
|
| 4887 | 4882 | if name == fieldName { |
|
| 4888 | 4883 | return i; |
|
| 4889 | 4884 | } |
|
| 4890 | 4885 | } |
|
| 4891 | 4886 | } |
| 5018 | 5013 | let missingName = recordType.fields[lit.fields.len].name else panic; |
|
| 5019 | 5014 | throw emitError(self, node, ErrorKind::RecordFieldMissing(missingName)); |
|
| 5020 | 5015 | } |
|
| 5021 | 5016 | ||
| 5022 | 5017 | // Fields must be in declaration order. |
|
| 5023 | - | for idx in 0..lit.fields.len { |
|
| 5024 | - | let fieldNode = lit.fields[idx]; |
|
| 5018 | + | for fieldNode, idx in lit.fields { |
|
| 5025 | 5019 | let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value |
|
| 5026 | 5020 | else panic "resolveRecordLit: expected field node value"; |
|
| 5027 | 5021 | let label = fieldArg.label |
|
| 5028 | 5022 | else panic "resolveRecordLit: expected labeled field"; |
|
| 5029 | 5023 | let fieldName = try nodeName(self, label); |
| 5075 | 5069 | })); |
|
| 5076 | 5070 | } |
|
| 5077 | 5071 | } |
|
| 5078 | 5072 | ||
| 5079 | 5073 | // Fields must be in declaration order. |
|
| 5080 | - | for idx in 0..lit.fields.len { |
|
| 5081 | - | let fieldNode = lit.fields[idx]; |
|
| 5074 | + | for fieldNode, idx in lit.fields { |
|
| 5082 | 5075 | let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value |
|
| 5083 | 5076 | else panic "resolveAnonRecordLit: expected field node value"; |
|
| 5084 | 5077 | let label = fieldArg.label |
|
| 5085 | 5078 | else panic "resolveAnonRecordLit: expected labeled field"; |
|
| 5086 | 5079 | let fieldName = try nodeName(self, label); |
| 5696 | 5689 | if let typeNode = clause.typeNode { |
|
| 5697 | 5690 | // Typed catch clause: validate against callee's throw list. |
|
| 5698 | 5691 | let errTy = try infer(self, typeNode); |
|
| 5699 | 5692 | let mut foundIdx: ?u32 = nil; |
|
| 5700 | 5693 | ||
| 5701 | - | for j in 0..calleeInfo.throwList.len { |
|
| 5702 | - | if errTy == *calleeInfo.throwList[j] { |
|
| 5694 | + | for throwType, j in calleeInfo.throwList { |
|
| 5695 | + | if errTy == *throwType { |
|
| 5703 | 5696 | foundIdx = j; |
|
| 5704 | 5697 | break; |
|
| 5705 | 5698 | } |
|
| 5706 | 5699 | } |
|
| 5707 | 5700 | let idx = foundIdx else { |
lib/std/lang/resolver/printer.rad
+4 -4
| 110 | 110 | io::print("?"); |
|
| 111 | 111 | printTypeBody(*inner, brief); |
|
| 112 | 112 | } |
|
| 113 | 113 | case super::Type::Fn(fnType) => { |
|
| 114 | 114 | io::print("fn("); |
|
| 115 | - | for i in 0..fnType.paramTypes.len { |
|
| 115 | + | for paramType, i in fnType.paramTypes { |
|
| 116 | 116 | if i > 0 { |
|
| 117 | 117 | io::print(", "); |
|
| 118 | 118 | } |
|
| 119 | - | printTypeName(*fnType.paramTypes[i]); |
|
| 119 | + | printTypeName(*paramType); |
|
| 120 | 120 | } |
|
| 121 | 121 | io::print(")"); |
|
| 122 | 122 | io::print(" -> "); |
|
| 123 | 123 | printTypeName(*fnType.returnType); |
|
| 124 | 124 | if fnType.throwList.len > 0 { |
|
| 125 | 125 | io::print(" throws "); |
|
| 126 | - | for i in 0..fnType.throwList.len { |
|
| 126 | + | for throwType, i in fnType.throwList { |
|
| 127 | 127 | if i > 0 { |
|
| 128 | 128 | io::print(", "); |
|
| 129 | 129 | } |
|
| 130 | - | printTypeName(*fnType.throwList[i]); |
|
| 130 | + | printTypeName(*throwType); |
|
| 131 | 131 | } |
|
| 132 | 132 | } |
|
| 133 | 133 | } |
|
| 134 | 134 | case super::Type::Nominal(info) => { |
|
| 135 | 135 | if brief { |
lib/std/lang/sexpr.rad
+9 -9
| 45 | 45 | pub fn allocItems(a: *mut alloc::Arena, items: *[Expr]) -> *[Expr] { |
|
| 46 | 46 | if items.len == 0 { |
|
| 47 | 47 | return &[]; |
|
| 48 | 48 | } |
|
| 49 | 49 | let buf = try! allocExprs(a, items.len); |
|
| 50 | - | for i in 0..items.len { |
|
| 51 | - | buf[i] = items[i]; |
|
| 50 | + | for item, i in items { |
|
| 51 | + | buf[i] = item; |
|
| 52 | 52 | } |
|
| 53 | 53 | return buf; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | /// Allocate and copy prefix items followed by suffix items. |
| 58 | 58 | let total = prefix.len + suffix.len; |
|
| 59 | 59 | if total == 0 { |
|
| 60 | 60 | return &[]; |
|
| 61 | 61 | } |
|
| 62 | 62 | let buf = try! allocExprs(a, total); |
|
| 63 | - | for i in 0..prefix.len { |
|
| 64 | - | buf[i] = prefix[i]; |
|
| 63 | + | for item, i in prefix { |
|
| 64 | + | buf[i] = item; |
|
| 65 | 65 | } |
|
| 66 | - | for i in 0..suffix.len { |
|
| 67 | - | buf[prefix.len + i] = suffix[i]; |
|
| 66 | + | for item, i in suffix { |
|
| 67 | + | buf[prefix.len + i] = item; |
|
| 68 | 68 | } |
|
| 69 | 69 | return buf; |
|
| 70 | 70 | } |
|
| 71 | 71 | ||
| 72 | 72 | /// Shorthand for creating a symbol. |
| 177 | 177 | } |
|
| 178 | 178 | write(out, ")"); |
|
| 179 | 179 | } |
|
| 180 | 180 | case Expr::Vec { items } => { |
|
| 181 | 181 | write(out, "["); |
|
| 182 | - | for i in 0..items.len { |
|
| 183 | - | if items[i] != Expr::Null { |
|
| 182 | + | for item, i in items { |
|
| 183 | + | if item != Expr::Null { |
|
| 184 | 184 | if i > 0 { |
|
| 185 | 185 | write(out, " "); |
|
| 186 | 186 | } |
|
| 187 | - | printTo(items[i], depth, out); |
|
| 187 | + | printTo(item, depth, out); |
|
| 188 | 188 | } |
|
| 189 | 189 | } |
|
| 190 | 190 | write(out, "]"); |
|
| 191 | 191 | } |
|
| 192 | 192 | case Expr::Block { name, items, children } => { |