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

Method Optimize

cel/folding.go:83–143  ·  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

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

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