Added "ans" variable

pull/2/head
Mark 2023-06-14 14:04:32 -07:00
parent d00679c44a
commit 2dec478b74
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
7 changed files with 62 additions and 29 deletions

View File

@ -21,16 +21,18 @@ use crate::evaluate::EvalError;
#[inline(always)] #[inline(always)]
fn do_expression( fn do_expression(
stdout: &mut RawTerminal<std::io::Stdout>, stdout: &mut RawTerminal<std::io::Stdout>,
s: &String s: &String,
) -> Result<(), std::io::Error> { history: &Vec<parser::Token>
) -> Result<parser::Token, ()> {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::suspend_raw_mode(&stdout)?; RawTerminal::suspend_raw_mode(&stdout).unwrap();
let g = parser::parse(&s); let g = parser::parse(&s);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::activate_raw_mode(&stdout)?; RawTerminal::activate_raw_mode(&stdout).unwrap();
// Check for parse errors // Check for parse errors
if let Err((l, e)) = g { if let Err((l, e)) = g {
@ -41,8 +43,8 @@ fn do_expression(
"^".repeat(l.len), "^".repeat(l.len),
e.to_string(), e.to_string(),
color::Fg(color::Reset), color::Fg(color::Reset),
)?; ).unwrap();
return Ok(()); return Err(());
} }
let Ok(g) = g else {panic!()}; let Ok(g) = g else {panic!()};
@ -54,15 +56,15 @@ fn do_expression(
style::Bold, color::Fg(color::Magenta), style::Bold, color::Fg(color::Magenta),
style::Reset, color::Fg(color::Reset), style::Reset, color::Fg(color::Reset),
g.to_string() g.to_string()
)?; ).unwrap();
// Evaluate expression // Evaluate expression
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::suspend_raw_mode(&stdout)?; RawTerminal::suspend_raw_mode(&stdout).unwrap();
let g = evaluate(&g); let g = evaluate(&g, history);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
RawTerminal::activate_raw_mode(&stdout)?; RawTerminal::activate_raw_mode(&stdout).unwrap();
// Show output // Show output
if let Ok(q) = g { if let Ok(q) = g {
@ -73,7 +75,9 @@ fn do_expression(
style::Reset, style::Reset,
q.to_string_outer(), q.to_string_outer(),
color::Fg(color::Reset) color::Fg(color::Reset)
)?; ).unwrap();
return Ok(q);
} else { } else {
match g { match g {
Ok(_) => panic!(), Ok(_) => panic!(),
@ -85,7 +89,7 @@ fn do_expression(
color::Fg(color::Red), color::Fg(color::Red),
style::Reset, style::Reset,
color::Fg(color::Reset), color::Fg(color::Reset),
)?; ).unwrap();
}, },
Err(EvalError::ZeroDivision) => { Err(EvalError::ZeroDivision) => {
@ -95,7 +99,7 @@ fn do_expression(
color::Fg(color::Red), color::Fg(color::Red),
style::Reset, style::Reset,
color::Fg(color::Reset), color::Fg(color::Reset),
)?; ).unwrap();
}, },
Err(EvalError::BadMath) => { Err(EvalError::BadMath) => {
@ -105,7 +109,7 @@ fn do_expression(
color::Fg(color::Red), color::Fg(color::Red),
style::Reset, style::Reset,
color::Fg(color::Reset), color::Fg(color::Reset),
)?; ).unwrap();
}, },
Err(EvalError::IncompatibleUnit) => { Err(EvalError::IncompatibleUnit) => {
@ -115,14 +119,22 @@ fn do_expression(
color::Fg(color::Red), color::Fg(color::Red),
style::Reset, style::Reset,
color::Fg(color::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 Err(());
return Ok(());
} }
@ -146,6 +158,8 @@ pub fn main() -> Result<(), std::io::Error> {
//write!(stdout, "{:?}", size).unwrap(); //write!(stdout, "{:?}", size).unwrap();
let mut pb: PromptBuffer = PromptBuffer::new(64); let mut pb: PromptBuffer = PromptBuffer::new(64);
let mut history: Vec<parser::Token> = Vec::new();
'outer: loop { 'outer: loop {
@ -165,7 +179,8 @@ pub fn main() -> Result<(), std::io::Error> {
} else if command::is_command(&in_str) { } else if command::is_command(&in_str) {
command::do_command(&mut stdout, &in_str)?; command::do_command(&mut stdout, &in_str)?;
} else { } 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; break;

View File

@ -6,7 +6,7 @@ use super::function::eval_function;
use super::EvalError; use super::EvalError;
pub fn evaluate(t: &Token) -> Result<Token, EvalError> { pub fn evaluate(t: &Token, history: &Vec<Token>) -> Result<Token, EvalError> {
let mut g = t.clone(); let mut g = t.clone();
let mut coords: Vec<usize> = Vec::with_capacity(16); let mut coords: Vec<usize> = Vec::with_capacity(16);
coords.push(0); coords.push(0);
@ -31,9 +31,18 @@ pub fn evaluate(t: &Token) -> Result<Token, EvalError> {
loop { loop {
e = match e { e = match e {
Token::Quantity(_) => { break; }, Token::Quantity(_) => { break; },
Token::Constant(c) => { evaluate(&c.value()).unwrap() } Token::Constant(c) => { evaluate(&c.value(), history).unwrap() },
Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? } Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? },
Token::Operator(o, v) => { eval_operator(&o, &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<Token, EvalError> {
match h { match h {
Token::Operator(_,_) => { coords.push(0); }, Token::Operator(_,_)
Token::Constant(_) => { coords.push(0); }, | Token::Constant(_)
| Token::Variable(_)
=> { coords.push(0); },
Token::Quantity(_) => { Token::Quantity(_) => {
let l = coords.pop().unwrap(); let l = coords.pop().unwrap();

View File

@ -9,5 +9,6 @@ pub enum EvalError {
BadMath, BadMath,
TooBig, TooBig,
ZeroDivision, ZeroDivision,
IncompatibleUnit IncompatibleUnit,
NoHistory
} }

View File

@ -83,6 +83,9 @@ impl PreToken {
let c = Unit::from_string(&s); let c = Unit::from_string(&s);
if c.is_some() { return Ok(Token::Quantity(c.unwrap())); } 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))); return Err((l, ParserError::Undefined(s)));
} }

View File

@ -50,9 +50,9 @@ fn push_token(g: &mut VecDeque<PreToken>, t: Option<PreToken>, stop_i: usize) {
} }
} }
// Some operators are written as words.
if let PreToken::PreWord(l, s) = &t { if let PreToken::PreWord(l, s) = &t {
let o = Operator::from_string(s); if Operator::from_string(s).is_some() {
if o.is_some() {
t = PreToken::PreOperator(*l, s.clone()); t = PreToken::PreOperator(*l, s.clone());
} }
} }

View File

@ -8,6 +8,7 @@ use super::Constant;
#[derive(Debug)] #[derive(Debug)]
#[derive(Clone)] #[derive(Clone)]
pub enum Token { pub enum Token {
Variable(String),
Quantity(Quantity), Quantity(Quantity),
Constant(Constant), Constant(Constant),
Operator(Operator, VecDeque<Token>), Operator(Operator, VecDeque<Token>),
@ -18,6 +19,7 @@ impl ToString for Token {
match self { match self {
Token::Quantity(v) => v.to_string(), Token::Quantity(v) => v.to_string(),
Token::Constant(c) => c.to_string(), Token::Constant(c) => c.to_string(),
Token::Variable(s) => s.clone(),
Token::Operator(o,a) => o.print(a) Token::Operator(o,a) => o.print(a)
} }
} }
@ -30,6 +32,7 @@ impl Token {
match self { match self {
Token::Quantity(v) => v.to_string_outer(), Token::Quantity(v) => v.to_string_outer(),
Token::Constant(c) => c.to_string(), Token::Constant(c) => c.to_string(),
Token::Variable(s) => s.clone(),
Token::Operator(o,a) => o.print(a) Token::Operator(o,a) => o.print(a)
} }
} }

View File

@ -9,7 +9,7 @@ fn eval_to_str(s: &str) -> Result<String, ()> {
}; };
//let out_str = g.print(); //let out_str = g.print();
return match evaluate(&g) { return match evaluate(&g, &Vec::new()) {
Ok(x) => Ok(x.to_string_outer()), Ok(x) => Ok(x.to_string_outer()),
Err(_) => Err(()) Err(_) => Err(())
}; };