refactor: redefining assumptions about declarations
This commit is contained in:
parent
be297047d1
commit
33e3c1c271
4 changed files with 210 additions and 202 deletions
341
src/AstGen.zig
341
src/AstGen.zig
|
|
@ -11,9 +11,8 @@ gpa: std.mem.Allocator,
|
|||
tree: *const Ast,
|
||||
string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
|
||||
string_bytes: std.ArrayListUnmanaged(u8) = .empty,
|
||||
globals: std.ArrayListUnmanaged(Ir.Inst.Index) = .empty,
|
||||
instructions: std.ArrayListUnmanaged(Ir.Inst) = .empty,
|
||||
globals: std.ArrayListUnmanaged(Ir.Global) = .empty,
|
||||
global_ref_table: std.AutoHashMapUnmanaged(Ir.NullTerminatedString, usize) = .empty,
|
||||
extra: std.ArrayListUnmanaged(u32) = .empty,
|
||||
scratch: std.ArrayListUnmanaged(u32) = .empty,
|
||||
compile_errors: std.ArrayListUnmanaged(Ir.Inst.CompileErrors.Item) = .empty,
|
||||
|
|
@ -166,41 +165,6 @@ fn strFromNode(astgen: *AstGen, node: *const Ast.Node) !IndexSlice {
|
|||
return astgen.strFromSlice(name_bytes);
|
||||
}
|
||||
|
||||
fn qualifiedString(
|
||||
astgen: *AstGen,
|
||||
prefix: Ir.NullTerminatedString,
|
||||
relative: Ir.NullTerminatedString,
|
||||
) !Ir.NullTerminatedString {
|
||||
const gpa = astgen.gpa;
|
||||
const string_bytes = &astgen.string_bytes;
|
||||
const string_table = &astgen.string_table;
|
||||
const str_index: u32 = @intCast(string_bytes.items.len);
|
||||
|
||||
switch (prefix) {
|
||||
.empty => return relative,
|
||||
else => |prev| {
|
||||
try string_bytes.appendSlice(gpa, nullTerminatedString(astgen, prev));
|
||||
try string_bytes.append(gpa, '.');
|
||||
try string_bytes.appendSlice(gpa, nullTerminatedString(astgen, relative));
|
||||
|
||||
const key: []const u8 = string_bytes.items[str_index..];
|
||||
const gop = try string_table.getOrPutContextAdapted(gpa, key, StringIndexAdapter{
|
||||
.bytes = string_bytes,
|
||||
}, StringIndexContext{
|
||||
.bytes = string_bytes,
|
||||
});
|
||||
if (gop.found_existing) {
|
||||
string_bytes.shrinkRetainingCapacity(str_index);
|
||||
return @enumFromInt(gop.key_ptr.*);
|
||||
} else {
|
||||
gop.key_ptr.* = str_index;
|
||||
try string_bytes.append(gpa, 0);
|
||||
return @enumFromInt(str_index);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform IR code generation via tree-walk.
|
||||
pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
||||
var astgen: AstGen = .{
|
||||
|
|
@ -217,7 +181,6 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
|||
var file_scope: Scope = .{
|
||||
.parent = null,
|
||||
.decls = .empty,
|
||||
.namespace_prefix = .empty,
|
||||
.astgen = &astgen,
|
||||
};
|
||||
var block: GenIr = .{
|
||||
|
|
@ -263,7 +226,6 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
|||
return .{
|
||||
.instructions = if (fatal) &.{} else try astgen.instructions.toOwnedSlice(gpa),
|
||||
.string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
|
||||
.globals = try astgen.globals.toOwnedSlice(gpa),
|
||||
.extra = try astgen.extra.toOwnedSlice(gpa),
|
||||
};
|
||||
}
|
||||
|
|
@ -273,7 +235,6 @@ fn deinit(astgen: *AstGen) void {
|
|||
astgen.string_table.deinit(gpa);
|
||||
astgen.string_bytes.deinit(gpa);
|
||||
astgen.globals.deinit(gpa);
|
||||
astgen.global_ref_table.deinit(gpa);
|
||||
astgen.instructions.deinit(gpa);
|
||||
astgen.extra.deinit(gpa);
|
||||
astgen.scratch.deinit(gpa);
|
||||
|
|
@ -429,56 +390,6 @@ const GenIr = struct {
|
|||
} });
|
||||
}
|
||||
|
||||
fn makeBlockInst(gi: *GenIr, tag: Ir.Inst.Tag) !Ir.Inst.Index {
|
||||
const inst_index: Ir.Inst.Index = @enumFromInt(gi.astgen.instructions.items.len);
|
||||
const gpa = gi.astgen.gpa;
|
||||
try gi.astgen.instructions.append(gpa, .{
|
||||
.tag = tag,
|
||||
.data = .{
|
||||
.payload = undefined,
|
||||
},
|
||||
});
|
||||
return inst_index;
|
||||
}
|
||||
|
||||
fn addKnot(self: *GenIr) !Ir.Inst.Index {
|
||||
const gpa = self.astgen.gpa;
|
||||
const body = self.instructionsSlice();
|
||||
const extra_len = @typeInfo(Ir.Inst.Knot).@"struct".fields.len + body.len;
|
||||
try self.astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
|
||||
const new_index: Ir.Inst.Index = @enumFromInt(self.astgen.instructions.items.len);
|
||||
try self.astgen.instructions.append(gpa, .{
|
||||
.tag = .decl_knot,
|
||||
.data = .{
|
||||
.payload = undefined,
|
||||
},
|
||||
});
|
||||
const inst_data = &self.astgen.instructions.items[@intFromEnum(new_index)].data;
|
||||
inst_data.payload.extra_index = self.astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.Knot{ .body_len = @intCast(body.len) },
|
||||
);
|
||||
|
||||
self.astgen.appendBlockBody(body);
|
||||
return new_index;
|
||||
}
|
||||
|
||||
fn addVar(gen: *GenIr, node: *const Ast.Node) !Ir.Inst.Index {
|
||||
const gpa = gen.astgen.gpa;
|
||||
const body = gen.instructionsSlice();
|
||||
const extra_len = @typeInfo(Ir.Inst.Var).@"struct".fields.len + body.len;
|
||||
try gen.astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
try gen.astgen.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const extra_index = gen.astgen.addExtraAssumeCapacity(Ir.Inst.Var{
|
||||
.body_len = @intCast(body.len),
|
||||
});
|
||||
const new_index = try gen.addPayloadNodeWithIndex(.decl_var, node, extra_index);
|
||||
gen.astgen.appendBlockBody(body);
|
||||
gen.instructions.appendAssumeCapacity(new_index.toIndex().?);
|
||||
return new_index.toIndex().?;
|
||||
}
|
||||
|
||||
fn addCondBr(gen: *GenIr, tag: Ir.Inst.Tag) !Ir.Inst.Index {
|
||||
const gpa = gen.astgen.gpa;
|
||||
try gen.instructions.ensureUnusedCapacity(gpa, 1);
|
||||
|
|
@ -509,6 +420,18 @@ const GenIr = struct {
|
|||
return gen.addPayloadNodeWithIndex(tag, node, extra_index);
|
||||
}
|
||||
|
||||
fn makePayloadNode(self: *GenIr, tag: Ir.Inst.Tag) !Ir.Inst.Index {
|
||||
const astgen = self.astgen;
|
||||
const inst_index: Ir.Inst.Index = @enumFromInt(astgen.instructions.items.len);
|
||||
try astgen.instructions.append(astgen.gpa, .{
|
||||
.tag = tag,
|
||||
.data = .{
|
||||
.payload = undefined,
|
||||
},
|
||||
});
|
||||
return inst_index;
|
||||
}
|
||||
|
||||
fn setBlockBody(self: *GenIr, inst: Ir.Inst.Index) !void {
|
||||
const gpa = self.astgen.gpa;
|
||||
const body = self.instructionsSlice();
|
||||
|
|
@ -527,7 +450,6 @@ const GenIr = struct {
|
|||
const Scope = struct {
|
||||
parent: ?*Scope,
|
||||
astgen: *AstGen,
|
||||
namespace_prefix: Ir.NullTerminatedString,
|
||||
decls: std.AutoHashMapUnmanaged(Ir.NullTerminatedString, Decl),
|
||||
|
||||
const Decl = struct {
|
||||
|
|
@ -544,16 +466,10 @@ const Scope = struct {
|
|||
return .{
|
||||
.parent = parent_scope,
|
||||
.astgen = parent_scope.astgen,
|
||||
.namespace_prefix = parent_scope.namespace_prefix,
|
||||
.decls = .empty,
|
||||
};
|
||||
}
|
||||
|
||||
fn setNamespacePrefix(scope: *Scope, relative: Ir.NullTerminatedString) !void {
|
||||
const astgen = scope.astgen;
|
||||
scope.namespace_prefix = try astgen.qualifiedString(scope.namespace_prefix, relative);
|
||||
}
|
||||
|
||||
fn insert(self: *Scope, ref: Ir.NullTerminatedString, decl: Decl) !void {
|
||||
const gpa = self.astgen.gpa;
|
||||
return self.decls.put(gpa, ref, decl);
|
||||
|
|
@ -573,38 +489,89 @@ fn setDeclaration(
|
|||
decl_index: Ir.Inst.Index,
|
||||
args: struct {
|
||||
name: Ir.NullTerminatedString,
|
||||
tag: Ir.Global.Tag,
|
||||
ref: Ir.Inst.Index,
|
||||
decl_node: *const Ast.Node,
|
||||
body_block: *GenIr,
|
||||
is_constant: bool = true,
|
||||
value: Ir.Inst.Index,
|
||||
gi: *GenIr,
|
||||
},
|
||||
) !void {
|
||||
const astgen = args.body_block.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const astgen = args.gi.astgen;
|
||||
const extra_len = @typeInfo(Ir.Inst.Declaration).@"struct".fields.len;
|
||||
const global_index = astgen.globals.items.len;
|
||||
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, extra_len);
|
||||
try astgen.globals.ensureUnusedCapacity(gpa, 1);
|
||||
try astgen.global_ref_table.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
if (astgen.global_ref_table.get(args.name)) |_| {
|
||||
return fail(astgen, args.decl_node, "redefined identifier", .{});
|
||||
}
|
||||
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_len);
|
||||
|
||||
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.Declaration{ .name = args.name, .value = args.ref },
|
||||
Ir.Inst.Declaration{
|
||||
.name = args.name,
|
||||
.value = args.value,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn setDeclVarPayload(
|
||||
decl_index: Ir.Inst.Index,
|
||||
body_block: *GenIr,
|
||||
) !void {
|
||||
defer body_block.unstack();
|
||||
|
||||
const astgen = body_block.astgen;
|
||||
const body = body_block.instructionsSlice();
|
||||
const extra_len = @typeInfo(Ir.Inst.Var).@"struct".fields.len + body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_len);
|
||||
|
||||
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.Var{
|
||||
.body_len = @intCast(body.len),
|
||||
},
|
||||
);
|
||||
astgen.appendBlockBody(body);
|
||||
}
|
||||
|
||||
fn setDeclStitchPayload(
|
||||
decl_index: Ir.Inst.Index,
|
||||
body_block: *GenIr,
|
||||
) !void {
|
||||
defer body_block.unstack();
|
||||
|
||||
const astgen = body_block.astgen;
|
||||
const block_body = body_block.instructionsSlice();
|
||||
const extra_len = @typeInfo(Ir.Inst.Knot).@"struct".fields.len + block_body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_len);
|
||||
|
||||
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.Stitch{
|
||||
.body_len = @intCast(block_body.len),
|
||||
},
|
||||
);
|
||||
|
||||
astgen.globals.appendAssumeCapacity(.{
|
||||
.tag = args.tag,
|
||||
.name = args.name,
|
||||
.is_constant = args.is_constant,
|
||||
});
|
||||
astgen.global_ref_table.putAssumeCapacity(args.name, global_index);
|
||||
args.body_block.unstack();
|
||||
astgen.appendBlockBody(block_body);
|
||||
}
|
||||
|
||||
fn setDeclKnotPayload(
|
||||
decl_index: Ir.Inst.Index,
|
||||
body_block: *GenIr,
|
||||
stitches_block: *GenIr,
|
||||
) !void {
|
||||
defer body_block.unstack();
|
||||
defer stitches_block.unstack();
|
||||
|
||||
const astgen = body_block.astgen;
|
||||
const block_body = body_block.instructionsSliceUpto(stitches_block);
|
||||
const stitches_body = stitches_block.instructionsSlice();
|
||||
const extra_len =
|
||||
@typeInfo(Ir.Inst.Knot).@"struct".fields.len + block_body.len + stitches_body.len;
|
||||
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_len);
|
||||
|
||||
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
||||
Ir.Inst.Knot{
|
||||
.body_len = @intCast(block_body.len),
|
||||
.stitches_len = @intCast(stitches_body.len),
|
||||
},
|
||||
);
|
||||
|
||||
astgen.appendBlockBody(block_body);
|
||||
astgen.appendBlockBody(stitches_body);
|
||||
}
|
||||
|
||||
fn setCondBrPayload(
|
||||
|
|
@ -843,7 +810,7 @@ fn ifStmt(
|
|||
|
||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||
const condbr = try block_scope.addCondBr(.condbr);
|
||||
const block = try parent_block.makeBlockInst(.block);
|
||||
const block = try parent_block.makePayloadNode(.block);
|
||||
try block_scope.setBlockBody(block); // unstacks block
|
||||
try parent_block.instructions.append(astgen.gpa, block);
|
||||
|
||||
|
|
@ -888,7 +855,7 @@ fn ifChain(
|
|||
const body_node = branch.data.bin.rhs.?;
|
||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||
const condbr = try block_scope.addCondBr(.condbr);
|
||||
const block_inst = try parent_block.makeBlockInst(.block);
|
||||
const block_inst = try parent_block.makePayloadNode(.block);
|
||||
try block_scope.setBlockBody(block_inst);
|
||||
try parent_block.instructions.append(gpa, block_inst);
|
||||
|
||||
|
|
@ -936,7 +903,7 @@ fn switchStmt(
|
|||
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);
|
||||
const switch_br = try parent_block.makePayloadNode(.switch_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
|
@ -1057,7 +1024,7 @@ fn choiceStmt(
|
|||
const choice_branches = stmt_node.data.list.items.?;
|
||||
assert(choice_branches.len != 0);
|
||||
|
||||
const choice_br = try parent_block.makeBlockInst(.choice_br);
|
||||
const choice_br = try parent_block.makePayloadNode(.choice_br);
|
||||
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||
try case_indexes.ensureUnusedCapacity(gpa, choice_branches.len);
|
||||
defer case_indexes.deinit(gpa);
|
||||
|
|
@ -1180,11 +1147,16 @@ fn callExpr(
|
|||
|
||||
const scratch_top = astgen.scratch.items.len;
|
||||
defer astgen.scratch.shrinkRetainingCapacity(scratch_top);
|
||||
const args_count = if (args_node) |n| n.data.list.items.?.len else 0;
|
||||
const args_count = if (args_node) |n| switch (n.tag) {
|
||||
.call_expr => n.data.list.items.?.len,
|
||||
else => 0,
|
||||
} else 0;
|
||||
try astgen.scratch.resize(gpa, scratch_top + args_count);
|
||||
var scratch_index = scratch_top;
|
||||
|
||||
if (args_node) |n| {
|
||||
if (args_node) |n| blk: {
|
||||
if (n.tag != .call_expr) break :blk;
|
||||
|
||||
const args_list = n.data.list.items.?;
|
||||
for (args_list) |arg| {
|
||||
var arg_block = gi.makeSubBlock();
|
||||
|
|
@ -1229,9 +1201,10 @@ fn callExpr(
|
|||
|
||||
fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||
// FIXME: The AST should always have an args list for these nodes.
|
||||
// FIXME: Oh God, the AST is completely fucked for this.
|
||||
const lhs = node.data.bin.lhs.?;
|
||||
switch (lhs.tag) {
|
||||
.identifier => {
|
||||
.identifier, .selector_expr => {
|
||||
const callee = try calleeExpr(gi, scope, lhs);
|
||||
switch (callee) {
|
||||
.direct => |callee_obj| {
|
||||
|
|
@ -1249,9 +1222,8 @@ fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
|||
},
|
||||
}
|
||||
},
|
||||
else => {
|
||||
_ = try callExpr(gi, scope, lhs, .divert);
|
||||
},
|
||||
.call_expr => _ = try callExpr(gi, scope, lhs, .divert),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1282,27 +1254,25 @@ fn tempDecl(gi: *GenIr, scope: *Scope, decl_node: *const Ast.Node) !void {
|
|||
|
||||
fn varDecl(gi: *GenIr, scope: *Scope, decl_node: *const Ast.Node) !void {
|
||||
const astgen = gi.astgen;
|
||||
const gpa = astgen.gpa;
|
||||
const identifier_node = decl_node.data.bin.lhs.?;
|
||||
const expr_node = decl_node.data.bin.rhs.?;
|
||||
const decl_inst = try gi.add(.{
|
||||
.tag = .declaration,
|
||||
.data = .{ .payload = undefined },
|
||||
});
|
||||
const decl_inst = try gi.makePayloadNode(.declaration);
|
||||
|
||||
var decl_block = gi.makeSubBlock();
|
||||
defer decl_block.unstack();
|
||||
|
||||
const var_inst = try decl_block.makePayloadNode(.decl_var);
|
||||
_ = try expr(&decl_block, scope, expr_node);
|
||||
const var_inst = try decl_block.addVar(decl_node);
|
||||
const name_str = try astgen.strFromNode(identifier_node);
|
||||
try setDeclaration(decl_inst.toIndex().?, .{
|
||||
.tag = .variable,
|
||||
|
||||
try setDeclVarPayload(var_inst, &decl_block);
|
||||
try setDeclaration(decl_inst, .{
|
||||
.name = name_str.index,
|
||||
.ref = var_inst,
|
||||
.decl_node = decl_node,
|
||||
.body_block = &decl_block,
|
||||
.is_constant = decl_node.tag == .const_decl,
|
||||
.value = var_inst,
|
||||
.gi = gi,
|
||||
});
|
||||
try astgen.globals.append(gpa, decl_inst);
|
||||
}
|
||||
|
||||
fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
||||
|
|
@ -1341,29 +1311,30 @@ fn defaultBlock(
|
|||
.tag = .declaration,
|
||||
.data = .{ .payload = undefined },
|
||||
});
|
||||
|
||||
var decl_scope = gi.makeSubBlock();
|
||||
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);
|
||||
|
||||
const name_str = try astgen.strFromSlice(Story.default_knot_name);
|
||||
const knot_inst = try decl_scope.addKnot();
|
||||
var stub_scope = decl_scope.makeSubBlock();
|
||||
defer stub_scope.unstack();
|
||||
try setDeclKnotPayload(knot_inst, &decl_scope, &stub_scope);
|
||||
|
||||
const decl_str = try astgen.strFromSlice(Story.default_knot_name);
|
||||
try setDeclaration(decl_inst, .{
|
||||
.tag = .knot,
|
||||
.name = name_str.index,
|
||||
.ref = knot_inst,
|
||||
.decl_node = body_node,
|
||||
.body_block = &decl_scope,
|
||||
.name = decl_str.index,
|
||||
.value = knot_inst,
|
||||
.gi = gi,
|
||||
});
|
||||
}
|
||||
|
||||
fn stitchDeclInner(
|
||||
gi: *GenIr,
|
||||
scope: *Scope,
|
||||
decl_node: *const Ast.Node,
|
||||
_: *const Ast.Node,
|
||||
prototype_node: *const Ast.Node,
|
||||
body_node: ?*const Ast.Node,
|
||||
) InnerError!void {
|
||||
|
|
@ -1378,6 +1349,8 @@ fn stitchDeclInner(
|
|||
var decl_block = gi.makeSubBlock();
|
||||
defer decl_block.unstack();
|
||||
|
||||
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| {
|
||||
|
|
@ -1398,13 +1371,12 @@ fn stitchDeclInner(
|
|||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
||||
}
|
||||
|
||||
const name_str = try astgen.strFromNode(identifier_node);
|
||||
const decl_str = try astgen.strFromNode(identifier_node);
|
||||
try setDeclStitchPayload(stitch_inst, &decl_block);
|
||||
try setDeclaration(decl_inst, .{
|
||||
.tag = .knot,
|
||||
.name = try astgen.qualifiedString(scope.namespace_prefix, name_str.index),
|
||||
.ref = try decl_block.addKnot(),
|
||||
.decl_node = decl_node,
|
||||
.body_block = &decl_block,
|
||||
.name = decl_str.index,
|
||||
.value = stitch_inst,
|
||||
.gi = gi,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1421,33 +1393,64 @@ fn stitchDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *const Ast.Node) Inne
|
|||
fn functionDecl(_: *GenIr, _: *Scope, _: *const Ast.Node) InnerError!void {}
|
||||
|
||||
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 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 },
|
||||
});
|
||||
|
||||
var decl_scope = parent_scope.makeChild();
|
||||
defer decl_scope.deinit();
|
||||
var child_block = gi.makeSubBlock();
|
||||
defer child_block.unstack();
|
||||
|
||||
const knot_inst = try gi.makePayloadNode(.decl_knot);
|
||||
|
||||
var child_scope = parent_scope.makeChild();
|
||||
defer child_scope.deinit();
|
||||
|
||||
if (prototype_node.data.bin.rhs) |args_node| {
|
||||
const args_list = args_node.data.list.items.?;
|
||||
for (args_list) |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);
|
||||
|
||||
// TODO: Maybe make decl accept a ref?
|
||||
try child_scope.insert(arg_str.index, .{
|
||||
.decl_node = arg,
|
||||
.inst_index = arg_inst.toIndex().?,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var start_index: usize = 0;
|
||||
const first_child = nested_decls_list[0];
|
||||
if (first_child.tag == .block_stmt) {
|
||||
try stitchDeclInner(gi, &decl_scope, decl_node, prototype_node, first_child);
|
||||
try blockStmt(&child_block, &child_scope, first_child);
|
||||
start_index += 1;
|
||||
} else {
|
||||
try stitchDeclInner(gi, &decl_scope, decl_node, prototype_node, null);
|
||||
}
|
||||
|
||||
const name_str = try gi.astgen.strFromNode(identifier_node);
|
||||
try decl_scope.setNamespacePrefix(name_str.index);
|
||||
var nested_block = child_block.makeSubBlock();
|
||||
defer nested_block.unstack();
|
||||
|
||||
for (nested_decls_list[start_index..]) |nested_decl_node| {
|
||||
switch (nested_decl_node.tag) {
|
||||
.stitch_decl => try stitchDecl(gi, &decl_scope, nested_decl_node),
|
||||
.function_decl => try functionDecl(gi, &decl_scope, nested_decl_node),
|
||||
.stitch_decl => try stitchDecl(&nested_block, &child_scope, nested_decl_node),
|
||||
.function_decl => try functionDecl(&nested_block, &child_scope, nested_decl_node),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const name_str = try gi.astgen.strFromNode(identifier_node);
|
||||
try setDeclKnotPayload(knot_inst, &child_block, &nested_block);
|
||||
try setDeclaration(decl_inst, .{
|
||||
.name = name_str.index,
|
||||
.value = knot_inst,
|
||||
.gi = gi,
|
||||
});
|
||||
}
|
||||
|
||||
fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
|
||||
|
|
@ -1482,5 +1485,11 @@ fn file(gi: *GenIr, scope: *Scope, file_node: *const Ast.Node) InnerError!void {
|
|||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const globals_len = gi.astgen.globals.items.len;
|
||||
try gi.astgen.instructions.ensureUnusedCapacity(gi.astgen.gpa, globals_len);
|
||||
for (gi.astgen.globals.items) |global| {
|
||||
gi.instructions.appendAssumeCapacity(global);
|
||||
}
|
||||
return file_scope.setBlockBody(file_inst);
|
||||
}
|
||||
|
|
|
|||
31
src/Ir.zig
31
src/Ir.zig
|
|
@ -12,7 +12,6 @@ string_bytes: []u8,
|
|||
/// Ancillary data for instructions. The meaning of this data is determined by
|
||||
/// the value of `Inst.Tag`. See `ExtraIndex` for the values of reserved indexes.
|
||||
extra: []u32,
|
||||
globals: []Global,
|
||||
|
||||
pub const ExtraIndex = enum(u32) {
|
||||
/// If this is 0, no compile errors. Otherwise there is a `CompileErrors`
|
||||
|
|
@ -90,31 +89,16 @@ pub fn dumpInfo(ir: Ir, writer: *std.Io.Writer) !void {
|
|||
try writer.print("00: {s}\n", .{str});
|
||||
start = end + 1;
|
||||
}
|
||||
for (ir.globals) |global| {
|
||||
try writer.print("{any}\n", .{global});
|
||||
}
|
||||
return writer.flush();
|
||||
}
|
||||
|
||||
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
|
||||
gpa.free(ir.string_bytes);
|
||||
gpa.free(ir.instructions);
|
||||
gpa.free(ir.globals);
|
||||
gpa.free(ir.extra);
|
||||
ir.* = undefined;
|
||||
}
|
||||
|
||||
pub const Global = struct {
|
||||
tag: Tag,
|
||||
name: Ir.NullTerminatedString,
|
||||
is_constant: bool,
|
||||
|
||||
pub const Tag = enum {
|
||||
knot,
|
||||
variable,
|
||||
};
|
||||
};
|
||||
|
||||
pub const Inst = struct {
|
||||
tag: Tag,
|
||||
data: Data,
|
||||
|
|
@ -164,8 +148,9 @@ pub const Inst = struct {
|
|||
pub const Tag = enum {
|
||||
file,
|
||||
declaration,
|
||||
decl_knot,
|
||||
decl_var,
|
||||
decl_knot,
|
||||
decl_stitch,
|
||||
/// Uses the `str_tok` union field.
|
||||
decl_ref,
|
||||
alloc,
|
||||
|
|
@ -247,11 +232,19 @@ pub const Inst = struct {
|
|||
value: Index,
|
||||
};
|
||||
|
||||
pub const Knot = struct {
|
||||
pub const Var = struct {
|
||||
body_len: u32,
|
||||
};
|
||||
|
||||
pub const Var = struct {
|
||||
pub const Knot = struct {
|
||||
/// Number of instructions for the knot's main block.
|
||||
body_len: u32,
|
||||
/// Number of nested stitches.
|
||||
stitches_len: u32,
|
||||
};
|
||||
|
||||
pub const Stitch = struct {
|
||||
/// Number of instructions for the stitch's body block.
|
||||
body_len: u32,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -122,12 +122,12 @@ pub const Compilation = struct {
|
|||
}
|
||||
break :fatal true;
|
||||
} else fatal: {
|
||||
sema.analyzeFile(.file_inst) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.AnalysisFail => break :fatal true,
|
||||
// TODO: These errors should be handled...
|
||||
else => |e| return e,
|
||||
};
|
||||
//sema.analyzeFile(.file_inst) catch |err| switch (err) {
|
||||
// error.OutOfMemory => return error.OutOfMemory,
|
||||
// error.AnalysisFail => break :fatal true,
|
||||
// // TODO: These errors should be handled...
|
||||
// else => |e| return e,
|
||||
//};
|
||||
break :fatal false;
|
||||
};
|
||||
return .{
|
||||
|
|
@ -144,10 +144,8 @@ pub const Compilation = struct {
|
|||
pub fn setupStoryRuntime(cu: *Compilation, gpa: std.mem.Allocator, story: *Story) !void {
|
||||
assert(cu.errors.len == 0);
|
||||
|
||||
const globals_len = cu.ir.globals.len;
|
||||
const constants_pool = &story.constants_pool;
|
||||
try constants_pool.ensureUnusedCapacity(gpa, cu.constants.len);
|
||||
try story.globals.ensureUnusedCapacity(gpa, @intCast(globals_len));
|
||||
|
||||
for (cu.constants) |constant| {
|
||||
switch (constant) {
|
||||
|
|
@ -164,10 +162,6 @@ pub const Compilation = struct {
|
|||
},
|
||||
}
|
||||
}
|
||||
for (cu.ir.globals) |global| {
|
||||
const name_bytes = cu.ir.nullTerminatedString(global.name);
|
||||
story.globals.putAssumeCapacity(name_bytes, null);
|
||||
}
|
||||
for (cu.knots) |*knot| {
|
||||
const knot_name = cu.ir.nullTerminatedString(knot.name);
|
||||
const runtime_chunk: *Object.ContentPath = try .create(story, .{
|
||||
|
|
@ -177,7 +171,7 @@ pub const Compilation = struct {
|
|||
.const_pool = try knot.constants.toOwnedSlice(gpa),
|
||||
.bytes = try knot.bytecode.toOwnedSlice(gpa),
|
||||
});
|
||||
story.globals.putAssumeCapacity(knot_name, &runtime_chunk.base);
|
||||
try story.globals.put(gpa, knot_name, &runtime_chunk.base);
|
||||
}
|
||||
story.string_bytes = cu.ir.string_bytes;
|
||||
cu.ir.string_bytes = &.{};
|
||||
|
|
|
|||
|
|
@ -204,18 +204,29 @@ pub const Writer = struct {
|
|||
try self.writeIndent(w);
|
||||
}
|
||||
|
||||
fn writeKnotDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void {
|
||||
fn writeStitchDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void {
|
||||
const data = self.code.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = self.code.extraData(Ir.Inst.Knot, data.extra_index);
|
||||
const extra = self.code.extraData(Ir.Inst.Stitch, data.extra_index);
|
||||
const body_slice = self.code.bodySlice(extra.end, extra.data.body_len);
|
||||
try w.writeAll("body=");
|
||||
try self.writeBodyInner(w, body_slice);
|
||||
}
|
||||
|
||||
fn writeVarDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void {
|
||||
fn writeKnotDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void {
|
||||
const data = self.code.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = self.code.extraData(Ir.Inst.Knot, data.extra_index);
|
||||
const body_slice = self.code.bodySlice(extra.end, extra.data.body_len);
|
||||
const stitch_slice = self.code.bodySlice(extra.end + body_slice.len, extra.data.stitches_len);
|
||||
try w.writeAll("body=");
|
||||
try self.writeBodyInner(w, body_slice);
|
||||
try w.writeAll(", stitches=");
|
||||
try self.writeBodyInner(w, stitch_slice);
|
||||
}
|
||||
|
||||
fn writeVarDeclInst(self: *Writer, w: *std.Io.Writer, inst: Ir.Inst.Index) Error!void {
|
||||
const data = self.code.instructions[@intFromEnum(inst)].data.payload;
|
||||
const extra = self.code.extraData(Ir.Inst.Var, data.extra_index);
|
||||
const body_slice = self.code.bodySlice(extra.end, extra.data.body_len);
|
||||
try w.writeAll("body=");
|
||||
try self.writeBodyInner(w, body_slice);
|
||||
}
|
||||
|
|
@ -272,8 +283,9 @@ pub const Writer = struct {
|
|||
switch (tmp.tag) {
|
||||
.file => try self.writeFileInst(w, inst),
|
||||
.declaration => try self.writeDeclarationInst(w, inst),
|
||||
.decl_knot => try self.writeKnotDeclInst(w, inst),
|
||||
.decl_var => try self.writeVarDeclInst(w, inst),
|
||||
.decl_knot => try self.writeKnotDeclInst(w, inst),
|
||||
.decl_stitch => try self.writeVarDeclInst(w, inst),
|
||||
.decl_ref => try self.writeStrTokInst(w, inst),
|
||||
.condbr => try self.writeCondbrInst(w, inst),
|
||||
.@"break" => try self.writeBreakInst(w, inst),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue