Skip to content

Commit 1c2f6df

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
[Pratt Parser] Add an option to enable Pratt Parser
PiperOrigin-RevId: 945370852
1 parent 05556a0 commit 1c2f6df

25 files changed

Lines changed: 5096 additions & 63 deletions

common/expr_factory.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ namespace tools {
3838
class ProtoToPredicateBuilder;
3939
}
4040

41+
namespace parser_internal {
42+
template <typename ExprNode>
43+
class AstFactoryInterface;
44+
}
45+
4146
class ExprFactory {
4247
protected:
4348
// `IsExprLike` determines whether `T` is some `Expr`. Currently that means
@@ -385,6 +390,7 @@ class ExprFactory {
385390
friend class ParserMacroExprFactory;
386391
friend class OptimizerExprFactory;
387392
friend class tools::ProtoToPredicateBuilder;
393+
friend class parser_internal::AstFactoryInterface<Expr>;
388394

389395
ExprFactory() : accu_var_(kAccumulatorVariableName) {}
390396

conformance/BUILD

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ _TESTS_TO_SKIP_LEGACY_DASHBOARD = [
247247
]
248248

249249
# Generates a bunch of `cc_test` whose names follow the pattern
250-
# `conformance_(...)_{arena|refcount}_{optimized|unoptimized}_{recursive|iterative}`.
250+
# `conformance_(...)_{pratt|antlr}_{optimized|unoptimized}_{recursive|iterative}`.
251251
gen_conformance_tests(
252252
name = "conformance_parse_only",
253253
data = _ALL_TESTS,
@@ -316,7 +316,7 @@ gen_conformance_tests(
316316
)
317317

318318
# Generates a bunch of `cc_test` whose names follow the pattern
319-
# `conformance_dashboard_..._{arena|refcount}_{optimized|unoptimized}_{recursive|iterative}`.
319+
# `conformance_dashboard_..._{pratt|antlr}_{optimized|unoptimized}_{recursive|iterative}`.
320320
gen_conformance_tests(
321321
name = "conformance_dashboard_parse_only",
322322
dashboard = True,

conformance/run.bzl

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ def _expand_tests_to_skip(tests_to_skip):
4747
result.append(test_to_skip[0:slash] + part)
4848
return result
4949

50-
def _conformance_test_name(name, optimize, recursive):
50+
def _conformance_test_name(name, pratt, optimize, recursive):
5151
return "_".join(
5252
[
5353
name,
54+
"pratt" if pratt else "antlr",
5455
"optimized" if optimize else "unoptimized",
5556
"recursive" if recursive else "iterative",
5657
],
5758
)
5859

59-
def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators):
60+
def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt):
6061
args = []
6162
if modern:
6263
args.append("--modern")
@@ -74,12 +75,16 @@ def _conformance_test_args(modern, optimize, recursive, select_opt, skip_check,
7475
args.append("--dashboard")
7576
if enable_variadic_logical_operators:
7677
args.append("--enable_variadic_logical_operators")
78+
if pratt:
79+
args.append("--enable_pratt_parser")
80+
else:
81+
args.append("--noenable_pratt_parser")
7782
return args
7883

79-
def _conformance_test(name, data, modern, optimize, recursive, select_opt, skip_check, skip_tests, tags, dashboard, enable_variadic_logical_operators):
84+
def _conformance_test(name, data, modern, optimize, recursive, select_opt, skip_check, skip_tests, tags, dashboard, enable_variadic_logical_operators, pratt):
8085
cc_test(
81-
name = _conformance_test_name(name, optimize, recursive),
82-
args = _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators) + ["$(rlocationpath {})".format(test) for test in data],
86+
name = _conformance_test_name(name, pratt, optimize, recursive),
87+
args = _conformance_test_args(modern, optimize, recursive, select_opt, skip_check, dashboard, enable_variadic_logical_operators, pratt) + ["$(rlocationpath {})".format(test) for test in data],
8388
env = select(
8489
{
8590
"@platforms//os:windows": {"CEL_SKIP_TESTS": ",".join(skip_tests + _TESTS_TO_SKIP_WINDOWS)},
@@ -108,23 +113,25 @@ def gen_conformance_tests(name, data, modern = False, checked = False, select_op
108113
"""
109114
skip_check = not checked
110115
tests = []
111-
for optimize in (True, False):
112-
for recursive in (True, False):
113-
test_name = _conformance_test_name(name, optimize, recursive)
114-
tests.append(test_name)
115-
_conformance_test(
116-
name,
117-
data,
118-
modern = modern,
119-
optimize = optimize,
120-
recursive = recursive,
121-
select_opt = select_opt,
122-
skip_check = skip_check,
123-
skip_tests = _expand_tests_to_skip(skip_tests),
124-
tags = tags,
125-
dashboard = dashboard,
126-
enable_variadic_logical_operators = enable_variadic_logical_operators,
127-
)
116+
for pratt in (True, False):
117+
for optimize in (True, False):
118+
for recursive in (True, False):
119+
test_name = _conformance_test_name(name, pratt, optimize, recursive)
120+
tests.append(test_name)
121+
_conformance_test(
122+
name,
123+
data,
124+
modern = modern,
125+
optimize = optimize,
126+
recursive = recursive,
127+
select_opt = select_opt,
128+
skip_check = skip_check,
129+
skip_tests = _expand_tests_to_skip(skip_tests),
130+
tags = tags,
131+
dashboard = dashboard,
132+
enable_variadic_logical_operators = enable_variadic_logical_operators,
133+
pratt = pratt,
134+
)
128135
native.test_suite(
129136
name = name,
130137
tests = tests,

conformance/run.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ ABSL_FLAG(bool, select_optimization, false, "Enable select optimization.");
6969
ABSL_FLAG(bool, enable_variadic_logical_operators, false,
7070
"Enable parsing logical AND & OR operators as a single flat variadic "
7171
"call.");
72+
ABSL_FLAG(bool, enable_pratt_parser, true,
73+
"Enable manual (Pratt) parser instead of ANTLR parser.");
7274

7375
namespace {
7476

@@ -266,6 +268,7 @@ NewConformanceServiceFromFlags() {
266268
.select_optimization = absl::GetFlag(FLAGS_select_optimization),
267269
.enable_variadic_logical_operators =
268270
absl::GetFlag(FLAGS_enable_variadic_logical_operators),
271+
.enable_pratt_parser = absl::GetFlag(FLAGS_enable_pratt_parser),
269272
});
270273
ABSL_CHECK_OK(status_or_service);
271274
return std::shared_ptr<cel_conformance::ConformanceServiceInterface>(

conformance/service.cc

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,16 @@ cel::expr::Expr ExtractExpr(
129129
absl::Status LegacyParse(const conformance::v1alpha1::ParseRequest& request,
130130
conformance::v1alpha1::ParseResponse& response,
131131
bool enable_optional_syntax,
132-
bool enable_variadic_logical_operators) {
132+
bool enable_variadic_logical_operators,
133+
bool enable_pratt_parser) {
133134
if (request.cel_source().empty()) {
134135
return absl::InvalidArgumentError("no source code");
135136
}
136137
cel::ParserOptions options;
137138
options.enable_optional_syntax = enable_optional_syntax;
138139
options.enable_quoted_identifiers = true;
139140
options.enable_variadic_logical_operators = enable_variadic_logical_operators;
141+
options.enable_pratt_parser = enable_pratt_parser;
140142
cel::MacroRegistry macros;
141143
CEL_RETURN_IF_ERROR(cel::RegisterStandardMacros(macros, options));
142144
CEL_RETURN_IF_ERROR(
@@ -239,7 +241,7 @@ class LegacyConformanceServiceImpl : public ConformanceServiceInterface {
239241
public:
240242
static absl::StatusOr<std::unique_ptr<LegacyConformanceServiceImpl>> Create(
241243
bool optimize, bool recursive, bool select_optimization,
242-
bool enable_variadic_logical_operators) {
244+
bool enable_variadic_logical_operators, bool enable_pratt_parser) {
243245
static auto* constant_arena = new Arena();
244246

245247
google::protobuf::LinkMessageReflection<
@@ -317,14 +319,15 @@ class LegacyConformanceServiceImpl : public ConformanceServiceInterface {
317319
builder->GetRegistry(), options));
318320

319321
return absl::WrapUnique(new LegacyConformanceServiceImpl(
320-
std::move(builder), enable_variadic_logical_operators));
322+
std::move(builder), enable_variadic_logical_operators,
323+
enable_pratt_parser));
321324
}
322325

323326
void Parse(const conformance::v1alpha1::ParseRequest& request,
324327
conformance::v1alpha1::ParseResponse& response) override {
325328
auto status =
326329
LegacyParse(request, response, /*enable_optional_syntax=*/false,
327-
enable_variadic_logical_operators_);
330+
enable_variadic_logical_operators_, enable_pratt_parser_);
328331
if (!status.ok()) {
329332
auto* issue = response.add_issues();
330333
issue->set_code(ToGrpcCode(status.code()));
@@ -423,19 +426,22 @@ class LegacyConformanceServiceImpl : public ConformanceServiceInterface {
423426

424427
private:
425428
LegacyConformanceServiceImpl(std::unique_ptr<CelExpressionBuilder> builder,
426-
bool enable_variadic_logical_operators)
429+
bool enable_variadic_logical_operators,
430+
bool enable_pratt_parser)
427431
: builder_(std::move(builder)),
428-
enable_variadic_logical_operators_(enable_variadic_logical_operators) {}
432+
enable_variadic_logical_operators_(enable_variadic_logical_operators),
433+
enable_pratt_parser_(enable_pratt_parser) {}
429434

430435
std::unique_ptr<CelExpressionBuilder> builder_;
431436
bool enable_variadic_logical_operators_;
437+
bool enable_pratt_parser_;
432438
};
433439

434440
class ModernConformanceServiceImpl : public ConformanceServiceInterface {
435441
public:
436442
static absl::StatusOr<std::unique_ptr<ModernConformanceServiceImpl>> Create(
437443
bool optimize, bool recursive, bool select_optimization,
438-
bool enable_variadic_logical_operators) {
444+
bool enable_variadic_logical_operators, bool enable_pratt_parser) {
439445
google::protobuf::LinkMessageReflection<
440446
cel::expr::conformance::proto3::TestAllTypes>();
441447
google::protobuf::LinkMessageReflection<
@@ -477,9 +483,9 @@ class ModernConformanceServiceImpl : public ConformanceServiceInterface {
477483
options.max_recursion_depth = 48;
478484
}
479485

480-
return absl::WrapUnique(
481-
new ModernConformanceServiceImpl(options, optimize, select_optimization,
482-
enable_variadic_logical_operators));
486+
return absl::WrapUnique(new ModernConformanceServiceImpl(
487+
options, optimize, select_optimization,
488+
enable_variadic_logical_operators, enable_pratt_parser));
483489
}
484490

485491
absl::StatusOr<std::unique_ptr<const cel::Runtime>> Setup(
@@ -532,7 +538,7 @@ class ModernConformanceServiceImpl : public ConformanceServiceInterface {
532538
conformance::v1alpha1::ParseResponse& response) override {
533539
auto status =
534540
LegacyParse(request, response, /*enable_optional_syntax=*/true,
535-
enable_variadic_logical_operators_);
541+
enable_variadic_logical_operators_, enable_pratt_parser_);
536542
if (!status.ok()) {
537543
auto* issue = response.add_issues();
538544
issue->set_code(ToGrpcCode(status.code()));
@@ -624,11 +630,13 @@ class ModernConformanceServiceImpl : public ConformanceServiceInterface {
624630
ModernConformanceServiceImpl(const RuntimeOptions& options,
625631
bool enable_optimizations,
626632
bool enable_select_optimization,
627-
bool enable_variadic_logical_operators)
633+
bool enable_variadic_logical_operators,
634+
bool enable_pratt_parser)
628635
: options_(options),
629636
enable_optimizations_(enable_optimizations),
630637
enable_select_optimization_(enable_select_optimization),
631-
enable_variadic_logical_operators_(enable_variadic_logical_operators) {}
638+
enable_variadic_logical_operators_(enable_variadic_logical_operators),
639+
enable_pratt_parser_(enable_pratt_parser) {}
632640

633641
static absl::StatusOr<std::unique_ptr<cel::TraceableProgram>> Plan(
634642
const cel::Runtime& runtime,
@@ -660,6 +668,7 @@ class ModernConformanceServiceImpl : public ConformanceServiceInterface {
660668
bool enable_optimizations_;
661669
bool enable_select_optimization_;
662670
bool enable_variadic_logical_operators_;
671+
bool enable_pratt_parser_;
663672
};
664673

665674
} // namespace
@@ -673,11 +682,11 @@ NewConformanceService(const ConformanceServiceOptions& options) {
673682
if (options.modern) {
674683
return google::api::expr::runtime::ModernConformanceServiceImpl::Create(
675684
options.optimize, options.recursive, options.select_optimization,
676-
options.enable_variadic_logical_operators);
685+
options.enable_variadic_logical_operators, options.enable_pratt_parser);
677686
} else {
678687
return google::api::expr::runtime::LegacyConformanceServiceImpl::Create(
679688
options.optimize, options.recursive, options.select_optimization,
680-
options.enable_variadic_logical_operators);
689+
options.enable_variadic_logical_operators, options.enable_pratt_parser);
681690
}
682691
}
683692

conformance/service.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct ConformanceServiceOptions {
4747
bool recursive;
4848
bool select_optimization;
4949
bool enable_variadic_logical_operators = false;
50+
bool enable_pratt_parser = true;
5051
};
5152

5253
absl::StatusOr<std::unique_ptr<ConformanceServiceInterface>>

parser/BUILD

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ cc_library(
4242
":source_factory",
4343
"//common:ast",
4444
"//common:constant",
45+
"//common:expr",
4546
"//common:expr_factory",
4647
"//common:operators",
4748
"//common:source",
@@ -50,8 +51,8 @@ cc_library(
5051
"//internal:lexis",
5152
"//internal:status_macros",
5253
"//internal:strings",
53-
"//internal:utf8",
5454
"//parser/internal:cel_cc_parser",
55+
"//parser/internal:pratt_parser",
5556
"@antlr4-cpp-runtime",
5657
"@com_google_absl//absl/base:core_headers",
5758
"@com_google_absl//absl/cleanup",
@@ -60,6 +61,7 @@ cc_library(
6061
"@com_google_absl//absl/container:flat_hash_set",
6162
"@com_google_absl//absl/functional:overload",
6263
"@com_google_absl//absl/log:absl_check",
64+
"@com_google_absl//absl/log:check",
6365
"@com_google_absl//absl/memory",
6466
"@com_google_absl//absl/status",
6567
"@com_google_absl//absl/status:statusor",
@@ -197,6 +199,31 @@ cc_test(
197199
],
198200
)
199201

202+
cc_test(
203+
name = "pratt_parser_test",
204+
srcs = ["parser_test.cc"],
205+
defines = ["CEL_TEST_ENABLE_PRATT_PARSER=1"],
206+
deps = [
207+
":macro",
208+
":options",
209+
":parser",
210+
":parser_interface",
211+
":source_factory",
212+
"//common:constant",
213+
"//common:expr",
214+
"//common:source",
215+
"//internal:testing",
216+
"//testutil:expr_printer",
217+
"@com_google_absl//absl/algorithm:container",
218+
"@com_google_absl//absl/status",
219+
"@com_google_absl//absl/status:status_matchers",
220+
"@com_google_absl//absl/strings",
221+
"@com_google_absl//absl/strings:str_format",
222+
"@com_google_absl//absl/types:optional",
223+
"@com_google_cel_spec//proto/cel/expr:syntax_cc_proto",
224+
],
225+
)
226+
200227
cc_test(
201228
name = "parser_benchmarks",
202229
srcs = ["parser_benchmarks.cc"],

0 commit comments

Comments
 (0)