clarkmcc / cel-rust

Common Expression Language interpreter written in Rust
https://crates.io/crates/cel-interpreter
MIT License
377 stars 21 forks source link

Generalize interpreter values #86

Closed jrandolf closed 1 month ago

jrandolf commented 1 month ago

CEL is primarily used to build expressions that are passed to other systems, such as database engines. The current interpreter, however, functions more like an advanced calculator for in-memory objects, as it is limited to working with built-in primitives.

A solution here would be to construct a generalized walker that walks the ast and automatically performs certain calculations such as timestamps and etc.

clarkmcc commented 1 month ago

CEL is primarily used to build expressions that are passed to other systems, such as database engines.

According to the official CEL spec and documentation, I wouldn't say this is completely true.

Common Expression Language (CEL) is an expression language that’s fast, portable, and safe to execute in performance-critical applications. CEL is designed to be embedded in an application, with application-specific extensions, and is ideal for extending declarative configurations that your applications might already use. https://github.com/google/cel-cpp/tree/master/codelab

Common Expression Language (CEL) is a general-purpose expression language designed to be fast, portable, and safe to execute. You can use CEL on its own or embed it into a larger product. CEL is a great fit for a wide variety applications, from routing remote procedure calls (RPCs) to defining security policies. CEL is extensible, platform independent, and optimized for compile-once/evaluate-many workflows. https://cel.dev/overview/cel-overview

Many services and applications evaluate declarative configurations. For example, role-based access control (RBAC) is a declarative configuration that produces an access decision given a user role and a set of users. While declarative configs are sufficient for most cases, sometimes you need more expressive power. That's where CEL comes in. https://cel.dev/overview/cel-overview

Now, that doesn't mean it can't be used for anything you could come up with, but to say that it's usually passed to database engines as a sort of "WHERE" clause is a heavy generalization. The current interpreter implementation is designed to be similar in purpose to its C++, Java, and Go interpreter counterparts -- sandboxed CEL expression execution on dynamic data.

I'm not opposed to looking at ways to make CEL fit more use-cases though, I'm just saying your use case is not what this project (and probably the CEL language as a whole) was originally targeted at.

If you have an idea for an improvement, please show some specific examples of what you think can be improved and we can see what makes sense to support in this project!

jrandolf commented 1 month ago

but to say that it's usually passed to database engines as a sort of "WHERE" clause is a heavy generalization

But... that's what CEL is. It's a general-purpose expression language. To be precise, although the current interpreter "looks" similar to the Go and Java counterparts, both Java and Go are completely expressive in terms of generality.

If you have an idea for an improvement, please show some specific examples of what you think can be improved and we can see what makes sense to support in this project!

We can do the following, following the footsteps of Go:

  1. Create a new object-safe trait called Val similar to https://github.com/google/cel-go/blob/master/common/types/ref/reference.go#L37
  2. Add that to the Value enum and update the interpreter to call convert_to_native and convert_to_type at the appropriate places.
  3. Voila! A generalized interpreter.

    Note: There are several details I skipped, but that's an approximate solution required to make the interpreter apply generally.