refactor: no more optional lists in ast nodes
This commit is contained in:
parent
d08e753664
commit
b231e66b49
5 changed files with 84 additions and 104 deletions
11
src/Ast.zig
11
src/Ast.zig
|
|
@ -9,8 +9,7 @@ const assert = std.debug.assert;
|
|||
|
||||
filename: []const u8,
|
||||
source: []const u8,
|
||||
// TODO: Make this non-nullable. Empty files are valid.
|
||||
root: ?*Node = null,
|
||||
root: *Node,
|
||||
errors: []const Error,
|
||||
|
||||
pub const Node = struct {
|
||||
|
|
@ -98,7 +97,7 @@ pub const Node = struct {
|
|||
rhs: ?*Node,
|
||||
},
|
||||
list: struct {
|
||||
items: ?[]*Node,
|
||||
items: []*Node,
|
||||
},
|
||||
choice_expr: struct {
|
||||
start_expr: ?*Node,
|
||||
|
|
@ -111,7 +110,7 @@ pub const Node = struct {
|
|||
},
|
||||
knot_decl: struct {
|
||||
prototype: *Node,
|
||||
children: ?[]*Node,
|
||||
children: []*Node,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -145,7 +144,7 @@ pub const Node = struct {
|
|||
gpa: std.mem.Allocator,
|
||||
tag: Tag,
|
||||
span: Span,
|
||||
items: ?[]*Node,
|
||||
items: []*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, span);
|
||||
node.data = .{
|
||||
|
|
@ -195,7 +194,7 @@ pub const Node = struct {
|
|||
tag: Tag,
|
||||
loc: Span,
|
||||
prototype: *Node,
|
||||
children: ?[]*Node,
|
||||
children: []*Node,
|
||||
) !*Node {
|
||||
const node = try Node.create(gpa, tag, loc);
|
||||
node.data = .{
|
||||
|
|
|
|||
|
|
@ -337,10 +337,12 @@ fn renderAstWalk(
|
|||
node: *const Ast.Node,
|
||||
options: NodeOptions,
|
||||
) !void {
|
||||
const gpa = r.gpa;
|
||||
var children: std.ArrayListUnmanaged(?*const Ast.Node) = .empty;
|
||||
defer children.deinit(r.gpa);
|
||||
defer children.deinit(gpa);
|
||||
|
||||
try renderAstNode(r, writer, node, options);
|
||||
|
||||
switch (node.tag) {
|
||||
.false_literal,
|
||||
.true_literal,
|
||||
|
|
@ -361,19 +363,14 @@ fn renderAstWalk(
|
|||
.choice_stmt,
|
||||
.content,
|
||||
=> {
|
||||
const list = node.data.list.items;
|
||||
if (list) |items| for (items) |n| {
|
||||
try children.append(r.gpa, n);
|
||||
};
|
||||
const data = node.data.list;
|
||||
for (data.items) |child_node| try children.append(gpa, child_node);
|
||||
},
|
||||
.choice_expr => {
|
||||
const lhs = node.data.choice_expr.start_expr;
|
||||
const mhs = node.data.choice_expr.option_expr;
|
||||
const rhs = node.data.choice_expr.inner_expr;
|
||||
|
||||
if (lhs) |n| try children.append(r.gpa, n);
|
||||
if (mhs) |n| try children.append(r.gpa, n);
|
||||
if (rhs) |n| try children.append(r.gpa, n);
|
||||
const data = node.data.choice_expr;
|
||||
if (data.start_expr) |lhs| try children.append(gpa, lhs);
|
||||
if (data.option_expr) |mhs| try children.append(gpa, mhs);
|
||||
if (data.inner_expr) |rhs| try children.append(gpa, rhs);
|
||||
},
|
||||
.add_expr,
|
||||
.subtract_expr,
|
||||
|
|
@ -417,38 +414,28 @@ fn renderAstWalk(
|
|||
.else_branch,
|
||||
.invalid,
|
||||
=> {
|
||||
const lhs = node.data.bin.lhs;
|
||||
const rhs = node.data.bin.rhs;
|
||||
|
||||
if (lhs) |n| try children.append(r.gpa, n);
|
||||
if (rhs) |n| try children.append(r.gpa, n);
|
||||
const data = node.data.bin;
|
||||
if (data.lhs) |lhs| try children.append(gpa, lhs);
|
||||
if (data.rhs) |rhs| try children.append(gpa, rhs);
|
||||
},
|
||||
.knot_decl => {
|
||||
const lhs = node.data.knot_decl.prototype;
|
||||
try children.append(r.gpa, lhs);
|
||||
|
||||
const list = node.data.knot_decl.children;
|
||||
if (list) |items| for (items) |n| {
|
||||
try children.append(r.gpa, n);
|
||||
};
|
||||
const data = node.data.knot_decl;
|
||||
try children.append(gpa, data.prototype);
|
||||
for (data.children) |child_node| try children.append(gpa, child_node);
|
||||
},
|
||||
.switch_stmt, .if_stmt, .multi_if_stmt => {
|
||||
const expr = node.data.switch_stmt.condition_expr;
|
||||
if (expr) |n| try children.append(r.gpa, n);
|
||||
|
||||
const list = node.data.switch_stmt.cases;
|
||||
for (list) |case_stmt| {
|
||||
try children.append(r.gpa, case_stmt);
|
||||
}
|
||||
const data = node.data.switch_stmt;
|
||||
if (data.condition_expr) |expr_node| try children.append(gpa, expr_node);
|
||||
for (data.cases) |case_stmt| try children.append(gpa, case_stmt);
|
||||
},
|
||||
.inline_logic_expr => {
|
||||
const lhs = node.data.bin.lhs;
|
||||
if (lhs) |n| try children.append(r.gpa, n);
|
||||
const data = node.data.bin;
|
||||
if (data.lhs) |lhs| try children.append(gpa, lhs);
|
||||
},
|
||||
}
|
||||
for (children.items, 0..) |maybe_child, i| {
|
||||
const old_len = if (!options.is_root)
|
||||
try r.prefix.pushChildPrefix(r.gpa, options.is_last)
|
||||
try r.prefix.pushChildPrefix(gpa, options.is_last)
|
||||
else
|
||||
0;
|
||||
const child_is_last = (i == children.items.len - 1);
|
||||
|
|
@ -483,11 +470,9 @@ pub fn renderTree(
|
|||
defer r.prefix.deinit(gpa);
|
||||
defer r.lines.deinit(gpa);
|
||||
|
||||
if (ast.root) |root| {
|
||||
try r.renderAstWalk(writer, root, .{
|
||||
try r.renderAstWalk(writer, ast.root, .{
|
||||
.is_root = true,
|
||||
.is_last = true,
|
||||
});
|
||||
}
|
||||
try writer.flush();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,8 +196,7 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
|||
|
||||
const fatal = if (tree.errors.len == 0) fatal: {
|
||||
// TODO: Make sure this is never null.
|
||||
const root_node = tree.root.?;
|
||||
file(&block, &file_scope, root_node) catch |err| switch (err) {
|
||||
file(&block, &file_scope, tree.root) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.SemanticError => break :fatal true,
|
||||
else => |e| return e,
|
||||
|
|
@ -789,9 +788,10 @@ fn exprStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst
|
|||
}
|
||||
|
||||
fn inlineLogicExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
// TODO: Maybe we should introduce a unary node type to avoid optional checks?
|
||||
const main_node = node.data.bin.lhs.?;
|
||||
return expr(gi, scope, main_node);
|
||||
if (node.data.bin.lhs) |lhs| {
|
||||
return expr(gi, scope, lhs);
|
||||
}
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn validateSwitchProngs(gen: *GenIr, stmt_node: *const Ast.Node) InnerError!void {
|
||||
|
|
@ -817,7 +817,7 @@ fn validateSwitchProngs(gen: *GenIr, stmt_node: *const Ast.Node) InnerError!void
|
|||
}
|
||||
stmt_has_else = true;
|
||||
},
|
||||
else => unreachable,
|
||||
inline else => |tag| @panic("Unexpected node " ++ @tagName(tag)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -996,11 +996,11 @@ fn switchStmt(
|
|||
return switch_br.toRef();
|
||||
}
|
||||
|
||||
fn contentExpr(block: *GenIr, scope: *Scope, expr_node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
fn contentExpr(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.Inst.Ref {
|
||||
// FIXME: This is a placeholder until we figure out what this function should be returning.
|
||||
// TODO: Make sure that this is not nullable.
|
||||
const node_list = expr_node.data.list.items.?;
|
||||
for (node_list) |child_node| {
|
||||
const data = node.data.list;
|
||||
for (data.items) |child_node| {
|
||||
switch (child_node.tag) {
|
||||
.string_literal => {
|
||||
const result = try stringLiteral(block, child_node);
|
||||
|
|
@ -1051,15 +1051,13 @@ fn choiceStmt(
|
|||
) 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 data = stmt_node.data.list;
|
||||
const choice_br = try parent_block.makePayloadNode(.choice_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, choice_branches.len);
|
||||
try case_indexes.ensureUnusedCapacity(gpa, data.items.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
||||
for (choice_branches) |branch_stmt| {
|
||||
for (data.items) |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.?.data.choice_expr;
|
||||
|
|
@ -1082,7 +1080,6 @@ fn choiceStmt(
|
|||
if (branch_data.rhs) |branch_body| {
|
||||
_ = try blockStmt(&sub_block, scope, branch_body);
|
||||
}
|
||||
_ = try sub_block.addUnaryNode(.implicit_ret, .none);
|
||||
|
||||
const body = sub_block.instructionsSlice();
|
||||
const case_extra_len = @typeInfo(Ir.Inst.SwitchBr.Case).@"struct".fields.len + body.len;
|
||||
|
|
@ -1106,7 +1103,7 @@ fn choiceStmt(
|
|||
astgen.instructions.items[@intFromEnum(choice_br)].data.payload = .{
|
||||
.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.ChoiceBr{
|
||||
.cases_len = @intCast(choice_branches.len),
|
||||
.cases_len = @intCast(data.items.len),
|
||||
},
|
||||
),
|
||||
.src_offset = @intCast(stmt_node.loc.start),
|
||||
|
|
@ -1172,7 +1169,6 @@ fn callExpr(
|
|||
const gpa = astgen.gpa;
|
||||
const data = node.data.bin;
|
||||
const callee_node = data.lhs.?;
|
||||
const args_node = data.rhs;
|
||||
const callee = try calleeExpr(gi, scope, callee_node);
|
||||
|
||||
const scratch_top = astgen.scratch.items.len;
|
||||
|
|
@ -1180,7 +1176,7 @@ fn callExpr(
|
|||
|
||||
// FIXME: List nodes should not have optional slices.
|
||||
// This hack is an abomination.
|
||||
const arguments: ?[]*Ast.Node = if (args_node) |n| if (n.data.list.items) |items| items else null else null;
|
||||
const arguments: ?[]*Ast.Node = if (data.rhs) |args_node| args_node.data.list.items else null;
|
||||
const args_count = if (arguments) |args| args.len else 0;
|
||||
|
||||
try astgen.scratch.resize(gpa, scratch_top + args_count);
|
||||
|
|
@ -1365,10 +1361,10 @@ fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
|||
}
|
||||
}
|
||||
|
||||
fn blockStmt(block: *GenIr, scope: *Scope, stmt_node: *const Ast.Node) InnerError!void {
|
||||
fn blockStmt(block: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
// TODO: Make sure that this value is concrete to omit check.
|
||||
const block_stmts = stmt_node.data.list.items.?;
|
||||
try blockInner(block, scope, block_stmts);
|
||||
const data = node.data.list;
|
||||
try blockInner(block, scope, data.items);
|
||||
}
|
||||
|
||||
fn defaultBlock(
|
||||
|
|
@ -1377,6 +1373,7 @@ fn defaultBlock(
|
|||
body_node: *const Ast.Node,
|
||||
) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const data = body_node.data.list;
|
||||
const decl_inst = try gi.addAsIndex(.{
|
||||
.tag = .declaration,
|
||||
.data = .{ .payload = undefined },
|
||||
|
|
@ -1385,9 +1382,7 @@ fn defaultBlock(
|
|||
defer decl_scope.unstack();
|
||||
|
||||
const knot_inst = try decl_scope.makePayloadNode(.decl_knot);
|
||||
// TODO: Make sure that this value is concrete to omit check.
|
||||
const block_stmts = body_node.data.list.items.?;
|
||||
try blockInner(&decl_scope, scope, block_stmts);
|
||||
try blockInner(&decl_scope, scope, data.items);
|
||||
|
||||
var stub_scope = decl_scope.makeSubBlock();
|
||||
defer stub_scope.unstack();
|
||||
|
|
@ -1423,8 +1418,8 @@ fn stitchDeclInner(
|
|||
const stitch_inst = try decl_block.makePayloadNode(.decl_stitch);
|
||||
|
||||
if (prototype_data.rhs) |args_node| {
|
||||
const args_list = args_node.data.list.items.?;
|
||||
for (args_list) |arg| {
|
||||
const args_data = args_node.data.list;
|
||||
for (args_data.items) |arg| {
|
||||
assert(arg.tag == .parameter_decl);
|
||||
const arg_str = try astgen.strFromNode(arg);
|
||||
const arg_inst = try decl_block.addStrTok(.param, arg_str.index, arg.loc.start);
|
||||
|
|
@ -1437,8 +1432,8 @@ fn stitchDeclInner(
|
|||
}
|
||||
}
|
||||
if (body_node) |body| {
|
||||
const body_list = body.data.list.items.?;
|
||||
try blockInner(&decl_block, scope, body_list);
|
||||
const body_data = body.data.list;
|
||||
try blockInner(&decl_block, scope, body_data.items);
|
||||
} else {
|
||||
try blockInner(&decl_block, scope, &.{});
|
||||
}
|
||||
|
|
@ -1484,8 +1479,8 @@ fn functionDeclInner(
|
|||
const stitch_inst = try decl_block.makePayloadNode(.decl_function);
|
||||
|
||||
if (prototype_data.rhs) |args_node| {
|
||||
const args_list = args_node.data.list.items.?;
|
||||
for (args_list) |arg| {
|
||||
const args_data = args_node.data.list;
|
||||
for (args_data.items) |arg| {
|
||||
assert(arg.tag == .parameter_decl);
|
||||
const arg_str = try astgen.strFromNode(arg);
|
||||
const arg_inst = try decl_block.addStrTok(.param, arg_str.index, arg.loc.start);
|
||||
|
|
@ -1525,10 +1520,9 @@ fn functionDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) In
|
|||
|
||||
fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const knot_data = decl_node.data.knot_decl;
|
||||
const prototype_node = knot_data.prototype;
|
||||
const data = decl_node.data.knot_decl;
|
||||
const prototype_node = data.prototype;
|
||||
const identifier_node = prototype_node.data.bin.lhs.?;
|
||||
const nested_decls_list = knot_data.children.?;
|
||||
const decl_inst = try gi.addAsIndex(.{
|
||||
.tag = .declaration,
|
||||
.data = .{ .payload = undefined },
|
||||
|
|
@ -1543,8 +1537,8 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
|
|||
defer child_scope.deinit();
|
||||
|
||||
if (prototype_node.data.bin.rhs) |args_node| {
|
||||
const args_list = args_node.data.list.items.?;
|
||||
for (args_list) |arg| {
|
||||
const args_data = args_node.data.list;
|
||||
for (args_data.items) |arg| {
|
||||
assert(arg.tag == .parameter_decl);
|
||||
const arg_str = try astgen.strFromNode(arg);
|
||||
const arg_inst = try child_block.addStrTok(.param, arg_str.index, arg.loc.start);
|
||||
|
|
@ -1556,8 +1550,8 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
|
|||
});
|
||||
}
|
||||
}
|
||||
if (nested_decls_list.len > 0) {
|
||||
const first_child = nested_decls_list[0];
|
||||
if (data.children.len > 0) {
|
||||
const first_child = data.children[0];
|
||||
if (first_child.tag == .block_stmt) {
|
||||
try blockStmt(&child_block, &child_scope, first_child);
|
||||
node_index += 1;
|
||||
|
|
@ -1567,7 +1561,7 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
|
|||
var nested_block = child_block.makeSubBlock();
|
||||
defer nested_block.unstack();
|
||||
|
||||
for (nested_decls_list[node_index..]) |nested_decl_node| {
|
||||
for (data.children[node_index..]) |nested_decl_node| {
|
||||
switch (nested_decl_node.tag) {
|
||||
.stitch_decl => try stitchDecl(&nested_block, &child_scope, nested_decl_node),
|
||||
.function_decl => try functionDecl(&nested_block, &child_scope, nested_decl_node),
|
||||
|
|
@ -1585,12 +1579,12 @@ fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) InnerE
|
|||
});
|
||||
}
|
||||
|
||||
fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
|
||||
fn file(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void {
|
||||
const astgen = gi.astgen;
|
||||
const data = node.data.list;
|
||||
const file_inst = try gi.addAsIndex(.{
|
||||
.tag = .file,
|
||||
.data = .{
|
||||
.payload = undefined,
|
||||
},
|
||||
.data = .{ .payload = undefined },
|
||||
});
|
||||
|
||||
var node_index: usize = 0;
|
||||
|
|
@ -1598,15 +1592,14 @@ fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
|
|||
defer file_scope.unstack();
|
||||
|
||||
// TODO: Make sure this is non-nullable.
|
||||
const nested_decls_list = file_node.data.list.items orelse return;
|
||||
if (nested_decls_list.len > 0) {
|
||||
const first_child = nested_decls_list[0];
|
||||
if (data.items.len > 0) {
|
||||
const first_child = data.items[0];
|
||||
if (first_child.tag == .block_stmt) {
|
||||
try defaultBlock(&file_scope, scope, first_child);
|
||||
node_index += 1;
|
||||
}
|
||||
}
|
||||
for (nested_decls_list[node_index..]) |child_node| {
|
||||
for (data.items[node_index..]) |child_node| {
|
||||
switch (child_node.tag) {
|
||||
.knot_decl => try knotDecl(gi, scope, child_node),
|
||||
.stitch_decl => try stitchDecl(gi, scope, child_node),
|
||||
|
|
@ -1615,9 +1608,9 @@ fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
|
|||
}
|
||||
}
|
||||
|
||||
const globals_len = gi.astgen.globals.items.len;
|
||||
try gi.astgen.instructions.ensureUnusedCapacity(gi.astgen.gpa, globals_len);
|
||||
for (gi.astgen.globals.items) |global| {
|
||||
const globals_len = astgen.globals.items.len;
|
||||
try astgen.instructions.ensureUnusedCapacity(astgen.gpa, globals_len);
|
||||
for (astgen.globals.items) |global| {
|
||||
gi.instructions.appendAssumeCapacity(global);
|
||||
}
|
||||
return file_scope.setBlockBody(file_inst);
|
||||
|
|
|
|||
|
|
@ -268,11 +268,11 @@ fn makeNodeSequence(
|
|||
loc: Ast.Node.Span,
|
||||
scratch_offset: usize,
|
||||
) Error!*Ast.Node {
|
||||
var list: ?[]*Ast.Node = null;
|
||||
if (!p.isScratchEmpty(context)) {
|
||||
list = try p.nodeListFromScratch(scratch_offset, p.scratch.items.len);
|
||||
}
|
||||
const list = try p.nodeListFromScratch(scratch_offset, p.scratch.items.len);
|
||||
return .createList(p.arena, tag, loc, list);
|
||||
}
|
||||
return .createList(p.arena, tag, loc, &.{});
|
||||
}
|
||||
|
||||
fn isBlockStackEmpty(p: *Parse, context: *const StmtContext) bool {
|
||||
|
|
|
|||
|
|
@ -347,6 +347,15 @@ pub const Module = struct {
|
|||
options: Options,
|
||||
) !Module {
|
||||
const tree = try Ast.parse(gpa, arena, options.source_bytes, options.filename, 0);
|
||||
if (options.dump_writer) |w| {
|
||||
if (options.dump_ast) {
|
||||
try w.writeAll("=== AST ===\n");
|
||||
try tree.render(gpa, w, .{
|
||||
.use_color = options.dump_use_color,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var module: Module = .{
|
||||
.gpa = gpa,
|
||||
.arena = arena,
|
||||
|
|
@ -356,12 +365,6 @@ pub const Module = struct {
|
|||
errdefer module.deinit();
|
||||
|
||||
if (options.dump_writer) |w| {
|
||||
if (options.dump_ast) {
|
||||
try w.writeAll("=== AST ===\n");
|
||||
try module.tree.render(gpa, w, .{
|
||||
.use_color = options.dump_use_color,
|
||||
});
|
||||
}
|
||||
if (options.dump_ir) {
|
||||
try w.writeAll("=== Semantic IR ===\n");
|
||||
try module.ir.dumpInfo(w);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue