diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..879eac1 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,31 @@ +use crate::parser::Token; +use std::collections::HashMap; + +#[derive(Debug)] +pub struct Context { + history: Vec, + variables: HashMap +} + +impl Context { + pub fn new() -> Context { + Context{ history: Vec::new(), variables: HashMap::new() } + } + + pub fn push_hist(&mut self, t: Token) { self.history.push(t); } + pub fn push_var(&mut self, s: String, t: Token) { self.variables.insert(s, t); } + pub fn del_var(&mut self, s: &String) { self.variables.remove(s); } + + pub fn get_variable(&self, s: String) -> Option { + + let v: Option<&Token>; + + if s == "ans" { + v = self.history.last(); + } else { + v = self.variables.get(&s); + } + + if v.is_some() { Some(v.unwrap().clone()) } else { None } + } +} diff --git a/src/entry/unix/unix.rs b/src/entry/unix/unix.rs index 999b899..0be7ea8 100644 --- a/src/entry/unix/unix.rs +++ b/src/entry/unix/unix.rs @@ -13,20 +13,18 @@ use termion::{ }; use super::promptbuffer::PromptBuffer; -//use crate::tokens::EvalError; use crate::parser; use crate::command; use crate::evaluate::evaluate; use crate::evaluate::EvalError; - - +use crate::context::Context; #[inline(always)] fn do_expression( stdout: &mut RawTerminal, s: &String, - history: &Vec + context: &Context ) -> Result { #[cfg(debug_assertions)] RawTerminal::suspend_raw_mode(&stdout).unwrap(); @@ -62,7 +60,7 @@ fn do_expression( // Evaluate expression #[cfg(debug_assertions)] RawTerminal::suspend_raw_mode(&stdout).unwrap(); - let g = evaluate(&g, history); + let g = evaluate(&g, context); #[cfg(debug_assertions)] RawTerminal::activate_raw_mode(&stdout).unwrap(); @@ -158,7 +156,7 @@ pub fn main() -> Result<(), std::io::Error> { //write!(stdout, "{:?}", size).unwrap(); let mut pb: PromptBuffer = PromptBuffer::new(64); - let mut history: Vec = Vec::new(); + let mut context: Context = Context::new(); 'outer: loop { @@ -179,8 +177,8 @@ pub fn main() -> Result<(), std::io::Error> { } else if command::is_command(&in_str) { command::do_command(&mut stdout, &in_str)?; } else { - let r = do_expression(&mut stdout, &in_str, &history); - if let Ok(t) = r { history.push(t); } + let r = do_expression(&mut stdout, &in_str, &context); + if let Ok(t) = r { context.push_hist(t); } } break; diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs index 466beed..31cb77e 100644 --- a/src/evaluate/evaluate.rs +++ b/src/evaluate/evaluate.rs @@ -1,12 +1,13 @@ use crate::parser::Token; use crate::parser::Operator; +use crate::context::Context; + use super::operator::eval_operator; use super::function::eval_function; use super::EvalError; - -pub fn evaluate(t: &Token, history: &Vec) -> Result { +pub fn evaluate(t: &Token, context: &Context) -> Result { let mut g = t.clone(); let mut coords: Vec = Vec::with_capacity(16); coords.push(0); @@ -31,17 +32,13 @@ pub fn evaluate(t: &Token, history: &Vec) -> Result { loop { e = match e { Token::Quantity(_) => { break; }, - Token::Constant(c) => { evaluate(&c.value(), history).unwrap() }, + Token::Constant(c) => { evaluate(&c.value(), context).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!(); } + if let Some(t) = context.get_variable(s) { t } else { + return Err(EvalError::NoHistory); + } } }; } diff --git a/src/main.rs b/src/main.rs index bac372b..9830ace 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ pub mod parser; pub mod command; pub mod quantity; pub mod evaluate; - +pub mod context; mod entry; use crate::entry::main_e; diff --git a/src/tests.rs b/src/tests.rs index 797fbd6..386d31b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,6 +1,7 @@ // Many of these have been borrowed from insect. use crate::parser; use crate::evaluate::evaluate; +use crate::context::Context; fn eval_to_str(s: &str) -> Result { let g = match parser::parse(&String::from(s)) { @@ -9,7 +10,7 @@ fn eval_to_str(s: &str) -> Result { }; //let out_str = g.print(); - return match evaluate(&g, &Vec::new()) { + return match evaluate(&g, &Context::new()) { Ok(x) => Ok(x.to_string_outer()), Err(_) => Err(()) };