Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1172681

Browse filesBrowse files
jnthntatumcopybara-github
authored andcommitted
Add declarations for string extension functions.
PiperOrigin-RevId: 694282924
1 parent c4f9b58 commit 1172681
Copy full SHA for 1172681

File tree

Expand file treeCollapse file tree

6 files changed

+206
-1
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+206
-1
lines changed

‎conformance/BUILD

Copy file name to clipboardExpand all lines: conformance/BUILD
-1Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,6 @@ gen_conformance_tests(
318318
modern = True,
319319
skip_tests = _TESTS_TO_SKIP_MODERN + [
320320
# TODO: Need to add function declarations for these extensions.
321-
"string_ext",
322321
"math_ext",
323322
"encoders_ext",
324323
# block is a post-check optimization that inserts internal variables. The C++ type checker

‎conformance/service.cc

Copy file name to clipboardExpand all lines: conformance/service.cc
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,8 @@ class ModernConformanceServiceImpl : public ConformanceServiceInterface {
640640
if (!request.no_std_env()) {
641641
CEL_RETURN_IF_ERROR(builder.AddLibrary(cel::StandardCheckerLibrary()));
642642
CEL_RETURN_IF_ERROR(builder.AddLibrary(cel::OptionalCheckerLibrary()));
643+
CEL_RETURN_IF_ERROR(
644+
builder.AddLibrary(cel::extensions::StringsCheckerLibrary()));
643645
}
644646

645647
for (const auto& decl : request.type_env()) {

‎extensions/BUILD

Copy file name to clipboardExpand all lines: extensions/BUILD
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,10 @@ cc_library(
329329
srcs = ["strings.cc"],
330330
hdrs = ["strings.h"],
331331
deps = [
332+
"//checker:type_checker_builder",
333+
"//checker/internal:builtins_arena",
332334
"//common:casting",
335+
"//common:decl",
333336
"//common:type",
334337
"//common:value",
335338
"//eval/public:cel_function_registry",
@@ -340,6 +343,7 @@ cc_library(
340343
"//runtime:function_registry",
341344
"//runtime:runtime_options",
342345
"//runtime/internal:errors",
346+
"@com_google_absl//absl/base:no_destructor",
343347
"@com_google_absl//absl/status",
344348
"@com_google_absl//absl/status:statusor",
345349
"@com_google_absl//absl/strings",
@@ -353,7 +357,12 @@ cc_test(
353357
srcs = ["strings_test.cc"],
354358
deps = [
355359
":strings",
360+
"//checker:standard_library",
361+
"//checker:type_checker_builder",
362+
"//checker:validation_result",
363+
"//common:decl",
356364
"//common:value",
365+
"//compiler:compiler_factory",
357366
"//extensions/protobuf:runtime_adapter",
358367
"//internal:testing",
359368
"//internal:testing_descriptor_pool",
@@ -364,6 +373,7 @@ cc_test(
364373
"//runtime:runtime_builder",
365374
"//runtime:runtime_options",
366375
"//runtime:standard_runtime_builder_factory",
376+
"//testutil:baseline_tests",
367377
"@com_google_absl//absl/status:status_matchers",
368378
"@com_google_absl//absl/strings:cord",
369379
"@com_google_cel_spec//proto/cel/expr:syntax_cc_proto",

‎extensions/strings.cc

Copy file name to clipboardExpand all lines: extensions/strings.cc
+119Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121
#include <tuple>
2222
#include <utility>
2323

24+
#include "absl/base/no_destructor.h"
2425
#include "absl/status/status.h"
2526
#include "absl/status/statusor.h"
2627
#include "absl/strings/ascii.h"
2728
#include "absl/strings/cord.h"
2829
#include "absl/strings/string_view.h"
30+
#include "checker/internal/builtins_arena.h"
31+
#include "checker/type_checker_builder.h"
2932
#include "common/casting.h"
33+
#include "common/decl.h"
3034
#include "common/type.h"
3135
#include "common/value.h"
3236
#include "common/value_manager.h"
@@ -43,6 +47,8 @@ namespace cel::extensions {
4347

4448
namespace {
4549

50+
using ::cel::checker_internal::BuiltinsArena;
51+
4652
struct AppendToStringVisitor {
4753
std::string& append_to;
4854

@@ -261,6 +267,115 @@ absl::StatusOr<Value> Replace1(ValueManager& value_manager,
261267
return Replace2(value_manager, string, old_sub, new_sub, -1);
262268
}
263269

270+
const Type& ListStringType() {
271+
static absl::NoDestructor<Type> kInstance(
272+
ListType(BuiltinsArena(), StringType()));
273+
return *kInstance;
274+
}
275+
276+
absl::Status RegisterStringsDecls(TypeCheckerBuilder& builder) {
277+
// Runtime Supported functions.
278+
CEL_ASSIGN_OR_RETURN(
279+
auto join_decl,
280+
MakeFunctionDecl(
281+
"join",
282+
MakeMemberOverloadDecl("list_join", StringType(), ListStringType()),
283+
MakeMemberOverloadDecl("list_join_string", StringType(),
284+
ListStringType(), StringType())));
285+
CEL_ASSIGN_OR_RETURN(
286+
auto split_decl,
287+
MakeFunctionDecl(
288+
"split",
289+
MakeMemberOverloadDecl("string_split_string", ListStringType(),
290+
StringType(), StringType()),
291+
MakeMemberOverloadDecl("string_split_string_int", ListStringType(),
292+
StringType(), StringType(), IntType())));
293+
CEL_ASSIGN_OR_RETURN(
294+
auto lower_decl,
295+
MakeFunctionDecl("lowerAscii",
296+
MakeMemberOverloadDecl("string_lower_ascii",
297+
StringType(), StringType())));
298+
299+
CEL_ASSIGN_OR_RETURN(
300+
auto replace_decl,
301+
MakeFunctionDecl(
302+
"replace",
303+
MakeMemberOverloadDecl("string_replace_string_string", StringType(),
304+
StringType(), StringType(), StringType()),
305+
MakeMemberOverloadDecl("string_replace_string_string_int",
306+
StringType(), StringType(), StringType(),
307+
StringType(), IntType())));
308+
309+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(join_decl)));
310+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(split_decl)));
311+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(lower_decl)));
312+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(replace_decl)));
313+
314+
// Additional functions described in the spec.
315+
CEL_ASSIGN_OR_RETURN(
316+
auto char_at_decl,
317+
MakeFunctionDecl(
318+
"charAt", MakeMemberOverloadDecl("string_char_at_int", StringType(),
319+
StringType(), IntType())));
320+
CEL_ASSIGN_OR_RETURN(
321+
auto index_of_decl,
322+
MakeFunctionDecl(
323+
"indexOf",
324+
MakeMemberOverloadDecl("string_index_of_string", IntType(),
325+
StringType(), StringType()),
326+
MakeMemberOverloadDecl("string_index_of_string_int", IntType(),
327+
StringType(), StringType(), IntType())));
328+
CEL_ASSIGN_OR_RETURN(
329+
auto last_index_of_decl,
330+
MakeFunctionDecl(
331+
"lastIndexOf",
332+
MakeMemberOverloadDecl("string_last_index_of_string", IntType(),
333+
StringType(), StringType()),
334+
MakeMemberOverloadDecl("string_last_index_of_string_int", IntType(),
335+
StringType(), StringType(), IntType())));
336+
337+
CEL_ASSIGN_OR_RETURN(
338+
auto substring_decl,
339+
MakeFunctionDecl(
340+
"substring",
341+
MakeMemberOverloadDecl("string_substring_int", StringType(),
342+
StringType(), IntType()),
343+
MakeMemberOverloadDecl("string_substring_int_int", StringType(),
344+
StringType(), IntType(), IntType())));
345+
CEL_ASSIGN_OR_RETURN(
346+
auto upper_ascii_decl,
347+
MakeFunctionDecl("upperAscii",
348+
MakeMemberOverloadDecl("string_upper_ascii",
349+
StringType(), StringType())));
350+
CEL_ASSIGN_OR_RETURN(
351+
auto format_decl,
352+
MakeFunctionDecl("format",
353+
MakeMemberOverloadDecl("string_format", StringType(),
354+
StringType(), ListType())));
355+
CEL_ASSIGN_OR_RETURN(
356+
auto quote_decl,
357+
MakeFunctionDecl(
358+
"strings.quote",
359+
MakeOverloadDecl("strings_quote", StringType(), StringType())));
360+
361+
CEL_ASSIGN_OR_RETURN(
362+
auto reverse_decl,
363+
MakeFunctionDecl("reverse",
364+
MakeMemberOverloadDecl("string_reverse", StringType(),
365+
StringType())));
366+
367+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(char_at_decl)));
368+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(index_of_decl)));
369+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(last_index_of_decl)));
370+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(substring_decl)));
371+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(upper_ascii_decl)));
372+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(format_decl)));
373+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(quote_decl)));
374+
CEL_RETURN_IF_ERROR(builder.AddFunction(std::move(reverse_decl)));
375+
376+
return absl::OkStatus();
377+
}
378+
264379
} // namespace
265380

266381
absl::Status RegisterStringsFunctions(FunctionRegistry& registry,
@@ -314,4 +429,8 @@ absl::Status RegisterStringsFunctions(
314429
google::api::expr::runtime::ConvertToRuntimeOptions(options));
315430
}
316431

432+
CheckerLibrary StringsCheckerLibrary() {
433+
return {"strings", &RegisterStringsDecls};
434+
}
435+
317436
} // namespace cel::extensions

‎extensions/strings.h

Copy file name to clipboardExpand all lines: extensions/strings.h
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define THIRD_PARTY_CEL_CPP_EXTENSIONS_STRINGS_H_
1717

1818
#include "absl/status/status.h"
19+
#include "checker/type_checker_builder.h"
1920
#include "eval/public/cel_function_registry.h"
2021
#include "eval/public/cel_options.h"
2122
#include "runtime/function_registry.h"
@@ -31,6 +32,8 @@ absl::Status RegisterStringsFunctions(
3132
google::api::expr::runtime::CelFunctionRegistry* registry,
3233
const google::api::expr::runtime::InterpreterOptions& options);
3334

35+
CheckerLibrary StringsCheckerLibrary();
36+
3437
} // namespace cel::extensions
3538

3639
#endif // THIRD_PARTY_CEL_CPP_EXTENSIONS_STRINGS_H_

‎extensions/strings_test.cc

Copy file name to clipboardExpand all lines: extensions/strings_test.cc
+72Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@
2020
#include "cel/expr/syntax.pb.h"
2121
#include "absl/status/status_matchers.h"
2222
#include "absl/strings/cord.h"
23+
#include "checker/standard_library.h"
24+
#include "checker/type_checker_builder.h"
25+
#include "checker/validation_result.h"
26+
#include "common/decl.h"
2327
#include "common/value.h"
28+
#include "compiler/compiler_factory.h"
2429
#include "extensions/protobuf/runtime_adapter.h"
2530
#include "internal/testing.h"
2631
#include "internal/testing_descriptor_pool.h"
@@ -31,6 +36,7 @@
3136
#include "runtime/runtime_builder.h"
3237
#include "runtime/runtime_options.h"
3338
#include "runtime/standard_runtime_builder_factory.h"
39+
#include "testutil/baseline_tests.h"
3440
#include "google/protobuf/arena.h"
3541

3642
namespace cel::extensions {
@@ -40,6 +46,7 @@ using ::absl_testing::IsOk;
4046
using ::cel::expr::ParsedExpr;
4147
using ::google::api::expr::parser::Parse;
4248
using ::google::api::expr::parser::ParserOptions;
49+
using ::testing::Values;
4350

4451
TEST(Strings, SplitWithEmptyDelimiterCord) {
4552
google::protobuf::Arena arena;
@@ -173,5 +180,70 @@ TEST(Strings, ReplaceWithZeroLimit) {
173180
EXPECT_TRUE(result.GetBool().NativeValue());
174181
}
175182

183+
TEST(StringsCheckerLibrary, SmokeTest) {
184+
google::protobuf::Arena arena;
185+
ASSERT_OK_AND_ASSIGN(
186+
auto builder, NewCompilerBuilder(internal::GetTestingDescriptorPool()));
187+
ASSERT_THAT(builder->AddLibrary(StringsCheckerLibrary()), IsOk());
188+
ASSERT_THAT(builder->AddLibrary(StandardCheckerLibrary()), IsOk());
189+
ASSERT_THAT(builder->GetCheckerBuilder().AddVariable(
190+
MakeVariableDecl("foo", StringType())),
191+
IsOk());
192+
193+
ASSERT_OK_AND_ASSIGN(auto compiler, std::move(*builder).Build());
194+
195+
ASSERT_OK_AND_ASSIGN(
196+
ValidationResult result,
197+
compiler->Compile("foo.replace('he', 'we', 1) == 'wello hello'"));
198+
ASSERT_TRUE(result.IsValid());
199+
200+
EXPECT_EQ(test::FormatBaselineAst(*result.GetAst()),
201+
R"(_==_(
202+
foo~string^foo.replace(
203+
"he"~string,
204+
"we"~string,
205+
1~int
206+
)~string^string_replace_string_string_int,
207+
"wello hello"~string
208+
)~bool^equals)");
209+
}
210+
211+
// Basic test for the included declarations.
212+
// Additional coverage for behavior in the spec tests.
213+
class StringsCheckerLibraryTest : public ::testing::TestWithParam<std::string> {
214+
};
215+
216+
TEST_P(StringsCheckerLibraryTest, TypeChecks) {
217+
const std::string& expr = GetParam();
218+
google::protobuf::Arena arena;
219+
ASSERT_OK_AND_ASSIGN(
220+
auto builder, NewCompilerBuilder(internal::GetTestingDescriptorPool()));
221+
ASSERT_THAT(builder->AddLibrary(StringsCheckerLibrary()), IsOk());
222+
ASSERT_THAT(builder->AddLibrary(StandardCheckerLibrary()), IsOk());
223+
224+
ASSERT_OK_AND_ASSIGN(auto compiler, std::move(*builder).Build());
225+
226+
ASSERT_OK_AND_ASSIGN(ValidationResult result, compiler->Compile(expr));
227+
EXPECT_TRUE(result.IsValid()) << "Failed to compile: " << expr;
228+
}
229+
230+
INSTANTIATE_TEST_SUITE_P(
231+
Expressions, StringsCheckerLibraryTest,
232+
Values("['a', 'b', 'c'].join() == 'abc'",
233+
"['a', 'b', 'c'].join('|') == 'a|b|c'",
234+
"'a|b|c'.split('|') == ['a', 'b', 'c']",
235+
"'a|b|c'.split('|', 1) == ['a', 'b|c']",
236+
"'a|b|c'.split('|') == ['a', 'b', 'c']",
237+
"'AbC'.lowerAscii() == 'abc'",
238+
"'tacocat'.replace('cat', 'dog') == 'tacodog'",
239+
"'tacocat'.replace('aco', 'an', 2) == 'tacocat'",
240+
"'tacocat'.charAt(2) == 'c'", "'tacocat'.indexOf('c') == 2",
241+
"'tacocat'.indexOf('c', 3) == 4", "'tacocat'.lastIndexOf('c') == 4",
242+
"'tacocat'.lastIndexOf('c', 5) == -1",
243+
"'tacocat'.substring(1) == 'acocat'",
244+
"'tacocat'.substring(1, 3) == 'aco'", "'aBc'.upperAscii() == 'ABC'",
245+
"'abc %d'.format([2]) == 'abc 2'",
246+
"strings.quote('abc') == \"'abc 2'\"", "'abc'.reverse() == 'cba'"));
247+
176248
} // namespace
177249
} // namespace cel::extensions

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.