DzLox

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

commit 681d9d22cff1fb9ec93735934a3fbad3380912b2
parent 9c08125283c712015f7c4397fe30d70b8f3dc6f7
Author: Ashymad <szymon.mikulicz@posteo.net>
Date:   Thu, 14 Mar 2024 09:20:31 +0100

Boolean operations

Diffstat:
Mzlox/src/chunk.zig | 3+++
Mzlox/src/compiler.zig | 23+++++++++++++++++------
Mzlox/src/debug.zig | 3+++
Mzlox/src/value.zig | 15+++++++++++----
Mzlox/src/vm.zig | 19+++++++++++--------
Mzlox/src/wrap.zig | 6++++++
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; +}