[rlox] Add Not op

This commit is contained in:
ctsk
2023-10-08 21:31:07 +02:00
parent 8ace98a215
commit f617738674
3 changed files with 69 additions and 20 deletions

View File

@@ -1,4 +1,4 @@
use crate::bc::Value::Number;
use crate::bc::Value::{Bool, Number};
use std::convert::From;
use std::fmt;
@@ -9,6 +9,7 @@ pub enum Op {
Nil,
True,
False,
Not,
Negate,
Add,
Subtract,
@@ -30,6 +31,13 @@ impl Value {
_ => None,
}
}
pub fn as_bool(self) -> Option<bool> {
match self {
Bool(val) => Some(val),
_ => None,
}
}
}
impl From<f64> for Value {
@@ -38,6 +46,12 @@ impl From<f64> for Value {
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Bool(value)
}
}
pub struct Chunk {
pub code: Vec<Op>,
pub debug_info: Vec<usize>,
@@ -139,7 +153,8 @@ impl fmt::Debug for TraceInfo<'_> {
match op {
Op::Return | Op::Nil | Op::True
| Op::False | Op::Negate | Op::Add
| Op::Subtract | Op::Multiply | Op::Divide => {
| Op::Subtract | Op::Multiply | Op::Divide
| Op::Not => {
write!(f, "{:?}", op)
}
Op::Constant { offset } => {

View File

@@ -333,11 +333,16 @@ impl<'src> Parser<'src> {
None => panic!("Expected further tokens"),
Some(token) => match token {
Token {
ttype: TokenType::Minus,
ttype: ttype@(TokenType::Minus | TokenType::Bang),
span: _,
} => {
self._expression(chunk, Precedence::Unary);
chunk.add_op(Op::Negate, 0);
let op = match ttype {
TokenType::Minus => Op::Negate,
TokenType::Bang => Op::Not,
_ => unreachable!(),
};
chunk.add_op(op, 0);
}
Token {
ttype: TokenType::Number,
@@ -467,14 +472,17 @@ mod tests {
);
}
#[test]
fn test_parser() {
let source = "1 + 1 * (2 + 1)";
fn test_parse_expression(source: &str, expected: &Chunk) {
let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new();
parser.expression(&mut chunk);
assert!(chunk.instr_eq(expected));
}
#[test]
fn test_parser() {
let source = "1 + 1 * (2 + 1)";
use crate::bc::Op::*;
let expected = Chunk::new_with(
vec![
@@ -490,17 +498,12 @@ mod tests {
vec![1., 1., 2., 1.].into_iter().map(Value::from).collect(),
);
assert!(chunk.instr_eq(&expected));
test_parse_expression(source, &expected);
}
#[test]
fn parse_nil() {
let source = "nil + nil";
let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new();
parser.expression(&mut chunk);
use crate::bc::Op::*;
let expected = Chunk::new_with(
vec![Nil, Nil, Add],
@@ -508,17 +511,12 @@ mod tests {
vec![],
);
assert!(chunk.instr_eq(&expected));
test_parse_expression(source, &expected);
}
#[test]
fn parse_bool_literals() {
let source = "true * false";
let scanner = Scanner::new(source);
let mut parser = Parser::new(scanner);
let mut chunk = Chunk::new();
parser.expression(&mut chunk);
use crate::bc::Op::*;
let expected = Chunk::new_with(
vec![True, False, Multiply],
@@ -526,7 +524,19 @@ mod tests {
vec![],
);
assert!(chunk.instr_eq(&expected));
test_parse_expression(source, &expected);
}
#[test]
fn parse_bool_expression() {
let source = "!false";
use crate::bc::Op::*;
let expected = Chunk::new_with(
vec![False, Not],
vec![],
vec![],
);
test_parse_expression(source, &expected);
}
}

View File

@@ -51,6 +51,13 @@ impl VM {
.ok_or(self.type_err("Number", top_of_stack))
}
fn pop_bool(&mut self) -> Result<bool, VMError> {
let top_of_stack = self.pop()?;
top_of_stack
.as_bool()
.ok_or(self.type_err("Boolean", top_of_stack))
}
pub fn run(&mut self, chunk: &Chunk) -> Result<Option<Value>, VMError> {
while self.pc < chunk.code.len() {
let instr = chunk.code[self.pc];
@@ -83,6 +90,10 @@ impl VM {
let new_val = -self.pop_num()?;
self.push(new_val.into());
}
Op::Not => {
let new_val = !self.pop_bool()?;
self.push(new_val.into());
}
Op::Add | Op::Subtract | Op::Multiply | Op::Divide => {
let b = self.pop_num()?;
let a = self.pop_num()?;
@@ -158,4 +169,17 @@ mod tests {
vm.type_err("Number", Value::Nil)
);
}
#[test]
fn simple_booleans() {
let chunk = Chunk::new_with(
vec![Op::False, Op::Not],
vec![],
vec![],
);
let mut vm = VM::new();
vm.run(&chunk).unwrap();
assert_eq!(vm.stack[0], true.into());
}
}