feat: code generation for switch statements
This commit is contained in:
parent
e5e2b7c559
commit
fac5a968e3
3 changed files with 195 additions and 14 deletions
|
|
@ -735,29 +735,103 @@ fn multiIfStmt(
|
|||
const branch = branch_list[0];
|
||||
const body_node = branch.data.bin.rhs.?;
|
||||
try blockStmt(parent_block, scope, body_node);
|
||||
return @enumFromInt(0);
|
||||
return .none;
|
||||
}
|
||||
_ = try ifChain(parent_block, scope, branch_list);
|
||||
return @enumFromInt(0);
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn switchStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!Ir.Inst.Ref {
|
||||
const astgen = parent_block.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const switch_stmt = stmt_node.data.switch_stmt;
|
||||
|
||||
try validateSwitchProngs(parent_block, stmt_node);
|
||||
|
||||
const cond_inst = try expr(parent_block, scope, switch_stmt.condition_expr);
|
||||
const switch_br = try parent_block.makeBlockInst(.switch_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
||||
const switch_cases = switch_stmt.cases[0 .. switch_stmt.cases.len - 1];
|
||||
for (switch_cases) |case_stmt| {
|
||||
// TODO: Maybe make this non-nullable
|
||||
const case_expr = case_stmt.data.bin.lhs.?;
|
||||
const operand: Ir.Inst.Ref = switch (case_expr.tag) {
|
||||
.number_literal => try numberLiteral(parent_block, case_expr),
|
||||
.true_literal => .bool_true,
|
||||
.false_literal => .bool_false,
|
||||
else => return parent_block.fail(.invalid_switch_case, case_stmt),
|
||||
};
|
||||
var case_block = parent_block.makeSubBlock();
|
||||
defer case_block.unstack();
|
||||
_ = try blockStmt(&case_block, scope, case_stmt.data.bin.rhs.?);
|
||||
_ = try case_block.addBreak(.@"break", switch_br);
|
||||
|
||||
const body = case_block.instructionsSlice();
|
||||
const case_extra_len = @typeInfo(Ir.Inst.SwitchBr.Case).@"struct".fields.len + body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, case_extra_len);
|
||||
|
||||
const extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.SwitchBr.Case{
|
||||
.operand = operand,
|
||||
.body_len = @intCast(body.len),
|
||||
},
|
||||
);
|
||||
astgen.appendBlockBody(body);
|
||||
case_indexes.appendAssumeCapacity(extra_index);
|
||||
}
|
||||
|
||||
try parent_block.instructions.append(gpa, switch_br);
|
||||
|
||||
const else_branch = switch_stmt.cases[switch_stmt.cases.len - 1];
|
||||
var case_block = parent_block.makeSubBlock();
|
||||
defer case_block.unstack();
|
||||
_ = try blockStmt(&case_block, scope, else_branch.data.bin.rhs.?);
|
||||
_ = try case_block.addBreak(.@"break", switch_br);
|
||||
|
||||
const else_body = case_block.instructionsSlice();
|
||||
const extra_len =
|
||||
@typeInfo(Ir.Inst.SwitchBr).@"struct".fields.len + case_indexes.items.len + else_body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
|
||||
astgen.instructions.items[@intFromEnum(switch_br)].data.payload = .{
|
||||
.payload_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.SwitchBr{
|
||||
.operand = cond_inst,
|
||||
.cases_len = @intCast(switch_cases.len),
|
||||
.else_body_len = @intCast(else_body.len),
|
||||
},
|
||||
),
|
||||
};
|
||||
astgen.extra.appendSliceAssumeCapacity(case_indexes.items[0..]);
|
||||
astgen.appendBlockBody(else_body);
|
||||
return switch_br.toRef();
|
||||
}
|
||||
|
||||
fn contentExpr(block: *GenIr, scope: *Scope, expr_node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
// FIXME: This is a placeholder until we figure out what this function should be returning.
|
||||
var last_inst: Ir.Inst.Ref = undefined;
|
||||
// TODO: Make sure that this is not nullable.
|
||||
const node_list = expr_node.data.list.items.?;
|
||||
for (node_list) |child_node| {
|
||||
last_inst = switch (child_node.tag) {
|
||||
.string_literal => try stringLiteral(block, child_node),
|
||||
.inline_logic_expr => try inlineLogicExpr(block, scope, child_node),
|
||||
.if_stmt => try ifStmt(block, scope, child_node),
|
||||
.multi_if_stmt => try multiIfStmt(block, scope, child_node),
|
||||
//.switch_stmt => try switchStmt(block, scope, child_node),
|
||||
switch (child_node.tag) {
|
||||
.string_literal => {
|
||||
const result = try stringLiteral(block, child_node);
|
||||
_ = try block.addUnaryNode(.content_push, result);
|
||||
},
|
||||
.inline_logic_expr => _ = try inlineLogicExpr(block, scope, child_node),
|
||||
.if_stmt => _ = try ifStmt(block, scope, child_node),
|
||||
.multi_if_stmt => _ = try multiIfStmt(block, scope, child_node),
|
||||
.switch_stmt => _ = try switchStmt(block, scope, child_node),
|
||||
else => unreachable,
|
||||
};
|
||||
last_inst = try block.addUnaryNode(.content_push, last_inst);
|
||||
}
|
||||
}
|
||||
return last_inst;
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn contentStmt(gen: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue