Skip to content

Commit

Permalink
rework the type system
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayyn committed May 24, 2024
1 parent 99bb011 commit a5f0aca
Show file tree
Hide file tree
Showing 19 changed files with 693 additions and 308 deletions.
6 changes: 3 additions & 3 deletions cel-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ readme = "../README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ordered-float = "4.2.0"
ordered_hash_map = "0.4.0"
regex = "1.4.2"
lalrpop-util = "0.19.1"
lazy_static = "1.4.0"

[dev_dependencies]
[dev-dependencies]
cel-spec = {path = "../cel-spec"}

[build-dependencies]
lalrpop = { version = "0.19.1", features = ["lexer"] }
lalrpop = { version = "0.19.1", features = ["lexer"] }
19 changes: 5 additions & 14 deletions cel-rs/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
use std::{collections::HashMap, rc::Rc};

use crate::{eval::Bag, Value};
use crate::value::value::{Val};

#[derive(Default)]
pub struct Context {
par: Option<Rc<Context>>,
vars: HashMap<&'static str, Value>
}

impl Bag for Context {
fn unpack(self) -> Value {
todo!()
}
vars: HashMap<&'static str, Val>
}

impl Context {
pub fn add_variable(mut self, name: &'static str, val: Value) -> Self {
pub fn add_variable(mut self, name: &'static str, val: Val) -> Self {
self.vars.insert(name, val);
self
}

pub fn resolve(&self, name: &String) -> Option<Value> {
// TODO: this is probably expensive to do.
self.vars.get(name.as_str()).map(|f| f.to_owned())
pub fn resolve(&self, name: &String) -> Option<&Val> {
self.vars.get(name.as_str())
}
pub fn parent(&self) -> Option<Rc<Context>> {
self.par.clone()
Expand Down
245 changes: 138 additions & 107 deletions cel-rs/src/eval.rs
Original file line number Diff line number Diff line change
@@ -1,127 +1,158 @@
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
}
}
use crate::parser::{Atom, Expression, RelationOp};
use crate::value::value::{Val};
use crate::Context;

#[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, 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) {
// return val
// }
// panic!("unknown attribute {}", attr)
// },
// crate::parser::Member::FunctionCall(name, mut rargs) => {
// let mut args = Vec::with_capacity(rargs.len());
// rargs.reverse();
// for arg in rargs {
// args.push(self.eval(arg, ctx).unpack());
// }

fn eval_member(&self, expr: Expression, member: Member, ctx: &mut Context) -> impl Bag {
let v = self.eval(expr, 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) {
return val
}
panic!("unknown attribute {}", attr)
},
crate::parser::Member::FunctionCall(name, mut rargs) => {
let mut args = Vec::with_capacity(rargs.len());
rargs.reverse();
for arg in rargs {
args.push(self.eval(arg, ctx).unpack());
}

if let Some(val) = ctx.resolve(&name) {
args.push(v.clone());
args.reverse();
if let Value::Function(f) = val {
return (f.overloads.first().unwrap().func)(args)
}
}

panic!("is not a func")
},
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))
}
// if let Some(val) = ctx.resolve(&name) {
// args.push(v.clone());
// args.reverse();
// if let Value::Function(f) = val {
// return (f.overloads.first().unwrap().func)(args)
// }
// }

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))
}
// panic!("is not a func")
// },
// 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))
// }

pub fn eval(&self, expr: Expression, ctx: &mut Context) -> impl Bag {
// 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) -> Val {
match expr {
Expression::Atom(atom) => Value::from(atom),
Expression::Arithmetic(_, _, _) => todo!(),
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"),
let l = self.eval(*left, ctx);
let r = self.eval(*right, ctx);
Val::new_bool(match op {
RelationOp::Equals => l.eq(&r),
RelationOp::LessThan => l.lt(&r),
RelationOp::LessThanEq => l.le(&r),
RelationOp::GreaterThan => l.gt(&r),
RelationOp::GreaterThanEq => l.ge(&r),
RelationOp::NotEquals => l.ne(&r),
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)
},
Expression::Member(_, _) => todo!(),
Expression::FunctionCall(_) => todo!(),
Expression::List(_) => todo!(),
Expression::Map(_) => todo!(),
Expression::Atom(atom) => self.eval_atom(atom, ctx),
Expression::Ident(ident) => ctx
.resolve(&ident)
.unwrap_or(&Val::new_error(format!("unknown variable {}", ident)))
.to_owned(),
}
}

pub fn eval_atom(&self, atom: Atom, ctx: &mut Context) -> Val {
match atom {
Atom::Int(i) => Val::new_int(i),
Atom::UInt(u) => Val::new_uint(u),
Atom::Float(f) => Val::new_double(f),
Atom::String(s) => Val::new_string(s),
Atom::Bytes(b) => Val::new_bytes(b),
Atom::Bool(b) => Val::new_bool(b),
Atom::Null => Val::new_null(),
}
}

// 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)
// },
// Expression::FunctionCall(_) => todo!(),
// }
// }
}
15 changes: 8 additions & 7 deletions cel-rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
pub mod context;
pub mod program;
pub use crate::program::Program;
pub use crate::context::Context;
pub mod value;
pub use crate::value::Value;
mod context;
mod value;
mod program;
mod eval;
mod parser;
mod parser;

// public api
pub use crate::program::Program;
pub use crate::context::Context;
Loading

0 comments on commit a5f0aca

Please sign in to comment.