From 53238250b985bcfbcf7d86a836e4b52e3fa3e9cc Mon Sep 17 00:00:00 2001 From: Adrian Schneider Date: Sat, 28 Aug 2021 21:56:57 +0200 Subject: [PATCH 1/2] start work on adding variable support --- core/src/ast/query.rs | 1 + core/src/context.rs | 5 +++++ core/src/eval.rs | 15 +++++++++++++-- core/src/text_query.rs | 11 +++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/core/src/ast/query.rs b/core/src/ast/query.rs index 9f5a29d5..c0a17e83 100644 --- a/core/src/ast/query.rs +++ b/core/src/ast/query.rs @@ -21,6 +21,7 @@ pub enum Query { UnitsFor(Expr), Search(String), Error(String), + Let(String, Expr), } impl fmt::Display for Conversion { diff --git a/core/src/context.rs b/core/src/context.rs index c94c1016..8c1ee773 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -32,6 +32,7 @@ pub struct Context { pub short_output: bool, pub use_humanize: bool, pub previous_result: Option, + pub variables: BTreeMap, } impl Default for Context { @@ -65,6 +66,7 @@ impl Context { substance_symbols: BTreeMap::new(), temporaries: BTreeMap::new(), previous_result: None, + variables: BTreeMap::new(), } } @@ -87,6 +89,9 @@ impl Context { if name == "ans" || name == "ANS" || name == "_" { return ctx.previous_result.clone(); } + if let Some(v) = ctx.variables.get(name).cloned() { + return Some(v); + } if let Some(v) = ctx.temporaries.get(name).cloned() { return Some(v); } diff --git a/core/src/eval.rs b/core/src/eval.rs index b0e03e23..003507fb 100644 --- a/core/src/eval.rs +++ b/core/src/eval.rs @@ -701,7 +701,7 @@ impl Context { } /// Evaluates an expression, include `->` conversions. - pub fn eval_outer(&self, expr: &Query) -> Result { + pub fn eval_outer(&mut self, expr: &Query) -> Result { match *expr { Query::Expr(Expr::Unit { ref name }) if { @@ -1178,7 +1178,18 @@ impl Context { s.to_reply(self).map_err(QueryError::generic)?, )), } - } + }, + Query::Let(ref var_name, ref expr) => { + // todo: check whether already defined with self.lookup(var_name) + let res = self.eval(expr)?; + if let Value::Number(num) = res { + let parts = num.to_parts(self); + self.variables.insert(var_name.clone(), num); + Ok(QueryReply::Number(parts)) + } else { + Err(QueryError::generic("let expressions currently only supported for numeric results".to_string())) + } + }, Query::Error(ref e) => Err(QueryError::generic(e.clone())), } } diff --git a/core/src/text_query.rs b/core/src/text_query.rs index c677c18c..021a049b 100644 --- a/core/src/text_query.rs +++ b/core/src/text_query.rs @@ -753,6 +753,17 @@ pub fn parse_query(iter: &mut Iter<'_>) -> Query { return Query::Search(s.clone()); } } + Some(Token::Ident(ref s)) if s == "let" => { + iter.next(); + if let Some(Token::Ident(ref s)) = iter.peek().cloned() { + iter.next(); + if let Some(Token::Equals) = iter.peek() { + iter.next(); + return Query::Let(s.clone(), parse_eq(iter)); + } + } + return Query::Error("let needs to have form `let var = expr`".to_string()); + } _ => (), } let left = parse_eq(iter); From 4489f772446a78db50f2c68ce60a91cf9b471e1a Mon Sep 17 00:00:00 2001 From: Adrian Schneider Date: Sat, 28 Aug 2021 22:02:39 +0200 Subject: [PATCH 2/2] move variables to end so they can't mask anything else --- core/src/context.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/context.rs b/core/src/context.rs index 8c1ee773..a52e0004 100644 --- a/core/src/context.rs +++ b/core/src/context.rs @@ -89,9 +89,6 @@ impl Context { if name == "ans" || name == "ANS" || name == "_" { return ctx.previous_result.clone(); } - if let Some(v) = ctx.variables.get(name).cloned() { - return Some(v); - } if let Some(v) = ctx.temporaries.get(name).cloned() { return Some(v); } @@ -109,6 +106,9 @@ impl Context { }); } } + if let Some(v) = ctx.variables.get(name).cloned() { + return Some(v); + } None }