From e7e7ef3b10d1ffab2707be735f5274f826527195 Mon Sep 17 00:00:00 2001 From: ctsk <9384305+ctsk@users.noreply.github.com> Date: Sun, 8 Oct 2023 11:20:00 +0200 Subject: [PATCH] [rlox] Clean up --- rlox/src/bc.rs | 34 ++++++++++----- rlox/src/lc.rs | 109 ++++++++++++++++++++++++++--------------------- rlox/src/main.rs | 17 +++++++- rlox/src/vm.rs | 60 +++++++++++++------------- 4 files changed, 131 insertions(+), 89 deletions(-) diff --git a/rlox/src/bc.rs b/rlox/src/bc.rs index a345af2..6b86012 100644 --- a/rlox/src/bc.rs +++ b/rlox/src/bc.rs @@ -1,7 +1,7 @@ use std::convert::From; use std::fmt; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Op { Return, Constant { offset: usize }, @@ -44,14 +44,28 @@ impl Chunk { } } - pub fn add_op(&mut self, op: Op, line: usize) { - self.code.push(op); - self.debug_info.push(line); + pub fn new_with(code: Vec, debug_info: Vec, constants: Vec) -> Self { + Chunk { + code, + debug_info, + constants + } } - pub fn add_constant(&mut self, value: Value) -> usize { + pub fn instr_eq(&self, other: &Chunk) -> bool { + self.code == other.code && self.constants == other.constants + } + + pub fn add_op(&mut self, op: Op, line: usize) -> &mut Self { + self.code.push(op); + self.debug_info.push(line); + + self + } + + pub fn add_constant(&mut self, value: Value, line: usize) -> &mut Self { self.constants.push(value); - self.constants.len() - 1 + self.add_op(Op::Constant {offset: self.constants.len() - 1}, line) } } @@ -69,8 +83,8 @@ impl fmt::Debug for Chunk { "{:?}", TraceInfo { offset: idx, - op: op, - chunk: &self + op, + chunk: self } )?; } @@ -82,9 +96,7 @@ impl fmt::Debug for Chunk { impl fmt::Debug for NamedChunk { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { writeln!(f, "-*-*- {} -*-*-", self.name)?; - write!(f, "{:?}", self.chunk)?; - - Ok(()) + write!(f, "{:?}", self.chunk) } } diff --git a/rlox/src/lc.rs b/rlox/src/lc.rs index a82ba45..6181a89 100644 --- a/rlox/src/lc.rs +++ b/rlox/src/lc.rs @@ -6,8 +6,6 @@ use crate::bc::{Chunk, Op}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] enum TokenType { - Eof, - LeftParen, RightParen, LeftBrace, @@ -111,7 +109,7 @@ impl<'src> Scanner<'src> { where P: Fn(char) -> bool, { - self.iter.next_if(|&(_, c)| p(c)).map(|(p, c)| p) + self.iter.next_if(|&(_, c)| p(c)).map(|(p, _c)| p) } fn consume_if_eq(&mut self, expected: char) -> Option { @@ -132,7 +130,7 @@ impl<'src> Scanner<'src> { } fn consume_until_eq(&mut self, limit: char) -> Option { - while let Some((p, c)) = self.iter.next() { + for (p, c) in self.iter.by_ref() { if c == limit { return Some(p); } @@ -265,7 +263,6 @@ impl<'src> Iterator for Scanner<'src> { struct Parser<'src> { scanner: Peekable>, - chunk: Chunk, } enum Associativity { @@ -309,20 +306,16 @@ impl<'src> Parser<'src> { fn new(sc: Scanner<'src>) -> Self { Parser { scanner: sc.into_iter().peekable(), - chunk: Chunk::new(), } } - fn result(&self) -> &Chunk { - return &self.chunk; - } - fn precedence(ttype: TokenType) -> Precedence { use TokenType::*; match ttype { Plus | Minus => Precedence::Term, Star | Slash => Precedence::Factor, - _ => todo!(), + RightParen => Precedence::None, + _ => panic!("{:?}", ttype), } } @@ -330,53 +323,55 @@ impl<'src> Parser<'src> { use Precedence::*; match prec { Term | Factor => Associativity::Left, + None => Associativity::Left, _ => Associativity::NonAssoc, } } - fn _expression(&mut self, min_prec: Precedence) { + fn _expression(&mut self, chunk: &mut Chunk, min_prec: Precedence) { match self.scanner.next().unwrap() { Token { ttype: TokenType::Minus, span: _, } => { - self._expression(Precedence::Unary); - self.chunk.add_op(Op::Negate, 0) + self._expression(chunk, Precedence::Unary); + chunk.add_op(Op::Negate, 0); } Token { ttype: TokenType::Number, span, - } => match span.parse::() { - Ok(c) => { - let constant_pos = self.chunk.add_constant(c.into()); - self.chunk.add_op(Op::Constant { offset: constant_pos }, 0); - } - _ => panic!("Could not parse number"), - }, + } => { + match span.parse::() { + Ok(c) => chunk.add_constant(c.into(), 0), + _ => panic!("Could not parse number"), + }; + } + Token { + ttype: TokenType::LeftParen, + span: _, + } => { + self._expression(chunk, Precedence::None); + assert_eq!(self.scanner.next().unwrap().ttype, TokenType::RightParen) + } _ => panic!("Expected '-' or number"), }; - loop { - let op = match self.scanner.next_if(|token| { - let op_prec = Self::precedence(token.ttype); - if op_prec == min_prec { - match Self::associativity(min_prec) { - Associativity::Left => false, - Associativity::Right => true, - Associativity::NonAssoc => { - panic!("NonAssoc operation found in associative position") - } + while let Some(op) = self.scanner.next_if(|token| { + let op_prec = Self::precedence(token.ttype); + if op_prec == min_prec { + match Self::associativity(min_prec) { + Associativity::Left => false, + Associativity::Right => true, + Associativity::NonAssoc => { + panic!("NonAssoc operation found in associative position") } - } else { - return op_prec > min_prec; } - }) { - Some(token) => token, - None => break, - }; - + } else { + op_prec > min_prec + } + }) { // Generates code for rhs - self._expression(Self::precedence(op.ttype)); + self._expression(chunk, Self::precedence(op.ttype)); let op_decoded = match op.ttype { TokenType::Plus => Op::Add, @@ -386,22 +381,25 @@ impl<'src> Parser<'src> { _ => todo!(), }; - self.chunk.add_op(op_decoded, 0) + chunk.add_op(op_decoded, 0); } } - pub fn expression(&mut self) { - self._expression(Precedence::None); + pub fn expression(&mut self, chunk: &mut Chunk) { + self._expression(chunk, Precedence::None) } } -pub fn compile(source: &str) { +pub fn compile(source: &str, chunk: &mut Chunk) { let scanner = Scanner::new(source); - let parser = Parser::new(scanner); + let mut parser = Parser::new(scanner); + parser.expression(chunk); } #[cfg(test)] mod tests { + use crate::bc::Value; + use super::*; #[test] @@ -456,12 +454,27 @@ mod tests { #[test] fn test_parser() { - let source = "1 + 1 * 2"; + let source = "1 + 1 * (2 + 1)"; let scanner = Scanner::new(source); let mut parser = Parser::new(scanner); - parser.expression(); - let result = parser.result(); + let mut chunk = Chunk::new(); + parser.expression(&mut chunk); - print!("{:?}", result) + use crate::bc::Op::*; + let expected = Chunk::new_with( + vec![ + Constant { offset: 0 }, + Constant { offset: 1 }, + Constant { offset: 2 }, + Constant { offset: 3 }, + Add, + Multiply, + Add, + ], + vec![], + vec![1., 1., 2., 1.].into_iter().map(Value::from).collect() + ); + + assert!(chunk.instr_eq(&expected)); } } diff --git a/rlox/src/main.rs b/rlox/src/main.rs index ea0563f..f68c36a 100644 --- a/rlox/src/main.rs +++ b/rlox/src/main.rs @@ -15,8 +15,9 @@ fn run_file() { fn main() { let num_args = env::args().len(); + let mut chunk = bc::Chunk::new(); - lc::compile("print(1+2*3)"); + lc::compile("print(1+2*3)", &mut chunk); if num_args == 1 { repl(); @@ -26,3 +27,17 @@ fn main() { println!("Usage: rlox [path]"); } } + +#[cfg(test)] +mod tests { + use crate::{bc::Chunk, lc::compile, vm::VM}; + + #[test] + fn test_compile_and_run_pi_math() { + let source = "-(3 * 7 * 11 * 17) / -(500 + 1000 - 250)"; + let mut chunk = Chunk::new(); + compile(source, &mut chunk); + let mut vm = VM::new(); + vm.run(&chunk).unwrap(); + } +} diff --git a/rlox/src/vm.rs b/rlox/src/vm.rs index dbd4e51..24577a2 100644 --- a/rlox/src/vm.rs +++ b/rlox/src/vm.rs @@ -22,7 +22,7 @@ impl VM { } fn runtime_err(&self, msg: &'static str) -> VMError { - return VMError::Runtime(msg, self.pc); + VMError::Runtime(msg, self.pc) } fn push(&mut self, value: Value) { @@ -30,7 +30,9 @@ impl VM { } fn pop(&mut self) -> Result { - self.stack.pop().ok_or_else(|| self.runtime_err("Attempt to pop of empty stack.")) + self.stack + .pop() + .ok_or_else(|| self.runtime_err("Attempt to pop of empty stack.")) } pub fn run(&mut self, chunk: &Chunk) -> Result<(), VMError> { @@ -50,7 +52,7 @@ impl VM { TraceInfo { offset: self.pc - 1, op: instr, - chunk: chunk + chunk } ); } @@ -70,14 +72,14 @@ impl VM { Op::Subtract => Ok(a.val - b.val), Op::Multiply => Ok(a.val * b.val), Op::Divide => Ok(a.val / b.val), - _ => Err(self.runtime_err("Op not implemented")) + _ => Err(self.runtime_err("Op not implemented")), }?; self.push(r.into()) } } } - return Ok(()); + Ok(()) } } @@ -87,30 +89,30 @@ mod tests { #[test] fn simple_arithmetic() { - let mut chunk = Chunk::new(); - chunk.add_constant(Value::from(3.)); - chunk.add_constant(Value::from(7.)); - chunk.add_constant(Value::from(11.)); - chunk.add_constant(Value::from(17.)); - chunk.add_constant(Value::from(500.)); - chunk.add_constant(Value::from(1000.)); - chunk.add_constant(Value::from(250.)); - - chunk.add_op(Op::Constant { offset: 0 }, 1); - chunk.add_op(Op::Constant { offset: 1 }, 1); - chunk.add_op(Op::Multiply, 1); - chunk.add_op(Op::Constant { offset: 2 }, 1); - chunk.add_op(Op::Constant { offset: 3 }, 1); - chunk.add_op(Op::Multiply, 1); - chunk.add_op(Op::Multiply, 1); - chunk.add_op(Op::Negate, 1); - chunk.add_op(Op::Constant { offset: 4 }, 2); - chunk.add_op(Op::Constant { offset: 5 }, 2); - chunk.add_op(Op::Add, 2); - chunk.add_op(Op::Constant { offset: 6 }, 2); - chunk.add_op(Op::Subtract, 2); - chunk.add_op(Op::Negate, 2); - chunk.add_op(Op::Divide, 2); + let chunk = Chunk::new_with( + vec![ + Op::Constant { offset: 0 }, + Op::Constant { offset: 1 }, + Op::Multiply, + Op::Constant { offset: 2 }, + Op::Constant { offset: 3 }, + Op::Multiply, + Op::Multiply, + Op::Negate, + Op::Constant { offset: 4 }, + Op::Constant { offset: 5 }, + Op::Add, + Op::Constant { offset: 6 }, + Op::Subtract, + Op::Negate, + Op::Divide, + ], + vec![], + vec![3., 7., 11., 17., 500., 1000., 250.] + .into_iter() + .map(Value::from) + .collect(), + ); let mut vm = VM::new(); vm.run(&chunk).unwrap();