mirror of https://github.com/rm-dr/daisy
Added shadow variables
parent
602fde4441
commit
837f256347
|
@ -6,7 +6,10 @@ use std::collections::HashMap;
|
|||
pub struct Context {
|
||||
history: Vec<Expression>,
|
||||
variables: HashMap<String, Expression>,
|
||||
functions: HashMap<String, (Vec<String>, Expression)>
|
||||
functions: HashMap<String, (Vec<String>, Expression)>,
|
||||
|
||||
// Shadow variables, for function evaluation.
|
||||
shadow: HashMap<String, Option<Expression>>
|
||||
}
|
||||
|
||||
// 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<Expression> {
|
||||
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<String, Expression> {
|
||||
return &self.variables
|
||||
}
|
||||
|
||||
pub fn add_shadow(&mut self, s: String, v: Option<Expression>) {
|
||||
if !self.valid_varible(&s) { panic!() }
|
||||
self.shadow.insert(s, v);
|
||||
}
|
||||
|
||||
pub fn clear_shadow(&mut self) {
|
||||
self.shadow = HashMap::new();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ fn eval_to_str(s: &str) -> Result<String, ()> {
|
|||
};
|
||||
//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(())
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue