Commit 11998d2972
Changed files (5)
src/astgen.zig
@@ -1584,6 +1584,10 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
const case = uncasted_case.castTag(.SwitchCase).?;
const case_src = tree.token_locs[case.firstToken()].start;
+ if (case.payload != null) {
+ return mod.fail(scope, case_src, "TODO switch case payload capture", .{});
+ }
+
if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
if (else_src) |src| {
return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});
src/codegen.zig
@@ -786,6 +786,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
.wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
.varptr => return self.genVarPtr(inst.castTag(.varptr).?),
+ .@"switch" => return self.genSwitch(inst.castTag(.@"switch").?),
}
}
@@ -1989,6 +1990,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return @bitCast(MCValue, inst.codegen.mcv);
}
+ fn genSwitch(self: *Self, inst: *ir.Inst.Switch) !MCValue {
+ switch (arch) {
+ else => return self.fail(inst.base.src, "TODO genSwitch for {}", .{self.target.cpu.arch}),
+ }
+ }
+
fn performReloc(self: *Self, src: usize, reloc: Reloc) !void {
switch (reloc) {
.rel32 => |pos| {
src/ir.zig
@@ -91,6 +91,7 @@ pub const Inst = struct {
intcast,
unwrap_optional,
wrap_optional,
+ @"switch",
pub fn Type(tag: Tag) type {
return switch (tag) {
@@ -137,6 +138,7 @@ pub const Inst = struct {
.constant => Constant,
.loop => Loop,
.varptr => VarPtr,
+ .@"switch" => Switch,
};
}
@@ -458,6 +460,28 @@ pub const Inst = struct {
return null;
}
};
+
+ pub const Switch = struct {
+ pub const base_tag = Tag.@"switch";
+
+ base: Inst,
+ target_ptr: *Inst,
+ cases: []Case,
+ @"else": ?Body,
+
+ pub const Case = struct {
+ items: []Value,
+ body: Body,
+ };
+
+ pub fn operandCount(self: *const Switch) usize {
+ return 1;
+ }
+ pub fn getOperand(self: *const Switch, index: usize) ?*Inst {
+ return self.target_ptr;
+ }
+ // TODO case body deaths
+ };
};
pub const Body = struct {
src/zir.zig
@@ -2549,6 +2549,9 @@ const EmitZIR = struct {
},
.varptr => @panic("TODO"),
+ .@"switch" => {
+ @panic("TODO");
+ },
};
try self.metadata.put(new_inst, .{
.deaths = inst.deaths,
src/zir_sema.zig
@@ -1233,7 +1233,70 @@ fn analyzeInstSwitch(mod: *Module, scope: *Scope, inst: *zir.Inst.Switch) InnerE
const target = try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target_ptr.src);
try validateSwitch(mod, scope, target, inst);
- return mod.fail(scope, inst.base.src, "TODO analyzeInstSwitch", .{});
+ // TODO comptime execution
+
+ // excludes else and '_' cases
+ const case_count = inst.positionals.cases.len - @boolToInt(inst.kw_args.special_case != .none);
+
+ const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
+ const switch_inst = try parent_block.arena.create(Inst.Switch);
+ switch_inst.* = .{
+ .base = .{
+ .tag = Inst.Switch.base_tag,
+ .ty = Type.initTag(.noreturn),
+ .src = inst.base.src,
+ },
+ .target_ptr = target_ptr,
+ .@"else" = null,
+ .cases = try parent_block.arena.alloc(Inst.Switch.Case, case_count),
+ };
+
+ var case_block: Scope.Block = .{
+ .parent = parent_block,
+ .func = parent_block.func,
+ .decl = parent_block.decl,
+ .instructions = .{},
+ .arena = parent_block.arena,
+ .is_comptime = parent_block.is_comptime,
+ };
+ defer case_block.instructions.deinit(mod.gpa);
+
+ var items_tmp = std.ArrayList(Value).init(mod.gpa);
+ defer items_tmp.deinit();
+
+ for (inst.positionals.cases[0..case_count]) |case, i| {
+ // Reset without freeing.
+ case_block.instructions.items.len = 0;
+ items_tmp.items.len = 0;
+
+ for (case.items) |item| {
+ if (item.castTag(.switch_range)) |range| {
+ return mod.fail(scope, item.src, "genSwitch expand range", .{});
+ }
+ const resolved = try resolveInst(mod, scope, item);
+ const casted = try mod.coerce(scope, target.ty, resolved);
+ const val = try mod.resolveConstValue(scope, casted);
+ try items_tmp.append(val);
+ }
+
+ try analyzeBody(mod, &case_block.base, case.body);
+
+ switch_inst.cases[i] = .{
+ .items = try parent_block.arena.dupe(Value, items_tmp.items),
+ .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
+ };
+ }
+
+ if (inst.kw_args.special_case != .none) {
+ case_block.instructions.items.len = 0;
+
+ try analyzeBody(mod, &case_block.base, inst.positionals.cases[case_count].body);
+ switch_inst.@"else" = .{
+ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
+ };
+ }
+
+ return &switch_inst.base;
}
fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Switch) InnerError!void {