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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,165 +1,128 @@
|
|||||||
use std::fmt::{Debug, Display};
|
|
||||||
|
|
||||||
use function::builtin::builtin_function;
|
use function::builtin::builtin_function;
|
||||||
|
|
||||||
use crate::{context::Context, error::*, value::Value};
|
use crate::{context::Context, error::*, value::Value};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
|
|
||||||
pub trait Operator: Debug + Display {
|
#[derive(Debug)]
|
||||||
|
pub enum Operator {
|
||||||
|
RootNode,
|
||||||
|
|
||||||
|
Add,
|
||||||
|
Sub,
|
||||||
|
Neg,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
|
Mod,
|
||||||
|
Exp,
|
||||||
|
|
||||||
|
Eq,
|
||||||
|
Neq,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
Geq,
|
||||||
|
Leq,
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
|
Not,
|
||||||
|
|
||||||
|
Tuple,
|
||||||
|
Assign,
|
||||||
|
|
||||||
|
Chain,
|
||||||
|
|
||||||
|
Const { value: Value },
|
||||||
|
VariableIdentifier { identifier: String },
|
||||||
|
FunctionIdentifier { identifier: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Operator {
|
||||||
|
pub(crate) fn value(value: Value) -> Self {
|
||||||
|
Operator::Const { value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn variable_identifier(identifier: String) -> Self {
|
||||||
|
Operator::VariableIdentifier { identifier }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn function_identifier(identifier: String) -> Self {
|
||||||
|
Operator::FunctionIdentifier { identifier }
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the precedence of the operator.
|
/// Returns the precedence of the operator.
|
||||||
/// A high precedence means that the operator has priority to be deeper in the tree.
|
/// A high precedence means that the operator has priority to be deeper in the tree.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn precedence(&self) -> i32;
|
pub(crate) fn precedence(&self) -> i32 {
|
||||||
|
use crate::operator::Operator::*;
|
||||||
|
match self {
|
||||||
|
RootNode => 200,
|
||||||
|
|
||||||
|
Add | Sub => 95,
|
||||||
|
Neg => 110,
|
||||||
|
Mul | Div | Mod => 100,
|
||||||
|
Exp => 120,
|
||||||
|
|
||||||
|
Eq | Neq | Gt | Lt | Geq | Leq => 80,
|
||||||
|
And => 75,
|
||||||
|
Or => 70,
|
||||||
|
Not => 110,
|
||||||
|
|
||||||
|
Tuple => 40,
|
||||||
|
Assign => 50,
|
||||||
|
|
||||||
|
Chain => 0,
|
||||||
|
|
||||||
|
Const { value: _ } => 200,
|
||||||
|
VariableIdentifier { identifier: _ } => 200,
|
||||||
|
FunctionIdentifier { identifier: _ } => 190,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right,
|
/// Returns true if chains of operators with the same precedence as this one should be evaluated left-to-right,
|
||||||
/// and false if they should be evaluated right-to-left.
|
/// and false if they should be evaluated right-to-left.
|
||||||
/// Left-to-right chaining has priority if operators with different order but same precedence are chained.
|
/// Left-to-right chaining has priority if operators with different order but same precedence are chained.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn is_left_to_right(&self) -> bool {
|
pub(crate) fn is_left_to_right(&self) -> bool {
|
||||||
true
|
use crate::operator::Operator::*;
|
||||||
|
match self {
|
||||||
|
Assign => false,
|
||||||
|
FunctionIdentifier { identifier: _ } => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// True if this operator is a leaf, meaning it accepts no arguments.
|
/// True if this operator is a leaf, meaning it accepts no arguments.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn is_leaf(&self) -> bool {
|
pub(crate) fn is_leaf(&self) -> bool {
|
||||||
self.max_argument_amount() == 0
|
self.max_argument_amount() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the maximum amount of arguments required by this operator.
|
/// Returns the maximum amount of arguments required by this operator.
|
||||||
// Make this a const fn once #57563 is resolved
|
// Make this a const fn once #57563 is resolved
|
||||||
fn max_argument_amount(&self) -> usize;
|
pub(crate) fn max_argument_amount(&self) -> usize {
|
||||||
|
use crate::operator::Operator::*;
|
||||||
|
match self {
|
||||||
|
Add | Sub | Mul | Div | Mod | Exp | Eq | Neq | Gt | Lt | Geq | Leq | And | Or
|
||||||
|
| Tuple | Assign | Chain => 2,
|
||||||
|
Not | Neg | RootNode => 1,
|
||||||
|
Const { value: _ } => 0,
|
||||||
|
VariableIdentifier { identifier: _ } => 0,
|
||||||
|
FunctionIdentifier { identifier: _ } => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluates the operator with the given arguments and context.
|
/// Evaluates the operator with the given arguments and context.
|
||||||
fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value>;
|
pub(crate) fn eval(&self, arguments: &[Value], context: &dyn Context) -> EvalexprResult<Value> {
|
||||||
|
use crate::operator::Operator::*;
|
||||||
/// Evaluates the operator with the given arguments and mutable context.
|
match self {
|
||||||
fn eval_mut(&self, arguments: &[Value], context: &mut dyn Context) -> EvalexprResult<Value> {
|
RootNode => {
|
||||||
self.eval(arguments, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an identifier if this operator is a function or variable identifier, or `None` otherwise.
|
|
||||||
fn identifier(&self) -> Option<&str> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a variable identifier if this operator is a variable identifier, or `None` otherwise.
|
|
||||||
fn variable_identifier(&self) -> Option<&str> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a function identifier if this operator is a function identifier, or `None` otherwise.
|
|
||||||
fn function_identifier(&self) -> Option<&str> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct RootNode;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Add;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Sub;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Neg;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Mul;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Div;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Mod;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Exp;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Eq;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Neq;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Gt;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Lt;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Geq;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Leq;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct And;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Or;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Not;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Tuple;
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Assign;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Chain;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Const {
|
|
||||||
value: Value,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Const {
|
|
||||||
pub fn new(value: Value) -> Self {
|
|
||||||
Self { value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct VariableIdentifier {
|
|
||||||
identifier: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VariableIdentifier {
|
|
||||||
pub fn new(identifier: String) -> Self {
|
|
||||||
Self { identifier }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct FunctionIdentifier {
|
|
||||||
identifier: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionIdentifier {
|
|
||||||
pub fn new(identifier: String) -> Self {
|
|
||||||
Self { identifier }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator for RootNode {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
200
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
if let Some(first) = arguments.first() {
|
if let Some(first) = arguments.first() {
|
||||||
Ok(first.clone())
|
Ok(first.clone())
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Add => {
|
||||||
|
|
||||||
impl Operator for Add {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
95
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number_or_string(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number_or_string(&arguments[1])?;
|
expect_number_or_string(&arguments[1])?;
|
||||||
@ -185,18 +148,7 @@ impl Operator for Add {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Sub => {
|
||||||
|
|
||||||
impl Operator for Sub {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
95
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -217,18 +169,7 @@ impl Operator for Sub {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Neg => {
|
||||||
|
|
||||||
impl Operator for Neg {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
110
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
|
|
||||||
@ -243,18 +184,7 @@ impl Operator for Neg {
|
|||||||
Ok(Value::Float(-arguments[0].as_number().unwrap()))
|
Ok(Value::Float(-arguments[0].as_number().unwrap()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Mul => {
|
||||||
|
|
||||||
impl Operator for Mul {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
100
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -275,18 +205,7 @@ impl Operator for Mul {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Div => {
|
||||||
|
|
||||||
impl Operator for Div {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
100
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -307,18 +226,7 @@ impl Operator for Div {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Mod => {
|
||||||
|
|
||||||
impl Operator for Mod {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
100
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -339,18 +247,7 @@ impl Operator for Mod {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Exp => {
|
||||||
|
|
||||||
impl Operator for Exp {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
120
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[1])?;
|
||||||
@ -362,18 +259,7 @@ impl Operator for Exp {
|
|||||||
.powf(arguments[1].as_number().unwrap()),
|
.powf(arguments[1].as_number().unwrap()),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
Eq => {
|
||||||
|
|
||||||
impl Operator for Eq {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
if arguments[0] == arguments[1] {
|
if arguments[0] == arguments[1] {
|
||||||
@ -382,18 +268,7 @@ impl Operator for Eq {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Neq => {
|
||||||
|
|
||||||
impl Operator for Neq {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
|
|
||||||
if arguments[0] != arguments[1] {
|
if arguments[0] != arguments[1] {
|
||||||
@ -402,18 +277,7 @@ impl Operator for Neq {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Gt => {
|
||||||
|
|
||||||
impl Operator for Gt {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number_or_string(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number_or_string(&arguments[1])?;
|
expect_number_or_string(&arguments[1])?;
|
||||||
@ -438,18 +302,7 @@ impl Operator for Gt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Lt => {
|
||||||
|
|
||||||
impl Operator for Lt {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number_or_string(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number_or_string(&arguments[1])?;
|
expect_number_or_string(&arguments[1])?;
|
||||||
@ -474,18 +327,7 @@ impl Operator for Lt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Geq => {
|
||||||
|
|
||||||
impl Operator for Geq {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number_or_string(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number_or_string(&arguments[1])?;
|
expect_number_or_string(&arguments[1])?;
|
||||||
@ -510,18 +352,7 @@ impl Operator for Geq {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Leq => {
|
||||||
|
|
||||||
impl Operator for Leq {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
80
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
expect_number_or_string(&arguments[0])?;
|
expect_number_or_string(&arguments[0])?;
|
||||||
expect_number_or_string(&arguments[1])?;
|
expect_number_or_string(&arguments[1])?;
|
||||||
@ -546,18 +377,7 @@ impl Operator for Leq {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
And => {
|
||||||
|
|
||||||
impl Operator for And {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
75
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
@ -568,18 +388,7 @@ impl Operator for And {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Or => {
|
||||||
|
|
||||||
impl Operator for Or {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
70
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
let b = expect_boolean(&arguments[1])?;
|
let b = expect_boolean(&arguments[1])?;
|
||||||
@ -590,18 +399,7 @@ impl Operator for Or {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Not => {
|
||||||
|
|
||||||
impl Operator for Not {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
110
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
let a = expect_boolean(&arguments[0])?;
|
let a = expect_boolean(&arguments[0])?;
|
||||||
|
|
||||||
@ -611,18 +409,7 @@ impl Operator for Not {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Tuple => {
|
||||||
|
|
||||||
impl Operator for Tuple {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
40
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
if let Value::Tuple(tuple) = &arguments[0] {
|
if let Value::Tuple(tuple) = &arguments[0] {
|
||||||
let mut tuple = tuple.clone();
|
let mut tuple = tuple.clone();
|
||||||
@ -645,110 +432,29 @@ impl Operator for Tuple {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Assign => Err(EvalexprError::ContextNotManipulable),
|
||||||
|
Chain => {
|
||||||
impl Operator for Assign {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
50
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_left_to_right(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, _arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
Err(EvalexprError::ContextNotManipulable)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_mut(&self, arguments: &[Value], context: &mut Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 2)?;
|
|
||||||
let target = expect_string(&arguments[0])?;
|
|
||||||
context.set_value(target.into(), arguments[1].clone())?;
|
|
||||||
|
|
||||||
Ok(Value::Empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator for Chain {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
2
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> Result<Value, EvalexprError> {
|
|
||||||
if arguments.is_empty() {
|
if arguments.is_empty() {
|
||||||
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
|
return Err(EvalexprError::wrong_operator_argument_amount(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(arguments.get(1).cloned().unwrap_or(Value::Empty))
|
Ok(arguments.get(1).cloned().unwrap_or(Value::Empty))
|
||||||
}
|
}
|
||||||
}
|
Const { value } => {
|
||||||
|
|
||||||
impl Operator for Const {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
200
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], _context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 0)?;
|
expect_operator_argument_amount(arguments.len(), 0)?;
|
||||||
|
|
||||||
Ok(self.value.clone())
|
Ok(value.clone())
|
||||||
}
|
}
|
||||||
}
|
VariableIdentifier { identifier } => {
|
||||||
|
if let Some(value) = context.get_value(&identifier).cloned() {
|
||||||
impl Operator for VariableIdentifier {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
200
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, _arguments: &[Value], context: &Context) -> EvalexprResult<Value> {
|
|
||||||
if let Some(value) = context.get_value(&self.identifier).cloned() {
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::VariableIdentifierNotFound(
|
Err(EvalexprError::VariableIdentifierNotFound(
|
||||||
self.identifier.clone(),
|
identifier.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FunctionIdentifier { identifier } => {
|
||||||
fn identifier(&self) -> Option<&str> {
|
|
||||||
Some(&self.identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn variable_identifier(&self) -> Option<&str> {
|
|
||||||
Some(&self.identifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator for FunctionIdentifier {
|
|
||||||
fn precedence(&self) -> i32 {
|
|
||||||
190
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_left_to_right(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_argument_amount(&self) -> usize {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval(&self, arguments: &[Value], context: &Context) -> EvalexprResult<Value> {
|
|
||||||
expect_operator_argument_amount(arguments.len(), 1)?;
|
expect_operator_argument_amount(arguments.len(), 1)?;
|
||||||
|
|
||||||
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
let arguments = if let Value::Tuple(arguments) = &arguments[0] {
|
||||||
@ -757,22 +463,35 @@ impl Operator for FunctionIdentifier {
|
|||||||
arguments
|
arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(function) = context.get_function(&self.identifier) {
|
if let Some(function) = context.get_function(&identifier) {
|
||||||
function.call(arguments)
|
function.call(arguments)
|
||||||
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
|
} else if let Some(builtin_function) = builtin_function(&identifier) {
|
||||||
builtin_function.call(arguments)
|
builtin_function.call(arguments)
|
||||||
} else {
|
} else {
|
||||||
Err(EvalexprError::FunctionIdentifierNotFound(
|
Err(EvalexprError::FunctionIdentifierNotFound(
|
||||||
self.identifier.clone(),
|
identifier.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn identifier(&self) -> Option<&str> {
|
|
||||||
Some(&self.identifier)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_identifier(&self) -> Option<&str> {
|
/// Evaluates the operator with the given arguments and mutable context.
|
||||||
Some(&self.identifier)
|
pub(crate) fn eval_mut(
|
||||||
|
&self,
|
||||||
|
arguments: &[Value],
|
||||||
|
context: &mut dyn Context,
|
||||||
|
) -> EvalexprResult<Value> {
|
||||||
|
use crate::operator::Operator::*;
|
||||||
|
match self {
|
||||||
|
Assign => {
|
||||||
|
expect_operator_argument_amount(arguments.len(), 2)?;
|
||||||
|
let target = expect_string(&arguments[0])?;
|
||||||
|
context.set_value(target.into(), arguments[1].clone())?;
|
||||||
|
|
||||||
|
Ok(Value::Empty)
|
||||||
|
}
|
||||||
|
_ => self.eval(arguments, context),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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