diff --git a/src/AstGen.zig b/src/AstGen.zig index 4c8aa30..e2b498e 100644 --- a/src/AstGen.zig +++ b/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); } diff --git a/src/Ir.zig b/src/Ir.zig index b1c52c8..e4a62af 100644 --- a/src/Ir.zig +++ b/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, }; diff --git a/src/compile.zig b/src/compile.zig index 6b56c27..401604e 100644 --- a/src/compile.zig +++ b/src/compile.zig @@ -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 = &.{}; diff --git a/src/print_ir.zig b/src/print_ir.zig index 42ea508..663baec 100644 --- a/src/print_ir.zig +++ b/src/print_ir.zig @@ -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),