feat: choice expression nodes extended to full content parsing
This commit is contained in:
parent
066369cc13
commit
aad95a75ee
8 changed files with 380 additions and 165 deletions
147
src/AstGen.zig
147
src/AstGen.zig
|
|
@ -285,11 +285,11 @@ const GenIr = struct {
|
|||
return last_inst.isNoReturn();
|
||||
}
|
||||
|
||||
fn endsWithContent(self: *GenIr) bool {
|
||||
fn endsWithGlue(self: *GenIr) bool {
|
||||
if (self.isEmpty()) return false;
|
||||
const last_inst_index = self.instructions.items[self.instructions.items.len - 1];
|
||||
const last_inst = self.astgen.instructions.items[@intFromEnum(last_inst_index)];
|
||||
return last_inst.tag == .content_push;
|
||||
return last_inst.tag == .content_glue;
|
||||
}
|
||||
|
||||
fn makeSubBlock(self: *GenIr) GenIr {
|
||||
|
|
@ -814,7 +814,7 @@ fn inlineIfStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.
|
|||
if (data.rhs) |rhs| {
|
||||
// TODO: Revisit this. This isn't quite correct.
|
||||
switch (rhs.tag) {
|
||||
.content => _ = try content(&then_block, scope, rhs),
|
||||
.content => _ = try content(&then_block, scope, rhs, false, false),
|
||||
inline else => |tag| @panic("Unexpected node type: " ++ @tagName(tag)),
|
||||
}
|
||||
}
|
||||
|
|
@ -1058,7 +1058,13 @@ fn switchStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.In
|
|||
return switch_br.toRef();
|
||||
}
|
||||
|
||||
fn content(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
fn content(
|
||||
block: *GenIr,
|
||||
scope: *Scope,
|
||||
node: *const Ast.Node,
|
||||
is_last: bool,
|
||||
ignore_divert: bool,
|
||||
) InnerError!void {
|
||||
const data = node.data.content;
|
||||
if (data.leading_glue) {
|
||||
_ = try block.addUnaryNode(.content_glue, .none);
|
||||
|
|
@ -1081,17 +1087,26 @@ fn content(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.In
|
|||
else => unreachable,
|
||||
}
|
||||
}
|
||||
if (data.trailing_glue) {
|
||||
_ = try block.addUnaryNode(.content_glue, .none);
|
||||
} else if (block.endsWithContent()) {
|
||||
if (is_last) {
|
||||
_ = try block.addUnaryNode(.content_line, .none);
|
||||
if (data.trailing_glue or data.trailing_divert != null) {
|
||||
_ = try block.addUnaryNode(.content_glue, .none);
|
||||
}
|
||||
if (!ignore_divert) {
|
||||
if (data.trailing_divert) |trailing| {
|
||||
_ = try divertExpr(block, scope, trailing);
|
||||
_ = try block.addUnaryNode(.content_glue, .none);
|
||||
}
|
||||
}
|
||||
}
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn contentStmt(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
const data = node.data.bin;
|
||||
_ = try content(block, scope, data.lhs.?);
|
||||
fn contentStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||
const items = node.data.list.items;
|
||||
for (items, 0..) |n, i| {
|
||||
const is_last = i == items.len - 1;
|
||||
try content(gi, scope, n, is_last, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
|
|
@ -1108,19 +1123,13 @@ fn assignStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
|||
return fail(astgen, identifier_node, "unknown identifier", .{});
|
||||
}
|
||||
|
||||
fn choiceStarStmt(gi: *GenIr, _: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
return stringLiteral(gi, node);
|
||||
}
|
||||
|
||||
fn choiceStmt(
|
||||
parent_block: *GenIr,
|
||||
scope: *Scope,
|
||||
stmt_node: *const Ast.Node,
|
||||
) InnerError!void {
|
||||
const astgen = parent_block.astgen;
|
||||
fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const data = stmt_node.data.list;
|
||||
const choice_br = try parent_block.makePayloadNode(.choice_br);
|
||||
const data = node.data.list;
|
||||
const choice_br = try gi.makePayloadNode(.choice_br);
|
||||
|
||||
var trailing_divert: ?*Ast.Node = null;
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, data.items.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
|
@ -1129,46 +1138,83 @@ fn choiceStmt(
|
|||
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.?.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.start_expr) |node| {
|
||||
op_1 = try choiceStarStmt(parent_block, scope, node);
|
||||
}
|
||||
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);
|
||||
var block_1 = gi.makeSubBlock();
|
||||
defer block_1.unstack();
|
||||
|
||||
if (branch_expr.start_expr) |lhs| {
|
||||
for (lhs) |n| {
|
||||
if (n.data.content.trailing_divert) |trailing| {
|
||||
trailing_divert = trailing;
|
||||
}
|
||||
_ = try content(&block_1, scope, n, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
var sub_block = parent_block.makeSubBlock();
|
||||
defer sub_block.unstack();
|
||||
if (branch_data.rhs) |branch_body| {
|
||||
_ = try blockStmt(&sub_block, scope, branch_body);
|
||||
}
|
||||
if (!sub_block.endsWithNoReturn()) {
|
||||
_ = try sub_block.addUnaryNode(.implicit_ret, .none);
|
||||
var block_2 = block_1.makeSubBlock();
|
||||
defer block_2.unstack();
|
||||
|
||||
if (branch_expr.option_expr) |mhs| {
|
||||
for (mhs) |n| {
|
||||
assert(n.data.content.trailing_divert == null);
|
||||
_ = try content(&block_2, scope, n, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
const body = sub_block.instructionsSlice();
|
||||
const case_extra_len = @typeInfo(Ir.Inst.SwitchBr.Case).@"struct".fields.len + body.len;
|
||||
var block_3 = block_2.makeSubBlock();
|
||||
defer block_3.unstack();
|
||||
|
||||
if (branch_expr.inner_expr) |rhs| {
|
||||
for (rhs) |n| {
|
||||
if (n.data.content.trailing_divert) |trailing| {
|
||||
trailing_divert = trailing;
|
||||
}
|
||||
_ = try content(&block_3, scope, n, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
var body_block = gi.makeSubBlock();
|
||||
defer body_block.unstack();
|
||||
|
||||
if (trailing_divert) |trailing| {
|
||||
_ = try divertExpr(&body_block, scope, trailing);
|
||||
} else if (branch_data.rhs) |branch_body| {
|
||||
_ = try blockStmt(&body_block, scope, branch_body);
|
||||
}
|
||||
if (!body_block.endsWithNoReturn()) {
|
||||
_ = try body_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
const lhs_body = block_1.instructionsSliceUpto(&block_2);
|
||||
const mhs_body = block_2.instructionsSliceUpto(&block_3);
|
||||
const rhs_body = block_3.instructionsSliceUpto(&body_block);
|
||||
const body = body_block.instructionsSlice();
|
||||
const case_extra_len =
|
||||
@typeInfo(Ir.Inst.SwitchBr.Case).@"struct".fields.len +
|
||||
lhs_body.len + mhs_body.len + rhs_body.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,
|
||||
.lhs_len = @intCast(lhs_body.len),
|
||||
.mhs_len = @intCast(mhs_body.len),
|
||||
.rhs_len = @intCast(rhs_body.len),
|
||||
.body_len = @intCast(body.len),
|
||||
},
|
||||
);
|
||||
astgen.appendBlockBody(lhs_body);
|
||||
astgen.appendBlockBody(mhs_body);
|
||||
astgen.appendBlockBody(rhs_body);
|
||||
astgen.appendBlockBody(body);
|
||||
case_indexes.appendAssumeCapacity(extra_index);
|
||||
}
|
||||
|
||||
try parent_block.instructions.append(gpa, choice_br);
|
||||
const extra_len = @typeInfo(Ir.Inst.ChoiceBr).@"struct".fields.len + case_indexes.items.len;
|
||||
try gi.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);
|
||||
|
||||
astgen.instructions.items[@intFromEnum(choice_br)].data.payload = .{
|
||||
|
|
@ -1177,7 +1223,7 @@ fn choiceStmt(
|
|||
.cases_len = @intCast(data.items.len),
|
||||
},
|
||||
),
|
||||
.src_offset = @intCast(stmt_node.loc.start),
|
||||
.src_offset = @intCast(node.loc.start),
|
||||
};
|
||||
astgen.extra.appendSliceAssumeCapacity(case_indexes.items[0..]);
|
||||
}
|
||||
|
|
@ -1631,6 +1677,9 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
|
|||
node_index += 1;
|
||||
}
|
||||
}
|
||||
if (!child_block.endsWithNoReturn()) {
|
||||
_ = try child_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
var nested_block = child_block.makeSubBlock();
|
||||
defer nested_block.unstack();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue