From f617738674c7a03de00e4146f9aab6cafbfb301f Mon Sep 17 00:00:00 2001 From: ctsk <9384305+ctsk@users.noreply.github.com> Date: Sun, 8 Oct 2023 21:31:07 +0200 Subject: [PATCH] [rlox] Add Not op --- rlox/src/bc.rs | 19 +++++++++++++++++-- rlox/src/lc.rs | 46 ++++++++++++++++++++++++++++------------------ rlox/src/vm.rs | 24 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/rlox/src/bc.rs b/rlox/src/bc.rs index 400bec8..eb53a7d 100644 --- a/rlox/src/bc.rs +++ b/rlox/src/bc.rs @@ -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 { + match self { + Bool(val) => Some(val), + _ => None, + } + } } impl From for Value { @@ -38,6 +46,12 @@ impl From for Value { } } +impl From for Value { + fn from(value: bool) -> Self { + Bool(value) + } +} + pub struct Chunk { pub code: Vec, pub debug_info: Vec, @@ -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 } => { diff --git a/rlox/src/lc.rs b/rlox/src/lc.rs index ab3a5fc..92ed38e 100644 --- a/rlox/src/lc.rs +++ b/rlox/src/lc.rs @@ -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); } } diff --git a/rlox/src/vm.rs b/rlox/src/vm.rs index 4968847..43d86ce 100644 --- a/rlox/src/vm.rs +++ b/rlox/src/vm.rs @@ -51,6 +51,13 @@ impl VM { .ok_or(self.type_err("Number", top_of_stack)) } + fn pop_bool(&mut self) -> Result { + 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, 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()); + } }