Closures, Higher-Order Functions, and Everything in Between #44
|
@ -1,7 +1,7 @@
|
|||
|
||||
let test_param = "monkey wrench"
|
||||
|
||||
let printer = lambda (pfx, arbitrary):
|
||||
let printer = lambda (pfx):
|
||||
@print(test_param)
|
||||
|
||||
return lambda (msg):
|
||||
|
|
|
@ -197,7 +197,7 @@ pub const HexadecimalFormat = struct {
|
|||
_ = writer;
|
||||
_ = value;
|
||||
|
||||
return null;
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -18,10 +18,6 @@ opcodes: OpcodeList,
|
|||
constants: ConstList,
|
||||
bindings: []?*kym.RuntimeRef,
|
||||
kayomn marked this conversation as resolved
|
||||
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
kayomn marked this conversation as resolved
kayomn
commented
This shouldn't be capable of crashing the process - needs better handling. This shouldn't be capable of crashing the process - needs better handling.
|
||||
return binding_index;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
May be worth replacing with VM managed Buffer object rather than raw Zig array.
Actually this is out of scope and really a non-issue right now.