cel-rs 0.2.0

Common Expression Language (cel) for Rust.
Documentation
use core::panic;
use std::rc::Rc;
use ordered_hash_map::OrderedHashMap;
use crate::parser::{ArithmeticOp, Expression, Member, RelationOp};
use crate::{value::Value, Context};

pub trait Bag {
   fn unpack(self) -> Value;
}

impl Bag for Value {
    fn unpack(self) -> Value {
        self
    }  
}

#[derive(Default)]
pub struct Eval {}

impl Eval {

    fn eval_member(&self, expr: Expression, member: Member, ctx: &mut Context) -> impl Bag {
        let v = self.eval(expr.clone(), ctx).unpack();
        match member {
            crate::parser::Member::Attribute(attr) => {
                if let Value::Map(v) = v {
                    let value = v.get(&Value::String(attr)).expect("TODO: unknown map key");
                    return value.to_owned()
                }
                if let Some(val) = ctx.resolve(&attr) {
                    println!("{}", &attr);
                    return  val
                }
                
                panic!("unknown attribute {}", attr)
            },
            crate::parser::Member::FunctionCall(args) => {
                println!("call args = {:?}  v = {:?}, expr = {:?}", args, v, expr);
                Value::Null
            },
            crate::parser::Member::Index(i) => {
                let i = self.eval(*i, ctx).unpack();
                if let Value::Map(v) = v {
                    let value = v.get(&i).expect("TODO: unknown map key");
                    return value.to_owned()
                } 
                Value::Null
            },
            crate::parser::Member::Fields(_) => todo!("Fields"),
        }
    }
    fn eval_map(&self, entries: Vec<(Expression, Expression)>, ctx: &mut Context) -> Value {
        let mut map = OrderedHashMap::with_capacity(entries.len());
        for (kexpr, vexpr) in entries {
            let k = self.eval(kexpr, ctx).unpack();
            let v = self.eval(vexpr, ctx).unpack();
            map.insert(k, v);
        }
        Value::Map(Rc::new(map))
    }

    fn eval_list(&self, elems: Vec<Expression>, ctx: &mut Context) -> Value {
        let mut list = Vec::with_capacity(elems.len());
        for expr in elems {
            let v = self.eval(expr, ctx).unpack();
            list.push(v);
        }
        Value::List(Rc::new(list))
    }

    pub fn eval(&self, expr: Expression, ctx: &mut Context) -> impl Bag {
        match expr {
            Expression::Atom(atom) => Value::from(atom),
            Expression::Relation(left, op, right) => {
                let left = self.eval(*left, ctx).unpack();
                let right = self.eval(*right, ctx).unpack();
                let result = match op {
                    RelationOp::Equals => left.eq(&right),
                    RelationOp::LessThan => todo!("lt"),
                    RelationOp::LessThanEq => todo!("lte"),
                    RelationOp::GreaterThan => todo!("gt"),
                    RelationOp::GreaterThanEq => todo!("gte"),
                    RelationOp::NotEquals => todo!("ne"),
                    RelationOp::In => todo!("in"),
                };
                Value::Bool(result)
            }
            Expression::Arithmetic(left, op, right) => {
                let left = self.eval(*left, ctx).unpack();
                let right = self.eval(*right, ctx).unpack();
                match op {
                    ArithmeticOp::Add => left + right,
                    ArithmeticOp::Subtract => left - right,
                    ArithmeticOp::Divide => left / right,
                    ArithmeticOp::Multiply => left * right,
                    ArithmeticOp::Modulus => todo!("modulus"),
                }
            }
            Expression::Ternary(_, _, _) => todo!(),
            Expression::Or(_, _) => todo!(),
            Expression::And(_, _) => todo!(),
            Expression::Unary(_, _) => todo!(),
            Expression::Member(expr, member) => self.eval_member(*expr, *member, ctx).unpack(),
            Expression::List(elems) => self.eval_list(elems, ctx),
            Expression::Map(entries) => self.eval_map(entries, ctx),
            Expression::Ident(r) => {
                let val  = ctx.resolve(&r);
                if let Some(val) = val {
                    return val
                }
                panic!("unknown attribute {}", &r)
            },
        }
    }
}