DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

commit 05deccbb3b058e462dbb667bda3086e14f934ce2
parent 206ed850745f3073331e937a445aee5582334310
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Mon, 12 Aug 2024 22:12:41 +0200

Native functions

Diffstat:
Mzlox/src/compiler.zig | 5++++-
Mzlox/src/main.zig | 2+-
Mzlox/src/obj.zig | 2++
Mzlox/src/vm.zig | 25++++++++++++++++++++++---
4 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig @@ -183,7 +183,10 @@ pub fn Compiler(size: comptime_int) type { } fn emitReturn(self: *Self) void { - self.emit2OP(OP.NIL, OP.RETURN); + if (self.currentFunction.type != Obj.Function.Type.Script) { + self.emitOP(OP.NIL); + } + self.emitOP(OP.RETURN); } fn errorAtCurrent(self: *Self, message: []const u8) void { diff --git a/zlox/src/main.zig b/zlox/src/main.zig @@ -39,7 +39,7 @@ pub fn runFile(allocator: std.mem.Allocator, path: []const u8) anyerror!void { } pub fn repl(allocator: std.mem.Allocator, dbg: bool) anyerror!void { - var VM = vm.VM.init(allocator); + var VM = try vm.VM.init(allocator); defer VM.deinit(); _ = Linenoise.linenoiseHistorySetMaxLen(100); diff --git a/zlox/src/obj.zig b/zlox/src/obj.zig @@ -12,11 +12,13 @@ pub const Obj = packed struct { pub const String = @import("obj/string.zig").String; pub const Table = @import("obj/table.zig").Table; pub const Function = @import("obj/function.zig").Function; + pub const Native = @import("obj/native.zig").Native; pub const Type = enum(u8) { String, Table, Function, + Native, pub fn get(comptime self: @This()) type { return @field(Super, @tagName(self)); diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -9,6 +9,7 @@ const Callback = @import("vm/callbacks.zig"); const table = @import("table.zig"); const hash = @import("hash.zig"); const utils = @import("comptime_utils.zig"); +const vm_native = @import("vm/native.zig"); pub const InterpreterError = compiler.CompilerError || Callback.Error || error{ CompileError, RuntimeError, StackOverflow, IndexOutOfBounds, Overflow, DivisionByZero }; @@ -58,9 +59,17 @@ pub const VM = struct { } }; + fn defineNative(self: *@This(), name: []const u8, arity: u8, fun: Obj.Native.Fn) !void { + const nameObj = try self.objects.emplace(.String, &.{name}); + const funObj = try self.objects.emplace_cast(.Native, Obj.Native.Arg{.fun = fun, .name = name, .arity = arity}); + _ = try self.globals.set(nameObj, Global.make_con(Value.init(funObj))); + } - pub fn init(allocator: std.mem.Allocator) @This() { - return @This(){ .globals = Globals.init(allocator), .objects = Obj.List.init(allocator), .allocator = allocator }; + pub fn init(allocator: std.mem.Allocator) !@This() { + var self = @This(){ .globals = Globals.init(allocator), .objects = Obj.List.init(allocator), .allocator = allocator }; + try self.defineNative("clock", 0, vm_native.clock); + try vm_native.set_start(); + return self; } pub fn interpret(self: *@This(), source: []const u8, dbg: bool) InterpreterError!void { @@ -149,6 +158,16 @@ pub const VM = struct { fn callValue(self: *@This(), callee: Value, argCount: u8) !void { if(callee.is(Obj.Type.Function)) { try self.call(callee.obj.cast(.Function) catch unreachable, argCount); + } else if(callee.is(Obj.Type.Native)) { + const native = callee.obj.cast(.Native) catch unreachable; + if (argCount != native.arity) { + self.runtimeError("Expected {d} arguments but got {d}", .{native.arity, argCount}); + return InterpreterError.RuntimeError; + } + const result = native.call(argCount, self.stackTop - argCount); + self.stackTop -= argCount + 1; + self.push(result); + return; } else { self.runtimeError("Can only call functions and classes", .{}); return InterpreterError.RuntimeError; @@ -269,7 +288,7 @@ pub const VM = struct { var pushed = false; if (obj.is(Value.obj)) { switch(obj.obj.type) { - .Function => {}, + .Function, .Native => {}, inline else => |tp| { self.push((obj.obj.cast(tp) catch unreachable).get(key) catch Value.init({})); pushed = true;