Skip to content

Commit

Permalink
functions
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayyn committed May 27, 2024
1 parent eb4b2e3 commit 3b41061
Show file tree
Hide file tree
Showing 20 changed files with 263 additions and 95 deletions.
39 changes: 30 additions & 9 deletions cel-rs/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,42 @@
use crate::{function::Function, value::value::Val};
use std::{collections::HashMap, rc::Rc};
use crate::value::value::{Val};

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

impl Default for Context {
fn default() -> Self {
Self {
par: Default::default(),
variables: Default::default(),
funtions: HashMap::from([
("dyn", crate::std::new_dyn())
]),
}
}
}

impl Context {
pub fn add_variable(mut self, name: &'static str, val: Val) -> Self {
self.vars.insert(name, val);
pub fn add_variable(&mut self, name: &'static str, val: Val) -> &mut Self {
self.variables.insert(name, val);
self
}
pub fn resolve(&self, name: &String) -> Option<&Val> {
self.vars.get(name.as_str())
pub fn resolve_variable(&self, name: &String) -> Option<&Val> {
self.variables.get(name.as_str())
}

pub fn add_function(&mut self, name: &'static str, func: Function) -> &mut Self {
self.funtions.insert(name, func);
self
}
pub fn resolve_function(&self, name: &String) -> Option<&Function> {
self.funtions.get(name.as_str())
}

pub fn parent(&self) -> Option<Rc<Context>> {
self.par.clone()
self.par.clone()
}
}
}
80 changes: 36 additions & 44 deletions cel-rs/src/eval.rs
Original file line number Diff line number Diff line change
@@ -1,59 +1,53 @@
use std::collections::HashMap;
use std::rc::Rc;

use crate::parser::{Atom, Expression, RelationOp};
use crate::parser::{Atom, Expression, Member, 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_function(
&self,
name: Rc<String>,
receiver: Option<Val>,
argexprs: Vec<Expression>,
ctx: &mut Context,
) -> Val {
let mut args = Vec::with_capacity(argexprs.len() + 1);

// 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)
// }
// }
if let Some(expr) = receiver {
args.push(expr)
}

// 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"),
// }
// }
for expr in argexprs {
args.push(self.eval(expr, ctx));
}

if let Some(func) = ctx.resolve_function(&name) {
return (func.overloads.first().unwrap().func)(args)
}
Val::new_error("unknown func".to_string())
}
fn eval_member(&self, expr: Box<Expression>, member: Box<Member>, ctx: &mut Context) -> Val {
let v = self.eval(*expr, ctx);
match *member {
crate::parser::Member::Attribute(attr) => todo!(),
crate::parser::Member::FunctionCall(name, argexprs) => {
self.eval_function(name, Some(v), argexprs, ctx)
}
crate::parser::Member::Index(i) => todo!(),
crate::parser::Member::Fields(_) => todo!(),
}
}

pub fn eval(&self, expr: Expression, ctx: &mut Context) -> Val {
match expr {
Expression::GlobalFunctionCall(name, argexprs) => {
self.eval_function(name, None, argexprs, ctx)
}
Expression::Arithmetic(_, _, _) => todo!(),
Expression::Relation(left, op, right) => {
let l = self.eval(*left, ctx);
Expand All @@ -72,13 +66,12 @@ impl Eval {
Expression::Or(_, _) => todo!(),
Expression::And(_, _) => todo!(),
Expression::Unary(_, _) => todo!(),
Expression::Member(_, _) => todo!(),
Expression::FunctionCall(_) => todo!(),
Expression::Member(expr, member) => self.eval_member(expr, member, ctx),
Expression::List(values) => self.eval_list(values, ctx),
Expression::Map(entries) => self.eval_map(entries, ctx),
Expression::Atom(atom) => self.eval_atom(atom, ctx),
Expression::Ident(ident) => ctx
.resolve(&ident)
.resolve_variable(&ident)
.unwrap_or(&Val::new_error(format!("unknown variable {}", ident)))
.to_owned(),
}
Expand All @@ -94,7 +87,6 @@ impl Eval {
Val::new_map(Rc::new(map))
}


fn eval_list(&self, elems: Vec<Expression>, ctx: &mut Context) -> Val {
let mut list = Vec::with_capacity(elems.len());
for expr in elems {
Expand Down
15 changes: 15 additions & 0 deletions cel-rs/src/function.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::Val;

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Function {
pub name: &'static str,
pub overloads: &'static [Overload],
}

type Func = fn(args: Vec<Val>) -> Val;

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Overload {
pub key: &'static str,
pub func: Func
}
2 changes: 2 additions & 0 deletions cel-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ mod value;
mod program;
mod eval;
mod parser;
mod function;
mod std;

// public api
pub use crate::program::Program;
Expand Down
2 changes: 1 addition & 1 deletion cel-rs/src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub enum Expression {

Member(Box<Expression>, Box<Member>),

FunctionCall(Box<Member>),
GlobalFunctionCall(Rc<String>, Vec<Expression>),

List(Vec<Expression>),
Map(Vec<(Expression, Expression)>),
Expand Down
2 changes: 1 addition & 1 deletion cel-rs/src/parser/cel.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub Member: Expression = {
pub Primary: Expression = {
"."? <Ident> => Expression::Ident(<>.into()).into(),
"."? <identifier:Ident> "(" <arguments:CommaSeparated<Expression>> ")" => {
Expression::FunctionCall(Member::FunctionCall(identifier.into(), arguments).into()).into()
Expression::GlobalFunctionCall(identifier.into(), arguments)
},
Atom => Expression::Atom(<>).into(),
"[" <members:CommaSeparated<Expression>> "]" => Expression::List(<>).into(),
Expand Down
3 changes: 2 additions & 1 deletion cel-rs/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ pub mod tests {

#[test]
fn test_bool() {
let mut ctx = program::Context::default().add_variable("a", Val::new_bool(true));
let mut ctx = program::Context::default();
ctx.add_variable("a", Val::new_bool(true));
assert_eq!(eval_program!(r#"a == true"#, &mut ctx), Val::new_bool(true));
assert_eq!(eval_program!(r#"a == false"#, &mut ctx), Val::new_bool(false));
}
Expand Down
18 changes: 18 additions & 0 deletions cel-rs/src/std.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use crate::{function::{Function, Overload}, Val};


fn invoke_dyn(args: Vec<Val>) -> Val {
args.first().unwrap().clone()
}

pub fn new_dyn() -> Function {
Function {
name: "dyn",
overloads: &[Overload {
key: "dyn",
func: invoke_dyn,
}],
}
}


10 changes: 6 additions & 4 deletions cel-rs/src/value/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ impl Value for Bool {
}

fn equals(&self, other: &Val) -> Val {
other
.as_bool()
.map(|f| Val::new_bool(&self.0 == f))
.unwrap_or(Val::new_bool(false))
Val::new_bool(
other
.native_value()
.downcast_ref::<bool>()
.is_some_and(|f| f.eq(&self.0)),
)
}
}
9 changes: 9 additions & 0 deletions cel-rs/src/value/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ impl Value for Bytes {
&self.0
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(
other
.native_value()
.downcast_ref::<Rc<Vec<u8>>>()
.is_some_and(|f| f.eq(&self.0)),
)
}

fn compare(&self, other: &Val) -> Option<Val> {
other.native_value().downcast_ref::<Rc<Vec<u8>>>().map(|ob| {
(&self.0).cmp(ob).into()
Expand Down
9 changes: 9 additions & 0 deletions cel-rs/src/value/double.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ impl Value for Double {
&self.0
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(
other
.native_value()
.downcast_ref::<f64>()
.is_some_and(|f| f.eq(&self.0)),
)
}

fn compare(&self, other: &Val) -> Option<Val> {
let vl = other.native_value().downcast_ref::<f64>();
if vl.is_some() {
Expand Down
21 changes: 19 additions & 2 deletions cel-rs/src/value/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::fmt;

use super::{value::{Value, Val}, ty::Ty};
use super::{
ty::Ty,
value::{Val, Value},
};

#[derive(Eq, PartialEq)]
pub struct Error {
Expand Down Expand Up @@ -34,8 +37,22 @@ impl Value for Error {
fn ty(&self) -> Ty {
Ty::Error
}

fn native_value(&self) -> &dyn std::any::Any {
self
}

fn equals(&self, other: &Val) -> Val {
if other.ty() != Ty::Error {
return Val::new_bool(false);
}

Val::new_bool(
other
.native_value()
.downcast_ref::<Self>()
.map(|oerr| oerr.eq(self))
.is_some_and(|f| f)
)
}
}
13 changes: 10 additions & 3 deletions cel-rs/src/value/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@ impl Value for Int {
&self.0
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(
other
.native_value()
.downcast_ref::<i64>()
.is_some_and(|f| f.eq(&self.0)),
)
}

fn compare(&self, other: &Val) -> Option<Val> {
other
.native_value()
.downcast_ref::<i64>()
.map(|oi| {
(&self.0).cmp(oi).into()
})
.map(|oi| (&self.0).cmp(oi).into())
}
}
5 changes: 5 additions & 0 deletions cel-rs/src/value/null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ impl Value for Null {
fn native_value(&self) -> &dyn std::any::Any {
&()
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(other.ty() == Ty::Null)
}

fn compare(&self, other: &Val) -> Option<Val> {
if other.ty() == Ty::Null {
return Some(Val::from(Ordering::Equal))
Expand Down
8 changes: 8 additions & 0 deletions cel-rs/src/value/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ impl Value for String {
&self.0
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(
other
.native_value()
.downcast_ref::<StdString>()
.is_some_and(|f| f.eq(&self.0)),
)
}
fn compare(&self, other: &Val) -> Option<Val> {
other.native_value().downcast_ref::<StdString>().map(|oths| {
Val::from((&self.0).cmp(oths))
Expand Down
11 changes: 11 additions & 0 deletions cel-rs/src/value/ty.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::Val;

use super::value::Value;

// https://github.com/google/cel-spec/blob/master/doc/langdef.md#values
Expand Down Expand Up @@ -48,4 +50,13 @@ impl Value for Ty {
fn native_value(&self) -> &dyn std::any::Any {
self
}

fn equals(&self, other: &Val) -> Val {
Val::new_bool(
other
.native_value()
.downcast_ref::<Self>()
.is_some_and(|f| f.eq(&self)),
)
}
}
Loading

0 comments on commit 3b41061

Please sign in to comment.