| ... | @@ -273,6 +273,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -273,6 +273,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 273 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), | 273 | .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), |
| 274 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), | 274 | .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?), |
| 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), | 275 | .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), |
| | 276 | .For => return forExpr(mod, scope, rl, node.castTag(.For).?), |
| 276 | | 277 | |
| 277 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), | 278 | .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), |
| 278 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), | 279 | .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), |
| ... | @@ -288,7 +289,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -288,7 +289,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 288 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), | 289 | .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), |
| 289 | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), | 290 | .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), |
| 290 | .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}), | 291 | .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}), |
| 291 | .For => return mod.failNode(scope, node, "TODO implement astgen.expr for .For", .{}), | | |
| 292 | .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), | 292 | .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), |
| 293 | .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}), | 293 | .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}), |
| 294 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), | 294 | .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), |
| ... | @@ -497,7 +497,7 @@ fn varDecl( | ... | @@ -497,7 +497,7 @@ fn varDecl( |
| 497 | const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTrailer("type_node")) |type_node| a: { | 497 | const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTrailer("type_node")) |type_node| a: { |
| 498 | const type_inst = try typeExpr(mod, scope, type_node); | 498 | const type_inst = try typeExpr(mod, scope, type_node); |
| 499 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); | 499 | const alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst); |
| 500 | break :a .{ .alloc = try addZIRUnOp(mod, scope, name_src, .alloc, type_inst), .result_loc = .{ .ptr = alloc } }; | 500 | break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } }; |
| 501 | } else a: { | 501 | } else a: { |
| 502 | const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred); | 502 | const alloc = try addZIRNoOp(mod, scope, name_src, .alloc_inferred); |
| 503 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? } }; | 503 | break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? } }; |
| ... | @@ -624,7 +624,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, | ... | @@ -624,7 +624,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, |
| 624 | .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, | 624 | .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, |
| 625 | .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, | 625 | .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, |
| 626 | .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, | 626 | .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, |
| 627 | .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, | 627 | .Slice => if (mutable) T.mut_slice_type else T.const_slice_type, |
| 628 | }, child_type); | 628 | }, child_type); |
| 629 | } | 629 | } |
| 630 | | 630 | |
| ... | @@ -794,9 +794,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix | ... | @@ -794,9 +794,7 @@ fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfix |
| 794 | const lhs = try expr(mod, scope, .ref, node.lhs); | 794 | const lhs = try expr(mod, scope, .ref, node.lhs); |
| 795 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); | 795 | const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?); |
| 796 | | 796 | |
| 797 | const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}); | 797 | return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{})); |
| 798 | if (rl == .ref) return pointer; | | |
| 799 | return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer)); | | |
| 800 | } | 798 | } |
| 801 | | 799 | |
| 802 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { | 800 | fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { |
| ... | @@ -1080,6 +1078,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1080,6 +1078,12 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1080 | } | 1078 | } |
| 1081 | } | 1079 | } |
| 1082 | | 1080 | |
| | 1081 | if (while_node.label) |tok| |
| | 1082 | return mod.failTok(scope, tok, "TODO labeled while", .{}); |
| | 1083 | |
| | 1084 | if (while_node.inline_token) |tok| |
| | 1085 | return mod.failTok(scope, tok, "TODO inline while", .{}); |
| | 1086 | |
| 1083 | var expr_scope: Scope.GenZIR = .{ | 1087 | var expr_scope: Scope.GenZIR = .{ |
| 1084 | .parent = scope, | 1088 | .parent = scope, |
| 1085 | .decl = scope.decl().?, | 1089 | .decl = scope.decl().?, |
| ... | @@ -1198,6 +1202,179 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W | ... | @@ -1198,6 +1202,179 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W |
| 1198 | return &while_block.base; | 1202 | return &while_block.base; |
| 1199 | } | 1203 | } |
| 1200 | | 1204 | |
| | 1205 | fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For) InnerError!*zir.Inst { |
| | 1206 | if (for_node.label) |tok| |
| | 1207 | return mod.failTok(scope, tok, "TODO labeled for", .{}); |
| | 1208 | |
| | 1209 | if (for_node.inline_token) |tok| |
| | 1210 | return mod.failTok(scope, tok, "TODO inline for", .{}); |
| | 1211 | |
| | 1212 | var for_scope: Scope.GenZIR = .{ |
| | 1213 | .parent = scope, |
| | 1214 | .decl = scope.decl().?, |
| | 1215 | .arena = scope.arena(), |
| | 1216 | .instructions = .{}, |
| | 1217 | }; |
| | 1218 | defer for_scope.instructions.deinit(mod.gpa); |
| | 1219 | |
| | 1220 | // setup variables and constants |
| | 1221 | const tree = scope.tree(); |
| | 1222 | const for_src = tree.token_locs[for_node.for_token].start; |
| | 1223 | const index_ptr = blk: { |
| | 1224 | const usize_type = try addZIRInstConst(mod, &for_scope.base, for_src, .{ |
| | 1225 | .ty = Type.initTag(.type), |
| | 1226 | .val = Value.initTag(.usize_type), |
| | 1227 | }); |
| | 1228 | const index_ptr = try addZIRUnOp(mod, &for_scope.base, for_src, .alloc, usize_type); |
| | 1229 | // initialize to zero |
| | 1230 | const zero = try addZIRInstConst(mod, &for_scope.base, for_src, .{ |
| | 1231 | .ty = Type.initTag(.usize), |
| | 1232 | .val = Value.initTag(.zero), |
| | 1233 | }); |
| | 1234 | _ = try addZIRBinOp(mod, &for_scope.base, for_src, .store, index_ptr, zero); |
| | 1235 | break :blk index_ptr; |
| | 1236 | }; |
| | 1237 | const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr); |
| | 1238 | const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start; |
| | 1239 | const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{ |
| | 1240 | .object_ptr = array_ptr, |
| | 1241 | .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}), |
| | 1242 | }, .{}); |
| | 1243 | |
| | 1244 | var loop_scope: Scope.GenZIR = .{ |
| | 1245 | .parent = &for_scope.base, |
| | 1246 | .decl = for_scope.decl, |
| | 1247 | .arena = for_scope.arena, |
| | 1248 | .instructions = .{}, |
| | 1249 | }; |
| | 1250 | defer loop_scope.instructions.deinit(mod.gpa); |
| | 1251 | |
| | 1252 | var cond_scope: Scope.GenZIR = .{ |
| | 1253 | .parent = &loop_scope.base, |
| | 1254 | .decl = loop_scope.decl, |
| | 1255 | .arena = loop_scope.arena, |
| | 1256 | .instructions = .{}, |
| | 1257 | }; |
| | 1258 | defer cond_scope.instructions.deinit(mod.gpa); |
| | 1259 | |
| | 1260 | // check condition i < array_expr.len |
| | 1261 | const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr); |
| | 1262 | const len = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, len_ptr); |
| | 1263 | const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len); |
| | 1264 | |
| | 1265 | const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{ |
| | 1266 | .condition = cond, |
| | 1267 | .then_body = undefined, // populated below |
| | 1268 | .else_body = undefined, // populated below |
| | 1269 | }, .{}); |
| | 1270 | const cond_block = try addZIRInstBlock(mod, &loop_scope.base, for_src, .{ |
| | 1271 | .instructions = try loop_scope.arena.dupe(*zir.Inst, cond_scope.instructions.items), |
| | 1272 | }); |
| | 1273 | |
| | 1274 | // increment index variable |
| | 1275 | const one = try addZIRInstConst(mod, &loop_scope.base, for_src, .{ |
| | 1276 | .ty = Type.initTag(.usize), |
| | 1277 | .val = Value.initTag(.one), |
| | 1278 | }); |
| | 1279 | const index_plus_one = try addZIRBinOp(mod, &loop_scope.base, for_src, .add, index, one); |
| | 1280 | _ = try addZIRBinOp(mod, &loop_scope.base, for_src, .store, index_ptr, index_plus_one); |
| | 1281 | |
| | 1282 | // looping stuff |
| | 1283 | const loop = try addZIRInstLoop(mod, &for_scope.base, for_src, .{ |
| | 1284 | .instructions = try for_scope.arena.dupe(*zir.Inst, loop_scope.instructions.items), |
| | 1285 | }); |
| | 1286 | const for_block = try addZIRInstBlock(mod, scope, for_src, .{ |
| | 1287 | .instructions = try scope.arena().dupe(*zir.Inst, for_scope.instructions.items), |
| | 1288 | }); |
| | 1289 | |
| | 1290 | // while body |
| | 1291 | const then_src = tree.token_locs[for_node.body.lastToken()].start; |
| | 1292 | var then_scope: Scope.GenZIR = .{ |
| | 1293 | .parent = &cond_scope.base, |
| | 1294 | .decl = cond_scope.decl, |
| | 1295 | .arena = cond_scope.arena, |
| | 1296 | .instructions = .{}, |
| | 1297 | }; |
| | 1298 | defer then_scope.instructions.deinit(mod.gpa); |
| | 1299 | |
| | 1300 | // Most result location types can be forwarded directly; however |
| | 1301 | // if we need to write to a pointer which has an inferred type, |
| | 1302 | // proper type inference requires peer type resolution on the while's |
| | 1303 | // branches. |
| | 1304 | const branch_rl: ResultLoc = switch (rl) { |
| | 1305 | .discard, .none, .ty, .ptr, .ref => rl, |
| | 1306 | .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = for_block }, |
| | 1307 | }; |
| | 1308 | |
| | 1309 | var index_scope: Scope.LocalPtr = undefined; |
| | 1310 | const then_sub_scope = blk: { |
| | 1311 | const payload = for_node.payload.castTag(.PointerIndexPayload).?; |
| | 1312 | const is_ptr = payload.ptr_token != null; |
| | 1313 | const value_name = tree.tokenSlice(payload.value_symbol.firstToken()); |
| | 1314 | if (!mem.eql(u8, value_name, "_")) { |
| | 1315 | return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement for value payload", .{}); |
| | 1316 | } else if (is_ptr) { |
| | 1317 | return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{}); |
| | 1318 | } |
| | 1319 | |
| | 1320 | const index_symbol_node = payload.index_symbol orelse |
| | 1321 | break :blk &then_scope.base; |
| | 1322 | |
| | 1323 | const index_name = tree.tokenSlice(index_symbol_node.firstToken()); |
| | 1324 | if (mem.eql(u8, index_name, "_")) { |
| | 1325 | break :blk &then_scope.base; |
| | 1326 | } |
| | 1327 | // TODO ensure this is const |
| | 1328 | index_scope = .{ |
| | 1329 | .parent = &then_scope.base, |
| | 1330 | .gen_zir = &then_scope, |
| | 1331 | .name = index_name, |
| | 1332 | .ptr = index_ptr, |
| | 1333 | }; |
| | 1334 | break :blk &index_scope.base; |
| | 1335 | }; |
| | 1336 | |
| | 1337 | const then_result = try expr(mod, then_sub_scope, branch_rl, for_node.body); |
| | 1338 | if (!then_result.tag.isNoReturn()) { |
| | 1339 | _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{ |
| | 1340 | .block = cond_block, |
| | 1341 | .operand = then_result, |
| | 1342 | }, .{}); |
| | 1343 | } |
| | 1344 | condbr.positionals.then_body = .{ |
| | 1345 | .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items), |
| | 1346 | }; |
| | 1347 | |
| | 1348 | // else branch |
| | 1349 | var else_scope: Scope.GenZIR = .{ |
| | 1350 | .parent = &cond_scope.base, |
| | 1351 | .decl = cond_scope.decl, |
| | 1352 | .arena = cond_scope.arena, |
| | 1353 | .instructions = .{}, |
| | 1354 | }; |
| | 1355 | defer else_scope.instructions.deinit(mod.gpa); |
| | 1356 | |
| | 1357 | if (for_node.@"else") |else_node| { |
| | 1358 | const else_src = tree.token_locs[else_node.body.lastToken()].start; |
| | 1359 | const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body); |
| | 1360 | if (!else_result.tag.isNoReturn()) { |
| | 1361 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{ |
| | 1362 | .block = for_block, |
| | 1363 | .operand = else_result, |
| | 1364 | }, .{}); |
| | 1365 | } |
| | 1366 | } else { |
| | 1367 | const else_src = tree.token_locs[for_node.lastToken()].start; |
| | 1368 | _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.BreakVoid, .{ |
| | 1369 | .block = for_block, |
| | 1370 | }, .{}); |
| | 1371 | } |
| | 1372 | condbr.positionals.else_body = .{ |
| | 1373 | .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items), |
| | 1374 | }; |
| | 1375 | return &for_block.base; |
| | 1376 | } |
| | 1377 | |
| 1201 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { | 1378 | fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { |
| 1202 | const tree = scope.tree(); | 1379 | const tree = scope.tree(); |
| 1203 | const src = tree.token_locs[cfe.ltoken].start; | 1380 | const src = tree.token_locs[cfe.ltoken].start; |