google / cel-go

Fast, portable, non-Turing complete expression evaluation with gradual typing (Go)
https://cel.dev
Apache License 2.0
2.26k stars 220 forks source link

AST replacement of sub-expressions #1000

Closed theoilie closed 2 months ago

theoilie commented 2 months ago

Feature request checklist

Change I'm wondering about a sort of AST replacement for sub-expressions. If my expression contains a variable which is a placeholder for another expression, then I replace it with the string before compiling. However, the variable in question would've already been compiled previously, so I already have its AST. I'm wondering if it's possible to use this AST instead of having to do manual string replacement.

Example Let's say expressions a and b evaluate to doubles:

a := "1.0 + 1.0"
aAST := env.Compile(a)
b := "a + 1.0"
bAST := env.Compile(b)

Now for expression a + b could it be possible to use the already-compiled ASTs for a and b?

env := cel.NewEnv([]cel.EnvOption{cel.Variable("a", cel.DoubleType), cel.Variable("b", cel.DoubleType)})

// We have to actually replace a and b here with their actual string expression (eg, "1.0 + 1.0").
// Otherwise, when we provide values in prg.Eval() below, the values have to be double type, not the string expression
cAST := env.Compile("a + b")
prg := myPrg(cAST)

// Values for a and b in this map have to be already evaluated into double type.
// We can't do "1.0 + 1.0" for "a" or else we're giving a string type for what's supposed to be a double.
// Is it possible to have a type here which is double but can use the already-compiled ASTs for a and b?
prg.Eval(map[string]any{"a": aAST, "b": bAST})

Alternatives considered The alternative I'm doing works, but it involves having to re-compile an expression which was already previously compiled. Specifically, the alternative is: before compiling, recursively find all variable names and replace them with their string expressions so that the whole expression string gets compiled without any variables.

TristonianJones commented 2 months ago

Hi @theoilie, you may want to look at using the cel/inclining.go approach for combining expressions. It should do what you want, at least for generating new ASTs

-Tristan

theoilie commented 2 months ago

Hi @theoilie, you may want to look at using the cel/inclining.go approach for combining expressions. It should do what you want, at least for generating new ASTs

-Tristan

This looks perfect -- thank you very much!