feat: formatting strings at runtime

This commit is contained in:
Brett Broadhurst 2026-04-05 14:45:10 -06:00
parent 6924e929d8
commit d2cd7fa888
Failed to generate hash of commit
10 changed files with 211 additions and 34 deletions

View file

@ -31,6 +31,7 @@ stack: []Value = &.{},
call_stack: []CallFrame = &.{},
code_chunks: std.ArrayListUnmanaged(*Object.Code) = .empty,
/// Linked list of all tracked runtime objects.
/// We don't currently have a garbage collector, though this will necessary.
gc_objects: std.SinglyLinkedList = .{},
/// Global constants pool.
constants_pool: []const Value = &.{},
@ -110,6 +111,9 @@ pub const Opcode = enum(u8) {
br_table,
br_dispatch,
br_select_index,
string_builder,
string_append,
string_freeze,
_,
};
@ -138,6 +142,13 @@ pub const Value = union(enum) {
};
}
pub fn castObject(v: Value, comptime T: type) *T {
return switch (v) {
.object => |object| return @ptrCast(object),
else => unreachable,
};
}
pub fn isNumeric(v: Value) bool {
return v == .int or v == .float;
}
@ -230,24 +241,20 @@ pub const Value = union(enum) {
pub fn eql(lhs: Value, rhs: Value) bool {
return switch (lhs) {
.nil => rhs == .nil,
.bool => |l| switch (rhs) {
.bool => |r| l == r,
else => false,
},
.int => |l| switch (rhs) {
.int => |r| l == r,
.float => |r| @as(f64, @floatFromInt(l)) == r,
else => false,
},
.float => |l| switch (rhs) {
.int => |r| l == @as(f64, @floatFromInt(r)),
.float => |r| l == r,
else => false,
},
.object => |lobj| switch (rhs) {
.object => |robj| Object.eql(lobj, robj),
else => false,
@ -771,6 +778,32 @@ fn step(vm: *Story, variables: *VariablesState) !StepSignal {
return error.InvalidArgument;
}
},
.string_builder => {
const builder_object = try Object.StringBuilder.create(vm);
try pushStack(vm, .{ .object = &builder_object.base });
frame.ip += 1;
},
.string_append => {
if (popStack(vm)) |value| {
if (peekStack(vm, 0)) |builder| {
const string_builder = builder.castObject(Object.StringBuilder);
try string_builder.append(value);
frame.ip += 1;
continue;
}
}
return error.InvalidArgument;
},
.string_freeze => {
if (popStack(vm)) |value| {
const string_builder = value.castObject(Object.StringBuilder);
const frozen = try string_builder.freeze(vm);
try pushStack(vm, .{ .object = &frozen.base });
frame.ip += 1;
continue;
}
return error.InvalidArgument;
},
else => return error.InvalidInstruction,
}
}