MCPcopy Create free account
hub / github.com/cel-expr/cel-go / Optimize

Method Optimize

cel/folding.go:85–145  ·  view source on GitHub ↗

Optimize queries the expression graph for scalar and aggregate literal expressions within call and select statements and then evaluates them and replaces the call site with the literal result. Note: only values which can be represented as literals in CEL syntax are supported.

(ctx *OptimizerContext, a *ast.AST)

Source from the content-addressed store, hash-verified

83//
84// Note: only values which can be represented as literals in CEL syntax are supported.
85func (opt *constantFoldingOptimizer) Optimize(ctx *OptimizerContext, a *ast.AST) *ast.AST {
86 root := ast.NavigateAST(a)
87
88 // Walk the list of foldable expression and continue to fold until there are no more folds left.
89 // All of the fold candidates returned by the constantExprMatcher should succeed unless there's
90 // a logic bug with the selection of expressions.
91 constantExprMatcherCapture := func(e ast.NavigableExpr) bool { return opt.constantExprMatcher(ctx, a, e) }
92 foldableExprs := ast.MatchDescendants(root, constantExprMatcherCapture)
93 foldCount := 0
94 for len(foldableExprs) != 0 && foldCount < opt.maxFoldIterations {
95 for _, fold := range foldableExprs {
96 // If the expression could be folded because it's a non-strict call, and the
97 // branches are pruned, continue to the next fold.
98 if fold.Kind() == ast.CallKind && maybePruneBranches(ctx, a, fold) {
99 continue
100 }
101 // Late-bound function calls cannot be folded.
102 if fold.Kind() == ast.CallKind && isLateBoundFunctionCall(ctx, fold) {
103 continue
104 }
105 // Otherwise, assume all context is needed to evaluate the expression.
106 err := opt.tryFold(ctx, a, fold)
107 // Ignore errors for identifiers or subexpressions that cannot be folded, since there is no guarantee that the environment
108 // has a value for them.
109 if err != nil && fold.Kind() != ast.IdentKind && !errors.Is(err, errCannotFold) {
110 ctx.ReportErrorAtID(fold.ID(), "constant-folding evaluation failed: %v", err.Error())
111 return a
112 }
113 }
114 foldCount++
115 foldableExprs = ast.MatchDescendants(root, constantExprMatcherCapture)
116 }
117 // Once all of the constants have been folded, try to run through the remaining comprehensions
118 // one last time. In this case, there's no guarantee they'll run, so we only update the
119 // target comprehension node with the literal value if the evaluation succeeds.
120 for _, compre := range ast.MatchDescendants(root, ast.KindMatcher(ast.ComprehensionKind)) {
121 opt.tryFold(ctx, a, compre)
122 }
123
124 // If the output is a list, map, or struct which contains optional entries, then prune it
125 // to make sure that the optionals, if resolved, do not surface in the output literal.
126 pruneOptionalElements(ctx, root)
127
128 // Ensure that all intermediate values in the folded expression can be represented as valid
129 // CEL literals within the AST structure. Use `PostOrderVisit` rather than `MatchDescendents`
130 // to avoid extra allocations during this final pass through the AST.
131 ast.PostOrderVisit(root, ast.NewExprVisitor(func(e ast.Expr) {
132 if e.Kind() != ast.LiteralKind {
133 return
134 }
135 val := e.AsLiteral()
136 adapted, err := adaptLiteral(ctx, val)
137 if err != nil {
138 ctx.ReportErrorAtID(root.ID(), "constant-folding evaluation failed: %v", err.Error())
139 return
140 }
141 ctx.UpdateExpr(e, adapted)
142 }))

Callers

nothing calls this directly

Calls 15

constantExprMatcherMethod · 0.95
tryFoldMethod · 0.95
NavigateASTFunction · 0.92
MatchDescendantsFunction · 0.92
KindMatcherFunction · 0.92
PostOrderVisitFunction · 0.92
NewExprVisitorFunction · 0.92
maybePruneBranchesFunction · 0.85
isLateBoundFunctionCallFunction · 0.85
pruneOptionalElementsFunction · 0.85
adaptLiteralFunction · 0.85
UpdateExprMethod · 0.80

Tested by

no test coverage detected