commit 681d9d22cff1fb9ec93735934a3fbad3380912b2
parent 9c08125283c712015f7c4397fe30d70b8f3dc6f7
Author: Ashymad <szymon.mikulicz@posteo.net>
Date: Thu, 14 Mar 2024 09:20:31 +0100
Boolean operations
Diffstat:
6 files changed, 51 insertions(+), 18 deletions(-)
diff --git a/zlox/src/chunk.zig b/zlox/src/chunk.zig
@@ -8,6 +8,9 @@ pub const OP = enum(u8) {
NIL,
TRUE,
FALSE,
+ EQUAL,
+ GREATER,
+ LESS,
RETURN,
NEGATE,
ADD,
diff --git a/zlox/src/compiler.zig b/zlox/src/compiler.zig
@@ -73,13 +73,13 @@ pub const Compiler = struct {
T.STAR => R(null, S.binary, P.FACTOR ),
T.QUESTION => R(null, S.ternary, P.TERNARY ),
T.BANG => R(S.unary, null, P.NONE ),
- T.BANG_EQUAL => R(null, null, P.NONE ),
+ T.BANG_EQUAL => R(null, S.binary, P.EQUALITY ),
T.EQUAL => R(null, null, P.NONE ),
- T.EQUAL_EQUAL => R(null, null, P.NONE ),
- T.GREATER => R(null, null, P.NONE ),
- T.GREATER_EQUAL => R(null, null, P.NONE ),
- T.LESS => R(null, null, P.NONE ),
- T.LESS_EQUAL => R(null, null, P.NONE ),
+ T.EQUAL_EQUAL => R(null, S.binary, P.EQUALITY ),
+ T.GREATER => R(null, S.binary, P.COMPARISON ),
+ T.GREATER_EQUAL => R(null, S.binary, P.COMPARISON ),
+ T.LESS => R(null, S.binary, P.COMPARISON ),
+ T.LESS_EQUAL => R(null, S.binary, P.COMPARISON ),
T.IDENTIFIER => R(null, null, P.NONE ),
T.STRING => R(null, null, P.NONE ),
T.NUMBER => R(S.number, null, P.NONE ),
@@ -148,6 +148,11 @@ pub const Compiler = struct {
self.emitByte(byte);
}
+ fn emit2OP(self: *@This(), op: chunk.OP, op2: chunk.OP) void {
+ self.emitOP(op);
+ self.emitOP(op2);
+ }
+
fn endCompiler(self: *@This()) void {
self.emitReturn();
if (!self.hadError) {
@@ -276,6 +281,12 @@ pub const Compiler = struct {
scanner.TokenType.MINUS => self.emitOP(chunk.OP.SUBTRACT),
scanner.TokenType.STAR => self.emitOP(chunk.OP.MULTIPLY),
scanner.TokenType.SLASH => self.emitOP(chunk.OP.DIVIDE),
+ scanner.TokenType.BANG_EQUAL => self.emit2OP(chunk.OP.EQUAL, chunk.OP.NOT),
+ scanner.TokenType.EQUAL_EQUAL => self.emitOP(chunk.OP.EQUAL),
+ scanner.TokenType.GREATER => self.emitOP(chunk.OP.GREATER),
+ scanner.TokenType.GREATER_EQUAL => self.emit2OP(chunk.OP.LESS, chunk.OP.NOT),
+ scanner.TokenType.LESS => self.emitOP(chunk.OP.LESS),
+ scanner.TokenType.LESS_EQUAL => self.emit2OP(chunk.OP.GREATER, chunk.OP.NOT),
else => unreachable,
}
}
diff --git a/zlox/src/debug.zig b/zlox/src/debug.zig
@@ -31,6 +31,9 @@ pub fn disassembleInstruction(ch: chunk.Chunk, offset: usize) !usize {
@intFromEnum(OP.MULTIPLY) => simpleInstruction("OP_MULTIPLY", offset),
@intFromEnum(OP.TRUE) => simpleInstruction("OP_TRUE", offset),
@intFromEnum(OP.FALSE) => simpleInstruction("OP_FALSE", offset),
+ @intFromEnum(OP.EQUAL) => simpleInstruction("OP_EQUAL", offset),
+ @intFromEnum(OP.LESS) => simpleInstruction("OP_LESS", offset),
+ @intFromEnum(OP.GREATER) => simpleInstruction("OP_GREATER", offset),
@intFromEnum(OP.NIL) => simpleInstruction("OP_NIL", offset),
@intFromEnum(OP.NOT) => simpleInstruction("OP_NOT", offset),
@intFromEnum(OP.CONSTANT) => try constantInstruction("OP_CONSTANT", ch, offset),
diff --git a/zlox/src/value.zig b/zlox/src/value.zig
@@ -24,9 +24,7 @@ pub const Value = union(enum) {
}
pub fn new(comptime tag: Tag, value: tagType(tag)) @This() {
- var ret = @This(){ .number = undefined };
- ret.set(tag, value);
- return ret;
+ return @unionInit(@This(), @tagName(tag), value);
}
pub fn get(self: @This(), comptime tag: Tag) tagType(tag) {
@@ -38,7 +36,7 @@ pub const Value = union(enum) {
}
pub fn tagType(comptime tag: Tag) type {
- return @TypeOf(@field(@This(){ .number = undefined }, @tagName(tag)));
+ return @TypeOf(@field(@unionInit(@This(), @tagName(tag), undefined), @tagName(tag)));
}
pub const ParseNumberError = std.fmt.ParseFloatError;
@@ -54,6 +52,15 @@ pub const Value = union(enum) {
else => true,
};
}
+
+ pub fn equal(self: @This(), other: @This()) bool {
+ if (@intFromEnum(self) != @intFromEnum(other)) return false;
+ return switch (self) {
+ .number => |x| x == other.number,
+ .bool => |x| x == other.bool,
+ .nil => true,
+ };
+ }
};
pub const ValueArray = array.Array(Value, u8, 8);
diff --git a/zlox/src/vm.zig b/zlox/src/vm.zig
@@ -73,13 +73,13 @@ pub const VM = struct {
return (self.stackTop - (1 + distance))[0];
}
- fn binary_op(self: *@This(), comptime tag: Value.Tag, op: fn (type, Value.tagType(tag), Value.tagType(tag)) Value.tagType(tag)) !void {
+ fn binary_op(self: *@This(), comptime in_tag: Value.Tag, comptime out_tag: Value.Tag, op: fn (type, Value.tagType(in_tag), Value.tagType(in_tag)) Value.tagType(out_tag)) !void {
const b = self.pop();
const a = self.pop();
- if (a.is(tag) and b.is(tag)) {
- self.push(Value.new(tag, op(Value.tagType(tag), a.get(tag), b.get(tag))));
+ if (a.is(in_tag) and b.is(in_tag)) {
+ self.push(Value.new(out_tag, op(Value.tagType(in_tag), a.get(in_tag), b.get(in_tag))));
} else {
- self.runtimeError("Operands have invalid types, expected: {s}", .{@tagName(tag)});
+ self.runtimeError("Operands have invalid types, expected: {s}", .{@tagName(in_tag)});
return InterpreterError.RuntimeError;
}
}
@@ -119,12 +119,15 @@ pub const VM = struct {
}
self.push(Value{ .number = -self.pop().number });
},
- @intFromEnum(OP.ADD) => try self.binary_op(Value.number, wrp.add),
- @intFromEnum(OP.SUBTRACT) => try self.binary_op(Value.number, wrp.sub),
- @intFromEnum(OP.MULTIPLY) => try self.binary_op(Value.number, wrp.mul),
- @intFromEnum(OP.DIVIDE) => try self.binary_op(Value.number, wrp.div),
+ @intFromEnum(OP.ADD) => try self.binary_op(Value.number, Value.number, wrp.add),
+ @intFromEnum(OP.SUBTRACT) => try self.binary_op(Value.number, Value.number, wrp.sub),
+ @intFromEnum(OP.MULTIPLY) => try self.binary_op(Value.number, Value.number, wrp.mul),
+ @intFromEnum(OP.DIVIDE) => try self.binary_op(Value.number, Value.number, wrp.div),
@intFromEnum(OP.TRUE) => self.push(Value{ .bool = true }),
@intFromEnum(OP.FALSE) => self.push(Value{ .bool = false }),
+ @intFromEnum(OP.EQUAL) => self.push(Value{ .bool = self.pop().equal(self.pop()) }),
+ @intFromEnum(OP.LESS) => try self.binary_op(Value.number, Value.bool, wrp.less),
+ @intFromEnum(OP.GREATER) => try self.binary_op(Value.number, Value.bool, wrp.more),
@intFromEnum(OP.NIL) => self.push(Value{ .nil = undefined }),
@intFromEnum(OP.NOT) => self.push(Value{ .bool = !self.pop().isTruthy() }),
else => return InterpreterError.CompileError,
diff --git a/zlox/src/wrap.zig b/zlox/src/wrap.zig
@@ -10,3 +10,9 @@ pub fn sub(comptime T: type, a: T, b: T) T {
pub fn div(comptime T: type, a: T, b: T) T {
return a / b;
}
+pub fn less(comptime T: type, a: T, b: T) bool {
+ return a < b;
+}
+pub fn more(comptime T: type, a: T, b: T) bool {
+ return a > b;
+}