Compare commits

..

2 commits

Author SHA1 Message Date
71dba5c77d vm: add greater and less 2019-06-02 00:23:50 -03:00
15c58a2216 comparison operators, part 1 2019-06-02 00:16:33 -03:00
3 changed files with 59 additions and 8 deletions

View file

@ -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;

View file

@ -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,
}
}

View file

@ -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) {