diff --git a/samples/native_power.lox b/samples/native_power.lox new file mode 100644 index 0000000..5b9375a --- /dev/null +++ b/samples/native_power.lox @@ -0,0 +1,3 @@ +print power(str2num("3"),str2num("3")); + +print str2num("3") + str2num("4"); \ No newline at end of file diff --git a/src/native.zig b/src/native.zig new file mode 100644 index 0000000..ddce08c --- /dev/null +++ b/src/native.zig @@ -0,0 +1,64 @@ +const std = @import("std"); + +const Obj = @import("./object.zig").Obj; +const Value = @import("./values.zig").Value; +const VM = @import("./vm.zig").VM; + +pub fn clock(vm: *VM, arg_count: usize, args: []Value) Value { + _ = vm; + _ = arg_count; + _ = args; + + const ts = std.time.milliTimestamp(); + return Value.number_val(@floatFromInt(ts)); +} + +pub fn power(vm: *VM, arg_count: usize, args: []Value) Value { + _ = vm; + + if (arg_count != 2) { + std.debug.print("power() is expecting 2 arguments.\n", .{}); + return Value.nil_val(); + } + + if (!args[0].is_number() or !args[0].is_number()) { + std.debug.print("args must be numbers.\n", .{}); + return Value.nil_val(); + } + + const result_f64: f64 = std.math.pow(f64, args[0].as_number(), args[1].as_number()); + + return Value.number_val(result_f64); +} + +pub fn str2num(vm: *VM, arg_count: usize, args: []Value) Value { + _ = vm; + + if (arg_count != 1 or !args[0].is_string()) { + std.debug.print("str2num() is expecting 1 string argument.\n", .{}); + return Value.nil_val(); + } + + const result = std.fmt.parseFloat(f64, args[0].as_cstring()) catch { + std.debug.print("invalid string for number.\n", .{}); + return Value.nil_val(); + }; + + return Value.number_val(result); +} + +pub fn num2str(vm: *VM, arg_count: usize, args: []Value) Value { + if (arg_count != 1 or !args[0].is_number()) { + std.debug.print("num2str() is expecting 1 number argument.\n", .{}); + return Value.nil_val(); + } + + const str = std.fmt.allocPrint(vm.allocator, "{d}", .{args[0].as_number()}) catch { + std.debug.print("unable to convert number to string.\n", .{}); + return Value.nil_val(); + }; + + const result = Obj.String.new(vm.allocator, str); + + return Value.obj_val(result); +} diff --git a/src/object.zig b/src/object.zig index 09d8704..d5697ed 100644 --- a/src/object.zig +++ b/src/object.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const Chunk = @import("./chunk.zig").Chunk; const Value = @import("./values.zig").Value; +const VM = @import("./vm.zig").VM; const compute_hash = @import("./utils.zig").compute_hash; @@ -13,7 +14,7 @@ pub const ObjType = enum { Native, }; -pub const NativeFn = *const fn (arg_count: usize, args: []Value) Value; +pub const NativeFn = *const fn (vm: *VM, arg_count: usize, args: []Value) Value; pub const Obj = struct { kind: ObjType, diff --git a/src/vm.zig b/src/vm.zig index 08bad7f..c89b6d9 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -12,6 +12,8 @@ const ObjType = @import("./object.zig").ObjType; const NativeFn = @import("./object.zig").NativeFn; const Table = @import("./table.zig").Table; +const natives = @import("./native.zig"); + const compile = @import("./compile.zig").compile; const compute_hash = @import("./utils.zig").compute_hash; @@ -56,7 +58,9 @@ pub const VM = struct { } pub fn init_vm(self: *VM) void { - self.define_native("clock", clock_native); + self.define_native("clock", natives.clock); + self.define_native("power", natives.power); + self.define_native("str2num", natives.str2num); } pub fn destroy(self: *VM) void { @@ -386,8 +390,9 @@ pub const VM = struct { ObjType.Native => { const native_obj: *Obj.Native = callee.as_obj().as_native(); const value = native_obj.native( + self, arg_count, - self.stack[self.current_frame().slots_idx - arg_count .. self.current_frame().slots_idx], + self.stack[self.stack_top - arg_count .. self.stack_top], ); self.stack_top -= arg_count + 1; _ = try self.push(value); @@ -431,11 +436,4 @@ pub const VM = struct { _ = self.pop(); _ = self.pop(); } - - pub fn clock_native(arg_count: usize, args: []Value) Value { - const ts = std.time.milliTimestamp(); - _ = arg_count; - _ = args; - return Value.number_val(@floatFromInt(ts)); - } };