Compare commits
4 Commits
bb2745c3d0
...
c64767ba59
Author | SHA1 | Date | |
---|---|---|---|
c64767ba59 | |||
0974cb016b | |||
d1110d8683 | |||
a7605c6ffa |
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -5,8 +5,8 @@
|
|||||||
"name": "Runtime",
|
"name": "Runtime",
|
||||||
"type": "gdb",
|
"type": "gdb",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"target": "./zig-out/bin/ona-runner",
|
"target": "${workspaceRoot}/zig-out/bin/ona-runner",
|
||||||
"cwd": "${workspaceRoot}/debug",
|
"cwd": "${workspaceRoot}/debug/",
|
||||||
"valuesFormatting": "parseText"
|
"valuesFormatting": "parseText"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
434
source/coral/io.zig
Normal file → Executable file
434
source/coral/io.zig
Normal file → Executable file
@ -1,219 +1,215 @@
|
|||||||
const debug = @import("./debug.zig");
|
const debug = @import("./debug.zig");
|
||||||
|
|
||||||
const math = @import("./math.zig");
|
const math = @import("./math.zig");
|
||||||
|
|
||||||
pub const MemoryArena = struct {
|
pub const MemoryArena = struct {
|
||||||
|
|
||||||
|
|
||||||
pub fn as_allocator(self: *MemoryArena) MemoryAllocator {
|
pub fn as_allocator(self: *MemoryArena) MemoryAllocator {
|
||||||
return MemoryAllocator.bind(self, MemoryArena);
|
return MemoryAllocator.bind(self, MemoryArena);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MemoryAllocator = struct {
|
pub const MemoryAllocator = struct {
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
call: *const fn (capture: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8,
|
call: *const fn (capture: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8,
|
||||||
|
|
||||||
const Capture = [@sizeOf(usize)]u8;
|
const Capture = [@sizeOf(usize)]u8;
|
||||||
|
|
||||||
pub fn bind(state: anytype, comptime Actions: type) MemoryAllocator {
|
pub fn bind(state: anytype, comptime Actions: type) MemoryAllocator {
|
||||||
const State = @TypeOf(state);
|
const State = @TypeOf(state);
|
||||||
const state_info = @typeInfo(State);
|
const state_info = @typeInfo(State);
|
||||||
|
|
||||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = state,
|
.context = state,
|
||||||
|
|
||||||
.call = struct {
|
.call = struct {
|
||||||
fn reallocate(context: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8 {
|
fn reallocate(context: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8 {
|
||||||
return Actions.reallocate(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), maybe_allocation, size);
|
return Actions.reallocate(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), maybe_allocation, size);
|
||||||
}
|
}
|
||||||
}.reallocate,
|
}.reallocate,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_many(self: MemoryAllocator, comptime Type: type, amount: usize) ?[*]Type {
|
pub fn allocate_many(self: MemoryAllocator, comptime Type: type, amount: usize) ?[*]Type {
|
||||||
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type) * amount)));
|
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type) * amount)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_one(self: MemoryAllocator, comptime Type: type) ?*Type {
|
pub fn allocate_one(self: MemoryAllocator, comptime Type: type) ?*Type {
|
||||||
return @ptrCast(?*Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type))));
|
return @ptrCast(?*Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type))));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deallocate(self: MemoryAllocator, maybe_allocation: anytype) void {
|
pub fn deallocate(self: MemoryAllocator, maybe_allocation: anytype) void {
|
||||||
if (@typeInfo(@TypeOf(maybe_allocation)) != .Pointer)
|
if (@typeInfo(@TypeOf(maybe_allocation)) != .Pointer)
|
||||||
@compileError("`maybe_allocation` must be a pointer type");
|
@compileError("`maybe_allocation` must be a pointer type");
|
||||||
|
|
||||||
debug.assert(self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), 0) == null);
|
debug.assert(self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), 0) == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reallocate(self: MemoryAllocator, comptime Type: type, maybe_allocation: ?[*]Type, amount: usize) ?[*]Type {
|
pub fn reallocate(self: MemoryAllocator, comptime Type: type, maybe_allocation: ?[*]Type, amount: usize) ?[*]Type {
|
||||||
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type),
|
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type),
|
||||||
self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), @sizeOf(Type) * amount)));
|
self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), @sizeOf(Type) * amount)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ReadError = error{
|
pub const ReadError = error{
|
||||||
IoUnavailable,
|
IoUnavailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Reader = struct {
|
pub const Reader = struct {
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
call: *const fn (context: *anyopaque, buffer: []u8) ReadError!usize,
|
call: *const fn (context: *anyopaque, buffer: []u8) ReadError!usize,
|
||||||
|
|
||||||
pub fn bind(state: anytype, comptime Actions: type) Reader {
|
pub fn bind(state: anytype, comptime Actions: type) Reader {
|
||||||
const State = @TypeOf(state);
|
const State = @TypeOf(state);
|
||||||
const state_info = @typeInfo(State);
|
const state_info = @typeInfo(State);
|
||||||
|
|
||||||
if (@typeInfo(State) != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
if (@typeInfo(State) != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = @ptrCast(*anyopaque, state),
|
.context = @ptrCast(*anyopaque, state),
|
||||||
|
|
||||||
.call = struct {
|
.call = struct {
|
||||||
fn read(context: *anyopaque, buffer: []u8) ReadError!usize {
|
fn read(context: *anyopaque, buffer: []u8) ReadError!usize {
|
||||||
return Actions.read(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
return Actions.read(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||||
}
|
}
|
||||||
}.read,
|
}.read,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: Reader, buffer: []u8) ReadError!usize {
|
pub fn read(self: Reader, buffer: []u8) ReadError!usize {
|
||||||
return self.call(self.context, buffer);
|
return self.call(self.context, buffer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn Tag(comptime Element: type) type {
|
pub fn Tag(comptime Element: type) type {
|
||||||
return switch (@typeInfo(Element)) {
|
return switch (@typeInfo(Element)) {
|
||||||
.Enum => |info| info.tag_type,
|
.Enum => |info| info.tag_type,
|
||||||
.Union => |info| info.tag_type orelse @compileError(@typeName(Element) ++ " has no tag type"),
|
.Union => |info| info.tag_type orelse @compileError(@typeName(Element) ++ " has no tag type"),
|
||||||
else => @compileError("expected enum or union type, found '" ++ @typeName(Element) ++ "'"),
|
else => @compileError("expected enum or union type, found '" ++ @typeName(Element) ++ "'"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const WriteError = error{
|
pub const WriteError = error{
|
||||||
IoUnavailable,
|
IoUnavailable,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Writer = struct {
|
pub const Writer = struct {
|
||||||
context: *anyopaque,
|
context: *anyopaque,
|
||||||
call: *const fn (context: *anyopaque, buffer: []const u8) WriteError!usize,
|
call: *const fn (context: *anyopaque, buffer: []const u8) WriteError!usize,
|
||||||
|
|
||||||
pub fn bind(state: anytype, comptime Actions: type) Writer {
|
pub fn bind(state: anytype, comptime Actions: type) Writer {
|
||||||
const State = @TypeOf(state);
|
const State = @TypeOf(state);
|
||||||
const state_info = @typeInfo(State);
|
const state_info = @typeInfo(State);
|
||||||
|
|
||||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = @ptrCast(*anyopaque, state),
|
.context = @ptrCast(*anyopaque, state),
|
||||||
|
|
||||||
.call = struct {
|
.call = struct {
|
||||||
fn write(context: *anyopaque, buffer: []const u8) ReadError!usize {
|
fn write(context: *anyopaque, buffer: []const u8) ReadError!usize {
|
||||||
return Actions.write(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
return Actions.write(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||||
}
|
}
|
||||||
}.write,
|
}.write,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: Writer, buffer: []const u8) WriteError!usize {
|
pub fn write(self: Writer, buffer: []const u8) WriteError!usize {
|
||||||
return self.call(self.context, buffer);
|
return self.call(self.context, buffer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn bytes_of(value: anytype) []const u8 {
|
pub fn bytes_of(value: anytype) []const u8 {
|
||||||
const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
|
const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
|
||||||
|
|
||||||
debug.assert(pointer_info.size == .One);
|
debug.assert(pointer_info.size == .One);
|
||||||
|
|
||||||
return @ptrCast([*]const u8, value)[0 .. @sizeOf(pointer_info.child)];
|
return @ptrCast([*]const u8, value)[0 .. @sizeOf(pointer_info.child)];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compare(this: []const u8, that: []const u8) isize {
|
pub fn compare(this: []const u8, that: []const u8) isize {
|
||||||
const range = math.min(usize, this.len, that.len);
|
const range = math.min(usize, this.len, that.len);
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
|
|
||||||
while (index < range) : (index += 1) {
|
while (index < range) : (index += 1) {
|
||||||
const difference = @intCast(isize, this[index]) - @intCast(isize, that[index]);
|
const difference = @intCast(isize, this[index]) - @intCast(isize, that[index]);
|
||||||
|
|
||||||
if (difference != 0) return difference;
|
if (difference != 0) return difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
return @intCast(isize, this.len) - @intCast(isize, that.len);
|
return @intCast(isize, this.len) - @intCast(isize, that.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy(target: []u8, source: []const u8) void {
|
pub fn copy(target: []u8, source: []const u8) void {
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
|
|
||||||
while (index < source.len) : (index += 1) target[index] = source[index];
|
while (index < source.len) : (index += 1) target[index] = source[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ends_with(target: []const u8, match: []const u8) bool {
|
pub fn ends_with(target: []const u8, match: []const u8) bool {
|
||||||
if (target.len < match.len) return false;
|
if (target.len < match.len) return false;
|
||||||
|
|
||||||
var index = @as(usize, 0);
|
var index = @as(usize, 0);
|
||||||
|
|
||||||
while (index < match.len) : (index += 1) {
|
while (index < match.len) : (index += 1) {
|
||||||
if (target[target.len - (1 + index)] != match[match.len - (1 + index)]) return false;
|
if (target[target.len - (1 + index)] != match[match.len - (1 + index)]) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn equals(this: []const u8, that: []const u8) bool {
|
pub fn equals(this: []const u8, that: []const u8) bool {
|
||||||
if (this.len != that.len) return false;
|
if (this.len != that.len) return false;
|
||||||
|
|
||||||
{
|
{
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
|
|
||||||
while (index < this.len) : (index += 1) if (this[index] != that[index]) return false;
|
while (index < this.len) : (index += 1) if (this[index] != that[index]) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var null_context = @as(usize, 0);
|
var null_context = @as(usize, 0);
|
||||||
|
|
||||||
pub const null_writer = Writer.bind(&null_context, struct {
|
pub const null_writer = Writer.bind(&null_context, struct {
|
||||||
pub fn write(context: *usize, buffer: []const u8) usize {
|
pub fn write(context: *usize, buffer: []const u8) usize {
|
||||||
debug.assert(context.* == 0);
|
debug.assert(context.* == 0);
|
||||||
|
|
||||||
return buffer.len;
|
return buffer.len;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pub fn slice_sentineled(comptime element: type, comptime sentinel: element, sequence: [*:sentinel]const element) []const element {
|
pub fn slice_sentineled(comptime element: type, comptime sentinel: element, sequence: [*:sentinel]const element) []const element {
|
||||||
var length: usize = 0;
|
var length: usize = 0;
|
||||||
|
|
||||||
while (sequence[length] != sentinel) : (length += 1) {}
|
while (sequence[length] != sentinel) : (length += 1) {}
|
||||||
|
|
||||||
return sequence[0..length];
|
return sequence[0..length];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stream(output: Writer, input: Reader, buffer: []u8) (ReadError || WriteError)!u64 {
|
pub fn stream(output: Writer, input: Reader, buffer: []u8) (ReadError || WriteError)!u64 {
|
||||||
var total_written: u64 = 0;
|
var total_written: u64 = 0;
|
||||||
var read = try input.read(buffer);
|
var read = try input.read(buffer);
|
||||||
|
|
||||||
while (read != 0) {
|
while (read != 0) {
|
||||||
total_written += try output.write(buffer[0..read]);
|
total_written += try output.write(buffer[0..read]);
|
||||||
read = try input.read(buffer);
|
read = try input.read(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return total_written;
|
return total_written;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn swap(comptime Element: type, this: *Element, that: *Element) void {
|
pub fn swap(comptime Element: type, this: *Element, that: *Element) void {
|
||||||
const temp = this.*;
|
const temp = this.*;
|
||||||
|
|
||||||
this.* = that.*;
|
this.* = that.*;
|
||||||
that.* = temp;
|
that.* = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tag(value: anytype) Tag(@TypeOf(value)) {
|
pub fn zero(target: []u8) void {
|
||||||
return @as(Tag(@TypeOf(value)), value);
|
for (target) |*t| t.* = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zero(target: []u8) void {
|
|
||||||
for (target) |*t| t.* = 0;
|
|
||||||
}
|
|
||||||
|
1289
source/kym/bytecode.zig
Normal file → Executable file
1289
source/kym/bytecode.zig
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -144,10 +144,7 @@ pub const Vm = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
pub const CompileError = error {
|
pub const CompileError = bytecode.ParseError;
|
||||||
BadSyntax,
|
|
||||||
OutOfMemory,
|
|
||||||
};
|
|
||||||
|
|
||||||
const HeapAllocation = union(enum) {
|
const HeapAllocation = union(enum) {
|
||||||
next_free: u32,
|
next_free: u32,
|
||||||
|
@ -33,6 +33,22 @@ pub const Token = union(enum) {
|
|||||||
keyword_return,
|
keyword_return,
|
||||||
keyword_self,
|
keyword_self,
|
||||||
|
|
||||||
|
pub const ExpectError = error {
|
||||||
|
UnexpectedToken,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn expect(self: Token, tag: coral.io.Tag(Token)) ExpectError!void {
|
||||||
|
if (self != tag) return error.UnexpectedToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect_any(self: Token, tags: []const coral.io.Tag(Token)) ExpectError!void {
|
||||||
|
for (tags) |tag| {
|
||||||
|
if (self == tag) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.UnexpectedToken;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn text(self: Token) []const u8 {
|
pub fn text(self: Token) []const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.unknown => |unknown| @ptrCast([*]const u8, &unknown)[0 .. 1],
|
.unknown => |unknown| @ptrCast([*]const u8, &unknown)[0 .. 1],
|
||||||
@ -64,6 +80,7 @@ pub const Token = union(enum) {
|
|||||||
.keyword_false => "false",
|
.keyword_false => "false",
|
||||||
.keyword_true => "true",
|
.keyword_true => "true",
|
||||||
.keyword_return => "return",
|
.keyword_return => "return",
|
||||||
|
.keyword_self => "self",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -72,8 +89,12 @@ pub const Tokenizer = struct {
|
|||||||
source: []const u8,
|
source: []const u8,
|
||||||
cursor: usize = 0,
|
cursor: usize = 0,
|
||||||
|
|
||||||
|
pub fn has_next(self: Tokenizer) bool {
|
||||||
|
return self.cursor < self.source.len;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(self: *Tokenizer) ?Token {
|
pub fn next(self: *Tokenizer) ?Token {
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
' ', '\t' => self.cursor += 1,
|
' ', '\t' => self.cursor += 1,
|
||||||
|
|
||||||
'\n' => {
|
'\n' => {
|
||||||
@ -87,13 +108,13 @@ pub const Tokenizer = struct {
|
|||||||
|
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'0' ... '9' => self.cursor += 1,
|
'0' ... '9' => self.cursor += 1,
|
||||||
|
|
||||||
'.' => {
|
'.' => {
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'0' ... '9' => self.cursor += 1,
|
'0' ... '9' => self.cursor += 1,
|
||||||
else => break,
|
else => break,
|
||||||
};
|
};
|
||||||
@ -136,13 +157,13 @@ pub const Tokenizer = struct {
|
|||||||
'@' => {
|
'@' => {
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
if (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
if (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'A'...'Z', 'a'...'z', '_' => {
|
'A'...'Z', 'a'...'z', '_' => {
|
||||||
const begin = self.cursor;
|
const begin = self.cursor;
|
||||||
|
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'0'...'9', 'A'...'Z', 'a'...'z', '_' => self.cursor += 1,
|
'0'...'9', 'A'...'Z', 'a'...'z', '_' => self.cursor += 1,
|
||||||
else => break,
|
else => break,
|
||||||
};
|
};
|
||||||
@ -157,7 +178,7 @@ pub const Tokenizer = struct {
|
|||||||
|
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'"' => break,
|
'"' => break,
|
||||||
else => self.cursor += 1,
|
else => self.cursor += 1,
|
||||||
};
|
};
|
||||||
@ -180,7 +201,7 @@ pub const Tokenizer = struct {
|
|||||||
|
|
||||||
self.cursor += 1;
|
self.cursor += 1;
|
||||||
|
|
||||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||||
'"' => break,
|
'"' => break,
|
||||||
else => self.cursor += 1,
|
else => self.cursor += 1,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user