|
|
@ -27,7 +27,7 @@ pub const RuntimeEnv = struct {
|
|
|
|
interned_symbols: SymbolSet,
|
|
|
|
interned_symbols: SymbolSet,
|
|
|
|
allocator: coral.io.Allocator,
|
|
|
|
allocator: coral.io.Allocator,
|
|
|
|
error_handler: ErrorHandler,
|
|
|
|
error_handler: ErrorHandler,
|
|
|
|
syscallables: RefTable,
|
|
|
|
system_bindings: RefTable,
|
|
|
|
locals: RefList,
|
|
|
|
locals: RefList,
|
|
|
|
frames: FrameStack,
|
|
|
|
frames: FrameStack,
|
|
|
|
|
|
|
|
|
|
|
@ -348,7 +348,7 @@ pub const RuntimeEnv = struct {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
.push_system => |push_system| {
|
|
|
|
.push_system => |push_system| {
|
|
|
|
if (self.env.syscallables.lookup(self.constants.values[push_system])) |syscallable| {
|
|
|
|
if (self.env.system_bindings.lookup(self.constants.values[push_system])) |syscallable| {
|
|
|
|
try self.env.locals.push_one(try self.env.acquire(syscallable));
|
|
|
|
try self.env.locals.push_one(try self.env.acquire(syscallable));
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
try self.env.locals.push_one(null);
|
|
|
|
try self.env.locals.push_one(null);
|
|
|
@ -413,12 +413,20 @@ pub const RuntimeEnv = struct {
|
|
|
|
try self.env.set(indexable, index, value);
|
|
|
|
try self.env.set(indexable, index, value);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
.object_call => {
|
|
|
|
.object_call => |object_call| {
|
|
|
|
const result = call: {
|
|
|
|
const result = call: {
|
|
|
|
const callable = try self.env.expect(try self.pop_local());
|
|
|
|
const callable = try self.env.expect(try self.pop_local());
|
|
|
|
|
|
|
|
|
|
|
|
defer self.env.discard(callable);
|
|
|
|
defer self.env.discard(callable);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try self.env.frames.push_one(.{
|
|
|
|
|
|
|
|
.name = "<lambda>",
|
|
|
|
|
|
|
|
.arg_count = object_call,
|
|
|
|
|
|
|
|
.locals_top = self.env.locals.values.len,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer coral.debug.assert(self.env.frames.pop() != null);
|
|
|
|
|
|
|
|
|
|
|
|
break: call try switch (callable.object().payload) {
|
|
|
|
break: call try switch (callable.object().payload) {
|
|
|
|
.dynamic => |dynamic| dynamic.typeinfo().call(.{
|
|
|
|
.dynamic => |dynamic| dynamic.typeinfo().call(.{
|
|
|
|
.userdata = dynamic.userdata(),
|
|
|
|
.userdata = dynamic.userdata(),
|
|
|
@ -429,6 +437,12 @@ pub const RuntimeEnv = struct {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (0 .. object_call) |_| {
|
|
|
|
|
|
|
|
if (try self.pop_local()) |popped_arg| {
|
|
|
|
|
|
|
|
self.env.discard(popped_arg);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
errdefer {
|
|
|
|
errdefer {
|
|
|
|
if (result) |ref| {
|
|
|
|
if (result) |ref| {
|
|
|
|
self.env.discard(ref);
|
|
|
|
self.env.discard(ref);
|
|
|
@ -901,8 +915,19 @@ pub const RuntimeEnv = struct {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn bind_syscaller(_: *RuntimeEnv, comptime _: []const coral.io.Byte, _: Caller) RuntimeError!void {
|
|
|
|
pub fn bind_system(self: *RuntimeEnv, name: []const coral.io.Byte, value: *const RuntimeRef) RuntimeError!void {
|
|
|
|
|
|
|
|
const name_symbol = try self.new_symbol(name);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
errdefer self.discard(name_symbol);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const acquired_value = try self.acquire(value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
errdefer self.discard(acquired_value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (try self.system_bindings.replace(name_symbol, acquired_value)) |replaced| {
|
|
|
|
|
|
|
|
self.discard(replaced.key);
|
|
|
|
|
|
|
|
self.discard(replaced.value);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn call(self: *RuntimeEnv, callable: *RuntimeRef, args: []const *RuntimeRef) RuntimeError!?*RuntimeRef {
|
|
|
|
pub fn call(self: *RuntimeEnv, callable: *RuntimeRef, args: []const *RuntimeRef) RuntimeError!?*RuntimeRef {
|
|
|
@ -1006,16 +1031,17 @@ pub const RuntimeEnv = struct {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var iterable = self.syscallables.as_iterable();
|
|
|
|
var iterable = self.system_bindings.as_iterable();
|
|
|
|
|
|
|
|
|
|
|
|
while (iterable.next()) |entry| {
|
|
|
|
while (iterable.next()) |entry| {
|
|
|
|
|
|
|
|
self.discard(entry.key);
|
|
|
|
self.discard(entry.value);
|
|
|
|
self.discard(entry.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
self.frames.free();
|
|
|
|
self.frames.free();
|
|
|
|
self.locals.free();
|
|
|
|
self.locals.free();
|
|
|
|
self.syscallables.free();
|
|
|
|
self.system_bindings.free();
|
|
|
|
self.interned_symbols.free();
|
|
|
|
self.interned_symbols.free();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1042,7 +1068,7 @@ pub const RuntimeEnv = struct {
|
|
|
|
return RuntimeEnv{
|
|
|
|
return RuntimeEnv{
|
|
|
|
.locals = RefList.make(allocator),
|
|
|
|
.locals = RefList.make(allocator),
|
|
|
|
.frames = FrameStack.make(allocator),
|
|
|
|
.frames = FrameStack.make(allocator),
|
|
|
|
.syscallables = RefTable.make(allocator, .{}),
|
|
|
|
.system_bindings = RefTable.make(allocator, .{}),
|
|
|
|
.interned_symbols = SymbolSet.make(allocator, .{}),
|
|
|
|
.interned_symbols = SymbolSet.make(allocator, .{}),
|
|
|
|
.error_handler = error_handler,
|
|
|
|
.error_handler = error_handler,
|
|
|
|
.allocator = allocator,
|
|
|
|
.allocator = allocator,
|
|
|
@ -1056,13 +1082,17 @@ pub const RuntimeEnv = struct {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn new_dynamic(self: *RuntimeEnv, typeinfo: *const Typeinfo) RuntimeError!*RuntimeRef {
|
|
|
|
pub fn new_dynamic(
|
|
|
|
|
|
|
|
self: *RuntimeEnv,
|
|
|
|
|
|
|
|
userdata: [*]const coral.io.Byte,
|
|
|
|
|
|
|
|
typeinfo: *const Typeinfo,
|
|
|
|
|
|
|
|
) RuntimeError!*RuntimeRef {
|
|
|
|
const dynamic = try self.allocator.reallocate(null, @sizeOf(usize) + typeinfo.size);
|
|
|
|
const dynamic = try self.allocator.reallocate(null, @sizeOf(usize) + typeinfo.size);
|
|
|
|
|
|
|
|
|
|
|
|
errdefer self.allocator.deallocate(dynamic);
|
|
|
|
errdefer self.allocator.deallocate(dynamic);
|
|
|
|
|
|
|
|
|
|
|
|
coral.io.copy(dynamic, coral.io.bytes_of(&typeinfo));
|
|
|
|
coral.io.copy(dynamic, coral.io.bytes_of(&typeinfo));
|
|
|
|
coral.io.zero(dynamic[@sizeOf(usize) ..]);
|
|
|
|
coral.io.copy(dynamic[@sizeOf(usize) ..], userdata[0 .. typeinfo.size]);
|
|
|
|
|
|
|
|
|
|
|
|
return RuntimeRef.allocate(self.allocator, .{
|
|
|
|
return RuntimeRef.allocate(self.allocator, .{
|
|
|
|
.ref_count = 1,
|
|
|
|
.ref_count = 1,
|
|
|
@ -1134,17 +1164,13 @@ pub const RuntimeEnv = struct {
|
|
|
|
table.contiguous.free();
|
|
|
|
table.contiguous.free();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const newed = try self.new_dynamic(&.{
|
|
|
|
return try self.new_dynamic(coral.io.bytes_of(&table).ptr, &.{
|
|
|
|
.name = "table",
|
|
|
|
.name = "table",
|
|
|
|
.size = @sizeOf(Table),
|
|
|
|
.size = @sizeOf(Table),
|
|
|
|
.destruct = Table.typeinfo_destruct,
|
|
|
|
.destruct = Table.typeinfo_destruct,
|
|
|
|
.get = Table.typeinfo_get,
|
|
|
|
.get = Table.typeinfo_get,
|
|
|
|
.set = Table.typeinfo_set,
|
|
|
|
.set = Table.typeinfo_set,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
coral.io.copy(self.unbox_dynamic(newed) catch unreachable, coral.io.bytes_of(&table));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return newed;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, message: []const coral.io.Byte) RuntimeError {
|
|
|
|
pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, message: []const coral.io.Byte) RuntimeError {
|
|
|
@ -1364,3 +1390,27 @@ pub const Typeinfo = struct {
|
|
|
|
return method.env.raise(error.TypeMismatch, "object is not index-settable");
|
|
|
|
return method.env.raise(error.TypeMismatch, "object is not index-settable");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn bind_syscaller(env: *RuntimeEnv, name: []const coral.io.Byte, caller: Caller) RuntimeError!void {
|
|
|
|
|
|
|
|
const callable = try new_caller(env, caller);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer env.discard(callable);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try env.bind_system(name, callable);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn new_caller(env: *RuntimeEnv, value: Caller) RuntimeError!*RuntimeRef {
|
|
|
|
|
|
|
|
const Callable = struct {
|
|
|
|
|
|
|
|
fn call(method: Typeinfo.Method) RuntimeError!?*RuntimeRef {
|
|
|
|
|
|
|
|
coral.debug.assert(method.userdata.len == @sizeOf(Caller));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return @as(*Caller, @ptrCast(@alignCast(method.userdata))).invoke(method.env);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return env.new_dynamic(coral.io.bytes_of(&value).ptr, &.{
|
|
|
|
|
|
|
|
.name = "<native>",
|
|
|
|
|
|
|
|
.size = @sizeOf(Caller),
|
|
|
|
|
|
|
|
.call = Callable.call,
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|