Add partial work on new VM interface
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
24a4590293
commit
d5d5b69f54
|
@ -4,6 +4,7 @@ pub const Value = union(enum) {
|
||||||
newline: void,
|
newline: void,
|
||||||
string: []const u8,
|
string: []const u8,
|
||||||
unsigned: u128,
|
unsigned: u128,
|
||||||
|
signed: i128,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn print(writer: io.Writer, values: []const Value) io.WriteError!usize {
|
pub fn print(writer: io.Writer, values: []const Value) io.WriteError!usize {
|
||||||
|
|
|
@ -22,8 +22,8 @@ pub const Environment = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const NewOptions = struct {
|
pub const NewOptions = struct {
|
||||||
userdata_size: usize = 0,
|
userdata: []const u8 = &.{},
|
||||||
userinfo: usize = 0,
|
identity: ?*const anyopaque = null,
|
||||||
behavior: *const Object.Behavior = &.{},
|
behavior: *const Object.Behavior = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,19 +35,30 @@ pub const Environment = struct {
|
||||||
pub fn call(self: *Environment, object: *Object, arguments: []const Value) RuntimeError!Value {
|
pub fn call(self: *Environment, object: *Object, arguments: []const Value) RuntimeError!Value {
|
||||||
var global_object = Object{
|
var global_object = Object{
|
||||||
.ref_count = 0,
|
.ref_count = 0,
|
||||||
.userinfo = 0,
|
.identity = &self.globals,
|
||||||
.userdata = &.{},
|
.userdata = &.{},
|
||||||
.fields = self.globals,
|
.fields = self.globals,
|
||||||
.behavior = &.{},
|
.behavior = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
return object.behavior.caller(.{
|
return object.behavior.caller(.{
|
||||||
.environment = self,
|
.env = self,
|
||||||
.arguments = arguments,
|
.args = arguments,
|
||||||
.object = &global_object,
|
.caller = &global_object,
|
||||||
|
.callee = object,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn check(self: Environment, condition: bool, failure_message: []const u8) RuntimeError!void {
|
||||||
|
if (condition) return;
|
||||||
|
|
||||||
|
// TODO: Emit failure message.
|
||||||
|
_ = self;
|
||||||
|
_ = failure_message;
|
||||||
|
|
||||||
|
return error.CheckFailure;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Environment) void {
|
pub fn deinit(self: *Environment) void {
|
||||||
self.stack.deinit(self.allocator);
|
self.stack.deinit(self.allocator);
|
||||||
self.calls.deinit(self.allocator);
|
self.calls.deinit(self.allocator);
|
||||||
|
@ -57,7 +68,7 @@ pub const Environment = struct {
|
||||||
try self.globals.assign(self.allocator, global_name, value);
|
try self.globals.assign(self.allocator, global_name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(allocator: coral.io.Allocator, init_options: InitOptions) !Environment {
|
pub fn init(allocator: coral.io.Allocator, options: InitOptions) !Environment {
|
||||||
var environment = Environment{
|
var environment = Environment{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.globals = .{},
|
.globals = .{},
|
||||||
|
@ -70,8 +81,8 @@ pub const Environment = struct {
|
||||||
environment.calls.deinit(allocator);
|
environment.calls.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
try environment.stack.grow(allocator, init_options.stack_max);
|
try environment.stack.grow(allocator, options.stack_max);
|
||||||
try environment.calls.grow(allocator, init_options.calls_max);
|
try environment.calls.grow(allocator, options.calls_max);
|
||||||
|
|
||||||
return environment;
|
return environment;
|
||||||
}
|
}
|
||||||
|
@ -81,14 +92,16 @@ pub const Environment = struct {
|
||||||
|
|
||||||
errdefer coral.io.deallocate(self.allocator, object);
|
errdefer coral.io.deallocate(self.allocator, object);
|
||||||
|
|
||||||
const userdata = try coral.io.allocate_many(u8, options.userdata_size, self.allocator);
|
const userdata = try coral.io.allocate_many(u8, options.userdata.len, self.allocator);
|
||||||
|
|
||||||
errdefer coral.io.deallocate(self.allocator, userdata);
|
errdefer coral.io.deallocate(self.allocator, userdata);
|
||||||
|
|
||||||
|
coral.io.copy(userdata, options.userdata);
|
||||||
|
|
||||||
object.* = .{
|
object.* = .{
|
||||||
.userdata = userdata,
|
.userdata = userdata,
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.userinfo = options.userinfo,
|
.identity = options.identity orelse userdata.ptr,
|
||||||
.behavior = options.behavior,
|
.behavior = options.behavior,
|
||||||
.fields = .{},
|
.fields = .{},
|
||||||
};
|
};
|
||||||
|
@ -101,7 +114,7 @@ pub const Environment = struct {
|
||||||
return self.new(.none, .{});
|
return self.new(.none, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_script(self: *Environment, options: NewScriptOptions) RuntimeError!*Object {
|
pub fn new_script(self: *Environment, options: NewScriptOptions) coral.io.AllocationError!*Object {
|
||||||
// TODO: Implement.
|
// TODO: Implement.
|
||||||
_ = self;
|
_ = self;
|
||||||
_ = options;
|
_ = options;
|
||||||
|
@ -110,30 +123,21 @@ pub const Environment = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_string(self: *Environment, string_data: []const u8) coral.io.AllocationError!*Object {
|
pub fn new_string(self: *Environment, string_data: []const u8) coral.io.AllocationError!*Object {
|
||||||
const string_behavior = &.{};
|
const object = try self.new(.{
|
||||||
|
.userdata = string_data,
|
||||||
if (string_data.len == 0) {
|
.behavior = &.{},
|
||||||
// Empty string.
|
|
||||||
return self.new(.{.behavior = string_behavior});
|
|
||||||
}
|
|
||||||
|
|
||||||
const string_object = try self.new(.{
|
|
||||||
.userdata_size = string_data.len,
|
|
||||||
.behavior = string_behavior
|
|
||||||
});
|
});
|
||||||
|
|
||||||
errdefer self.release(string_object);
|
errdefer self.release(object);
|
||||||
|
|
||||||
coral.io.copy(string_object.userdata, string_data);
|
return object;
|
||||||
|
|
||||||
return string_object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_string_from_float(self: *Environment, float: Float) coral.io.AllocationError!*Object {
|
pub fn new_string_from(self: *Environment, formats: []const coral.format.Value) coral.io.AllocationError!*Object {
|
||||||
// TODO: Implement.
|
// TODO: Implement.
|
||||||
_ = float;
|
coral.format.print(coral.io.null_writer, formats);
|
||||||
|
|
||||||
return self.new_string("0.0");
|
return self.new_string("");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_string_from_integer(self: *Environment, integer: Integer) coral.io.AllocationError!*Object {
|
pub fn new_string_from_integer(self: *Environment, integer: Integer) coral.io.AllocationError!*Object {
|
||||||
|
@ -143,13 +147,6 @@ pub const Environment = struct {
|
||||||
return self.new_string("0");
|
return self.new_string("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_string_from_object(self: *Environment, object: *Object) coral.io.AllocationError!*Object {
|
|
||||||
// TODO: Implement.
|
|
||||||
_ = object;
|
|
||||||
|
|
||||||
return self.new_string("");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_table(self: *Environment) coral.io.AllocationError!*Object {
|
pub fn new_table(self: *Environment) coral.io.AllocationError!*Object {
|
||||||
// TODO: Implement.
|
// TODO: Implement.
|
||||||
return self.new(.none, .{});
|
return self.new(.none, .{});
|
||||||
|
@ -174,6 +171,23 @@ pub const Environment = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn user_cast(self: *Environment, object: *Object, expected_identity: *const anyopaque, comptime CastTarget: type) RuntimeError!*CastTarget {
|
||||||
|
// TODO: Emit failure message.
|
||||||
|
_ = self;
|
||||||
|
|
||||||
|
if (object.identity != expected_identity) {
|
||||||
|
// Identity does not match what was expected.
|
||||||
|
return error.InvalidOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.userdata.len != @sizeOf(CastTarget)) {
|
||||||
|
// Userdata size does not match target type.
|
||||||
|
return error.InvalidOperation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return @ptrCast(*CastTarget, @alignCast(@alignOf(CastTarget), object.userdata));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn virtual_call(self: *Environment, object: *Object, index: Value, arguments: []const Value) RuntimeError!Value {
|
pub fn virtual_call(self: *Environment, object: *Object, index: Value, arguments: []const Value) RuntimeError!Value {
|
||||||
const value = try self.virtual_get(object, index);
|
const value = try self.virtual_get(object, index);
|
||||||
|
|
||||||
|
@ -217,39 +231,43 @@ pub const Integer = i32;
|
||||||
|
|
||||||
pub const Object = struct {
|
pub const Object = struct {
|
||||||
ref_count: usize,
|
ref_count: usize,
|
||||||
userinfo: usize,
|
identity: *const anyopaque,
|
||||||
userdata: []u8,
|
userdata: []u8,
|
||||||
behavior: *const Behavior,
|
behavior: *const Behavior,
|
||||||
fields: ValueTable,
|
fields: ValueTable,
|
||||||
|
|
||||||
pub const Behavior = struct {
|
pub const Behavior = struct {
|
||||||
caller: *const Caller = default_call,
|
caller: *const Caller = default_call,
|
||||||
|
deinitialize: *const Deinitializer = default_deinitialize,
|
||||||
getter: *const Getter = default_get,
|
getter: *const Getter = default_get,
|
||||||
setter: *const Setter = default_set,
|
setter: *const Setter = default_set,
|
||||||
destructor: *const Destructor = default_destruct,
|
|
||||||
|
|
||||||
fn default_call(_: CallContext) RuntimeError!Value {
|
fn default_call(_: CallContext) RuntimeError!Value {
|
||||||
return error.InvalidOperation;
|
return error.InvalidOperation;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_destruct(_: DestructContext) void {
|
fn default_deinitialize(_: DeinitializeContext) void {
|
||||||
|
// Nothing to deinitialize by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_get(context: GetContext) RuntimeError!Value {
|
fn default_get(context: GetContext) RuntimeError!Value {
|
||||||
const index = try switch (context.index) {
|
switch (context.index) {
|
||||||
.object => |object| context.environment.new_string_from_object(object),
|
.object => |index| {
|
||||||
.integer => |integer| context.environment.new_string_from_integer(integer),
|
if (!index.is_string()) return error.InvalidOperation;
|
||||||
.float => |float| context.environment.new_string_from_float(float),
|
|
||||||
|
return context.obj.fields.lookup(index.userdata) orelse .nil;
|
||||||
|
},
|
||||||
|
|
||||||
|
.integer => |integer| {
|
||||||
|
const index = context.env.new_string_from(&.{.{.signed = integer}});
|
||||||
|
|
||||||
|
defer context.env.release(index);
|
||||||
|
|
||||||
|
return context.obj.fields.lookup(index.userdata) orelse .nil;
|
||||||
|
},
|
||||||
|
|
||||||
else => return error.InvalidOperation,
|
else => return error.InvalidOperation,
|
||||||
};
|
}
|
||||||
|
|
||||||
defer context.environment.release(index);
|
|
||||||
|
|
||||||
// A string is just a serious of bytes (i.e. userdata with no userinfo).
|
|
||||||
coral.debug.assert(index.userinfo == 0);
|
|
||||||
|
|
||||||
return context.object.fields.lookup(index.userdata) orelse .nil;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_set(_: SetContext) RuntimeError!void {
|
fn default_set(_: SetContext) RuntimeError!void {
|
||||||
|
@ -258,41 +276,32 @@ pub const Object = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const CallContext = struct {
|
pub const CallContext = struct {
|
||||||
environment: *Environment,
|
env: *Environment,
|
||||||
object: *Object,
|
caller: *Object,
|
||||||
arguments: []const Value,
|
callee: *Object,
|
||||||
|
args: []const Value,
|
||||||
pub fn check(self: CallContext, condition: bool, failure_message: []const u8) RuntimeError!void {
|
|
||||||
if (condition) return;
|
|
||||||
|
|
||||||
// TODO: Emit failure message.
|
|
||||||
_ = self;
|
|
||||||
_ = failure_message;
|
|
||||||
|
|
||||||
return error.CheckFailure;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Caller = fn (context: CallContext) RuntimeError!Value;
|
pub const Caller = fn (context: CallContext) RuntimeError!Value;
|
||||||
|
|
||||||
pub const DestructContext = struct {
|
pub const DeinitializeContext = struct {
|
||||||
environment: *Environment,
|
env: *Environment,
|
||||||
object: *Object,
|
obj: *Object,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Destructor = fn (context: DestructContext) void;
|
pub const Deinitializer = fn (context: DeinitializeContext) void;
|
||||||
|
|
||||||
pub const GetContext = struct {
|
pub const GetContext = struct {
|
||||||
environment: *Environment,
|
env: *Environment,
|
||||||
object: *const Object,
|
obj: *const Object,
|
||||||
index: Value,
|
index: Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Getter = fn (context: GetContext) RuntimeError!Value;
|
pub const Getter = fn (context: GetContext) RuntimeError!Value;
|
||||||
|
|
||||||
pub const SetContext = struct {
|
pub const SetContext = struct {
|
||||||
environment: *Environment,
|
env: *Environment,
|
||||||
object: *Object,
|
obj: *Object,
|
||||||
index: Value,
|
index: Value,
|
||||||
value: Value,
|
value: Value,
|
||||||
};
|
};
|
||||||
|
@ -302,6 +311,11 @@ pub const Object = struct {
|
||||||
pub fn as_value(self: *Object) Value {
|
pub fn as_value(self: *Object) Value {
|
||||||
return .{.object = self};
|
return .{.object = self};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_string(self: Object) bool {
|
||||||
|
// Userdata represents a string (of bytes) if it's identity is it's userdata.
|
||||||
|
return self.identity == @ptrCast(*const anyopaque, self.userdata.ptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const RuntimeError = coral.io.AllocationError || error {
|
pub const RuntimeError = coral.io.AllocationError || error {
|
||||||
|
|
|
@ -4,72 +4,82 @@ const kym = @import("kym");
|
||||||
|
|
||||||
const ona = @import("ona");
|
const ona = @import("ona");
|
||||||
|
|
||||||
const transform2d_typename = @typeName(ona.gfx.Transform2D);
|
const transform_typeid = @typeName(ona.canvas.Transform);
|
||||||
|
|
||||||
fn bind_canvas(environment: *kym.vm.Environment, canvas: *ona.gfx.Canvas) !void {
|
fn new_canvas_item(environment: *kym.vm.Environment, canvas_item: ona.CanvasItem) !*kym.vm.Object {
|
||||||
const object = try environment.new(.{});
|
const typeid = @typeName(ona.CanvasItem);
|
||||||
|
|
||||||
defer environment.release(object);
|
var object = try environment.new(.{
|
||||||
|
.userdata = coral.io.bytes_of(&canvas_item),
|
||||||
const sprite_creator = try environment.new(.{
|
.identity = typeid,
|
||||||
.userinfo = @ptrToInt(canvas),
|
|
||||||
|
|
||||||
.behavior = &.{
|
|
||||||
.caller = struct {
|
|
||||||
fn call(context: kym.vm.Object.CallContext) kym.vm.RuntimeError!kym.vm.Value {
|
|
||||||
try context.check(context.arguments.len == 2, "2 arguments expected");
|
|
||||||
|
|
||||||
const transform = context.arguments[0].object;
|
|
||||||
|
|
||||||
try context.check(transform.userinfo == @ptrToInt(transform2d_typename), "`transform2d` expected");
|
|
||||||
|
|
||||||
_ = try @intToPtr(*ona.gfx.Canvas, context.object.userinfo).create_sprite(
|
|
||||||
coral.io.bytes_to(ona.gfx.Transform2D, transform.userdata).?);
|
|
||||||
|
|
||||||
return .nil;
|
|
||||||
}
|
|
||||||
}.call,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defer environment.release(sprite_creator);
|
errdefer environment.release(object);
|
||||||
|
|
||||||
try environment.raw_set(object, "create_sprite", sprite_creator.as_value());
|
return object;
|
||||||
try environment.global_set("canvas", object.as_value());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn bind_transform_2d(environment: *kym.Environment) !*kym.Object {
|
fn new_transform(environment: *kym.Environment, transform: ona.canvas.Transform) !*kym.vm.Object {
|
||||||
// const allocator = environment.allocator();
|
var object = try environment.new(.{
|
||||||
// const transform_2d = try allocator.allocate_one(ona.gfx.Transform2D);
|
.userdata = coral.io.bytes_of(&transform),
|
||||||
|
.identity = transform_typeid,
|
||||||
|
});
|
||||||
|
|
||||||
// errdefer allocator.deallocate(transform_2d);
|
errdefer environment.release(object);
|
||||||
|
|
||||||
// const object = try environment.new(@ptrToInt(transform_2d), .{
|
return object;
|
||||||
// .destructor = struct {
|
}
|
||||||
// fn destruct() void {
|
|
||||||
// allocator.deallocate(transform_2d);
|
|
||||||
// }
|
|
||||||
// }.destruct,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// defer environment.release(object);
|
|
||||||
|
|
||||||
// try environment.set_field(environment.globals(), object);
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn main() anyerror!void {
|
pub fn main() anyerror!void {
|
||||||
return ona.App.run(anyerror, start);
|
return ona.App.run(anyerror, start);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start(app: *ona.App) anyerror!void {
|
fn start(app: *ona.App) anyerror!void {
|
||||||
var kym_env = try kym.vm.Environment.init(ona.allocator, .{
|
var kym_environment = try kym.vm.Environment.init(ona.allocator, .{
|
||||||
.stack_max = 256,
|
.stack_max = 256,
|
||||||
.calls_max = 256,
|
.calls_max = 256,
|
||||||
});
|
});
|
||||||
|
|
||||||
defer kym_env.deinit();
|
defer kym_environment.deinit();
|
||||||
|
|
||||||
try bind_canvas(&kym_env, app.canvas());
|
const Ona = struct {
|
||||||
|
app: *ona.App,
|
||||||
|
|
||||||
|
const typeid = @typeName(ona.App);
|
||||||
|
};
|
||||||
|
|
||||||
|
var ona_lib = try kym_environment.new(.{
|
||||||
|
.userdata = coral.io.bytes_of(&Ona{
|
||||||
|
.app = app,
|
||||||
|
}),
|
||||||
|
|
||||||
|
.identity = Ona.typeid,
|
||||||
|
});
|
||||||
|
|
||||||
|
defer kym_environment.release(ona_lib);
|
||||||
|
|
||||||
|
try kym_environment.global_set("ona", ona_lib.as_value());
|
||||||
|
|
||||||
|
{
|
||||||
|
var sprite_creator = try kym_environment.new(.{.behavior = &.{.caller = struct {
|
||||||
|
fn call(context: kym.vm.Object.CallContext) kym.vm.RuntimeError!kym.vm.Value {
|
||||||
|
try context.env.check(context.args.len == 2, "2 arguments expected");
|
||||||
|
|
||||||
|
var item = try ona.CanvasItem.init((try context.env.user_cast(context.caller, Ona.typeid, Ona)).app, .{
|
||||||
|
.transform = (try context.env.user_cast(context.args[0].object, transform_typeid, ona.canvas.Transform)).*,
|
||||||
|
.options = .{.sprite = .{}},
|
||||||
|
});
|
||||||
|
|
||||||
|
errdefer item.deinit();
|
||||||
|
|
||||||
|
return (try new_canvas_item(context.env, item)).as_value();
|
||||||
|
}
|
||||||
|
}.call}});
|
||||||
|
|
||||||
|
defer kym_environment.release(sprite_creator);
|
||||||
|
|
||||||
|
try kym_environment.raw_set(ona_lib, "create_sprite", sprite_creator.as_value());
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const index_path = "index.kym";
|
const index_path = "index.kym";
|
||||||
|
@ -92,18 +102,16 @@ fn start(app: *ona.App) anyerror!void {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const index_script = try kym_env.new_script(.{
|
const index_script = try kym_environment.new_script(.{
|
||||||
.name = index_path,
|
.name = index_path,
|
||||||
.data = index_buffer.data
|
.data = index_buffer.data
|
||||||
});
|
});
|
||||||
|
|
||||||
defer kym_env.release(index_script);
|
defer kym_environment.release(index_script);
|
||||||
|
|
||||||
_ = try kym_env.call(index_script, &.{});
|
_ = try kym_environment.call(index_script, &.{});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (app.poll()) {
|
app.loop();
|
||||||
app.present();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue