Skip to content

Commit 037e0bb

Browse files
maskri17copybara-github
authored andcommitted
Adding a TypeSpec to Type resolver.
PiperOrigin-RevId: 915029748
1 parent 352666f commit 037e0bb

4 files changed

Lines changed: 508 additions & 0 deletions

File tree

common/BUILD

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,38 @@ cc_test(
4646
],
4747
)
4848

49+
cc_library(
50+
name = "type_spec_resolver",
51+
srcs = ["type_spec_resolver.cc"],
52+
hdrs = ["type_spec_resolver.h"],
53+
deps = [
54+
":ast",
55+
":type",
56+
"//internal:status_macros",
57+
"@com_google_absl//absl/status",
58+
"@com_google_absl//absl/status:statusor",
59+
"@com_google_absl//absl/strings",
60+
"@com_google_protobuf//:protobuf",
61+
],
62+
)
63+
64+
cc_test(
65+
name = "type_spec_resolver_test",
66+
srcs = ["type_spec_resolver_test.cc"],
67+
deps = [
68+
":ast",
69+
":type",
70+
":type_kind",
71+
":type_spec_resolver",
72+
"//internal:testing",
73+
"//internal:testing_descriptor_pool",
74+
"@com_google_absl//absl/base:no_destructor",
75+
"@com_google_absl//absl/status",
76+
"@com_google_absl//absl/status:status_matchers",
77+
"@com_google_protobuf//:protobuf",
78+
],
79+
)
80+
4981
cc_library(
5082
name = "expr",
5183
srcs = ["expr.cc"],

common/type_spec_resolver.cc

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "common/type_spec_resolver.h"
16+
17+
#include <string>
18+
#include <utility>
19+
#include <vector>
20+
21+
#include "absl/status/status.h"
22+
#include "absl/status/statusor.h"
23+
#include "absl/strings/str_cat.h"
24+
#include "absl/strings/string_view.h"
25+
#include "common/type.h"
26+
#include "internal/status_macros.h"
27+
28+
namespace cel {
29+
30+
absl::StatusOr<Type> ConvertTypeSpecToType(const TypeSpec& type_spec,
31+
google::protobuf::Arena* arena,
32+
const google::protobuf::DescriptorPool& pool) {
33+
if (type_spec.has_null()) return Type(NullType{});
34+
if (type_spec.has_dyn()) return Type(DynType{});
35+
36+
if (type_spec.has_primitive()) {
37+
switch (type_spec.primitive()) {
38+
case PrimitiveType::kBool:
39+
return Type(BoolType{});
40+
case PrimitiveType::kInt64:
41+
return Type(IntType{});
42+
case PrimitiveType::kUint64:
43+
return Type(UintType{});
44+
case PrimitiveType::kDouble:
45+
return Type(DoubleType{});
46+
case PrimitiveType::kString:
47+
return Type(StringType{});
48+
case PrimitiveType::kBytes:
49+
return Type(BytesType{});
50+
default:
51+
return absl::InvalidArgumentError("Unsupported primitive type");
52+
}
53+
}
54+
55+
if (type_spec.has_well_known()) {
56+
switch (type_spec.well_known()) {
57+
case WellKnownTypeSpec::kAny:
58+
return Type(AnyType{});
59+
case WellKnownTypeSpec::kTimestamp:
60+
return Type(TimestampType{});
61+
case WellKnownTypeSpec::kDuration:
62+
return Type(DurationType{});
63+
default:
64+
return absl::InvalidArgumentError("Unsupported well-known type");
65+
}
66+
}
67+
68+
if (type_spec.has_wrapper()) {
69+
switch (type_spec.wrapper()) {
70+
case PrimitiveType::kBool:
71+
return Type(BoolWrapperType{});
72+
case PrimitiveType::kInt64:
73+
return Type(IntWrapperType{});
74+
case PrimitiveType::kUint64:
75+
return Type(UintWrapperType{});
76+
case PrimitiveType::kDouble:
77+
return Type(DoubleWrapperType{});
78+
case PrimitiveType::kString:
79+
return Type(StringWrapperType{});
80+
case PrimitiveType::kBytes:
81+
return Type(BytesWrapperType{});
82+
default:
83+
return absl::InvalidArgumentError("Unsupported wrapper type");
84+
}
85+
}
86+
87+
if (type_spec.has_list_type()) {
88+
CEL_ASSIGN_OR_RETURN(
89+
auto elem_type,
90+
ConvertTypeSpecToType(type_spec.list_type().elem_type(), arena, pool));
91+
return Type(ListType(arena, elem_type));
92+
}
93+
94+
if (type_spec.has_map_type()) {
95+
CEL_ASSIGN_OR_RETURN(
96+
auto key_type,
97+
ConvertTypeSpecToType(type_spec.map_type().key_type(), arena, pool));
98+
CEL_ASSIGN_OR_RETURN(
99+
auto value_type,
100+
ConvertTypeSpecToType(type_spec.map_type().value_type(), arena, pool));
101+
return Type(MapType(arena, key_type, value_type));
102+
}
103+
104+
if (type_spec.has_function()) {
105+
const auto& func_spec = type_spec.function();
106+
CEL_ASSIGN_OR_RETURN(
107+
auto result_type,
108+
ConvertTypeSpecToType(func_spec.result_type(), arena, pool));
109+
std::vector<Type> arg_types;
110+
for (const auto& arg_spec : func_spec.arg_types()) {
111+
CEL_ASSIGN_OR_RETURN(auto arg_type,
112+
ConvertTypeSpecToType(arg_spec, arena, pool));
113+
arg_types.push_back(std::move(arg_type));
114+
}
115+
return Type(FunctionType(arena, result_type, arg_types));
116+
}
117+
118+
if (type_spec.has_type_param()) {
119+
const std::string& name = type_spec.type_param().type();
120+
auto* allocated_name = google::protobuf::Arena::Create<std::string>(arena, name);
121+
return Type(TypeParamType(absl::string_view(*allocated_name)));
122+
}
123+
124+
if (type_spec.has_message_type()) {
125+
const std::string& name = type_spec.message_type().type();
126+
const google::protobuf::Descriptor* descriptor = pool.FindMessageTypeByName(name);
127+
if (descriptor == nullptr) {
128+
return absl::InvalidArgumentError(absl::StrCat(
129+
"Message type '", name, "' not found in descriptor pool"));
130+
}
131+
return Type::Message(descriptor);
132+
}
133+
134+
if (type_spec.has_abstract_type()) {
135+
const std::string& name = type_spec.abstract_type().name();
136+
137+
// Check if it's a message type in the pool
138+
const google::protobuf::Descriptor* descriptor = pool.FindMessageTypeByName(name);
139+
if (descriptor != nullptr) {
140+
if (!type_spec.abstract_type().parameter_types().empty()) {
141+
return absl::InvalidArgumentError(absl::StrCat(
142+
"Message type '", name, "' cannot have type parameters"));
143+
}
144+
return Type::Message(descriptor);
145+
}
146+
147+
// Check if it's an enum type in the pool
148+
const google::protobuf::EnumDescriptor* enum_descriptor =
149+
pool.FindEnumTypeByName(name);
150+
if (enum_descriptor != nullptr) {
151+
if (!type_spec.abstract_type().parameter_types().empty()) {
152+
return absl::InvalidArgumentError(
153+
absl::StrCat("Enum type '", name, "' cannot have type parameters"));
154+
}
155+
return Type::Enum(enum_descriptor);
156+
}
157+
158+
// Otherwise fallback to OpaqueType
159+
std::vector<Type> params;
160+
for (const auto& param_spec : type_spec.abstract_type().parameter_types()) {
161+
CEL_ASSIGN_OR_RETURN(auto param,
162+
ConvertTypeSpecToType(param_spec, arena, pool));
163+
params.push_back(std::move(param));
164+
}
165+
auto* allocated_name = google::protobuf::Arena::Create<std::string>(arena, name);
166+
return Type(OpaqueType(arena, absl::string_view(*allocated_name), params));
167+
}
168+
169+
if (type_spec.has_type()) {
170+
CEL_ASSIGN_OR_RETURN(auto contained_type,
171+
ConvertTypeSpecToType(type_spec.type(), arena, pool));
172+
return Type(TypeType(arena, contained_type));
173+
}
174+
175+
if (type_spec.has_error()) {
176+
return Type(ErrorType{});
177+
}
178+
179+
return absl::InvalidArgumentError("Unknown TypeSpec kind");
180+
}
181+
182+
} // namespace cel

common/type_spec_resolver.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef THIRD_PARTY_CEL_CPP_COMMON_TYPE_SPEC_RESOLVER_H_
16+
#define THIRD_PARTY_CEL_CPP_COMMON_TYPE_SPEC_RESOLVER_H_
17+
18+
#include "absl/status/statusor.h"
19+
#include "common/ast.h"
20+
#include "common/type.h"
21+
#include "google/protobuf/arena.h"
22+
#include "google/protobuf/descriptor.h"
23+
24+
namespace cel {
25+
26+
// Resolves a `cel::TypeSpec` to a `cel::Type`.
27+
//
28+
// TypeSpec only specifies a type while Type provides support for inspecting
29+
// properties of the type when used in CEL. Returns a status with code
30+
// `InvalidArgument` if the input cannot be resolved to a type.
31+
absl::StatusOr<Type> ConvertTypeSpecToType(const TypeSpec& type_spec,
32+
google::protobuf::Arena* arena,
33+
const google::protobuf::DescriptorPool& pool);
34+
35+
} // namespace cel
36+
37+
#endif // THIRD_PARTY_CEL_CPP_COMMON_TYPE_SPEC_RESOLVER_H_

0 commit comments

Comments
 (0)