DzLox

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

commit 04238b101d6ca652145eeec15fa049e5bbbeebbb
parent b941bf2bbdf0470c8f3ccb8b5f23b2d9c16138e7
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date:   Sat,  3 Aug 2024 21:38:42 +0200

Indexing maps

Diffstat:
Mzlox/src/chunk.zig | 2++
Mzlox/src/compiler.zig | 27+++++++++++++++++++++------
Mzlox/src/debug.zig | 2++
Mzlox/src/vm.zig | 24++++++++++++++++++++++++
4 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/zlox/src/chunk.zig b/zlox/src/chunk.zig @@ -30,6 +30,8 @@ pub const OP = enum(u8) { JUMP_IF_FALSE, JUMP, LOOP, + SET_INDEX, + GET_INDEX, }; pub const Chunk = struct { diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig @@ -21,7 +21,7 @@ const Precedence = enum { TERM, // + - FACTOR, // * / UNARY, // ! - - CALL, // . () + CALL, // . () [] PRIMARY, pub fn inc(self: @This()) @This() { @@ -80,9 +80,9 @@ pub fn Compiler(size: comptime_int) type { // zig fmt: off T.LEFT_PAREN => R(S.grouping, null, P.NONE ), T.RIGHT_PAREN => R(null, null, P.NONE ), - T.LEFT_BRACE => R(null, null, P.NONE ), + T.LEFT_BRACE => R(null, null, P.NONE ), T.RIGHT_BRACE => R(null, null, P.NONE ), - T.LEFT_BRACKET => R(S.map, null, P.NONE ), + T.LEFT_BRACKET => R(S.map, S.index, P.CALL ), T.RIGHT_BRACKET => R(null, null, P.NONE ), T.COMMA => R(null, null, P.NONE ), T.DOT => R(null, null, P.NONE ), @@ -258,16 +258,16 @@ pub fn Compiler(size: comptime_int) type { } fn string(self: *Self, _: bool) void { - self.emitConstant(Value.init(self.objects.emplace(.String, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]}) catch |err| { + self.emitConstant(self.parseLiteralString() catch |err| { self.lastError = err; self.errorAtPrevious("Couldn't allocate object"); return; - })); + }); } fn parseLiteralValue(self: *Self) CompilerError!Value { if (self.match(Token.STRING)) { - return Value.init(try self.objects.emplace(.String, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]})); + return self.parseLiteralString(); } else if (self.match(Token.NUMBER)) { return try Value.parseNumber(self.previous.lexeme); } else if (self.match(Token.FALSE)) { @@ -284,6 +284,10 @@ pub fn Compiler(size: comptime_int) type { } } + fn parseLiteralString(self: *Self) !Value { + return Value.init(try self.objects.emplace(.String, &.{self.previous.lexeme[1 .. self.previous.lexeme.len - 1]})); + } + fn parseLiteralMap(self: *Self) CompilerError!Value { var array = try ValueArray.init(self.allocator); defer array.deinit(); @@ -305,6 +309,17 @@ pub fn Compiler(size: comptime_int) type { }); } + fn index(self: *Self, canAssign: bool) void { + self.expression(); + self.consume(Token.RIGHT_BRACKET, "Expect ']' after index expression"); + if (canAssign and self.match(Token.EQUAL)) { + self.expression(); + self.emitOP(OP.SET_INDEX); + } else { + self.emitOP(OP.GET_INDEX); + } + } + fn variable(self: *Self, canAssign: bool) void { self.namedVariable(self.previous, canAssign); } diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig @@ -47,6 +47,8 @@ pub fn disassembleInstruction(ch: chunk.Chunk, offset: usize) !usize { @intFromEnum(OP.JUMP_IF_FALSE) => try jumpInstruction("OP_JUMP_IF_FALSE", true, ch, offset), @intFromEnum(OP.JUMP) => try jumpInstruction("OP_JUMP", true, ch, offset), @intFromEnum(OP.LOOP) => try jumpInstruction("OP_LOOP", false, ch, offset), + @intFromEnum(OP.SET_INDEX) => simpleInstruction("SET_INDEX", offset), + @intFromEnum(OP.GET_INDEX) => simpleInstruction("GET_INDEX", offset), else => blk: { print("Unknown opcode {}\n", .{try ch.code.get(offset)}); break :blk offset + 1; diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig @@ -202,6 +202,30 @@ pub const VM = struct { return InterpreterError.RuntimeError; } }, + @intFromEnum(OP.GET_INDEX) => { + const idx = self.pop(); + const map = self.pop(); + if (!map.is(Obj.Type.Map)) { + self.runtimeError("Cannot index a non-map value", .{}); + return InterpreterError.RuntimeError; + } + self.push((map.obj.cast(.Map) catch unreachable).map.get(idx) catch { + idx.print(); + self.runtimeError(" key does not exist in the map", .{}); + return InterpreterError.RuntimeError; + }); + }, + @intFromEnum(OP.SET_INDEX) => { + const val = self.pop(); + const idx = self.pop(); + const map = self.pop(); + if (!map.is(Obj.Type.Map)) { + self.runtimeError("Cannot index a non-map value", .{}); + return InterpreterError.RuntimeError; + } + _ = try (map.obj.cast(.Map) catch unreachable).map.set(idx, val); + self.push(val); + }, @intFromEnum(OP.DEFINE_GLOBAL) => _ = try self.vm.globals.set(self.read_string(), Global.make_var(self.pop())), @intFromEnum(OP.DEFINE_GLOBAL_CONSTANT) => _ = try self.vm.globals.set(self.read_string(), Global.make_con(self.pop())), @intFromEnum(OP.SUBTRACT) => try self.binary_op(Value.number, Value.number, Callback.sub),