DzLox

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

commit bdf60511df5e35856bb557b5d5946b7b2349f8d4
parent cd43147544be4d6d48a6959ea0bdae6176d9c321
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Sun, 11 Aug 2024 01:20:16 +0200

Start functions

Diffstat:
Mzlox/src/compiler.zig | 32++++++++++++++++++--------------
Mzlox/src/obj/function.zig | 32+++++++++++++++++++++++---------
Mzlox/src/vm.zig | 70+++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
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}); } }; }