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;
|
||||
kayomn marked this conversation as resolved
Outdated
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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"),
|
||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
Why unreachable? Why unreachable?
|
||||
.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| {
|
||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
Why unreachable? Why unreachable?
|
||||
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
kayomn
commented
May be worth replacing with VM managed Buffer object rather than raw Zig array. May be worth replacing with VM managed Buffer object rather than raw Zig array.
kayomn
commented
Actually this is out of scope and really a non-issue right now. Actually this is out of scope and really a non-issue right now.
|
||||
|
||||
const Box = struct {
|
||||
|
||||
};
|
||||
|
||||
const Builtin = enum {
|
||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
What is this for? What is this for?
|
||||
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);
|
||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
Shorten to use Shorten to use `root.report_declare_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 {
|
||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
Should ideally be marked pub as is used on public interface for struct. Should ideally be marked pub as is used on public interface for struct.
|
||||
DeclarationExists,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
TODO functions should be unreachable and have a comment.