Refactor operators into an enum
(This commit is not formatted properly) Relates to #46
This commit is contained in:
parent
697fbb5d45
commit
6c078c49e5
@ -18,18 +18,22 @@ impl fmt::Display for EvalexprError {
|
|||||||
),
|
),
|
||||||
ExpectedString { actual } => {
|
ExpectedString { actual } => {
|
||||||
write!(f, "Expected a Value::String, but got {:?}.", actual)
|
write!(f, "Expected a Value::String, but got {:?}.", actual)
|
||||||
},
|
}
|
||||||
ExpectedInt { actual } => write!(f, "Expected a Value::Int, but got {:?}.", actual),
|
ExpectedInt { actual } => write!(f, "Expected a Value::Int, but got {:?}.", actual),
|
||||||
ExpectedFloat { actual } => write!(f, "Expected a Value::Float, but got {:?}.", actual),
|
ExpectedFloat { actual } => write!(f, "Expected a Value::Float, but got {:?}.", actual),
|
||||||
ExpectedNumber { actual } => {
|
ExpectedNumber { actual } => write!(
|
||||||
write!(f, "Expected a Value::Float or Value::Int, but got {:?}.", actual)
|
f,
|
||||||
},
|
"Expected a Value::Float or Value::Int, but got {:?}.",
|
||||||
ExpectedNumberOrString { actual } => {
|
actual
|
||||||
write!(f, "Expected a Value::Number or a Value::String, but got {:?}.", actual)
|
),
|
||||||
},
|
ExpectedNumberOrString { actual } => write!(
|
||||||
|
f,
|
||||||
|
"Expected a Value::Number or a Value::String, but got {:?}.",
|
||||||
|
actual
|
||||||
|
),
|
||||||
ExpectedBoolean { actual } => {
|
ExpectedBoolean { actual } => {
|
||||||
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
|
write!(f, "Expected a Value::Boolean, but got {:?}.", actual)
|
||||||
},
|
}
|
||||||
ExpectedTuple { actual } => write!(f, "Expected a Value::Tuple, but got {:?}.", actual),
|
ExpectedTuple { actual } => write!(f, "Expected a Value::Tuple, but got {:?}.", actual),
|
||||||
ExpectedEmpty { actual } => write!(f, "Expected a Value::Empty, but got {:?}.", actual),
|
ExpectedEmpty { actual } => write!(f, "Expected a Value::Empty, but got {:?}.", actual),
|
||||||
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
|
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
|
||||||
@ -49,7 +53,7 @@ impl fmt::Display for EvalexprError {
|
|||||||
),
|
),
|
||||||
TypeError { expected, actual } => {
|
TypeError { expected, actual } => {
|
||||||
write!(f, "Expected one of {:?}, but got {:?}.", expected, actual)
|
write!(f, "Expected one of {:?}, but got {:?}.", expected, actual)
|
||||||
},
|
}
|
||||||
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
|
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
|
||||||
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
|
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
|
||||||
UnmatchedPartialToken { first, second } => {
|
UnmatchedPartialToken { first, second } => {
|
||||||
@ -67,7 +71,7 @@ impl fmt::Display for EvalexprError {
|
|||||||
first
|
first
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
|
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
|
||||||
SubtractionError {
|
SubtractionError {
|
||||||
minuend,
|
minuend,
|
||||||
@ -80,11 +84,15 @@ impl fmt::Display for EvalexprError {
|
|||||||
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
|
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
|
||||||
DivisionError { dividend, divisor } => {
|
DivisionError { dividend, divisor } => {
|
||||||
write!(f, "Error dividing {} / {}", dividend, divisor)
|
write!(f, "Error dividing {} / {}", dividend, divisor)
|
||||||
},
|
}
|
||||||
ModulationError { dividend, divisor } => {
|
ModulationError { dividend, divisor } => {
|
||||||
write!(f, "Error modulating {} % {}", dividend, divisor)
|
write!(f, "Error modulating {} % {}", dividend, divisor)
|
||||||
},
|
}
|
||||||
InvalidRegex { regex, message } => write!(f, "Regular expression {:?} is invalid: {:?}", regex, message),
|
InvalidRegex { regex, message } => write!(
|
||||||
|
f,
|
||||||
|
"Regular expression {:?} is invalid: {:?}",
|
||||||
|
regex, message
|
||||||
|
),
|
||||||
ContextNotManipulable => write!(f, "Cannot manipulate context"),
|
ContextNotManipulable => write!(f, "Cannot manipulate context"),
|
||||||
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
|
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
|
||||||
CustomMessage(message) => write!(f, "Error: {}", message),
|
CustomMessage(message) => write!(f, "Error: {}", message),
|
||||||
|
@ -290,7 +290,7 @@ impl EvalexprError {
|
|||||||
|
|
||||||
/// Constructs `EvalexprError::InvalidRegex(regex)`
|
/// Constructs `EvalexprError::InvalidRegex(regex)`
|
||||||
pub fn invalid_regex(regex: String, message: String) -> Self {
|
pub fn invalid_regex(regex: String, message: String) -> Self {
|
||||||
EvalexprError::InvalidRegex{ regex, message }
|
EvalexprError::InvalidRegex { regex, message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,10 +309,7 @@ pub(crate) fn expect_operator_argument_amount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
|
/// Returns `Ok(())` if the actual and expected parameters are equal, and `Err(Error::WrongFunctionArgumentAmount)` otherwise.
|
||||||
pub fn expect_function_argument_amount(
|
pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> {
|
||||||
actual: usize,
|
|
||||||
expected: usize,
|
|
||||||
) -> EvalexprResult<()> {
|
|
||||||
if actual == expected {
|
if actual == expected {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -67,7 +67,6 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
)),
|
)),
|
||||||
|
|
||||||
// string functions
|
// string functions
|
||||||
|
|
||||||
#[cfg(feature = "regex_support")]
|
#[cfg(feature = "regex_support")]
|
||||||
"str::regex_matches" => Some(Function::new(
|
"str::regex_matches" => Some(Function::new(
|
||||||
Some(2),
|
Some(2),
|
||||||
@ -76,7 +75,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
let re_str = expect_string(&arguments[1])?;
|
let re_str = expect_string(&arguments[1])?;
|
||||||
match Regex::new(re_str) {
|
match Regex::new(re_str) {
|
||||||
Ok(re) => Ok(Value::Boolean(re.is_match(subject))),
|
Ok(re) => Ok(Value::Boolean(re.is_match(subject))),
|
||||||
Err(err) => Err(EvalexprError::invalid_regex(re_str.to_string(), format!("{}", err)))
|
Err(err) => Err(EvalexprError::invalid_regex(
|
||||||
|
re_str.to_string(),
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
@ -89,7 +91,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
|||||||
let repl = expect_string(&arguments[2])?;
|
let repl = expect_string(&arguments[2])?;
|
||||||
match Regex::new(re_str) {
|
match Regex::new(re_str) {
|
||||||
Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())),
|
Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())),
|
||||||
Err(err) => Err(EvalexprError::invalid_regex(re_str.to_string(), format!("{}", err))),
|
Err(err) => Err(EvalexprError::invalid_regex(
|
||||||
|
re_str.to_string(),
|
||||||
|
format!("{}", err),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
|
@ -2,140 +2,37 @@ use std::fmt::{Display, Error, Formatter};
|
|||||||
|
|
||||||
use operator::*;
|
use operator::*;
|
||||||
|
|
||||||
impl Display for RootNode {
|
impl Display for Operator {
|
||||||
fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Add {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||||
write!(f, "+")
|
use crate::operator::Operator::*;
|
||||||
}
|
match self {
|
||||||
}
|
RootNode => Ok(()),
|
||||||
|
Add => write!(f, "+"),
|
||||||
|
Sub => write!(f, "-"),
|
||||||
|
Neg => write!(f, "-"),
|
||||||
|
Mul => write!(f, "*"),
|
||||||
|
Div => write!(f, "/"),
|
||||||
|
Mod => write!(f, "%"),
|
||||||
|
Exp => write!(f, "^"),
|
||||||
|
|
||||||
impl Display for Sub {
|
Eq => write!(f, "=="),
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
Neq => write!(f, "!="),
|
||||||
write!(f, "-")
|
Gt => write!(f, ">"),
|
||||||
}
|
Lt => write!(f, "<"),
|
||||||
}
|
Geq => write!(f, ">="),
|
||||||
|
Leq => write!(f, "<="),
|
||||||
|
And => write!(f, "&&"),
|
||||||
|
Or => write!(f, "||"),
|
||||||
|
Not => write!(f, "!"),
|
||||||
|
|
||||||
impl Display for Neg {
|
Tuple => write!(f, ", "),
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
Assign => write!(f, " = "),
|
||||||
write!(f, "-")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Mul {
|
Chain => write!(f, "; "),
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "*")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Div {
|
Const { value } => write!(f, "{}", value),
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
VariableIdentifier { identifier } => write!(f, "{}", identifier),
|
||||||
write!(f, "/")
|
FunctionIdentifier { identifier } => write!(f, "{}", identifier),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Mod {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "%")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Exp {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "^")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Eq {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "==")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Neq {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "!=")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Gt {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, ">")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Lt {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "<")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Geq {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, ">=")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Leq {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "<=")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for And {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "&&")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Or {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "||")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Not {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Tuple {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, ", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Assign {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "; ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Chain {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, " = ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Const {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "{}", self.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for VariableIdentifier {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "{}", self.identifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for FunctionIdentifier {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
|
||||||
write!(f, "{}", self.identifier)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1213
src/operator/mod.rs
1213
src/operator/mod.rs
File diff suppressed because it is too large
Load Diff
@ -83,7 +83,7 @@ fn char_to_partial_token(c: char) -> PartialToken {
|
|||||||
} else {
|
} else {
|
||||||
PartialToken::Literal(c.to_string())
|
PartialToken::Literal(c.to_string())
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
|
|||||||
PartialToken::Token(token) => {
|
PartialToken::Token(token) => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
Some(token)
|
Some(token)
|
||||||
},
|
}
|
||||||
PartialToken::Literal(literal) => {
|
PartialToken::Literal(literal) => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
if let Ok(number) = literal.parse::<IntType>() {
|
if let Ok(number) = literal.parse::<IntType>() {
|
||||||
@ -245,38 +245,38 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
|
|||||||
} else {
|
} else {
|
||||||
Some(Token::Identifier(literal.to_string()))
|
Some(Token::Identifier(literal.to_string()))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
PartialToken::Whitespace => {
|
PartialToken::Whitespace => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
PartialToken::Eq => match second {
|
PartialToken::Eq => match second {
|
||||||
Some(PartialToken::Eq) => Some(Token::Eq),
|
Some(PartialToken::Eq) => Some(Token::Eq),
|
||||||
_ => {
|
_ => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
Some(Token::Assign)
|
Some(Token::Assign)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
PartialToken::ExclamationMark => match second {
|
PartialToken::ExclamationMark => match second {
|
||||||
Some(PartialToken::Eq) => Some(Token::Eq),
|
Some(PartialToken::Eq) => Some(Token::Eq),
|
||||||
_ => {
|
_ => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
Some(Token::Not)
|
Some(Token::Not)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
PartialToken::Gt => match second {
|
PartialToken::Gt => match second {
|
||||||
Some(PartialToken::Eq) => Some(Token::Geq),
|
Some(PartialToken::Eq) => Some(Token::Geq),
|
||||||
_ => {
|
_ => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
Some(Token::Gt)
|
Some(Token::Gt)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
PartialToken::Lt => match second {
|
PartialToken::Lt => match second {
|
||||||
Some(PartialToken::Eq) => Some(Token::Leq),
|
Some(PartialToken::Eq) => Some(Token::Leq),
|
||||||
_ => {
|
_ => {
|
||||||
cutoff = 1;
|
cutoff = 1;
|
||||||
Some(Token::Lt)
|
Some(Token::Lt)
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
PartialToken::Ampersand => match second {
|
PartialToken::Ampersand => match second {
|
||||||
Some(PartialToken::Ampersand) => Some(Token::And),
|
Some(PartialToken::Ampersand) => Some(Token::And),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use Node;
|
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
use Node;
|
||||||
|
|
||||||
/// An iterator that traverses an operator tree in pre-order.
|
/// An iterator that traverses an operator tree in pre-order.
|
||||||
pub struct NodeIter<'a> {
|
pub struct NodeIter<'a> {
|
||||||
@ -47,7 +47,7 @@ impl<'a> Iterator for NodeIter<'a> {
|
|||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
/// Returns an iterator over all nodes in this tree.
|
/// Returns an iterator over all nodes in this tree.
|
||||||
pub fn iter(&self) -> impl Iterator<Item=&Node> {
|
pub fn iter(&self) -> impl Iterator<Item = &Node> {
|
||||||
NodeIter::new(self)
|
NodeIter::new(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,19 +35,19 @@ mod iter;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
operator: Box<dyn Operator>,
|
operator: Operator,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
fn new<T: Operator + 'static>(operator: T) -> Self {
|
fn new(operator: Operator) -> Self {
|
||||||
Self {
|
Self {
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
operator: Box::new(operator),
|
operator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn root_node() -> Self {
|
fn root_node() -> Self {
|
||||||
Self::new(RootNode)
|
Self::new(Operator::RootNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all identifiers in this expression.
|
/// Returns an iterator over all identifiers in this expression.
|
||||||
@ -67,7 +67,11 @@ impl Node {
|
|||||||
/// assert_eq!(iter.next(), None);
|
/// assert_eq!(iter.next(), None);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
|
pub fn iter_identifiers(&self) -> impl Iterator<Item = &str> {
|
||||||
self.iter().filter_map(|node| node.operator.identifier())
|
self.iter().filter_map(|node| match node.operator() {
|
||||||
|
Operator::VariableIdentifier { identifier }
|
||||||
|
| Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all variable identifiers in this expression.
|
/// Returns an iterator over all variable identifiers in this expression.
|
||||||
@ -86,7 +90,10 @@ impl Node {
|
|||||||
/// assert_eq!(iter.next(), None);
|
/// assert_eq!(iter.next(), None);
|
||||||
/// ```
|
/// ```
|
||||||
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| node.operator.variable_identifier())
|
self.iter().filter_map(|node| match node.operator() {
|
||||||
|
Operator::VariableIdentifier { identifier } => Some(identifier.as_str()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all function identifiers in this expression.
|
/// Returns an iterator over all function identifiers in this expression.
|
||||||
@ -103,7 +110,10 @@ impl Node {
|
|||||||
/// assert_eq!(iter.next(), None);
|
/// assert_eq!(iter.next(), None);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> {
|
pub fn iter_function_identifiers(&self) -> impl Iterator<Item = &str> {
|
||||||
self.iter().filter_map(|node| node.operator.function_identifier())
|
self.iter().filter_map(|node| match node.operator() {
|
||||||
|
Operator::FunctionIdentifier { identifier } => Some(identifier.as_str()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the operator tree rooted at this node with the given context.
|
/// Evaluates the operator tree rooted at this node with the given context.
|
||||||
@ -347,7 +357,7 @@ impl Node {
|
|||||||
&self.children
|
&self.children
|
||||||
}
|
}
|
||||||
|
|
||||||
fn operator(&self) -> &Box<dyn Operator> {
|
fn operator(&self) -> &Operator {
|
||||||
&self.operator
|
&self.operator
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,60 +414,60 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
|
|||||||
let next = token_iter.peek().cloned();
|
let next = token_iter.peek().cloned();
|
||||||
|
|
||||||
let node = match token.clone() {
|
let node = match token.clone() {
|
||||||
Token::Plus => Some(Node::new(Add)),
|
Token::Plus => Some(Node::new(Operator::Add)),
|
||||||
Token::Minus => {
|
Token::Minus => {
|
||||||
if last_token_is_rightsided_value {
|
if last_token_is_rightsided_value {
|
||||||
Some(Node::new(Sub))
|
Some(Node::new(Operator::Sub))
|
||||||
} else {
|
} else {
|
||||||
Some(Node::new(Neg))
|
Some(Node::new(Operator::Neg))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Token::Star => Some(Node::new(Mul)),
|
Token::Star => Some(Node::new(Operator::Mul)),
|
||||||
Token::Slash => Some(Node::new(Div)),
|
Token::Slash => Some(Node::new(Operator::Div)),
|
||||||
Token::Percent => Some(Node::new(Mod)),
|
Token::Percent => Some(Node::new(Operator::Mod)),
|
||||||
Token::Hat => Some(Node::new(Exp)),
|
Token::Hat => Some(Node::new(Operator::Exp)),
|
||||||
|
|
||||||
Token::Eq => Some(Node::new(Eq)),
|
Token::Eq => Some(Node::new(Operator::Eq)),
|
||||||
Token::Neq => Some(Node::new(Neq)),
|
Token::Neq => Some(Node::new(Operator::Neq)),
|
||||||
Token::Gt => Some(Node::new(Gt)),
|
Token::Gt => Some(Node::new(Operator::Gt)),
|
||||||
Token::Lt => Some(Node::new(Lt)),
|
Token::Lt => Some(Node::new(Operator::Lt)),
|
||||||
Token::Geq => Some(Node::new(Geq)),
|
Token::Geq => Some(Node::new(Operator::Geq)),
|
||||||
Token::Leq => Some(Node::new(Leq)),
|
Token::Leq => Some(Node::new(Operator::Leq)),
|
||||||
Token::And => Some(Node::new(And)),
|
Token::And => Some(Node::new(Operator::And)),
|
||||||
Token::Or => Some(Node::new(Or)),
|
Token::Or => Some(Node::new(Operator::Or)),
|
||||||
Token::Not => Some(Node::new(Not)),
|
Token::Not => Some(Node::new(Operator::Not)),
|
||||||
|
|
||||||
Token::LBrace => {
|
Token::LBrace => {
|
||||||
root.push(Node::root_node());
|
root.push(Node::root_node());
|
||||||
None
|
None
|
||||||
},
|
}
|
||||||
Token::RBrace => {
|
Token::RBrace => {
|
||||||
if root.len() < 2 {
|
if root.len() < 2 {
|
||||||
return Err(EvalexprError::UnmatchedRBrace);
|
return Err(EvalexprError::UnmatchedRBrace);
|
||||||
} else {
|
} else {
|
||||||
root.pop()
|
root.pop()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
Token::Comma => Some(Node::new(Tuple)),
|
Token::Comma => Some(Node::new(Operator::Tuple)),
|
||||||
Token::Assign => Some(Node::new(Assign)),
|
Token::Assign => Some(Node::new(Operator::Assign)),
|
||||||
Token::Semicolon => Some(Node::new(Chain)),
|
Token::Semicolon => Some(Node::new(Operator::Chain)),
|
||||||
|
|
||||||
Token::Identifier(identifier) => {
|
Token::Identifier(identifier) => {
|
||||||
let mut result = Some(Node::new(VariableIdentifier::new(identifier.clone())));
|
let mut result = Some(Node::new(Operator::variable_identifier(identifier.clone())));
|
||||||
if let Some(next) = next {
|
if let Some(next) = next {
|
||||||
if next == &Token::Assign {
|
if next == &Token::Assign {
|
||||||
result = Some(Node::new(Const::new(identifier.clone().into())));
|
result = Some(Node::new(Operator::value(identifier.clone().into())));
|
||||||
} else if next.is_leftsided_value() {
|
} else if next.is_leftsided_value() {
|
||||||
result = Some(Node::new(FunctionIdentifier::new(identifier)));
|
result = Some(Node::new(Operator::function_identifier(identifier)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
},
|
}
|
||||||
Token::Float(float) => Some(Node::new(Const::new(Value::Float(float)))),
|
Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))),
|
||||||
Token::Int(int) => Some(Node::new(Const::new(Value::Int(int)))),
|
Token::Int(int) => Some(Node::new(Operator::value(Value::Int(int)))),
|
||||||
Token::Boolean(boolean) => Some(Node::new(Const::new(Value::Boolean(boolean)))),
|
Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))),
|
||||||
Token::String(string) => Some(Node::new(Const::new(Value::String(string)))),
|
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(node) = node {
|
if let Some(node) = node {
|
||||||
|
@ -21,7 +21,7 @@ impl Display for Value {
|
|||||||
value.fmt(f)?;
|
value.fmt(f)?;
|
||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
},
|
}
|
||||||
Value::Empty => write!(f, "()"),
|
Value::Empty => write!(f, "()"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,18 +279,9 @@ fn test_n_ary_functions() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builtin_functions() {
|
fn test_builtin_functions() {
|
||||||
assert_eq!(
|
assert_eq!(eval("min(4.0, 3)"), Ok(Value::Int(3)));
|
||||||
eval("min(4.0, 3)"),
|
assert_eq!(eval("max(4.0, 3)"), Ok(Value::Float(4.0)));
|
||||||
Ok(Value::Int(3))
|
assert_eq!(eval("len(\"foobar\")"), Ok(Value::Int(6)));
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
eval("max(4.0, 3)"),
|
|
||||||
Ok(Value::Float(4.0))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
eval("len(\"foobar\")"),
|
|
||||||
Ok(Value::Int(6))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval("str::to_lowercase(\"FOOBAR\")"),
|
eval("str::to_lowercase(\"FOOBAR\")"),
|
||||||
Ok(Value::from("foobar"))
|
Ok(Value::from("foobar"))
|
||||||
@ -317,10 +308,10 @@ fn test_regex_functions() {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
);
|
);
|
||||||
match eval("str::regex_matches(\"foo\", \"[\")") {
|
match eval("str::regex_matches(\"foo\", \"[\")") {
|
||||||
Err(EvalexprError::InvalidRegex{ regex, message }) => {
|
Err(EvalexprError::InvalidRegex { regex, message }) => {
|
||||||
assert_eq!(regex, "[");
|
assert_eq!(regex, "[");
|
||||||
assert!(message.contains("unclosed character class"));
|
assert!(message.contains("unclosed character class"));
|
||||||
},
|
}
|
||||||
v => panic!(v),
|
v => panic!(v),
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
Loading…
Reference in New Issue
Block a user