Compare commits
No commits in common. "dc674ae2c34aef8a84398f19b725f4312d973720" and "7b266fde587ec56da79847b8fe3eb8e85080459d" have entirely different histories.
dc674ae2c3
...
7b266fde58
@ -1,8 +1,6 @@
|
|||||||
|
|
||||||
title = "Afterglow"
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title = title,
|
title = "Afterglow",
|
||||||
width = 1280,
|
width = 1280,
|
||||||
height = 800,
|
height = 800,
|
||||||
tick_rate = 60,
|
tick_rate = 60,
|
||||||
|
@ -287,17 +287,18 @@ pub fn TableTraits(comptime Key: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_string(key: []const io.Byte) usize {
|
|
||||||
var hash_code = @as(usize, 5381);
|
|
||||||
|
|
||||||
for (key) |byte| {
|
|
||||||
hash_code = ((hash_code << 5) +% hash_code) +% byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const string_table_traits = TableTraits([]const io.Byte){
|
pub const string_table_traits = TableTraits([]const io.Byte){
|
||||||
.hash = hash_string,
|
.hash = struct {
|
||||||
|
fn hash(key: []const io.Byte) usize {
|
||||||
|
var hash_code = @as(usize, 5381);
|
||||||
|
|
||||||
|
for (key) |byte| {
|
||||||
|
hash_code = ((hash_code << 5) + hash_code) + byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash_code;
|
||||||
|
}
|
||||||
|
}.hash,
|
||||||
|
|
||||||
.match = io.equals,
|
.match = io.equals,
|
||||||
};
|
};
|
||||||
|
@ -172,6 +172,8 @@ pub const HexadecimalFormat = struct {
|
|||||||
_ = self;
|
_ = self;
|
||||||
_ = writer;
|
_ = writer;
|
||||||
_ = value;
|
_ = value;
|
||||||
|
|
||||||
|
unreachable;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -265,8 +267,7 @@ noinline fn print_value(writer: io.Writer, value: anytype) PrintError!void {
|
|||||||
.Float => DecimalFormat.default.print(writer, value),
|
.Float => DecimalFormat.default.print(writer, value),
|
||||||
|
|
||||||
.Pointer => |pointer| switch (pointer.size) {
|
.Pointer => |pointer| switch (pointer.size) {
|
||||||
.Many, .C => HexadecimalFormat.default.print(writer, @intFromPtr(value)),
|
.One, .Many, .C => HexadecimalFormat.default.print(writer, @intFromPtr(value)),
|
||||||
.One => if (pointer.child == []const u8) print_string(writer, *value) else HexadecimalFormat.default.print(writer, @intFromPtr(value)),
|
|
||||||
.Slice => if (pointer.child == u8) print_string(writer, value) else @compileError(unformattableMessage(Value)),
|
.Slice => if (pointer.child == u8) print_string(writer, value) else @compileError(unformattableMessage(Value)),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -30,46 +30,9 @@ const Compiler = struct {
|
|||||||
state: *State,
|
state: *State,
|
||||||
opcodes: OpcodeList,
|
opcodes: OpcodeList,
|
||||||
|
|
||||||
locals: struct {
|
|
||||||
buffer: [255][]const coral.io.Byte = [_][]const coral.io.Byte{""} ** 255,
|
|
||||||
count: u8 = 0,
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
fn declare(self: *Self, identifier: []const u8) CompileError!void {
|
|
||||||
if (self.count == self.buffer.len) {
|
|
||||||
return error.TooManyLocals;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.buffer[self.count] = identifier;
|
|
||||||
self.count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve(self: *Self, local_identifier: []const coral.io.Byte) ?u8 {
|
|
||||||
var index = @as(u8, self.count);
|
|
||||||
|
|
||||||
while (index != 0) {
|
|
||||||
index -= 1;
|
|
||||||
|
|
||||||
if (coral.io.equals(local_identifier, self.buffer[index])) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
const CompileError = coral.io.AllocationError || error {
|
|
||||||
UndefinedLocal,
|
|
||||||
TooManyLocals,
|
|
||||||
};
|
|
||||||
|
|
||||||
const LocalsList = coral.list.Stack([]const u8);
|
|
||||||
|
|
||||||
const OpcodeList = coral.list.Stack(Opcode);
|
const OpcodeList = coral.list.Stack(Opcode);
|
||||||
|
|
||||||
fn compile_ast(self: *Compiler, ast: Ast) CompileError!void {
|
fn compile_ast(self: *Compiler, ast: Ast) coral.io.AllocationError!void {
|
||||||
for (ast.list_statements()) |statement| {
|
for (ast.list_statements()) |statement| {
|
||||||
switch (statement) {
|
switch (statement) {
|
||||||
.return_expression => |return_expression| {
|
.return_expression => |return_expression| {
|
||||||
@ -79,21 +42,11 @@ const Compiler = struct {
|
|||||||
.return_nothing => {
|
.return_nothing => {
|
||||||
try self.opcodes.push_one(.push_nil);
|
try self.opcodes.push_one(.push_nil);
|
||||||
},
|
},
|
||||||
|
|
||||||
.set_local => |local| {
|
|
||||||
try self.compile_expression(local.expression);
|
|
||||||
|
|
||||||
if (self.locals.resolve(local.identifier)) |index| {
|
|
||||||
try self.opcodes.push_one(.{.set_local = index});
|
|
||||||
} else {
|
|
||||||
try self.locals.declare(local.identifier);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_expression(self: *Compiler, expression: Ast.Expression) CompileError!void {
|
fn compile_expression(self: *Compiler, expression: Ast.Expression) coral.io.AllocationError!void {
|
||||||
const is_zero = struct {
|
const is_zero = struct {
|
||||||
fn is_zero(utf8: []const u8) bool {
|
fn is_zero(utf8: []const u8) bool {
|
||||||
return coral.io.equals(utf8, "0") or coral.io.equals(utf8, "0.0");
|
return coral.io.equals(utf8, "0") or coral.io.equals(utf8, "0.0");
|
||||||
@ -168,13 +121,7 @@ const Compiler = struct {
|
|||||||
|
|
||||||
.grouped_expression => |grouped_expression| {
|
.grouped_expression => |grouped_expression| {
|
||||||
try self.compile_expression(grouped_expression.*);
|
try self.compile_expression(grouped_expression.*);
|
||||||
},
|
}
|
||||||
|
|
||||||
.get_local => |local| {
|
|
||||||
try self.opcodes.push_one(.{
|
|
||||||
.get_local = self.locals.resolve(local) orelse return error.UndefinedLocal,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +141,6 @@ const Compiler = struct {
|
|||||||
|
|
||||||
fn make(allocator: coral.io.Allocator, state: *State) Compiler {
|
fn make(allocator: coral.io.Allocator, state: *State) Compiler {
|
||||||
return .{
|
return .{
|
||||||
.locals = .{},
|
|
||||||
.opcodes = OpcodeList.make(allocator),
|
.opcodes = OpcodeList.make(allocator),
|
||||||
.state = state,
|
.state = state,
|
||||||
};
|
};
|
||||||
@ -244,9 +190,6 @@ pub const Opcode = union (enum) {
|
|||||||
push_table: u32,
|
push_table: u32,
|
||||||
push_object: *State.Object,
|
push_object: *State.Object,
|
||||||
|
|
||||||
set_local: u8,
|
|
||||||
get_local: u8,
|
|
||||||
|
|
||||||
not,
|
not,
|
||||||
neg,
|
neg,
|
||||||
|
|
||||||
@ -325,16 +268,6 @@ pub const RuntimeEnv = struct {
|
|||||||
try self.state.push_value(.{.object = acquired_object});
|
try self.state.push_value(.{.object = acquired_object});
|
||||||
},
|
},
|
||||||
|
|
||||||
.set_local => |local| {
|
|
||||||
if (!self.state.set_value(local, try self.state.pop_value())) {
|
|
||||||
return self.raise(error.BadOperation, "invalid local set");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
.get_local => |local| {
|
|
||||||
try self.state.push_value(self.state.get_value(local));
|
|
||||||
},
|
|
||||||
|
|
||||||
.not => {
|
.not => {
|
||||||
try self.state.push_value(switch (try self.state.pop_value()) {
|
try self.state.push_value(switch (try self.state.pop_value()) {
|
||||||
.nil => return self.raise(error.BadOperation, "cannot convert nil to true or false"),
|
.nil => return self.raise(error.BadOperation, "cannot convert nil to true or false"),
|
||||||
@ -456,11 +389,7 @@ pub const RuntimeEnv = struct {
|
|||||||
|
|
||||||
defer compiler.free();
|
defer compiler.free();
|
||||||
|
|
||||||
compiler.compile_ast(ast) catch |compile_error| return switch (compile_error) {
|
try compiler.compile_ast(ast);
|
||||||
error.OutOfMemory => error.OutOfMemory,
|
|
||||||
error.UndefinedLocal => self.raise(error.BadOperation, "use of undefined local"),
|
|
||||||
error.TooManyLocals => self.raise(error.OutOfMemory, "functions cannot contain more than 255 locals"),
|
|
||||||
};
|
|
||||||
|
|
||||||
return self.execute_chunk(source.name, compiler.list_opcodes());
|
return self.execute_chunk(source.name, compiler.list_opcodes());
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ pub const Expression = union (enum) {
|
|||||||
string_literal: []const u8,
|
string_literal: []const u8,
|
||||||
table_literal: NamedList,
|
table_literal: NamedList,
|
||||||
grouped_expression: *Expression,
|
grouped_expression: *Expression,
|
||||||
get_local: []const u8,
|
|
||||||
|
|
||||||
binary_operation: struct {
|
binary_operation: struct {
|
||||||
operator: BinaryOperator,
|
operator: BinaryOperator,
|
||||||
@ -75,11 +74,6 @@ pub const Statement = union (enum) {
|
|||||||
return_expression: Expression,
|
return_expression: Expression,
|
||||||
return_nothing,
|
return_nothing,
|
||||||
|
|
||||||
set_local: struct {
|
|
||||||
identifier: []const coral.io.Byte,
|
|
||||||
expression: Expression,
|
|
||||||
},
|
|
||||||
|
|
||||||
const List = coral.list.Stack(Statement);
|
const List = coral.list.Stack(Statement);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -181,33 +175,6 @@ pub fn parse(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!void {
|
|||||||
has_returned = true;
|
has_returned = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
.local => |identifier| {
|
|
||||||
try self.check_syntax(tokenizer.step(.{.include_newlines = true}), "statement has no effect");
|
|
||||||
|
|
||||||
switch (tokenizer.current_token) {
|
|
||||||
.symbol_equals => {
|
|
||||||
try self.check_syntax(
|
|
||||||
tokenizer.step(.{.include_newlines = true}),
|
|
||||||
"expected expression after `=`");
|
|
||||||
|
|
||||||
try self.statements.push_one(.{
|
|
||||||
.set_local = .{
|
|
||||||
.identifier = identifier,
|
|
||||||
.expression = try self.parse_expression(tokenizer)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tokenizer.step(.{.include_newlines = true})) {
|
|
||||||
try self.check_syntax(
|
|
||||||
tokenizer.current_token == .newline,
|
|
||||||
"expected end of declaration after variable assignment");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.fail_syntax("expected `=` after local"),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
else => return self.fail_syntax("invalid statement"),
|
else => return self.fail_syntax("invalid statement"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,15 +211,15 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!Expression
|
|||||||
},
|
},
|
||||||
|
|
||||||
.number => |value| {
|
.number => |value| {
|
||||||
|
_ = tokenizer.step(.{.include_newlines = false});
|
||||||
|
|
||||||
return Expression{.number_literal = value};
|
return Expression{.number_literal = value};
|
||||||
},
|
},
|
||||||
|
|
||||||
.string => |value| {
|
.string => |value| {
|
||||||
return Expression{.string_literal = value};
|
_ = tokenizer.step(.{.include_newlines = false});
|
||||||
},
|
|
||||||
|
|
||||||
.local => |identifier| {
|
return Expression{.string_literal = value};
|
||||||
return Expression{.get_local = identifier};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
.symbol_brace_left => {
|
.symbol_brace_left => {
|
||||||
@ -282,8 +249,6 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!Expression
|
|||||||
.expression = try self.parse_expression(tokenizer),
|
.expression = try self.parse_expression(tokenizer),
|
||||||
});
|
});
|
||||||
|
|
||||||
try self.check_syntax(tokenizer.step(.{.include_newlines = false}), "unexpected end of table");
|
|
||||||
|
|
||||||
switch (tokenizer.current_token) {
|
switch (tokenizer.current_token) {
|
||||||
.symbol_comma => _ = tokenizer.step(.{.include_newlines = false}),
|
.symbol_comma => _ = tokenizer.step(.{.include_newlines = false}),
|
||||||
|
|
||||||
|
@ -100,14 +100,6 @@ pub fn free(self: *Self) void {
|
|||||||
self.interned.free();
|
self.interned.free();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(self: *Self, tail_index: usize) Variant {
|
|
||||||
if (tail_index >= self.values.values.len) {
|
|
||||||
return .nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.values.values[self.values.values.len - (1 + tail_index)];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn make(allocator: coral.io.Allocator) Self {
|
pub fn make(allocator: coral.io.Allocator) Self {
|
||||||
return .{
|
return .{
|
||||||
.values = DataStack.make(allocator),
|
.values = DataStack.make(allocator),
|
||||||
@ -140,13 +132,3 @@ pub fn release(self: *Self, object: *Object) void {
|
|||||||
self.allocator.deallocate(object);
|
self.allocator.deallocate(object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(self: *Self, tail_index: usize, value: Variant) bool {
|
|
||||||
if (tail_index >= self.values.values.len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.values.values[self.values.values.len - (1 + tail_index)] = value;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -37,7 +37,6 @@ pub const Token = union(enum) {
|
|||||||
keyword_true,
|
keyword_true,
|
||||||
keyword_return,
|
keyword_return,
|
||||||
keyword_self,
|
keyword_self,
|
||||||
keyword_const,
|
|
||||||
|
|
||||||
pub fn text(self: Token) []const u8 {
|
pub fn text(self: Token) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
@ -72,7 +71,6 @@ pub const Token = union(enum) {
|
|||||||
.number => |literal| literal,
|
.number => |literal| literal,
|
||||||
.string => |literal| literal,
|
.string => |literal| literal,
|
||||||
|
|
||||||
.keyword_const => "const",
|
|
||||||
.keyword_nil => "nil",
|
.keyword_nil => "nil",
|
||||||
.keyword_false => "false",
|
.keyword_false => "false",
|
||||||
.keyword_true => "true",
|
.keyword_true => "true",
|
||||||
@ -162,12 +160,6 @@ pub const Tokenizer = struct {
|
|||||||
coral.debug.assert(identifier.len != 0);
|
coral.debug.assert(identifier.len != 0);
|
||||||
|
|
||||||
switch (identifier[0]) {
|
switch (identifier[0]) {
|
||||||
'c' => if (coral.io.ends_with(identifier, "onst")) {
|
|
||||||
self.current_token = .keyword_const;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
'n' => if (coral.io.ends_with(identifier, "il")) {
|
'n' => if (coral.io.ends_with(identifier, "il")) {
|
||||||
self.current_token = .keyword_nil;
|
self.current_token = .keyword_nil;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user