Skip to content

Commit bb0a7c4

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Refactor type signature generation to use TypeSpec.
Refactors the internal signature generation logic to operate on `cel::TypeSpec` instead of `cel::Type`. Adds a utility to convert `cel::Type` to `cel::TypeSpec` PiperOrigin-RevId: 924976939
1 parent dd4f368 commit bb0a7c4

9 files changed

Lines changed: 424 additions & 223 deletions

File tree

common/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ cc_library(
5353
deps = [
5454
":ast",
5555
":type",
56+
":type_kind",
5657
"//internal:status_macros",
5758
"@com_google_absl//absl/status",
5859
"@com_google_absl//absl/status:statusor",

common/ast/metadata.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,10 @@ class TypeSpec {
573573

574574
TypeSpecKind& mutable_type_kind() { return type_kind_; }
575575

576+
bool is_specified() const {
577+
return !absl::holds_alternative<UnsetTypeSpec>(type_kind_);
578+
}
579+
576580
bool has_dyn() const {
577581
return absl::holds_alternative<DynTypeSpec>(type_kind_);
578582
}

common/internal/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ cc_test(
165165
"//common:ast",
166166
"//common:type",
167167
"//common:type_kind",
168+
"//common:type_spec_resolver",
168169
"//internal:testing",
169170
"//internal:testing_descriptor_pool",
170171
"@com_google_absl//absl/base:no_destructor",

common/internal/signature.cc

Lines changed: 158 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -64,139 +64,180 @@ void AppendEscaped(std::string* result, std::string_view str, bool escape_dot) {
6464
}
6565
}
6666

67-
absl::Status AppendTypeParameters(std::string* result, const Type& type);
67+
absl::Status AppendTypeDesc(std::string* result, const TypeSpec& type_spec);
6868

69-
// Recursively appends a string representation of the given `type` to `result`.
70-
// Type parameters are enclosed in angle brackets and separated by commas.
71-
//
72-
// Grammar:
73-
// TypeDesc = NamespaceIdentifier [ "<" TypeList ">" ] ;
74-
// NamespaceIdentifier = [ "." ] Identifier { "." Identifier } ;
75-
// TypeList = TypeElem { "," TypeElem } ;
76-
// TypeElem = TypeDesc | TypeParam
77-
// TypeParam = "~" Alpha ;
78-
// Identifier = ( Alpha | "_" ) { AlphaNumeric | "_" } ;
79-
// (* Terminals *)
80-
// Alpha = "a"..."z" | "A"..."Z" ;
81-
// Digit = "0"..."9" ;
82-
// AlphaNumeric = Alpha | Digit ;
83-
//
84-
// For compatibility, the implementation allows unexpected characters in
85-
// type names and parameters and escapes them with a backslash.
86-
absl::Status AppendTypeDesc(std::string* result, const Type& type) {
87-
switch (type.kind()) {
88-
case TypeKind::kNull:
89-
absl::StrAppend(result, "null");
90-
break;
91-
case TypeKind::kBool:
92-
absl::StrAppend(result, "bool");
93-
break;
94-
case TypeKind::kInt:
95-
absl::StrAppend(result, "int");
96-
break;
97-
case TypeKind::kUint:
98-
absl::StrAppend(result, "uint");
99-
break;
100-
case TypeKind::kDouble:
101-
absl::StrAppend(result, "double");
102-
break;
103-
case TypeKind::kString:
104-
absl::StrAppend(result, "string");
105-
break;
106-
case TypeKind::kBytes:
107-
absl::StrAppend(result, "bytes");
108-
break;
109-
case TypeKind::kDuration:
110-
absl::StrAppend(result, "duration");
111-
break;
112-
case TypeKind::kTimestamp:
113-
absl::StrAppend(result, "timestamp");
114-
break;
115-
case TypeKind::kAny:
116-
absl::StrAppend(result, "any");
117-
break;
118-
case TypeKind::kDyn:
119-
absl::StrAppend(result, "dyn");
120-
break;
121-
case TypeKind::kBoolWrapper:
122-
absl::StrAppend(result, "bool_wrapper");
123-
break;
124-
case TypeKind::kIntWrapper:
125-
absl::StrAppend(result, "int_wrapper");
126-
break;
127-
case TypeKind::kUintWrapper:
128-
absl::StrAppend(result, "uint_wrapper");
129-
break;
130-
case TypeKind::kDoubleWrapper:
131-
absl::StrAppend(result, "double_wrapper");
132-
break;
133-
case TypeKind::kStringWrapper:
134-
absl::StrAppend(result, "string_wrapper");
135-
break;
136-
case TypeKind::kBytesWrapper:
137-
absl::StrAppend(result, "bytes_wrapper");
138-
break;
139-
case TypeKind::kList:
140-
absl::StrAppend(result, "list");
141-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
142-
break;
143-
case TypeKind::kMap:
144-
absl::StrAppend(result, "map");
145-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
146-
break;
147-
case TypeKind::kFunction:
148-
absl::StrAppend(result, "function");
149-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
150-
break;
151-
case TypeKind::kType:
152-
absl::StrAppend(result, "type");
153-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
154-
break;
155-
case TypeKind::kTypeParam:
156-
absl::StrAppend(result, "~");
157-
AppendEscaped(result, type.GetTypeParam().name(), /*escape_dot=*/true);
158-
break;
159-
case TypeKind::kOpaque:
160-
AppendEscaped(result, type.name(), /*escape_dot=*/false);
161-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
162-
break;
163-
case TypeKind::kStruct:
164-
AppendEscaped(result, type.name(), /*escape_dot=*/false);
165-
CEL_RETURN_IF_ERROR(AppendTypeParameters(result, type));
166-
break;
167-
default:
168-
return absl::InvalidArgumentError(
169-
absl::StrFormat("Type kind: %s is not supported in CEL declarations",
170-
type.DebugString()));
69+
absl::Status AppendTypeSpecList(std::string* result,
70+
const std::vector<TypeSpec>& params) {
71+
if (!params.empty()) {
72+
result->push_back('<');
73+
for (size_t i = 0; i < params.size(); ++i) {
74+
CEL_RETURN_IF_ERROR(AppendTypeDesc(result, params[i]));
75+
if (i < params.size() - 1) {
76+
result->push_back(',');
77+
}
78+
}
79+
result->push_back('>');
17180
}
17281
return absl::OkStatus();
17382
}
17483

175-
absl::Status AppendTypeParameters(std::string* result, const Type& type) {
176-
const auto& parameters = type.GetParameters();
177-
if (!parameters.empty()) {
178-
result->push_back('<');
179-
for (size_t i = 0; i < parameters.size(); ++i) {
180-
CEL_RETURN_IF_ERROR(AppendTypeDesc(result, parameters[i]));
181-
if (i < parameters.size() - 1) {
84+
absl::Status AppendTypeDesc(std::string* result, const TypeSpec& type_spec) {
85+
if (type_spec.has_null()) {
86+
absl::StrAppend(result, "null");
87+
} else if (type_spec.has_dyn()) {
88+
absl::StrAppend(result, "dyn");
89+
} else if (type_spec.has_primitive()) {
90+
switch (type_spec.primitive()) {
91+
case PrimitiveType::kBool:
92+
absl::StrAppend(result, "bool");
93+
break;
94+
case PrimitiveType::kInt64:
95+
absl::StrAppend(result, "int");
96+
break;
97+
case PrimitiveType::kUint64:
98+
absl::StrAppend(result, "uint");
99+
break;
100+
case PrimitiveType::kDouble:
101+
absl::StrAppend(result, "double");
102+
break;
103+
case PrimitiveType::kString:
104+
absl::StrAppend(result, "string");
105+
break;
106+
case PrimitiveType::kBytes:
107+
absl::StrAppend(result, "bytes");
108+
break;
109+
default:
110+
return absl::InvalidArgumentError("Unsupported primitive type");
111+
}
112+
} else if (type_spec.has_well_known()) {
113+
switch (type_spec.well_known()) {
114+
case WellKnownTypeSpec::kAny:
115+
absl::StrAppend(result, "any");
116+
break;
117+
case WellKnownTypeSpec::kTimestamp:
118+
absl::StrAppend(result, "timestamp");
119+
break;
120+
case WellKnownTypeSpec::kDuration:
121+
absl::StrAppend(result, "duration");
122+
break;
123+
default:
124+
return absl::InvalidArgumentError("Unsupported well-known type");
125+
}
126+
} else if (type_spec.has_wrapper()) {
127+
switch (type_spec.wrapper()) {
128+
case PrimitiveType::kBool:
129+
absl::StrAppend(result, "bool_wrapper");
130+
break;
131+
case PrimitiveType::kInt64:
132+
absl::StrAppend(result, "int_wrapper");
133+
break;
134+
case PrimitiveType::kUint64:
135+
absl::StrAppend(result, "uint_wrapper");
136+
break;
137+
case PrimitiveType::kDouble:
138+
absl::StrAppend(result, "double_wrapper");
139+
break;
140+
case PrimitiveType::kString:
141+
absl::StrAppend(result, "string_wrapper");
142+
break;
143+
case PrimitiveType::kBytes:
144+
absl::StrAppend(result, "bytes_wrapper");
145+
break;
146+
default:
147+
return absl::InvalidArgumentError("Unsupported wrapper type");
148+
}
149+
} else if (type_spec.has_list_type()) {
150+
absl::StrAppend(result, "list");
151+
if (type_spec.list_type().has_elem_type()) {
152+
result->push_back('<');
153+
CEL_RETURN_IF_ERROR(
154+
AppendTypeDesc(result, type_spec.list_type().elem_type()));
155+
result->push_back('>');
156+
}
157+
} else if (type_spec.has_map_type()) {
158+
absl::StrAppend(result, "map");
159+
if (type_spec.map_type().has_key_type()) {
160+
result->push_back('<');
161+
CEL_RETURN_IF_ERROR(
162+
AppendTypeDesc(result, type_spec.map_type().key_type()));
163+
result->push_back(',');
164+
if (type_spec.map_type().has_value_type()) {
165+
CEL_RETURN_IF_ERROR(
166+
AppendTypeDesc(result, type_spec.map_type().value_type()));
167+
} else {
168+
absl::StrAppend(result, "dyn");
169+
}
170+
result->push_back('>');
171+
}
172+
} else if (type_spec.has_function()) {
173+
absl::StrAppend(result, "function");
174+
if (type_spec.function().has_result_type() ||
175+
!type_spec.function().arg_types().empty()) {
176+
result->push_back('<');
177+
if (type_spec.function().has_result_type()) {
178+
CEL_RETURN_IF_ERROR(
179+
AppendTypeDesc(result, type_spec.function().result_type()));
180+
} else {
181+
absl::StrAppend(result, "dyn");
182+
}
183+
for (const auto& arg : type_spec.function().arg_types()) {
182184
result->push_back(',');
185+
CEL_RETURN_IF_ERROR(AppendTypeDesc(result, arg));
183186
}
187+
result->push_back('>');
184188
}
189+
} else if (type_spec.has_type()) {
190+
absl::StrAppend(result, "type");
191+
result->push_back('<');
192+
CEL_RETURN_IF_ERROR(AppendTypeDesc(result, type_spec.type()));
185193
result->push_back('>');
194+
} else if (type_spec.has_type_param()) {
195+
absl::StrAppend(result, "~");
196+
AppendEscaped(result, type_spec.type_param().type(), /*escape_dot=*/true);
197+
} else if (type_spec.has_abstract_type()) {
198+
AppendEscaped(result, type_spec.abstract_type().name(),
199+
/*escape_dot=*/false);
200+
CEL_RETURN_IF_ERROR(AppendTypeSpecList(
201+
result, type_spec.abstract_type().parameter_types()));
202+
} else if (type_spec.has_message_type()) {
203+
AppendEscaped(result, type_spec.message_type().type(),
204+
/*escape_dot=*/false);
205+
} else {
206+
return absl::InvalidArgumentError(absl::StrCat(
207+
"Unsupported type in signature: ", FormatTypeSpec(type_spec)));
186208
}
187209
return absl::OkStatus();
188210
}
189211
} // namespace
190212

191213
absl::StatusOr<std::string> MakeTypeSignature(const Type& type) {
192214
std::string result;
193-
CEL_RETURN_IF_ERROR(AppendTypeDesc(&result, type));
215+
CEL_ASSIGN_OR_RETURN(TypeSpec type_spec, ConvertTypeToTypeSpec(type));
216+
CEL_RETURN_IF_ERROR(AppendTypeDesc(&result, type_spec));
217+
return result;
218+
}
219+
220+
absl::StatusOr<std::string> MakeTypeSpecSignature(const TypeSpec& type_spec) {
221+
std::string result;
222+
CEL_RETURN_IF_ERROR(AppendTypeDesc(&result, type_spec));
194223
return result;
195224
}
196225

197226
absl::StatusOr<std::string> MakeOverloadSignature(
198227
std::string_view function_name, const std::vector<Type>& args,
199228
bool is_member) {
229+
std::vector<TypeSpec> arg_type_specs;
230+
arg_type_specs.reserve(args.size());
231+
for (const auto& arg : args) {
232+
CEL_ASSIGN_OR_RETURN(TypeSpec type_spec, ConvertTypeToTypeSpec(arg));
233+
arg_type_specs.push_back(type_spec);
234+
}
235+
return MakeOverloadSignature(function_name, arg_type_specs, is_member);
236+
}
237+
238+
absl::StatusOr<std::string> MakeOverloadSignature(
239+
std::string_view function_name, const std::vector<TypeSpec>& args,
240+
bool is_member) {
200241
std::string result;
201242
if (is_member) {
202243
if (!args.empty()) {
@@ -589,10 +630,14 @@ absl::StatusOr<ParsedFunctionOverload> ParseFunctionSignature(
589630
return out;
590631
}
591632

633+
absl::StatusOr<TypeSpec> ParseTypeSpec(std::string_view signature) {
634+
std::string stripped_sig = StripUnescapedWhitespace(signature);
635+
return ParseTypeSignature(stripped_sig);
636+
}
637+
592638
absl::StatusOr<Type> ParseType(std::string_view signature, google::protobuf::Arena* arena,
593639
const google::protobuf::DescriptorPool& pool) {
594-
std::string stripped_sig = StripUnescapedWhitespace(signature);
595-
CEL_ASSIGN_OR_RETURN(auto type_spec, ParseTypeSignature(stripped_sig));
640+
CEL_ASSIGN_OR_RETURN(auto type_spec, ParseTypeSpec(signature));
596641
return cel::ConvertTypeSpecToType(type_spec, arena, pool);
597642
}
598643

common/internal/signature.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
namespace cel::common_internal {
2929

30-
// Generates an signature for a `cel::Type`, which is a string representation of
30+
// Generates a signature for a `cel::Type`, which is a string representation of
3131
// the type.
3232
//
3333
// Examples:
@@ -37,7 +37,17 @@ namespace cel::common_internal {
3737
// - `list<my_type<~A>>`
3838
absl::StatusOr<std::string> MakeTypeSignature(const Type& type);
3939

40-
// Generates an identifier for a function overload based on the function name
40+
// Generates a signature for a `cel::TypeSpec`, which is a string
41+
// representation of the type.
42+
//
43+
// Examples:
44+
//
45+
// - `int`
46+
// - `list<int>`
47+
// - `list<my_type<~A>>`
48+
absl::StatusOr<std::string> MakeTypeSpecSignature(const TypeSpec& type_spec);
49+
50+
// Generates a signature for a function overload based on the function name
4151
// and the types of the arguments. If `is_member` is true, the first argument
4252
// type is used as the receiver and is prepended to the function name, followed
4353
// by a dollar sign.
@@ -59,6 +69,15 @@ absl::StatusOr<std::string> MakeOverloadSignature(
5969
std::string_view function_name, const std::vector<Type>& args,
6070
bool is_member);
6171

72+
// Generates a signature for a function overload based on the function name
73+
// and the type specs of the arguments. See above for more details.
74+
absl::StatusOr<std::string> MakeOverloadSignature(
75+
std::string_view function_name, const std::vector<TypeSpec>& args,
76+
bool is_member);
77+
78+
// Parses a string type signature directly into a `cel::TypeSpec`.
79+
absl::StatusOr<TypeSpec> ParseTypeSpec(std::string_view signature);
80+
6281
// Parses a string type signature directly into a `cel::Type`.
6382
absl::StatusOr<Type> ParseType(std::string_view signature, google::protobuf::Arena* arena,
6483
const google::protobuf::DescriptorPool& pool);

0 commit comments

Comments
 (0)