1414
1515#include " eval/compiler/resolver.h"
1616
17+ #include < cstddef>
1718#include < cstdint>
19+ #include < cstdio>
1820#include < string>
1921#include < utility>
2022#include < vector>
2123
24+ #include " absl/base/no_destructor.h"
2225#include " absl/container/flat_hash_map.h"
2326#include " absl/status/statusor.h"
2427#include " absl/strings/match.h"
2730#include " absl/strings/string_view.h"
2831#include " absl/strings/strip.h"
2932#include " absl/types/optional.h"
33+ #include " absl/types/span.h"
3034#include " common/kind.h"
3135#include " common/type.h"
3236#include " common/type_reflector.h"
@@ -96,37 +100,41 @@ std::vector<std::string> Resolver::FullyQualifiedNames(absl::string_view name,
96100 // and handle the case where this id is in the reference map as either a
97101 // function name or identifier name.
98102 std::vector<std::string> names;
99- // Handle the case where the name contains a leading '.' indicating it is
100- // already fully-qualified.
101- if (absl::StartsWith (name, " ." )) {
102- std::string fully_qualified_name = std::string (name.substr (1 ));
103- names.push_back (fully_qualified_name);
104- return names;
105- }
106103
107- // namespace prefixes is guaranteed to contain at least empty string, so this
108- // function will always produce at least one result.
109- for (const auto & prefix : namespace_prefixes_) {
104+ auto prefixes = GetPrefixesFor (name);
105+ for (const auto & prefix : prefixes) {
110106 std::string fully_qualified_name = absl::StrCat (prefix, name);
111107 names.push_back (fully_qualified_name);
112108 }
113109 return names;
114110}
115111
112+ absl::Span<const std::string> Resolver::GetPrefixesFor (
113+ absl::string_view& name) const {
114+ static const absl::NoDestructor<std::string> kEmptyPrefix (" " );
115+ if (absl::StartsWith (name, " ." )) {
116+ name = name.substr (1 );
117+ return absl::MakeConstSpan (kEmptyPrefix .get (), 1 );
118+ }
119+ return namespace_prefixes_;
120+ }
121+
116122absl::optional<cel::Value> Resolver::FindConstant (absl::string_view name,
117123 int64_t expr_id) const {
118- auto names = FullyQualifiedNames (name, expr_id);
119- for (const auto & name : names) {
124+ auto prefixes = GetPrefixesFor (name);
125+ for (const auto & prefix : prefixes) {
126+ std::string qualified_name = absl::StrCat (prefix, name);
120127 // Attempt to resolve the fully qualified name to a known enum.
121- auto enum_entry = enum_value_map_.find (name );
128+ auto enum_entry = enum_value_map_.find (qualified_name );
122129 if (enum_entry != enum_value_map_.end ()) {
123130 return enum_entry->second ;
124131 }
125132 // Conditionally resolve fully qualified names as type values if the option
126133 // to do so is configured in the expression builder. If the type name is
127134 // not qualified, then it too may be returned as a constant value.
128- if (resolve_qualified_type_identifiers_ || !absl::StrContains (name, " ." )) {
129- auto type_value = type_reflector_.FindType (name);
135+ if (resolve_qualified_type_identifiers_ ||
136+ !absl::StrContains (qualified_name, " ." )) {
137+ auto type_value = type_reflector_.FindType (qualified_name);
130138 if (type_value.ok () && type_value->has_value ()) {
131139 return TypeValue (**type_value);
132140 }
@@ -157,6 +165,27 @@ std::vector<cel::FunctionOverloadReference> Resolver::FindOverloads(
157165 return funcs;
158166}
159167
168+ std::vector<cel::FunctionOverloadReference> Resolver::FindOverloads (
169+ absl::string_view name, bool receiver_style, size_t arity,
170+ int64_t expr_id) const {
171+ std::vector<cel::FunctionOverloadReference> funcs;
172+ auto prefixes = GetPrefixesFor (name);
173+ for (const auto & prefix : prefixes) {
174+ std::string qualified_name = absl::StrCat (prefix, name);
175+ // Only one set of overloads is returned along the namespace hierarchy as
176+ // the function name resolution follows the same behavior as variable name
177+ // resolution, meaning the most specific definition wins. This is different
178+ // from how C++ namespaces work, as they will accumulate the overload set
179+ // over the namespace hierarchy.
180+ funcs = function_registry_.FindStaticOverloadsByArity (
181+ qualified_name, receiver_style, arity);
182+ if (!funcs.empty ()) {
183+ return funcs;
184+ }
185+ }
186+ return funcs;
187+ }
188+
160189std::vector<cel::FunctionRegistry::LazyOverload> Resolver::FindLazyOverloads (
161190 absl::string_view name, bool receiver_style,
162191 const std::vector<cel::Kind>& types, int64_t expr_id) const {
@@ -173,10 +202,27 @@ std::vector<cel::FunctionRegistry::LazyOverload> Resolver::FindLazyOverloads(
173202 return funcs;
174203}
175204
205+ std::vector<cel::FunctionRegistry::LazyOverload> Resolver::FindLazyOverloads (
206+ absl::string_view name, bool receiver_style, size_t arity,
207+ int64_t expr_id) const {
208+ std::vector<cel::FunctionRegistry::LazyOverload> funcs;
209+ auto prefixes = GetPrefixesFor (name);
210+ for (const auto & prefix : prefixes) {
211+ std::string qualified_name = absl::StrCat (prefix, name);
212+ funcs = function_registry_.FindLazyOverloadsByArity (name, receiver_style,
213+ arity);
214+ if (!funcs.empty ()) {
215+ return funcs;
216+ }
217+ }
218+ return funcs;
219+ }
220+
176221absl::StatusOr<absl::optional<std::pair<std::string, cel::Type>>>
177222Resolver::FindType (absl::string_view name, int64_t expr_id) const {
178- auto qualified_names = FullyQualifiedNames (name, expr_id);
179- for (auto & qualified_name : qualified_names) {
223+ auto prefixes = GetPrefixesFor (name);
224+ for (auto & prefix : prefixes) {
225+ std::string qualified_name = absl::StrCat (prefix, name);
180226 CEL_ASSIGN_OR_RETURN (auto maybe_type,
181227 type_reflector_.FindType (qualified_name));
182228 if (maybe_type.has_value ()) {
0 commit comments