refactor: redefining assumptions about declarations

This commit is contained in:
Brett Broadhurst 2026-03-23 22:45:55 -06:00
parent be297047d1
commit 33e3c1c271
Failed to generate hash of commit
4 changed files with 210 additions and 202 deletions

View file

@ -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);
}

View file

@ -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,
};

View file

@ -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 = &.{};

View file

@ -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),