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

Method resolveFunction

interpreter/planner.go:665–725  ·  view source on GitHub ↗

resolveFunction determines the call target, function name, and overload name from a given Expr value. The resolveFunction resolves ambiguities where a function may either be a receiver-style invocation or a qualified global function name. - The target expression may only consist of ident and select

(expr ast.Expr)

Source from the content-addressed store, hash-verified

663// - The function is declared in the environment using its fully-qualified name.
664// - The fully-qualified function name matches the string serialized target value.
665func (p *planBuilder) resolveFunction(expr ast.Expr) (ast.Expr, string, string) {
666 // Note: similar logic exists within the `checker/checker.go`. If making changes here
667 // please consider the impact on checker.go and consolidate implementations or mirror code
668 // as appropriate.
669 call := expr.AsCall()
670 var target ast.Expr = nil
671 if call.IsMemberFunction() {
672 target = call.Target()
673 }
674 fnName := call.FunctionName()
675
676 // Checked expressions always have a reference map entry, and _should_ have the fully qualified
677 // function name as the fnName value.
678 oRef, hasOverload := p.refMap[expr.ID()]
679 if hasOverload {
680 if len(oRef.OverloadIDs) == 1 {
681 return target, fnName, oRef.OverloadIDs[0]
682 }
683 // Note, this namespaced function name will not appear as a fully qualified name in ASTs
684 // built and stored before cel-go v0.5.0; however, this functionality did not work at all
685 // before the v0.5.0 release.
686 return target, fnName, ""
687 }
688
689 // Parse-only expressions need to handle the same logic as is normally performed at check time,
690 // but with potentially much less information. The only reliable source of information about
691 // which functions are configured is the dispatcher.
692 if target == nil {
693 // If the user has a parse-only expression, then it should have been configured as such in
694 // the interpreter dispatcher as it may have been omitted from the checker environment.
695 for _, qualifiedName := range p.container.ResolveCandidateNames(fnName) {
696 _, found := p.disp.FindOverload(qualifiedName)
697 if found {
698 return nil, qualifiedName, ""
699 }
700 }
701 // It's possible that the overload was not found, but this situation is accounted for in
702 // the planCall phase; however, the leading dot used for denoting fully-qualified
703 // namespaced identifiers must be stripped, as all declarations already use fully-qualified
704 // names. This stripping behavior is handled automatically by the ResolveCandidateNames
705 // call.
706 return target, strings.TrimPrefix(fnName, "."), ""
707 }
708
709 // Handle the situation where the function target actually indicates a qualified function name.
710 qualifiedPrefix, maybeQualified := p.toQualifiedName(target)
711 if maybeQualified {
712 maybeQualifiedName := qualifiedPrefix + "." + fnName
713 for _, qualifiedName := range p.container.ResolveCandidateNames(maybeQualifiedName) {
714 _, found := p.disp.FindOverload(qualifiedName)
715 if found {
716 // Clear the target to ensure the proper arity is used for finding the
717 // implementation.
718 return nil, qualifiedName, ""
719 }
720 }
721 }
722 // In the default case, the function is exactly as it was advertised: a receiver call on with

Callers 1

planCallMethod · 0.95

Calls 8

toQualifiedNameMethod · 0.95
ResolveCandidateNamesMethod · 0.80
AsCallMethod · 0.65
IsMemberFunctionMethod · 0.65
TargetMethod · 0.65
FunctionNameMethod · 0.65
IDMethod · 0.65
FindOverloadMethod · 0.65

Tested by

no test coverage detected