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,
|
tree: *const Ast,
|
||||||
string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
|
string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .empty,
|
||||||
string_bytes: std.ArrayListUnmanaged(u8) = .empty,
|
string_bytes: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
|
globals: std.ArrayListUnmanaged(Ir.Inst.Index) = .empty,
|
||||||
instructions: std.ArrayListUnmanaged(Ir.Inst) = .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,
|
extra: std.ArrayListUnmanaged(u32) = .empty,
|
||||||
scratch: std.ArrayListUnmanaged(u32) = .empty,
|
scratch: std.ArrayListUnmanaged(u32) = .empty,
|
||||||
compile_errors: std.ArrayListUnmanaged(Ir.Inst.CompileErrors.Item) = .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);
|
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.
|
/// Perform IR code generation via tree-walk.
|
||||||
pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
||||||
var astgen: AstGen = .{
|
var astgen: AstGen = .{
|
||||||
|
|
@ -217,7 +181,6 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
||||||
var file_scope: Scope = .{
|
var file_scope: Scope = .{
|
||||||
.parent = null,
|
.parent = null,
|
||||||
.decls = .empty,
|
.decls = .empty,
|
||||||
.namespace_prefix = .empty,
|
|
||||||
.astgen = &astgen,
|
.astgen = &astgen,
|
||||||
};
|
};
|
||||||
var block: GenIr = .{
|
var block: GenIr = .{
|
||||||
|
|
@ -263,7 +226,6 @@ pub fn generate(gpa: std.mem.Allocator, tree: *const Ast) !Ir {
|
||||||
return .{
|
return .{
|
||||||
.instructions = if (fatal) &.{} else try astgen.instructions.toOwnedSlice(gpa),
|
.instructions = if (fatal) &.{} else try astgen.instructions.toOwnedSlice(gpa),
|
||||||
.string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
|
.string_bytes = try astgen.string_bytes.toOwnedSlice(gpa),
|
||||||
.globals = try astgen.globals.toOwnedSlice(gpa),
|
|
||||||
.extra = try astgen.extra.toOwnedSlice(gpa),
|
.extra = try astgen.extra.toOwnedSlice(gpa),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +235,6 @@ fn deinit(astgen: *AstGen) void {
|
||||||
astgen.string_table.deinit(gpa);
|
astgen.string_table.deinit(gpa);
|
||||||
astgen.string_bytes.deinit(gpa);
|
astgen.string_bytes.deinit(gpa);
|
||||||
astgen.globals.deinit(gpa);
|
astgen.globals.deinit(gpa);
|
||||||
astgen.global_ref_table.deinit(gpa);
|
|
||||||
astgen.instructions.deinit(gpa);
|
astgen.instructions.deinit(gpa);
|
||||||
astgen.extra.deinit(gpa);
|
astgen.extra.deinit(gpa);
|
||||||
astgen.scratch.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 {
|
fn addCondBr(gen: *GenIr, tag: Ir.Inst.Tag) !Ir.Inst.Index {
|
||||||
const gpa = gen.astgen.gpa;
|
const gpa = gen.astgen.gpa;
|
||||||
try gen.instructions.ensureUnusedCapacity(gpa, 1);
|
try gen.instructions.ensureUnusedCapacity(gpa, 1);
|
||||||
|
|
@ -509,6 +420,18 @@ const GenIr = struct {
|
||||||
return gen.addPayloadNodeWithIndex(tag, node, extra_index);
|
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 {
|
fn setBlockBody(self: *GenIr, inst: Ir.Inst.Index) !void {
|
||||||
const gpa = self.astgen.gpa;
|
const gpa = self.astgen.gpa;
|
||||||
const body = self.instructionsSlice();
|
const body = self.instructionsSlice();
|
||||||
|
|
@ -527,7 +450,6 @@ const GenIr = struct {
|
||||||
const Scope = struct {
|
const Scope = struct {
|
||||||
parent: ?*Scope,
|
parent: ?*Scope,
|
||||||
astgen: *AstGen,
|
astgen: *AstGen,
|
||||||
namespace_prefix: Ir.NullTerminatedString,
|
|
||||||
decls: std.AutoHashMapUnmanaged(Ir.NullTerminatedString, Decl),
|
decls: std.AutoHashMapUnmanaged(Ir.NullTerminatedString, Decl),
|
||||||
|
|
||||||
const Decl = struct {
|
const Decl = struct {
|
||||||
|
|
@ -544,16 +466,10 @@ const Scope = struct {
|
||||||
return .{
|
return .{
|
||||||
.parent = parent_scope,
|
.parent = parent_scope,
|
||||||
.astgen = parent_scope.astgen,
|
.astgen = parent_scope.astgen,
|
||||||
.namespace_prefix = parent_scope.namespace_prefix,
|
|
||||||
.decls = .empty,
|
.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 {
|
fn insert(self: *Scope, ref: Ir.NullTerminatedString, decl: Decl) !void {
|
||||||
const gpa = self.astgen.gpa;
|
const gpa = self.astgen.gpa;
|
||||||
return self.decls.put(gpa, ref, decl);
|
return self.decls.put(gpa, ref, decl);
|
||||||
|
|
@ -573,38 +489,89 @@ fn setDeclaration(
|
||||||
decl_index: Ir.Inst.Index,
|
decl_index: Ir.Inst.Index,
|
||||||
args: struct {
|
args: struct {
|
||||||
name: Ir.NullTerminatedString,
|
name: Ir.NullTerminatedString,
|
||||||
tag: Ir.Global.Tag,
|
value: Ir.Inst.Index,
|
||||||
ref: Ir.Inst.Index,
|
gi: *GenIr,
|
||||||
decl_node: *const Ast.Node,
|
|
||||||
body_block: *GenIr,
|
|
||||||
is_constant: bool = true,
|
|
||||||
},
|
},
|
||||||
) !void {
|
) !void {
|
||||||
const astgen = args.body_block.astgen;
|
const astgen = args.gi.astgen;
|
||||||
const gpa = astgen.gpa;
|
|
||||||
const extra_len = @typeInfo(Ir.Inst.Declaration).@"struct".fields.len;
|
const extra_len = @typeInfo(Ir.Inst.Declaration).@"struct".fields.len;
|
||||||
const global_index = astgen.globals.items.len;
|
try astgen.extra.ensureUnusedCapacity(astgen.gpa, extra_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", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
const inst_data = &astgen.instructions.items[@intFromEnum(decl_index)].data;
|
||||||
inst_data.payload.extra_index = astgen.addExtraAssumeCapacity(
|
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(.{
|
astgen.appendBlockBody(block_body);
|
||||||
.tag = args.tag,
|
}
|
||||||
.name = args.name,
|
|
||||||
.is_constant = args.is_constant,
|
fn setDeclKnotPayload(
|
||||||
});
|
decl_index: Ir.Inst.Index,
|
||||||
astgen.global_ref_table.putAssumeCapacity(args.name, global_index);
|
body_block: *GenIr,
|
||||||
args.body_block.unstack();
|
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(
|
fn setCondBrPayload(
|
||||||
|
|
@ -843,7 +810,7 @@ fn ifStmt(
|
||||||
|
|
||||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||||
const condbr = try block_scope.addCondBr(.condbr);
|
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 block_scope.setBlockBody(block); // unstacks block
|
||||||
try parent_block.instructions.append(astgen.gpa, block);
|
try parent_block.instructions.append(astgen.gpa, block);
|
||||||
|
|
||||||
|
|
@ -888,7 +855,7 @@ fn ifChain(
|
||||||
const body_node = branch.data.bin.rhs.?;
|
const body_node = branch.data.bin.rhs.?;
|
||||||
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
const cond_inst = try expr(&block_scope, scope, cond_expr);
|
||||||
const condbr = try block_scope.addCondBr(.condbr);
|
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 block_scope.setBlockBody(block_inst);
|
||||||
try parent_block.instructions.append(gpa, block_inst);
|
try parent_block.instructions.append(gpa, block_inst);
|
||||||
|
|
||||||
|
|
@ -936,7 +903,7 @@ fn switchStmt(
|
||||||
try validateSwitchProngs(parent_block, stmt_node);
|
try validateSwitchProngs(parent_block, stmt_node);
|
||||||
|
|
||||||
const cond_inst = try expr(parent_block, scope, switch_stmt.condition_expr);
|
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;
|
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||||
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
try case_indexes.ensureUnusedCapacity(gpa, switch_stmt.cases.len);
|
||||||
defer case_indexes.deinit(gpa);
|
defer case_indexes.deinit(gpa);
|
||||||
|
|
@ -1057,7 +1024,7 @@ fn choiceStmt(
|
||||||
const choice_branches = stmt_node.data.list.items.?;
|
const choice_branches = stmt_node.data.list.items.?;
|
||||||
assert(choice_branches.len != 0);
|
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;
|
var case_indexes: std.ArrayListUnmanaged(u32) = .empty;
|
||||||
try case_indexes.ensureUnusedCapacity(gpa, choice_branches.len);
|
try case_indexes.ensureUnusedCapacity(gpa, choice_branches.len);
|
||||||
defer case_indexes.deinit(gpa);
|
defer case_indexes.deinit(gpa);
|
||||||
|
|
@ -1180,11 +1147,16 @@ fn callExpr(
|
||||||
|
|
||||||
const scratch_top = astgen.scratch.items.len;
|
const scratch_top = astgen.scratch.items.len;
|
||||||
defer astgen.scratch.shrinkRetainingCapacity(scratch_top);
|
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);
|
try astgen.scratch.resize(gpa, scratch_top + args_count);
|
||||||
var scratch_index = scratch_top;
|
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.?;
|
const args_list = n.data.list.items.?;
|
||||||
for (args_list) |arg| {
|
for (args_list) |arg| {
|
||||||
var arg_block = gi.makeSubBlock();
|
var arg_block = gi.makeSubBlock();
|
||||||
|
|
@ -1229,9 +1201,10 @@ fn callExpr(
|
||||||
|
|
||||||
fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||||
// FIXME: The AST should always have an args list for these nodes.
|
// 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.?;
|
const lhs = node.data.bin.lhs.?;
|
||||||
switch (lhs.tag) {
|
switch (lhs.tag) {
|
||||||
.identifier => {
|
.identifier, .selector_expr => {
|
||||||
const callee = try calleeExpr(gi, scope, lhs);
|
const callee = try calleeExpr(gi, scope, lhs);
|
||||||
switch (callee) {
|
switch (callee) {
|
||||||
.direct => |callee_obj| {
|
.direct => |callee_obj| {
|
||||||
|
|
@ -1249,9 +1222,8 @@ fn divertExpr(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {
|
.call_expr => _ = try callExpr(gi, scope, lhs, .divert),
|
||||||
_ = 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 {
|
fn varDecl(gi: *GenIr, scope: *Scope, decl_node: *const Ast.Node) !void {
|
||||||
const astgen = gi.astgen;
|
const astgen = gi.astgen;
|
||||||
|
const gpa = astgen.gpa;
|
||||||
const identifier_node = decl_node.data.bin.lhs.?;
|
const identifier_node = decl_node.data.bin.lhs.?;
|
||||||
const expr_node = decl_node.data.bin.rhs.?;
|
const expr_node = decl_node.data.bin.rhs.?;
|
||||||
const decl_inst = try gi.add(.{
|
const decl_inst = try gi.makePayloadNode(.declaration);
|
||||||
.tag = .declaration,
|
|
||||||
.data = .{ .payload = undefined },
|
|
||||||
});
|
|
||||||
|
|
||||||
var decl_block = gi.makeSubBlock();
|
var decl_block = gi.makeSubBlock();
|
||||||
defer decl_block.unstack();
|
defer decl_block.unstack();
|
||||||
|
|
||||||
|
const var_inst = try decl_block.makePayloadNode(.decl_var);
|
||||||
_ = try expr(&decl_block, scope, expr_node);
|
_ = try expr(&decl_block, scope, expr_node);
|
||||||
const var_inst = try decl_block.addVar(decl_node);
|
|
||||||
const name_str = try astgen.strFromNode(identifier_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,
|
.name = name_str.index,
|
||||||
.ref = var_inst,
|
.value = var_inst,
|
||||||
.decl_node = decl_node,
|
.gi = gi,
|
||||||
.body_block = &decl_block,
|
|
||||||
.is_constant = decl_node.tag == .const_decl,
|
|
||||||
});
|
});
|
||||||
|
try astgen.globals.append(gpa, decl_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
fn blockInner(gi: *GenIr, parent_scope: *Scope, stmt_list: []*Ast.Node) !void {
|
||||||
|
|
@ -1341,29 +1311,30 @@ fn defaultBlock(
|
||||||
.tag = .declaration,
|
.tag = .declaration,
|
||||||
.data = .{ .payload = undefined },
|
.data = .{ .payload = undefined },
|
||||||
});
|
});
|
||||||
|
|
||||||
var decl_scope = gi.makeSubBlock();
|
var decl_scope = gi.makeSubBlock();
|
||||||
defer decl_scope.unstack();
|
defer decl_scope.unstack();
|
||||||
|
|
||||||
|
const knot_inst = try decl_scope.makePayloadNode(.decl_knot);
|
||||||
// TODO: Make sure that this value is concrete to omit check.
|
// TODO: Make sure that this value is concrete to omit check.
|
||||||
const block_stmts = body_node.data.list.items.?;
|
const block_stmts = body_node.data.list.items.?;
|
||||||
try blockInner(&decl_scope, scope, block_stmts);
|
try blockInner(&decl_scope, scope, block_stmts);
|
||||||
|
|
||||||
const name_str = try astgen.strFromSlice(Story.default_knot_name);
|
var stub_scope = decl_scope.makeSubBlock();
|
||||||
const knot_inst = try decl_scope.addKnot();
|
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, .{
|
try setDeclaration(decl_inst, .{
|
||||||
.tag = .knot,
|
.name = decl_str.index,
|
||||||
.name = name_str.index,
|
.value = knot_inst,
|
||||||
.ref = knot_inst,
|
.gi = gi,
|
||||||
.decl_node = body_node,
|
|
||||||
.body_block = &decl_scope,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stitchDeclInner(
|
fn stitchDeclInner(
|
||||||
gi: *GenIr,
|
gi: *GenIr,
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
decl_node: *const Ast.Node,
|
_: *const Ast.Node,
|
||||||
prototype_node: *const Ast.Node,
|
prototype_node: *const Ast.Node,
|
||||||
body_node: ?*const Ast.Node,
|
body_node: ?*const Ast.Node,
|
||||||
) InnerError!void {
|
) InnerError!void {
|
||||||
|
|
@ -1378,6 +1349,8 @@ fn stitchDeclInner(
|
||||||
var decl_block = gi.makeSubBlock();
|
var decl_block = gi.makeSubBlock();
|
||||||
defer decl_block.unstack();
|
defer decl_block.unstack();
|
||||||
|
|
||||||
|
const stitch_inst = try decl_block.makePayloadNode(.decl_stitch);
|
||||||
|
|
||||||
if (prototype_data.rhs) |args_node| {
|
if (prototype_data.rhs) |args_node| {
|
||||||
const args_list = args_node.data.list.items.?;
|
const args_list = args_node.data.list.items.?;
|
||||||
for (args_list) |arg| {
|
for (args_list) |arg| {
|
||||||
|
|
@ -1398,13 +1371,12 @@ fn stitchDeclInner(
|
||||||
_ = try decl_block.addUnaryNode(.implicit_ret, .none);
|
_ = 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, .{
|
try setDeclaration(decl_inst, .{
|
||||||
.tag = .knot,
|
.name = decl_str.index,
|
||||||
.name = try astgen.qualifiedString(scope.namespace_prefix, name_str.index),
|
.value = stitch_inst,
|
||||||
.ref = try decl_block.addKnot(),
|
.gi = gi,
|
||||||
.decl_node = decl_node,
|
|
||||||
.body_block = &decl_block,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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 functionDecl(_: *GenIr, _: *Scope, _: *const Ast.Node) InnerError!void {}
|
||||||
|
|
||||||
fn knotDecl(gi: *GenIr, parent_scope: *Scope, decl_node: *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 knot_data = decl_node.data.knot_decl;
|
||||||
const prototype_node = knot_data.prototype;
|
const prototype_node = knot_data.prototype;
|
||||||
const identifier_node = prototype_node.data.bin.lhs.?;
|
const identifier_node = prototype_node.data.bin.lhs.?;
|
||||||
const nested_decls_list = knot_data.children.?;
|
const nested_decls_list = knot_data.children.?;
|
||||||
|
const decl_inst = try gi.addAsIndex(.{
|
||||||
|
.tag = .declaration,
|
||||||
|
.data = .{ .payload = undefined },
|
||||||
|
});
|
||||||
|
|
||||||
var decl_scope = parent_scope.makeChild();
|
var child_block = gi.makeSubBlock();
|
||||||
defer decl_scope.deinit();
|
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;
|
var start_index: usize = 0;
|
||||||
const first_child = nested_decls_list[0];
|
const first_child = nested_decls_list[0];
|
||||||
if (first_child.tag == .block_stmt) {
|
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;
|
start_index += 1;
|
||||||
} else {
|
|
||||||
try stitchDeclInner(gi, &decl_scope, decl_node, prototype_node, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const name_str = try gi.astgen.strFromNode(identifier_node);
|
var nested_block = child_block.makeSubBlock();
|
||||||
try decl_scope.setNamespacePrefix(name_str.index);
|
defer nested_block.unstack();
|
||||||
|
|
||||||
for (nested_decls_list[start_index..]) |nested_decl_node| {
|
for (nested_decls_list[start_index..]) |nested_decl_node| {
|
||||||
switch (nested_decl_node.tag) {
|
switch (nested_decl_node.tag) {
|
||||||
.stitch_decl => try stitchDecl(gi, &decl_scope, nested_decl_node),
|
.stitch_decl => try stitchDecl(&nested_block, &child_scope, nested_decl_node),
|
||||||
.function_decl => try functionDecl(gi, &decl_scope, nested_decl_node),
|
.function_decl => try functionDecl(&nested_block, &child_scope, nested_decl_node),
|
||||||
else => unreachable,
|
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 {
|
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,
|
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);
|
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
|
/// 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.
|
/// the value of `Inst.Tag`. See `ExtraIndex` for the values of reserved indexes.
|
||||||
extra: []u32,
|
extra: []u32,
|
||||||
globals: []Global,
|
|
||||||
|
|
||||||
pub const ExtraIndex = enum(u32) {
|
pub const ExtraIndex = enum(u32) {
|
||||||
/// If this is 0, no compile errors. Otherwise there is a `CompileErrors`
|
/// 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});
|
try writer.print("00: {s}\n", .{str});
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
}
|
}
|
||||||
for (ir.globals) |global| {
|
|
||||||
try writer.print("{any}\n", .{global});
|
|
||||||
}
|
|
||||||
return writer.flush();
|
return writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
|
pub fn deinit(ir: *Ir, gpa: std.mem.Allocator) void {
|
||||||
gpa.free(ir.string_bytes);
|
gpa.free(ir.string_bytes);
|
||||||
gpa.free(ir.instructions);
|
gpa.free(ir.instructions);
|
||||||
gpa.free(ir.globals);
|
|
||||||
gpa.free(ir.extra);
|
gpa.free(ir.extra);
|
||||||
ir.* = undefined;
|
ir.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const Global = struct {
|
|
||||||
tag: Tag,
|
|
||||||
name: Ir.NullTerminatedString,
|
|
||||||
is_constant: bool,
|
|
||||||
|
|
||||||
pub const Tag = enum {
|
|
||||||
knot,
|
|
||||||
variable,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Inst = struct {
|
pub const Inst = struct {
|
||||||
tag: Tag,
|
tag: Tag,
|
||||||
data: Data,
|
data: Data,
|
||||||
|
|
@ -164,8 +148,9 @@ pub const Inst = struct {
|
||||||
pub const Tag = enum {
|
pub const Tag = enum {
|
||||||
file,
|
file,
|
||||||
declaration,
|
declaration,
|
||||||
decl_knot,
|
|
||||||
decl_var,
|
decl_var,
|
||||||
|
decl_knot,
|
||||||
|
decl_stitch,
|
||||||
/// Uses the `str_tok` union field.
|
/// Uses the `str_tok` union field.
|
||||||
decl_ref,
|
decl_ref,
|
||||||
alloc,
|
alloc,
|
||||||
|
|
@ -247,11 +232,19 @@ pub const Inst = struct {
|
||||||
value: Index,
|
value: Index,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Knot = struct {
|
pub const Var = struct {
|
||||||
body_len: u32,
|
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,
|
body_len: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -122,12 +122,12 @@ pub const Compilation = struct {
|
||||||
}
|
}
|
||||||
break :fatal true;
|
break :fatal true;
|
||||||
} else fatal: {
|
} else fatal: {
|
||||||
sema.analyzeFile(.file_inst) catch |err| switch (err) {
|
//sema.analyzeFile(.file_inst) catch |err| switch (err) {
|
||||||
error.OutOfMemory => return error.OutOfMemory,
|
// error.OutOfMemory => return error.OutOfMemory,
|
||||||
error.AnalysisFail => break :fatal true,
|
// error.AnalysisFail => break :fatal true,
|
||||||
// TODO: These errors should be handled...
|
// // TODO: These errors should be handled...
|
||||||
else => |e| return e,
|
// else => |e| return e,
|
||||||
};
|
//};
|
||||||
break :fatal false;
|
break :fatal false;
|
||||||
};
|
};
|
||||||
return .{
|
return .{
|
||||||
|
|
@ -144,10 +144,8 @@ pub const Compilation = struct {
|
||||||
pub fn setupStoryRuntime(cu: *Compilation, gpa: std.mem.Allocator, story: *Story) !void {
|
pub fn setupStoryRuntime(cu: *Compilation, gpa: std.mem.Allocator, story: *Story) !void {
|
||||||
assert(cu.errors.len == 0);
|
assert(cu.errors.len == 0);
|
||||||
|
|
||||||
const globals_len = cu.ir.globals.len;
|
|
||||||
const constants_pool = &story.constants_pool;
|
const constants_pool = &story.constants_pool;
|
||||||
try constants_pool.ensureUnusedCapacity(gpa, cu.constants.len);
|
try constants_pool.ensureUnusedCapacity(gpa, cu.constants.len);
|
||||||
try story.globals.ensureUnusedCapacity(gpa, @intCast(globals_len));
|
|
||||||
|
|
||||||
for (cu.constants) |constant| {
|
for (cu.constants) |constant| {
|
||||||
switch (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| {
|
for (cu.knots) |*knot| {
|
||||||
const knot_name = cu.ir.nullTerminatedString(knot.name);
|
const knot_name = cu.ir.nullTerminatedString(knot.name);
|
||||||
const runtime_chunk: *Object.ContentPath = try .create(story, .{
|
const runtime_chunk: *Object.ContentPath = try .create(story, .{
|
||||||
|
|
@ -177,7 +171,7 @@ pub const Compilation = struct {
|
||||||
.const_pool = try knot.constants.toOwnedSlice(gpa),
|
.const_pool = try knot.constants.toOwnedSlice(gpa),
|
||||||
.bytes = try knot.bytecode.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;
|
story.string_bytes = cu.ir.string_bytes;
|
||||||
cu.ir.string_bytes = &.{};
|
cu.ir.string_bytes = &.{};
|
||||||
|
|
|
||||||
|
|
@ -204,18 +204,29 @@ pub const Writer = struct {
|
||||||
try self.writeIndent(w);
|
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 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);
|
const body_slice = self.code.bodySlice(extra.end, extra.data.body_len);
|
||||||
try w.writeAll("body=");
|
try w.writeAll("body=");
|
||||||
try self.writeBodyInner(w, body_slice);
|
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 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.Knot, data.extra_index);
|
||||||
const body_slice = self.code.bodySlice(extra.end, extra.data.body_len);
|
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 w.writeAll("body=");
|
||||||
try self.writeBodyInner(w, body_slice);
|
try self.writeBodyInner(w, body_slice);
|
||||||
}
|
}
|
||||||
|
|
@ -272,8 +283,9 @@ pub const Writer = struct {
|
||||||
switch (tmp.tag) {
|
switch (tmp.tag) {
|
||||||
.file => try self.writeFileInst(w, inst),
|
.file => try self.writeFileInst(w, inst),
|
||||||
.declaration => try self.writeDeclarationInst(w, inst),
|
.declaration => try self.writeDeclarationInst(w, inst),
|
||||||
.decl_knot => try self.writeKnotDeclInst(w, inst),
|
|
||||||
.decl_var => try self.writeVarDeclInst(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),
|
.decl_ref => try self.writeStrTokInst(w, inst),
|
||||||
.condbr => try self.writeCondbrInst(w, inst),
|
.condbr => try self.writeCondbrInst(w, inst),
|
||||||
.@"break" => try self.writeBreakInst(w, inst),
|
.@"break" => try self.writeBreakInst(w, inst),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue