Closures, Higher-Order Functions, and Everything in Between #44
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
let test_param = "monkey wrench"
|
let test_param = "monkey wrench"
|
||||||
|
|
||||||
let printer = lambda (pfx, arbitrary):
|
let printer = lambda (pfx):
|
||||||
@print(test_param)
|
@print(test_param)
|
||||||
|
|
||||||
return lambda (msg):
|
return lambda (msg):
|
||||||
|
|
|
@ -197,7 +197,7 @@ pub const HexadecimalFormat = struct {
|
||||||
_ = writer;
|
_ = writer;
|
||||||
_ = value;
|
_ = 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.?]);
|
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)),
|
.symbol => |symbol| self.new_string(coral.io.slice_sentineled(@as(coral.io.Byte, 0), symbol)),
|
||||||
.string => value.acquire(),
|
.string => value.acquire(),
|
||||||
|
|
||||||
|
@ -658,7 +658,7 @@ pub const RuntimeEnv = struct {
|
||||||
var string = [_:0]coral.io.Byte{0} ** 64;
|
var string = [_:0]coral.io.Byte{0} ** 64;
|
||||||
var buffer = coral.io.FixedBuffer{.bytes = &string};
|
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],
|
.x = vector2[0],
|
||||||
.y = vector2[1],
|
.y = vector2[1],
|
||||||
});
|
});
|
||||||
|
@ -672,7 +672,7 @@ pub const RuntimeEnv = struct {
|
||||||
var string = [_:0]coral.io.Byte{0} ** 96;
|
var string = [_:0]coral.io.Byte{0} ** 96;
|
||||||
var buffer = coral.io.FixedBuffer{.bytes = &string};
|
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],
|
.x = vector3[0],
|
||||||
.y = vector3[1],
|
.y = vector3[1],
|
||||||
.z = vector3[2],
|
.z = vector3[2],
|
||||||
|
@ -688,11 +688,10 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_dynamic(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError![]coral.io.Byte {
|
pub fn unwrap_dynamic(self: *RuntimeEnv, value: *const RuntimeRef, typeinfo: *const Typeinfo) RuntimeError![]coral.io.Byte {
|
||||||
return switch (value.object().payload) {
|
return value.as_dynamic(typeinfo) orelse self.raise(error.TypeMismatch, "expected dynamic object, not {typename}", .{
|
||||||
.dynamic => |dynamic| dynamic.userdata(),
|
.typename = value.typename(),
|
||||||
else => self.raise(error.TypeMismatch, "expected fixed object")
|
});
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_float(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!Float {
|
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 {
|
pub fn unwrap_fixed(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!Fixed {
|
||||||
return value.as_fixed() orelse self.raise(error.TypeMismatch, "expected fixed, not {typename}", .{
|
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,
|
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 => |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)),
|
.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 {
|
pub fn get_field(env: *RuntimeEnv, indexable: *RuntimeRef, field: []const coral.io.Byte) RuntimeError!?*RuntimeRef {
|
||||||
const field_symbol = try env.new_symbol(field);
|
const field_symbol = try env.new_symbol(field);
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,6 @@ opcodes: OpcodeList,
|
||||||
constants: ConstList,
|
constants: ConstList,
|
||||||
bindings: []?*kym.RuntimeRef,
|
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 {
|
const Builtin = enum {
|
||||||
kayomn marked this conversation as resolved
Outdated
kayomn
commented
What is this for? What is this for?
|
|||||||
import,
|
import,
|
||||||
print,
|
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_false => coral.utf8.print_string(writer, "push false\n"),
|
||||||
|
|
||||||
.push_const => |push_const| print: {
|
.push_const => |push_const| print: {
|
||||||
if (push_const >= chunk.constants.values.len) {
|
try kym.assert(env, push_const < chunk.constants.values.len);
|
||||||
return env.raise(error.IllegalState, "invalid constant", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
const string_ref = try env.to_string(chunk.constants.values[push_const]);
|
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_false => try env.locals.push_one(try env.new_boolean(false)),
|
||||||
|
|
||||||
.push_const => |push_const| {
|
.push_const => |push_const| {
|
||||||
if (push_const >= self.constants.values.len) {
|
try kym.assert(env, push_const < self.constants.values.len);
|
||||||
return env.raise(error.IllegalState, "invalid constant", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
try env.locals.push_one(self.constants.values[push_const].acquire());
|
try env.locals.push_one(self.constants.values[push_const].acquire());
|
||||||
},
|
},
|
||||||
|
|
||||||
.push_local => |push_local| {
|
.push_local => |push_local| {
|
||||||
if (push_local >= (env.locals.values.len - frame.locals_top)) {
|
try kym.assert(env, push_local < (env.locals.values.len - frame.locals_top));
|
||||||
return env.raise(error.IllegalState, "invalid local", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (env.locals.values[frame.locals_top + push_local]) |local| {
|
if (env.locals.values[frame.locals_top + push_local]) |local| {
|
||||||
try env.locals.push_one(local.acquire());
|
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 => {
|
.push_top => {
|
||||||
const frame_locals = env.locals.values[frame.locals_top ..];
|
const frame_locals = env.locals.values[frame.locals_top ..];
|
||||||
|
|
||||||
if (frame_locals.len == 0) {
|
try kym.assert(env, frame_locals.len != 0);
|
||||||
return env.raise(error.IllegalState, "stack overflow", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame_locals[frame_locals.len - 1]) |local| {
|
if (frame_locals[frame_locals.len - 1]) |local| {
|
||||||
try env.locals.push_one(local.acquire());
|
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| {
|
.push_binding => |push_binding| {
|
||||||
if (push_binding > self.bindings.len) {
|
try kym.assert(env, push_binding <= self.bindings.len);
|
||||||
return env.raise(error.IllegalState, "binding out of range", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
try env.locals.push_one(if (self.bindings[push_binding]) |value| value.acquire() else null);
|
try env.locals.push_one(if (self.bindings[push_binding]) |value| value.acquire() else null);
|
||||||
},
|
},
|
||||||
|
|
||||||
.bind => |bind| {
|
.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 {
|
const chunk = @as(*Self, @ptrCast(@alignCast(try env.unwrap_dynamic(callable, typeinfo))));
|
||||||
return env.raise(error.IllegalState, "cannot bind objects to a {typename}", .{
|
|
||||||
.typename = lambda.typename(),
|
|
||||||
});
|
|
||||||
})));
|
|
||||||
|
|
||||||
chunk.bindings = try coral.io.allocate_many(env.allocator, bind, @as(?*kym.RuntimeRef, null));
|
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;
|
binding.* = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
try env.locals.push_one(lambda);
|
try env.locals.push_one(callable);
|
||||||
},
|
},
|
||||||
|
|
||||||
.push_builtin => |push_builtin| {
|
.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);
|
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;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +631,7 @@ fn syscall_vec3(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.R
|
||||||
|
|
||||||
pub const typeinfo = &kym.Typeinfo{
|
pub const typeinfo = &kym.Typeinfo{
|
||||||
.size = @sizeOf(Self),
|
.size = @sizeOf(Self),
|
||||||
.name = "func",
|
.name = "lambda",
|
||||||
.destruct = typeinfo_destruct,
|
.destruct = typeinfo_destruct,
|
||||||
.call = typeinfo_call,
|
.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});
|
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});
|
try self.chunk.opcodes.push_one(.{.push_binding = index});
|
||||||
|
|
||||||
if (is_declaration_boxed(declaration_get.declaration)) {
|
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});
|
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.chunk.opcodes.push_one(.{.push_binding = index});
|
||||||
try self.compile_expression(environment, declaration_set.assign, null);
|
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);
|
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);
|
var binding_index = @as(u8, 0);
|
||||||
|
|
||||||
while (binding_index < environment.capture_count) : (binding_index += 1) {
|
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;
|
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) {
|
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;
|
return binding_index;
|
||||||
|
|
|
@ -120,26 +120,12 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
.declaration = declare: {
|
.declaration = declare: {
|
||||||
if (is_constant) {
|
if (is_constant) {
|
||||||
break: declare environment.declare_constant(identifier) catch |declaration_error| {
|
break: declare environment.declare_constant(identifier) catch |declaration_error| {
|
||||||
return switch (declaration_error) {
|
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`.
|
|||||||
error.OutOfMemory => error.OutOfMemory,
|
|
||||||
|
|
||||||
error.DeclarationExists =>
|
|
||||||
root.report_error(stream, "declaration `{identifier}` already exists", .{
|
|
||||||
.identifier = identifier,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
break: declare environment.declare_variable(identifier) catch |declaration_error| {
|
break: declare environment.declare_variable(identifier) catch |declaration_error| {
|
||||||
return switch (declaration_error) {
|
return root.report_declare_error(stream, identifier, declaration_error);
|
||||||
error.OutOfMemory => error.OutOfMemory,
|
|
||||||
|
|
||||||
error.DeclarationExists =>
|
|
||||||
root.report_error(stream, "declaration `{identifier}` already exists", .{
|
|
||||||
.identifier = identifier,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -29,7 +29,7 @@ pub const Environment = struct {
|
||||||
capture_index: u8,
|
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,
|
DeclarationExists,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
TODO functions should be unreachable and have a comment.