Compare commits
No commits in common. "8f3a33a52b69c15419eac4fc21c4664662e0c275" and "03a8abc5dd17326dfa3a98f46934ac00330b9cdd" have entirely different histories.
8f3a33a52b
...
03a8abc5dd
|
@ -374,7 +374,7 @@ pub fn tag_of(comptime value: anytype) Tag(@TypeOf(value)) {
|
||||||
return @as(Tag(@TypeOf(value)), value);
|
return @as(Tag(@TypeOf(value)), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_null(buffer: []const u8) ?usize {
|
pub fn write_null(buffer: []const u8) ?usize {
|
||||||
return buffer.len;
|
return buffer.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ const tokens = @import("./kym/tokens.zig");
|
||||||
const tree = @import("./kym/tree.zig");
|
const tree = @import("./kym/tree.zig");
|
||||||
|
|
||||||
pub const Frame = struct {
|
pub const Frame = struct {
|
||||||
callable: *RuntimeRef,
|
name_stringable: *RuntimeRef,
|
||||||
arg_count: u8,
|
arg_count: u8,
|
||||||
locals_top: usize,
|
locals_top: usize,
|
||||||
|
|
||||||
|
@ -89,21 +89,21 @@ pub const RuntimeEnv = struct {
|
||||||
pub fn call(self: *RuntimeEnv, callable: *const RuntimeRef, args: []const *RuntimeRef) RuntimeError!?*RuntimeRef {
|
pub fn call(self: *RuntimeEnv, callable: *const RuntimeRef, args: []const *RuntimeRef) RuntimeError!?*RuntimeRef {
|
||||||
// TODO: Handle errors.
|
// TODO: Handle errors.
|
||||||
for (args) |arg| {
|
for (args) |arg| {
|
||||||
try self.locals.push_one(arg.acquire());
|
try self.locals.push_one(try self.acquire(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
const frame = try self.push_frame(callable, @intCast(args.len));
|
const frame = try self.push_frame(callable, args.len);
|
||||||
|
|
||||||
defer self.pop_frame();
|
defer self.pop_frame();
|
||||||
|
|
||||||
return self.call_frame(&frame);
|
return self.call_frame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_frame(self: *RuntimeEnv, frame: *const Frame) RuntimeError!?*RuntimeRef {
|
pub fn call_frame(self: *RuntimeEnv, callable: *const RuntimeRef, frame: Frame) RuntimeError!?*RuntimeRef {
|
||||||
return switch (frame.callable.object().payload) {
|
return switch (callable.object().payload) {
|
||||||
.syscall => |syscall| syscall(self, frame),
|
.syscall => |syscall| syscall(self, frame),
|
||||||
.dynamic => |dynamic| dynamic.typeinfo().call(self, dynamic.userdata(), frame),
|
.dynamic => |dynamic| dynamic.typeinfo().call(self, dynamic.userdata(), frame),
|
||||||
else => self.raise(error.TypeMismatch, "{typename} is not callable", .{.typename = frame.callable.typename()}),
|
else => self.raise(error.TypeMismatch, "{typename} is not callable", .{.typename = callable.typename()}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,17 +279,10 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_boxed(self: *RuntimeEnv, boxable: *RuntimeRef) RuntimeError!?*RuntimeRef {
|
|
||||||
return switch (boxable.object().payload) {
|
|
||||||
.boxed => |boxed| if (boxed) |boxed_value| boxed_value.acquire() else null,
|
|
||||||
else => self.raise(error.TypeMismatch, "{typename} is not boxable", .{.typename = boxable.typename()}),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn import(self: *RuntimeEnv, file_path: file.Path) RuntimeError!?*RuntimeRef {
|
pub fn import(self: *RuntimeEnv, file_path: file.Path) RuntimeError!?*RuntimeRef {
|
||||||
var callable = try self.new_dynamic(coral.io.bytes_of(&make_chunk: {
|
const file_name = file_path.get_string();
|
||||||
const file_name = file_path.get_string();
|
|
||||||
|
|
||||||
|
var chunk = make_chunk: {
|
||||||
const file_data =
|
const file_data =
|
||||||
(try file.allocate_and_load(self.allocator, self.options.import_access, file_path)) orelse {
|
(try file.allocate_and_load(self.allocator, self.options.import_access, file_path)) orelse {
|
||||||
return self.raise(error.BadOperation, "failed to open or read `{name}`", .{
|
return self.raise(error.BadOperation, "failed to open or read `{name}`", .{
|
||||||
|
@ -315,12 +308,26 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
break: make_chunk try Chunk.make(self, file_name, &root.environment);
|
const chunk_name = try self.new_string(file_name);
|
||||||
}), Chunk.typeinfo);
|
|
||||||
|
|
||||||
defer self.discard(callable);
|
defer self.discard(chunk_name);
|
||||||
|
|
||||||
return self.call(callable, &.{});
|
break: make_chunk try Chunk.make(self, chunk_name, &root.environment);
|
||||||
|
};
|
||||||
|
|
||||||
|
defer chunk.free(self);
|
||||||
|
|
||||||
|
return execute_chunk: {
|
||||||
|
const name = try self.new_string(file_name);
|
||||||
|
|
||||||
|
defer self.discard(name);
|
||||||
|
|
||||||
|
const frame = try self.push_frame(name, 0);
|
||||||
|
|
||||||
|
defer self.pop_frame();
|
||||||
|
|
||||||
|
break: execute_chunk chunk.execute(self, frame);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make(allocator: coral.io.Allocator, options: Options) coral.io.AllocationError!RuntimeEnv {
|
pub fn make(allocator: coral.io.Allocator, options: Options) coral.io.AllocationError!RuntimeEnv {
|
||||||
|
@ -374,14 +381,14 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_boolean(self: *RuntimeEnv, value: bool) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_boolean(self: *RuntimeEnv, value: bool) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = if (value) .true else .false,
|
.payload = if (value) .true else .false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_boxed(self: *RuntimeEnv, value: ?*const RuntimeRef) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_boxed(self: *RuntimeEnv, value: ?*const RuntimeRef) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.boxed = if (value) |ref| ref.acquire() else null},
|
.payload = .{.boxed = if (value) |ref| ref.acquire() else null},
|
||||||
|
@ -392,7 +399,7 @@ pub const RuntimeEnv = struct {
|
||||||
self: *RuntimeEnv,
|
self: *RuntimeEnv,
|
||||||
userdata: []const coral.io.Byte,
|
userdata: []const coral.io.Byte,
|
||||||
typeinfo: *const Typeinfo,
|
typeinfo: *const Typeinfo,
|
||||||
) coral.io.AllocationError!*RuntimeRef {
|
) RuntimeError!*RuntimeRef {
|
||||||
coral.debug.assert(userdata.len == typeinfo.size);
|
coral.debug.assert(userdata.len == typeinfo.size);
|
||||||
|
|
||||||
const dynamic = try self.allocator.reallocate(null, @sizeOf(usize) + typeinfo.size);
|
const dynamic = try self.allocator.reallocate(null, @sizeOf(usize) + typeinfo.size);
|
||||||
|
@ -408,21 +415,21 @@ pub const RuntimeEnv = struct {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_fixed(self: *RuntimeEnv, value: Fixed) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_fixed(self: *RuntimeEnv, value: Fixed) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.fixed = value},
|
.payload = .{.fixed = value},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_float(self: *RuntimeEnv, value: Float) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_float(self: *RuntimeEnv, value: Float) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.float = value},
|
.payload = .{.float = value},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_string(self: *RuntimeEnv, value: []const coral.io.Byte) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_string(self: *RuntimeEnv, value: []const coral.io.Byte) RuntimeError!*RuntimeRef {
|
||||||
if (value.len > coral.math.max_int(@typeInfo(Fixed).Int)) {
|
if (value.len > coral.math.max_int(@typeInfo(Fixed).Int)) {
|
||||||
return error.OutOfMemory;
|
return error.OutOfMemory;
|
||||||
}
|
}
|
||||||
|
@ -443,7 +450,7 @@ pub const RuntimeEnv = struct {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_symbol(self: *RuntimeEnv, value: []const coral.io.Byte) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_symbol(self: *RuntimeEnv, value: []const coral.io.Byte) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
|
|
||||||
|
@ -461,14 +468,14 @@ pub const RuntimeEnv = struct {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_syscall(self: *RuntimeEnv, value: *const Syscall) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_syscall(self: *RuntimeEnv, value: *const Syscall) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.syscall = value},
|
.payload = .{.syscall = value},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_table(self: *RuntimeEnv) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_table(self: *RuntimeEnv) RuntimeError!*RuntimeRef {
|
||||||
var table = Table.make(self);
|
var table = Table.make(self);
|
||||||
|
|
||||||
errdefer table.free(self);
|
errdefer table.free(self);
|
||||||
|
@ -476,14 +483,14 @@ pub const RuntimeEnv = struct {
|
||||||
return try self.new_dynamic(coral.io.bytes_of(&table), Table.typeinfo);
|
return try self.new_dynamic(coral.io.bytes_of(&table), Table.typeinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_vector2(self: *RuntimeEnv, x: f32, y: f32) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_vector2(self: *RuntimeEnv, x: f32, y: f32) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.vector2 = .{x, y}},
|
.payload = .{.vector2 = .{x, y}},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_vector3(self: *RuntimeEnv, x: f32, y: f32, z: f32) coral.io.AllocationError!*RuntimeRef {
|
pub fn new_vector3(self: *RuntimeEnv, x: f32, y: f32, z: f32) RuntimeError!*RuntimeRef {
|
||||||
return RuntimeRef.allocate(self.allocator, .{
|
return RuntimeRef.allocate(self.allocator, .{
|
||||||
.ref_count = 1,
|
.ref_count = 1,
|
||||||
.payload = .{.vector3 = .{x, y, z}},
|
.payload = .{.vector3 = .{x, y, z}},
|
||||||
|
@ -506,7 +513,7 @@ pub const RuntimeEnv = struct {
|
||||||
const popped_frame = self.frames.pop();
|
const popped_frame = self.frames.pop();
|
||||||
|
|
||||||
coral.debug.assert(popped_frame != null);
|
coral.debug.assert(popped_frame != null);
|
||||||
self.discard(popped_frame.?.callable);
|
self.discard(popped_frame.?.name_stringable);
|
||||||
|
|
||||||
var locals_to_pop = self.locals.values.len - popped_frame.?.locals_top;
|
var locals_to_pop = self.locals.values.len - popped_frame.?.locals_top;
|
||||||
|
|
||||||
|
@ -527,21 +534,9 @@ pub const RuntimeEnv = struct {
|
||||||
return self.locals.pop() orelse self.raise(error.IllegalState, "stack underflow", .{});
|
return self.locals.pop() orelse self.raise(error.IllegalState, "stack underflow", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_frame(self: *RuntimeEnv, callable: *const RuntimeRef, arg_count: u8) RuntimeError!Frame {
|
pub fn push_frame(self: *RuntimeEnv, name_stringable: *RuntimeRef, arg_count: u8) RuntimeError!Frame {
|
||||||
if (callable.as_dynamic(Chunk.typeinfo)) |chunk_userdata| {
|
|
||||||
const arity = @as(*Chunk, @ptrCast(@alignCast(chunk_userdata))).arity;
|
|
||||||
|
|
||||||
if (arg_count < arity) {
|
|
||||||
return self.raise(error.BadOperation, "expected `{expected}` {noun}, {provided} provided", .{
|
|
||||||
.expected = arity,
|
|
||||||
.provided = arg_count,
|
|
||||||
.noun = if (arity == 1) "argument" else "arguments",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const frame = Frame{
|
const frame = Frame{
|
||||||
.callable = callable.acquire(),
|
.name_stringable = name_stringable.acquire(),
|
||||||
.arg_count = arg_count,
|
.arg_count = arg_count,
|
||||||
.locals_top = self.locals.values.len - arg_count,
|
.locals_top = self.locals.values.len - arg_count,
|
||||||
};
|
};
|
||||||
|
@ -552,11 +547,13 @@ pub const RuntimeEnv = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, comptime format: []const coral.io.Byte, args: anytype) RuntimeError {
|
pub fn raise(self: *RuntimeEnv, error_value: RuntimeError, comptime format: []const coral.io.Byte, args: anytype) RuntimeError {
|
||||||
const formatted_message = try coral.utf8.alloc_formatted(self.allocator, format, args);
|
{
|
||||||
|
const formatted_message = try coral.utf8.alloc_formatted(self.allocator, format, args);
|
||||||
|
|
||||||
defer self.allocator.deallocate(formatted_message);
|
defer self.allocator.deallocate(formatted_message);
|
||||||
|
|
||||||
self.print_error(formatted_message);
|
self.print_error(formatted_message);
|
||||||
|
}
|
||||||
|
|
||||||
if (!self.frames.is_empty()) {
|
if (!self.frames.is_empty()) {
|
||||||
self.print_error("stack trace:");
|
self.print_error("stack trace:");
|
||||||
|
@ -566,38 +563,17 @@ pub const RuntimeEnv = struct {
|
||||||
while (remaining_frames != 0) {
|
while (remaining_frames != 0) {
|
||||||
remaining_frames -= 1;
|
remaining_frames -= 1;
|
||||||
|
|
||||||
const callable = self.frames.values[remaining_frames].callable;
|
const callable_string = try self.to_string(self.frames.values[remaining_frames].name_stringable);
|
||||||
const name = try self.to_string(callable);
|
|
||||||
|
|
||||||
defer self.discard(name);
|
defer self.discard(callable_string);
|
||||||
|
|
||||||
if (callable.as_dynamic(Chunk.typeinfo)) |chunk_userdata| {
|
self.print_error(get_name: {
|
||||||
const chunk = @as(*Chunk, @ptrCast(@alignCast(chunk_userdata)));
|
const string = callable_string.as_string();
|
||||||
|
|
||||||
const chunk_name = try coral.utf8.alloc_formatted(self.allocator, "{name}@{line}", .{
|
coral.debug.assert(string != null);
|
||||||
.name = get_name: {
|
|
||||||
const string = name.as_string();
|
|
||||||
|
|
||||||
coral.debug.assert(string != null);
|
break: get_name string.?;
|
||||||
|
});
|
||||||
break: get_name string.?;
|
|
||||||
},
|
|
||||||
|
|
||||||
.line = chunk.lines.values[chunk.cursor],
|
|
||||||
});
|
|
||||||
|
|
||||||
defer self.allocator.deallocate(chunk_name);
|
|
||||||
|
|
||||||
self.print_error(chunk_name);
|
|
||||||
} else {
|
|
||||||
self.print_error(get_name: {
|
|
||||||
const string = name.as_string();
|
|
||||||
|
|
||||||
coral.debug.assert(string != null);
|
|
||||||
|
|
||||||
break: get_name string.?;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,22 +590,6 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_boxed(self: *RuntimeEnv, boxable: *RuntimeRef, value: ?*const RuntimeRef) RuntimeError!void {
|
|
||||||
switch (boxable.object().payload) {
|
|
||||||
.boxed => |*boxed| {
|
|
||||||
if (boxed.*) |unboxed_value| {
|
|
||||||
self.discard(unboxed_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
boxed.* = if (value) |ref| ref.acquire() else null;
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.raise(error.TypeMismatch, "{typename} is not boxable", .{
|
|
||||||
.typename = boxable.typename(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sub(self: *RuntimeEnv, lhs: *const RuntimeRef, rhs: *const RuntimeRef) RuntimeError!*RuntimeRef {
|
pub fn sub(self: *RuntimeEnv, lhs: *const RuntimeRef, rhs: *const RuntimeRef) RuntimeError!*RuntimeRef {
|
||||||
return switch (lhs.object().payload) {
|
return switch (lhs.object().payload) {
|
||||||
.fixed => |lhs_fixed| switch (rhs.object().payload) {
|
.fixed => |lhs_fixed| switch (rhs.object().payload) {
|
||||||
|
@ -663,7 +623,7 @@ pub const RuntimeEnv = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(self: *RuntimeEnv, value: *const RuntimeRef) coral.io.AllocationError!*RuntimeRef {
|
pub fn to_string(self: *RuntimeEnv, value: *const RuntimeRef) RuntimeError!*RuntimeRef {
|
||||||
const decimal_format = coral.utf8.DecimalFormat.default;
|
const decimal_format = coral.utf8.DecimalFormat.default;
|
||||||
|
|
||||||
return switch (value.object().payload) {
|
return switch (value.object().payload) {
|
||||||
|
@ -723,8 +683,8 @@ pub const RuntimeEnv = struct {
|
||||||
break: convert self.new_string(string[0 .. length.?]);
|
break: convert self.new_string(string[0 .. length.?]);
|
||||||
},
|
},
|
||||||
|
|
||||||
.syscall => self.new_string("syscall"),
|
.syscall => self.new_string("<syscall>"),
|
||||||
.dynamic => |dynamic| dynamic.typeinfo().to_string(self, dynamic.userdata()),
|
.dynamic => self.new_string("<dynamic>"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,6 +793,13 @@ pub const RuntimeRef = opaque {
|
||||||
return @ptrCast(try coral.io.allocate_one(allocator, data));
|
return @ptrCast(try coral.io.allocate_one(allocator, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_boxed(self: *const RuntimeRef) ?*?*RuntimeRef {
|
||||||
|
return switch (self.object().payload) {
|
||||||
|
.boxed => |*boxed| boxed,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_dynamic(self: *const RuntimeRef, typeinfo: *const Typeinfo) ?[]u8 {
|
pub fn as_dynamic(self: *const RuntimeRef, typeinfo: *const Typeinfo) ?[]u8 {
|
||||||
return switch (self.object().payload) {
|
return switch (self.object().payload) {
|
||||||
.dynamic => |dynamic| if (dynamic.typeinfo() == typeinfo) dynamic.userdata() else null,
|
.dynamic => |dynamic| if (dynamic.typeinfo() == typeinfo) dynamic.userdata() else null,
|
||||||
|
@ -898,8 +865,8 @@ pub const RuntimeRef = opaque {
|
||||||
break: unbox boxed_value.equals(other);
|
break: unbox boxed_value.equals(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other.object().payload == .boxed) {
|
if (other.as_boxed()) |boxed_value| {
|
||||||
break: unbox other.object().payload.boxed == null;
|
break: unbox boxed_value.* == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
break: unbox false;
|
break: unbox false;
|
||||||
|
@ -984,18 +951,17 @@ pub const RuntimeRef = opaque {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Syscall = fn (env: *RuntimeEnv, frame: *const Frame) RuntimeError!?*RuntimeRef;
|
pub const Syscall = fn (env: *RuntimeEnv, frame: Frame) RuntimeError!?*RuntimeRef;
|
||||||
|
|
||||||
pub const Typeinfo = struct {
|
pub const Typeinfo = struct {
|
||||||
name: []const coral.io.Byte,
|
name: []const coral.io.Byte,
|
||||||
size: usize,
|
size: usize,
|
||||||
destruct: ?*const fn (env: *RuntimeEnv, userdata: []coral.io.Byte) void = null,
|
destruct: ?*const fn (env: *RuntimeEnv, userdata: []coral.io.Byte) void = null,
|
||||||
to_string: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte) coral.io.AllocationError!*RuntimeRef = default_to_string,
|
call: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, frame: Frame) RuntimeError!?*RuntimeRef = default_call,
|
||||||
call: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, frame: *const Frame) RuntimeError!?*RuntimeRef = default_call,
|
|
||||||
get: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, index: *const RuntimeRef) RuntimeError!?*RuntimeRef = default_get,
|
get: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, index: *const RuntimeRef) RuntimeError!?*RuntimeRef = default_get,
|
||||||
set: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, value: *const RuntimeRef, value: ?*const RuntimeRef) RuntimeError!void = default_set,
|
set: *const fn (env: *RuntimeEnv, userdata: []coral.io.Byte, value: *const RuntimeRef, value: ?*const RuntimeRef) RuntimeError!void = default_set,
|
||||||
|
|
||||||
fn default_call(env: *RuntimeEnv, _: []coral.io.Byte, _: *const Frame) RuntimeError!?*RuntimeRef {
|
fn default_call(env: *RuntimeEnv, _: []coral.io.Byte, _: Frame) RuntimeError!?*RuntimeRef {
|
||||||
return env.raise(error.BadOperation, "this dynamic object is not callable", .{});
|
return env.raise(error.BadOperation, "this dynamic object is not callable", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1006,10 +972,6 @@ pub const Typeinfo = struct {
|
||||||
fn default_set(env: *RuntimeEnv, _: []coral.io.Byte, _: *const RuntimeRef, _: ?*const RuntimeRef) RuntimeError!void {
|
fn default_set(env: *RuntimeEnv, _: []coral.io.Byte, _: *const RuntimeRef, _: ?*const RuntimeRef) RuntimeError!void {
|
||||||
return env.raise(error.BadOperation, "this dynamic object is not set-indexable", .{});
|
return env.raise(error.BadOperation, "this dynamic object is not set-indexable", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_to_string(env: *RuntimeEnv, _: []coral.io.Byte) coral.io.AllocationError!*RuntimeRef {
|
|
||||||
return env.new_string("{}");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn assert(env: *RuntimeEnv, condition: bool) RuntimeError!void {
|
pub fn assert(env: *RuntimeEnv, condition: bool) RuntimeError!void {
|
||||||
|
|
|
@ -2,6 +2,8 @@ const app = @import("../app.zig");
|
||||||
|
|
||||||
const Compiler = @import("./Compiler.zig");
|
const Compiler = @import("./Compiler.zig");
|
||||||
|
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
const coral = @import("coral");
|
const coral = @import("coral");
|
||||||
|
|
||||||
const file = @import("../file.zig");
|
const file = @import("../file.zig");
|
||||||
|
@ -13,8 +15,6 @@ const tree = @import("./tree.zig");
|
||||||
name: *kym.RuntimeRef,
|
name: *kym.RuntimeRef,
|
||||||
arity: u8,
|
arity: u8,
|
||||||
opcodes: OpcodeList,
|
opcodes: OpcodeList,
|
||||||
lines: LineList,
|
|
||||||
cursor: usize,
|
|
||||||
constants: ConstList,
|
constants: ConstList,
|
||||||
bindings: []?*kym.RuntimeRef,
|
bindings: []?*kym.RuntimeRef,
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ const Builtin = enum {
|
||||||
|
|
||||||
const ConstList = coral.list.Stack(*kym.RuntimeRef);
|
const ConstList = coral.list.Stack(*kym.RuntimeRef);
|
||||||
|
|
||||||
const LineList = coral.list.Stack(u32);
|
const OpcodeList = coral.list.Stack(union (enum) {
|
||||||
|
|
||||||
pub const Opcode = union (enum) {
|
|
||||||
ret,
|
ret,
|
||||||
pop,
|
pop,
|
||||||
push_nil,
|
push_nil,
|
||||||
|
@ -66,9 +64,7 @@ pub const Opcode = union (enum) {
|
||||||
|
|
||||||
jt: u32,
|
jt: u32,
|
||||||
jf: u32,
|
jf: u32,
|
||||||
};
|
});
|
||||||
|
|
||||||
const OpcodeList = coral.list.Stack(Opcode);
|
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
@ -103,26 +99,26 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
|
||||||
|
|
||||||
coral.debug.assert(string != null);
|
coral.debug.assert(string != null);
|
||||||
|
|
||||||
break: print coral.utf8.print_formatted(writer, "push const ({value})\n", .{.value = string.?});
|
break: print coral.utf8.print_formatted(writer, "push const <{value}>\n", .{.value = string.?});
|
||||||
},
|
},
|
||||||
|
|
||||||
.push_local => |push_local| coral.utf8.print_formatted(writer, "push local ({local})\n", .{
|
.push_local => |push_local| coral.utf8.print_formatted(writer, "push local <{local}>\n", .{
|
||||||
.local = push_local,
|
.local = push_local,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.push_top => coral.utf8.print_string(writer, "push top\n"),
|
.push_top => coral.utf8.print_string(writer, "push top\n"),
|
||||||
|
|
||||||
.push_table => |push_table| coral.utf8.print_formatted(writer, "push table ({count})\n", .{
|
.push_table => |push_table| coral.utf8.print_formatted(writer, "push table <{count}>\n", .{
|
||||||
.count = push_table,
|
.count = push_table,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.push_boxed => coral.utf8.print_string(writer, "push boxed\n"),
|
.push_boxed => coral.utf8.print_string(writer, "push boxed\n"),
|
||||||
|
|
||||||
.push_binding => |push_binding| coral.utf8.print_formatted(writer, "push binding ({binding})\n", .{
|
.push_binding => |push_binding| coral.utf8.print_formatted(writer, "push binding <{binding}>\n", .{
|
||||||
.binding = push_binding,
|
.binding = push_binding,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.push_builtin => |push_builtin| coral.utf8.print_formatted(writer, "push builtin ({builtin})\n", .{
|
.push_builtin => |push_builtin| coral.utf8.print_formatted(writer, "push builtin <{builtin}>\n", .{
|
||||||
.builtin = switch (push_builtin) {
|
.builtin = switch (push_builtin) {
|
||||||
.import => "import",
|
.import => "import",
|
||||||
.print => "print",
|
.print => "print",
|
||||||
|
@ -131,11 +127,11 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.bind => |bind| coral.utf8.print_formatted(writer, "bind ({count})\n", .{
|
.bind => |bind| coral.utf8.print_formatted(writer, "bind <{count}>\n", .{
|
||||||
.count = bind,
|
.count = bind,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
.set_local => |local_set| coral.utf8.print_formatted(writer, "set local ({local})\n", .{
|
.set_local => |local_set| coral.utf8.print_formatted(writer, "set local <{local}>\n", .{
|
||||||
.local = local_set,
|
.local = local_set,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -143,7 +139,7 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
|
||||||
.set_box => coral.utf8.print_string(writer, "set box\n"),
|
.set_box => coral.utf8.print_string(writer, "set box\n"),
|
||||||
.get_dynamic => coral.utf8.print_string(writer, "get dynamic\n"),
|
.get_dynamic => coral.utf8.print_string(writer, "get dynamic\n"),
|
||||||
.set_dynamic => coral.utf8.print_string(writer, "set dynamic\n"),
|
.set_dynamic => coral.utf8.print_string(writer, "set dynamic\n"),
|
||||||
.call => |call| coral.utf8.print_formatted(writer, "call ({count})\n", .{.count = call}),
|
.call => |call| coral.utf8.print_formatted(writer, "call <{count}>\n", .{.count = call}),
|
||||||
.not => coral.utf8.print_string(writer, "not\n"),
|
.not => coral.utf8.print_string(writer, "not\n"),
|
||||||
.neg => coral.utf8.print_string(writer, "neg\n"),
|
.neg => coral.utf8.print_string(writer, "neg\n"),
|
||||||
.add => coral.utf8.print_string(writer, "add\n"),
|
.add => coral.utf8.print_string(writer, "add\n"),
|
||||||
|
@ -155,19 +151,19 @@ pub fn dump(chunk: Self, env: *kym.RuntimeEnv) kym.RuntimeError!*kym.RuntimeRef
|
||||||
.clt => coral.utf8.print_string(writer, "clt\n"),
|
.clt => coral.utf8.print_string(writer, "clt\n"),
|
||||||
.cge => coral.utf8.print_string(writer, "cge\n"),
|
.cge => coral.utf8.print_string(writer, "cge\n"),
|
||||||
.cle => coral.utf8.print_string(writer, "cle\n"),
|
.cle => coral.utf8.print_string(writer, "cle\n"),
|
||||||
.jf => |jf| coral.utf8.print_formatted(writer, "jf ({instruction})\n", .{.instruction = jf}),
|
.jf => |jf| coral.utf8.print_formatted(writer, "jf <{instruction}>\n", .{.instruction = jf}),
|
||||||
.jt => |jt| coral.utf8.print_formatted(writer, "jt ({instruction})\n", .{.instruction = jt}),
|
.jt => |jt| coral.utf8.print_formatted(writer, "jt <{instruction}>\n", .{.instruction = jt}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return env.new_string(buffer.values);
|
return env.new_string(buffer.values);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
pub fn execute(self: Self, env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
self.cursor = 0;
|
var opcode_cursor = @as(u32, 0);
|
||||||
|
|
||||||
while (self.cursor < self.opcodes.values.len) : (self.cursor += 1) {
|
while (opcode_cursor < self.opcodes.values.len) : (opcode_cursor += 1) {
|
||||||
switch (self.opcodes.values[self.cursor]) {
|
switch (self.opcodes.values[opcode_cursor]) {
|
||||||
.ret => break,
|
.ret => break,
|
||||||
|
|
||||||
.pop => {
|
.pop => {
|
||||||
|
@ -310,24 +306,27 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
|
||||||
|
|
||||||
defer env.discard(box);
|
defer env.discard(box);
|
||||||
|
|
||||||
if (try env.get_boxed(box)) |unboxed| {
|
const boxed = box.as_boxed() orelse {
|
||||||
errdefer env.discard(unboxed);
|
return env.raise(error.TypeMismatch, "{typename} is not unboxable", .{.typename = box.typename()});
|
||||||
|
};
|
||||||
|
|
||||||
try env.locals.push_one(unboxed);
|
try env.locals.push_one(if (boxed.*) |value| value.acquire() else null);
|
||||||
} else {
|
|
||||||
try env.locals.push_one(null);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.set_box => {
|
.set_box => {
|
||||||
const box = try env.expect(try env.pop_local());
|
const box = try env.expect(try env.pop_local());
|
||||||
|
|
||||||
defer env.discard(box);
|
errdefer env.discard(box);
|
||||||
|
|
||||||
const value = try env.expect(try env.pop_local());
|
const boxed = box.as_boxed() orelse {
|
||||||
|
return env.raise(error.TypeMismatch, "{typename} is not unboxable", .{.typename = box.typename()});
|
||||||
|
};
|
||||||
|
|
||||||
defer env.discard(box);
|
if (boxed.*) |value| {
|
||||||
try env.set_boxed(box, value);
|
env.discard(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
boxed.* = box;
|
||||||
},
|
},
|
||||||
|
|
||||||
.get_dynamic => {
|
.get_dynamic => {
|
||||||
|
@ -380,7 +379,7 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
|
||||||
|
|
||||||
defer env.pop_frame();
|
defer env.pop_frame();
|
||||||
|
|
||||||
break: call try env.call_frame(&call_frame);
|
break: call try env.call_frame(callable, call_frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
errdefer {
|
errdefer {
|
||||||
|
@ -533,10 +532,10 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
|
||||||
defer env.discard(condition);
|
defer env.discard(condition);
|
||||||
|
|
||||||
if (!condition.is_truthy()) {
|
if (!condition.is_truthy()) {
|
||||||
self.cursor = jf;
|
opcode_cursor = jf;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.cursor = jf;
|
opcode_cursor = jf;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -545,7 +544,7 @@ pub fn execute(self: *Self, env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.R
|
||||||
defer env.discard(condition);
|
defer env.discard(condition);
|
||||||
|
|
||||||
if (condition.is_truthy()) {
|
if (condition.is_truthy()) {
|
||||||
self.cursor = jt;
|
opcode_cursor = jt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -577,15 +576,13 @@ pub fn free(self: *Self, env: *kym.RuntimeEnv) void {
|
||||||
self.bindings = &.{};
|
self.bindings = &.{};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *const tree.Environment) kym.RuntimeError!Self {
|
pub fn make(env: *kym.RuntimeEnv, name: *const kym.RuntimeRef, environment: *const tree.Environment) kym.RuntimeError!Self {
|
||||||
var chunk = Self{
|
var chunk = Self{
|
||||||
.name = try env.new_symbol(name),
|
.name = name.acquire(),
|
||||||
.opcodes = OpcodeList.make(env.allocator),
|
.opcodes = OpcodeList.make(env.allocator),
|
||||||
.constants = ConstList.make(env.allocator),
|
.constants = ConstList.make(env.allocator),
|
||||||
.lines = LineList.make(env.allocator),
|
|
||||||
.bindings = &.{},
|
.bindings = &.{},
|
||||||
.arity = environment.argument_count,
|
.arity = environment.argument_count,
|
||||||
.cursor = 0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var compiler = Compiler{
|
var compiler = Compiler{
|
||||||
|
@ -598,17 +595,17 @@ pub fn make(env: *kym.RuntimeEnv, name: []const coral.io.Byte, environment: *con
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syscall_import(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
fn syscall_import(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
return env.import(file.Path.from(&.{try env.unwrap_string(try frame.expect_arg(env, 0))}));
|
return env.import(file.Path.from(&.{try env.unwrap_string(try frame.expect_arg(env, 0))}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syscall_print(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
fn syscall_print(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
env.print(try env.unwrap_string(try frame.expect_arg(env, 0)));
|
env.print(try env.unwrap_string(try frame.expect_arg(env, 0)));
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syscall_vec2(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
fn syscall_vec2(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
|
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
|
||||||
|
|
||||||
if (frame.has_arg(env, 1)) |y| {
|
if (frame.has_arg(env, 1)) |y| {
|
||||||
|
@ -618,7 +615,7 @@ fn syscall_vec2(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!
|
||||||
return env.new_vector2(x, x);
|
return env.new_vector2(x, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn syscall_vec3(env: *kym.RuntimeEnv, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
fn syscall_vec3(env: *kym.RuntimeEnv, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
|
const x = @as(f32, @floatCast(try env.unwrap_float(try frame.expect_arg(env, 0))));
|
||||||
|
|
||||||
if (frame.has_arg(env, 1)) |y| {
|
if (frame.has_arg(env, 1)) |y| {
|
||||||
|
@ -637,22 +634,22 @@ pub const typeinfo = &kym.Typeinfo{
|
||||||
.name = "lambda",
|
.name = "lambda",
|
||||||
.destruct = typeinfo_destruct,
|
.destruct = typeinfo_destruct,
|
||||||
.call = typeinfo_call,
|
.call = typeinfo_call,
|
||||||
.to_string = typeinfo_to_string,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn typeinfo_call(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, frame: *const kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
fn typeinfo_call(env: *kym.RuntimeEnv, userdata: []coral.io.Byte, frame: kym.Frame) kym.RuntimeError!?*kym.RuntimeRef {
|
||||||
return @as(*Self, @ptrCast(@alignCast(userdata))).execute(env, frame);
|
const chunk = @as(*Self, @ptrCast(@alignCast(userdata)));
|
||||||
|
|
||||||
|
if (frame.arg_count < chunk.arity) {
|
||||||
|
return env.raise(error.BadOperation, "expected `{expected_count}` {noun}, {provided_count} provided", .{
|
||||||
|
.expected_count = frame.arg_count,
|
||||||
|
.provided_count = chunk.arity,
|
||||||
|
.noun = if (frame.arg_count == 1) "argument" else "arguments",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunk.execute(env, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void {
|
fn typeinfo_destruct(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) void {
|
||||||
@as(*Self, @ptrCast(@alignCast(userdata))).free(env);
|
@as(*Self, @ptrCast(@alignCast(userdata))).free(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typeinfo_to_string(env: *kym.RuntimeEnv, userdata: []coral.io.Byte) coral.io.AllocationError!*kym.RuntimeRef {
|
|
||||||
return env.to_string(@as(*Self, @ptrCast(@alignCast(userdata))).name);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(self: *Self, line: u32, opcode: Opcode) coral.io.AllocationError!void {
|
|
||||||
try self.opcodes.push_one(opcode);
|
|
||||||
try self.lines.push_one(line);
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,30 +37,30 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (expression.kind) {
|
switch (expression.kind) {
|
||||||
.nil_literal => try self.chunk.write(expression.line, .push_nil),
|
.nil_literal => try self.chunk.opcodes.push_one(.push_nil),
|
||||||
.true_literal => try self.chunk.write(expression.line, .push_true),
|
.true_literal => try self.chunk.opcodes.push_one(.push_true),
|
||||||
.false_literal => try self.chunk.write(expression.line, .push_false),
|
.false_literal => try self.chunk.opcodes.push_one(.push_false),
|
||||||
|
|
||||||
.number_literal => |literal| {
|
.number_literal => |literal| {
|
||||||
for (literal) |codepoint| {
|
for (literal) |codepoint| {
|
||||||
if (codepoint == '.') {
|
if (codepoint == '.') {
|
||||||
return self.chunk.write(expression.line, .{
|
return self.chunk.opcodes.push_one(.{
|
||||||
.push_const = try self.declare_float(number_format.parse(literal, kym.Float) orelse unreachable),
|
.push_const = try self.declare_float(number_format.parse(literal, kym.Float) orelse unreachable),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.chunk.write(expression.line, .{
|
try self.chunk.opcodes.push_one(.{
|
||||||
.push_const = try self.declare_fixed(number_format.parse(literal, kym.Fixed) orelse unreachable),
|
.push_const = try self.declare_fixed(number_format.parse(literal, kym.Fixed) orelse unreachable),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
.string_literal => |literal| {
|
.string_literal => |literal| {
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_string(literal)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_string(literal)});
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_literal => |literal| {
|
.symbol_literal => |literal| {
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(literal)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_symbol(literal)});
|
||||||
},
|
},
|
||||||
|
|
||||||
.table_construct => |table_construct| {
|
.table_construct => |table_construct| {
|
||||||
|
@ -71,13 +71,13 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
try self.compile_expression(environment, entry, null);
|
try self.compile_expression(environment, entry, null);
|
||||||
|
|
||||||
if (entry.kind != .key_value) {
|
if (entry.kind != .key_value) {
|
||||||
try self.chunk.write(expression.line, .push_top);
|
try self.chunk.opcodes.push_one(.push_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
field_count += 1;
|
field_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.chunk.write(expression.line, .{.push_table = field_count});
|
try self.chunk.opcodes.push_one(.{.push_table = field_count});
|
||||||
},
|
},
|
||||||
|
|
||||||
.key_value => |key_value| {
|
.key_value => |key_value| {
|
||||||
|
@ -86,12 +86,16 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
},
|
},
|
||||||
|
|
||||||
.lambda_construct => |lambda_construct| {
|
.lambda_construct => |lambda_construct| {
|
||||||
var chunk = try Chunk.make(self.env, name orelse "<lambda>", lambda_construct.environment);
|
const anonymous_chunk_name = try self.env.new_symbol(name orelse "<lambda>");
|
||||||
|
|
||||||
|
defer self.env.discard(anonymous_chunk_name);
|
||||||
|
|
||||||
|
var chunk = try Chunk.make(self.env, anonymous_chunk_name, lambda_construct.environment);
|
||||||
|
|
||||||
errdefer chunk.free(self.env);
|
errdefer chunk.free(self.env);
|
||||||
|
|
||||||
if (lambda_construct.environment.capture_count == 0) {
|
if (lambda_construct.environment.capture_count == 0) {
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_chunk(chunk)});
|
||||||
} else {
|
} else {
|
||||||
const lambda_captures = lambda_construct.environment.get_captures();
|
const lambda_captures = lambda_construct.environment.get_captures();
|
||||||
var index = lambda_captures.len;
|
var index = lambda_captures.len;
|
||||||
|
@ -99,14 +103,14 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
while (index != 0) {
|
while (index != 0) {
|
||||||
index -= 1;
|
index -= 1;
|
||||||
|
|
||||||
try self.chunk.write(expression.line, switch (lambda_captures[index]) {
|
try self.chunk.opcodes.push_one(switch (lambda_captures[index]) {
|
||||||
.declaration_index => |declaration_index| .{.push_local = declaration_index},
|
.declaration_index => |declaration_index| .{.push_local = declaration_index},
|
||||||
.capture_index => |capture_index| .{.push_binding = capture_index},
|
.capture_index => |capture_index| .{.push_binding = capture_index},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_chunk(chunk)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_chunk(chunk)});
|
||||||
try self.chunk.write(expression.line, .{.bind = lambda_construct.environment.capture_count});
|
try self.chunk.opcodes.push_one(.{.bind = lambda_construct.environment.capture_count});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -114,7 +118,7 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
try self.compile_expression(environment, binary_op.lhs_operand, null);
|
try self.compile_expression(environment, binary_op.lhs_operand, null);
|
||||||
try self.compile_expression(environment, binary_op.rhs_operand, null);
|
try self.compile_expression(environment, binary_op.rhs_operand, null);
|
||||||
|
|
||||||
try self.chunk.write(expression.line, switch (binary_op.operation) {
|
try self.chunk.opcodes.push_one(switch (binary_op.operation) {
|
||||||
.addition => .add,
|
.addition => .add,
|
||||||
.subtraction => .sub,
|
.subtraction => .sub,
|
||||||
.multiplication => .mul,
|
.multiplication => .mul,
|
||||||
|
@ -130,7 +134,7 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
.unary_op => |unary_op| {
|
.unary_op => |unary_op| {
|
||||||
try self.compile_expression(environment, unary_op.operand, null);
|
try self.compile_expression(environment, unary_op.operand, null);
|
||||||
|
|
||||||
try self.chunk.write(expression.line, switch (unary_op.operation) {
|
try self.chunk.opcodes.push_one(switch (unary_op.operation) {
|
||||||
.boolean_negation => .not,
|
.boolean_negation => .not,
|
||||||
.numeric_negation => .neg,
|
.numeric_negation => .neg,
|
||||||
});
|
});
|
||||||
|
@ -140,25 +144,25 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
const argument_count = try self.compile_argument(environment, invoke.argument);
|
const argument_count = try self.compile_argument(environment, invoke.argument);
|
||||||
|
|
||||||
try self.compile_expression(environment, invoke.object, null);
|
try self.compile_expression(environment, invoke.object, null);
|
||||||
try self.chunk.write(expression.line, .{.call = argument_count});
|
try self.chunk.opcodes.push_one(.{.call = argument_count});
|
||||||
},
|
},
|
||||||
|
|
||||||
.group => |group| try self.compile_expression(environment, group, null),
|
.group => |group| try self.compile_expression(environment, group, null),
|
||||||
.import_builtin => try self.chunk.write(expression.line, .{.push_builtin = .import}),
|
.import_builtin => try self.chunk.opcodes.push_one(.{.push_builtin = .import}),
|
||||||
.print_builtin => try self.chunk.write(expression.line, .{.push_builtin = .print}),
|
.print_builtin => try self.chunk.opcodes.push_one(.{.push_builtin = .print}),
|
||||||
.vec2_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec2}),
|
.vec2_builtin => try self.chunk.opcodes.push_one(.{.push_builtin = .vec2}),
|
||||||
.vec3_builtin => try self.chunk.write(expression.line, .{.push_builtin = .vec3}),
|
.vec3_builtin => try self.chunk.opcodes.push_one(.{.push_builtin = .vec3}),
|
||||||
|
|
||||||
.declaration_get => |declaration_get| {
|
.declaration_get => |declaration_get| {
|
||||||
if (get_local_index(environment, declaration_get.declaration)) |index| {
|
if (get_local_index(environment, declaration_get.declaration)) |index| {
|
||||||
return self.chunk.write(expression.line, .{.push_local = index});
|
return self.chunk.opcodes.push_one(.{.push_local = index});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try self.get_binding_index(environment, declaration_get.declaration)) |index| {
|
if (try self.get_binding_index(environment, declaration_get.declaration)) |index| {
|
||||||
try self.chunk.write(expression.line, .{.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)) {
|
||||||
try self.chunk.write(expression.line, .get_box);
|
try self.chunk.opcodes.push_one(.get_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -171,15 +175,15 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
if (get_local_index(environment, declaration_set.declaration)) |index| {
|
if (get_local_index(environment, declaration_set.declaration)) |index| {
|
||||||
try self.compile_expression(environment, declaration_set.assign, null);
|
try self.compile_expression(environment, declaration_set.assign, null);
|
||||||
|
|
||||||
return self.chunk.write(expression.line, .{.set_local = index});
|
return self.chunk.opcodes.push_one(.{.set_local = index});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try self.get_binding_index(environment, declaration_set.declaration)) |index| {
|
if (try self.get_binding_index(environment, declaration_set.declaration)) |index| {
|
||||||
try self.chunk.write(expression.line, .{.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);
|
||||||
|
|
||||||
if (is_declaration_boxed(declaration_set.declaration)) {
|
if (is_declaration_boxed(declaration_set.declaration)) {
|
||||||
try self.chunk.write(expression.line, .set_box);
|
try self.chunk.opcodes.push_one(.set_box);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -190,28 +194,28 @@ fn compile_expression(self: Self, environment: *const tree.Environment, expressi
|
||||||
|
|
||||||
.field_get => |field_get| {
|
.field_get => |field_get| {
|
||||||
try self.compile_expression(environment, field_get.object, null);
|
try self.compile_expression(environment, field_get.object, null);
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_get.identifier)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_symbol(field_get.identifier)});
|
||||||
try self.chunk.write(expression.line, .get_dynamic);
|
try self.chunk.opcodes.push_one(.get_dynamic);
|
||||||
},
|
},
|
||||||
|
|
||||||
.field_set => |field_set| {
|
.field_set => |field_set| {
|
||||||
try self.compile_expression(environment, field_set.object, null);
|
try self.compile_expression(environment, field_set.object, null);
|
||||||
try self.chunk.write(expression.line, .{.push_const = try self.declare_symbol(field_set.identifier)});
|
try self.chunk.opcodes.push_one(.{.push_const = try self.declare_symbol(field_set.identifier)});
|
||||||
try self.compile_expression(environment, field_set.assign, null);
|
try self.compile_expression(environment, field_set.assign, null);
|
||||||
try self.chunk.write(expression.line, .set_dynamic);
|
try self.chunk.opcodes.push_one(.set_dynamic);
|
||||||
},
|
},
|
||||||
|
|
||||||
.subscript_get => |subscript_get| {
|
.subscript_get => |subscript_get| {
|
||||||
try self.compile_expression(environment, subscript_get.object, null);
|
try self.compile_expression(environment, subscript_get.object, null);
|
||||||
try self.compile_expression(environment, subscript_get.index, null);
|
try self.compile_expression(environment, subscript_get.index, null);
|
||||||
try self.chunk.write(expression.line, .get_dynamic);
|
try self.chunk.opcodes.push_one(.get_dynamic);
|
||||||
},
|
},
|
||||||
|
|
||||||
.subscript_set => |subscript_set| {
|
.subscript_set => |subscript_set| {
|
||||||
try self.compile_expression(environment, subscript_set.object, null);
|
try self.compile_expression(environment, subscript_set.object, null);
|
||||||
try self.compile_expression(environment, subscript_set.index, null);
|
try self.compile_expression(environment, subscript_set.index, null);
|
||||||
try self.compile_expression(environment, subscript_set.assign, null);
|
try self.compile_expression(environment, subscript_set.assign, null);
|
||||||
try self.chunk.write(expression.line, .set_dynamic);
|
try self.chunk.opcodes.push_one(.set_dynamic);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +225,7 @@ pub fn compile_environment(self: Self, environment: *const tree.Environment) kym
|
||||||
const last_statement = try self.compile_statement(environment, statement);
|
const last_statement = try self.compile_statement(environment, statement);
|
||||||
|
|
||||||
if (last_statement.kind != .@"return") {
|
if (last_statement.kind != .@"return") {
|
||||||
try self.chunk.write(last_statement.line, .push_nil);
|
try self.chunk.opcodes.push_one(.push_nil);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,16 +239,16 @@ fn compile_statement(self: Self, environment: *const tree.Environment, initial_s
|
||||||
if (@"return".returned_expression) |expression| {
|
if (@"return".returned_expression) |expression| {
|
||||||
try self.compile_expression(environment, expression, null);
|
try self.compile_expression(environment, expression, null);
|
||||||
} else {
|
} else {
|
||||||
try self.chunk.write(current_statement.line, .push_nil);
|
try self.chunk.opcodes.push_one(.push_nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Omit ret calls at ends of chunk.
|
// TODO: Omit ret calls at ends of chunk.
|
||||||
try self.chunk.write(current_statement.line, .ret);
|
try self.chunk.opcodes.push_one(.ret);
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"while" => |@"while"| {
|
.@"while" => |@"while"| {
|
||||||
try self.compile_expression(environment, @"while".loop_expression, null);
|
try self.compile_expression(environment, @"while".loop_expression, null);
|
||||||
try self.chunk.write(current_statement.line, .{.jf = 0});
|
try self.chunk.opcodes.push_one(.{.jf = 0});
|
||||||
|
|
||||||
const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1));
|
const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1));
|
||||||
|
|
||||||
|
@ -252,12 +256,12 @@ fn compile_statement(self: Self, environment: *const tree.Environment, initial_s
|
||||||
self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1);
|
self.chunk.opcodes.values[origin_index].jf = @intCast(self.chunk.opcodes.values.len - 1);
|
||||||
|
|
||||||
try self.compile_expression(environment, @"while".loop_expression, null);
|
try self.compile_expression(environment, @"while".loop_expression, null);
|
||||||
try self.chunk.write(current_statement.line, .{.jt = origin_index});
|
try self.chunk.opcodes.push_one(.{.jt = origin_index});
|
||||||
},
|
},
|
||||||
|
|
||||||
.@"if" => |@"if"| {
|
.@"if" => |@"if"| {
|
||||||
try self.compile_expression(environment, @"if".then_expression, null);
|
try self.compile_expression(environment, @"if".then_expression, null);
|
||||||
try self.chunk.write(current_statement.line, .{.jf = 0});
|
try self.chunk.opcodes.push_one(.{.jf = 0});
|
||||||
|
|
||||||
const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1));
|
const origin_index = @as(u32, @intCast(self.chunk.opcodes.values.len - 1));
|
||||||
|
|
||||||
|
@ -273,7 +277,7 @@ fn compile_statement(self: Self, environment: *const tree.Environment, initial_s
|
||||||
try self.compile_expression(environment, declare.initial_expression, declare.declaration.identifier);
|
try self.compile_expression(environment, declare.initial_expression, declare.declaration.identifier);
|
||||||
|
|
||||||
if (is_declaration_boxed(declare.declaration)) {
|
if (is_declaration_boxed(declare.declaration)) {
|
||||||
try self.chunk.write(current_statement.line, .push_boxed);
|
try self.chunk.opcodes.push_one(.push_boxed);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -281,7 +285,7 @@ fn compile_statement(self: Self, environment: *const tree.Environment, initial_s
|
||||||
try self.compile_expression(environment, top_expression, null);
|
try self.compile_expression(environment, top_expression, null);
|
||||||
|
|
||||||
if (top_expression.kind == .invoke) {
|
if (top_expression.kind == .invoke) {
|
||||||
try self.chunk.write(current_statement.line, .pop);
|
try self.chunk.opcodes.push_one(.pop);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ const tokens = @import("./tokens.zig");
|
||||||
const tree = @import("./tree.zig");
|
const tree = @import("./tree.zig");
|
||||||
|
|
||||||
next: ?*const Self = null,
|
next: ?*const Self = null,
|
||||||
line: u32,
|
|
||||||
|
|
||||||
kind: union (enum) {
|
kind: union (enum) {
|
||||||
nil_literal,
|
nil_literal,
|
||||||
|
@ -81,8 +80,6 @@ pub const BinaryOp = struct {
|
||||||
const unnecessary_temp = expression;
|
const unnecessary_temp = expression;
|
||||||
|
|
||||||
expression = try root.create_expr(.{
|
expression = try root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.binary_op = .{
|
.binary_op = .{
|
||||||
.rhs_operand = try parse_next(root, stream, environment),
|
.rhs_operand = try parse_next(root, stream, environment),
|
||||||
|
@ -176,8 +173,6 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = switch (expression.kind) {
|
.kind = switch (expression.kind) {
|
||||||
.declaration_get => |declaration_get| convert: {
|
.declaration_get => |declaration_get| convert: {
|
||||||
if (declaration_get.declaration.is.readonly) {
|
if (declaration_get.declaration.is.readonly) {
|
||||||
|
@ -244,7 +239,7 @@ fn parse_factor(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
const unnecessary_temp = expression;
|
const unnecessary_temp = expression;
|
||||||
|
|
||||||
expression = try root.create_expr(.{
|
expression = try root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.field_get = .{
|
.field_get = .{
|
||||||
|
@ -268,7 +263,7 @@ fn parse_factor(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
const unnecessary_temp = expression;
|
const unnecessary_temp = expression;
|
||||||
|
|
||||||
expression = try root.create_expr(.{
|
expression = try root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.subscript_get = .{
|
.subscript_get = .{
|
||||||
|
@ -286,8 +281,6 @@ fn parse_factor(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_paren_left => {
|
.symbol_paren_left => {
|
||||||
const lines_stepped = stream.lines_stepped;
|
|
||||||
|
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
var first_argument = @as(?*Self, null);
|
var first_argument = @as(?*Self, null);
|
||||||
|
@ -317,7 +310,7 @@ fn parse_factor(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
const unnecessary_temp = expression;
|
const unnecessary_temp = expression;
|
||||||
|
|
||||||
expression = try root.create_expr(.{
|
expression = try root.create_expr(.{
|
||||||
.line = lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.invoke = .{
|
.invoke = .{
|
||||||
|
@ -348,55 +341,37 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
|
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.group = expression}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.group = expression},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_nil => {
|
.keyword_nil => {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .nil_literal});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .nil_literal,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_true => {
|
.keyword_true => {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .true_literal});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .true_literal,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_false => {
|
.keyword_false => {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .false_literal});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .false_literal,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.number => |value| {
|
.number => |value| {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.number_literal = value}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.number_literal = value},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.string => |value| {
|
.string => |value| {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.string_literal = value}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.string_literal = value},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_at => {
|
.symbol_at => {
|
||||||
|
@ -410,31 +385,19 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
if (coral.io.are_equal(identifier, "import")) {
|
if (coral.io.are_equal(identifier, "import")) {
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .import_builtin});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .import_builtin,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coral.io.are_equal(identifier, "print")) {
|
if (coral.io.are_equal(identifier, "print")) {
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .print_builtin});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .print_builtin,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coral.io.are_equal(identifier, "vec2")) {
|
if (coral.io.are_equal(identifier, "vec2")) {
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .vec2_builtin});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .vec2_builtin,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coral.io.are_equal(identifier, "vec3")) {
|
if (coral.io.are_equal(identifier, "vec3")) {
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .vec3_builtin});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .vec3_builtin,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.report_error(stream, "unexpected identifier after `@`", .{});
|
return root.report_error(stream, "unexpected identifier after `@`", .{});
|
||||||
|
@ -450,18 +413,13 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
|
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.symbol_literal = identifier}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.symbol_literal = identifier},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.identifier => |identifier| {
|
.identifier => |identifier| {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.declaration_get = .{
|
.declaration_get = .{
|
||||||
.declaration = (try environment.resolve_declaration(identifier)) orelse {
|
.declaration = (try environment.resolve_declaration(identifier)) orelse {
|
||||||
|
@ -528,20 +486,14 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
|
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.lambda_construct = .{.environment = lambda_environment}}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.lambda_construct = .{.environment = lambda_environment}},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_brace_left => {
|
.symbol_brace_left => {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
if (stream.token == .symbol_brace_right) {
|
if (stream.token == .symbol_brace_right) {
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.table_construct = .{.entry = null}}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.table_construct = .{.entry = null}},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const first_entry = try parse_table_entry(root, stream, environment);
|
const first_entry = try parse_table_entry(root, stream, environment);
|
||||||
|
@ -566,17 +518,14 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
|
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{.kind = .{.table_construct = .{.entry = first_entry}}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.table_construct = .{.entry = first_entry}},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_minus => {
|
.symbol_minus => {
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.unary_op = .{
|
.unary_op = .{
|
||||||
|
@ -591,7 +540,7 @@ fn parse_operand(root: *tree.Root, stream: *tokens.Stream, environment: *tree.En
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.unary_op = .{
|
.unary_op = .{
|
||||||
|
@ -625,16 +574,10 @@ fn parse_table_entry(root: *tree.Root, stream: *tokens.Stream, environment: *tre
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.key_value = .{
|
.key_value = .{
|
||||||
.value = try parse(root, stream, environment),
|
.value = try parse(root, stream, environment),
|
||||||
|
.key = try root.create_expr(.{.kind = .{.symbol_literal = field}}),
|
||||||
.key = try root.create_expr(.{
|
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.symbol_literal = field},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -658,8 +601,6 @@ fn parse_table_entry(root: *tree.Root, stream: *tokens.Stream, environment: *tre
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_expr(.{
|
return root.create_expr(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.key_value = .{
|
.key_value = .{
|
||||||
.value = try parse(root, stream, environment),
|
.value = try parse(root, stream, environment),
|
||||||
|
|
|
@ -7,7 +7,6 @@ const tokens = @import("./tokens.zig");
|
||||||
const tree = @import("./tree.zig");
|
const tree = @import("./tree.zig");
|
||||||
|
|
||||||
next: ?*const Self = null,
|
next: ?*const Self = null,
|
||||||
line: u32,
|
|
||||||
|
|
||||||
kind: union (enum) {
|
kind: union (enum) {
|
||||||
top_expression: *const Expr,
|
top_expression: *const Expr,
|
||||||
|
@ -46,7 +45,6 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
|
|
||||||
if (stream.token != .end and stream.token != .newline) {
|
if (stream.token != .end and stream.token != .newline) {
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.@"return" = .{.returned_expression = try Expr.parse(root, stream, environment)}},
|
.kind = .{.@"return" = .{.returned_expression = try Expr.parse(root, stream, environment)}},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,10 +53,7 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
return root.report_error(stream, "expected end or newline after return statement", .{});
|
return root.report_error(stream, "expected end or newline after return statement", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{.kind = .{.@"return" = .{.returned_expression = null}}});
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.@"return" = .{.returned_expression = null}},
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_while => {
|
.keyword_while => {
|
||||||
|
@ -88,8 +83,6 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
}
|
}
|
||||||
|
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.@"while" = .{
|
.@"while" = .{
|
||||||
.loop = first_statement,
|
.loop = first_statement,
|
||||||
|
@ -120,8 +113,6 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.declare = .{
|
.declare = .{
|
||||||
.initial_expression = try Expr.parse(root, stream, environment),
|
.initial_expression = try Expr.parse(root, stream, environment),
|
||||||
|
@ -144,10 +135,7 @@ pub fn parse(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Enviro
|
||||||
|
|
||||||
.keyword_if => return parse_branch(root, stream, environment),
|
.keyword_if => return parse_branch(root, stream, environment),
|
||||||
|
|
||||||
else => return root.create_stmt(.{
|
else => return root.create_stmt(.{.kind = .{.top_expression = try Expr.parse(root, stream, environment)}}),
|
||||||
.line = stream.lines_stepped,
|
|
||||||
.kind = .{.top_expression = try Expr.parse(root, stream, environment)},
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +159,7 @@ fn parse_branch(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.@"if" = .{
|
.@"if" = .{
|
||||||
|
@ -205,7 +193,7 @@ fn parse_branch(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
stream.skip_newlines();
|
stream.skip_newlines();
|
||||||
|
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.@"if" = .{
|
.@"if" = .{
|
||||||
|
@ -219,7 +207,7 @@ fn parse_branch(root: *tree.Root, stream: *tokens.Stream, environment: *tree.Env
|
||||||
|
|
||||||
.keyword_elif => {
|
.keyword_elif => {
|
||||||
return root.create_stmt(.{
|
return root.create_stmt(.{
|
||||||
.line = stream.lines_stepped,
|
.next = null,
|
||||||
|
|
||||||
.kind = .{
|
.kind = .{
|
||||||
.@"if" = .{
|
.@"if" = .{
|
||||||
|
|
|
@ -103,7 +103,7 @@ pub const Token = union(enum) {
|
||||||
|
|
||||||
pub const Stream = struct {
|
pub const Stream = struct {
|
||||||
source: []const coral.io.Byte,
|
source: []const coral.io.Byte,
|
||||||
lines_stepped: u32 = 1,
|
lines_stepped: usize = 1,
|
||||||
token: Token = .newline,
|
token: Token = .newline,
|
||||||
|
|
||||||
pub fn skip_newlines(self: *Stream) void {
|
pub fn skip_newlines(self: *Stream) void {
|
||||||
|
|
Loading…
Reference in New Issue