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 {
|
pub struct Context {
|
||||||
history: Vec<Expression>,
|
history: Vec<Expression>,
|
||||||
variables: HashMap<String, 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
|
// General functions
|
||||||
|
@ -16,6 +19,7 @@ impl Context {
|
||||||
history: Vec::new(),
|
history: Vec::new(),
|
||||||
variables: HashMap::new(),
|
variables: HashMap::new(),
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
|
shadow: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,14 +46,22 @@ impl Context {
|
||||||
} else { return Err(()); }
|
} else { return Err(()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns None if this is a "floating" variable
|
||||||
pub fn get_variable(&self, s: &String) -> Option<Expression> {
|
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>;
|
let v: Option<&Expression>;
|
||||||
if s == "ans" {
|
if s == "ans" {
|
||||||
v = self.history.last();
|
v = self.history.last();
|
||||||
} else {
|
} else {
|
||||||
v = self.variables.get(s);
|
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 {
|
pub fn valid_varible(&self, s: &str) -> bool {
|
||||||
|
@ -72,13 +84,25 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_varible(&self, s: &str) -> bool {
|
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> {
|
pub fn get_variables(&self) -> &HashMap<String, Expression> {
|
||||||
return &self.variables
|
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
|
// Evaluate expression
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
RawTerminal::suspend_raw_mode(&stdout).unwrap();
|
RawTerminal::suspend_raw_mode(&stdout).unwrap();
|
||||||
let g_evaluated = evaluate::evaluate(&g, context, false)?;
|
let g_evaluated = evaluate::evaluate(&g, context)?;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
RawTerminal::activate_raw_mode(&stdout).unwrap();
|
RawTerminal::activate_raw_mode(&stdout).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@ use super::function::eval_function;
|
||||||
|
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
t: &Expression,
|
t: &Expression,
|
||||||
context: &mut Context,
|
context: &mut Context
|
||||||
allow_incomplete: bool
|
|
||||||
) -> Result<
|
) -> Result<
|
||||||
Expression,
|
Expression,
|
||||||
(LineLocation, DaisyError)
|
(LineLocation, DaisyError)
|
||||||
|
@ -52,19 +51,17 @@ pub fn evaluate(
|
||||||
let new = match g {
|
let new = match g {
|
||||||
Expression::Quantity(_, _) => None,
|
Expression::Quantity(_, _) => None,
|
||||||
Expression::Tuple(_, _) => 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) => {
|
Expression::Variable(l, s) => {
|
||||||
// Don't move up, re-evaluate
|
// Don't move up, re-evaluate
|
||||||
// This makes variables containing floating variables work properly
|
// This makes variables containing floating variables work properly
|
||||||
// (For example, try x = a + 2, a = 2, x. x should evaluate to 4.)
|
// (For example, try x = a + 2, a = 2, x. x should evaluate to 4.)
|
||||||
move_up = false;
|
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.
|
context.get_variable(&s)
|
||||||
// Comment this to allow floating varables.
|
|
||||||
if v.is_none() { return Err((*l, DaisyError::Undefined(s.clone()))); }
|
|
||||||
|
|
||||||
v
|
|
||||||
},
|
},
|
||||||
Expression::Operator(_, Operator::Function(_), _) => { Some(eval_function(g)?) },
|
Expression::Operator(_, Operator::Function(_), _) => { Some(eval_function(g)?) },
|
||||||
Expression::Operator(_, _, _) => { eval_operator(g, context)? },
|
Expression::Operator(_, _, _) => { eval_operator(g, context)? },
|
||||||
|
@ -80,13 +77,13 @@ pub fn evaluate(
|
||||||
*g = new;
|
*g = new;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if !allow_incomplete {
|
/*
|
||||||
if let Expression::Quantity(_, _) = g {}
|
if let Expression::Quantity(_, _) = g {}
|
||||||
else {
|
else {
|
||||||
let l = g.get_linelocation();
|
let l = g.get_linelocation();
|
||||||
return Err((l, DaisyError::EvaluationError))
|
return Err((l, DaisyError::EvaluationError))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Always move up if we couldn't evaluate this node.
|
// Always move up if we couldn't evaluate this node.
|
||||||
move_up = true;
|
move_up = true;
|
||||||
|
|
|
@ -78,15 +78,13 @@ impl Token {
|
||||||
},
|
},
|
||||||
|
|
||||||
Token::Word(l, s) => {
|
Token::Word(l, s) => {
|
||||||
|
|
||||||
let c = Constant::from_string(&s);
|
let c = Constant::from_string(&s);
|
||||||
if c.is_some() { return Ok(Expression::Constant(l, c.unwrap())); }
|
if c.is_some() { return Ok(Expression::Constant(l, c.unwrap())); }
|
||||||
|
|
||||||
let c = Unit::from_string(&s);
|
let c = Unit::from_string(&s);
|
||||||
if c.is_some() { return Ok(Expression::Quantity(l, c.unwrap())); }
|
if c.is_some() { return Ok(Expression::Quantity(l, c.unwrap())); }
|
||||||
|
|
||||||
let c = context.get_variable(&s);
|
if context.is_varible(&s) { return Ok(Expression::Variable(l, s)); }
|
||||||
if c.is_some() { return Ok(Expression::Variable(l, 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();
|
//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()),
|
Ok(x) => Ok(x.to_string_outer()),
|
||||||
Err(_) => Err(())
|
Err(_) => Err(())
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue