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
This commit is contained in:
Sebastian Schmidt 2022-07-04 17:10:28 +03:00
parent 54c4286672
commit e70e9d366a
4 changed files with 37 additions and 15 deletions

View File

@ -41,7 +41,9 @@ impl Display for Operator {
Chain => write!(f, "; "), Chain => write!(f, "; "),
Const { value } => write!(f, "{}", value), Const { value } => write!(f, "{}", value),
VariableIdentifier { identifier } => write!(f, "{}", identifier), VariableIdentifierWrite { identifier } | VariableIdentifierRead { identifier } => {
write!(f, "{}", identifier)
},
FunctionIdentifier { identifier } => write!(f, "{}", identifier), FunctionIdentifier { identifier } => write!(f, "{}", identifier),
} }
} }

View File

@ -75,8 +75,13 @@ pub enum Operator {
/** The value of the constant. */ /** The value of the constant. */
value: Value, value: Value,
}, },
/// A variable identifier. /// A write to a variable identifier.
VariableIdentifier { VariableIdentifierWrite {
/// The identifier of the variable.
identifier: String,
},
/// A read from a variable identifier.
VariableIdentifierRead {
/// The identifier of the variable. /// The identifier of the variable.
identifier: String, identifier: String,
}, },
@ -92,8 +97,12 @@ impl Operator {
Operator::Const { value } Operator::Const { value }
} }
pub(crate) fn variable_identifier(identifier: String) -> Self { pub(crate) fn variable_identifier_write(identifier: String) -> Self {
Operator::VariableIdentifier { identifier } Operator::VariableIdentifierWrite { identifier }
}
pub(crate) fn variable_identifier_read(identifier: String) -> Self {
Operator::VariableIdentifierRead { identifier }
} }
pub(crate) fn function_identifier(identifier: String) -> Self { pub(crate) fn function_identifier(identifier: String) -> Self {
@ -124,7 +133,7 @@ impl Operator {
Chain => 0, Chain => 0,
Const { .. } => 200, Const { .. } => 200,
VariableIdentifier { .. } => 200, VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => 200,
FunctionIdentifier { .. } => 190, FunctionIdentifier { .. } => 190,
} }
} }
@ -159,7 +168,7 @@ impl Operator {
Tuple | Chain => None, Tuple | Chain => None,
Not | Neg | RootNode => Some(1), Not | Neg | RootNode => Some(1),
Const { .. } => Some(0), Const { .. } => Some(0),
VariableIdentifier { .. } => Some(0), VariableIdentifierWrite { .. } | VariableIdentifierRead { .. } => Some(0),
FunctionIdentifier { .. } => Some(1), FunctionIdentifier { .. } => Some(1),
} }
} }
@ -422,7 +431,12 @@ impl Operator {
Ok(value.clone()) 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)?; expect_operator_argument_amount(arguments.len(), 0)?;
if let Some(value) = context.get_value(identifier).cloned() { if let Some(value) = context.get_value(identifier).cloned() {
@ -473,7 +487,7 @@ impl Operator {
expect_operator_argument_amount(arguments.len(), 2)?; expect_operator_argument_amount(arguments.len(), 2)?;
let target = arguments[0].as_string()?; let target = arguments[0].as_string()?;
let left_value = Operator::VariableIdentifier { let left_value = Operator::VariableIdentifierRead {
identifier: target.clone(), identifier: target.clone(),
} }
.eval(&Vec::new(), context)?; .eval(&Vec::new(), context)?;

View File

@ -69,7 +69,8 @@ impl Node {
/// ``` /// ```
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> { pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() { self.iter().filter_map(|node| match node.operator() {
Operator::VariableIdentifier { identifier } Operator::VariableIdentifierWrite { identifier }
| Operator::VariableIdentifierRead { identifier }
| Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()), | Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
_ => None, _ => None,
}) })
@ -92,7 +93,8 @@ impl Node {
/// ``` /// ```
pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> { pub fn iter_variable_identifiers(&self) -> impl Iterator<Item = &str> {
self.iter().filter_map(|node| match node.operator() { 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, _ => None,
}) })
} }
@ -616,10 +618,14 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
Token::Semicolon => Some(Node::new(Operator::Chain)), Token::Semicolon => Some(Node::new(Operator::Chain)),
Token::Identifier(identifier) => { 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 let Some(next) = next {
if next.is_assignment() { 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() { } else if next.is_leftsided_value() {
result = Some(Node::new(Operator::function_identifier(identifier))); result = Some(Node::new(Operator::function_identifier(identifier)));
} }

View File

@ -2090,7 +2090,7 @@ fn assignment_lhs_is_identifier() {
let operators: Vec<_> = tree.iter().map(|node| node.operator().clone()).collect(); let operators: Vec<_> = tree.iter().map(|node| node.operator().clone()).collect();
let mut context = HashMapContext::new(); 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_eq!(context.get_value("a"), Some(&Value::Int(1)));
assert!( assert!(
@ -2098,7 +2098,7 @@ fn assignment_lhs_is_identifier() {
operators.as_slice(), operators.as_slice(),
[ [
Operator::Assign, Operator::Assign,
Operator::VariableIdentifier { identifier: value }, Operator::VariableIdentifierWrite { identifier: value },
Operator::Const { Operator::Const {
value: Value::Int(1) value: Value::Int(1)
} }