feat: code generation for simple choice statements, testing machinery
This commit is contained in:
parent
fac5a968e3
commit
ee26be6254
13 changed files with 304 additions and 70 deletions
120
src/AstGen.zig
120
src/AstGen.zig
|
|
@ -758,6 +758,7 @@ fn switchStmt(
|
|||
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
||||
// TODO: Length checks.
|
||||
const switch_cases = switch_stmt.cases[0 .. switch_stmt.cases.len - 1];
|
||||
for (switch_cases) |case_stmt| {
|
||||
// TODO: Maybe make this non-nullable
|
||||
|
|
@ -855,78 +856,77 @@ fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
|||
return gi.fail(.unknown_identifier, identifier_node);
|
||||
}
|
||||
|
||||
fn choiceStmt(gen: *GenIr, scope: *Scope, stmt_node: *const Ast.Node) InnerError!void {
|
||||
const Choice = struct {
|
||||
label_index: usize,
|
||||
start_expression: ?*const Ast.Node,
|
||||
option_expression: ?*const Ast.Node,
|
||||
inner_expression: ?*const Ast.Node,
|
||||
block_stmt: ?*const Ast.Node,
|
||||
};
|
||||
fn choiceStarStmt(gi: *GenIr, _: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
return stringLiteral(gi, node);
|
||||
}
|
||||
|
||||
const branch_list = stmt_node.data.list.items orelse unreachable;
|
||||
assert(branch_list.len != 0);
|
||||
fn choiceStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!void {
|
||||
const astgen = parent_block.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const choice_branches = stmt_node.data.list.items.?;
|
||||
assert(choice_branches.len != 0);
|
||||
|
||||
const gpa = gen.astgen.gpa;
|
||||
var choice_list: std.ArrayListUnmanaged(Choice) = .empty;
|
||||
defer choice_list.deinit(gpa);
|
||||
try choice_list.ensureUnusedCapacity(gpa, branch_list.len);
|
||||
const choice_br = try parent_block.makeBlockInst(.choice_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, choice_branches.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
||||
for (branch_list) |branch_stmt| {
|
||||
for (choice_branches) |branch_stmt| {
|
||||
assert(branch_stmt.tag == .choice_star_stmt or branch_stmt.tag == .choice_plus_stmt);
|
||||
const branch_data = branch_stmt.data.bin;
|
||||
const branch_expr = branch_data.lhs orelse unreachable;
|
||||
const branch_expr_data = branch_expr.data.choice_expr;
|
||||
const label_index = try gen.makeLabel();
|
||||
const branch_expr = branch_data.lhs.?.data.choice_expr;
|
||||
var op_1: Ir.Inst.Ref = .none;
|
||||
var op_2: Ir.Inst.Ref = .none;
|
||||
var op_3: Ir.Inst.Ref = .none;
|
||||
|
||||
if (branch_expr_data.start_expr) |node| {
|
||||
try stringLiteral(gen, node);
|
||||
try gen.emitSimpleInst(.stream_push);
|
||||
if (branch_expr.start_expr) |node| {
|
||||
op_1 = try choiceStarStmt(parent_block, scope, node);
|
||||
}
|
||||
if (branch_expr_data.option_expr) |node| {
|
||||
try stringLiteral(gen, node);
|
||||
try gen.emitSimpleInst(.stream_push);
|
||||
if (branch_expr.option_expr) |node| {
|
||||
op_2 = try choiceStarStmt(parent_block, scope, node);
|
||||
}
|
||||
if (branch_expr.inner_expr) |node| {
|
||||
op_3 = try choiceStarStmt(parent_block, scope, node);
|
||||
}
|
||||
|
||||
const fixup_offset = try gen.emitJumpInst(.br_push);
|
||||
_ = try gen.makeFixup(.{
|
||||
.mode = .absolute,
|
||||
.label_index = label_index,
|
||||
.code_offset = fixup_offset,
|
||||
});
|
||||
var sub_block = parent_block.makeSubBlock();
|
||||
defer sub_block.unstack();
|
||||
if (branch_data.rhs) |branch_body| {
|
||||
_ = try blockStmt(&sub_block, scope, branch_body);
|
||||
}
|
||||
_ = try sub_block.addUnaryNode(.implicit_ret, .none);
|
||||
|
||||
choice_list.appendAssumeCapacity(.{
|
||||
.label_index = label_index,
|
||||
.start_expression = branch_expr_data.start_expr,
|
||||
.inner_expression = branch_expr_data.inner_expr,
|
||||
.option_expression = branch_expr_data.option_expr,
|
||||
.block_stmt = branch_data.rhs,
|
||||
});
|
||||
const body = sub_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.ChoiceBr.Case{
|
||||
.operand_1 = op_1,
|
||||
.operand_2 = op_2,
|
||||
.operand_3 = op_3,
|
||||
.body_len = @intCast(body.len),
|
||||
},
|
||||
);
|
||||
astgen.appendBlockBody(body);
|
||||
case_indexes.appendAssumeCapacity(extra_index);
|
||||
}
|
||||
|
||||
try gen.emitSimpleInst(.br_table);
|
||||
try gen.emitSimpleInst(.br_select_index);
|
||||
try gen.emitSimpleInst(.br_dispatch);
|
||||
try parent_block.instructions.append(gpa, choice_br);
|
||||
const extra_len = @typeInfo(Ir.Inst.ChoiceBr).@"struct".fields.len + case_indexes.items.len;
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
|
||||
for (choice_list.items) |choice| {
|
||||
gen.setLabel(choice.label_index);
|
||||
|
||||
if (choice.start_expression) |expr_node| {
|
||||
try stringLiteral(gen, expr_node);
|
||||
try gen.emitSimpleInst(.stream_push);
|
||||
}
|
||||
if (choice.inner_expression) |expr_node| {
|
||||
try stringLiteral(gen, expr_node);
|
||||
try gen.emitSimpleInst(.stream_push);
|
||||
}
|
||||
|
||||
try gen.emitSimpleInst(.stream_flush);
|
||||
if (choice.block_stmt) |block| {
|
||||
try blockStmt(gen, scope, block);
|
||||
} else {
|
||||
try gen.emitSimpleInst(.exit);
|
||||
}
|
||||
}
|
||||
astgen.instructions.items[@intFromEnum(choice_br)].data.payload = .{
|
||||
.payload_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.ChoiceBr{
|
||||
.cases_len = @intCast(choice_branches.len),
|
||||
},
|
||||
),
|
||||
};
|
||||
astgen.extra.appendSliceAssumeCapacity(case_indexes.items[0..]);
|
||||
}
|
||||
|
||||
fn tempDecl(gi: *GenIr, scope: *Scope, decl_node: *const Ast.Node) !void {
|
||||
|
|
@ -982,7 +982,7 @@ fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
|||
.temp_decl => try tempDecl(gi, &child_scope, inner_node),
|
||||
.assign_stmt => try assignStmt(gi, &child_scope, inner_node),
|
||||
.content_stmt => try contentStmt(gi, &child_scope, inner_node),
|
||||
//.choice_stmt => try choiceStmt(gen, scope, inner_node),
|
||||
.choice_stmt => try choiceStmt(gi, &child_scope, inner_node),
|
||||
.expr_stmt => try exprStmt(gi, &child_scope, inner_node),
|
||||
else => unreachable,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue