diff --git a/src/chunk.zig b/src/chunk.zig index eb002d6..50aca63 100644 --- a/src/chunk.zig +++ b/src/chunk.zig @@ -20,6 +20,11 @@ const AllOpcodes = struct { pub False: u8 = 10, pub Not: u8 = 11, + + // comparison op codes! + pub Equal: u8 = 12, + pub Greater: u8 = 13, + pub Less: u8 = 14, }; pub const OpCode = AllOpcodes{}; @@ -178,6 +183,12 @@ pub const Chunk = struct { return try simpleInstruction(stdout, "OP_FALSE", index); } else if (instruction == OpCode.Not) { return try simpleInstruction(stdout, "OP_NOT", index); + } else if (instruction == OpCode.Equal) { + return try simpleInstruction(stdout, "OP_EQUAL", index); + } else if (instruction == OpCode.Greater) { + return try simpleInstruction(stdout, "OP_GREATER", index); + } else if (instruction == OpCode.Less) { + return try simpleInstruction(stdout, "OP_LESS", index); } else { try stdout.print("Unknown opcode: {}\n", instruction); return index + 1; diff --git a/src/compiler.zig b/src/compiler.zig index 5928b95..459adda 100644 --- a/src/compiler.zig +++ b/src/compiler.zig @@ -77,16 +77,16 @@ var rules = []ParseRule{ // as the token enum says, those are 1/2 char tokens. ParseRule{ .prefix = Compiler.unary }, // this is specifically for the != operator - ParseRule{ .precedence = .Equality }, + ParseRule{ .infix = Compiler.binary, .precedence = .Equality }, ParseRule{}, // this is specifically for the == operator - ParseRule{ .precedence = .Equality }, + ParseRule{ .infix = Compiler.binary, .precedence = .Equality }, // all the comparison ones - ParseRule{ .precedence = .Comparison }, - ParseRule{ .precedence = .Comparison }, - ParseRule{ .precedence = .Comparison }, - ParseRule{ .precedence = .Comparison }, + ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, + ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, + ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, + ParseRule{ .infix = Compiler.binary, .precedence = .Comparison }, ParseRule{}, ParseRule{}, @@ -190,7 +190,7 @@ pub const Compiler = struct { try self.currentChunk().write(byte, self.parser.previous.line); } - fn emitBytes(self: *Compiler, byte1: u8, byte2: u82) !void { + fn emitBytes(self: *Compiler, byte1: u8, byte2: u8) !void { try self.emitByte(byte1); try self.emitByte(byte2); } @@ -221,7 +221,6 @@ pub const Compiler = struct { /// Emits bytecode for a number being loaded into the code. fn number(self: *Compiler) !void { - std.debug.warn("parsing number: '{}'\n", self.parser.previous.lexeme); var value: f64 = try std.fmt.parseFloat( f64, self.parser.previous.lexeme, @@ -251,6 +250,15 @@ pub const Compiler = struct { .MINUS => try self.emitByte(OpCode.Subtract), .STAR => try self.emitByte(OpCode.Multiply), .SLASH => try self.emitByte(OpCode.Divide), + + .EQUAL_EQUAL => try self.emitByte(OpCode.Equal), + .GREATER => try self.emitByte(OpCode.Greater), + .LESS => try self.emitByte(OpCode.Less), + + .BANG_EQUAL => try self.emitBytes(OpCode.Equal, OpCode.Not), + .GREATER_EQUAL => try self.emitBytes(OpCode.Less, OpCode.Not), + .LESS_EQUAL => try self.emitBytes(OpCode.Greater, OpCode.Not), + else => unreachable, } } diff --git a/src/vm.zig b/src/vm.zig index 5b89051..1fbf0ac 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -20,6 +20,16 @@ fn isFalsey(val: value.Value) bool { return val.vtype == .Nil or (val.vtype == .Bool and !val.as.Bool); } +fn valuesEqual(a: value.Value, b: value.Value) bool { + if (a.vtype != b.vtype) return false; + + switch (a.vtype) { + .Nil => return true, + .Bool => return a.as.Bool == b.as.Bool, + .Number => return a.as.Number == b.as.Number, + } +} + pub const VM = struct { chk: *Chunk = undefined, src: []const u8, @@ -133,6 +143,18 @@ pub const VM = struct { try self.push(values.NumberVal(a / b)); } + fn doGreater(self: *VM) !void { + var b = try self.popNum(); + var a = try self.popNum(); + try self.push(values.BoolVal(a > b)); + } + + fn doLess(self: *VM) !void { + var b = try self.popNum(); + var a = try self.popNum(); + try self.push(values.BoolVal(a < b)); + } + fn runtimeError(self: *VM, comptime fmt: []const u8, args: ...) void { std.debug.warn(fmt, args); std.debug.warn("\n[line {}] in script\n", self.chk.lines[self.ip]); @@ -170,6 +192,15 @@ pub const VM = struct { chunk.OpCode.True => try self.push(values.BoolVal(true)), chunk.OpCode.False => try self.push(values.BoolVal(false)), + chunk.OpCode.Equal => blk: { + var a = self.pop(); + var b = self.pop(); + try self.push(values.BoolVal(valuesEqual(a, b))); + }, + + chunk.OpCode.Greater => try self.doGreater(), + chunk.OpCode.Less => try self.doLess(), + chunk.OpCode.Add => try self.doAdd(), chunk.OpCode.Subtract => try self.doSub(), chunk.OpCode.Multiply => try self.doMul(), @@ -177,6 +208,7 @@ pub const VM = struct { chunk.OpCode.Not => blk: { try self.push(values.BoolVal(isFalsey(self.pop()))); }, + chunk.OpCode.Negate => blk: { var val = self.peek(0); if (val.vtype != .Bool) {