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 } => {
|
||||
write!(f, "Expected a Value::String, 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),
|
||||
ExpectedNumber { actual } => {
|
||||
write!(f, "Expected a Value::Float or Value::Int, but got {:?}.", actual)
|
||||
},
|
||||
ExpectedNumberOrString { actual } => {
|
||||
write!(f, "Expected a Value::Number or a Value::String, but got {:?}.", actual)
|
||||
},
|
||||
ExpectedNumber { actual } => write!(
|
||||
f,
|
||||
"Expected a Value::Float or Value::Int, but got {:?}.",
|
||||
actual
|
||||
),
|
||||
ExpectedNumberOrString { actual } => write!(
|
||||
f,
|
||||
"Expected a Value::Number or a Value::String, but got {:?}.",
|
||||
actual
|
||||
),
|
||||
ExpectedBoolean { actual } => {
|
||||
write!(f, "Expected a Value::Boolean, 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),
|
||||
AppendedToLeafNode => write!(f, "Tried to append a node to a leaf node."),
|
||||
@ -49,7 +53,7 @@ impl fmt::Display for EvalexprError {
|
||||
),
|
||||
TypeError { expected, actual } => {
|
||||
write!(f, "Expected one of {:?}, but got {:?}.", expected, actual)
|
||||
},
|
||||
}
|
||||
UnmatchedLBrace => write!(f, "Found an unmatched opening parenthesis '('."),
|
||||
UnmatchedRBrace => write!(f, "Found an unmatched closing parenthesis ')'."),
|
||||
UnmatchedPartialToken { first, second } => {
|
||||
@ -67,7 +71,7 @@ impl fmt::Display for EvalexprError {
|
||||
first
|
||||
)
|
||||
}
|
||||
},
|
||||
}
|
||||
AdditionError { augend, addend } => write!(f, "Error adding {} + {}", augend, addend),
|
||||
SubtractionError {
|
||||
minuend,
|
||||
@ -80,11 +84,15 @@ impl fmt::Display for EvalexprError {
|
||||
} => write!(f, "Error multiplying {} * {}", multiplicand, multiplier),
|
||||
DivisionError { dividend, divisor } => {
|
||||
write!(f, "Error dividing {} / {}", dividend, divisor)
|
||||
},
|
||||
}
|
||||
ModulationError { 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"),
|
||||
IllegalEscapeSequence(string) => write!(f, "Illegal escape sequence: {}", string),
|
||||
CustomMessage(message) => write!(f, "Error: {}", message),
|
||||
|
@ -290,7 +290,7 @@ impl EvalexprError {
|
||||
|
||||
/// Constructs `EvalexprError::InvalidRegex(regex)`
|
||||
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.
|
||||
pub fn expect_function_argument_amount(
|
||||
actual: usize,
|
||||
expected: usize,
|
||||
) -> EvalexprResult<()> {
|
||||
pub fn expect_function_argument_amount(actual: usize, expected: usize) -> EvalexprResult<()> {
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
|
@ -67,7 +67,6 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
||||
)),
|
||||
|
||||
// string functions
|
||||
|
||||
#[cfg(feature = "regex_support")]
|
||||
"str::regex_matches" => Some(Function::new(
|
||||
Some(2),
|
||||
@ -76,7 +75,10 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
|
||||
let re_str = expect_string(&arguments[1])?;
|
||||
match Regex::new(re_str) {
|
||||
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])?;
|
||||
match Regex::new(re_str) {
|
||||
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::*;
|
||||
|
||||
impl Display for RootNode {
|
||||
fn fmt(&self, _f: &mut Formatter) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Add {
|
||||
impl Display for Operator {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
Eq => write!(f, "=="),
|
||||
Neq => 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 {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "-")
|
||||
}
|
||||
}
|
||||
Tuple => write!(f, ", "),
|
||||
Assign => write!(f, " = "),
|
||||
|
||||
impl Display for Mul {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "*")
|
||||
}
|
||||
}
|
||||
Chain => write!(f, "; "),
|
||||
|
||||
impl Display for Div {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
write!(f, "/")
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
Const { value } => write!(f, "{}", value),
|
||||
VariableIdentifier { identifier } => write!(f, "{}", identifier),
|
||||
FunctionIdentifier { identifier } => write!(f, "{}", 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 {
|
||||
PartialToken::Literal(c.to_string())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
|
||||
PartialToken::Token(token) => {
|
||||
cutoff = 1;
|
||||
Some(token)
|
||||
},
|
||||
}
|
||||
PartialToken::Literal(literal) => {
|
||||
cutoff = 1;
|
||||
if let Ok(number) = literal.parse::<IntType>() {
|
||||
@ -245,38 +245,38 @@ fn partial_tokens_to_tokens(mut tokens: &[PartialToken]) -> EvalexprResult<Vec<T
|
||||
} else {
|
||||
Some(Token::Identifier(literal.to_string()))
|
||||
}
|
||||
},
|
||||
}
|
||||
PartialToken::Whitespace => {
|
||||
cutoff = 1;
|
||||
None
|
||||
},
|
||||
}
|
||||
PartialToken::Eq => match second {
|
||||
Some(PartialToken::Eq) => Some(Token::Eq),
|
||||
_ => {
|
||||
cutoff = 1;
|
||||
Some(Token::Assign)
|
||||
},
|
||||
}
|
||||
},
|
||||
PartialToken::ExclamationMark => match second {
|
||||
Some(PartialToken::Eq) => Some(Token::Eq),
|
||||
_ => {
|
||||
cutoff = 1;
|
||||
Some(Token::Not)
|
||||
},
|
||||
}
|
||||
},
|
||||
PartialToken::Gt => match second {
|
||||
Some(PartialToken::Eq) => Some(Token::Geq),
|
||||
_ => {
|
||||
cutoff = 1;
|
||||
Some(Token::Gt)
|
||||
},
|
||||
}
|
||||
},
|
||||
PartialToken::Lt => match second {
|
||||
Some(PartialToken::Eq) => Some(Token::Leq),
|
||||
_ => {
|
||||
cutoff = 1;
|
||||
Some(Token::Lt)
|
||||
},
|
||||
}
|
||||
},
|
||||
PartialToken::Ampersand => match second {
|
||||
Some(PartialToken::Ampersand) => Some(Token::And),
|
||||
|
@ -1,5 +1,5 @@
|
||||
use Node;
|
||||
use std::slice::Iter;
|
||||
use Node;
|
||||
|
||||
/// An iterator that traverses an operator tree in pre-order.
|
||||
pub struct NodeIter<'a> {
|
||||
@ -47,7 +47,7 @@ impl<'a> Iterator for NodeIter<'a> {
|
||||
|
||||
impl Node {
|
||||
/// 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)
|
||||
}
|
||||
}
|
@ -35,19 +35,19 @@ mod iter;
|
||||
#[derive(Debug)]
|
||||
pub struct Node {
|
||||
children: Vec<Node>,
|
||||
operator: Box<dyn Operator>,
|
||||
operator: Operator,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
fn new<T: Operator + 'static>(operator: T) -> Self {
|
||||
fn new(operator: Operator) -> Self {
|
||||
Self {
|
||||
children: Vec::new(),
|
||||
operator: Box::new(operator),
|
||||
operator,
|
||||
}
|
||||
}
|
||||
|
||||
fn root_node() -> Self {
|
||||
Self::new(RootNode)
|
||||
Self::new(Operator::RootNode)
|
||||
}
|
||||
|
||||
/// Returns an iterator over all identifiers in this expression.
|
||||
@ -67,7 +67,11 @@ impl Node {
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
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.
|
||||
@ -86,7 +90,10 @@ impl Node {
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
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.
|
||||
@ -103,7 +110,10 @@ impl Node {
|
||||
/// assert_eq!(iter.next(), None);
|
||||
/// ```
|
||||
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.
|
||||
@ -347,7 +357,7 @@ impl Node {
|
||||
&self.children
|
||||
}
|
||||
|
||||
fn operator(&self) -> &Box<dyn Operator> {
|
||||
fn 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 node = match token.clone() {
|
||||
Token::Plus => Some(Node::new(Add)),
|
||||
Token::Plus => Some(Node::new(Operator::Add)),
|
||||
Token::Minus => {
|
||||
if last_token_is_rightsided_value {
|
||||
Some(Node::new(Sub))
|
||||
Some(Node::new(Operator::Sub))
|
||||
} else {
|
||||
Some(Node::new(Neg))
|
||||
Some(Node::new(Operator::Neg))
|
||||
}
|
||||
},
|
||||
Token::Star => Some(Node::new(Mul)),
|
||||
Token::Slash => Some(Node::new(Div)),
|
||||
Token::Percent => Some(Node::new(Mod)),
|
||||
Token::Hat => Some(Node::new(Exp)),
|
||||
}
|
||||
Token::Star => Some(Node::new(Operator::Mul)),
|
||||
Token::Slash => Some(Node::new(Operator::Div)),
|
||||
Token::Percent => Some(Node::new(Operator::Mod)),
|
||||
Token::Hat => Some(Node::new(Operator::Exp)),
|
||||
|
||||
Token::Eq => Some(Node::new(Eq)),
|
||||
Token::Neq => Some(Node::new(Neq)),
|
||||
Token::Gt => Some(Node::new(Gt)),
|
||||
Token::Lt => Some(Node::new(Lt)),
|
||||
Token::Geq => Some(Node::new(Geq)),
|
||||
Token::Leq => Some(Node::new(Leq)),
|
||||
Token::And => Some(Node::new(And)),
|
||||
Token::Or => Some(Node::new(Or)),
|
||||
Token::Not => Some(Node::new(Not)),
|
||||
Token::Eq => Some(Node::new(Operator::Eq)),
|
||||
Token::Neq => Some(Node::new(Operator::Neq)),
|
||||
Token::Gt => Some(Node::new(Operator::Gt)),
|
||||
Token::Lt => Some(Node::new(Operator::Lt)),
|
||||
Token::Geq => Some(Node::new(Operator::Geq)),
|
||||
Token::Leq => Some(Node::new(Operator::Leq)),
|
||||
Token::And => Some(Node::new(Operator::And)),
|
||||
Token::Or => Some(Node::new(Operator::Or)),
|
||||
Token::Not => Some(Node::new(Operator::Not)),
|
||||
|
||||
Token::LBrace => {
|
||||
root.push(Node::root_node());
|
||||
None
|
||||
},
|
||||
}
|
||||
Token::RBrace => {
|
||||
if root.len() < 2 {
|
||||
return Err(EvalexprError::UnmatchedRBrace);
|
||||
} else {
|
||||
root.pop()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
Token::Comma => Some(Node::new(Tuple)),
|
||||
Token::Assign => Some(Node::new(Assign)),
|
||||
Token::Semicolon => Some(Node::new(Chain)),
|
||||
Token::Comma => Some(Node::new(Operator::Tuple)),
|
||||
Token::Assign => Some(Node::new(Operator::Assign)),
|
||||
Token::Semicolon => Some(Node::new(Operator::Chain)),
|
||||
|
||||
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 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() {
|
||||
result = Some(Node::new(FunctionIdentifier::new(identifier)));
|
||||
result = Some(Node::new(Operator::function_identifier(identifier)));
|
||||
}
|
||||
}
|
||||
result
|
||||
},
|
||||
Token::Float(float) => Some(Node::new(Const::new(Value::Float(float)))),
|
||||
Token::Int(int) => Some(Node::new(Const::new(Value::Int(int)))),
|
||||
Token::Boolean(boolean) => Some(Node::new(Const::new(Value::Boolean(boolean)))),
|
||||
Token::String(string) => Some(Node::new(Const::new(Value::String(string)))),
|
||||
}
|
||||
Token::Float(float) => Some(Node::new(Operator::value(Value::Float(float)))),
|
||||
Token::Int(int) => Some(Node::new(Operator::value(Value::Int(int)))),
|
||||
Token::Boolean(boolean) => Some(Node::new(Operator::value(Value::Boolean(boolean)))),
|
||||
Token::String(string) => Some(Node::new(Operator::value(Value::String(string)))),
|
||||
};
|
||||
|
||||
if let Some(node) = node {
|
||||
|
@ -21,7 +21,7 @@ impl Display for Value {
|
||||
value.fmt(f)?;
|
||||
}
|
||||
write!(f, ")")
|
||||
},
|
||||
}
|
||||
Value::Empty => write!(f, "()"),
|
||||
}
|
||||
}
|
||||
|
@ -279,18 +279,9 @@ fn test_n_ary_functions() {
|
||||
|
||||
#[test]
|
||||
fn test_builtin_functions() {
|
||||
assert_eq!(
|
||||
eval("min(4.0, 3)"),
|
||||
Ok(Value::Int(3))
|
||||
);
|
||||
assert_eq!(
|
||||
eval("max(4.0, 3)"),
|
||||
Ok(Value::Float(4.0))
|
||||
);
|
||||
assert_eq!(
|
||||
eval("len(\"foobar\")"),
|
||||
Ok(Value::Int(6))
|
||||
);
|
||||
assert_eq!(eval("min(4.0, 3)"), Ok(Value::Int(3)));
|
||||
assert_eq!(eval("max(4.0, 3)"), Ok(Value::Float(4.0)));
|
||||
assert_eq!(eval("len(\"foobar\")"), Ok(Value::Int(6)));
|
||||
assert_eq!(
|
||||
eval("str::to_lowercase(\"FOOBAR\")"),
|
||||
Ok(Value::from("foobar"))
|
||||
@ -317,10 +308,10 @@ fn test_regex_functions() {
|
||||
Ok(Value::Boolean(false))
|
||||
);
|
||||
match eval("str::regex_matches(\"foo\", \"[\")") {
|
||||
Err(EvalexprError::InvalidRegex{ regex, message }) => {
|
||||
Err(EvalexprError::InvalidRegex { regex, message }) => {
|
||||
assert_eq!(regex, "[");
|
||||
assert!(message.contains("unclosed character class"));
|
||||
},
|
||||
}
|
||||
v => panic!(v),
|
||||
};
|
||||
assert_eq!(
|
||||
|
Loading…
Reference in New Issue
Block a user