| author | |
| committer | |
| log | 11998d2972bf1f7253351fc756c4f1766a412f1d |
| tree | 0dc85f1256f937ecc23df204f1fc38c4ccaeea90 |
| parent | 2c12f4a993343abb65ebb881f095c38ba0310306 |
| signature |
5 files changed, 102 insertions(+), 1 deletions(-)
src/astgen.zig+4| ... | ... | @@ -1584,6 +1584,10 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node |
| 1584 | 1584 | const case = uncasted_case.castTag(.SwitchCase).?; |
| 1585 | 1585 | const case_src = tree.token_locs[case.firstToken()].start; |
| 1586 | 1586 | |
| 1587 | if (case.payload != null) { | |
| 1588 | return mod.fail(scope, case_src, "TODO switch case payload capture", .{}); | |
| 1589 | } | |
| 1590 | ||
| 1587 | 1591 | if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { |
| 1588 | 1592 | if (else_src) |src| { |
| 1589 | 1593 | return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{}); |
src/codegen.zig+7| ... | ... | @@ -786,6 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 786 | 786 | .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), |
| 787 | 787 | .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), |
| 788 | 788 | .varptr => return self.genVarPtr(inst.castTag(.varptr).?), |
| 789 | .@"switch" => return self.genSwitch(inst.castTag(.@"switch").?), | |
| 789 | 790 | } |
| 790 | 791 | } |
| 791 | 792 | |
| ... | ... | @@ -1989,6 +1990,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1989 | 1990 | return @bitCast(MCValue, inst.codegen.mcv); |
| 1990 | 1991 | } |
| 1991 | 1992 | |
| 1993 | fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue { | |
| 1994 | switch (arch) { | |
| 1995 | else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}), | |
| 1996 | } | |
| 1997 | } | |
| 1998 | ||
| 1992 | 1999 | fn performReloc(self: *Self, src: usize, reloc: Reloc) !void { |
| 1993 | 2000 | switch (reloc) { |
| 1994 | 2001 | .rel32 => |pos| { |
src/ir.zig+24| ... | ... | @@ -91,6 +91,7 @@ pub const Inst = struct { |
| 91 | 91 | intcast, |
| 92 | 92 | unwrap_optional, |
| 93 | 93 | wrap_optional, |
| 94 | @"switch", | |
| 94 | 95 | |
| 95 | 96 | pub fn Type(tag: Tag) type { |
| 96 | 97 | return switch (tag) { |
| ... | ... | @@ -137,6 +138,7 @@ pub const Inst = struct { |
| 137 | 138 | .constant => Constant, |
| 138 | 139 | .loop => Loop, |
| 139 | 140 | .varptr => VarPtr, |
| 141 | .@"switch" => Switch, | |
| 140 | 142 | }; |
| 141 | 143 | } |
| 142 | 144 | |
| ... | ... | @@ -458,6 +460,28 @@ pub const Inst = struct { |
| 458 | 460 | return null; |
| 459 | 461 | } |
| 460 | 462 | }; |
| 463 | ||
| 464 | pub const Switch = struct { | |
| 465 | pub const base_tag = Tag.@"switch"; | |
| 466 | ||
| 467 | base: Inst, | |
| 468 | target_ptr: *Inst, | |
| 469 | cases: []Case, | |
| 470 | @"else": ?Body, | |
| 471 | ||
| 472 | pub const Case = struct { | |
| 473 | items: []Value, | |
| 474 | body: Body, | |
| 475 | }; | |
| 476 | ||
| 477 | pub fn operandCount(self: *const Switch) usize { | |
| 478 | return 1; | |
| 479 | } | |
| 480 | pub fn getOperand(self: *const Switch, index: usize) ?*Inst { | |
| 481 | return self.target_ptr; | |
| 482 | } | |
| 483 | // TODO case body deaths | |
| 484 | }; | |
| 461 | 485 | }; |
| 462 | 486 | |
| 463 | 487 | pub const Body = struct { |
src/zir.zig+3| ... | ... | @@ -2549,6 +2549,9 @@ const EmitZIR = struct { |
| 2549 | 2549 | }, |
| 2550 | 2550 | |
| 2551 | 2551 | .varptr => @panic("TODO"), |
| 2552 | .@"switch" => { | |
| 2553 | @panic("TODO"); | |
| 2554 | }, | |
| 2552 | 2555 | }; |
| 2553 | 2556 | try self.metadata.put(new_inst, .{ |
| 2554 | 2557 | .deaths = inst.deaths, |
src/zir_sema.zig+64-1| ... | ... | @@ -1233,7 +1233,70 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE |
| 1233 | 1233 | const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src); |
| 1234 | 1234 | try validateSwitch(mod, scope, target, inst); |
| 1235 | 1235 | |
| 1236 | return mod.fail(scope, inst.base.src, "TODO analyzeInstSwitch", .{}); | |
| 1236 | // TODO comptime execution | |
| 1237 | ||
| 1238 | // excludes else and '_' cases | |
| 1239 | const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none); | |
| 1240 | ||
| 1241 | const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); | |
| 1242 | const switch_inst = try parent_block.arena.create(Inst.Switch); | |
| 1243 | switch_inst.* = .{ | |
| 1244 | .base = .{ | |
| 1245 | .tag = Inst.Switch.base_tag, | |
| 1246 | .ty = Type.initTag(.noreturn), | |
| 1247 | .src = inst.base.src, | |
| 1248 | }, | |
| 1249 | .target_ptr = target_ptr, | |
| 1250 | .@"else" = null, | |
| 1251 | .cases = try parent_block.arena.alloc(Inst.Switch.Case, case_count), | |
| 1252 | }; | |
| 1253 | ||
| 1254 | var case_block: Scope.Block = .{ | |
| 1255 | .parent = parent_block, | |
| 1256 | .func = parent_block.func, | |
| 1257 | .decl = parent_block.decl, | |
| 1258 | .instructions = .{}, | |
| 1259 | .arena = parent_block.arena, | |
| 1260 | .is_comptime = parent_block.is_comptime, | |
| 1261 | }; | |
| 1262 | defer case_block.instructions.deinit(mod.gpa); | |
| 1263 | ||
| 1264 | var items_tmp = std.ArrayList(Value).init(mod.gpa); | |
| 1265 | defer items_tmp.deinit(); | |
| 1266 | ||
| 1267 | for (inst.positionals.cases[0..case_count]) |case, i| { | |
| 1268 | // Reset without freeing. | |
| 1269 | case_block.instructions.items.len = 0; | |
| 1270 | items_tmp.items.len = 0; | |
| 1271 | ||
| 1272 | for (case.items) |item| { | |
| 1273 | if (item.castTag(.switch_range)) |range| { | |
| 1274 | return mod.fail(scope, item.src, "genSwitch expand range", .{}); | |
| 1275 | } | |
| 1276 | const resolved = try resolveInst(mod, scope, item); | |
| 1277 | const casted = try mod.coerce(scope, target.ty, resolved); | |
| 1278 | const val = try mod.resolveConstValue(scope, casted); | |
| 1279 | try items_tmp.append(val); | |
| 1280 | } | |
| 1281 | ||
| 1282 | try analyzeBody(mod, &case_block.base, case.body); | |
| 1283 | ||
| 1284 | switch_inst.cases[i] = .{ | |
| 1285 | .items = try parent_block.arena.dupe(Value, items_tmp.items), | |
| 1286 | .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) }, | |
| 1287 | }; | |
| 1288 | } | |
| 1289 | ||
| 1290 | if (inst.kw_args.special_case != .none) { | |
| 1291 | case_block.instructions.items.len = 0; | |
| 1292 | ||
| 1293 | try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body); | |
| 1294 | switch_inst.@"else" = .{ | |
| 1295 | .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items), | |
| 1296 | }; | |
| 1297 | } | |
| 1298 | ||
| 1299 | return &switch_inst.base; | |
| 1237 | 1300 | } |
| 1238 | 1301 | |
| 1239 | 1302 | fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void { |