Replace System Objects with Builtins and Syscalls #33
|
@ -14,8 +14,8 @@ options = {
|
|||
options["foo"] = "rab"
|
||||
options[42] = "24"
|
||||
|
||||
@log_info(options.title)
|
||||
@log_info(options["foo"])
|
||||
@log_info(options[42])
|
||||
@print(options.title)
|
||||
@print(options["foo"])
|
||||
@print(options[42])
|
||||
|
||||
return options
|
||||
|
|
|
@ -12,8 +12,8 @@ pub const Manifest = struct {
|
|||
height: u16 = 480,
|
||||
tick_rate: f32 = 60.0,
|
||||
|
||||
pub fn load(self: *Manifest, env: *kym.RuntimeEnv, file_access: file.Access) kym.RuntimeError!void {
|
||||
const manifest = try env.expect(try env.execute_file(file_access, file.Path.from(&.{"app.ona"})));
|
||||
pub fn load(self: *Manifest, env: *kym.RuntimeEnv) kym.RuntimeError!void {
|
||||
const manifest = try env.expect(try env.import(file.Path.from(&.{"app.ona"})));
|
||||
|
||||
defer env.discard(manifest);
|
||||
|
||||
|
|
|
@ -4,30 +4,14 @@ const coral = @import("coral");
|
|||
|
||||
const file = @import("./file.zig");
|
||||
|
||||
pub const Caller = coral.io.Generator(RuntimeError!?*RuntimeRef, *RuntimeEnv);
|
||||
|
||||
pub const ErrorHandler = coral.io.Generator(void, ErrorInfo);
|
||||
|
||||
pub const ErrorInfo = struct {
|
||||
message: []const coral.io.Byte,
|
||||
frames: []const Frame,
|
||||
};
|
||||
|
||||
pub const Fixed = i32;
|
||||
|
||||
pub const Float = f64;
|
||||
|
||||
pub const Frame = struct {
|
||||
name: []const coral.io.Byte,
|
||||
arg_count: u8,
|
||||
locals_top: usize,
|
||||
};
|
||||
|
||||
pub const RuntimeEnv = struct {
|
||||
options: Options,
|
||||
interned_symbols: SymbolSet,
|
||||
allocator: coral.io.Allocator,
|
||||
error_handler: ErrorHandler,
|
||||
system_bindings: RefTable,
|
||||
locals: RefList,
|
||||
frames: FrameStack,
|
||||
|
||||
|
@ -37,6 +21,11 @@ pub const RuntimeEnv = struct {
|
|||
opcodes: OpcodeList,
|
||||
constants: ConstList,
|
||||
|
||||
const Builtin = enum {
|
||||
import,
|
||||
print,
|
||||
};
|
||||
|
||||
const Constant = union (enum) {
|
||||
fixed: Fixed,
|
||||
float: Float,
|
||||
|
@ -51,7 +40,7 @@ pub const RuntimeEnv = struct {
|
|||
push_const: u16,
|
||||
push_local: u8,
|
||||
push_table: u32,
|
||||
push_system: u16,
|
||||
push_builtin: Builtin,
|
||||
local_set: u8,
|
||||
object_get,
|
||||
object_set,
|
||||
|
@ -175,10 +164,12 @@ pub const RuntimeEnv = struct {
|
|||
try self.compile_expression(chunk, grouped_expression.*);
|
||||
},
|
||||
|
||||
.get_system => |get_system| {
|
||||
try chunk.opcodes.push_one(.{
|
||||
.push_system = try chunk.declare_constant(.{.symbol = get_system}),
|
||||
});
|
||||
.import => {
|
||||
try chunk.opcodes.push_one(.{.push_builtin = .import});
|
||||
},
|
||||
|
||||
.print => {
|
||||
try chunk.opcodes.push_one(.{.push_builtin = .print});
|
||||
},
|
||||
|
||||
.local_get => |local_get| {
|
||||
|
@ -360,12 +351,15 @@ pub const RuntimeEnv = struct {
|
|||
try self.env.locals.push_one(table);
|
||||
},
|
||||
|
||||
.push_system => |push_system| {
|
||||
if (self.env.system_bindings.lookup(self.constants.values[push_system])) |syscallable| {
|
||||
try self.env.locals.push_one(try self.env.acquire(syscallable));
|
||||
} else {
|
||||
try self.env.locals.push_one(null);
|
||||
}
|
||||
.push_builtin => |push_builtin| {
|
||||
const builtin_syscall = try self.env.new_syscall(switch (push_builtin) {
|
||||
.import => syscall_import,
|
||||
.print => syscall_print,
|
||||
});
|
||||
|
||||
errdefer self.env.discard(builtin_syscall);
|
||||
|
||||
try self.env.locals.push_one(builtin_syscall);
|
||||
},
|
||||
|
||||
.local_set => |local_set| {
|
||||
|
@ -441,6 +435,8 @@ pub const RuntimeEnv = struct {
|
|||
defer coral.debug.assert(self.env.frames.pop() != null);
|
||||
|
||||
break: call try switch (callable.object().payload) {
|
||||
.syscall => |syscall| syscall(self.env),
|
||||
|
||||
.dynamic => |dynamic| dynamic.typeinfo().call(.{
|
||||
.userdata = dynamic.userdata(),
|
||||
.env = self.env,
|
||||
|
@ -799,7 +795,19 @@ pub const RuntimeEnv = struct {
|
|||
|
||||
const ConstList = coral.list.Stack(*RuntimeRef);
|
||||
|
||||
const FrameStack = coral.list.Stack(Frame);
|
||||
const FrameStack = coral.list.Stack(struct {
|
||||
name: []const coral.io.Byte,
|
||||
arg_count: u8,
|
||||
locals_top: usize,
|
||||
});
|
||||
|
||||
pub const Options = struct {
|
||||
import_access: file.Access,
|
||||
print: *const Printer,
|
||||
print_error: *const Printer,
|
||||
};
|
||||
kayomn marked this conversation as resolved
|
||||
|
||||
pub const Printer = fn (buffer: []const coral.io.Byte) void;
|
||||
|
||||
const RefList = coral.list.Stack(?*RuntimeRef);
|
||||
|
||||
|
@ -916,7 +924,7 @@ pub const RuntimeEnv = struct {
|
|||
return @ptrCast(object);
|
||||
}
|
||||
|
||||
pub fn arg(self: *RuntimeEnv, index: usize) RuntimeError!?*RuntimeRef {
|
||||
pub fn acquire_arg(self: *RuntimeEnv, index: usize) RuntimeError!?*RuntimeRef {
|
||||
const frame = self.frames.peek() orelse return self.raise(error.IllegalState, "stack underflow");
|
||||
|
||||
if (index < frame.arg_count) {
|
||||
|
@ -957,6 +965,8 @@ pub const RuntimeEnv = struct {
|
|||
defer coral.io.assert(self.frames.pop() != null);
|
||||
|
||||
return switch (callable.object().payload) {
|
||||
.syscall => |syscall| syscall(self.env),
|
||||
|
||||
.dynamic => |dynamic| dynamic.typeinfo.call(.{
|
||||
.userdata = dynamic.userdata(),
|
||||
.env = self,
|
||||
|
@ -975,7 +985,7 @@ pub const RuntimeEnv = struct {
|
|||
|
||||
if (object.ref_count == 0) {
|
||||
switch (object.payload) {
|
||||
.false, .true, .float, .fixed, .symbol => {},
|
||||
.false, .true, .float, .fixed, .symbol, .syscall => {},
|
||||
|
||||
.string => |string| {
|
||||
coral.debug.assert(string.len >= 0);
|
||||
|
@ -998,8 +1008,8 @@ pub const RuntimeEnv = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn execute_file(self: *RuntimeEnv, file_access: file.Access, file_path: file.Path) RuntimeError!?*RuntimeRef {
|
||||
const file_data = (try file.allocate_and_load(self.allocator, file_access, file_path)) orelse {
|
||||
pub fn import(self: *RuntimeEnv, file_path: file.Path) RuntimeError!?*RuntimeRef {
|
||||
const file_data = (try file.allocate_and_load(self.allocator, self.options.import_access, file_path)) orelse {
|
||||
return self.raise(error.BadOperation, "failed to open or read file specified");
|
||||
};
|
||||
|
||||
|
@ -1043,18 +1053,8 @@ pub const RuntimeEnv = struct {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
var iterable = self.system_bindings.as_iterable();
|
||||
|
||||
while (iterable.next()) |entry| {
|
||||
self.discard(entry.key);
|
||||
self.discard(entry.value);
|
||||
}
|
||||
}
|
||||
|
||||
self.frames.free();
|
||||
self.locals.free();
|
||||
self.system_bindings.free();
|
||||
self.interned_symbols.free();
|
||||
}
|
||||
|
||||
|
@ -1069,13 +1069,12 @@ pub const RuntimeEnv = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn make(allocator: coral.io.Allocator, error_handler: ErrorHandler) coral.io.AllocationError!RuntimeEnv {
|
||||
pub fn make(allocator: coral.io.Allocator, options: Options) coral.io.AllocationError!RuntimeEnv {
|
||||
return RuntimeEnv{
|
||||
.locals = RefList.make(allocator),
|
||||
.frames = FrameStack.make(allocator),
|
||||
.system_bindings = RefTable.make(allocator, .{}),
|
||||
.interned_symbols = SymbolSet.make(allocator, .{}),
|
||||
.error_handler = error_handler,
|
||||
.options = options,
|
||||
.allocator = allocator,
|
||||
};
|
||||
}
|
||||
|
@ -1158,6 +1157,13 @@ pub const RuntimeEnv = struct {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn new_syscall(self: *RuntimeEnv, value: *const Syscall) RuntimeError!*RuntimeRef {
|
||||
return RuntimeRef.allocate(self.allocator, .{
|
||||
.ref_count = 1,
|
||||
.payload = .{.syscall = value},
|
||||
});
|
||||
}
|
||||
|
||||
pub fn new_table(self: *RuntimeEnv) RuntimeError!*RuntimeRef {
|
||||
var table = Table{
|
||||
.associative = RefTable.make(self.allocator, .{}),
|
||||
|
@ -1178,11 +1184,24 @@ pub const RuntimeEnv = struct {
|
|||
});
|
||||
}
|
||||
|
||||
pub fn print(self: *RuntimeEnv, buffer: []const coral.io.Byte) void {
|
||||
self.options.print(buffer);
|
||||
}
|
||||
|
||||
pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, message: []const coral.io.Byte) RuntimeError {
|
||||
self.error_handler.invoke(.{
|
||||
.message = message,
|
||||
.frames = self.frames.values,
|
||||
});
|
||||
self.options.print_error(message);
|
||||
|
||||
if (!self.frames.is_empty()) {
|
||||
self.options.print_error("stack trace:");
|
||||
|
||||
var remaining_frames = self.frames.values.len;
|
||||
|
||||
while (remaining_frames != 0) {
|
||||
remaining_frames -= 1;
|
||||
|
||||
self.options.print_error(self.frames.values[remaining_frames].name);
|
||||
}
|
||||
}
|
||||
|
||||
return error_value;
|
||||
}
|
||||
|
@ -1254,6 +1273,7 @@ pub const RuntimeRef = opaque {
|
|||
float: Float,
|
||||
fixed: Fixed,
|
||||
symbol: [*:0]const coral.io.Byte,
|
||||
syscall: *const Syscall,
|
||||
|
||||
string: struct {
|
||||
ptr: [*]coral.io.Byte,
|
||||
|
@ -1323,6 +1343,11 @@ pub const RuntimeRef = opaque {
|
|||
else => false,
|
||||
},
|
||||
|
||||
.syscall => |self_syscall| switch (other.object().payload) {
|
||||
.syscall => |other_syscall| self_syscall == other_syscall,
|
||||
else => false,
|
||||
},
|
||||
|
||||
.string => |self_string| switch (other.object().payload) {
|
||||
.string => |other_string| coral.io.equals(self_string.unpack(), other_string.unpack()),
|
||||
else => false,
|
||||
|
@ -1344,7 +1369,8 @@ pub const RuntimeRef = opaque {
|
|||
.true => 1231,
|
||||
.float => |float| @bitCast(float),
|
||||
.fixed => |fixed| @intCast(@as(u32, @bitCast(fixed))),
|
||||
.symbol => |symbol| @bitCast(@intFromPtr(symbol)),
|
||||
.symbol => |symbol| @intFromPtr(symbol),
|
||||
.syscall => |syscall| @intFromPtr(syscall),
|
||||
.string => |string| coral.io.djb2_hash(@typeInfo(usize).Int, string.unpack()),
|
||||
.dynamic => |dynamic| @intFromPtr(dynamic.typeinfo()) ^ @intFromPtr(dynamic.userdata().ptr),
|
||||
};
|
||||
|
@ -1364,12 +1390,15 @@ pub const RuntimeRef = opaque {
|
|||
.float => |float| float != 0,
|
||||
.fixed => |fixed| fixed != 0,
|
||||
.symbol => true,
|
||||
.syscall => true,
|
||||
.string => |string| string.len != 0,
|
||||
.dynamic => true,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Syscall = fn (env: *RuntimeEnv) RuntimeError!?*RuntimeRef;
|
||||
|
||||
pub const Typeinfo = struct {
|
||||
name: []const coral.io.Byte,
|
||||
size: usize,
|
||||
|
@ -1396,14 +1425,6 @@ pub const Typeinfo = struct {
|
|||
}
|
||||
};
|
||||
|
||||
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 get_field(env: *RuntimeEnv, indexable: *RuntimeRef, field: []const coral.io.Byte) RuntimeError!?*RuntimeRef {
|
||||
const field_symbol = try env.new_symbol(field);
|
||||
|
||||
|
@ -1428,18 +1449,20 @@ pub fn get_key(env: *RuntimeEnv, indexable: *RuntimeRef, key: []const coral.io.B
|
|||
return env.get(indexable, key_string);
|
||||
}
|
||||
|
||||
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));
|
||||
fn syscall_import(env: *RuntimeEnv) RuntimeError!?*RuntimeRef {
|
||||
const arg = try env.expect(try env.acquire_arg(0));
|
||||
|
||||
return @as(*Caller, @ptrCast(@alignCast(method.userdata))).invoke(method.env);
|
||||
}
|
||||
};
|
||||
defer env.discard(arg);
|
||||
|
||||
return env.new_dynamic(coral.io.bytes_of(&value).ptr, &.{
|
||||
.name = "<native>",
|
||||
.size = @sizeOf(Caller),
|
||||
.call = Callable.call,
|
||||
});
|
||||
return env.import(file.Path.from(&.{try env.unbox_string(arg)}));
|
||||
}
|
||||
|
||||
fn syscall_print(env: *RuntimeEnv) RuntimeError!?*RuntimeRef {
|
||||
const arg = try env.expect(try env.acquire_arg(0));
|
||||
|
||||
defer env.discard(arg);
|
||||
|
||||
env.print(try env.unbox_string(arg));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -13,12 +13,13 @@ pub const Expression = union (enum) {
|
|||
nil_literal,
|
||||
true_literal,
|
||||
false_literal,
|
||||
import,
|
||||
print,
|
||||
number_literal: []const coral.io.Byte,
|
||||
string_literal: []const coral.io.Byte,
|
||||
symbol_literal: []const coral.io.Byte,
|
||||
table_literal: TableLiteral,
|
||||
grouped_expression: *Expression,
|
||||
get_system: []const coral.io.Byte,
|
||||
local_get: []const coral.io.Byte,
|
||||
local_set: []const coral.io.Byte,
|
||||
|
||||
|
@ -351,10 +352,27 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||
break: parse .{.local_get = identifier};
|
||||
},
|
||||
|
||||
.system_identifier => |system_identifier| {
|
||||
.builtin => |builtin| {
|
||||
self.tokenizer.skip_newlines();
|
||||
coral.debug.assert(builtin.len != 0);
|
||||
|
||||
break: parse .{.get_system = system_identifier};
|
||||
switch (builtin[0]) {
|
||||
'i' => {
|
||||
if (coral.io.ends_with(builtin, "mport")) {
|
||||
break: parse .import;
|
||||
}
|
||||
},
|
||||
|
||||
'p' => {
|
||||
if (coral.io.ends_with(builtin, "rint")) {
|
||||
break: parse .print;
|
||||
}
|
||||
},
|
||||
|
||||
else => {},
|
||||
}
|
||||
|
||||
return self.report("unknown builtin");
|
||||
},
|
||||
kayomn marked this conversation as resolved
kayomn
commented
Should discerning the specific builtin type be the job of the AST itself? I feel like it should be the job of the compiler during AST parsing. Should discerning the specific builtin type be the job of the AST itself? I feel like it should be the job of the compiler during AST parsing.
|
||||
|
||||
.symbol_brace_left => {
|
||||
|
|
|
@ -4,9 +4,8 @@ pub const Token = union(enum) {
|
|||
end,
|
||||
unknown: coral.io.Byte,
|
||||
newline,
|
||||
|
||||
system_identifier: []const coral.io.Byte,
|
||||
identifier: []const coral.io.Byte,
|
||||
builtin: []const coral.io.Byte,
|
||||
|
||||
symbol_plus,
|
||||
symbol_minus,
|
||||
|
@ -46,8 +45,8 @@ pub const Token = union(enum) {
|
|||
.unknown => |unknown| @as([*]const coral.io.Byte, @ptrCast(&unknown))[0 .. 1],
|
||||
.newline => "newline",
|
||||
|
||||
.system_identifier => |identifier| identifier,
|
||||
.identifier => |identifier| identifier,
|
||||
.builtin => |identifier| identifier,
|
||||
|
||||
.symbol_plus => "+",
|
||||
.symbol_minus => "-",
|
||||
|
@ -166,40 +165,52 @@ pub const Tokenizer = struct {
|
|||
coral.debug.assert(identifier.len != 0);
|
||||
|
||||
switch (identifier[0]) {
|
||||
'c' => if (coral.io.ends_with(identifier, "onst")) {
|
||||
'c' => {
|
||||
if (coral.io.ends_with(identifier, "onst")) {
|
||||
self.token = .keyword_const;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
'n' => if (coral.io.ends_with(identifier, "il")) {
|
||||
'n' => {
|
||||
if (coral.io.ends_with(identifier, "il")) {
|
||||
self.token = .keyword_nil;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
'f' => if (coral.io.ends_with(identifier, "alse")) {
|
||||
'f' => {
|
||||
if (coral.io.ends_with(identifier, "alse")) {
|
||||
self.token = .keyword_false;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
't' => if (coral.io.ends_with(identifier, "rue")) {
|
||||
't' => {
|
||||
if (coral.io.ends_with(identifier, "rue")) {
|
||||
self.token = .keyword_true;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
'r' => if (coral.io.ends_with(identifier, "eturn")) {
|
||||
'r' => {
|
||||
if (coral.io.ends_with(identifier, "eturn")) {
|
||||
self.token = .keyword_return;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
's' => if (coral.io.ends_with(identifier, "elf")) {
|
||||
's' => {
|
||||
if (coral.io.ends_with(identifier, "elf")) {
|
||||
self.token = .keyword_self;
|
||||
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
else => {},
|
||||
|
@ -213,44 +224,14 @@ pub const Tokenizer = struct {
|
|||
'@' => {
|
||||
cursor += 1;
|
||||
|
||||
if (cursor < self.source.len) switch (self.source[cursor]) {
|
||||
'A'...'Z', 'a'...'z', '_' => {
|
||||
const begin = cursor;
|
||||
|
||||
cursor += 1;
|
||||
|
||||
while (cursor < self.source.len) switch (self.source[cursor]) {
|
||||
'0'...'9', 'A'...'Z', 'a'...'z', '_' => cursor += 1,
|
||||
else => break,
|
||||
};
|
||||
|
||||
self.token = .{.system_identifier = self.source[begin .. cursor]};
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
'"' => {
|
||||
cursor += 1;
|
||||
|
||||
const begin = cursor;
|
||||
|
||||
cursor += 1;
|
||||
|
||||
while (cursor < self.source.len) switch (self.source[cursor]) {
|
||||
'"' => break,
|
||||
else => cursor += 1,
|
||||
};
|
||||
|
||||
self.token = .{.system_identifier = self.source[begin .. cursor]};
|
||||
cursor += 1;
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
else => {},
|
||||
};
|
||||
|
||||
self.token = .symbol_at;
|
||||
self.token = if (begin == cursor) .{.unknown = '@'} else .{.builtin = self.source[begin .. cursor]};
|
||||
|
||||
return;
|
||||
},
|
||||
|
|
|
@ -10,52 +10,6 @@ const heap = @import("./heap.zig");
|
|||
|
||||
const kym = @import("./kym.zig");
|
||||
|
||||
fn kym_handle_errors(info: kym.ErrorInfo) void {
|
||||
app.log_fail(info.message);
|
||||
|
||||
var remaining_frames = info.frames.len;
|
||||
|
||||
if (remaining_frames != 0) {
|
||||
app.log_fail("stack trace:");
|
||||
|
||||
while (remaining_frames != 0) {
|
||||
remaining_frames -= 1;
|
||||
|
||||
app.log_fail(info.frames[remaining_frames].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn kym_log_info(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
|
||||
const argument = try env.expect(try env.arg(0));
|
||||
|
||||
defer env.discard(argument);
|
||||
|
||||
app.log_info(try env.unbox_string(argument));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn kym_log_warn(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
|
||||
const argument = try env.expect(try env.arg(0));
|
||||
|
||||
defer env.discard(argument);
|
||||
|
||||
app.log_warn(try env.unbox_string(argument));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn kym_log_fail(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
|
||||
const argument = try env.expect(try env.arg(0));
|
||||
|
||||
defer env.discard(argument);
|
||||
|
||||
app.log_fail(try env.unbox_string(argument));
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
fn last_sdl_error() [:0]const u8 {
|
||||
return coral.io.slice_sentineled(@as(u8, 0), @as([*:0]const u8, @ptrCast(ext.SDL_GetError())));
|
||||
}
|
||||
|
@ -69,27 +23,19 @@ pub fn run_app(file_access: file.Access) void {
|
|||
|
||||
defer ext.SDL_Quit();
|
||||
|
||||
var script_env = kym.RuntimeEnv.make(heap.allocator, kym.ErrorHandler.from(kym_handle_errors)) catch {
|
||||
var script_env = kym.RuntimeEnv.make(heap.allocator, .{
|
||||
.print = app.log_info,
|
||||
.print_error = app.log_fail,
|
||||
.import_access = file_access,
|
||||
}) catch {
|
||||
return app.log_fail("failed to initialize script runtime");
|
||||
};
|
||||
|
||||
defer script_env.free();
|
||||
|
||||
kym.bind_syscaller(&script_env, "log_info", kym.Caller.from(kym_log_info)) catch {
|
||||
return app.log_fail("failed to bind `log_info` syscall");
|
||||
};
|
||||
|
||||
kym.bind_syscaller(&script_env, "log_warn", kym.Caller.from(kym_log_warn)) catch {
|
||||
return app.log_fail("failed to bind `log_warn` syscall");
|
||||
};
|
||||
|
||||
kym.bind_syscaller(&script_env, "log_fail", kym.Caller.from(kym_log_fail)) catch {
|
||||
return app.log_fail("failed to bind `log_fail` syscall");
|
||||
};
|
||||
|
||||
var manifest = app.Manifest{};
|
||||
|
||||
manifest.load(&script_env, file_access) catch return;
|
||||
manifest.load(&script_env) catch return;
|
||||
|
||||
const window = create: {
|
||||
const pos = ext.SDL_WINDOWPOS_CENTERED;
|
||||
|
|
Loading…
Reference in New Issue
Options should provide reasonable defaults if they're intended to be optional.