refactor: make room for loading and outputting pre-compiled files

This commit is contained in:
Brett Broadhurst 2026-04-13 18:40:04 -06:00
parent 3afbbb6ec2
commit 96866ba9ae
Failed to generate hash of commit
11 changed files with 537 additions and 433 deletions

View file

@ -1,13 +1,14 @@
//! Virtual machine state for story execution.
const std = @import("std");
const tokenizer = @import("tokenizer.zig");
const assert = std.debug.assert;
const Ast = @import("Ast.zig");
const AstGen = @import("AstGen.zig");
const Module = @import("compile.zig").Module;
const Compilation = @import("compile.zig").Compilation;
pub const Loader = @import("Story/Loader.zig");
pub const Object = @import("Story/Object.zig");
const Dumper = @import("Story/Dumper.zig");
pub const Dumper = @import("Story/Dumper.zig");
const ink = @import("root.zig");
const assert = std.debug.assert;
const Story = @This();
gpa: std.mem.Allocator,
@ -42,17 +43,6 @@ internal_counter: usize = 0,
pub const default_knot_name: [:0]const u8 = "$__main__$";
pub const VariableObserver = struct {
callback: Callback,
context: Context,
pub const Callback = *const fn (Value, Context) anyerror!void;
pub const Context = struct {
ptr: *anyopaque,
};
};
pub const Opcode = enum(u8) {
/// Exit the VM normally.
exit,
@ -118,6 +108,17 @@ pub const Opcode = enum(u8) {
_,
};
pub const VariableObserver = struct {
callback: Callback,
context: Context,
pub const Callback = *const fn (Value, Context) anyerror!void;
pub const Context = struct {
ptr: *anyopaque,
};
};
pub const CallFrame = struct {
/// Pointer to the knot that initiated the call.
callee: *Object.Knot,
@ -936,70 +937,6 @@ pub fn dump(story: *Story, writer: *std.Io.Writer) !void {
return Dumper.dump(story, writer);
}
pub const LoadOptions = struct {
filename: []const u8,
error_writer: *std.Io.Writer,
dump_writer: ?*std.Io.Writer = null,
dump_use_color: bool = true,
dump_ast: bool = false,
dump_ir: bool = false,
};
pub fn fromSourceBytes(
gpa: std.mem.Allocator,
source_bytes: [:0]const u8,
options: LoadOptions,
) !Story {
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
var comp = try Module.compile(gpa, arena, .{
.source_bytes = source_bytes,
.filename = options.filename,
.dump_writer = options.dump_writer,
.dump_use_color = options.dump_use_color,
.dump_ast = options.dump_ast,
.dump_ir = options.dump_ir,
});
defer comp.deinit();
if (comp.errors.items.len > 0) {
for (comp.errors.items) |err| {
try comp.renderError(options.error_writer, err);
}
return error.LoadFailed;
}
// TODO: Make this configureable.
const stack_size = 128;
const eval_stack_ptr = try gpa.alloc(Value, stack_size);
errdefer gpa.free(eval_stack_ptr);
const call_stack_ptr = try gpa.alloc(CallFrame, stack_size);
errdefer gpa.free(call_stack_ptr);
var story: Story = .{
.gpa = gpa,
.arena = .init(gpa),
.can_advance = false,
.dump_writer = null,
.stack = eval_stack_ptr,
.call_stack = call_stack_ptr,
};
errdefer story.deinit();
try comp.setupStoryRuntime(gpa, &story);
if (story.getKnot(Story.default_knot_name)) |knot| {
try story.pushStack(.{ .object = &knot.base });
try story.divert(knot, 0);
}
return story;
}
var read_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
pub const LoadFileOptions = struct {
error_writer: *std.Io.Writer,
};
@ -1009,6 +946,7 @@ pub fn readSourceFile(
filename: []const u8,
options: LoadFileOptions,
) !Story {
var read_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
// FIXME: Temporary until 0.16.x
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
@ -1030,3 +968,53 @@ pub fn readSourceFile(
.dump_ir = false,
});
}
pub const LoadOptions = struct {
filename: [:0]const u8,
errors: *std.ArrayListUnmanaged(Compilation.Error),
stack_size: usize = 128,
};
pub fn fromSourceBytes(
gpa: std.mem.Allocator,
source_bytes: [:0]const u8,
options: LoadOptions,
) !Story {
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
defer arena_allocator.deinit();
const arena = arena_allocator.allocator();
var tree = try Ast.parse(gpa, arena, source_bytes, options.filename, 0);
defer tree.deinit(gpa);
var ir = try AstGen.generate(gpa, &tree);
defer ir.deinit(gpa);
var cu = Compilation.build(gpa, tree, ir, options.errors) catch |err| switch (err) {
else => |e| return e,
};
defer cu.deinit();
if (cu.hasCompileErrors()) {
return error.CompilationError;
}
return .fromCompilation(gpa, &cu, .{
.stack_size = options.stack_size,
});
}
pub fn fromCompilation(
gpa: std.mem.Allocator,
cu: *Compilation,
options: Loader.Options,
) !Story {
return Loader.fromCompilation(gpa, cu, options);
}
pub fn fromCachedCompilation(
gpa: std.mem.Allocator,
bytes: []const u8,
options: Loader.Options,
) !Story {
return Loader.fromCachedCompilation(gpa, bytes, options);
}