Native "Syscall" Interface for Kym #21

Merged
kayomn merged 6 commits from kym-native-function into main 2023-07-22 15:03:22 +02:00
13 changed files with 85 additions and 65 deletions
Showing only changes of commit a320a795bc - Show all commits

View File

@ -74,7 +74,7 @@ pub const Stacking = struct {
const aligned_size = (size + alignment - 1) & ~(alignment - 1); const aligned_size = (size + alignment - 1) & ~(alignment - 1);
if (self.pages.values.len == 0) { if (self.pages.values.len == 0) {
const page = try self.allocate_page(math.max(self.min_page_size, aligned_size)); const page = try self.allocate_page(@max(self.min_page_size, aligned_size));
page.used = size; page.used = size;
@ -84,7 +84,7 @@ pub const Stacking = struct {
var page = self.current_page() orelse unreachable; var page = self.current_page() orelse unreachable;
if (page.available() <= aligned_size) { if (page.available() <= aligned_size) {
page = try self.allocate_page(math.max(self.min_page_size, aligned_size)); page = try self.allocate_page(@max(self.min_page_size, aligned_size));
} }
debug.assert(page.available() >= size); debug.assert(page.available() >= size);

View File

@ -96,7 +96,7 @@ pub const FixedBuffer = struct {
} }
pub fn write(self: *FixedBuffer, bytes: []const Byte) usize { pub fn write(self: *FixedBuffer, bytes: []const Byte) usize {
const writable = math.min(self.bytes.len, bytes.len); const writable = @min(self.bytes.len, bytes.len);
copy(self.bytes, bytes); copy(self.bytes, bytes);
@ -251,7 +251,7 @@ pub fn copy(target: []Byte, source: []const Byte) void {
} }
pub fn compare(this: []const Byte, that: []const Byte) isize { pub fn compare(this: []const Byte, that: []const Byte) isize {
const range = math.min(this.len, that.len); const range = @min(this.len, that.len);
var index: usize = 0; var index: usize = 0;
while (index < range) : (index += 1) { while (index < range) : (index += 1) {

View File

@ -16,16 +16,6 @@ pub fn Stack(comptime Value: type) type {
self.values = self.values[0 .. 0]; self.values = self.values[0 .. 0];
} }
pub fn drop(self: *Self, amount: usize) bool {
if (amount > self.values.len) {
return false;
}
self.values = self.values[0 .. self.values.len - amount];
return true;
}
pub fn free(self: *Self) void { pub fn free(self: *Self) void {
if (self.capacity == 0) { if (self.capacity == 0) {
return; return;
@ -111,7 +101,7 @@ pub fn Stack(comptime Value: type) type {
pub fn push_one(self: *Self, value: Value) io.AllocationError!void { pub fn push_one(self: *Self, value: Value) io.AllocationError!void {
if (self.values.len == self.capacity) { if (self.values.len == self.capacity) {
try self.grow(math.max(1, self.capacity)); try self.grow(@max(1, self.capacity));
} }
const offset_index = self.values.len; const offset_index = self.values.len;
@ -128,7 +118,5 @@ pub fn stack_as_writer(self: *ByteStack) io.Writer {
} }
fn write_stack(stack: *ByteStack, bytes: []const io.Byte) ?usize { fn write_stack(stack: *ByteStack, bytes: []const io.Byte) ?usize {
stack.push_all(bytes) catch return null; return stack.push_all(bytes) catch null;
return bytes.len;
} }

View File

@ -112,6 +112,9 @@ pub fn StringTable(comptime Value: type) type {
pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTraits(Key)) type { pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTraits(Key)) type {
kayomn marked this conversation as resolved
Review

A lot of duplication with @typeInfo(usize).Int and getting min / max limits of int types in general. These could be reduced into a constants declared in function body to reduce repetition.

A lot of duplication with `@typeInfo(usize).Int` and getting min / max limits of int types in general. These could be reduced into a constants declared in function body to reduce repetition.
const load_max = 0.75; const load_max = 0.75;
const hash_int = @typeInfo(usize).Int;
const max_int = math.max_int(hash_int);
const min_int = math.min_int(hash_int);
return struct { return struct {
allocator: io.Allocator, allocator: io.Allocator,
@ -123,8 +126,8 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTra
value: Value, value: Value,
fn write_into(self: Entry, entry_table: []?Entry) bool { fn write_into(self: Entry, entry_table: []?Entry) bool {
const hash_max = math.min(math.max_int(@typeInfo(usize).Int), entry_table.len); const hash_max = @min(max_int, entry_table.len);
var hashed_key = math.wrap(traits.hash(self.key), math.min_int(@typeInfo(usize).Int), hash_max); var hashed_key = math.wrap(traits.hash(self.key), min_int, hash_max);
var iterations = @as(usize, 0); var iterations = @as(usize, 0);
while (true) : (iterations += 1) { while (true) : (iterations += 1) {
@ -175,8 +178,8 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTra
} }
pub fn remove(self: *Self, key: Key) ?Entry { pub fn remove(self: *Self, key: Key) ?Entry {
const hash_max = math.min(math.max_int(@typeInfo(usize).Int), self.entries.len); const hash_max = @min(max_int, self.entries.len);
var hashed_key = math.wrap(traits.hash(key), math.min_int(@typeInfo(usize).Int), hash_max); var hashed_key = math.wrap(traits.hash(key), min_int, hash_max);
while (true) { while (true) {
const entry = &(self.entries[hashed_key] orelse continue); const entry = &(self.entries[hashed_key] orelse continue);
@ -199,8 +202,8 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTra
debug.assert(self.entries.len > self.count); debug.assert(self.entries.len > self.count);
{ {
const hash_max = math.min(math.max_int(@typeInfo(usize).Int), self.entries.len); const hash_max = @min(max_int, self.entries.len);
var hashed_key = math.wrap(traits.hash(key), math.min_int(@typeInfo(usize).Int), hash_max); var hashed_key = math.wrap(traits.hash(key), min_int, hash_max);
while (true) { while (true) {
const entry = &(self.entries[hashed_key] orelse { const entry = &(self.entries[hashed_key] orelse {
@ -273,8 +276,8 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTra
return null; return null;
} }
const hash_max = math.min(math.max_int(@typeInfo(usize).Int), self.entries.len); const hash_max = @min(max_int, self.entries.len);
var hashed_key = math.wrap(traits.hash(key), math.min_int(@typeInfo(usize).Int), hash_max); var hashed_key = math.wrap(traits.hash(key), min_int, hash_max);
var iterations = @as(usize, 0); var iterations = @as(usize, 0);
while (iterations < self.count) : (iterations += 1) { while (iterations < self.count) : (iterations += 1) {
@ -303,7 +306,7 @@ pub fn Table(comptime Key: type, comptime Value: type, comptime traits: TableTra
return; return;
} }
const min_count = math.max(1, self.count); const min_count = @max(1, self.count);
const table_size = min_count * 2; const table_size = min_count * 2;
const allocation = @as([*]?Entry, @ptrCast(@alignCast(try self.allocator.reallocate(null, @sizeOf(?Entry) * table_size))))[0 .. table_size]; const allocation = @as([*]?Entry, @ptrCast(@alignCast(try self.allocator.reallocate(null, @sizeOf(?Entry) * table_size))))[0 .. table_size];

View File

@ -1,7 +1,24 @@
const std = @import("std"); const std = @import("std");
pub fn max(a: anytype, b: anytype) @TypeOf(a, b) { pub fn Int(comptime int: std.builtin.Type.Int) type {
return @max(a, b); return @Type(.{.Int = int});
}
pub fn clamp(value: anytype, lower: anytype, upper: anytype) @TypeOf(value, lower, upper) {
return @max(lower, @min(upper, value));
}
pub fn clamped_cast(comptime dest_int: std.builtin.Type.Int, value: anytype) Int(dest_int) {
const Value = @TypeOf(value);
return switch (@typeInfo(Value)) {
.Int => |int| switch (int.signedness) {
.signed => @intCast(clamp(value, min_int(dest_int), max_int(dest_int))),
.unsigned => @intCast(@min(value, max_int(dest_int))),
},
else => @compileError("`" ++ @typeName(Value) ++ "` cannot be cast to an int"),
};
} }
pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int { pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int {
@ -12,10 +29,6 @@ pub fn max_int(comptime int: std.builtin.Type.Int) comptime_int {
return (1 << (bit_count - @intFromBool(int.signedness == .signed))) - 1; return (1 << (bit_count - @intFromBool(int.signedness == .signed))) - 1;
} }
pub fn min(a: anytype, b: anytype) @TypeOf(a, b) {
return @min(a, b);
}
pub fn min_int(comptime int: std.builtin.Type.Int) comptime_int { pub fn min_int(comptime int: std.builtin.Type.Int) comptime_int {
if (int.signedness == .unsigned) return 0; if (int.signedness == .unsigned) return 0;

View File

@ -126,7 +126,7 @@ pub const DecimalFormat = struct {
switch (@typeInfo(ValueType)) { switch (@typeInfo(ValueType)) {
.Int => |int| { .Int => |int| {
const radix = 10; const radix = 10;
var buffer = [_]u8{0} ** (1 + math.max(int.bits, 1)); var buffer = [_]u8{0} ** (1 + @max(int.bits, 1));
var buffer_start = buffer.len - 1; var buffer_start = buffer.len - 1;
{ {

View File

@ -23,8 +23,9 @@ pub const Manifest = struct {
defer env.discard(ref); defer env.discard(ref);
if (env.unbox(ref).expect_number()) |number| { if (env.unbox(ref).expect_number()) |number| {
// TODO: Add safety-checks to int cast. if (number > 0 and number < coral.math.max_int(@typeInfo(@TypeOf(self.width)).Int)) {
break: get @intFromFloat(number); break: get @intFromFloat(number);
}
} }
break: get self.width; break: get self.width;
@ -36,8 +37,9 @@ pub const Manifest = struct {
defer env.discard(ref); defer env.discard(ref);
if (env.unbox(ref).expect_number()) |number| { if (env.unbox(ref).expect_number()) |number| {
// TODO: Add safety-checks to int cast. if (number > 0 and number < coral.math.max_int(@typeInfo(@TypeOf(self.height)).Int)) {
break: get @intFromFloat(number); break: get @intFromFloat(number);
}
} }
break: get self.height; break: get self.height;
@ -49,7 +51,6 @@ pub const Manifest = struct {
defer env.discard(ref); defer env.discard(ref);
if (env.unbox(ref).expect_number()) |number| { if (env.unbox(ref).expect_number()) |number| {
// TODO: Add safety-checks to int cast.
break: get @floatCast(number); break: get @floatCast(number);
} }
@ -62,7 +63,7 @@ pub const Manifest = struct {
defer env.discard(title_ref); defer env.discard(title_ref);
const title_string = env.unbox(title_ref).expect_string() orelse ""; const title_string = env.unbox(title_ref).expect_string() orelse "";
const limited_title_len = coral.math.min(title_string.len, self.title.len); const limited_title_len = @min(title_string.len, self.title.len);
coral.io.copy(&self.title, title_string[0 .. limited_title_len]); coral.io.copy(&self.title, title_string[0 .. limited_title_len]);
coral.io.zero(self.title[limited_title_len .. self.title.len]); coral.io.zero(self.title[limited_title_len .. self.title.len]);
@ -75,13 +76,28 @@ pub const Manifest = struct {
}; };
pub fn log_info(message: []const coral.io.Byte) void { pub fn log_info(message: []const coral.io.Byte) void {
kayomn marked this conversation as resolved
Review

Potentially (but very unlikely to ever trigger) unsafe length cast.

Could do with clamping the length to the max buffer to be safe.

Potentially (but very unlikely to ever trigger) unsafe length cast. Could do with clamping the length to the max buffer to be safe.
ext.SDL_LogInfo(ext.SDL_LOG_CATEGORY_APPLICATION, "%.*s", @as(c_int, @intCast(message.len)), message.ptr); ext.SDL_LogInfo(
ext.SDL_LOG_CATEGORY_APPLICATION,
"%.*s",
coral.math.clamped_cast(@typeInfo(c_int).Int, message.len),
message.ptr,
);
} }
pub fn log_warn(message: []const coral.io.Byte) void { pub fn log_warn(message: []const coral.io.Byte) void {
ext.SDL_LogWarn(ext.SDL_LOG_CATEGORY_APPLICATION, "%.*s", @as(c_int, @intCast(message.len)), message.ptr); ext.SDL_LogWarn(
ext.SDL_LOG_CATEGORY_APPLICATION,
"%.*s",
coral.math.clamped_cast(@typeInfo(c_int).Int, message.len),
message.ptr,
);
} }
pub fn log_fail(message: []const coral.io.Byte) void { pub fn log_fail(message: []const coral.io.Byte) void {
ext.SDL_LogError(ext.SDL_LOG_CATEGORY_APPLICATION, "%.*s", @as(c_int, @intCast(message.len)), message.ptr); ext.SDL_LogError(
ext.SDL_LOG_CATEGORY_APPLICATION,
"%.*s",
coral.math.clamped_cast(@typeInfo(c_int).Int, message.len),
message.ptr,
);
} }

View File

@ -238,7 +238,7 @@ pub const RuntimeEnv = struct {
return self.raise(error.IllegalState, "out of bounds local get"); return self.raise(error.IllegalState, "out of bounds local get");
} }
return self.local_refs.values[local]; return self.acquire(self.local_refs.values[local]);
} }
pub fn pop_local(self: *RuntimeEnv) RuntimeError!?*RuntimeRef { pub fn pop_local(self: *RuntimeEnv) RuntimeError!?*RuntimeRef {

View File

@ -192,7 +192,7 @@ pub fn parse(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!void {
has_returned = true; has_returned = true;
}, },
.local => |identifier| { .identifier => |identifier| {
tokenizer.step(); tokenizer.step();
switch (tokenizer.token orelse return self.raise(no_effect_message)) { switch (tokenizer.token orelse return self.raise(no_effect_message)) {
@ -221,7 +221,7 @@ pub fn parse(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!void {
} }
}, },
.global => |identifier| { .special_identifier => |identifier| {
tokenizer.step(); tokenizer.step();
switch (tokenizer.token orelse return self.raise(no_effect_message)) { switch (tokenizer.token orelse return self.raise(no_effect_message)) {
@ -333,7 +333,7 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!Expression
return Expression{.string_literal = value}; return Expression{.string_literal = value};
}, },
.global => |identifier| { .special_identifier => |identifier| {
tokenizer.skip(.newline); tokenizer.skip(.newline);
var expression_list = Expression.List.make(allocator); var expression_list = Expression.List.make(allocator);
@ -375,7 +375,7 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!Expression
} }
}, },
.local => |identifier| { .identifier => |identifier| {
tokenizer.step(); tokenizer.step();
return Expression{.get_local = identifier}; return Expression{.get_local = identifier};
@ -394,7 +394,7 @@ fn parse_factor(self: *Self, tokenizer: *tokens.Tokenizer) ParseError!Expression
return Expression{.table_literal = table_fields}; return Expression{.table_literal = table_fields};
}, },
.local => |identifier| { .identifier => |identifier| {
tokenizer.skip(.newline); tokenizer.skip(.newline);
if (!tokenizer.is_token(.symbol_equals)) { if (!tokenizer.is_token(.symbol_equals)) {

View File

@ -23,7 +23,7 @@ pub fn new(env: *kym.RuntimeEnv) kym.RuntimeError!?*kym.RuntimeRef {
return try env.new_dynamic(coral.io.bytes_of(&self), &typeinfo); return try env.new_dynamic(coral.io.bytes_of(&self), &typeinfo);
} }
pub const typeinfo = kym.Typeinfo{ const typeinfo = kym.Typeinfo{
.name = "table", .name = "table",
.clean = typeinfo_clean, .clean = typeinfo_clean,
.get = typeinfo_get, .get = typeinfo_get,

View File

@ -1,11 +1,11 @@
const coral = @import("coral"); const coral = @import("coral");
pub const Token = union(enum) { pub const Token = union(enum) {
unknown: u8, unknown: coral.io.Byte,
newline, newline,
global: []const u8, special_identifier: []const coral.io.Byte,
local: []const u8, identifier: []const coral.io.Byte,
symbol_plus, symbol_plus,
symbol_minus, symbol_minus,
@ -29,8 +29,8 @@ pub const Token = union(enum) {
symbol_equals, symbol_equals,
symbol_double_equals, symbol_double_equals,
number: []const u8, number: []const coral.io.Byte,
string: []const u8, string: []const coral.io.Byte,
keyword_nil, keyword_nil,
keyword_false, keyword_false,
@ -39,13 +39,13 @@ pub const Token = union(enum) {
keyword_self, keyword_self,
keyword_const, keyword_const,
pub fn text(self: Token) []const u8 { pub fn text(self: Token) []const coral.io.Byte {
return switch (self) { return switch (self) {
.unknown => |unknown| @as([*]const u8, @ptrCast(&unknown))[0 .. 1], .unknown => |unknown| @as([*]const coral.io.Byte, @ptrCast(&unknown))[0 .. 1],
.newline => "newline", .newline => "newline",
.global => |identifier| identifier, .special_identifier => |identifier| identifier,
.local => |identifier| identifier, .identifier => |identifier| identifier,
.symbol_plus => "+", .symbol_plus => "+",
.symbol_minus => "-", .symbol_minus => "-",
@ -83,7 +83,7 @@ pub const Token = union(enum) {
}; };
pub const Tokenizer = struct { pub const Tokenizer = struct {
source: []const u8, source: []const coral.io.Byte,
lines_stepped: usize = 1, lines_stepped: usize = 1,
token: ?Token = null, token: ?Token = null,
@ -217,7 +217,7 @@ pub const Tokenizer = struct {
else => {}, else => {},
} }
self.token = .{.local = identifier}; self.token = .{.identifier = identifier};
return; return;
}, },
@ -236,7 +236,7 @@ pub const Tokenizer = struct {
else => break, else => break,
}; };
self.token = .{.global = self.source[begin .. cursor]}; self.token = .{.special_identifier = self.source[begin .. cursor]};
return; return;
}, },
@ -253,7 +253,7 @@ pub const Tokenizer = struct {
else => cursor += 1, else => cursor += 1,
}; };
self.token = .{.global = self.source[begin .. cursor]}; self.token = .{.special_identifier = self.source[begin .. cursor]};
cursor += 1; cursor += 1;
return; return;

View File

@ -67,7 +67,7 @@ pub fn run_app(file_access: file.Access) void {
.caller = kym.Caller.from(kym_log_fail), .caller = kym.Caller.from(kym_log_fail),
}, },
}) catch { }) catch {
return app.log_fail("failed to initialize script runtime"); return app.log_fail("failed to bind syscalls to script runtime");
}; };
var manifest = app.Manifest{}; var manifest = app.Manifest{};

View File

@ -1,5 +1,5 @@
const ona = @import("ona"); const ona = @import("ona");
pub fn main() anyerror!void { pub fn main() void {
ona.run_app(.{.sandboxed_path = &ona.file.Path.cwd}); ona.run_app(.{.sandboxed_path = &ona.file.Path.cwd});
} }