resolver 0.2.0

Expression evaluator
Documentation

use std::str::FromStr;
use serde_json::Value;
use crate::to_value;
use crate::error::Error;
use crate::node::Node;


#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operator {
    Add(u8),
    Mul(u8),
    Sub(u8),
    Div(u8),
    Rem(u8),
    /// Exponentiation (`**`)
    Pow(u8),
    Not(u8),
    /// Unary negation (`-x`)
    UnaryMinus(u8),
    Eq(u8),
    Ne(u8),
    Gt(u8),
    Lt(u8),
    Ge(u8),
    Le(u8),
    And(u8),
    Or(u8),
    /// Null-coalescing (`??`): returns left if non-null, else right
    NullCoalesce(u8),
    /// Membership test (`in`): `val in array/object/string`
    In(u8),
    /// Negated membership (`not in`)
    NotIn(u8),
    /// Bitwise AND (`&`)
    BitAnd(u8),
    /// Bitwise OR (`|`)
    BitOr(u8),
    /// Bitwise XOR (`^`)
    BitXor(u8),
    /// Bitwise NOT (`~`, unary)
    BitNot,
    /// Left shift (`<<`)
    Shl(u8),
    /// Right shift (`>>`)
    Shr(u8),
    Dot(u8),
    LeftParenthesis,
    RightParenthesis,
    LeftSquareBracket(u8),
    RightSquareBracket,
    DoubleQuotes,
    SingleQuote,
    WhiteSpace,
    Comma,
    Function(String),
    Identifier(String),
    Value(Value),
}

impl Operator {
    pub fn is_identifier(&self) -> bool {
        matches!(*self, Operator::Identifier(_))
    }

    pub fn can_at_beginning(&self) -> bool {
        matches!(*self, Operator::Not(_) |
            Operator::UnaryMinus(_) |
            Operator::BitNot |
            Operator::Function(_) |
            Operator::LeftParenthesis)
    }

    pub fn get_max_args(&self) -> Option<usize> {
        match *self {
            Operator::Add(_) | Operator::Sub(_) | Operator::Mul(_) | Operator::Div(_) |
            Operator::Eq(_) | Operator::Ne(_) | Operator::Gt(_) | Operator::Lt(_) |
            Operator::Ge(_) | Operator::Le(_) | Operator::And(_) | Operator::Or(_) |
            Operator::Rem(_) | Operator::Pow(_) | Operator::NullCoalesce(_) |
            Operator::In(_) | Operator::NotIn(_) |
            Operator::BitAnd(_) | Operator::BitOr(_) | Operator::BitXor(_) |
            Operator::Shl(_) | Operator::Shr(_) => Some(2),
            Operator::Not(_) | Operator::UnaryMinus(_) | Operator::BitNot => Some(1),
            Operator::Function(_) => None,
            _ => Some(0),
        }
    }

    pub fn get_min_args(&self) -> Option<usize> {
        match *self {
            Operator::Add(_) | Operator::Sub(_) | Operator::Mul(_) | Operator::Div(_) |
            Operator::Eq(_) | Operator::Ne(_) | Operator::Gt(_) | Operator::Lt(_) |
            Operator::Ge(_) | Operator::Le(_) | Operator::And(_) | Operator::Or(_) |
            Operator::Rem(_) | Operator::Pow(_) | Operator::NullCoalesce(_) |
            Operator::In(_) | Operator::NotIn(_) |
            Operator::BitAnd(_) | Operator::BitOr(_) | Operator::BitXor(_) |
            Operator::Shl(_) | Operator::Shr(_) => Some(2),
            Operator::Not(_) | Operator::UnaryMinus(_) | Operator::BitNot => Some(1),
            Operator::Function(_) => None,
            _ => Some(0),
        }
    }

    pub fn get_priority(&self) -> u8 {
        match *self {
            Operator::Add(priority) |
            Operator::Sub(priority) |
            Operator::Div(priority) |
            Operator::Mul(priority) |
            Operator::Eq(priority) |
            Operator::Ne(priority) |
            Operator::Gt(priority) |
            Operator::Lt(priority) |
            Operator::Ge(priority) |
            Operator::Le(priority) |
            Operator::And(priority) |
            Operator::Or(priority) |
            Operator::Rem(priority) |
            Operator::Pow(priority) |
            Operator::UnaryMinus(priority) |
            Operator::NullCoalesce(priority) |
            Operator::In(priority) |
            Operator::NotIn(priority) |
            Operator::BitAnd(priority) |
            Operator::BitOr(priority) |
            Operator::BitXor(priority) |
            Operator::Shl(priority) |
            Operator::Shr(priority) => priority,
            Operator::Value(_) |
            Operator::Identifier(_) => 0,
            _ => 99,
        }
    }

    pub fn is_left_parenthesis(&self) -> bool {
        *self == Operator::LeftParenthesis
    }

    pub fn is_not(&self) -> bool {
        matches!(*self, Operator::Not(_))
    }

    pub fn is_left_square_bracket(&self) -> bool {
        matches!(*self, Operator::LeftSquareBracket(_))
    }

    pub fn is_dot(&self) -> bool {
        matches!(*self, Operator::Dot(_))
    }

    pub fn is_value_or_ident(&self) -> bool {
        matches!(*self, Operator::Value(_) |
            Operator::Identifier(_))
    }

    pub fn can_have_child(&self) -> bool {
        matches!(*self, Operator::Function(_) |
            Operator::Add(_) |
            Operator::Sub(_) |
            Operator::Div(_) |
            Operator::Mul(_) |
            Operator::Rem(_) |
            Operator::Pow(_) |
            Operator::Eq(_) |
            Operator::Ne(_) |
            Operator::Gt(_) |
            Operator::Lt(_) |
            Operator::And(_) |
            Operator::Or(_) |
            Operator::NullCoalesce(_) |
            Operator::In(_) |
            Operator::NotIn(_) |
            Operator::BitAnd(_) |
            Operator::BitOr(_) |
            Operator::BitXor(_) |
            Operator::BitNot |
            Operator::Shl(_) |
            Operator::Shr(_) |
            Operator::Ge(_) |
            Operator::Not(_) |
            Operator::UnaryMinus(_) |
            Operator::Dot(_) |
            Operator::LeftSquareBracket(_) |
            Operator::Le(_))
    }

    pub fn is_left(&self) -> bool {
        matches!(*self, Operator::LeftParenthesis |
            Operator::LeftSquareBracket(_))
    }

    pub fn get_left(&self) -> Operator {
        match *self {
            Operator::RightParenthesis => Operator::LeftParenthesis,
            Operator::RightSquareBracket => Operator::LeftSquareBracket(100),
            _ => panic!("not bracket"),
        }
    }

    pub fn to_node(&self) -> Node {
        Node::new(self.clone())
    }

    pub fn children_to_node(&self, children: Vec<Node>) -> Node {
        let mut node = self.to_node();
        node.children = children;
        node
    }

    pub fn get_identifier(&self) -> &str {
        match *self {
            Operator::Identifier(ref ident) => ident,
            _ => panic!("not identifier"),
        }
    }
}

impl FromStr for Operator {
    type Err = Error;

    fn from_str(raw: &str) -> Result<Operator, Error> {
        match raw {
            "+" => Ok(Operator::Add(8)),
            "-" => Ok(Operator::Sub(8)),
            "*" => Ok(Operator::Mul(10)),
            "**" => Ok(Operator::Pow(12)),
            "/" => Ok(Operator::Div(10)),
            "%" => Ok(Operator::Rem(10)),
            "??" => Ok(Operator::NullCoalesce(1)),
            "in" => Ok(Operator::In(6)),
            "not in" => Ok(Operator::NotIn(6)),
            "&" => Ok(Operator::BitAnd(7)),
            "|" => Ok(Operator::BitOr(3)),
            "^" => Ok(Operator::BitXor(5)),
            "~" => Ok(Operator::BitNot),
            "<<" => Ok(Operator::Shl(9)),
            ">>" => Ok(Operator::Shr(9)),
            "(" => Ok(Operator::LeftParenthesis),
            ")" => Ok(Operator::RightParenthesis),
            "[" => Ok(Operator::LeftSquareBracket(100)),
            "]" => Ok(Operator::RightSquareBracket),
            "." => Ok(Operator::Dot(100)),
            "\"" => Ok(Operator::DoubleQuotes),
            "'" => Ok(Operator::SingleQuote),
            " " => Ok(Operator::WhiteSpace),
            "," => Ok(Operator::Comma),
            "!" => Ok(Operator::Not(99)),
            "false" => Ok(Operator::Value(to_value(false))),
            "true" => Ok(Operator::Value(to_value(true))),
            "==" => Ok(Operator::Eq(6)),
            "!=" => Ok(Operator::Ne(6)),
            ">" => Ok(Operator::Gt(6)),
            "<" => Ok(Operator::Lt(6)),
            ">=" => Ok(Operator::Ge(6)),
            "<=" => Ok(Operator::Le(6)),
            "&&" => Ok(Operator::And(4)),
            "||" => Ok(Operator::Or(2)),
            _ => Ok(Operator::Identifier(raw.to_owned())),
        }
    }
}