implementing native functions (ch24)
This commit is contained in:
parent
3daa675f8d
commit
a2200debb4
@ -4,5 +4,8 @@ build:
|
|||||||
run *ARGS:
|
run *ARGS:
|
||||||
zig build run -- {{ARGS}}
|
zig build run -- {{ARGS}}
|
||||||
|
|
||||||
|
run-fast *ARGS:
|
||||||
|
zig build run -Doptimize=ReleaseFast -- {{ARGS}}
|
||||||
|
|
||||||
test:
|
test:
|
||||||
zig build test
|
zig build test
|
||||||
|
@ -14,7 +14,7 @@ While reading [Crafting Interpreters](https://craftinginterpreters.com/), after
|
|||||||
- [x] 21 - Global Variables
|
- [x] 21 - Global Variables
|
||||||
- [x] 22 - Local Variables
|
- [x] 22 - Local Variables
|
||||||
- [x] 23 - Jumping Back and Forth
|
- [x] 23 - Jumping Back and Forth
|
||||||
- [ ] 24 - Calls and Functions
|
- [x] 24 - Calls and Functions
|
||||||
- [ ] 25 - Closures
|
- [ ] 25 - Closures
|
||||||
- [ ] 26 - Garbage Collection
|
- [ ] 26 - Garbage Collection
|
||||||
- [ ] 27 - Classes and Instances
|
- [ ] 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,
|
Primary,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ParserFn = *const fn (*Parser, bool) ParsingError!void;
|
||||||
|
|
||||||
const ParserRule = struct {
|
const ParserRule = struct {
|
||||||
prefix: ?*const fn (*Parser, bool) ParsingError!void,
|
prefix: ?ParserFn,
|
||||||
infix: ?*const fn (*Parser, bool) ParsingError!void,
|
infix: ?ParserFn,
|
||||||
precedence: Precedence,
|
precedence: Precedence,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ pub fn main() !void {
|
|||||||
defer std.process.argsFree(allocator, args);
|
defer std.process.argsFree(allocator, args);
|
||||||
|
|
||||||
var vm = VM.new(allocator);
|
var vm = VM.new(allocator);
|
||||||
|
vm.init_vm();
|
||||||
defer vm.destroy();
|
defer vm.destroy();
|
||||||
|
|
||||||
if (args.len == 1) {
|
if (args.len == 1) {
|
||||||
|
@ -3,14 +3,18 @@ const debug = std.debug;
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
const Chunk = @import("./chunk.zig").Chunk;
|
const Chunk = @import("./chunk.zig").Chunk;
|
||||||
|
const Value = @import("./values.zig").Value;
|
||||||
|
|
||||||
const compute_hash = @import("./utils.zig").compute_hash;
|
const compute_hash = @import("./utils.zig").compute_hash;
|
||||||
|
|
||||||
pub const ObjType = enum {
|
pub const ObjType = enum {
|
||||||
String,
|
String,
|
||||||
Function,
|
Function,
|
||||||
|
Native,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const NativeFn = *const fn (arg_count: usize, args: []Value) Value;
|
||||||
|
|
||||||
pub const Obj = struct {
|
pub const Obj = struct {
|
||||||
kind: ObjType,
|
kind: ObjType,
|
||||||
allocator: std.mem.Allocator,
|
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 {
|
pub fn is_type(self: *Obj, kind: ObjType) bool {
|
||||||
return self.kind == kind;
|
return self.kind == kind;
|
||||||
}
|
}
|
||||||
@ -77,7 +103,11 @@ pub const Obj = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_function(self: *Obj) bool {
|
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 {
|
pub fn print(self: *Obj) void {
|
||||||
@ -94,6 +124,10 @@ pub const Obj = struct {
|
|||||||
debug.print("<fn {s}>", .{obj.name.?.chars});
|
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);
|
const obj: *Function = @fieldParentPtr("obj", self);
|
||||||
obj.destroy();
|
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);
|
std.debug.assert(self.kind == ObjType.Function);
|
||||||
return @fieldParentPtr("obj", self);
|
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 Value = @import("./values.zig").Value;
|
||||||
const Obj = @import("./object.zig").Obj;
|
const Obj = @import("./object.zig").Obj;
|
||||||
const ObjType = @import("./object.zig").ObjType;
|
const ObjType = @import("./object.zig").ObjType;
|
||||||
|
const NativeFn = @import("./object.zig").NativeFn;
|
||||||
const Table = @import("./table.zig").Table;
|
const Table = @import("./table.zig").Table;
|
||||||
|
|
||||||
const compile = @import("./compile.zig").compile;
|
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 {
|
pub fn destroy(self: *VM) void {
|
||||||
if (constants.DEBUG_PRINT_INTERNAL_STRINGS) {
|
if (constants.DEBUG_PRINT_INTERNAL_STRINGS) {
|
||||||
self.strings.dump();
|
self.strings.dump();
|
||||||
@ -378,6 +383,16 @@ pub const VM = struct {
|
|||||||
ObjType.Function => {
|
ObjType.Function => {
|
||||||
return self.call(callee.as_obj().as_function(), arg_count);
|
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 => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -406,4 +421,21 @@ pub const VM = struct {
|
|||||||
|
|
||||||
return true;
|
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