Skip to content

Commit 37a2ce7

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
[Pratt Parser] Add support for macro expansion.
PiperOrigin-RevId: 944185801
1 parent 5c9cda7 commit 37a2ce7

11 files changed

Lines changed: 755 additions & 128 deletions

parser/internal/BUILD

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cc_library(
2626
deps = [
2727
"@com_google_absl//absl/functional:function_ref",
2828
"@com_google_absl//absl/status:statusor",
29+
"@com_google_absl//absl/types:span",
2930
],
3031
)
3132

@@ -38,10 +39,15 @@ cc_library(
3839
"//common:expr",
3940
"//common:expr_factory",
4041
"//internal:status_macros",
42+
"//parser:macro",
43+
"//parser:macro_expr_factory",
44+
"//parser:macro_registry",
45+
"@com_google_absl//absl/base:nullability",
4146
"@com_google_absl//absl/functional:function_ref",
4247
"@com_google_absl//absl/status",
4348
"@com_google_absl//absl/status:statusor",
4449
"@com_google_absl//absl/strings:string_view",
50+
"@com_google_absl//absl/types:span",
4551
],
4652
)
4753

@@ -86,6 +92,7 @@ cc_library(
8692
"//parser:options",
8793
"//parser:parser_interface",
8894
"@com_google_absl//absl/base:nullability",
95+
"@com_google_absl//absl/cleanup",
8996
"@com_google_absl//absl/container:flat_hash_map",
9097
"@com_google_absl//absl/status:statusor",
9198
"@com_google_absl//absl/strings",
@@ -127,12 +134,17 @@ cc_test(
127134
srcs = ["ast_factory_test.cc"],
128135
deps = [
129136
":ast_factory",
137+
":ast_factory_interface",
130138
"//common:constant",
131139
"//common:expr",
132140
"//internal:testing",
141+
"//parser:macro",
142+
"//parser:macro_expr_factory",
143+
"//parser:macro_registry",
133144
"@com_google_absl//absl/status",
134145
"@com_google_absl//absl/status:status_matchers",
135146
"@com_google_absl//absl/strings:string_view",
147+
"@com_google_absl//absl/types:span",
136148
],
137149
)
138150

@@ -159,6 +171,8 @@ cc_test(
159171
"//common:source",
160172
"//internal:status_macros",
161173
"//internal:testing",
174+
"//parser:macro",
175+
"//parser:macro_expr_factory",
162176
"//parser:options",
163177
"//parser:parser_interface",
164178
"//testutil:expr_printer",
@@ -169,6 +183,7 @@ cc_test(
169183
"@com_google_absl//absl/strings",
170184
"@com_google_absl//absl/strings:str_format",
171185
"@com_google_absl//absl/strings:string_view",
186+
"@com_google_absl//absl/types:span",
172187
],
173188
)
174189

parser/internal/ast_factory.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "parser/internal/ast_factory.h"
1616

17+
#include <cstddef>
1718
#include <cstdint>
1819
#include <optional>
1920
#include <string>
@@ -25,6 +26,8 @@
2526
#include "absl/strings/string_view.h"
2627
#include "common/expr.h"
2728
#include "internal/status_macros.h"
29+
#include "parser/internal/ast_factory_interface.h"
30+
#include "parser/macro.h"
2831

2932
namespace cel::parser_internal {
3033

@@ -266,4 +269,19 @@ MapNodeBuilder<cel::Expr> AstFactoryInterface<cel::Expr>::NewMapBuilder(
266269
return MapNodeBuilder<cel::Expr>(id);
267270
}
268271

272+
std::optional<MacroExprExpander<cel::Expr>>
273+
AstFactoryInterface<cel::Expr>::NewMacroExprExpander(std::string_view name,
274+
size_t arg_count,
275+
bool receiver_style) {
276+
if (macro_registry_ == nullptr) {
277+
return std::nullopt;
278+
}
279+
std::optional<cel::Macro> macro =
280+
macro_registry_->FindMacro(name, arg_count, receiver_style);
281+
if (!macro) {
282+
return std::nullopt;
283+
}
284+
return std::optional<MacroExprExpander<cel::Expr>>(std::in_place, *macro);
285+
}
286+
269287
} // namespace cel::parser_internal

parser/internal/ast_factory.h

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,24 @@
1515
#ifndef THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
1616
#define THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
1717

18+
#include <cstddef>
1819
#include <cstdint>
20+
#include <functional>
1921
#include <optional>
2022
#include <string>
23+
#include <utility>
2124

25+
#include "absl/base/nullability.h"
2226
#include "absl/functional/function_ref.h"
2327
#include "absl/status/statusor.h"
2428
#include "absl/strings/string_view.h"
29+
#include "absl/types/span.h"
2530
#include "common/expr.h"
2631
#include "common/expr_factory.h"
2732
#include "parser/internal/ast_factory_interface.h"
33+
#include "parser/macro.h"
34+
#include "parser/macro_expr_factory.h"
35+
#include "parser/macro_registry.h"
2836

2937
namespace cel::parser_internal {
3038

@@ -71,10 +79,35 @@ class StructNodeBuilder<cel::Expr> {
7179
cel::Expr expr_;
7280
};
7381

82+
template <>
83+
class AstFactoryInterface<cel::Expr>;
84+
85+
template <>
86+
class MacroExprExpanderSupport<cel::Expr> : public cel::MacroExprFactory {};
87+
88+
template <>
89+
class MacroExprExpander<cel::Expr> {
90+
public:
91+
explicit MacroExprExpander(cel::Macro macro) : macro_(std::move(macro)) {}
92+
93+
std::optional<cel::Expr> Expand(
94+
std::optional<std::reference_wrapper<cel::Expr>> target,
95+
absl::Span<cel::Expr> args,
96+
MacroExprExpanderSupport<cel::Expr>& support) {
97+
return macro_.Expand(support, target, args);
98+
}
99+
100+
private:
101+
cel::Macro macro_;
102+
};
103+
74104
template <>
75105
class AstFactoryInterface<cel::Expr> : public cel::ExprFactory {
76106
public:
77-
AstFactoryInterface() = default;
107+
explicit AstFactoryInterface(
108+
const cel::MacroRegistry* absl_nullable macro_registry = nullptr)
109+
: macro_registry_(macro_registry) {}
110+
78111
AstFactoryInterface(const AstFactoryInterface&) = delete;
79112
AstFactoryInterface(AstFactoryInterface&&) = delete;
80113
AstFactoryInterface& operator=(const AstFactoryInterface&) = delete;
@@ -126,6 +159,12 @@ class AstFactoryInterface<cel::Expr> : public cel::ExprFactory {
126159
StructNodeBuilder<cel::Expr> NewStructBuilder(int64_t id, std::string name);
127160

128161
MapNodeBuilder<cel::Expr> NewMapBuilder(int64_t id);
162+
163+
std::optional<MacroExprExpander<cel::Expr>> NewMacroExprExpander(
164+
std::string_view name, size_t arg_count, bool receiver_style);
165+
166+
private:
167+
const cel::MacroRegistry* absl_nullable macro_registry_ = nullptr;
129168
};
130169

131170
using AstFactory = AstFactoryInterface<cel::Expr>;

parser/internal/ast_factory_interface.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
#ifndef THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_INTERFACE_H_
1616
#define THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_INTERFACE_H_
1717

18+
#include <cstddef>
1819
#include <cstdint>
20+
#include <functional>
1921
#include <optional>
2022
#include <string>
2123
#include <string_view>
2224
#include <vector>
2325

2426
#include "absl/functional/function_ref.h"
2527
#include "absl/status/statusor.h"
28+
#include "absl/types/span.h"
2629

2730
namespace cel::parser_internal {
2831

@@ -49,6 +52,17 @@ class StructNodeBuilder {
4952
ExprNode Build();
5053
};
5154

55+
template <typename ExprNode>
56+
class MacroExprExpanderSupport {};
57+
58+
template <typename ExprNode>
59+
class MacroExprExpander {
60+
public:
61+
std::optional<ExprNode> Expand(
62+
std::optional<std::reference_wrapper<ExprNode>> target,
63+
absl::Span<ExprNode> args, MacroExprExpanderSupport<ExprNode>& support);
64+
};
65+
5266
// Interface for decoupling parser logic from the underlying AST node
5367
// data structures.
5468
//
@@ -104,6 +118,11 @@ class AstFactoryInterface {
104118
ListNodeBuilder<ExprNode> NewListBuilder(int64_t id);
105119
MapNodeBuilder<ExprNode> NewMapBuilder(int64_t id);
106120
StructNodeBuilder<ExprNode> NewStructBuilder(int64_t id, std::string name);
121+
122+
// Returns a macro expander for the given macro name, or null if there
123+
// is no registered macro with that name and argument count.
124+
std::optional<MacroExprExpander<ExprNode>> NewMacroExprExpander(
125+
std::string_view name, size_t arg_count, bool receiver_style);
107126
};
108127

109128
} // namespace cel::parser_internal

parser/internal/ast_factory_test.cc

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@
2222
#include "absl/status/status.h"
2323
#include "absl/status/status_matchers.h"
2424
#include "absl/strings/string_view.h"
25+
#include "absl/types/span.h"
2526
#include "common/constant.h"
2627
#include "common/expr.h"
2728
#include "internal/testing.h"
29+
#include "parser/internal/ast_factory_interface.h"
30+
#include "parser/macro.h"
31+
#include "parser/macro_expr_factory.h"
32+
#include "parser/macro_registry.h"
2833

2934
namespace cel::parser_internal {
3035
namespace {
3136

37+
using ::absl_testing::IsOk;
38+
3239
using ::absl_testing::StatusIs;
3340

3441
TEST(AstFactoryInterfaceTest, AstFactoryUnspecified) {
@@ -393,5 +400,50 @@ TEST(AstFactoryInterfaceTest, CopyAndReplaceMaxRecursionDepth) {
393400
StatusIs(absl::StatusCode::kInvalidArgument));
394401
}
395402

403+
class TestMacroExprExpanderSupport
404+
: public MacroExprExpanderSupport<cel::Expr> {
405+
public:
406+
int64_t NextId() override { return 42; }
407+
int64_t CopyId(int64_t id) override { return id; }
408+
cel::Expr ReportError(std::string_view) override { return cel::Expr(); }
409+
cel::Expr ReportErrorAt(const cel::Expr&, std::string_view) override {
410+
return cel::Expr();
411+
}
412+
};
413+
414+
TEST(AstFactoryInterfaceTest, MacroExprExpander) {
415+
MacroRegistry macro_registry;
416+
AstFactory factory(&macro_registry);
417+
ASSERT_OK_AND_ASSIGN(
418+
auto foo_macro,
419+
Macro::Global("foo", 1,
420+
[](MacroExprFactory& macro_factory,
421+
absl::Span<Expr> args) -> std::optional<Expr> {
422+
return macro_factory.NewCall("my_macro", std::move(args));
423+
}));
424+
425+
ASSERT_THAT(macro_registry.RegisterMacro(foo_macro), IsOk());
426+
427+
auto expander1 = factory.NewMacroExprExpander("foo", 1, false);
428+
ASSERT_TRUE(expander1.has_value());
429+
430+
std::vector<Expr> expand_args;
431+
expand_args.push_back(factory.NewIdent(1, "x"));
432+
433+
TestMacroExprExpanderSupport support;
434+
auto result =
435+
expander1->Expand(std::nullopt, absl::MakeSpan(expand_args), support);
436+
ASSERT_TRUE(result.has_value());
437+
438+
std::vector<Expr> expected_args;
439+
expected_args.push_back(factory.NewIdent(1, "x"));
440+
Expr expected = factory.NewCall(42, "my_macro", std::move(expected_args));
441+
442+
EXPECT_EQ(*result, expected);
443+
444+
auto expander2 = factory.NewMacroExprExpander("bar", 1, false);
445+
EXPECT_FALSE(expander2.has_value());
446+
}
447+
396448
} // namespace
397449
} // namespace cel::parser_internal

0 commit comments

Comments
 (0)