From e70e9d366ab33a0bb2d30f41b607f9711aa7c0bd Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Mon, 4 Jul 2022 17:10:28 +0300 Subject: [PATCH] Use explicit operator type for reading and writing variables. Before, variables written to were represented with the same operator as constants in the AST. This was hacky and confusing to some users. Closes #106 --- src/operator/display.rs | 4 +++- src/operator/mod.rs | 30 ++++++++++++++++++++++-------- src/tree/mod.rs | 14 ++++++++++---- tests/integration.rs | 4 ++-- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/operator/display.rs b/src/operator/display.rs index d4291e7..12351dd 100644 --- a/src/operator/display.rs +++ b/src/operator/display.rs @@ -41,7 +41,9 @@ impl Display for Operator { Chain => write!(f, "; "), Const { value } => write!(f, "{}", value), - VariableIdentifier { identifier } => write!(f, "{}", identifier), + VariableIdentifierWrite { identifier } | VariableIdentifierRead { identifier } => { + write!(f, "{}", identifier) + }, FunctionIdentifier { identifier } => write!(f, "{}", identifier), } } diff --git a/src/operator/mod.rs b/src/operator/mod.rs index a8ae045..5f2be51 100644 --- a/src/operator/mod.rs +++ b/src/operator/mod.rs @@ -75,8 +75,13 @@ pub enum Operator { /** The value of the constant. */ value: Value, }, - /// A variable identifier. - VariableIdentifier { + /// A write to a variable identifier. + VariableIdentifierWrite { + /// The identifier of the variable. + identifier: String, + }, + /// A read from a variable identifier. + VariableIdentifierRead { /// The identifier of the variable. identifier: String, }, @@ -92,8 +97,12 @@ impl Operator { Operator::Const { value } } - pub(crate) fn variable_identifier(identifier: String) -> Self { - Operator::VariableIdentifier { identifier } + pub(crate) fn variable_identifier_write(identifier: String) -> Self { + Operator::VariableIdentifierWrite { identifier } + } + + pub(crate) fn variable_identifier_read(identifier: String) -> Self { + Operator::VariableIdentifierRead { identifier } } pub(crate) fn function_identifier(identifier: String) -> Self { @@ -124,7 +133,7 @@ impl Operator { Chain => 0, Const { .. } => 200, - VariableIdentifier { .. } => 200, + VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => 200, FunctionIdentifier { .. } => 190, } } @@ -159,7 +168,7 @@ impl Operator { Tuple | Chain => None, Not | Neg | RootNode => Some(1), Const { .. } => Some(0), - VariableIdentifier { .. } => Some(0), + VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => Some(0), FunctionIdentifier { .. } => Some(1), } } @@ -422,7 +431,12 @@ impl Operator { Ok(value.clone()) }, - VariableIdentifier { identifier } => { + VariableIdentifierWrite { identifier } => { + expect_operator_argument_amount(arguments.len(), 0)?; + + Ok(identifier.clone().into()) + }, + VariableIdentifierRead { identifier } => { expect_operator_argument_amount(arguments.len(), 0)?; if let Some(value) = context.get_value(identifier).cloned() { @@ -473,7 +487,7 @@ impl Operator { expect_operator_argument_amount(arguments.len(), 2)?; let target = arguments[0].as_string()?; - let left_value = Operator::VariableIdentifier { + let left_value = Operator::VariableIdentifierRead { identifier: target.clone(), } .eval(&Vec::new(), context)?; diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 69f4494..1956e56 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -69,7 +69,8 @@ impl Node { /// ``` pub fn iter_identifiers(&self) -> impl Iterator { self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifier { identifier } + Operator::VariableIdentifierWrite { identifier } + | Operator::VariableIdentifierRead { identifier } | Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()), _ => None, }) @@ -92,7 +93,8 @@ impl Node { /// ``` pub fn iter_variable_identifiers(&self) -> impl Iterator { self.iter().filter_map(|node| match node.operator() { - Operator::VariableIdentifier { identifier } => Some(identifier.as_str()), + Operator::VariableIdentifierWrite { identifier } + | Operator::VariableIdentifierRead { identifier } => Some(identifier.as_str()), _ => None, }) } @@ -616,10 +618,14 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec) -> EvalexprResult Some(Node::new(Operator::Chain)), Token::Identifier(identifier) => { - let mut result = Some(Node::new(Operator::variable_identifier(identifier.clone()))); + let mut result = Some(Node::new(Operator::variable_identifier_read( + identifier.clone(), + ))); if let Some(next) = next { if next.is_assignment() { - result = Some(Node::new(Operator::value(identifier.clone().into()))); + result = Some(Node::new(Operator::variable_identifier_write( + identifier.clone(), + ))); } else if next.is_leftsided_value() { result = Some(Node::new(Operator::function_identifier(identifier))); } diff --git a/tests/integration.rs b/tests/integration.rs index 30f20d4..9524da3 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -2090,7 +2090,7 @@ fn assignment_lhs_is_identifier() { let operators: Vec<_> = tree.iter().map(|node| node.operator().clone()).collect(); let mut context = HashMapContext::new(); - tree.eval_empty_with_context_mut(&mut context).unwrap(); + tree.eval_with_context_mut(&mut context).unwrap(); assert_eq!(context.get_value("a"), Some(&Value::Int(1))); assert!( @@ -2098,7 +2098,7 @@ fn assignment_lhs_is_identifier() { operators.as_slice(), [ Operator::Assign, - Operator::VariableIdentifier { identifier: value }, + Operator::VariableIdentifierWrite { identifier: value }, Operator::Const { value: Value::Int(1) }