fix: content inconsistencies in the vm
This commit is contained in:
parent
236acc7d60
commit
ecd6017673
6 changed files with 259 additions and 115 deletions
|
|
@ -43,6 +43,7 @@ pub const Opcode = enum(u8) {
|
|||
exit,
|
||||
done,
|
||||
ret,
|
||||
nil,
|
||||
/// Pop a value off the stack, discarding it.
|
||||
pop,
|
||||
/// Push an object representing the boolean value of "true" to the stack.
|
||||
|
|
@ -105,8 +106,6 @@ pub const CallFrame = struct {
|
|||
/// Instruction pointer.
|
||||
ip: usize,
|
||||
bp: usize,
|
||||
/// Output stream base.
|
||||
output_base: usize,
|
||||
};
|
||||
|
||||
pub const Value = union(enum) {
|
||||
|
|
@ -450,10 +449,9 @@ fn call(vm: *Story, knot: *Object.Knot, args_count: u8) !void {
|
|||
.callee = knot,
|
||||
.ip = 0,
|
||||
.bp = vm.stack_top - args_count - 1,
|
||||
.output_base = vm.output_buffer.items.len,
|
||||
};
|
||||
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 {
|
||||
|
|
@ -477,7 +475,6 @@ fn divert(vm: *Story, knot: *Object.Knot, args_count: u8) !void {
|
|||
.callee = knot,
|
||||
.ip = 0,
|
||||
.bp = vm.stack_top - args_count - 1,
|
||||
.output_base = vm.output_buffer.items.len,
|
||||
};
|
||||
|
||||
vm.stack_top += knot.code.locals_count;
|
||||
|
|
@ -510,32 +507,18 @@ fn step(vm: *Story) !StepSignal {
|
|||
switch (code[frame.ip]) {
|
||||
.exit => return .exit,
|
||||
.done => return .done,
|
||||
.nil => {
|
||||
try pushStack(vm, .nil);
|
||||
frame.ip += 1;
|
||||
},
|
||||
.ret => {
|
||||
if (vm.call_stack_top == 0) return error.UnexpectedReturn;
|
||||
vm.call_stack_top -= 1;
|
||||
|
||||
const resolved_stream: ?Value = if (vm.output_buffer.items.len > frame.output_base) blk: {
|
||||
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;
|
||||
const value = popStack(vm).?;
|
||||
|
||||
vm.stack_top = frame.bp;
|
||||
vm.stack[vm.stack_top] = return_value;
|
||||
vm.stack[vm.stack_top] = value;
|
||||
vm.stack_top += 1;
|
||||
frame = &vm.call_stack[vm.call_stack_top - 1];
|
||||
},
|
||||
|
|
@ -726,7 +709,10 @@ fn step(vm: *Story) !StepSignal {
|
|||
.stream_push => {
|
||||
// TODO: Make this more strict.
|
||||
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;
|
||||
},
|
||||
|
|
@ -780,8 +766,8 @@ fn resolveOutputStream(
|
|||
gpa: std.mem.Allocator,
|
||||
stream: []const OutputCommand,
|
||||
) ![]const u8 {
|
||||
var glue_active = false;
|
||||
var pending_newline = false;
|
||||
var pending_glue = false;
|
||||
var result: std.ArrayListUnmanaged(u8) = .empty;
|
||||
defer result.deinit(gpa);
|
||||
|
||||
|
|
@ -792,16 +778,21 @@ fn resolveOutputStream(
|
|||
try result.append(gpa, '\n');
|
||||
pending_newline = false;
|
||||
}
|
||||
glue_active = false;
|
||||
const str = try Object.String.fromValue(story, value);
|
||||
try result.appendSlice(gpa, str.toSlice());
|
||||
pending_glue = false;
|
||||
switch (value) {
|
||||
.nil => {},
|
||||
else => {
|
||||
const str = try Object.String.fromValue(story, value);
|
||||
try result.appendSlice(gpa, str.toSlice());
|
||||
},
|
||||
}
|
||||
},
|
||||
.line => {
|
||||
if (!glue_active) pending_newline = true;
|
||||
if (!pending_glue) pending_newline = true;
|
||||
},
|
||||
.glue => {
|
||||
pending_newline = false;
|
||||
glue_active = true;
|
||||
pending_glue = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue