diff --git a/common/BUILD b/common/BUILD index 213a91035..1007f85dd 100644 --- a/common/BUILD +++ b/common/BUILD @@ -1035,8 +1035,10 @@ cc_library( "function_descriptor.h", ], deps = [ + ":ast", ":kind", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/functional:overload", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:span", ], diff --git a/common/function_descriptor.cc b/common/function_descriptor.cc index 779fe939b..a48f9c211 100644 --- a/common/function_descriptor.cc +++ b/common/function_descriptor.cc @@ -16,9 +16,14 @@ #include #include +#include +#include +#include #include "absl/base/macros.h" +#include "absl/functional/overload.h" #include "absl/types/span.h" +#include "common/ast.h" #include "common/kind.h" namespace cel { @@ -90,4 +95,86 @@ bool FunctionDescriptor::operator<(const FunctionDescriptor& other) const { return false; } +namespace { + +[[nodiscard]] +Kind TypeSpecToKind(const TypeSpec& spec) { + return std::visit( + absl::Overload( + [](UnsetTypeSpec) -> Kind { return Kind::kError; }, + [](const DynTypeSpec& spec) -> Kind { return Kind::kDyn; }, + [](const NullTypeSpec& spec) -> Kind { return Kind::kNull; }, + [](const PrimitiveType& spec) -> Kind { + switch (spec) { + case PrimitiveType::kPrimitiveTypeUnspecified: + return Kind::kError; + case PrimitiveType::kBool: + return Kind::kBool; + case PrimitiveType::kInt64: + return Kind::kInt; + case PrimitiveType::kUint64: + return Kind::kUint; + case PrimitiveType::kDouble: + return Kind::kDouble; + case PrimitiveType::kString: + return Kind::kString; + case PrimitiveType::kBytes: + return Kind::kBytes; + } + }, + [](const PrimitiveTypeWrapper& spec) -> Kind { + switch (spec.type()) { + case PrimitiveType::kPrimitiveTypeUnspecified: + return Kind::kError; + case PrimitiveType::kBool: + return Kind::kBoolWrapper; + case PrimitiveType::kInt64: + return Kind::kIntWrapper; + case PrimitiveType::kUint64: + return Kind::kUintWrapper; + case PrimitiveType::kDouble: + return Kind::kDoubleWrapper; + case PrimitiveType::kString: + return Kind::kStringWrapper; + case PrimitiveType::kBytes: + return Kind::kBytesWrapper; + } + }, + [](const WellKnownTypeSpec& spec) -> Kind { + switch (spec) { + case cel::WellKnownTypeSpec::kWellKnownTypeUnspecified: + return Kind::kError; + case cel::WellKnownTypeSpec::kDuration: + return Kind::kError; + case cel::WellKnownTypeSpec::kTimestamp: + return Kind::kTimestamp; + case cel::WellKnownTypeSpec::kAny: + return Kind::kAny; + } + }, + [](const ListTypeSpec& spec) -> Kind { return Kind::kList; }, + [](const MapTypeSpec& spec) -> Kind { return Kind::kMap; }, + [](const FunctionTypeSpec& spec) -> Kind { return Kind::kFunction; }, + [](const MessageTypeSpec& spec) -> Kind { return Kind::kStruct; }, + [](const ParamTypeSpec& spec) -> Kind { return Kind::kTypeParam; }, + [](const std::unique_ptr& spec) -> Kind { + return Kind::kType; + }, + [](const ErrorTypeSpec& spec) -> Kind { return Kind::kError; }, + [](const AbstractType& spec) -> Kind { return Kind::kOpaque; }), + spec.type_kind()); +} + +} // namespace + +std::vector FunctionDescriptor::FunctionTypeSpecToArgumentKinds( + const FunctionTypeSpec& spec) { + std::vector kinds; + kinds.reserve(spec.arg_types().size()); + for (const auto& arg : spec.arg_types()) { + kinds.push_back(TypeSpecToKind(arg)); + } + return kinds; +} + } // namespace cel diff --git a/common/function_descriptor.h b/common/function_descriptor.h index 1c97bdcca..2f3b6ffc8 100644 --- a/common/function_descriptor.h +++ b/common/function_descriptor.h @@ -19,8 +19,10 @@ #include #include +#include "absl/base/attributes.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" +#include "common/ast.h" #include "common/kind.h" namespace cel { @@ -42,8 +44,28 @@ struct FunctionDescriptorOptions { // Coarsely describes a function for the purpose of runtime resolution of // overloads. -class FunctionDescriptor final { +class FunctionDescriptor { public: + // Creates a FunctionDescriptor for a global function. + [[nodiscard]] + static FunctionDescriptor Global(absl::string_view name, + absl::string_view overload_id, + const FunctionTypeSpec& type, + FunctionDescriptorOptions options = {}) { + return FunctionDescriptor(name, overload_id, type, options, + /*is_receiver_style=*/false); + } + + // Creates a FunctionDescriptor for a member function. + [[nodiscard]] + static FunctionDescriptor Member(absl::string_view name, + absl::string_view overload_id, + const FunctionTypeSpec& type, + FunctionDescriptorOptions options = {}) { + return FunctionDescriptor(name, overload_id, type, options, + /*is_receiver_style=*/true); + } + FunctionDescriptor(const FunctionDescriptor&) = default; FunctionDescriptor(FunctionDescriptor&&) = default; FunctionDescriptor& operator=(const FunctionDescriptor&) = default; @@ -67,20 +89,26 @@ class FunctionDescriptor final { std::vector types, FunctionDescriptorOptions options = {}) : name_(name), - types_(std::move(types)), + kinds_(std::move(types)), is_receiver_style_(is_receiver_style), options_(std::move(options)) {} // Function name. const std::string& name() const { return name_; } + // Function overload ID. This may be empty for legacy code. + [[nodiscard]] + absl::string_view overload_id() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return overload_id_; + } + // Whether function is receiver style i.e. true means arg0.name(args[1:]...). bool receiver_style() const { return is_receiver_style_; } // The argument types the function accepts. // // TODO(uncreated-issue/17): make this kinds - const std::vector& types() const { return types_; } + const std::vector& types() const { return kinds_; } // if true (strict, default), error or unknown arguments are propagated // instead of calling the function. if false (non-strict), the function may @@ -108,8 +136,22 @@ class FunctionDescriptor final { bool operator<(const FunctionDescriptor& other) const; private: + [[nodiscard]] + static std::vector FunctionTypeSpecToArgumentKinds( + const FunctionTypeSpec& spec); + + FunctionDescriptor(absl::string_view name, absl::string_view overload_id, + const FunctionTypeSpec& type, + FunctionDescriptorOptions options, bool is_receiver_style) + : name_(name), + overload_id_(overload_id), + kinds_(FunctionTypeSpecToArgumentKinds(type)), + is_receiver_style_(is_receiver_style), + options_(std::move(options)) {} + std::string name_; - std::vector types_; + std::string overload_id_; + std::vector kinds_; bool is_receiver_style_; FunctionDescriptorOptions options_; };