commit 04238b101d6ca652145eeec15fa049e5bbbeebbb
parent b941bf2bbdf0470c8f3ccb8b5f23b2d9c16138e7
Author: Szymon Mikulicz <szymon.mikulicz@aptiv.com>
Date: Sat, 3 Aug 2024 21:38:42 +0200
Indexing maps
Diffstat:
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),