Learning Rust by playing with the Common Expression Language.
- Write a very basic CEL Lexer/Parser in Rust (using Chumsky)
- Evaluate the parsed CEL AST by implementing a basic Treewalk interpreter
- Write a basic CLI for evaluating CEL expressions with data loaded from stdin or a JSON/YAML file.
- Create rust packages for the Lexer/Parser and Interpreter
- See how conformant we can get to the CEL spec, parse the test data and evaluate the expressions.
- Wrap for Python
- Use a Pratt parser
oncenow that Chumsky supports it (zesterer/chumsky#464) - Possibly write a bytecode compiler for a simple stack based VM...
- Research and try the existing Rust implementations of CEL.
- Benchmark the Cloud Custodian Python-CEL implementation against the Rust ones.
- Use an existing Lexer like Logos
cargo run -- --expression="-(3.0 + 5.0) * 2.0e0 - -1.0"
Which outputs something like:
AST:
Arithmetic(Arithmetic(Unary(Neg, Arithmetic(Atom(Float(3.0)), Add, Atom(Float(5.0)))), Multiply, Atom(Float(2.0))), Subtract, Unary(Neg, Atom(Float(1.0))))
Evaluating program
NumericCelType(Float(-15.0))
Note while the parser is close to complete I'm not intending to implement a full interpreter with all built-in functions.
The interpreter has basic support for strings, numbers, bools, lists, maps, variables, and binary and unary operators.
cargo run -- --expression="size('hello world') > 5u"
Outputs:
AST:
Relation(Member(Ident("size"), FunctionCall([Atom(String("hello world"))])), GreaterThan, Atom(UInt(5)))
Evaluating program
Bool(true)
To add context from a JSON file use --input
with either a filename or -
to read from
stdin:
echo "{\"foo\":\"bar\"}" | cargo run -- --expression="foo" --input -
Outputs:
Parsed context data: Object {"foo": String("bar")}
AST:
Ident("foo")
Evaluating program
String("bar")
A Python package rustycel
using PyO3 in python_bindings
offers a simple evaluate
function from Python:
>>> import rustycel
>>> rustycel.evaluate("1u + 4u")
5
Note only a few primitive types are mapped back to Python native types.
- cel-go - Reference implementation of CEL by Google in Go.
- cel-python - Python implementation of CEL by Cloud Custodian as used in Netchecks.
- clarkmcc/cel-rust (Maintained fork of orf/cel-rust.) Implements separate crates for parser (using lalrpop) and interpreter (straightforward treewalk interpreter).
- thesayyn/cel-rust (Incomplete). WASM target with online demo. Parser uses lalrpop.
Test Data
https://github.com/google/cel-spec/blob/master/tests/simple/testdata/basic.textproto
- jaq
- https://github.com/panda-re/panda/blob/dev/panda/plugins/cosi_strace/src/c_type_parser.rs
- prql (uses a separate Chumsky Lexer to create Vec, then parses Token stream into Expr, Stmt, Literal etc)
- flux - lexed with Logos then parsed with Chumsky.
- Cotton Separate Chumsky Lexer and Parser.
- Cornucopia parses SQL.
- percival nice split between Lexer and Parser with WASM target.
- monty uses a lot of Rust macros
- blackstone
- savage