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",
|
||||
"type": "gdb",
|
||||
"request": "launch",
|
||||
"target": "./zig-out/bin/ona-runner",
|
||||
"cwd": "${workspaceRoot}/debug",
|
||||
"target": "${workspaceRoot}/zig-out/bin/ona-runner",
|
||||
"cwd": "${workspaceRoot}/debug/",
|
||||
"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 math = @import("./math.zig");
|
||||
|
||||
pub const MemoryArena = struct {
|
||||
|
||||
|
||||
pub fn as_allocator(self: *MemoryArena) MemoryAllocator {
|
||||
return MemoryAllocator.bind(self, MemoryArena);
|
||||
}
|
||||
};
|
||||
|
||||
pub const MemoryAllocator = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (capture: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8,
|
||||
|
||||
const Capture = [@sizeOf(usize)]u8;
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) MemoryAllocator {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = state,
|
||||
|
||||
.call = struct {
|
||||
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);
|
||||
}
|
||||
}.reallocate,
|
||||
};
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
pub fn allocate_one(self: MemoryAllocator, comptime Type: type) ?*Type {
|
||||
return @ptrCast(?*Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type))));
|
||||
}
|
||||
|
||||
pub fn deallocate(self: MemoryAllocator, maybe_allocation: anytype) void {
|
||||
if (@typeInfo(@TypeOf(maybe_allocation)) != .Pointer)
|
||||
@compileError("`maybe_allocation` must be a pointer type");
|
||||
|
||||
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 {
|
||||
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type),
|
||||
self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), @sizeOf(Type) * amount)));
|
||||
}
|
||||
};
|
||||
|
||||
pub const ReadError = error{
|
||||
IoUnavailable,
|
||||
};
|
||||
|
||||
pub const Reader = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (context: *anyopaque, buffer: []u8) ReadError!usize,
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) Reader {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (@typeInfo(State) != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = @ptrCast(*anyopaque, state),
|
||||
|
||||
.call = struct {
|
||||
fn read(context: *anyopaque, buffer: []u8) ReadError!usize {
|
||||
return Actions.read(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||
}
|
||||
}.read,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn read(self: Reader, buffer: []u8) ReadError!usize {
|
||||
return self.call(self.context, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn Tag(comptime Element: type) type {
|
||||
return switch (@typeInfo(Element)) {
|
||||
.Enum => |info| info.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) ++ "'"),
|
||||
};
|
||||
}
|
||||
|
||||
pub const WriteError = error{
|
||||
IoUnavailable,
|
||||
};
|
||||
|
||||
pub const Writer = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (context: *anyopaque, buffer: []const u8) WriteError!usize,
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) Writer {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = @ptrCast(*anyopaque, state),
|
||||
|
||||
.call = struct {
|
||||
fn write(context: *anyopaque, buffer: []const u8) ReadError!usize {
|
||||
return Actions.write(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||
}
|
||||
}.write,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write(self: Writer, buffer: []const u8) WriteError!usize {
|
||||
return self.call(self.context, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn bytes_of(value: anytype) []const u8 {
|
||||
const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
|
||||
|
||||
debug.assert(pointer_info.size == .One);
|
||||
|
||||
return @ptrCast([*]const u8, value)[0 .. @sizeOf(pointer_info.child)];
|
||||
}
|
||||
|
||||
pub fn compare(this: []const u8, that: []const u8) isize {
|
||||
const range = math.min(usize, this.len, that.len);
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < range) : (index += 1) {
|
||||
const difference = @intCast(isize, this[index]) - @intCast(isize, that[index]);
|
||||
|
||||
if (difference != 0) return difference;
|
||||
}
|
||||
|
||||
return @intCast(isize, this.len) - @intCast(isize, that.len);
|
||||
}
|
||||
|
||||
pub fn copy(target: []u8, source: []const u8) void {
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < source.len) : (index += 1) target[index] = source[index];
|
||||
}
|
||||
|
||||
pub fn ends_with(target: []const u8, match: []const u8) bool {
|
||||
if (target.len < match.len) return false;
|
||||
|
||||
var index = @as(usize, 0);
|
||||
|
||||
while (index < match.len) : (index += 1) {
|
||||
if (target[target.len - (1 + index)] != match[match.len - (1 + index)]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn equals(this: []const u8, that: []const u8) bool {
|
||||
if (this.len != that.len) return false;
|
||||
|
||||
{
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < this.len) : (index += 1) if (this[index] != that[index]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var null_context = @as(usize, 0);
|
||||
|
||||
pub const null_writer = Writer.bind(&null_context, struct {
|
||||
pub fn write(context: *usize, buffer: []const u8) usize {
|
||||
debug.assert(context.* == 0);
|
||||
|
||||
return buffer.len;
|
||||
}
|
||||
});
|
||||
|
||||
pub fn slice_sentineled(comptime element: type, comptime sentinel: element, sequence: [*:sentinel]const element) []const element {
|
||||
var length: usize = 0;
|
||||
|
||||
while (sequence[length] != sentinel) : (length += 1) {}
|
||||
|
||||
return sequence[0..length];
|
||||
}
|
||||
|
||||
pub fn stream(output: Writer, input: Reader, buffer: []u8) (ReadError || WriteError)!u64 {
|
||||
var total_written: u64 = 0;
|
||||
var read = try input.read(buffer);
|
||||
|
||||
while (read != 0) {
|
||||
total_written += try output.write(buffer[0..read]);
|
||||
read = try input.read(buffer);
|
||||
}
|
||||
|
||||
return total_written;
|
||||
}
|
||||
|
||||
pub fn swap(comptime Element: type, this: *Element, that: *Element) void {
|
||||
const temp = this.*;
|
||||
|
||||
this.* = that.*;
|
||||
that.* = temp;
|
||||
}
|
||||
|
||||
pub fn tag(value: anytype) Tag(@TypeOf(value)) {
|
||||
return @as(Tag(@TypeOf(value)), value);
|
||||
}
|
||||
|
||||
pub fn zero(target: []u8) void {
|
||||
for (target) |*t| t.* = 0;
|
||||
}
|
||||
const debug = @import("./debug.zig");
|
||||
|
||||
const math = @import("./math.zig");
|
||||
|
||||
pub const MemoryArena = struct {
|
||||
|
||||
|
||||
pub fn as_allocator(self: *MemoryArena) MemoryAllocator {
|
||||
return MemoryAllocator.bind(self, MemoryArena);
|
||||
}
|
||||
};
|
||||
|
||||
pub const MemoryAllocator = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (capture: *anyopaque, maybe_allocation: ?[*]u8, size: usize) ?[*]u8,
|
||||
|
||||
const Capture = [@sizeOf(usize)]u8;
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) MemoryAllocator {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = state,
|
||||
|
||||
.call = struct {
|
||||
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);
|
||||
}
|
||||
}.reallocate,
|
||||
};
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
pub fn allocate_one(self: MemoryAllocator, comptime Type: type) ?*Type {
|
||||
return @ptrCast(?*Type, @alignCast(@alignOf(Type), self.call(self.context, null, @sizeOf(Type))));
|
||||
}
|
||||
|
||||
pub fn deallocate(self: MemoryAllocator, maybe_allocation: anytype) void {
|
||||
if (@typeInfo(@TypeOf(maybe_allocation)) != .Pointer)
|
||||
@compileError("`maybe_allocation` must be a pointer type");
|
||||
|
||||
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 {
|
||||
return @ptrCast(?[*]Type, @alignCast(@alignOf(Type),
|
||||
self.call(self.context, @ptrCast(?[*]u8, maybe_allocation), @sizeOf(Type) * amount)));
|
||||
}
|
||||
};
|
||||
|
||||
pub const ReadError = error{
|
||||
IoUnavailable,
|
||||
};
|
||||
|
||||
pub const Reader = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (context: *anyopaque, buffer: []u8) ReadError!usize,
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) Reader {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (@typeInfo(State) != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = @ptrCast(*anyopaque, state),
|
||||
|
||||
.call = struct {
|
||||
fn read(context: *anyopaque, buffer: []u8) ReadError!usize {
|
||||
return Actions.read(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||
}
|
||||
}.read,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn read(self: Reader, buffer: []u8) ReadError!usize {
|
||||
return self.call(self.context, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn Tag(comptime Element: type) type {
|
||||
return switch (@typeInfo(Element)) {
|
||||
.Enum => |info| info.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) ++ "'"),
|
||||
};
|
||||
}
|
||||
|
||||
pub const WriteError = error{
|
||||
IoUnavailable,
|
||||
};
|
||||
|
||||
pub const Writer = struct {
|
||||
context: *anyopaque,
|
||||
call: *const fn (context: *anyopaque, buffer: []const u8) WriteError!usize,
|
||||
|
||||
pub fn bind(state: anytype, comptime Actions: type) Writer {
|
||||
const State = @TypeOf(state);
|
||||
const state_info = @typeInfo(State);
|
||||
|
||||
if (state_info != .Pointer) @compileError("`@typeOf(state)` must be a pointer type");
|
||||
|
||||
return .{
|
||||
.context = @ptrCast(*anyopaque, state),
|
||||
|
||||
.call = struct {
|
||||
fn write(context: *anyopaque, buffer: []const u8) ReadError!usize {
|
||||
return Actions.write(@ptrCast(State, @alignCast(@alignOf(state_info.Pointer.child), context)), buffer);
|
||||
}
|
||||
}.write,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn write(self: Writer, buffer: []const u8) WriteError!usize {
|
||||
return self.call(self.context, buffer);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn bytes_of(value: anytype) []const u8 {
|
||||
const pointer_info = @typeInfo(@TypeOf(value)).Pointer;
|
||||
|
||||
debug.assert(pointer_info.size == .One);
|
||||
|
||||
return @ptrCast([*]const u8, value)[0 .. @sizeOf(pointer_info.child)];
|
||||
}
|
||||
|
||||
pub fn compare(this: []const u8, that: []const u8) isize {
|
||||
const range = math.min(usize, this.len, that.len);
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < range) : (index += 1) {
|
||||
const difference = @intCast(isize, this[index]) - @intCast(isize, that[index]);
|
||||
|
||||
if (difference != 0) return difference;
|
||||
}
|
||||
|
||||
return @intCast(isize, this.len) - @intCast(isize, that.len);
|
||||
}
|
||||
|
||||
pub fn copy(target: []u8, source: []const u8) void {
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < source.len) : (index += 1) target[index] = source[index];
|
||||
}
|
||||
|
||||
pub fn ends_with(target: []const u8, match: []const u8) bool {
|
||||
if (target.len < match.len) return false;
|
||||
|
||||
var index = @as(usize, 0);
|
||||
|
||||
while (index < match.len) : (index += 1) {
|
||||
if (target[target.len - (1 + index)] != match[match.len - (1 + index)]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn equals(this: []const u8, that: []const u8) bool {
|
||||
if (this.len != that.len) return false;
|
||||
|
||||
{
|
||||
var index: usize = 0;
|
||||
|
||||
while (index < this.len) : (index += 1) if (this[index] != that[index]) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var null_context = @as(usize, 0);
|
||||
|
||||
pub const null_writer = Writer.bind(&null_context, struct {
|
||||
pub fn write(context: *usize, buffer: []const u8) usize {
|
||||
debug.assert(context.* == 0);
|
||||
|
||||
return buffer.len;
|
||||
}
|
||||
});
|
||||
|
||||
pub fn slice_sentineled(comptime element: type, comptime sentinel: element, sequence: [*:sentinel]const element) []const element {
|
||||
var length: usize = 0;
|
||||
|
||||
while (sequence[length] != sentinel) : (length += 1) {}
|
||||
|
||||
return sequence[0..length];
|
||||
}
|
||||
|
||||
pub fn stream(output: Writer, input: Reader, buffer: []u8) (ReadError || WriteError)!u64 {
|
||||
var total_written: u64 = 0;
|
||||
var read = try input.read(buffer);
|
||||
|
||||
while (read != 0) {
|
||||
total_written += try output.write(buffer[0..read]);
|
||||
read = try input.read(buffer);
|
||||
}
|
||||
|
||||
return total_written;
|
||||
}
|
||||
|
||||
pub fn swap(comptime Element: type, this: *Element, that: *Element) void {
|
||||
const temp = this.*;
|
||||
|
||||
this.* = that.*;
|
||||
that.* = temp;
|
||||
}
|
||||
|
||||
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 {
|
||||
BadSyntax,
|
||||
OutOfMemory,
|
||||
};
|
||||
pub const CompileError = bytecode.ParseError;
|
||||
|
||||
const HeapAllocation = union(enum) {
|
||||
next_free: u32,
|
||||
|
@ -33,6 +33,22 @@ pub const Token = union(enum) {
|
||||
keyword_return,
|
||||
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 {
|
||||
return switch (self) {
|
||||
.unknown => |unknown| @ptrCast([*]const u8, &unknown)[0 .. 1],
|
||||
@ -64,6 +80,7 @@ pub const Token = union(enum) {
|
||||
.keyword_false => "false",
|
||||
.keyword_true => "true",
|
||||
.keyword_return => "return",
|
||||
.keyword_self => "self",
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -72,8 +89,12 @@ pub const Tokenizer = struct {
|
||||
source: []const u8,
|
||||
cursor: usize = 0,
|
||||
|
||||
pub fn has_next(self: Tokenizer) bool {
|
||||
return self.cursor < self.source.len;
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
'\n' => {
|
||||
@ -87,13 +108,13 @@ pub const Tokenizer = struct {
|
||||
|
||||
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,
|
||||
|
||||
'.' => {
|
||||
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,
|
||||
else => break,
|
||||
};
|
||||
@ -136,13 +157,13 @@ pub const Tokenizer = struct {
|
||||
'@' => {
|
||||
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', '_' => {
|
||||
const begin = self.cursor;
|
||||
|
||||
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,
|
||||
else => break,
|
||||
};
|
||||
@ -157,7 +178,7 @@ pub const Tokenizer = struct {
|
||||
|
||||
self.cursor += 1;
|
||||
|
||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
||||
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||
'"' => break,
|
||||
else => self.cursor += 1,
|
||||
};
|
||||
@ -180,7 +201,7 @@ pub const Tokenizer = struct {
|
||||
|
||||
self.cursor += 1;
|
||||
|
||||
while (self.cursor < self.source.len) switch (self.source[self.cursor]) {
|
||||
while (self.has_next()) switch (self.source[self.cursor]) {
|
||||
'"' => break,
|
||||
else => self.cursor += 1,
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user