diff --git a/src/context.rs b/src/context.rs index 6ef855c..4bcbecf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,7 +6,10 @@ use std::collections::HashMap; pub struct Context { history: Vec, variables: HashMap, - functions: HashMap, Expression)> + functions: HashMap, Expression)>, + + // Shadow variables, for function evaluation. + shadow: HashMap> } // General functions @@ -16,6 +19,7 @@ impl Context { history: Vec::new(), variables: HashMap::new(), functions: HashMap::new(), + shadow: HashMap::new(), } } @@ -42,14 +46,22 @@ impl Context { } else { return Err(()); } } + // Returns None if this is a "floating" variable pub fn get_variable(&self, s: &String) -> Option { + if self.shadow.contains_key(s) { + return self.shadow.get(s).unwrap().clone(); + } + let v: Option<&Expression>; if s == "ans" { v = self.history.last(); } else { v = self.variables.get(s); } - if v.is_some() { Some(v.unwrap().clone()) } else { None } + + if v.is_some() { + return Some(v.unwrap().clone()); + } else { panic!() } } pub fn valid_varible(&self, s: &str) -> bool { @@ -72,13 +84,25 @@ impl Context { } pub fn is_varible(&self, s: &str) -> bool { - return self.valid_varible(s) && self.variables.contains_key(s); + return self.valid_varible(s) && ( + self.variables.contains_key(s) || + self.shadow.contains_key(s) + ); } pub fn get_variables(&self) -> &HashMap { return &self.variables } + pub fn add_shadow(&mut self, s: String, v: Option) { + if !self.valid_varible(&s) { panic!() } + self.shadow.insert(s, v); + } + + pub fn clear_shadow(&mut self) { + self.shadow = HashMap::new(); + } + } diff --git a/src/entry/unix/unix.rs b/src/entry/unix/unix.rs index 260cfeb..aa1f154 100644 --- a/src/entry/unix/unix.rs +++ b/src/entry/unix/unix.rs @@ -40,7 +40,7 @@ fn do_expression( // Evaluate expression #[cfg(debug_assertions)] RawTerminal::suspend_raw_mode(&stdout).unwrap(); - let g_evaluated = evaluate::evaluate(&g, context, false)?; + let g_evaluated = evaluate::evaluate(&g, context)?; #[cfg(debug_assertions)] RawTerminal::activate_raw_mode(&stdout).unwrap(); diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs index 670cf80..7bd37d2 100644 --- a/src/evaluate/evaluate.rs +++ b/src/evaluate/evaluate.rs @@ -10,8 +10,7 @@ use super::function::eval_function; pub fn evaluate( t: &Expression, - context: &mut Context, - allow_incomplete: bool + context: &mut Context ) -> Result< Expression, (LineLocation, DaisyError) @@ -52,19 +51,17 @@ pub fn evaluate( let new = match g { Expression::Quantity(_, _) => None, Expression::Tuple(_, _) => None, - Expression::Constant(_, c) => { Some(evaluate(&c.value(), context, false).unwrap()) }, + Expression::Constant(_, c) => { Some(evaluate(&c.value(), context).unwrap()) }, Expression::Variable(l, s) => { // Don't move up, re-evaluate // This makes variables containing floating variables work properly // (For example, try x = a + 2, a = 2, x. x should evaluate to 4.) move_up = false; - let v = context.get_variable(&s); + if !context.is_varible(&s) { + return Err((*l, DaisyError::Undefined(s.clone()))); + } - // Error if variable is undefined. - // Comment this to allow floating varables. - if v.is_none() { return Err((*l, DaisyError::Undefined(s.clone()))); } - - v + context.get_variable(&s) }, Expression::Operator(_, Operator::Function(_), _) => { Some(eval_function(g)?) }, Expression::Operator(_, _, _) => { eval_operator(g, context)? }, @@ -80,13 +77,13 @@ pub fn evaluate( *g = new; } else { - if !allow_incomplete { - if let Expression::Quantity(_, _) = g {} - else { - let l = g.get_linelocation(); - return Err((l, DaisyError::EvaluationError)) - } + /* + if let Expression::Quantity(_, _) = g {} + else { + let l = g.get_linelocation(); + return Err((l, DaisyError::EvaluationError)) } + */ // Always move up if we couldn't evaluate this node. move_up = true; diff --git a/src/parser/token.rs b/src/parser/token.rs index ba6c62f..bba2be4 100644 --- a/src/parser/token.rs +++ b/src/parser/token.rs @@ -78,15 +78,13 @@ impl Token { }, Token::Word(l, s) => { - let c = Constant::from_string(&s); if c.is_some() { return Ok(Expression::Constant(l, c.unwrap())); } let c = Unit::from_string(&s); if c.is_some() { return Ok(Expression::Quantity(l, c.unwrap())); } - let c = context.get_variable(&s); - if c.is_some() { return Ok(Expression::Variable(l, s)); } + if context.is_varible(&s) { return Ok(Expression::Variable(l, s)); } return Ok(Expression::Variable(l, s)); } diff --git a/src/tests.rs b/src/tests.rs index 4078fb8..204b313 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -10,7 +10,7 @@ fn eval_to_str(s: &str) -> Result { }; //let out_str = g.print(); - return match evaluate(&g, &mut Context::new(), false) { + return match evaluate(&g, &mut Context::new()) { Ok(x) => Ok(x.to_string_outer()), Err(_) => Err(()) };