From 90e70c4cd2637753ab8104e9dd367d3935b9ed0d Mon Sep 17 00:00:00 2001 From: ctsk <9384305+ctsk@users.noreply.github.com> Date: Mon, 9 Oct 2023 13:47:46 +0200 Subject: [PATCH] [rlox] Make nil falsey + add equal and comparisons --- rlox/src/bc.rs | 14 ++++++-------- rlox/src/lc.rs | 49 +++++++++++++++++++++++-------------------------- rlox/src/vm.rs | 46 ++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/rlox/src/bc.rs b/rlox/src/bc.rs index eb53a7d..370c2e6 100644 --- a/rlox/src/bc.rs +++ b/rlox/src/bc.rs @@ -15,9 +15,12 @@ pub enum Op { Subtract, Multiply, Divide, + Equal, + Greater, + Less, } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub enum Value { Nil, Bool(bool), @@ -112,7 +115,7 @@ impl fmt::Debug for Chunk { TraceInfo { offset: idx, op, - chunk: self + chunk: self, } )?; } @@ -151,18 +154,13 @@ 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::Not => { - write!(f, "{:?}", op) - } Op::Constant { offset } => { f.debug_struct("Constant") .field("val", &chunk.constants[offset]) .finish()?; write!(f, "") } + _ => write!(f, "{:?}", op) } } } diff --git a/rlox/src/lc.rs b/rlox/src/lc.rs index 92ed38e..acbe501 100644 --- a/rlox/src/lc.rs +++ b/rlox/src/lc.rs @@ -286,22 +286,6 @@ enum Precedence { Primary, } -type ParseInfo = (Associativity, Precedence, Op, Option); -fn get_info(ttype: TokenType) -> ParseInfo { - match ttype { - TokenType::Plus => (Associativity::Left, Precedence::Term, Op::Add, None), - TokenType::Minus => ( - Associativity::Left, - Precedence::Term, - Op::Subtract, - Some(Op::Negate), - ), - TokenType::Slash => (Associativity::Left, Precedence::Factor, Op::Divide, None), - TokenType::Star => (Associativity::Left, Precedence::Factor, Op::Multiply, None), - _ => todo!(), - } -} - impl<'src> Parser<'src> { fn new(sc: Scanner<'src>) -> Self { Parser { @@ -314,6 +298,8 @@ impl<'src> Parser<'src> { match ttype { Plus | Minus => Precedence::Term, Star | Slash => Precedence::Factor, + EqualEqual | BangEqual => Precedence::Equality, + Greater | GreaterEqual | Less | LessEqual => Precedence::Comparison, RightParen => Precedence::None, _ => panic!("{:?}", ttype), } @@ -322,8 +308,9 @@ impl<'src> Parser<'src> { fn associativity(prec: Precedence) -> Associativity { use Precedence::*; match prec { - Term | Factor => Associativity::Left, + Term | Factor | Equality | Comparison => Associativity::Left, None => Associativity::Left, + Unary => Associativity::Right, _ => Associativity::NonAssoc, } } @@ -393,15 +380,19 @@ impl<'src> Parser<'src> { // Generates code for rhs self._expression(chunk, Self::precedence(op.ttype)); - let op_decoded = match op.ttype { - TokenType::Plus => Op::Add, - TokenType::Minus => Op::Subtract, - TokenType::Star => Op::Multiply, - TokenType::Slash => Op::Divide, + match op.ttype { + TokenType::Plus => chunk.add_op(Op::Add, 0), + TokenType::Minus => chunk.add_op(Op::Subtract, 0), + TokenType::Star => chunk.add_op(Op::Multiply, 0), + TokenType::Slash => chunk.add_op(Op::Divide, 0), + TokenType::EqualEqual => chunk.add_op(Op::Equal, 0), + TokenType::Greater => chunk.add_op(Op::Greater, 0), + TokenType::Less => chunk.add_op(Op::Less, 0), + TokenType::BangEqual => chunk.add_op(Op::Equal, 0).add_op(Op::Not, 0), + TokenType::GreaterEqual => chunk.add_op(Op::Less, 0).add_op(Op::Not, 0), + TokenType::LessEqual => chunk.add_op(Op::Greater, 0).add_op(Op::Not, 0), _ => todo!(), }; - - chunk.add_op(op_decoded, 0); } } @@ -529,10 +520,16 @@ mod tests { #[test] fn parse_bool_expression() { - let source = "!false"; + let source = "!false == !true >= true <= false > true < false != true"; use crate::bc::Op::*; let expected = Chunk::new_with( - vec![False, Not], + vec![ + False, Not, True, Not, True, Less, Not, + False, Greater, Not, + True, Greater, + False, Less, + Equal, + True, Equal, Not], vec![], vec![], ); diff --git a/rlox/src/vm.rs b/rlox/src/vm.rs index 26a5cf3..5aa38f1 100644 --- a/rlox/src/vm.rs +++ b/rlox/src/vm.rs @@ -95,19 +95,35 @@ impl VM { self.push(new_val.into()); } Op::Not => { - let new_val = !self.pop_bool()?; + let top_of_stack = self.pop()?; + let new_val = match top_of_stack { + Value::Nil => Ok(true), + Value::Bool(val) => Ok(!val), + _ => Err(self.type_err("Boolean or Nil", top_of_stack)), + }?; self.push(new_val.into()); } Op::Add | Op::Subtract | Op::Multiply | Op::Divide => { let b = self.pop_num()?; let a = self.pop_num()?; let r = match instr { - Op::Add => Ok(a + b), - Op::Subtract => Ok(a - b), - Op::Multiply => Ok(a * b), - Op::Divide => Ok(a / b), - _ => Err(self.runtime_err("Op not implemented")), - }?; + Op::Add => a + b, + Op::Subtract => a - b, + Op::Multiply => a * b, + Op::Divide => a / b, + _ => unreachable!(), + }; + self.push(r.into()) + } + Op::Equal | Op::Greater | Op::Less => { + let b = self.pop()?; + let a = self.pop()?; + let r = match instr { + Op::Equal => a == b, + Op::Greater => a > b, + Op::Less => a < b, + _ => unreachable!(), + }; self.push(r.into()) } } @@ -123,6 +139,7 @@ impl VM { #[cfg(test)] mod tests { + use crate::bc::Op::Equal; use super::{Chunk, Op, Value, VM}; use crate::vm::VMError; @@ -177,7 +194,20 @@ mod tests { #[test] fn simple_booleans() { let chunk = Chunk::new_with( - vec![Op::False, Op::Not], + vec![Op::False, Op::Not, Op::False, Op::Not, Op::Equal], + vec![], + vec![], + ); + let mut vm = VM::new(); + vm.run(&chunk).unwrap(); + + assert_eq!(vm.stack[0], true.into()); + } + + #[test] + fn not_nil_is_true() { + let chunk = Chunk::new_with( + vec![Op::Nil, Op::Not], vec![], vec![], );