Compare commits
4 Commits
b6f7ab1edb
...
1f8f3fd9dc
Author | SHA1 | Date | |
---|---|---|---|
1f8f3fd9dc | |||
4ee0bcab67 | |||
9435348877 | |||
3173dd52fe |
@ -5,7 +5,7 @@ test = {
|
|||||||
.message = "don't you lecture me with your 30 dollar scripting language"
|
.message = "don't you lecture me with your 30 dollar scripting language"
|
||||||
}
|
}
|
||||||
|
|
||||||
# test.message = "game is loading"
|
test.message = "game is loading"
|
||||||
|
|
||||||
@log_info(test.message)
|
@log_info(test.message)
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ pub const Any = union (enum) {
|
|||||||
float: Float,
|
float: Float,
|
||||||
string: []const coral.io.Byte,
|
string: []const coral.io.Byte,
|
||||||
symbol: []const coral.io.Byte,
|
symbol: []const coral.io.Byte,
|
||||||
|
lambda,
|
||||||
dynamic: *const DynamicObject,
|
dynamic: *const DynamicObject,
|
||||||
|
|
||||||
pub fn expect_dynamic(self: Any) ?*const DynamicObject {
|
pub fn expect_dynamic(self: Any) ?*const DynamicObject {
|
||||||
@ -76,22 +77,20 @@ pub const Method = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const RuntimeEnv = struct {
|
pub const RuntimeEnv = struct {
|
||||||
interned_symbols: SymbolTable,
|
interned_symbols: RefTable,
|
||||||
allocator: coral.io.Allocator,
|
allocator: coral.io.Allocator,
|
||||||
error_handler: ErrorHandler,
|
error_handler: ErrorHandler,
|
||||||
syscallers: SyscallerTable,
|
syscallables: RefTable,
|
||||||
local_refs: RefStack,
|
local_refs: RefStack,
|
||||||
frames: FrameStack,
|
frames: FrameStack,
|
||||||
ref_values: RefSlab,
|
ref_values: RefSlab,
|
||||||
|
|
||||||
const FrameStack = coral.list.Stack(Frame);
|
const FrameStack = coral.list.Stack(Frame);
|
||||||
|
|
||||||
const SymbolTable = coral.map.StringTable(*RuntimeRef);
|
|
||||||
|
|
||||||
const SyscallerTable = coral.map.StringTable(Caller);
|
|
||||||
|
|
||||||
const RefStack = coral.list.Stack(?*RuntimeRef);
|
const RefStack = coral.list.Stack(?*RuntimeRef);
|
||||||
|
|
||||||
|
const RefTable = coral.map.StringTable(*RuntimeRef);
|
||||||
|
|
||||||
const RefSlab = coral.map.Slab(struct {
|
const RefSlab = coral.map.Slab(struct {
|
||||||
ref_count: usize,
|
ref_count: usize,
|
||||||
|
|
||||||
@ -102,15 +101,11 @@ pub const RuntimeEnv = struct {
|
|||||||
fixed: Fixed,
|
fixed: Fixed,
|
||||||
string: []coral.io.Byte,
|
string: []coral.io.Byte,
|
||||||
symbol: []coral.io.Byte,
|
symbol: []coral.io.Byte,
|
||||||
|
lambda: Caller,
|
||||||
dynamic: *DynamicObject,
|
dynamic: *DynamicObject,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
pub const Syscall = struct {
|
|
||||||
name: []const coral.io.Byte,
|
|
||||||
caller: Caller,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn acquire(self: *RuntimeEnv, ref: *const RuntimeRef) *RuntimeRef {
|
pub fn acquire(self: *RuntimeEnv, ref: *const RuntimeRef) *RuntimeRef {
|
||||||
const key = @intFromPtr(ref);
|
const key = @intFromPtr(ref);
|
||||||
var ref_data = self.ref_values.remove(key);
|
var ref_data = self.ref_values.remove(key);
|
||||||
@ -124,15 +119,9 @@ pub const RuntimeEnv = struct {
|
|||||||
return @ptrFromInt(key);
|
return @ptrFromInt(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bind_syscalls(self: *RuntimeEnv, syscalls: []const Syscall) RuntimeError!void {
|
|
||||||
for (syscalls) |syscall| {
|
|
||||||
_ = try self.syscallers.replace(syscall.name, syscall.caller);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call(
|
pub fn call(
|
||||||
self: *RuntimeEnv,
|
self: *RuntimeEnv,
|
||||||
caller: Caller,
|
callable_ref: *const RuntimeRef,
|
||||||
arg_count: u8,
|
arg_count: u8,
|
||||||
name: []const coral.io.Byte,
|
name: []const coral.io.Byte,
|
||||||
) RuntimeError!?*RuntimeRef {
|
) RuntimeError!?*RuntimeRef {
|
||||||
@ -154,16 +143,26 @@ pub const RuntimeEnv = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return caller.invoke(self);
|
return switch ((self.ref_values.lookup(@intFromPtr(callable_ref)) orelse unreachable).object) {
|
||||||
}
|
.lambda => |lambda| lambda.invoke(self),
|
||||||
|
|
||||||
|
.dynamic => |dynamic| dynamic.typeinfo.call(.{
|
||||||
|
.env = self,
|
||||||
|
.userdata = dynamic.userdata,
|
||||||
|
}),
|
||||||
|
|
||||||
pub fn callable(self: *RuntimeEnv, ref: *const RuntimeRef) RuntimeError!Caller {
|
|
||||||
return switch ((self.ref_values.lookup(@intFromPtr(ref)) orelse unreachable).object) {
|
|
||||||
.dynamic => |dynamic| Caller.bind(DynamicObject, dynamic, DynamicObject.call),
|
|
||||||
else => self.raise(error.TypeMismatch, "object is not callable"),
|
else => self.raise(error.TypeMismatch, "object is not callable"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bind_syscaller(self: *RuntimeEnv, comptime name: []const coral.io.Byte, caller: Caller) RuntimeError!void {
|
||||||
|
const lambda_ref = try self.new_lambda(caller);
|
||||||
|
|
||||||
|
if (try self.syscallables.replace(name, self.acquire(lambda_ref))) |replaced_entry| {
|
||||||
|
self.discard(replaced_entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn discard(self: *RuntimeEnv, ref: ?*RuntimeRef) void {
|
pub fn discard(self: *RuntimeEnv, ref: ?*RuntimeRef) void {
|
||||||
const key = @intFromPtr(ref orelse return);
|
const key = @intFromPtr(ref orelse return);
|
||||||
var ref_data = self.ref_values.remove(key) orelse unreachable;
|
var ref_data = self.ref_values.remove(key) orelse unreachable;
|
||||||
@ -174,7 +173,7 @@ pub const RuntimeEnv = struct {
|
|||||||
|
|
||||||
if (ref_data.ref_count == 0) {
|
if (ref_data.ref_count == 0) {
|
||||||
switch (ref_data.object) {
|
switch (ref_data.object) {
|
||||||
.false, .true, .float, .fixed => {},
|
.false, .true, .float, .fixed, .lambda => {},
|
||||||
.string => |string| self.allocator.deallocate(string),
|
.string => |string| self.allocator.deallocate(string),
|
||||||
.symbol => |symbol| self.allocator.deallocate(symbol),
|
.symbol => |symbol| self.allocator.deallocate(symbol),
|
||||||
|
|
||||||
@ -225,7 +224,11 @@ pub const RuntimeEnv = struct {
|
|||||||
|
|
||||||
try chunk.compile_ast(ast);
|
try chunk.compile_ast(ast);
|
||||||
|
|
||||||
return self.call(chunk.as_caller(), 0, name);
|
const chunk_ref = try self.new_lambda(chunk.as_caller());
|
||||||
|
|
||||||
|
defer self.discard(chunk_ref);
|
||||||
|
|
||||||
|
return self.call(chunk_ref, 0, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free(self: *RuntimeEnv) void {
|
pub fn free(self: *RuntimeEnv) void {
|
||||||
@ -241,9 +244,17 @@ pub const RuntimeEnv = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var iterable = self.syscallables.as_iterable();
|
||||||
|
|
||||||
|
while (iterable.next()) |entry| {
|
||||||
|
self.discard(entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.frames.free();
|
self.frames.free();
|
||||||
self.local_refs.free();
|
self.local_refs.free();
|
||||||
self.syscallers.free();
|
self.syscallables.free();
|
||||||
self.ref_values.free();
|
self.ref_values.free();
|
||||||
self.interned_symbols.free();
|
self.interned_symbols.free();
|
||||||
}
|
}
|
||||||
@ -267,6 +278,14 @@ pub const RuntimeEnv = struct {
|
|||||||
return self.acquire(self.local_refs.values[local] orelse return null);
|
return self.acquire(self.local_refs.values[local] orelse return null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_syscallable(self: *RuntimeEnv, name: []const coral.io.Byte) ?*RuntimeRef {
|
||||||
|
if (self.syscallables.lookup(name)) |system_ref| {
|
||||||
|
return self.acquire(system_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pop_local(self: *RuntimeEnv) RuntimeError!?*RuntimeRef {
|
pub fn pop_local(self: *RuntimeEnv) RuntimeError!?*RuntimeRef {
|
||||||
return self.local_refs.pop() orelse self.raise(error.IllegalState, "stack underflow");
|
return self.local_refs.pop() orelse self.raise(error.IllegalState, "stack underflow");
|
||||||
}
|
}
|
||||||
@ -300,8 +319,8 @@ pub const RuntimeEnv = struct {
|
|||||||
.local_refs = RefStack.make(allocator),
|
.local_refs = RefStack.make(allocator),
|
||||||
.ref_values = RefSlab.make(allocator),
|
.ref_values = RefSlab.make(allocator),
|
||||||
.frames = FrameStack.make(allocator),
|
.frames = FrameStack.make(allocator),
|
||||||
.syscallers = SyscallerTable.make(allocator, .{}),
|
.syscallables = RefTable.make(allocator, .{}),
|
||||||
.interned_symbols = SymbolTable.make(allocator, .{}),
|
.interned_symbols = RefTable.make(allocator, .{}),
|
||||||
.error_handler = error_handler,
|
.error_handler = error_handler,
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
};
|
};
|
||||||
@ -350,6 +369,13 @@ pub const RuntimeEnv = struct {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_lambda(self: *RuntimeEnv, caller: Caller) RuntimeError!*RuntimeRef {
|
||||||
|
return @ptrFromInt(try self.ref_values.insert(.{
|
||||||
|
.ref_count = 1,
|
||||||
|
.object = .{.lambda = caller},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_string(self: *RuntimeEnv, string_data: []const coral.io.Byte) RuntimeError!*RuntimeRef {
|
pub fn new_string(self: *RuntimeEnv, string_data: []const coral.io.Byte) RuntimeError!*RuntimeRef {
|
||||||
const string_copy = try coral.io.allocate_copy(self.allocator, string_data);
|
const string_copy = try coral.io.allocate_copy(self.allocator, string_data);
|
||||||
|
|
||||||
@ -405,10 +431,6 @@ pub const RuntimeEnv = struct {
|
|||||||
}, index_ref, value_ref);
|
}, index_ref, value_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn syscallable(self: *RuntimeEnv, name: []const coral.io.Byte) RuntimeError!Caller {
|
|
||||||
return self.syscallers.lookup(name) orelse self.raise(error.BadOperation, "attempt to get undefined syscall");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unbox(self: *RuntimeEnv, ref: *const RuntimeRef) Any {
|
pub fn unbox(self: *RuntimeEnv, ref: *const RuntimeRef) Any {
|
||||||
return switch ((self.ref_values.lookup(@intFromPtr(ref)) orelse unreachable).object) {
|
return switch ((self.ref_values.lookup(@intFromPtr(ref)) orelse unreachable).object) {
|
||||||
.false => .{.boolean = false},
|
.false => .{.boolean = false},
|
||||||
@ -417,6 +439,7 @@ pub const RuntimeEnv = struct {
|
|||||||
.float => |float| .{.float = float},
|
.float => |float| .{.float = float},
|
||||||
.string => |string| .{.string = string},
|
.string => |string| .{.string = string},
|
||||||
.symbol => |symbol| .{.symbol = symbol},
|
.symbol => |symbol| .{.symbol = symbol},
|
||||||
|
.lambda => .lambda,
|
||||||
.dynamic => |dynamic| .{.dynamic = dynamic},
|
.dynamic => |dynamic| .{.dynamic = dynamic},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -484,7 +507,8 @@ pub fn hash(env: *RuntimeEnv, ref: *const RuntimeRef) usize {
|
|||||||
.fixed => 0,
|
.fixed => 0,
|
||||||
.string => |string| coral.io.djb2_hash(@typeInfo(usize).Int, string),
|
.string => |string| coral.io.djb2_hash(@typeInfo(usize).Int, string),
|
||||||
.symbol => 0,
|
.symbol => 0,
|
||||||
.dynamic => |dynamic| @intFromPtr(dynamic),
|
.lambda => 0,
|
||||||
|
.dynamic => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,6 +544,7 @@ pub fn test_difference(
|
|||||||
else => env.raise(error.TypeMismatch, "right-hand object is not comparable with symbol objects"),
|
else => env.raise(error.TypeMismatch, "right-hand object is not comparable with symbol objects"),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.lambda => env.raise(error.TypeMismatch, "lambda objects are not comparable"),
|
||||||
.dynamic => env.raise(error.TypeMismatch, "dynamic objects are not comparable"),
|
.dynamic => env.raise(error.TypeMismatch, "dynamic objects are not comparable"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -555,10 +580,7 @@ pub fn test_equality(env: *RuntimeEnv, lhs_ref: *const RuntimeRef, rhs_ref: *con
|
|||||||
else => false,
|
else => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
.dynamic => |lhs_dynamic| switch (env.unbox(rhs_ref)) {
|
else => lhs_ref == rhs_ref,
|
||||||
.dynamic => |rhs_dynamic| rhs_dynamic == lhs_dynamic,
|
|
||||||
else => false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ pub const Expression = union (enum) {
|
|||||||
symbol_literal: []const coral.io.Byte,
|
symbol_literal: []const coral.io.Byte,
|
||||||
table_literal: TableLiteral,
|
table_literal: TableLiteral,
|
||||||
grouped_expression: *Expression,
|
grouped_expression: *Expression,
|
||||||
resolve_local: []const coral.io.Byte,
|
get_system: []const coral.io.Byte,
|
||||||
|
get_local: []const coral.io.Byte,
|
||||||
|
set_local: []const coral.io.Byte,
|
||||||
|
|
||||||
get_field: struct {
|
get_field: struct {
|
||||||
object_expression: *Expression,
|
object_expression: *Expression,
|
||||||
@ -31,11 +33,6 @@ pub const Expression = union (enum) {
|
|||||||
value_expression: *Expression,
|
value_expression: *Expression,
|
||||||
},
|
},
|
||||||
|
|
||||||
call_system: struct {
|
|
||||||
identifier: []const coral.io.Byte,
|
|
||||||
argument_expressions: List,
|
|
||||||
},
|
|
||||||
|
|
||||||
binary_operation: struct {
|
binary_operation: struct {
|
||||||
operator: BinaryOperator,
|
operator: BinaryOperator,
|
||||||
lhs_expression: *Expression,
|
lhs_expression: *Expression,
|
||||||
@ -47,6 +44,11 @@ pub const Expression = union (enum) {
|
|||||||
expression: *Expression,
|
expression: *Expression,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
call: struct {
|
||||||
|
object_expression: *Expression,
|
||||||
|
argument_expressions: List,
|
||||||
|
},
|
||||||
|
|
||||||
pub const BinaryOperator = enum {
|
pub const BinaryOperator = enum {
|
||||||
addition,
|
addition,
|
||||||
subtraction,
|
subtraction,
|
||||||
@ -91,18 +93,11 @@ pub const ParseError = error {
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub const Statement = union (enum) {
|
pub const Statement = union (enum) {
|
||||||
return_nothing,
|
@"return": struct {
|
||||||
return_expression: Expression,
|
expression: ?Expression,
|
||||||
|
|
||||||
assign_local: struct {
|
|
||||||
identifier: []const coral.io.Byte,
|
|
||||||
expression: Expression,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
call_system: struct {
|
expression: Expression,
|
||||||
identifier: []const coral.io.Byte,
|
|
||||||
argument_expressions: Expression.List,
|
|
||||||
},
|
|
||||||
|
|
||||||
const List = coral.list.Stack(Statement);
|
const List = coral.list.Stack(Statement);
|
||||||
};
|
};
|
||||||
@ -186,106 +181,58 @@ pub fn list_statements(self: Self) []const Statement {
|
|||||||
pub fn parse(self: *Self, data: []const coral.io.Byte) ParseError!void {
|
pub fn parse(self: *Self, data: []const coral.io.Byte) ParseError!void {
|
||||||
self.tokenizer = .{.source = data};
|
self.tokenizer = .{.source = data};
|
||||||
|
|
||||||
const allocator = self.arena.as_allocator();
|
|
||||||
var has_returned = false;
|
var has_returned = false;
|
||||||
|
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (self.tokenizer.token) {
|
try self.statements.push_one(parse_statement: {
|
||||||
.end => return,
|
switch (self.tokenizer.token) {
|
||||||
|
.end => return,
|
||||||
|
|
||||||
.keyword_return => {
|
.keyword_return => {
|
||||||
if (has_returned) {
|
if (has_returned) {
|
||||||
return self.report("multiple returns in function scope but expected only one");
|
return self.report("multiple returns in function scope but expected only one");
|
||||||
}
|
}
|
||||||
|
|
||||||
try self.statements.push_one(get_statement: {
|
|
||||||
self.tokenizer.step();
|
self.tokenizer.step();
|
||||||
|
|
||||||
if (self.tokenizer.token != .end and self.tokenizer.token != .newline) {
|
if (self.tokenizer.token != .end and self.tokenizer.token != .newline) {
|
||||||
break: get_statement .{.return_expression = try self.parse_expression()};
|
break: parse_statement .{
|
||||||
|
.@"return" = .{
|
||||||
|
.expression = try self.parse_expression(),
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.tokenizer.token != .end and self.tokenizer.token != .newline) {
|
if (self.tokenizer.token != .end and self.tokenizer.token != .newline) {
|
||||||
return self.report("expected end or newline after return statement");
|
return self.report("expected end or newline after return statement");
|
||||||
}
|
}
|
||||||
|
|
||||||
break: get_statement .return_nothing;
|
has_returned = true;
|
||||||
});
|
|
||||||
|
|
||||||
has_returned = true;
|
break: parse_statement .{
|
||||||
},
|
.@"return" = .{
|
||||||
|
.expression = null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
.identifier => |identifier| {
|
else => {
|
||||||
self.tokenizer.step();
|
break: parse_statement .{
|
||||||
|
.expression = try self.parse_expression()
|
||||||
switch (self.tokenizer.token) {
|
};
|
||||||
.end, .newline => return self.report("statement has no effect"),
|
},
|
||||||
|
}
|
||||||
.symbol_equals => {
|
});
|
||||||
self.tokenizer.step();
|
|
||||||
|
|
||||||
if (self.tokenizer.token == .end) {
|
|
||||||
return self.report("expected expression after `=`");
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.statements.push_one(.{
|
|
||||||
.assign_local = .{
|
|
||||||
.expression = try self.parse_expression(),
|
|
||||||
.identifier = identifier,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.report("expected `=` after local"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.special_identifier => |identifier| {
|
|
||||||
self.tokenizer.step();
|
|
||||||
|
|
||||||
switch (self.tokenizer.token) {
|
|
||||||
.end, .newline => return self.report("system call is missing arguments"),
|
|
||||||
|
|
||||||
.symbol_paren_left => {
|
|
||||||
self.tokenizer.step();
|
|
||||||
|
|
||||||
var expressions_list = Expression.List.make(allocator);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (self.tokenizer.token == .symbol_paren_right) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
try expressions_list.push_one(try self.parse_expression());
|
|
||||||
|
|
||||||
switch (self.tokenizer.token) {
|
|
||||||
.symbol_comma => continue,
|
|
||||||
.symbol_paren_right => break,
|
|
||||||
else => return self.report("expected `)` or argument after `(`"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tokenizer.skip_newlines();
|
|
||||||
|
|
||||||
try self.statements.push_one(.{
|
|
||||||
.call_system = .{
|
|
||||||
.argument_expressions = expressions_list,
|
|
||||||
.identifier = identifier,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.report("expected `=` after local"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.report("invalid statement"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parse_additive = binary_operation_parser(parse_equality, &.{
|
||||||
|
.addition,
|
||||||
|
.subtraction,
|
||||||
|
});
|
||||||
|
|
||||||
const parse_comparison = binary_operation_parser(parse_term, &.{
|
const parse_comparison = binary_operation_parser(parse_term, &.{
|
||||||
.greater_than_comparison,
|
.greater_than_comparison,
|
||||||
.greater_equals_comparison,
|
.greater_equals_comparison,
|
||||||
@ -297,15 +244,39 @@ const parse_equality = binary_operation_parser(parse_comparison, &.{
|
|||||||
.equals_comparison,
|
.equals_comparison,
|
||||||
});
|
});
|
||||||
|
|
||||||
const parse_expression = binary_operation_parser(parse_equality, &.{
|
pub fn parse_expression(self: *Self) ParseError!Expression {
|
||||||
.addition,
|
const allocator = self.arena.as_allocator();
|
||||||
.subtraction,
|
const expression = try parse_additive(self);
|
||||||
});
|
|
||||||
|
if (self.tokenizer.token == .symbol_equals) {
|
||||||
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
|
if (self.tokenizer.token == .end) {
|
||||||
|
return self.report("expected assignment after `=`");
|
||||||
|
}
|
||||||
|
|
||||||
|
return switch (expression) {
|
||||||
|
.get_local => |get_local| .{.set_local = get_local},
|
||||||
|
|
||||||
|
.get_field => |get_field| .{
|
||||||
|
.set_field = .{
|
||||||
|
.object_expression = get_field.object_expression,
|
||||||
|
.identifier = get_field.identifier,
|
||||||
|
.value_expression = try coral.io.allocate_one(allocator, try self.parse_expression()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
else => self.report("expected local or field on left-hand side of expression"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_factor(self: *Self) ParseError!Expression {
|
fn parse_factor(self: *Self) ParseError!Expression {
|
||||||
const allocator = self.arena.as_allocator();
|
const allocator = self.arena.as_allocator();
|
||||||
|
|
||||||
var expression = @as(Expression, get: {
|
var expression = @as(Expression, parse: {
|
||||||
switch (self.tokenizer.token) {
|
switch (self.tokenizer.token) {
|
||||||
.symbol_paren_left => {
|
.symbol_paren_left => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
@ -322,88 +293,49 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
|
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get Expression{.grouped_expression = try coral.io.allocate_one(allocator, expression)};
|
break: parse .{.grouped_expression = try coral.io.allocate_one(allocator, expression)};
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_nil => {
|
.keyword_nil => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .nil_literal;
|
break: parse .nil_literal;
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_true => {
|
.keyword_true => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .true_literal;
|
break: parse .true_literal;
|
||||||
},
|
},
|
||||||
|
|
||||||
.keyword_false => {
|
.keyword_false => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .false_literal;
|
break: parse .false_literal;
|
||||||
},
|
},
|
||||||
|
|
||||||
.number => |value| {
|
.number => |value| {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .{.number_literal = value};
|
break: parse .{.number_literal = value};
|
||||||
},
|
},
|
||||||
|
|
||||||
.string => |value| {
|
.string => |value| {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .{.string_literal = value};
|
break: parse .{.string_literal = value};
|
||||||
},
|
|
||||||
|
|
||||||
.special_identifier => |identifier| {
|
|
||||||
self.tokenizer.skip_newlines();
|
|
||||||
|
|
||||||
var expression_list = Expression.List.make(allocator);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
switch (self.tokenizer.token) {
|
|
||||||
.end => return self.report("expected expression or `)` after `(`"),
|
|
||||||
|
|
||||||
.symbol_paren_right => {
|
|
||||||
self.tokenizer.skip_newlines();
|
|
||||||
|
|
||||||
break: get .{
|
|
||||||
.call_system = .{
|
|
||||||
.identifier = identifier,
|
|
||||||
.argument_expressions = expression_list,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
else => {
|
|
||||||
try expression_list.push_one(try self.parse_expression());
|
|
||||||
|
|
||||||
switch (self.tokenizer.token) {
|
|
||||||
.end => return self.report("expected `,` or `)` after argument"),
|
|
||||||
.symbol_comma => continue,
|
|
||||||
|
|
||||||
.symbol_paren_right => {
|
|
||||||
self.tokenizer.skip_newlines();
|
|
||||||
|
|
||||||
break: get .{
|
|
||||||
.call_system = .{
|
|
||||||
.identifier = identifier,
|
|
||||||
.argument_expressions = expression_list,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.report("expected `,` or `)` after argument"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.identifier => |identifier| {
|
.identifier => |identifier| {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .{.resolve_local = identifier};
|
break: parse .{.get_local = identifier};
|
||||||
|
},
|
||||||
|
|
||||||
|
.system_identifier => |system_identifier| {
|
||||||
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
|
break: parse .{.get_system = system_identifier};
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_brace_left => {
|
.symbol_brace_left => {
|
||||||
@ -416,7 +348,7 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
.symbol_brace_right => {
|
.symbol_brace_right => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .{.table_literal = table_literal};
|
break: parse .{.table_literal = table_literal};
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_bracket_left => {
|
.symbol_bracket_left => {
|
||||||
@ -458,7 +390,7 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
.symbol_brace_right => {
|
.symbol_brace_right => {
|
||||||
self.tokenizer.skip_newlines();
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
break: get .{.table_literal = table_literal};
|
break: parse .{.table_literal = table_literal};
|
||||||
},
|
},
|
||||||
|
|
||||||
else => return self.report("expected `,` or `}` after expression"),
|
else => return self.report("expected `,` or `}` after expression"),
|
||||||
@ -477,7 +409,7 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
return self.report("expected expression after numeric negation (`-`)");
|
return self.report("expected expression after numeric negation (`-`)");
|
||||||
}
|
}
|
||||||
|
|
||||||
break: get .{
|
break: parse .{
|
||||||
.unary_operation = .{
|
.unary_operation = .{
|
||||||
.expression = try coral.io.allocate_one(allocator, try self.parse_factor()),
|
.expression = try coral.io.allocate_one(allocator, try self.parse_factor()),
|
||||||
.operator = .numeric_negation,
|
.operator = .numeric_negation,
|
||||||
@ -492,7 +424,7 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
return self.report("expected expression after boolean negation (`!`)");
|
return self.report("expected expression after boolean negation (`!`)");
|
||||||
}
|
}
|
||||||
|
|
||||||
break: get .{
|
break: parse .{
|
||||||
.unary_operation = .{
|
.unary_operation = .{
|
||||||
.expression = try coral.io.allocate_one(allocator, try self.parse_factor()),
|
.expression = try coral.io.allocate_one(allocator, try self.parse_factor()),
|
||||||
.operator = .boolean_negation,
|
.operator = .boolean_negation,
|
||||||
@ -504,32 +436,64 @@ fn parse_factor(self: *Self) ParseError!Expression {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
while (self.tokenizer.token == .symbol_period) {
|
while (true) {
|
||||||
self.tokenizer.skip_newlines();
|
switch (self.tokenizer.token) {
|
||||||
|
.symbol_period => {
|
||||||
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
const identifier = switch (self.tokenizer.token) {
|
// TODO: Remove when Zig fixes miscompilation with in-place struct re-assignment.
|
||||||
.identifier => |identifier| identifier,
|
const unnecessary_temp = try coral.io.allocate_one(allocator, expression);
|
||||||
else => return self.report("expected identifier after `.`"),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.tokenizer.skip_newlines();
|
expression = .{
|
||||||
|
.get_field = .{
|
||||||
|
.identifier = switch (self.tokenizer.token) {
|
||||||
|
.identifier => |field_identifier| field_identifier,
|
||||||
|
else => return self.report("expected identifier after `.`"),
|
||||||
|
},
|
||||||
|
|
||||||
expression = switch (self.tokenizer.token) {
|
.object_expression = unnecessary_temp,
|
||||||
.symbol_equals => .{
|
},
|
||||||
.set_field = .{
|
};
|
||||||
.value_expression = try coral.io.allocate_one(allocator, try self.parse_expression()),
|
|
||||||
.object_expression = try coral.io.allocate_one(allocator, expression),
|
self.tokenizer.skip_newlines();
|
||||||
.identifier = identifier,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
else => .{
|
.symbol_paren_left => {
|
||||||
.get_field = .{
|
var argument_expressions = Expression.List.make(allocator);
|
||||||
.object_expression = try coral.io.allocate_one(allocator, expression),
|
|
||||||
.identifier = identifier,
|
while (true) {
|
||||||
},
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
|
switch (self.tokenizer.token) {
|
||||||
|
.symbol_paren_right => break,
|
||||||
|
|
||||||
|
else => {
|
||||||
|
try argument_expressions.push_one(try self.parse_expression());
|
||||||
|
|
||||||
|
switch (self.tokenizer.token) {
|
||||||
|
.symbol_comma => continue,
|
||||||
|
.symbol_paren_right => break,
|
||||||
|
else => return self.report("expected `,` or `)` after function argument expression"),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tokenizer.skip_newlines();
|
||||||
|
|
||||||
|
// TODO: Remove when Zig fixes miscompilation with in-place struct re-assignment.
|
||||||
|
const unnecessary_temp = try coral.io.allocate_one(allocator, expression);
|
||||||
|
|
||||||
|
expression = .{
|
||||||
|
.call = .{
|
||||||
|
.argument_expressions = argument_expressions,
|
||||||
|
.object_expression = unnecessary_temp,
|
||||||
|
},
|
||||||
|
};
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
else => break,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
|
@ -95,18 +95,43 @@ const AstCompiler = struct {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.call => |call| {
|
||||||
|
if (call.argument_expressions.values.len > coral.math.max_int(@typeInfo(u8).Int)) {
|
||||||
|
return self.chunk.env.raise(error.BadSyntax, "lambdas may contain a maximum of 255 arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (call.argument_expressions.values) |argument_expression| {
|
||||||
|
try self.compile_expression(argument_expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.compile_expression(call.object_expression.*);
|
||||||
|
try self.chunk.append_opcode(.{.call = @intCast(call.argument_expressions.values.len)});
|
||||||
|
},
|
||||||
|
|
||||||
.grouped_expression => |grouped_expression| {
|
.grouped_expression => |grouped_expression| {
|
||||||
try self.compile_expression(grouped_expression.*);
|
try self.compile_expression(grouped_expression.*);
|
||||||
},
|
},
|
||||||
|
|
||||||
.resolve_local => |local| {
|
.get_system => |get_system| {
|
||||||
|
try self.chunk.append_opcode(.{.push_system = try self.chunk.declare_constant_string(get_system)});
|
||||||
|
},
|
||||||
|
|
||||||
|
.get_local => |get_local| {
|
||||||
try self.chunk.append_opcode(.{
|
try self.chunk.append_opcode(.{
|
||||||
.push_local = self.resolve_local(local) orelse {
|
.push_local = self.resolve_local(get_local) orelse {
|
||||||
return self.chunk.env.raise(error.OutOfMemory, "undefined local");
|
return self.chunk.env.raise(error.OutOfMemory, "undefined local");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.set_local => |set_local| {
|
||||||
|
if (self.resolve_local(set_local)) |index| {
|
||||||
|
try self.chunk.append_opcode(.{.set_local = index});
|
||||||
|
} else {
|
||||||
|
try self.declare_local(set_local);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
.get_field => |get_field| {
|
.get_field => |get_field| {
|
||||||
try self.compile_expression(get_field.object_expression.*);
|
try self.compile_expression(get_field.object_expression.*);
|
||||||
|
|
||||||
@ -127,57 +152,26 @@ const AstCompiler = struct {
|
|||||||
try self.compile_expression(set_field.value_expression.*);
|
try self.compile_expression(set_field.value_expression.*);
|
||||||
try self.chunk.append_opcode(.set_dynamic);
|
try self.chunk.append_opcode(.set_dynamic);
|
||||||
},
|
},
|
||||||
|
|
||||||
.call_system => |call| {
|
|
||||||
if (call.argument_expressions.values.len > coral.math.max_int(@typeInfo(u8).Int)) {
|
|
||||||
return self.chunk.env.raise(error.OutOfMemory, "functions may receive a maximum of 255 locals");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (call.argument_expressions.values) |argument_expression| {
|
|
||||||
try self.compile_expression(argument_expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.chunk.append_opcode(.{.push_const = try self.chunk.declare_constant_string(call.identifier)});
|
|
||||||
try self.chunk.append_opcode(.{.syscall = @intCast(call.argument_expressions.values.len)});
|
|
||||||
try self.chunk.append_opcode(.pop);
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_statement(self: *AstCompiler, statement: Ast.Statement) kym.RuntimeError!void {
|
fn compile_statement(self: *AstCompiler, statement: Ast.Statement) kym.RuntimeError!void {
|
||||||
switch (statement) {
|
switch (statement) {
|
||||||
.return_expression => |return_expression| try self.compile_expression(return_expression),
|
.@"return" => |@"return"| {
|
||||||
.return_nothing => try self.chunk.append_opcode(.push_nil),
|
if (@"return".expression) |expression| {
|
||||||
|
try self.compile_expression(expression);
|
||||||
.assign_local => |local| {
|
|
||||||
try self.compile_expression(local.expression);
|
|
||||||
|
|
||||||
if (self.resolve_local(local.identifier)) |index| {
|
|
||||||
try self.chunk.append_opcode(.{.set_local = index});
|
|
||||||
} else {
|
} else {
|
||||||
try self.declare_local(local.identifier);
|
try self.chunk.append_opcode(.push_nil);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
.call_system => |call| {
|
.expression => |expression| try self.compile_expression(expression),
|
||||||
if (call.argument_expressions.values.len > coral.math.max_int(@typeInfo(u8).Int)) {
|
|
||||||
return self.chunk.env.raise(error.OutOfMemory, "functions may receive a maximum of 255 locals");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (call.argument_expressions.values) |argument_expression| {
|
|
||||||
try self.compile_expression(argument_expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.chunk.append_opcode(.{.push_const = try self.chunk.declare_constant_string(call.identifier)});
|
|
||||||
try self.chunk.append_opcode(.{.syscall = @intCast(call.argument_expressions.values.len)});
|
|
||||||
try self.chunk.append_opcode(.pop);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_local(self: *AstCompiler, identifier: []const u8) kym.RuntimeError!void {
|
fn declare_local(self: *AstCompiler, identifier: []const u8) kym.RuntimeError!void {
|
||||||
if (self.local_identifiers_count == self.local_identifiers_buffer.len) {
|
if (self.local_identifiers_count == self.local_identifiers_buffer.len) {
|
||||||
return self.chunk.env.raise(error.OutOfMemory, "functions may contain a maximum of 255 locals");
|
return self.chunk.env.raise(error.OutOfMemory, "lambdas may contain a maximum of 255 locals");
|
||||||
}
|
}
|
||||||
|
|
||||||
self.local_identifiers_buffer[self.local_identifiers_count] = identifier;
|
self.local_identifiers_buffer[self.local_identifiers_count] = identifier;
|
||||||
@ -203,7 +197,7 @@ const AstCompiler = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const RefList = coral.list.Stack(?*kym.RuntimeRef);
|
const RefList = coral.list.Stack(*kym.RuntimeRef);
|
||||||
|
|
||||||
const LocalsList = coral.list.Stack([]const u8);
|
const LocalsList = coral.list.Stack([]const u8);
|
||||||
|
|
||||||
@ -215,11 +209,11 @@ pub const Opcode = union (enum) {
|
|||||||
push_const: u16,
|
push_const: u16,
|
||||||
push_local: u8,
|
push_local: u8,
|
||||||
push_table: u32,
|
push_table: u32,
|
||||||
|
push_system: u16,
|
||||||
set_local: u8,
|
set_local: u8,
|
||||||
get_dynamic,
|
get_dynamic,
|
||||||
set_dynamic,
|
set_dynamic,
|
||||||
call: u8,
|
call: u8,
|
||||||
syscall: u8,
|
|
||||||
|
|
||||||
not,
|
not,
|
||||||
neg,
|
neg,
|
||||||
@ -364,6 +358,17 @@ fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef
|
|||||||
try env.push_ref(table_ref);
|
try env.push_ref(table_ref);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.push_system => |push_system| {
|
||||||
|
const system_ref = self.env.get_syscallable(try kym.unbox_string(
|
||||||
|
self.env,
|
||||||
|
self.constant_refs.values[push_system],
|
||||||
|
));
|
||||||
|
|
||||||
|
defer self.env.discard(system_ref);
|
||||||
|
|
||||||
|
try self.env.push_ref(system_ref);
|
||||||
|
},
|
||||||
|
|
||||||
.push_local => |local| {
|
.push_local => |local| {
|
||||||
const ref = try env.get_local(local);
|
const ref = try env.get_local(local);
|
||||||
|
|
||||||
@ -401,6 +406,10 @@ fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef
|
|||||||
},
|
},
|
||||||
|
|
||||||
.set_dynamic => {
|
.set_dynamic => {
|
||||||
|
const value_ref = try env.pop_local();
|
||||||
|
|
||||||
|
defer env.discard(value_ref);
|
||||||
|
|
||||||
const index_ref = try env.pop_local() orelse {
|
const index_ref = try env.pop_local() orelse {
|
||||||
return env.raise(error.TypeMismatch, "nil is not a valid index");
|
return env.raise(error.TypeMismatch, "nil is not a valid index");
|
||||||
};
|
};
|
||||||
@ -413,10 +422,6 @@ fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef
|
|||||||
|
|
||||||
defer env.discard(indexable_ref);
|
defer env.discard(indexable_ref);
|
||||||
|
|
||||||
const value_ref = try env.pop_local();
|
|
||||||
|
|
||||||
defer env.discard(value_ref);
|
|
||||||
|
|
||||||
try env.set_dynamic(try kym.unbox_dynamic(env, indexable_ref), index_ref, value_ref);
|
try env.set_dynamic(try kym.unbox_dynamic(env, indexable_ref), index_ref, value_ref);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -428,25 +433,7 @@ fn execute(self: *Self, env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef
|
|||||||
|
|
||||||
defer env.discard(callable_ref);
|
defer env.discard(callable_ref);
|
||||||
|
|
||||||
break: call try env.call(try env.callable(callable_ref), arg_count, "");
|
break: call try env.call(callable_ref, arg_count, "");
|
||||||
};
|
|
||||||
|
|
||||||
defer env.discard(result_ref);
|
|
||||||
|
|
||||||
try env.push_ref(result_ref);
|
|
||||||
},
|
|
||||||
|
|
||||||
.syscall => |arg_count| {
|
|
||||||
const result_ref = call: {
|
|
||||||
const identifier_ref = try env.pop_local() orelse {
|
|
||||||
return env.raise(error.TypeMismatch, "nil is not syscallable");
|
|
||||||
};
|
|
||||||
|
|
||||||
defer env.discard(identifier_ref);
|
|
||||||
|
|
||||||
const identifier = try kym.unbox_string(env, identifier_ref);
|
|
||||||
|
|
||||||
break: call try env.call(try env.syscallable(identifier), arg_count, identifier);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
defer env.discard(result_ref);
|
defer env.discard(result_ref);
|
||||||
@ -667,10 +654,6 @@ pub fn free(self: *Self) void {
|
|||||||
self.constant_refs.free();
|
self.constant_refs.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_zero(utf8: []const u8) bool {
|
|
||||||
return coral.io.equals(utf8, "0") or coral.io.equals(utf8, "0.0");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make(env: *kym.RuntimeEnv) Self {
|
pub fn make(env: *kym.RuntimeEnv) Self {
|
||||||
return Self{
|
return Self{
|
||||||
.opcodes = OpcodeList.make(env.allocator),
|
.opcodes = OpcodeList.make(env.allocator),
|
||||||
|
@ -5,7 +5,7 @@ pub const Token = union(enum) {
|
|||||||
unknown: coral.io.Byte,
|
unknown: coral.io.Byte,
|
||||||
newline,
|
newline,
|
||||||
|
|
||||||
special_identifier: []const coral.io.Byte,
|
system_identifier: []const coral.io.Byte,
|
||||||
identifier: []const coral.io.Byte,
|
identifier: []const coral.io.Byte,
|
||||||
|
|
||||||
symbol_plus,
|
symbol_plus,
|
||||||
@ -46,7 +46,7 @@ pub const Token = union(enum) {
|
|||||||
.unknown => |unknown| @as([*]const coral.io.Byte, @ptrCast(&unknown))[0 .. 1],
|
.unknown => |unknown| @as([*]const coral.io.Byte, @ptrCast(&unknown))[0 .. 1],
|
||||||
.newline => "newline",
|
.newline => "newline",
|
||||||
|
|
||||||
.special_identifier => |identifier| identifier,
|
.system_identifier => |identifier| identifier,
|
||||||
.identifier => |identifier| identifier,
|
.identifier => |identifier| identifier,
|
||||||
|
|
||||||
.symbol_plus => "+",
|
.symbol_plus => "+",
|
||||||
@ -224,7 +224,7 @@ pub const Tokenizer = struct {
|
|||||||
else => break,
|
else => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.token = .{.special_identifier = self.source[begin .. cursor]};
|
self.token = .{.system_identifier = self.source[begin .. cursor]};
|
||||||
|
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
@ -241,7 +241,7 @@ pub const Tokenizer = struct {
|
|||||||
else => cursor += 1,
|
else => cursor += 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.token = .{.special_identifier = self.source[begin .. cursor]};
|
self.token = .{.system_identifier = self.source[begin .. cursor]};
|
||||||
cursor += 1;
|
cursor += 1;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -69,21 +69,16 @@ pub fn run_app(file_access: file.Access) void {
|
|||||||
|
|
||||||
defer script_env.free();
|
defer script_env.free();
|
||||||
|
|
||||||
script_env.bind_syscalls(&.{
|
script_env.bind_syscaller("log_info", kym.Caller.from(kym_log_info)) catch {
|
||||||
.{
|
return app.log_fail("failed to bind `log_info` syscall");
|
||||||
.name = "log_info",
|
};
|
||||||
.caller = kym.Caller.from(kym_log_info),
|
|
||||||
},
|
script_env.bind_syscaller("log_warn", kym.Caller.from(kym_log_warn)) catch {
|
||||||
.{
|
return app.log_fail("failed to bind `log_warn` syscall");
|
||||||
.name = "log_warn",
|
};
|
||||||
.caller = kym.Caller.from(kym_log_warn),
|
|
||||||
},
|
script_env.bind_syscaller("log_fail", kym.Caller.from(kym_log_fail)) catch {
|
||||||
.{
|
return app.log_fail("failed to bind `log_fail` syscall");
|
||||||
.name = "log_fail",
|
|
||||||
.caller = kym.Caller.from(kym_log_fail),
|
|
||||||
},
|
|
||||||
}) catch {
|
|
||||||
return app.log_fail("failed to bind syscalls to script runtime");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var manifest = app.Manifest{};
|
var manifest = app.Manifest{};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user