powerfx 0.1.0

Embedded PowerFX interpreter.
Documentation

use std::{sync::Arc, collections::BTreeMap, fmt::Display};

use chrono::NaiveDate;


#[derive(Debug, Clone, PartialEq)]
pub enum Literal {
    Date(NaiveDate),
    Number(f64),
    Boolean(bool),
    OptionSet(OptionSet),
    Text(Arc<str>),
    Image(Arc<str>),
    Hyperlink(Arc<str>),
    Media(Arc<str>),
    Record(Record),
    Table(Vec<Record>),
    Blank,
}

impl Literal {
    pub fn is_blank(&self) -> bool {
        match self {
            Literal::Blank => true,
            _ => false,
        }
    }

    pub fn is_not_blank(&self) -> bool {
        !self.is_blank()
    }
}

impl Display for Literal {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Literal::Date(d) => write!(f, "{}", d),
            Literal::Number(n) => write!(f, "{}", n),
            Literal::Boolean(b) => write!(f, "{}", b),
            Literal::OptionSet(o) => write!(f, "{:?}", o),
            Literal::Text(t) => write!(f, "{}", t),
            Literal::Image(i) => write!(f, "{}", i),
            Literal::Hyperlink(h) => write!(f, "{}", h),
            Literal::Media(m) => write!(f, "{}", m),
            Literal::Record(r) => write!(f, "{:?}", r),
            Literal::Table(t) => write!(f, "{:?}", t),
            Literal::Blank => write!(f, ""),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct OptionSet {
    pub options: BTreeMap<i64, String>,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Record {
    pub fields: BTreeMap<Arc<str>, Expression>
}

impl Record {
    pub fn from(fields: Vec<(Arc<str>, Expression)>) -> Record {
        Record { fields: fields.into_iter().collect::<BTreeMap<Arc<str>, Expression>>() }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Context {
    Parent,
    Self_,
    ThisItem,
    ThisRecord,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Expression {
    UnaryExpression(UnaryExpression),
    BinaryExpression(BinaryExpression),
    FunctionExpression(FunctionExpression),
}

#[derive(Debug, Clone, PartialEq)]
pub enum UnaryExpression {
    Not(Box<Expression>),
    IsBlank(Box<Expression>),
    IsNotBlank(Box<Expression>),
    Literal(Literal),
    Property { context: Context, key: Arc<str> },
    Parameter(Arc<str>),
    Identifier(Arc<str>),    
    Alias { source: Box<Expression>, alias: Arc<str> },
}

impl UnaryExpression {
    pub fn literal(value: Literal) -> Expression {
        Expression::UnaryExpression(UnaryExpression::Literal(value))
    }

    pub fn alias(source: Expression, alias: Arc<str>) -> Expression {
        Expression::UnaryExpression(Self::Alias { source: Box::new(source), alias })
    }
    
    pub fn parameter(name: Arc<str>) -> Expression {
        Expression::UnaryExpression(UnaryExpression::Parameter(name))
    }
    
    pub fn property(context: Context, key: Arc<str>) -> Expression {
        Expression::UnaryExpression(UnaryExpression::Property { context, key })
    }

    pub fn not(cond: Expression) -> Expression {
        Expression::UnaryExpression(Self::Not(Box::new(cond)))
    }

    pub fn ident(ident: Arc<str>) -> Expression {
        Expression::UnaryExpression(Self::Identifier(ident))
    }

    pub fn is_blank(expr: Expression) -> Expression {
        Expression::UnaryExpression(Self::IsBlank(Box::new(expr)))
    }

    pub fn is_not_blank(expr: Expression) -> Expression {
        Expression::UnaryExpression(Self::IsNotBlank(Box::new(expr)))
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum BinaryExpression {
    And(Box<Expression>, Box<Expression>),
    Or(Box<Expression>, Box<Expression>),
    
    Eq(Box<Expression>, Box<Expression>),
    Ne(Box<Expression>, Box<Expression>),
    Lt(Box<Expression>, Box<Expression>),
    Le(Box<Expression>, Box<Expression>),
    Gt(Box<Expression>, Box<Expression>),
    Ge(Box<Expression>, Box<Expression>),
    In(Box<Expression>, Box<Expression>, bool),
    
    Add(Box<Expression>, Box<Expression>),
    Subtract(Box<Expression>, Box<Expression>),
    Multiply(Box<Expression>, Box<Expression>),
    Divide(Box<Expression>, Box<Expression>),
    Modulo(Box<Expression>, Box<Expression>),
    Exponent(Box<Expression>, Box<Expression>),

}

impl BinaryExpression {
    pub fn and(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::And(Box::new(a), Box::new(b)))
    }

    pub fn or(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Or(Box::new(a), Box::new(b)))
    }

    pub fn eq(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Eq(Box::new(a), Box::new(b)))
    }

    pub fn ne(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Ne(Box::new(a), Box::new(b)))
    }

    pub fn lt(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Lt(Box::new(a), Box::new(b)))
    }

    pub fn le(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Le(Box::new(a), Box::new(b)))
    }

    pub fn gt(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Gt(Box::new(a), Box::new(b)))
    }

    pub fn in_(a: Expression, b: Expression, exact: bool) -> Expression {
        Expression::BinaryExpression(Self::In(Box::new(a), Box::new(b), exact))
    }

    pub fn ge(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Ge(Box::new(a), Box::new(b)))
    }

    pub fn add(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Add(Box::new(a), Box::new(b)))
    }

    pub fn subtract(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Subtract(Box::new(a), Box::new(b)))
    }

    pub fn multiply(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Multiply(Box::new(a), Box::new(b)))
    }

    pub fn divide(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Divide(Box::new(a), Box::new(b)))
    }

    pub fn modulo(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Modulo(Box::new(a), Box::new(b)))
    }

    pub fn exponent(a: Expression, b: Expression) -> Expression {
        Expression::BinaryExpression(Self::Exponent(Box::new(a), Box::new(b)))
    }

}


#[derive(Debug, Clone, PartialEq)]
pub struct FunctionExpression {
    pub name: Arc<str>, 
    pub args: Vec<Expression>,
}

impl FunctionExpression {
  pub fn function(name: Arc<str>, args: Vec<Expression>) -> Expression {
    Expression::FunctionExpression(FunctionExpression{ name, args })
  }
}