From 2dec478b74e0f1027b25c1aa95e414b1ba3d072b Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 14 Jun 2023 14:04:32 -0700 Subject: [PATCH] Added "ans" variable --- src/entry/unix/unix.rs | 53 +++++++++++++++++++++++------------- src/evaluate/evaluate.rs | 23 ++++++++++++---- src/evaluate/mod.rs | 3 +- src/parser/pretoken.rs | 3 ++ src/parser/stage/tokenize.rs | 4 +-- src/parser/token/token.rs | 3 ++ src/tests.rs | 2 +- 7 files changed, 62 insertions(+), 29 deletions(-) diff --git a/src/entry/unix/unix.rs b/src/entry/unix/unix.rs index 1cce689..999b899 100644 --- a/src/entry/unix/unix.rs +++ b/src/entry/unix/unix.rs @@ -21,16 +21,18 @@ use crate::evaluate::EvalError; + #[inline(always)] fn do_expression( stdout: &mut RawTerminal, - s: &String -) -> Result<(), std::io::Error> { + s: &String, + history: &Vec +) -> Result { #[cfg(debug_assertions)] - RawTerminal::suspend_raw_mode(&stdout)?; + RawTerminal::suspend_raw_mode(&stdout).unwrap(); let g = parser::parse(&s); #[cfg(debug_assertions)] - RawTerminal::activate_raw_mode(&stdout)?; + RawTerminal::activate_raw_mode(&stdout).unwrap(); // Check for parse errors if let Err((l, e)) = g { @@ -41,8 +43,8 @@ fn do_expression( "^".repeat(l.len), e.to_string(), color::Fg(color::Reset), - )?; - return Ok(()); + ).unwrap(); + return Err(()); } let Ok(g) = g else {panic!()}; @@ -54,15 +56,15 @@ fn do_expression( style::Bold, color::Fg(color::Magenta), style::Reset, color::Fg(color::Reset), g.to_string() - )?; + ).unwrap(); // Evaluate expression #[cfg(debug_assertions)] - RawTerminal::suspend_raw_mode(&stdout)?; - let g = evaluate(&g); + RawTerminal::suspend_raw_mode(&stdout).unwrap(); + let g = evaluate(&g, history); #[cfg(debug_assertions)] - RawTerminal::activate_raw_mode(&stdout)?; + RawTerminal::activate_raw_mode(&stdout).unwrap(); // Show output if let Ok(q) = g { @@ -73,7 +75,9 @@ fn do_expression( style::Reset, q.to_string_outer(), color::Fg(color::Reset) - )?; + ).unwrap(); + return Ok(q); + } else { match g { Ok(_) => panic!(), @@ -85,7 +89,7 @@ fn do_expression( color::Fg(color::Red), style::Reset, color::Fg(color::Reset), - )?; + ).unwrap(); }, Err(EvalError::ZeroDivision) => { @@ -95,7 +99,7 @@ fn do_expression( color::Fg(color::Red), style::Reset, color::Fg(color::Reset), - )?; + ).unwrap(); }, Err(EvalError::BadMath) => { @@ -105,7 +109,7 @@ fn do_expression( color::Fg(color::Red), style::Reset, color::Fg(color::Reset), - )?; + ).unwrap(); }, Err(EvalError::IncompatibleUnit) => { @@ -115,14 +119,22 @@ fn do_expression( color::Fg(color::Red), style::Reset, color::Fg(color::Reset), - )?; + ).unwrap(); + }, + + Err(EvalError::NoHistory) => { + write!( + stdout, "\n {}{}Evaluation Error: {}There is no previous answer to reference{}\r\n\n", + style::Bold, + color::Fg(color::Red), + style::Reset, + color::Fg(color::Reset), + ).unwrap(); } } } - - - return Ok(()); + return Err(()); } @@ -146,6 +158,8 @@ pub fn main() -> Result<(), std::io::Error> { //write!(stdout, "{:?}", size).unwrap(); let mut pb: PromptBuffer = PromptBuffer::new(64); + let mut history: Vec = Vec::new(); + 'outer: loop { @@ -165,7 +179,8 @@ pub fn main() -> Result<(), std::io::Error> { } else if command::is_command(&in_str) { command::do_command(&mut stdout, &in_str)?; } else { - do_expression(&mut stdout, &in_str)?; + let r = do_expression(&mut stdout, &in_str, &history); + if let Ok(t) = r { history.push(t); } } break; diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs index ccc117d..466beed 100644 --- a/src/evaluate/evaluate.rs +++ b/src/evaluate/evaluate.rs @@ -6,7 +6,7 @@ use super::function::eval_function; use super::EvalError; -pub fn evaluate(t: &Token) -> Result { +pub fn evaluate(t: &Token, history: &Vec) -> Result { let mut g = t.clone(); let mut coords: Vec = Vec::with_capacity(16); coords.push(0); @@ -31,9 +31,18 @@ pub fn evaluate(t: &Token) -> Result { loop { e = match e { Token::Quantity(_) => { break; }, - Token::Constant(c) => { evaluate(&c.value()).unwrap() } - Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? } - Token::Operator(o, v) => { eval_operator(&o, &v)? } + Token::Constant(c) => { evaluate(&c.value(), history).unwrap() }, + Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? }, + Token::Operator(o, v) => { eval_operator(&o, &v)? }, + Token::Variable(s) => { + if s == "ans" { + if history.len() == 0 { + return Err(EvalError::NoHistory); + } else { + history.last().unwrap().clone() + } + } else { panic!(); } + } }; } @@ -50,8 +59,10 @@ pub fn evaluate(t: &Token) -> Result { match h { - Token::Operator(_,_) => { coords.push(0); }, - Token::Constant(_) => { coords.push(0); }, + Token::Operator(_,_) + | Token::Constant(_) + | Token::Variable(_) + => { coords.push(0); }, Token::Quantity(_) => { let l = coords.pop().unwrap(); diff --git a/src/evaluate/mod.rs b/src/evaluate/mod.rs index 4e5cca9..605203d 100644 --- a/src/evaluate/mod.rs +++ b/src/evaluate/mod.rs @@ -9,5 +9,6 @@ pub enum EvalError { BadMath, TooBig, ZeroDivision, - IncompatibleUnit + IncompatibleUnit, + NoHistory } \ No newline at end of file diff --git a/src/parser/pretoken.rs b/src/parser/pretoken.rs index 26d9453..0338907 100644 --- a/src/parser/pretoken.rs +++ b/src/parser/pretoken.rs @@ -83,6 +83,9 @@ impl PreToken { let c = Unit::from_string(&s); if c.is_some() { return Ok(Token::Quantity(c.unwrap())); } + + if s == "ans" { return Ok(Token::Variable(String::from("ans"))); } + return Err((l, ParserError::Undefined(s))); } diff --git a/src/parser/stage/tokenize.rs b/src/parser/stage/tokenize.rs index 98390d0..5d705d7 100644 --- a/src/parser/stage/tokenize.rs +++ b/src/parser/stage/tokenize.rs @@ -50,9 +50,9 @@ fn push_token(g: &mut VecDeque, t: Option, stop_i: usize) { } } + // Some operators are written as words. if let PreToken::PreWord(l, s) = &t { - let o = Operator::from_string(s); - if o.is_some() { + if Operator::from_string(s).is_some() { t = PreToken::PreOperator(*l, s.clone()); } } diff --git a/src/parser/token/token.rs b/src/parser/token/token.rs index 23a6b33..eb3f0ef 100644 --- a/src/parser/token/token.rs +++ b/src/parser/token/token.rs @@ -8,6 +8,7 @@ use super::Constant; #[derive(Debug)] #[derive(Clone)] pub enum Token { + Variable(String), Quantity(Quantity), Constant(Constant), Operator(Operator, VecDeque), @@ -18,6 +19,7 @@ impl ToString for Token { match self { Token::Quantity(v) => v.to_string(), Token::Constant(c) => c.to_string(), + Token::Variable(s) => s.clone(), Token::Operator(o,a) => o.print(a) } } @@ -30,6 +32,7 @@ impl Token { match self { Token::Quantity(v) => v.to_string_outer(), Token::Constant(c) => c.to_string(), + Token::Variable(s) => s.clone(), Token::Operator(o,a) => o.print(a) } } diff --git a/src/tests.rs b/src/tests.rs index 9c08da1..797fbd6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -9,7 +9,7 @@ fn eval_to_str(s: &str) -> Result { }; //let out_str = g.print(); - return match evaluate(&g) { + return match evaluate(&g, &Vec::new()) { Ok(x) => Ok(x.to_string_outer()), Err(_) => Err(()) };