diff --git a/debug/app.ona b/debug/app.ona index 175db2a..bb14b64 100644 --- a/debug/app.ona +++ b/debug/app.ona @@ -1,7 +1,7 @@ let test_param = "monkey wrench" -let printer = lambda (pfx, arbitrary): +let printer = lambda (pfx): @print(test_param) return lambda (msg): diff --git a/source/coral/utf8.zig b/source/coral/utf8.zig index 7ca7d52..f7ddcc6 100644 --- a/source/coral/utf8.zig +++ b/source/coral/utf8.zig @@ -197,7 +197,7 @@ pub const HexadecimalFormat = struct { _ = writer; _ = value; - return null; + unreachable; } }; diff --git a/source/ona/kym.zig b/source/ona/kym.zig index 631a234..5004f9c 100644 --- a/source/ona/kym.zig +++ b/source/ona/kym.zig @@ -650,7 +650,7 @@ pub const RuntimeEnv = struct { break: convert self.new_string(string[0 .. length.?]); }, - .boxed => unreachable, + .boxed => |boxed| if (boxed) |boxed_value| self.to_string(boxed_value) else self.new_string("nil"), .symbol => |symbol| self.new_string(coral.io.slice_sentineled(@as(coral.io.Byte, 0), symbol)), .string => value.acquire(), @@ -658,7 +658,7 @@ pub const RuntimeEnv = struct { var string = [_:0]coral.io.Byte{0} ** 64; var buffer = coral.io.FixedBuffer{.bytes = &string}; - const length = coral.utf8.print_formatted(buffer.as_writer(), "vec3({x}, {y})", .{ + const length = coral.utf8.print_formatted(buffer.as_writer(), "@vec2({x}, {y})", .{ .x = vector2[0], .y = vector2[1], }); @@ -672,7 +672,7 @@ pub const RuntimeEnv = struct { var string = [_:0]coral.io.Byte{0} ** 96; var buffer = coral.io.FixedBuffer{.bytes = &string}; - const length = coral.utf8.print_formatted(buffer.as_writer(), "vec3({x}, {y}, {z})", .{ + const length = coral.utf8.print_formatted(buffer.as_writer(), "@vec3({x}, {y}, {z})", .{ .x = vector3[0], .y = vector3[1], .z = vector3[2], @@ -688,11 +688,10 @@ pub const RuntimeEnv = struct { }; } - pub fn unwrap_dynamic(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError![]coral.io.Byte { - return switch (value.object().payload) { - .dynamic => |dynamic| dynamic.userdata(), - else => self.raise(error.TypeMismatch, "expected fixed object") - }; + pub fn unwrap_dynamic(self: *RuntimeEnv, value: *const RuntimeRef, typeinfo: *const Typeinfo) RuntimeError![]coral.io.Byte { + return value.as_dynamic(typeinfo) orelse self.raise(error.TypeMismatch, "expected dynamic object, not {typename}", .{ + .typename = value.typename(), + }); } pub fn unwrap_float(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!Float { @@ -705,7 +704,7 @@ pub const RuntimeEnv = struct { pub fn unwrap_fixed(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!Fixed { return value.as_fixed() orelse self.raise(error.TypeMismatch, "expected fixed, not {typename}", .{ - .typename = value.typename() + .typename = value.typename(), }); } @@ -861,7 +860,17 @@ pub const RuntimeRef = opaque { else => false, }, - .boxed => unreachable, + .boxed => |boxed| unbox: { + if (boxed) |boxed_value| { + break: unbox boxed_value.equals(other); + } + + if (other.as_boxed()) |boxed_value| { + break: unbox boxed_value.* == null; + } + + break: unbox false; + }, .vector2 => |self_vector| switch (other.object().payload) { .vector2 => |other_vector| coral.io.are_equal(coral.io.bytes_of(&self_vector), coral.io.bytes_of(&other_vector)), @@ -965,6 +974,12 @@ pub const Typeinfo = struct { } }; +pub fn assert(env: *RuntimeEnv, condition: bool) RuntimeError!void { + if (!condition) { + return env.raise(error.IllegalState, "assertion", .{}); + } +} + pub fn get_field(env: *RuntimeEnv, indexable: *RuntimeRef, field: []const coral.io.Byte) RuntimeError!?*RuntimeRef { const field_symbol = try env.new_symbol(field); diff --git a/source/ona/kym/Chunk.zig b/source/ona/kym/Chunk.zig index 0051c4c..f763819 100644 --- a/source/ona/kym/Chunk.zig +++ b/source/ona/kym/Chunk.zig @@ -18,10 +18,6 @@ opcodes: OpcodeList, constants: ConstList, bindings: []?*kym.RuntimeRef, -const Box = struct { - -}; - const Builtin = enum { import, print, @@ -93,9 +89,7 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef .push_false => coral.utf8.print_string(writer, "push false\n"), .push_const => |push_const| print: { - if (push_const >= chunk.constants.values.len) { - return env.raise(error.IllegalState, "invalid constant", .{}); - } + try kym.assert(env, push_const < chunk.constants.values.len); const string_ref = try env.to_string(chunk.constants.values[push_const]); @@ -183,17 +177,12 @@ pub fn execute(self: Self, env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeEr .push_false => try env.locals.push_one(try env.new_boolean(false)), .push_const => |push_const| { - if (push_const >= self.constants.values.len) { - return env.raise(error.IllegalState, "invalid constant", .{}); - } - + try kym.assert(env, push_const < self.constants.values.len); try env.locals.push_one(self.constants.values[push_const].acquire()); }, .push_local => |push_local| { - if (push_local >= (env.locals.values.len - frame.locals_top)) { - return env.raise(error.IllegalState, "invalid local", .{}); - } + try kym.assert(env, push_local < (env.locals.values.len - frame.locals_top)); if (env.locals.values[frame.locals_top + push_local]) |local| { try env.locals.push_one(local.acquire()); @@ -205,9 +194,7 @@ pub fn execute(self: Self, env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeEr .push_top => { const frame_locals = env.locals.values[frame.locals_top ..]; - if (frame_locals.len == 0) { - return env.raise(error.IllegalState, "stack overflow", .{}); - } + try kym.assert(env, frame_locals.len != 0); if (frame_locals[frame_locals.len - 1]) |local| { try env.locals.push_one(local.acquire()); @@ -257,23 +244,16 @@ pub fn execute(self: Self, env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeEr }, .push_binding => |push_binding| { - if (push_binding > self.bindings.len) { - return env.raise(error.IllegalState, "binding out of range", .{}); - } - + try kym.assert(env, push_binding <= self.bindings.len); try env.locals.push_one(if (self.bindings[push_binding]) |value| value.acquire() else null); }, .bind => |bind| { - const lambda = try env.expect(try env.pop_local()); + const callable = try env.expect(try env.pop_local()); - errdefer env.discard(lambda); + errdefer env.discard(callable); - const chunk = @as(*Self, @ptrCast(@alignCast(lambda.as_dynamic(typeinfo) orelse { - return env.raise(error.IllegalState, "cannot bind objects to a {typename}", .{ - .typename = lambda.typename(), - }); - }))); + const chunk = @as(*Self, @ptrCast(@alignCast(try env.unwrap_dynamic(callable, typeinfo)))); chunk.bindings = try coral.io.allocate_many(env.allocator, bind, @as(?*kym.RuntimeRef, null)); @@ -295,7 +275,7 @@ pub fn execute(self: Self, env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeEr binding.* = value; } - try env.locals.push_one(lambda); + try env.locals.push_one(callable); }, .push_builtin => |push_builtin| { @@ -612,31 +592,6 @@ pub fn make(env: *kym.RuntimeEnv, name: *const kym.RuntimeRef, environment: *con try compiler.compile_environment(environment); - if (builtin.mode == .Debug) { - const name_string = try env.to_string(name); - - defer env.discard(name_string); - - const name_bytes = name_string.as_string(); - - coral.debug.assert(name_bytes != null); - - const allocation = try coral.utf8.alloc_formatted(env.allocator, "compiled {name}...", .{.name = name_bytes.?}); - - defer env.allocator.deallocate(allocation); - - app.log_info(allocation); - - const string_ref = try chunk.dump(env); - - defer env.discard(string_ref); - - const string = string_ref.as_string(); - - coral.debug.assert(string != null); - app.log_info(string.?); - } - return chunk; } @@ -676,7 +631,7 @@ fn syscall_vec3(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.R pub const typeinfo = &kym.Typeinfo{ .size = @sizeOf(Self), - .name = "func", + .name = "lambda", .destruct = typeinfo_destruct, .call = typeinfo_call, }; diff --git a/source/ona/kym/Compiler.zig b/source/ona/kym/Compiler.zig index d41736a..c34ea56 100644 --- a/source/ona/kym/Compiler.zig +++ b/source/ona/kym/Compiler.zig @@ -158,7 +158,7 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi return self.chunk.opcodes.push_one(.{.push_local = index}); } - if (get_binding_index(environment, declaration_get.declaration)) |index| { + if (try self.get_binding_index(environment, declaration_get.declaration)) |index| { try self.chunk.opcodes.push_one(.{.push_binding = index}); if (is_declaration_boxed(declaration_get.declaration)) { @@ -178,7 +178,7 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi return self.chunk.opcodes.push_one(.{.set_local = index}); } - if (get_binding_index(environment, declaration_set.declaration)) |index| { + if (try self.get_binding_index(environment, declaration_set.declaration)) |index| { try self.chunk.opcodes.push_one(.{.push_binding = index}); try self.compile_expression(environment, declaration_set.assign, null); @@ -376,7 +376,7 @@ fn declare_symbol(self: Self, symbol: []const coral.io.Byte) kym.RuntimeError!u1 return @intCast(self.chunk.constants.values.len - 1); } -pub fn get_binding_index(environment: *const tree.Environment, declaration: *const tree.Declaration) ?u8 { +pub fn get_binding_index(self: *const Self, environment: *const tree.Environment, declaration: *const tree.Declaration) kym.RuntimeError!?u8 { var binding_index = @as(u8, 0); while (binding_index < environment.capture_count) : (binding_index += 1) { @@ -388,7 +388,7 @@ pub fn get_binding_index(environment: *const tree.Environment, declaration: *con target_environment = target_environment.enclosing orelse return null; } - coral.debug.assert(capture.* == .declaration_index); + try kym.assert(self.env, capture.* == .declaration_index); if (&target_environment.declarations[capture.declaration_index] == declaration) { return binding_index; diff --git a/source/ona/kym/Stmt.zig b/source/ona/kym/Stmt.zig index ae8f226..c31059b 100644 --- a/source/ona/kym/Stmt.zig +++ b/source/ona/kym/Stmt.zig @@ -120,26 +120,12 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro .declaration = declare: { if (is_constant) { break: declare environment.declare_constant(identifier) catch |declaration_error| { - return switch (declaration_error) { - error.OutOfMemory => error.OutOfMemory, - - error.DeclarationExists => - root.report_error(stream, "declaration `{identifier}` already exists", .{ - .identifier = identifier, - }), - }; + return root.report_declare_error(stream, identifier, declaration_error); }; } break: declare environment.declare_variable(identifier) catch |declaration_error| { - return switch (declaration_error) { - error.OutOfMemory => error.OutOfMemory, - - error.DeclarationExists => - root.report_error(stream, "declaration `{identifier}` already exists", .{ - .identifier = identifier, - }), - }; + return root.report_declare_error(stream, identifier, declaration_error); }; }, }, diff --git a/source/ona/kym/tree.zig b/source/ona/kym/tree.zig index 814bd85..8b1c4b4 100644 --- a/source/ona/kym/tree.zig +++ b/source/ona/kym/tree.zig @@ -29,7 +29,7 @@ pub const Environment = struct { capture_index: u8, }; - const DeclareError = coral.io.AllocationError || error { + pub const DeclareError = coral.io.AllocationError || error { DeclarationExists, };