Add parser support for vector literals
continuous-integration/drone/push Build is passing Details

This commit is contained in:
kayomn 2023-08-13 13:54:31 +01:00
parent 919d32e714
commit 0fbdc001d4
7 changed files with 169 additions and 40 deletions

View File

@ -5,8 +5,6 @@ pub const debug = @import("./debug.zig");
pub const io = @import("./io.zig");
pub const lina = @import("./lina.zig");
pub const list = @import("./list.zig");
pub const map = @import("./map.zig");

View File

@ -207,6 +207,16 @@ pub fn Tag(comptime Element: type) type {
pub const Writer = Generator(?usize, []const Byte);
pub fn all_equals(target: []const Byte, match: Byte) bool {
for (0 .. target.len) |index| {
if (target[index] != match) {
return false;
}
}
return true;
}
pub fn allocate_copy(allocator: Allocator, source: []const Byte) AllocationError![]Byte {
const allocation = try allocator.actions.reallocate(allocator.context, @returnAddress(), null, source.len);
@ -265,6 +275,20 @@ pub fn allocate_string(allocator: Allocator, source: []const Byte) AllocationErr
return @ptrCast(allocation);
}
pub fn are_equal(target: []const Byte, match: []const Byte) bool {
if (target.len != match.len) {
return false;
}
for (0 .. target.len) |index| {
if (target[index] != match[index]) {
return false;
}
}
return true;
}
pub fn bytes_of(value: anytype) []const Byte {
const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
@ -326,20 +350,6 @@ pub fn ends_with(target: []const Byte, match: []const Byte) bool {
return true;
}
pub fn equals(target: []const Byte, match: []const Byte) bool {
if (target.len != match.len) {
return false;
}
for (0 .. target.len) |index| {
if (target[index] != match[index]) {
return false;
}
}
return true;
}
pub fn find_first(haystack: []const Byte, needle: Byte) ?usize {
for (0 .. haystack.len) |i| {
if (haystack[i] == needle) {

View File

@ -1,12 +0,0 @@
pub const Vector3 = struct {
x: f32,
y: f32,
z: f32,
pub fn equals(self: Vector3, other: Vector3) bool {
return self.x == other.x and self.y == other.y and self.z == other.z;
}
pub const zero = Vector3{.x = 0, .y = 0, .z = 0};
};

View File

@ -11,7 +11,7 @@ pub fn StringTable(comptime Value: type) type {
const Self = @This();
fn equals(key_a: []const io.Byte, key_b: []const io.Byte) bool {
return io.equals(key_a, key_b);
return io.are_equal(key_a, key_b);
}
fn hash(key: []const io.Byte) usize {

View File

@ -40,7 +40,7 @@ pub const DecimalFormat = struct {
},
else => {
if (self.delimiter.len == 0 or !io.equals(self.delimiter, utf8[index ..])) {
if (self.delimiter.len == 0 or !io.are_equal(self.delimiter, utf8[index ..])) {
return null;
}
},

View File

@ -39,6 +39,8 @@ pub const RuntimeEnv = struct {
push_false,
push_const: u16,
push_local: u8,
push_vector2,
push_vector3,
push_table: u32,
push_builtin: Builtin,
local_set: u8,
@ -108,6 +110,19 @@ pub const RuntimeEnv = struct {
});
},
.vector2_literal => |literal| {
try self.compile_expression(chunk, literal.y_expression.*);
try self.compile_expression(chunk, literal.x_expression.*);
try chunk.opcodes.push_one(.push_vector2);
},
.vector3_literal => |literal| {
try self.compile_expression(chunk, literal.z_expression.*);
try self.compile_expression(chunk, literal.y_expression.*);
try self.compile_expression(chunk, literal.x_expression.*);
try chunk.opcodes.push_one(.push_vector3);
},
.table_literal => |fields| {
if (fields.values.len > coral.math.max_int(@typeInfo(u32).Int)) {
return error.OutOfMemory;
@ -257,7 +272,7 @@ pub const RuntimeEnv = struct {
var index = @as(u8, self.local_identifiers_count - 1);
while (true) : (index -= 1) {
if (coral.io.equals(local_identifier, self.local_identifiers_buffer[index])) {
if (coral.io.are_equal(local_identifier, self.local_identifiers_buffer[index])) {
return index;
}
@ -324,6 +339,47 @@ pub const RuntimeEnv = struct {
}
},
.push_vector2 => {
const x = try self.env.expect(try self.pop_local());
defer self.env.discard(x);
const y = try self.env.expect(try self.pop_local());
defer self.env.discard(y);
const vector = try self.env.new_vector2(
@floatCast(try self.env.unbox_float(x)),
@floatCast(try self.env.unbox_float(y)));
errdefer self.env.discard(vector);
try self.env.locals.push_one(vector);
},
.push_vector3 => {
const x = try self.env.expect(try self.pop_local());
defer self.env.discard(x);
const y = try self.env.expect(try self.pop_local());
defer self.env.discard(y);
const z = try self.env.expect(try self.pop_local());
defer self.env.discard(z);
const vector = try self.env.new_vector3(
@floatCast(try self.env.unbox_float(x)),
@floatCast(try self.env.unbox_float(y)),
@floatCast(try self.env.unbox_float(z)));
errdefer self.env.discard(vector);
try self.env.locals.push_one(vector);
},
.push_table => |push_table| {
const table = try self.env.new_table();
@ -991,7 +1047,7 @@ pub const RuntimeEnv = struct {
if (object.ref_count == 0) {
switch (object.payload) {
.false, .true, .float, .fixed, .symbol, .vector, .syscall => {},
.false, .true, .float, .fixed, .symbol, .vector2, .vector3, .syscall => {},
.string => |string| {
coral.debug.assert(string.len >= 0);
@ -1190,10 +1246,17 @@ pub const RuntimeEnv = struct {
});
}
pub fn new_vector(self: *RuntimeEnv, x: f32, y: f32, z: f32) RuntimeError!*RuntimeRef {
pub fn new_vector2(self: *RuntimeEnv, x: f32, y: f32) RuntimeError!*RuntimeRef {
return RuntimeRef.allocate(self.allocator, .{
.ref_count = 1,
.payload = .{.vector = .{x, y, z}},
.payload = .{.vector2 = .{x, y}},
});
}
pub fn new_vector3(self: *RuntimeEnv, x: f32, y: f32, z: f32) RuntimeError!*RuntimeRef {
return RuntimeRef.allocate(self.allocator, .{
.ref_count = 1,
.payload = .{.vector3 = .{x, y, z}},
});
}
@ -1294,7 +1357,8 @@ pub const RuntimeRef = opaque {
float: Float,
fixed: Fixed,
symbol: [*:0]const coral.io.Byte,
vector: coral.lina.Vector3,
vector2: [2]f32,
vector3: [3]f32,
syscall: *const Syscall,
string: struct {
@ -1365,8 +1429,13 @@ pub const RuntimeRef = opaque {
else => false,
},
.vector => |self_vector| switch (other.object().payload) {
.vector => |other_vector| self_vector.equals(other_vector),
.vector2 => |self_vector| switch (other.object().payload) {
.vector2 => |other_vector| coral.io.are_equal(coral.io.bytes_of(&self_vector), coral.io.bytes_of(&other_vector)),
else => false,
},
.vector3 => |self_vector| switch (other.object().payload) {
.vector3 => |other_vector| coral.io.are_equal(coral.io.bytes_of(&self_vector), coral.io.bytes_of(&other_vector)),
else => false,
},
@ -1376,7 +1445,7 @@ pub const RuntimeRef = opaque {
},
.string => |self_string| switch (other.object().payload) {
.string => |other_string| coral.io.equals(self_string.unpack(), other_string.unpack()),
.string => |other_string| coral.io.are_equal(self_string.unpack(), other_string.unpack()),
else => false,
},
@ -1397,7 +1466,8 @@ pub const RuntimeRef = opaque {
.float => |float| @bitCast(float),
.fixed => |fixed| @intCast(@as(u32, @bitCast(fixed))),
.symbol => |symbol| @intFromPtr(symbol),
.vector => |vector| coral.io.jenkins_hash(@typeInfo(usize).Int, coral.io.bytes_of(&vector)),
.vector2 => |vector| @bitCast(vector),
.vector3 => |vector| coral.io.jenkins_hash(@typeInfo(usize).Int, coral.io.bytes_of(&vector)),
.syscall => |syscall| @intFromPtr(syscall),
.string => |string| coral.io.djb2_hash(@typeInfo(usize).Int, string.unpack()),
.dynamic => |dynamic| @intFromPtr(dynamic.typeinfo()) ^ @intFromPtr(dynamic.userdata().ptr),
@ -1418,7 +1488,8 @@ pub const RuntimeRef = opaque {
.float => |float| float != 0,
.fixed => |fixed| fixed != 0,
.symbol => true,
.vector => |vector| !vector.equals(coral.lina.Vector3.zero),
.vector2 => |vector| coral.io.all_equals(coral.io.bytes_of(&vector), 0),
.vector3 => |vector| coral.io.all_equals(coral.io.bytes_of(&vector), 0),
.syscall => true,
.string => |string| string.len != 0,
.dynamic => true,

View File

@ -60,6 +60,17 @@ pub const Expression = union (enum) {
argument_expressions: List,
},
vector2_literal: struct {
x_expression: *Expression,
y_expression: *Expression,
},
vector3_literal: struct {
x_expression: *Expression,
y_expression: *Expression,
z_expression: *Expression,
},
pub const BinaryOperator = enum {
addition,
subtraction,
@ -357,6 +368,57 @@ fn parse_factor(self: *Self) ParseError!Expression {
break: parse .{.builtin = builtin};
},
.symbol_bracket_left => {
self.tokenizer.skip_newlines();
var expressions = [3]?*Expression{null, null, null};
var size = @as(u2, 0);
while (true) {
if (size == expressions.len) {
return self.report("vector literals cannot contain more than 3 elements");
}
expressions[size] = try coral.io.allocate_one(allocator, try self.parse_expression());
size += 1;
switch (self.tokenizer.token) {
.symbol_comma => {
self.tokenizer.skip_newlines();
continue;
},
.symbol_bracket_right => {
self.tokenizer.skip_newlines();
break;
},
else => return self.report("expected `,` or `]` after vector literal element expression"),
}
}
break: parse switch (size) {
0, 1 => return self.report("vector literals must contain at least 2 elements"),
2 => .{
.vector2_literal = .{
.x_expression = expressions[0] orelse unreachable,
.y_expression = expressions[1] orelse unreachable,
},
},
3 => .{
.vector3_literal = .{
.x_expression = expressions[0] orelse unreachable,
.y_expression = expressions[1] orelse unreachable,
.z_expression = expressions[2] orelse unreachable,
},
},
};
},
.symbol_brace_left => {
var table_literal = Expression.TableLiteral.make(allocator);