implementing native functions (ch24)
This commit is contained in:
parent
3daa675f8d
commit
a2200debb4
@ -4,5 +4,8 @@ build:
|
||||
run *ARGS:
|
||||
zig build run -- {{ARGS}}
|
||||
|
||||
run-fast *ARGS:
|
||||
zig build run -Doptimize=ReleaseFast -- {{ARGS}}
|
||||
|
||||
test:
|
||||
zig build test
|
||||
|
@ -14,7 +14,7 @@ While reading [Crafting Interpreters](https://craftinginterpreters.com/), after
|
||||
- [x] 21 - Global Variables
|
||||
- [x] 22 - Local Variables
|
||||
- [x] 23 - Jumping Back and Forth
|
||||
- [ ] 24 - Calls and Functions
|
||||
- [x] 24 - Calls and Functions
|
||||
- [ ] 25 - Closures
|
||||
- [ ] 26 - Garbage Collection
|
||||
- [ ] 27 - Classes and Instances
|
||||
|
9
samples/ch24_fib.lox
Normal file
9
samples/ch24_fib.lox
Normal file
@ -0,0 +1,9 @@
|
||||
fun fib(n) {
|
||||
if (n < 2) return n;
|
||||
return fib(n - 2) + fib(n - 1);
|
||||
}
|
||||
|
||||
var start = clock();
|
||||
|
||||
print fib(20);
|
||||
print clock() - start;
|
@ -33,9 +33,11 @@ const Precedence = enum {
|
||||
Primary,
|
||||
};
|
||||
|
||||
const ParserFn = *const fn (*Parser, bool) ParsingError!void;
|
||||
|
||||
const ParserRule = struct {
|
||||
prefix: ?*const fn (*Parser, bool) ParsingError!void,
|
||||
infix: ?*const fn (*Parser, bool) ParsingError!void,
|
||||
prefix: ?ParserFn,
|
||||
infix: ?ParserFn,
|
||||
precedence: Precedence,
|
||||
};
|
||||
|
||||
|
@ -63,6 +63,7 @@ pub fn main() !void {
|
||||
defer std.process.argsFree(allocator, args);
|
||||
|
||||
var vm = VM.new(allocator);
|
||||
vm.init_vm();
|
||||
defer vm.destroy();
|
||||
|
||||
if (args.len == 1) {
|
||||
|
@ -3,14 +3,18 @@ const debug = std.debug;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const Chunk = @import("./chunk.zig").Chunk;
|
||||
const Value = @import("./values.zig").Value;
|
||||
|
||||
const compute_hash = @import("./utils.zig").compute_hash;
|
||||
|
||||
pub const ObjType = enum {
|
||||
String,
|
||||
Function,
|
||||
Native,
|
||||
};
|
||||
|
||||
pub const NativeFn = *const fn (arg_count: usize, args: []Value) Value;
|
||||
|
||||
pub const Obj = struct {
|
||||
kind: ObjType,
|
||||
allocator: std.mem.Allocator,
|
||||
@ -68,6 +72,28 @@ pub const Obj = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Native = struct {
|
||||
obj: Obj,
|
||||
native: NativeFn,
|
||||
|
||||
pub fn new(allocator: std.mem.Allocator, native: NativeFn) *Native {
|
||||
const obj = Obj{
|
||||
.kind = ObjType.Native,
|
||||
.allocator = allocator,
|
||||
};
|
||||
|
||||
const native_obj = allocator.create(Native) catch unreachable;
|
||||
native_obj.obj = obj;
|
||||
native_obj.native = native;
|
||||
|
||||
return native_obj;
|
||||
}
|
||||
|
||||
pub fn destroy(self: *Native) void {
|
||||
self.obj.allocator.destroy(self);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn is_type(self: *Obj, kind: ObjType) bool {
|
||||
return self.kind == kind;
|
||||
}
|
||||
@ -77,7 +103,11 @@ pub const Obj = struct {
|
||||
}
|
||||
|
||||
pub fn is_function(self: *Obj) bool {
|
||||
return self.is_function(ObjType.Function);
|
||||
return self.is_type(ObjType.Function);
|
||||
}
|
||||
|
||||
pub fn is_native(self: *Obj) bool {
|
||||
return self.is_type(ObjType.Native);
|
||||
}
|
||||
|
||||
pub fn print(self: *Obj) void {
|
||||
@ -94,6 +124,10 @@ pub const Obj = struct {
|
||||
debug.print("<fn {s}>", .{obj.name.?.chars});
|
||||
}
|
||||
},
|
||||
ObjType.Native => {
|
||||
// const obj = self.as_native();
|
||||
debug.print("<native fn>", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,6 +141,10 @@ pub const Obj = struct {
|
||||
const obj: *Function = @fieldParentPtr("obj", self);
|
||||
obj.destroy();
|
||||
},
|
||||
ObjType.Native => {
|
||||
const obj: *Native = @fieldParentPtr("obj", self);
|
||||
obj.destroy();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,4 +157,9 @@ pub const Obj = struct {
|
||||
std.debug.assert(self.kind == ObjType.Function);
|
||||
return @fieldParentPtr("obj", self);
|
||||
}
|
||||
|
||||
pub fn as_native(self: *Obj) *Native {
|
||||
std.debug.assert(self.kind == ObjType.Native);
|
||||
return @fieldParentPtr("obj", self);
|
||||
}
|
||||
};
|
||||
|
32
src/vm.zig
32
src/vm.zig
@ -9,6 +9,7 @@ const OpCode = @import("./opcode.zig").OpCode;
|
||||
const Value = @import("./values.zig").Value;
|
||||
const Obj = @import("./object.zig").Obj;
|
||||
const ObjType = @import("./object.zig").ObjType;
|
||||
const NativeFn = @import("./object.zig").NativeFn;
|
||||
const Table = @import("./table.zig").Table;
|
||||
|
||||
const compile = @import("./compile.zig").compile;
|
||||
@ -54,6 +55,10 @@ pub const VM = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn init_vm(self: *VM) void {
|
||||
self.define_native("clock", clock_native);
|
||||
}
|
||||
|
||||
pub fn destroy(self: *VM) void {
|
||||
if (constants.DEBUG_PRINT_INTERNAL_STRINGS) {
|
||||
self.strings.dump();
|
||||
@ -378,6 +383,16 @@ pub const VM = struct {
|
||||
ObjType.Function => {
|
||||
return self.call(callee.as_obj().as_function(), arg_count);
|
||||
},
|
||||
ObjType.Native => {
|
||||
const native_obj: *Obj.Native = callee.as_obj().as_native();
|
||||
const value = native_obj.native(
|
||||
arg_count,
|
||||
self.stack[self.current_frame().slots_idx - arg_count .. self.current_frame().slots_idx],
|
||||
);
|
||||
self.stack_top -= arg_count + 1;
|
||||
_ = try self.push(value);
|
||||
return true;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@ -406,4 +421,21 @@ pub const VM = struct {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn define_native(self: *VM, name: []const u8, native_fn: NativeFn) void {
|
||||
_ = try self.push(Value.obj_val(&self.copy_string(name).obj));
|
||||
_ = try self.push(Value.obj_val(&Obj.Native.new(self.allocator, native_fn).obj));
|
||||
|
||||
_ = self.globals.set(self.stack[0].as_string(), self.stack[1]);
|
||||
|
||||
_ = 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));
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user