commit bdf60511df5e35856bb557b5d5946b7b2349f8d4
parent cd43147544be4d6d48a6959ea0bdae6176d9c321
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date: Sun, 11 Aug 2024 01:20:16 +0200
Start functions
Diffstat:
3 files changed, 92 insertions(+), 42 deletions(-)
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -38,11 +38,11 @@ pub fn Compiler(size: comptime_int) type {
return struct {
current: scanner.Token,
previous: scanner.Token,
- scanner: scanner.Scanner,
+ scanner: *scanner.Scanner,
lastError: CompilerError,
hadError: bool,
panicMode: bool,
- compilingChunk: Chunk,
+ function: *Obj.Function,
objects: *Obj.List,
locals: [size]Local,
localCount: usize,
@@ -151,7 +151,7 @@ pub fn Compiler(size: comptime_int) type {
}
fn currentChunk(self: *Self) *Chunk {
- return &self.compilingChunk;
+ return self.function.chunk;
}
fn emitByte(self: *Self, byte: u8) void {
@@ -178,8 +178,9 @@ pub fn Compiler(size: comptime_int) type {
self.emitOP(op2);
}
- fn endCompiler(self: *Self) void {
+ fn end(self: *Self) *Obj.Function {
self.emitReturn();
+ return self.function;
}
fn emitReturn(self: *Self) void {
@@ -840,31 +841,34 @@ pub fn Compiler(size: comptime_int) type {
self.emitOP(OP.PRINT);
}
- pub fn compile(source: []const u8, objects: *Obj.List, allocator: std.mem.Allocator) CompilerError!Chunk {
- // zig fmt: off
- var self = Self{
- .scanner = try scanner.Scanner.init(source),
+ fn init(scan: *scanner.Scanner, objects: *Obj.List, function: *Obj.Function) Self {
+ return Self{
+ .scanner = scan,
.current = scanner.Token.Empty,
.previous = scanner.Token.Empty,
.panicMode = false,
.hadError = false,
.lastError = scanner.ScannerError.EmptyToken,
- .compilingChunk = try Chunk.init(allocator),
+ .function = function,
.objects = objects,
.locals = [_]Local{Local{.name = scanner.Token.Empty, .depth = 0, .con = true}} ** size,
- .localCount = 0,
+ .localCount = 1,
.scopeDepth = 0,
};
- // zig fmt: on
- errdefer self.compilingChunk.deinit();
+ }
+
+ pub fn compile(source: []const u8, objects: *Obj.List) CompilerError!*Obj.Function {
+ var scan = try scanner.Scanner.init(source);
+ var function = try objects.emplace(Obj.Type.Function, Obj.Function.Type.Script);
+ var self = Self.init(&scan, objects, function.cast(.Function) catch unreachable);
self.advance();
+
while (!self.match(Token.EOF)) {
self.declaration();
}
- self.endCompiler();
- return if (self.hadError) self.lastError else self.compilingChunk;
+ return if (self.hadError) self.lastError else self.end();
}
};
}
diff --git a/zlox/src/obj/function.zig b/zlox/src/obj/function.zig
@@ -7,14 +7,20 @@ const String = Super.String;
pub const Function = packed struct {
const Self = @This();
- pub const Arg = void;
+ pub const Arg = Type;
+
+ pub const Type = enum(u8) {
+ Function,
+ Script
+ };
obj: Super,
arity: u8,
chunk: *chunk.Chunk,
- name: *String,
+ name: ?*String,
+ type: Type,
- pub fn init(_: Arg, allocator: std.mem.Allocator) Error!*Self {
+ pub fn init(tp: Arg, allocator: std.mem.Allocator) Error!*Self {
const self: *Self = try allocator.create(Self);
self.* = Self{
.obj = Super{
@@ -22,8 +28,10 @@ pub const Function = packed struct {
},
.chunk = try allocator.create(chunk.Chunk),
.arity = 0,
+ .name = null,
+ .type = tp,
};
- self.chunk.* = chunk.Chunk.init(allocator);
+ self.chunk.* = try chunk.Chunk.init(allocator);
return self;
}
@@ -31,11 +39,17 @@ pub const Function = packed struct {
return @ptrCast(self);
}
- pub fn format(self: *const Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
- _ = self;
- _ = fmt;
- _ = options;
- _ = writer;
+ pub fn format(self: *const Self, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
+ switch(self.type) {
+ .Function => _ = try writer.write("<function: "),
+ .Script => _ = try writer.write("<script: "),
+ }
+ if (self.name) |name| {
+ _ = try writer.write(name.slice());
+ } else {
+ _ = try writer.write("-anonymous-");
+ }
+ _ = try writer.writeAll(">");
}
pub fn eql(self: *const Self, other: *const Self) bool {
diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig
@@ -8,6 +8,7 @@ const Obj = @import("obj.zig").Obj;
const Callback = @import("vm/callbacks.zig");
const table = @import("table.zig");
const hash = @import("hash.zig");
+const utils = @import("comptime_utils.zig");
pub const InterpreterError = compiler.CompilerError || Callback.Error || error{ CompileError, RuntimeError, IndexOutOfBounds, Overflow, DivisionByZero };
@@ -43,45 +44,76 @@ pub const VM = struct {
const Globals = table.Table(*const Obj.String, Global, hash.hash_t(*const Obj.String), Obj.String.eql);
+ const CallFrame = struct {
+ function: *const Obj.Function,
+ ip: [*]const u8,
+ slots: [*]Value,
+
+ pub fn init(function: *const Obj.Function, slots: [*]Value) @This() {
+ return @This() {
+ .function = function,
+ .ip = function.chunk.code.data.ptr,
+ .slots = slots
+ };
+ }
+ };
+
+
pub fn init(allocator: std.mem.Allocator) @This() {
return @This(){ .globals = Globals.init(allocator), .objects = Obj.List.init(allocator), .allocator = allocator };
}
pub fn interpret(self: *@This(), source: []const u8, dbg: bool) InterpreterError!void {
- const stackSize = 256;
+ const callstack_size = 64;
+ const stack_size = 256;
- var chunk = try compiler.Compiler(stackSize).compile(source, &self.objects, self.allocator);
- defer chunk.deinit();
+ const function = try compiler.Compiler(stack_size).compile(source, &self.objects);
//try debug.disassembleChunk(chunk, "Main");
- try Interpreter(stackSize).run(self, &chunk, dbg);
+ try Interpreter(callstack_size, stack_size).run(self, function, dbg);
}
- fn Interpreter(size: comptime_int) type {
+ fn Interpreter(callstack_size: comptime_int, stack_size: comptime_int) type {
return struct {
- ip: [*]const u8,
- chunk: *const Chunk,
+ frames: [callstack_size]CallFrame,
+ frameCount: usize,
stackTop: [*]Value,
- stack: [size]Value,
+ stack: [stack_size]Value,
vm: *VM,
- pub fn run(vm: *VM, chunk: *Chunk, dbg: bool) InterpreterError!void {
- var self = @This(){ .ip = chunk.code.data.ptr, .chunk = chunk, .stack = [_]Value{Value.init({})} ** size, .stackTop = undefined, .vm = vm };
+ pub fn run(vm: *VM, function: *Obj.Function, dbg: bool) InterpreterError!void {
+ var self = @This(){
+ .frames = [_]CallFrame{undefined} ** callstack_size,
+ .frameCount = 1,
+ .stack = [_]Value{Value.init({})} ** stack_size,
+ .stackTop = undefined,
+ .vm = vm
+ };
self.stackTop = &self.stack;
+ self.frames[0] = CallFrame.init(function, self.stackTop);
+ self.push(Value.init(function.cast()));
try self.execute(dbg);
}
+ fn frame(self: anytype) utils.copy_const(@TypeOf(self), *CallFrame) {
+ return &self.frames[self.frameCount - 1];
+ }
+
+ fn ip(self: *const @This()) [*]const u8 {
+ return self.frame().ip;
+ }
+
fn ip_add(self: *@This(), adv: usize) void {
- self.ip += adv;
+ self.frame().ip += adv;
}
fn ip_sub(self: *@This(), adv: usize) void {
- self.ip -= adv;
+ self.frame().ip -= adv;
}
fn read_byte(self: *@This()) u8 {
- const out: u8 = self.ip[0];
+ const out: u8 = self.ip()[0];
self.ip_add(1);
return out;
}
@@ -93,7 +125,7 @@ pub const VM = struct {
}
fn read_constant(self: *@This()) Value {
- return self.chunk.constants.get(self.read_byte()) catch unreachable;
+ return self.frame().function.chunk.constants.get(self.read_byte()) catch unreachable;
}
fn read_string(self: *@This()) *const Obj.String {
@@ -126,7 +158,7 @@ pub const VM = struct {
}
fn instruction_idx(self: *const @This()) usize {
- return @intFromPtr(self.ip) - @intFromPtr(self.chunk.code.data.ptr);
+ return @intFromPtr(self.ip()) - @intFromPtr(self.frame().function.chunk.code.data.ptr);
}
fn execute(self: *@This(), dbg: bool) !void {
@@ -138,7 +170,7 @@ pub const VM = struct {
std.debug.print("[{s}]", .{stackPtr[0]});
}
std.debug.print("\n", .{});
- _ = try debug.disassembleInstruction(self.chunk.*, self.instruction_idx());
+ _ = try debug.disassembleInstruction(self.frame().function.chunk.*, self.instruction_idx());
}
const instruction: u8 = self.read_byte();
switch (instruction) {
@@ -178,10 +210,10 @@ pub const VM = struct {
self.ip_sub(self.read_short());
},
@intFromEnum(OP.GET_LOCAL) => {
- self.push(self.stack[self.read_byte()]);
+ self.push(self.frame().slots[self.read_byte()]);
},
@intFromEnum(OP.SET_LOCAL) => {
- self.stack[self.read_byte()] = self.peek(0);
+ self.frame().slots[self.read_byte()] = self.peek(0);
},
@intFromEnum(OP.GET_GLOBAL) => {
const name = self.read_string();
@@ -255,7 +287,7 @@ pub const VM = struct {
fn runtimeError(self: *@This(), comptime fmt: []const u8, args: anytype) void {
std.debug.print(fmt, args);
- std.debug.print("\n[line {d}] in script\n", .{self.chunk.lines.get(self.instruction_idx()) catch 0});
+ std.debug.print("\n[line {d}] in script\n", .{self.frame().function.chunk.lines.get(self.instruction_idx()) catch 0});
}
};
}