fix: content inconsistencies in the vm
This commit is contained in:
parent
236acc7d60
commit
ecd6017673
6 changed files with 259 additions and 115 deletions
|
|
@ -857,7 +857,7 @@ fn inlineIfStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.
|
||||||
if (data.rhs) |rhs| {
|
if (data.rhs) |rhs| {
|
||||||
// TODO: Revisit this. This isn't quite correct.
|
// TODO: Revisit this. This isn't quite correct.
|
||||||
switch (rhs.tag) {
|
switch (rhs.tag) {
|
||||||
.content => _ = try content(&then_block, scope, rhs, false, false),
|
.content => _ = try content(&then_block, scope, rhs, false),
|
||||||
inline else => |tag| @panic("Unexpected node type: " ++ @tagName(tag)),
|
inline else => |tag| @panic("Unexpected node type: " ++ @tagName(tag)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1047,7 +1047,9 @@ fn switchStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!Ir.In
|
||||||
var case_block = gi.makeSubBlock();
|
var case_block = gi.makeSubBlock();
|
||||||
defer case_block.unstack();
|
defer case_block.unstack();
|
||||||
|
|
||||||
_ = try blockStmt(&case_block, scope, case_data.rhs.?);
|
if (case_data.rhs) |case_block_node| {
|
||||||
|
_ = try blockStmt(&case_block, scope, case_block_node);
|
||||||
|
}
|
||||||
if (!case_block.endsWithNoReturn()) {
|
if (!case_block.endsWithNoReturn()) {
|
||||||
_ = try case_block.addBreak(.@"break", case_stmt, switch_br, .void);
|
_ = try case_block.addBreak(.@"break", case_stmt, switch_br, .void);
|
||||||
}
|
}
|
||||||
|
|
@ -1105,9 +1107,9 @@ fn content(
|
||||||
block: *GenIr,
|
block: *GenIr,
|
||||||
scope: *Scope,
|
scope: *Scope,
|
||||||
node: *const Ast.Node,
|
node: *const Ast.Node,
|
||||||
is_last: bool,
|
|
||||||
ignore_divert: bool,
|
ignore_divert: bool,
|
||||||
) InnerError!void {
|
) InnerError!bool {
|
||||||
|
var suppress: bool = false;
|
||||||
const data = node.data.content;
|
const data = node.data.content;
|
||||||
if (data.leading_glue) {
|
if (data.leading_glue) {
|
||||||
_ = try block.addUnaryNode(.content_glue, .none);
|
_ = try block.addUnaryNode(.content_glue, .none);
|
||||||
|
|
@ -1122,33 +1124,43 @@ fn content(
|
||||||
const result = try inlineLogicExpr(block, scope, child_node);
|
const result = try inlineLogicExpr(block, scope, child_node);
|
||||||
_ = try block.addUnaryNode(.content_push, result);
|
_ = try block.addUnaryNode(.content_push, result);
|
||||||
},
|
},
|
||||||
.if_stmt => _ = try ifStmt(block, scope, child_node),
|
.if_stmt => _ = {
|
||||||
.multi_if_stmt => _ = try multiIfStmt(block, scope, child_node),
|
_ = try ifStmt(block, scope, child_node);
|
||||||
.switch_stmt => _ = try switchStmt(block, scope, child_node),
|
suppress = true;
|
||||||
|
},
|
||||||
|
.multi_if_stmt => {
|
||||||
|
_ = try multiIfStmt(block, scope, child_node);
|
||||||
|
suppress = true;
|
||||||
|
},
|
||||||
|
.switch_stmt => {
|
||||||
|
_ = try switchStmt(block, scope, child_node);
|
||||||
|
suppress = true;
|
||||||
|
},
|
||||||
.inline_if_stmt => _ = try inlineIfStmt(block, scope, child_node),
|
.inline_if_stmt => _ = try inlineIfStmt(block, scope, child_node),
|
||||||
.divert_expr => _ = try divertExpr(block, scope, child_node),
|
.divert_expr => _ = try divertExpr(block, scope, child_node),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_last) {
|
if (data.trailing_glue or data.trailing_divert != null) {
|
||||||
_ = try block.addUnaryNode(.content_line, .none);
|
_ = try block.addUnaryNode(.content_glue, .none);
|
||||||
if (data.trailing_glue or data.trailing_divert != null) {
|
}
|
||||||
|
if (!ignore_divert) {
|
||||||
|
if (data.trailing_divert) |trailing| {
|
||||||
|
_ = try divertExpr(block, scope, trailing);
|
||||||
_ = try block.addUnaryNode(.content_glue, .none);
|
_ = try block.addUnaryNode(.content_glue, .none);
|
||||||
}
|
}
|
||||||
if (!ignore_divert) {
|
|
||||||
if (data.trailing_divert) |trailing| {
|
|
||||||
_ = try divertExpr(block, scope, trailing);
|
|
||||||
_ = try block.addUnaryNode(.content_glue, .none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return suppress;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contentStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
fn contentStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) !void {
|
||||||
const items = node.data.list.items;
|
var supress: bool = false;
|
||||||
for (items, 0..) |n, i| {
|
const data = node.data.list;
|
||||||
const is_last = i == items.len - 1;
|
for (data.items) |item_node| {
|
||||||
try content(gi, scope, n, is_last, false);
|
supress = try content(gi, scope, item_node, false);
|
||||||
|
}
|
||||||
|
if (!supress) {
|
||||||
|
_ = try gi.addUnaryNode(.content_line, .void);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1186,11 +1198,11 @@ fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
||||||
defer block_1.unstack();
|
defer block_1.unstack();
|
||||||
|
|
||||||
if (branch_expr.start_expr) |lhs| {
|
if (branch_expr.start_expr) |lhs| {
|
||||||
for (lhs) |n| {
|
for (lhs) |lhs_node| {
|
||||||
if (n.data.content.trailing_divert) |trailing| {
|
if (lhs_node.data.content.trailing_divert) |trailing| {
|
||||||
trailing_divert = trailing;
|
trailing_divert = trailing;
|
||||||
}
|
}
|
||||||
_ = try content(&block_1, scope, n, false, true);
|
_ = try content(&block_1, scope, lhs_node, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1198,9 +1210,9 @@ fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
||||||
defer block_2.unstack();
|
defer block_2.unstack();
|
||||||
|
|
||||||
if (branch_expr.option_expr) |mhs| {
|
if (branch_expr.option_expr) |mhs| {
|
||||||
for (mhs) |n| {
|
for (mhs) |mhs_node| {
|
||||||
assert(n.data.content.trailing_divert == null);
|
assert(mhs_node.data.content.trailing_divert == null);
|
||||||
_ = try content(&block_2, scope, n, false, true);
|
_ = try content(&block_2, scope, mhs_node, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1208,11 +1220,11 @@ fn choiceStmt(gi: *GenIr, scope: *Scope, node: *const Ast.Node) InnerError!void
|
||||||
defer block_3.unstack();
|
defer block_3.unstack();
|
||||||
|
|
||||||
if (branch_expr.inner_expr) |rhs| {
|
if (branch_expr.inner_expr) |rhs| {
|
||||||
for (rhs) |n| {
|
for (rhs) |rhs_node| {
|
||||||
if (n.data.content.trailing_divert) |trailing| {
|
if (rhs_node.data.content.trailing_divert) |trailing| {
|
||||||
trailing_divert = trailing;
|
trailing_divert = trailing;
|
||||||
}
|
}
|
||||||
_ = try content(&block_3, scope, n, false, true);
|
_ = try content(&block_3, scope, rhs_node, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
206
src/Sema.zig
206
src/Sema.zig
|
|
@ -154,6 +154,12 @@ pub fn deinit(sema: *Sema) void {
|
||||||
sema.* = undefined;
|
sema.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const Block = struct {
|
||||||
|
parent_block: ?*Block,
|
||||||
|
block_inst: Ir.Inst.Index,
|
||||||
|
exit_label: usize,
|
||||||
|
};
|
||||||
|
|
||||||
pub const Builder = struct {
|
pub const Builder = struct {
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
namespace: *Module.Namespace,
|
namespace: *Module.Namespace,
|
||||||
|
|
@ -503,9 +509,12 @@ fn irBinaryOp(
|
||||||
fn analyzeInlineBody(
|
fn analyzeInlineBody(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
body: []const Ir.Inst.Index,
|
body: []const Ir.Inst.Index,
|
||||||
) !ValueInfo {
|
) !ValueInfo {
|
||||||
if (sema.analyzeBodyInner(builder, body, true)) |_| {} else |err| switch (err) {
|
if (sema.analyzeBodyInner(builder, block, body, true)) |_| {
|
||||||
|
// TODO: Do something.
|
||||||
|
} else |err| switch (err) {
|
||||||
error.ComptimeBreak => {},
|
error.ComptimeBreak => {},
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
}
|
}
|
||||||
|
|
@ -517,6 +526,7 @@ fn analyzeInlineBody(
|
||||||
fn irLogicalOp(
|
fn irLogicalOp(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
parent_block: *Block,
|
||||||
inst: Ir.Inst.Index,
|
inst: Ir.Inst.Index,
|
||||||
is_logical_or: bool,
|
is_logical_or: bool,
|
||||||
) InnerError!ValueInfo {
|
) InnerError!ValueInfo {
|
||||||
|
|
@ -535,7 +545,14 @@ fn irLogicalOp(
|
||||||
const value = ip.getOrPutBool(false);
|
const value = ip.getOrPutBool(false);
|
||||||
return .{ .value = value };
|
return .{ .value = value };
|
||||||
}
|
}
|
||||||
return try sema.analyzeInlineBody(builder, body);
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = parent_block,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
|
||||||
|
return sema.analyzeInlineBody(builder, &block, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
const else_label = try builder.addLabel();
|
const else_label = try builder.addLabel();
|
||||||
|
|
@ -543,7 +560,13 @@ fn irLogicalOp(
|
||||||
try builder.addFixup(if (is_logical_or) .jmp_t else .jmp_f, else_label);
|
try builder.addFixup(if (is_logical_or) .jmp_t else .jmp_f, else_label);
|
||||||
try builder.addByteOp(.pop);
|
try builder.addByteOp(.pop);
|
||||||
|
|
||||||
const rhs = try sema.analyzeInlineBody(builder, body);
|
var block: Block = .{
|
||||||
|
.parent_block = parent_block,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
|
||||||
|
const rhs = try sema.analyzeInlineBody(builder, &block, body);
|
||||||
try builder.ensureLoad(rhs);
|
try builder.ensureLoad(rhs);
|
||||||
builder.setLabel(else_label);
|
builder.setLabel(else_label);
|
||||||
return .none;
|
return .none;
|
||||||
|
|
@ -552,6 +575,7 @@ fn irLogicalOp(
|
||||||
fn irDeclRef(
|
fn irDeclRef(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
inst: Ir.Inst.Index,
|
inst: Ir.Inst.Index,
|
||||||
inline_block: bool,
|
inline_block: bool,
|
||||||
) InnerError!ValueInfo {
|
) InnerError!ValueInfo {
|
||||||
|
|
@ -562,7 +586,7 @@ fn irDeclRef(
|
||||||
if (inline_block) {
|
if (inline_block) {
|
||||||
switch (ident.tag) {
|
switch (ident.tag) {
|
||||||
.knot, .stitch, .function => unreachable,
|
.knot, .stitch, .function => unreachable,
|
||||||
.var_const => return sema.resolveGlobalDecl(builder, ip_index, src_loc),
|
.var_const => return sema.resolveGlobalDecl(builder, block, ip_index, src_loc),
|
||||||
.var_mut => return sema.fail(
|
.var_mut => return sema.fail(
|
||||||
src_loc,
|
src_loc,
|
||||||
"global variable assignments cannot refer to other variables",
|
"global variable assignments cannot refer to other variables",
|
||||||
|
|
@ -621,7 +645,12 @@ fn irLoad(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!ValueI
|
||||||
return .stack;
|
return .stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irCondBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
fn irCondBr(
|
||||||
|
sema: *Sema,
|
||||||
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
|
inst: Ir.Inst.Index,
|
||||||
|
) InnerError!ValueInfo {
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.CondBr, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.CondBr, data.extra_index);
|
||||||
const then_body = sema.ir.bodySlice(extra.end, extra.data.then_body_len);
|
const then_body = sema.ir.bodySlice(extra.end, extra.data.then_body_len);
|
||||||
|
|
@ -633,36 +662,44 @@ fn irCondBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!Valu
|
||||||
|
|
||||||
try builder.addFixup(.jmp_f, else_label);
|
try builder.addFixup(.jmp_f, else_label);
|
||||||
try builder.addByteOp(.pop);
|
try builder.addByteOp(.pop);
|
||||||
_ = try analyzeBodyInner(sema, builder, then_body, false);
|
|
||||||
|
_ = try analyzeBodyInner(sema, builder, block, then_body, false);
|
||||||
|
|
||||||
try builder.addFixup(.jmp, end_label);
|
try builder.addFixup(.jmp, end_label);
|
||||||
builder.setLabel(else_label);
|
builder.setLabel(else_label);
|
||||||
try builder.addByteOp(.pop);
|
try builder.addByteOp(.pop);
|
||||||
|
|
||||||
_ = try analyzeBodyInner(sema, builder, else_body, false);
|
_ = try analyzeBodyInner(sema, builder, block, else_body, false);
|
||||||
builder.setLabel(end_label);
|
builder.setLabel(end_label);
|
||||||
return .none;
|
return .none;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irBreak(sema: *Sema, inst: Ir.Inst.Index) InnerError!void {
|
fn irBlock(
|
||||||
_ = sema;
|
sema: *Sema,
|
||||||
_ = inst;
|
builder: *Builder,
|
||||||
}
|
parent_block: *Block,
|
||||||
|
inst: Ir.Inst.Index,
|
||||||
fn irBreakInline(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
) InnerError!void {
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.bin;
|
|
||||||
const rvalue_inst = sema.resolveInst(data.rhs);
|
|
||||||
return rvalue_inst;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn irBlock(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.Block, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.Block, data.extra_index);
|
||||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = parent_block,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||||
|
builder.setLabel(block.exit_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
fn irSwitchBlock(
|
||||||
|
sema: *Sema,
|
||||||
|
builder: *Builder,
|
||||||
|
parent_block: *Block,
|
||||||
|
inst: Ir.Inst.Index,
|
||||||
|
) InnerError!void {
|
||||||
const gpa = sema.gpa;
|
const gpa = sema.gpa;
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.SwitchBr, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.SwitchBr, data.extra_index);
|
||||||
|
|
@ -675,7 +712,12 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
||||||
const condition = sema.resolveInst(extra.data.operand);
|
const condition = sema.resolveInst(extra.data.operand);
|
||||||
if (condition != .none) try builder.ensureLoad(condition);
|
if (condition != .none) try builder.ensureLoad(condition);
|
||||||
|
|
||||||
const exit_label = try builder.addLabel();
|
var switch_block: Block = .{
|
||||||
|
.parent_block = parent_block,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
|
||||||
const cmp_var = builder.addStackSlot();
|
const cmp_var = builder.addStackSlot();
|
||||||
try builder.addConstOp(.store, cmp_var);
|
try builder.addConstOp(.store, cmp_var);
|
||||||
|
|
||||||
|
|
@ -701,8 +743,8 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
||||||
|
|
||||||
builder.setLabel(label_index);
|
builder.setLabel(label_index);
|
||||||
try builder.addByteOp(.pop);
|
try builder.addByteOp(.pop);
|
||||||
_ = try analyzeBodyInner(sema, builder, case_body, false);
|
_ = try analyzeBodyInner(sema, builder, &switch_block, case_body, false);
|
||||||
try builder.addFixup(.jmp, exit_label);
|
try builder.addFixup(.jmp, switch_block.exit_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
const else_body = sema.ir.bodySlice(
|
const else_body = sema.ir.bodySlice(
|
||||||
|
|
@ -711,8 +753,34 @@ fn irSwitchBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
||||||
);
|
);
|
||||||
|
|
||||||
builder.setLabel(else_label);
|
builder.setLabel(else_label);
|
||||||
_ = try analyzeBodyInner(sema, builder, else_body, false);
|
_ = try analyzeBodyInner(sema, builder, &switch_block, else_body, false);
|
||||||
builder.setLabel(exit_label);
|
builder.setLabel(switch_block.exit_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irBreak(
|
||||||
|
sema: *Sema,
|
||||||
|
builder: *Builder,
|
||||||
|
parent_block: *Block,
|
||||||
|
inst: Ir.Inst.Index,
|
||||||
|
) InnerError!void {
|
||||||
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
|
const extra = sema.ir.extraData(Ir.Inst.Break, data.extra_index).data;
|
||||||
|
const target = extra.block_inst;
|
||||||
|
|
||||||
|
var current_block: ?*Block = parent_block;
|
||||||
|
while (current_block) |block| : (current_block = block.parent_block) {
|
||||||
|
if (block.block_inst == target) {
|
||||||
|
try builder.addFixup(.jmp, block.exit_label);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return error.InvalidBreakTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irBreakInline(sema: *Sema, inst: Ir.Inst.Index) InnerError!ValueInfo {
|
||||||
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.bin;
|
||||||
|
const rvalue_inst = sema.resolveInst(data.rhs);
|
||||||
|
return rvalue_inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irContentPush(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
fn irContentPush(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
||||||
|
|
@ -723,7 +791,12 @@ fn irContentPush(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError
|
||||||
try builder.addByteOp(.stream_push);
|
try builder.addByteOp(.stream_push);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!void {
|
fn irChoiceBr(
|
||||||
|
sema: *Sema,
|
||||||
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
|
inst: Ir.Inst.Index,
|
||||||
|
) InnerError!void {
|
||||||
const gpa = sema.gpa;
|
const gpa = sema.gpa;
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const choice_extra = sema.ir.extraData(Ir.Inst.ChoiceBr, data.extra_index);
|
const choice_extra = sema.ir.extraData(Ir.Inst.ChoiceBr, data.extra_index);
|
||||||
|
|
@ -748,8 +821,8 @@ fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
||||||
branch_labels.appendAssumeCapacity(case_label);
|
branch_labels.appendAssumeCapacity(case_label);
|
||||||
|
|
||||||
try builder.addByteOp(.stream_mark);
|
try builder.addByteOp(.stream_mark);
|
||||||
_ = try analyzeBodyInner(sema, builder, lhs_slice, false);
|
_ = try analyzeBodyInner(sema, builder, block, lhs_slice, false);
|
||||||
_ = try analyzeBodyInner(sema, builder, mhs_slice, false);
|
_ = try analyzeBodyInner(sema, builder, block, mhs_slice, false);
|
||||||
try builder.addFixupAbsolute(.br_push, case_label);
|
try builder.addFixupAbsolute(.br_push, case_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -779,10 +852,10 @@ fn irChoiceBr(sema: *Sema, builder: *Builder, inst: Ir.Inst.Index) InnerError!vo
|
||||||
|
|
||||||
builder.setLabel(label);
|
builder.setLabel(label);
|
||||||
|
|
||||||
_ = try analyzeBodyInner(sema, builder, lhs_slice, false);
|
_ = try analyzeBodyInner(sema, builder, block, lhs_slice, false);
|
||||||
_ = try analyzeBodyInner(sema, builder, rhs_slice, false);
|
_ = try analyzeBodyInner(sema, builder, block, rhs_slice, false);
|
||||||
try builder.addByteOp(.stream_line);
|
try builder.addByteOp(.stream_line);
|
||||||
_ = try analyzeBodyInner(sema, builder, body_slice, false);
|
_ = try analyzeBodyInner(sema, builder, block, body_slice, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -804,6 +877,7 @@ fn irImplicitRet(_: *Sema, builder: *Builder, _: Ir.Inst.Index) InnerError!void
|
||||||
},
|
},
|
||||||
.function => {
|
.function => {
|
||||||
try builder.addByteOp(.stream_glue);
|
try builder.addByteOp(.stream_glue);
|
||||||
|
try builder.addByteOp(.nil);
|
||||||
try builder.addByteOp(.ret);
|
try builder.addByteOp(.ret);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -812,6 +886,7 @@ fn irImplicitRet(_: *Sema, builder: *Builder, _: Ir.Inst.Index) InnerError!void
|
||||||
fn irCall(
|
fn irCall(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
inst: Ir.Inst.Index,
|
inst: Ir.Inst.Index,
|
||||||
comptime kind: enum { direct, field },
|
comptime kind: enum { direct, field },
|
||||||
) !ValueInfo {
|
) !ValueInfo {
|
||||||
|
|
@ -853,7 +928,7 @@ fn irCall(
|
||||||
const arg_end = sema.ir.extra[extra.end + i];
|
const arg_end = sema.ir.extra[extra.end + i];
|
||||||
defer arg_start = arg_end;
|
defer arg_start = arg_end;
|
||||||
const arg_body = body[arg_start..arg_end];
|
const arg_body = body[arg_start..arg_end];
|
||||||
const arg_value = try sema.analyzeInlineBody(builder, @ptrCast(arg_body));
|
const arg_value = try sema.analyzeInlineBody(builder, block, @ptrCast(arg_body));
|
||||||
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
||||||
}
|
}
|
||||||
try builder.addConstOp(.call, @intCast(args_len));
|
try builder.addConstOp(.call, @intCast(args_len));
|
||||||
|
|
@ -863,6 +938,7 @@ fn irCall(
|
||||||
fn irDivert(
|
fn irDivert(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
inst: Ir.Inst.Index,
|
inst: Ir.Inst.Index,
|
||||||
comptime kind: enum { direct, field },
|
comptime kind: enum { direct, field },
|
||||||
) !void {
|
) !void {
|
||||||
|
|
@ -874,6 +950,7 @@ fn irDivert(
|
||||||
const extra = sema.ir.extraData(ExtraType, data.extra_index);
|
const extra = sema.ir.extraData(ExtraType, data.extra_index);
|
||||||
const body = sema.ir.extra[extra.end..];
|
const body = sema.ir.extra[extra.end..];
|
||||||
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
|
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.direct => {
|
.direct => {
|
||||||
const callee = sema.resolveInst(extra.data.callee);
|
const callee = sema.resolveInst(extra.data.callee);
|
||||||
|
|
@ -904,7 +981,7 @@ fn irDivert(
|
||||||
const arg_end = sema.ir.extra[extra.end + i];
|
const arg_end = sema.ir.extra[extra.end + i];
|
||||||
defer arg_start = arg_end;
|
defer arg_start = arg_end;
|
||||||
const arg_body = body[arg_start..arg_end];
|
const arg_body = body[arg_start..arg_end];
|
||||||
const arg_value = try analyzeBodyInner(sema, builder, @ptrCast(arg_body), false);
|
const arg_value = try analyzeBodyInner(sema, builder, block, @ptrCast(arg_body), false);
|
||||||
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
if (arg_value != .none) try builder.ensureLoad(arg_value);
|
||||||
}
|
}
|
||||||
try builder.addConstOp(.divert, @intCast(args_len));
|
try builder.addConstOp(.divert, @intCast(args_len));
|
||||||
|
|
@ -987,6 +1064,7 @@ fn analyzeDivertTarget(
|
||||||
fn analyzeBodyInner(
|
fn analyzeBodyInner(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
body: []const Ir.Inst.Index,
|
body: []const Ir.Inst.Index,
|
||||||
inline_block: bool,
|
inline_block: bool,
|
||||||
) InnerError!ValueInfo {
|
) InnerError!ValueInfo {
|
||||||
|
|
@ -1016,15 +1094,15 @@ fn analyzeBodyInner(
|
||||||
.mod => try irBinaryOp(sema, builder, inst, .mod),
|
.mod => try irBinaryOp(sema, builder, inst, .mod),
|
||||||
.neg => try irUnaryOp(sema, builder, inst, .neg),
|
.neg => try irUnaryOp(sema, builder, inst, .neg),
|
||||||
.not => try irUnaryOp(sema, builder, inst, .not),
|
.not => try irUnaryOp(sema, builder, inst, .not),
|
||||||
.bool_br_and => try irLogicalOp(sema, builder, inst, false),
|
.bool_br_and => try irLogicalOp(sema, builder, block, inst, false),
|
||||||
.bool_br_or => try irLogicalOp(sema, builder, inst, true),
|
.bool_br_or => try irLogicalOp(sema, builder, block, inst, true),
|
||||||
.cmp_eq => try irBinaryOp(sema, builder, inst, .cmp_eq),
|
.cmp_eq => try irBinaryOp(sema, builder, inst, .cmp_eq),
|
||||||
.cmp_neq => try irBinaryOp(sema, builder, inst, .cmp_neq),
|
.cmp_neq => try irBinaryOp(sema, builder, inst, .cmp_neq),
|
||||||
.cmp_lt => try irBinaryOp(sema, builder, inst, .cmp_lt),
|
.cmp_lt => try irBinaryOp(sema, builder, inst, .cmp_lt),
|
||||||
.cmp_lte => try irBinaryOp(sema, builder, inst, .cmp_lte),
|
.cmp_lte => try irBinaryOp(sema, builder, inst, .cmp_lte),
|
||||||
.cmp_gt => try irBinaryOp(sema, builder, inst, .cmp_gt),
|
.cmp_gt => try irBinaryOp(sema, builder, inst, .cmp_gt),
|
||||||
.cmp_gte => try irBinaryOp(sema, builder, inst, .cmp_gte),
|
.cmp_gte => try irBinaryOp(sema, builder, inst, .cmp_gte),
|
||||||
.decl_ref => try irDeclRef(sema, builder, inst, inline_block),
|
.decl_ref => try irDeclRef(sema, builder, block, inst, inline_block),
|
||||||
.ret => {
|
.ret => {
|
||||||
try irRet(sema, builder, inst);
|
try irRet(sema, builder, inst);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -1033,9 +1111,9 @@ fn analyzeBodyInner(
|
||||||
try irImplicitRet(sema, builder, inst);
|
try irImplicitRet(sema, builder, inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.condbr => try irCondBr(sema, builder, inst),
|
.condbr => try irCondBr(sema, builder, block, inst),
|
||||||
.@"break" => {
|
.@"break" => {
|
||||||
try irBreak(sema, inst);
|
try irBreak(sema, builder, block, inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.break_inline => {
|
.break_inline => {
|
||||||
|
|
@ -1043,7 +1121,7 @@ fn analyzeBodyInner(
|
||||||
return error.ComptimeBreak;
|
return error.ComptimeBreak;
|
||||||
},
|
},
|
||||||
.block => {
|
.block => {
|
||||||
try irBlock(sema, builder, inst);
|
try irBlock(sema, builder, block, inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.content_push => {
|
.content_push => {
|
||||||
|
|
@ -1059,21 +1137,21 @@ fn analyzeBodyInner(
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.choice_br => {
|
.choice_br => {
|
||||||
try irChoiceBr(sema, builder, inst);
|
try irChoiceBr(sema, builder, block, inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.switch_br => {
|
.switch_br => {
|
||||||
try irSwitchBr(sema, builder, inst);
|
try irSwitchBlock(sema, builder, block, inst);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.call => try irCall(sema, builder, inst, .direct),
|
.call => try irCall(sema, builder, block, inst, .direct),
|
||||||
.field_call => try irCall(sema, builder, inst, .field),
|
.field_call => try irCall(sema, builder, block, inst, .field),
|
||||||
.divert => {
|
.divert => {
|
||||||
try irDivert(sema, builder, inst, .direct);
|
try irDivert(sema, builder, block, inst, .direct);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.field_divert => {
|
.field_divert => {
|
||||||
try irDivert(sema, builder, inst, .field);
|
try irDivert(sema, builder, block, inst, .field);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
.field_ptr => try irFieldPtr(sema, builder, inst),
|
.field_ptr => try irFieldPtr(sema, builder, inst),
|
||||||
|
|
@ -1095,7 +1173,13 @@ pub fn analyzeStitch(
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.Stitch, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.Stitch, data.extra_index);
|
||||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = null,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: No diverts allowed.
|
// TODO: No diverts allowed.
|
||||||
|
|
@ -1107,7 +1191,13 @@ pub fn analyzeFunction(
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.Function, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.Function, data.extra_index);
|
||||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = null,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: No return allowed.
|
// TODO: No return allowed.
|
||||||
|
|
@ -1119,7 +1209,13 @@ pub fn analyzeKnot(
|
||||||
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
|
||||||
const extra = sema.ir.extraData(Ir.Inst.Knot, data.extra_index);
|
const extra = sema.ir.extraData(Ir.Inst.Knot, data.extra_index);
|
||||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||||
_ = try analyzeBodyInner(sema, builder, body, false);
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = null,
|
||||||
|
.exit_label = try builder.addLabel(),
|
||||||
|
.block_inst = inst,
|
||||||
|
};
|
||||||
|
_ = try analyzeBodyInner(sema, builder, &block, body, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn analyzeNestedDecl(
|
fn analyzeNestedDecl(
|
||||||
|
|
@ -1255,6 +1351,7 @@ fn scanTopLevelDecl(
|
||||||
fn resolveGlobalDecl(
|
fn resolveGlobalDecl(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
builder: *Builder,
|
builder: *Builder,
|
||||||
|
block: *Block,
|
||||||
decl_name: InternPool.Index,
|
decl_name: InternPool.Index,
|
||||||
src_loc: SrcLoc,
|
src_loc: SrcLoc,
|
||||||
) InnerError!ValueInfo {
|
) InnerError!ValueInfo {
|
||||||
|
|
@ -1266,7 +1363,7 @@ fn resolveGlobalDecl(
|
||||||
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
|
||||||
|
|
||||||
entry.resolution = .in_progress;
|
entry.resolution = .in_progress;
|
||||||
const val = try sema.analyzeInlineBody(builder, body);
|
const val = try sema.analyzeInlineBody(builder, block, body);
|
||||||
entry.resolution = .{ .resolved = val };
|
entry.resolution = .{ .resolved = val };
|
||||||
return val;
|
return val;
|
||||||
},
|
},
|
||||||
|
|
@ -1301,11 +1398,18 @@ pub fn scanTopLevelDecls(
|
||||||
while (iter.next()) |entry| {
|
while (iter.next()) |entry| {
|
||||||
const key = entry.key_ptr.*;
|
const key = entry.key_ptr.*;
|
||||||
const value = entry.value_ptr.*;
|
const value = entry.value_ptr.*;
|
||||||
|
|
||||||
|
var block: Block = .{
|
||||||
|
.parent_block = null,
|
||||||
|
.block_inst = @enumFromInt(0),
|
||||||
|
.exit_label = 0,
|
||||||
|
};
|
||||||
|
|
||||||
switch (value.tag) {
|
switch (value.tag) {
|
||||||
.var_mut, .var_const => {
|
.var_mut, .var_const => {
|
||||||
// TODO: Set a proper source offset for this.
|
// TODO: Set a proper source offset for this.
|
||||||
const src_loc: SrcLoc = .{ .src_offset = 0 };
|
const src_loc: SrcLoc = .{ .src_offset = 0 };
|
||||||
const result = try sema.resolveGlobalDecl(&builder, key, src_loc);
|
const result = try sema.resolveGlobalDecl(&builder, &block, key, src_loc);
|
||||||
const initial_value = sema.resolveValue(result).?;
|
const initial_value = sema.resolveValue(result).?;
|
||||||
try sema.module.globals.append(gpa, .{
|
try sema.module.globals.append(gpa, .{
|
||||||
.key = key,
|
.key = key,
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ pub const Opcode = enum(u8) {
|
||||||
exit,
|
exit,
|
||||||
done,
|
done,
|
||||||
ret,
|
ret,
|
||||||
|
nil,
|
||||||
/// Pop a value off the stack, discarding it.
|
/// Pop a value off the stack, discarding it.
|
||||||
pop,
|
pop,
|
||||||
/// Push an object representing the boolean value of "true" to the stack.
|
/// Push an object representing the boolean value of "true" to the stack.
|
||||||
|
|
@ -105,8 +106,6 @@ pub const CallFrame = struct {
|
||||||
/// Instruction pointer.
|
/// Instruction pointer.
|
||||||
ip: usize,
|
ip: usize,
|
||||||
bp: usize,
|
bp: usize,
|
||||||
/// Output stream base.
|
|
||||||
output_base: usize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
|
|
@ -450,10 +449,9 @@ fn call(vm: *Story, knot: *Object.Knot, args_count: u8) !void {
|
||||||
.callee = knot,
|
.callee = knot,
|
||||||
.ip = 0,
|
.ip = 0,
|
||||||
.bp = vm.stack_top - args_count - 1,
|
.bp = vm.stack_top - args_count - 1,
|
||||||
.output_base = vm.output_buffer.items.len,
|
|
||||||
};
|
};
|
||||||
vm.call_stack_top += 1;
|
vm.call_stack_top += 1;
|
||||||
vm.stack_top += knot.code.locals_count;
|
vm.stack_top += knot.code.stack_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divertValue(vm: *Story, value: Value, args_count: u8) !void {
|
fn divertValue(vm: *Story, value: Value, args_count: u8) !void {
|
||||||
|
|
@ -477,7 +475,6 @@ fn divert(vm: *Story, knot: *Object.Knot, args_count: u8) !void {
|
||||||
.callee = knot,
|
.callee = knot,
|
||||||
.ip = 0,
|
.ip = 0,
|
||||||
.bp = vm.stack_top - args_count - 1,
|
.bp = vm.stack_top - args_count - 1,
|
||||||
.output_base = vm.output_buffer.items.len,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.stack_top += knot.code.locals_count;
|
vm.stack_top += knot.code.locals_count;
|
||||||
|
|
@ -510,32 +507,18 @@ fn step(vm: *Story) !StepSignal {
|
||||||
switch (code[frame.ip]) {
|
switch (code[frame.ip]) {
|
||||||
.exit => return .exit,
|
.exit => return .exit,
|
||||||
.done => return .done,
|
.done => return .done,
|
||||||
|
.nil => {
|
||||||
|
try pushStack(vm, .nil);
|
||||||
|
frame.ip += 1;
|
||||||
|
},
|
||||||
.ret => {
|
.ret => {
|
||||||
if (vm.call_stack_top == 0) return error.UnexpectedReturn;
|
if (vm.call_stack_top == 0) return error.UnexpectedReturn;
|
||||||
vm.call_stack_top -= 1;
|
vm.call_stack_top -= 1;
|
||||||
|
|
||||||
const resolved_stream: ?Value = if (vm.output_buffer.items.len > frame.output_base) blk: {
|
const value = popStack(vm).?;
|
||||||
const frame_output = vm.output_buffer.items[frame.output_base..];
|
|
||||||
defer vm.output_buffer.shrinkRetainingCapacity(frame.output_base);
|
|
||||||
|
|
||||||
const str_bytes = try resolveOutputStream(vm, arena, frame_output);
|
|
||||||
const str_object = try Object.String.create(vm, .{ .bytes = str_bytes });
|
|
||||||
break :blk .{ .object = &str_object.base };
|
|
||||||
} else blk: {
|
|
||||||
break :blk null;
|
|
||||||
};
|
|
||||||
const return_value = if (resolved_stream) |stream| blk: {
|
|
||||||
if (frame.bp + frame.callee.code.stack_size + 1 < vm.stack_top) {
|
|
||||||
try vm.output_buffer.append(gpa, .{ .value = stream });
|
|
||||||
break :blk popStack(vm).?;
|
|
||||||
}
|
|
||||||
break :blk stream;
|
|
||||||
} else if (frame.bp + frame.callee.code.stack_size + 1 < vm.stack_top) blk: {
|
|
||||||
break :blk popStack(vm).?;
|
|
||||||
} else .nil;
|
|
||||||
|
|
||||||
vm.stack_top = frame.bp;
|
vm.stack_top = frame.bp;
|
||||||
vm.stack[vm.stack_top] = return_value;
|
vm.stack[vm.stack_top] = value;
|
||||||
vm.stack_top += 1;
|
vm.stack_top += 1;
|
||||||
frame = &vm.call_stack[vm.call_stack_top - 1];
|
frame = &vm.call_stack[vm.call_stack_top - 1];
|
||||||
},
|
},
|
||||||
|
|
@ -726,7 +709,10 @@ fn step(vm: *Story) !StepSignal {
|
||||||
.stream_push => {
|
.stream_push => {
|
||||||
// TODO: Make this more strict.
|
// TODO: Make this more strict.
|
||||||
if (popStack(vm)) |value| {
|
if (popStack(vm)) |value| {
|
||||||
try vm.output_buffer.append(gpa, .{ .value = value });
|
switch (value) {
|
||||||
|
.nil => {},
|
||||||
|
else => try vm.output_buffer.append(gpa, .{ .value = value }),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
frame.ip += 1;
|
frame.ip += 1;
|
||||||
},
|
},
|
||||||
|
|
@ -780,8 +766,8 @@ fn resolveOutputStream(
|
||||||
gpa: std.mem.Allocator,
|
gpa: std.mem.Allocator,
|
||||||
stream: []const OutputCommand,
|
stream: []const OutputCommand,
|
||||||
) ![]const u8 {
|
) ![]const u8 {
|
||||||
var glue_active = false;
|
|
||||||
var pending_newline = false;
|
var pending_newline = false;
|
||||||
|
var pending_glue = false;
|
||||||
var result: std.ArrayListUnmanaged(u8) = .empty;
|
var result: std.ArrayListUnmanaged(u8) = .empty;
|
||||||
defer result.deinit(gpa);
|
defer result.deinit(gpa);
|
||||||
|
|
||||||
|
|
@ -792,16 +778,21 @@ fn resolveOutputStream(
|
||||||
try result.append(gpa, '\n');
|
try result.append(gpa, '\n');
|
||||||
pending_newline = false;
|
pending_newline = false;
|
||||||
}
|
}
|
||||||
glue_active = false;
|
pending_glue = false;
|
||||||
const str = try Object.String.fromValue(story, value);
|
switch (value) {
|
||||||
try result.appendSlice(gpa, str.toSlice());
|
.nil => {},
|
||||||
|
else => {
|
||||||
|
const str = try Object.String.fromValue(story, value);
|
||||||
|
try result.appendSlice(gpa, str.toSlice());
|
||||||
|
},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.line => {
|
.line => {
|
||||||
if (!glue_active) pending_newline = true;
|
if (!pending_glue) pending_newline = true;
|
||||||
},
|
},
|
||||||
.glue => {
|
.glue => {
|
||||||
pending_newline = false;
|
pending_newline = false;
|
||||||
glue_active = true;
|
pending_glue = true;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ pub fn dumpInst(
|
||||||
.exit => return self.dumpSimpleInst(w, offset, op),
|
.exit => return self.dumpSimpleInst(w, offset, op),
|
||||||
.done => return self.dumpSimpleInst(w, offset, op),
|
.done => return self.dumpSimpleInst(w, offset, op),
|
||||||
.ret => return self.dumpSimpleInst(w, offset, op),
|
.ret => return self.dumpSimpleInst(w, offset, op),
|
||||||
|
.nil => return self.dumpSimpleInst(w, offset, op),
|
||||||
.pop => return self.dumpSimpleInst(w, offset, op),
|
.pop => return self.dumpSimpleInst(w, offset, op),
|
||||||
.true => return self.dumpSimpleInst(w, offset, op),
|
.true => return self.dumpSimpleInst(w, offset, op),
|
||||||
.false => return self.dumpSimpleInst(w, offset, op),
|
.false => return self.dumpSimpleInst(w, offset, op),
|
||||||
|
|
@ -359,10 +360,9 @@ pub fn trace(vm: *Story, writer: *std.Io.Writer, frame: *Story.CallFrame) !void
|
||||||
}
|
}
|
||||||
|
|
||||||
try writer.writeAll("]\n");
|
try writer.writeAll("]\n");
|
||||||
|
try writer.print("\tOutput => values=[", .{});
|
||||||
|
|
||||||
try writer.print("\tOutput => offset_base={d}, values=[", .{frame.output_base});
|
const output_window = vm.output_buffer.items[0..];
|
||||||
|
|
||||||
const output_window = vm.output_buffer.items[frame.output_base..];
|
|
||||||
for (output_window, 0..) |slot, i| {
|
for (output_window, 0..) |slot, i| {
|
||||||
if (i > 0) try writer.writeAll(", ");
|
if (i > 0) try writer.writeAll(", ");
|
||||||
try writer.print("{any}", .{slot});
|
try writer.print("{any}", .{slot});
|
||||||
|
|
|
||||||
|
|
@ -119,10 +119,22 @@ test "fixture - I042 (Weave options)" {
|
||||||
try testRuntimeFixture("I042");
|
try testRuntimeFixture("I042");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - I044 (#)" {
|
||||||
|
try testRuntimeFixture("I044");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "fixture - I045 (#)" {
|
||||||
|
try testRuntimeFixture("I045");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - I046 (Left right glue matching)" {
|
test "fixture - I046 (Left right glue matching)" {
|
||||||
try testRuntimeFixture("I046");
|
try testRuntimeFixture("I046");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - I047 (#)" {
|
||||||
|
try testRuntimeFixture("I047");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - I048 (Simple glue)" {
|
test "fixture - I048 (Simple glue)" {
|
||||||
try testRuntimeFixture("I048");
|
try testRuntimeFixture("I048");
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +180,10 @@ test "fixture - I087 (Non text in choice inner content)" {
|
||||||
try testRuntimeFixture("I087");
|
try testRuntimeFixture("I087");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - I094 (# content)" {
|
||||||
|
try testRuntimeFixture("I094");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - I095 (Multiline logic with glue)" {
|
test "fixture - I095 (Multiline logic with glue)" {
|
||||||
try testRuntimeFixture("I095");
|
try testRuntimeFixture("I095");
|
||||||
}
|
}
|
||||||
|
|
@ -176,6 +192,22 @@ test "fixture - I097 (Logic lines with newlines)" {
|
||||||
try testRuntimeFixture("I097");
|
try testRuntimeFixture("I097");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - I112 (#)" {
|
||||||
|
try testRuntimeFixture("I112");
|
||||||
|
}
|
||||||
|
|
||||||
|
//test "fixture - I113 (#)" {
|
||||||
|
// try testRuntimeFixture("I113");
|
||||||
|
//}
|
||||||
|
|
||||||
|
test "fixture - I115 (#)" {
|
||||||
|
try testRuntimeFixture("I115");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "fixture - I116 (#)" {
|
||||||
|
try testRuntimeFixture("I116");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - I117 (Factorial recursive)" {
|
test "fixture - I117 (Factorial recursive)" {
|
||||||
try testRuntimeFixture("I117");
|
try testRuntimeFixture("I117");
|
||||||
}
|
}
|
||||||
|
|
@ -196,6 +228,10 @@ test "fixture - I124 (Evaluating ink functions from game 2)" {
|
||||||
try testRuntimeFixture("I124");
|
try testRuntimeFixture("I124");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "fixture - I127 (#)" {
|
||||||
|
try testRuntimeFixture("I127");
|
||||||
|
}
|
||||||
|
|
||||||
test "fixture - I133 (Float printing precision)" {
|
test "fixture - I133 (Float printing precision)" {
|
||||||
try testRuntimeFixture("I133");
|
try testRuntimeFixture("I133");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,7 @@ pub const Module = struct {
|
||||||
try tree.render(gpa, w, .{
|
try tree.render(gpa, w, .{
|
||||||
.use_color = options.dump_use_color,
|
.use_color = options.dump_use_color,
|
||||||
});
|
});
|
||||||
|
try w.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue