clarkmcc / cel-rust Goto Github PK
View Code? Open in Web Editor NEWCommon Expression Language interpreter written in Rust
License: MIT License
Common Expression Language interpreter written in Rust
License: MIT License
I'm experimenting with writing a Python extension for this library using pyo3
and running into issues when it comes down to concurrency. I'm not really well-versed in Rust, but I asked about it here. As far as I understand it boils down to using Arc
instead of Rc
.
I'm currently using a Python version of CEL interpreter, but its performance leaves a lot to be desired, so I'm looking for an alternatives. I use CEL for feature flags so we have multiple compiled expressions which are evaluated from different threads.
What are your thoughts about it? What would it take to make the interpreter thread-safe?
I'm willing to help, but my Rust knowledge if very very limited :)
I've been playing around with this CEL implementation and I noticed one odd thing with the following expressions:
b && (c == "string")
b && c == "string"
c == "string" && b
Given this context
{"b": True, "c": "string"}
they should all evaluate to true
, but this is not what's happening:
True <= b && (c == "string")
False <= b && c == "string"
True <= c == "string" && b
Here's a simple reproducer:
use cel_interpreter::{Context,Program, Value};
fn main() {
let expressions = [
"b && (c == \"string\")",
"b && c == \"string\"",
"c == \"string\" && b",
];
for expression in expressions {
let program = Program::compile(expression).unwrap();
let mut context = Context::default();
context.add_variable("b", Value::Bool(true));
context.add_variable("c", Value::String(String::from("string").into()));
let result = program.execute(&context);
println!("{:?} <= {}", result, expression)
}
}
It produces the following output:
Ok(Bool(true)) <= b && (c == "string")
Ok(Bool(false)) <= b && c == "string"
Ok(Bool(true)) <= c == "string" && b
It seems like in the case of b && c == "string"
the interpreter effectively evaluates this expression
(b && c) == "string"
I'm also using a Python version of CEL interpreter and it evaluates it properly:
import celpy
expressions = [
'b && (c == "string")',
'b && c == "string"',
'c == "string" && b',
]
for expression in expressions:
env = celpy.Environment()
ast = env.compile(expression)
prgm = env.program(ast)
activation = celpy.json_to_cel({"a": 1, "b": True, "c": "string"})
result = prgm.evaluate(activation)
print(f"{result} <= {expression}")
Produces
True <= b && (c == "string")
True <= b && c == "string"
True <= c == "string" && b
#[derive(Serialize)]
struct MidType<'a> {
body: &'a [u8],
raw: &'a [u8]
}
fn main() {
let program = Program::compile("foo.body.contains(1)").unwrap();
let mut context = Context::default();
context.add_variable("foo", MidType {
body: &[1,2,3],
raw: &[]
}).unwrap();
let v = program.execute(&context).unwrap();
println!("{:?}",v);
}
the body will be serialized as List[UInt], but the number 1 is Int type. output: Bool(false)
The library supports traversing maps using dot notation, but index notation is not supported
// Dot notation
foo.bar
// Index notation
foo["bar"]
fn main() {
let program = Program::compile("headers[\"Content-Type\"].contains(\"application/json\")").unwrap();
let mut context = Context::default();
let mut headers = HashMap::new();
headers.insert("Content-Type","application/json".to_string());
println!("{}",headers["Content-Type"]);
context.add_variable("headers", headers);
let value = program.execute(&context).unwrap();
assert_eq!(value, true.into());
}
headers["Content-Type"] 这样会报错,thread 'main' panicked at 'not implemented'
该如何实现呢,我知道headers.status这种写法可以,但是需要修改表达式
Benefits of using chumsky for parsing:
High level plan:
&&
, ||
, in
and ternary operations'1'.double()
or 10.double()
Do you want to keep both parsers? If so, how should the API work to pick between them? Assume it wouldn't be too tricky to add unsigned ints and un-escaped strings to the current lalrpop version?
We should be able to add any type that implements Serialize as a variable to the context
I’m fairly new to Rust and am using this project. I’d like to convert the executed Value into a String so I can serialize it to JSON.
Does Value need to implement From for this to work?
The official cel-spec has some additional macros / functions that might be useful for some of our use cases like: exists
or exists_one
.
Unfortunately I am not able to implement them by myself because: Context.clone()
is pub(crate)
and not pub
:
cel-rust/interpreter/src/context.rs
Line 115 in f4fa854
Am I missing something or wouldn't it be useful to provide the clone functionality and context shadowing also for custom extension functions?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.