mirror of https://github.com/rm-dr/daisy
Added "ans" variable
parent
d00679c44a
commit
2dec478b74
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -9,5 +9,6 @@ pub enum EvalError {
|
||||||
BadMath,
|
BadMath,
|
||||||
TooBig,
|
TooBig,
|
||||||
ZeroDivision,
|
ZeroDivision,
|
||||||
IncompatibleUnit
|
IncompatibleUnit,
|
||||||
|
NoHistory
|
||||||
}
|
}
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue