feat: infrastructure to support qualified lookups

This commit is contained in:
Brett Broadhurst 2026-03-25 03:18:24 -06:00
parent e8ad1cd5b5
commit 440ec68481
Failed to generate hash of commit
6 changed files with 1118 additions and 575 deletions

View file

@ -14,7 +14,17 @@ node: std.SinglyLinkedList.Node,
pub const Tag = enum {
number,
string,
content_path,
code,
knot,
pub fn toStr(tag: Tag) []const u8 {
return switch (tag) {
.number => "Number",
.string => "String",
.code => "Code",
.knot => "Knot",
};
}
};
pub fn destroy(obj: *Object, story: *Story) void {
@ -27,8 +37,12 @@ pub fn destroy(obj: *Object, story: *Story) void {
const typed_obj: *Object.String = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
.content_path => {
const typed_obj: *Object.ContentPath = @alignCast(@fieldParentPtr("base", obj));
.code => {
const typed_obj: *Object.Code = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
.knot => {
const typed_obj: *Object.Knot = @alignCast(@fieldParentPtr("base", obj));
typed_obj.destroy(story);
},
}
@ -190,12 +204,13 @@ pub const String = struct {
const Type = Object.String;
pub fn create(
story: *Story,
pub const Options = struct {
bytes: []const u8,
) error{OutOfMemory}!*Object.String {
};
pub fn create(story: *Story, options: Options) error{OutOfMemory}!*Object.String {
const gpa = story.allocator;
const alloc_len = @sizeOf(Type) + bytes.len + 1;
const alloc_len = @sizeOf(Type) + options.bytes.len + 1;
const raw = try gpa.alignedAlloc(u8, .of(Type), alloc_len);
const object: *Type = @ptrCast(raw);
@ -206,15 +221,15 @@ pub const String = struct {
.node = .{},
},
.hash = 0,
.length = bytes.len,
.length = options.bytes.len,
.bytes = undefined,
};
// Point bytes slice to the memory *after* the struct
const buf = raw[@sizeOf(Type)..][0 .. bytes.len + 1];
const buf = raw[@sizeOf(Type)..][0 .. options.bytes.len + 1];
object.bytes = buf.ptr;
@memcpy(buf[0..bytes.len], bytes);
buf[bytes.len] = 0;
@memcpy(buf[0..options.bytes.len], options.bytes);
buf[options.bytes.len] = 0;
story.gc_objects.prepend(&object.base.node);
return object;
@ -227,6 +242,10 @@ pub const String = struct {
gpa.free(base[0..alloc_len]);
}
pub fn toSlice(obj: *Object.String) []const u8 {
return obj.bytes[0..obj.length];
}
pub fn fromObject(story: *Story, obj: *Object) !*Object.String {
switch (obj.tag) {
.number => {
@ -237,7 +256,9 @@ pub const String = struct {
const number_bytes = try std.fmt.bufPrint(&print_buffer, "{}", .{
number_object.data.integer,
});
return .create(story, number_bytes);
return .create(story, .{
.bytes = number_bytes,
});
},
.string => return @ptrCast(obj),
else => unreachable,
@ -254,59 +275,111 @@ pub const String = struct {
@memcpy(bytes[lhs.length..], rhs.bytes[0..rhs.length]);
//ink_gc_disown(story, INK_OBJ(lhs));
//ink_gc_disown(story, INK_OBJ(rhs));
return .create(story, bytes);
return .create(story, .{
.bytes = bytes,
});
}
};
pub const ContentPath = struct {
/// Immutable object type for code chunks.
pub const Code = struct {
base: Object,
name: *Object.String,
arity: usize,
// TODO: Rename this to stack size.
locals_count: usize,
// TODO: Rename this to constant_pool.
const_pool: []u32,
bytes: []const u8,
/// Number of arguments.
args_count: u32,
/// Number of local variables.
locals_count: u32,
/// Stack size required to load.
stack_size: u32,
/// Table of global constant indexes.
constants: []const u8,
/// Raw compiled bytecode.
bytecode: []const u8,
const Type = Object.ContentPath;
pub const CreateOptions = struct {
name: *Object.String,
arity: usize,
locals_count: usize,
const_pool: []u32,
bytes: []const u8,
pub const Options = struct {
args_count: u32,
locals_count: u32,
stack_size: u32,
constants: []const u8,
code_bytes: []const u8,
};
pub fn create(story: *Story, options: CreateOptions) error{OutOfMemory}!*Object.ContentPath {
const Type = Code;
pub fn create(story: *Story, options: Options) error{OutOfMemory}!*Object.Code {
const gpa = story.allocator;
const alloc_len = @sizeOf(Type);
const raw = try gpa.alignedAlloc(u8, .of(Type), alloc_len);
const raw = try gpa.alignedAlloc(u8, .of(Type), @sizeOf(Type));
const obj: *Type = @ptrCast(raw);
obj.* = .{
.base = .{
.tag = .content_path,
.tag = .code,
.is_marked = false,
.node = .{},
},
.name = options.name,
.arity = options.arity,
.args_count = options.args_count,
.locals_count = options.locals_count,
.const_pool = options.const_pool,
.bytes = options.bytes,
.stack_size = options.stack_size,
.constants = options.constants,
.bytecode = options.code_bytes,
};
story.gc_objects.prepend(&obj.base.node);
return obj;
}
pub fn destroy(obj: *ContentPath, story: *Story) void {
pub fn destroy(obj: *Code, story: *Story) void {
const gpa = story.allocator;
gpa.free(obj.const_pool);
gpa.free(obj.bytes);
gpa.free(obj.constants);
gpa.free(obj.bytecode);
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
gpa.free(base[0..@sizeOf(Type)]);
}
};
pub const Knot = struct {
base: Object,
/// Pointer to the name of the knot.
name: *Object.String,
/// Pointer to the code object for the knot.
code: *Object.Code,
members: std.StringHashMapUnmanaged(*Object) = .empty,
pub const Options = struct {
name: []const u8,
code: *Object.Code,
};
const Type = Knot;
pub fn create(story: *Story, options: Options) error{OutOfMemory}!*Object.Knot {
const gpa = story.allocator;
const raw = try gpa.alignedAlloc(u8, .of(Type), @sizeOf(Type));
const obj: *Type = @ptrCast(raw);
obj.* = .{
.base = .{
.tag = .knot,
.is_marked = false,
.node = .{},
},
.name = try .create(story, .{
.bytes = options.name,
}),
.code = options.code,
.members = .empty,
};
story.gc_objects.prepend(&obj.base.node);
return obj;
}
pub fn destroy(obj: *Knot, story: *Story) void {
const gpa = story.allocator;
obj.members.deinit(gpa);
const alloc_len = @sizeOf(Type);
const base: [*]align(@alignOf(Type)) u8 = @ptrCast(obj);
gpa.free(base[0..alloc_len]);
}
};