Skip to content

Commit 54a98f2

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
[Pratt Parser] Add AstFactoryInterface template
Also, add AstFactoryInterface<cel::Expr> specialization PiperOrigin-RevId: 953018238
1 parent cc92e62 commit 54a98f2

5 files changed

Lines changed: 519 additions & 0 deletions

File tree

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

parser/internal/BUILD

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ package(default_visibility = ["//visibility:public"])
2020

2121
licenses(["notice"])
2222

23+
cc_library(
24+
name = "ast_factory_interface",
25+
hdrs = ["ast_factory_interface.h"],
26+
)
27+
28+
cc_library(
29+
name = "ast_factory",
30+
hdrs = ["ast_factory.h"],
31+
deps = [
32+
":ast_factory_interface",
33+
"//common:constant",
34+
"//common:expr",
35+
"//common:expr_factory",
36+
"@com_google_absl//absl/strings:string_view",
37+
],
38+
)
39+
2340
cc_library(
2441
name = "options",
2542
hdrs = ["options.h"],
@@ -47,6 +64,17 @@ cc_library(
4764
],
4865
)
4966

67+
cc_test(
68+
name = "ast_factory_test",
69+
srcs = ["ast_factory_test.cc"],
70+
deps = [
71+
":ast_factory",
72+
"//common:expr",
73+
"//internal:testing",
74+
"@com_google_absl//absl/strings:string_view",
75+
],
76+
)
77+
5078
cc_test(
5179
name = "lexer_test",
5280
srcs = ["lexer_test.cc"],

parser/internal/ast_factory.h

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
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_PARSER_INTERNAL_AST_FACTORY_H_
16+
#define THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
17+
18+
#include <cstdint>
19+
#include <string>
20+
#include <utility>
21+
#include <vector>
22+
23+
#include "absl/strings/string_view.h"
24+
#include "common/constant.h"
25+
#include "common/expr.h"
26+
#include "common/expr_factory.h"
27+
#include "parser/internal/ast_factory_interface.h"
28+
29+
namespace cel::parser_internal {
30+
31+
// Explicit specialization of `AstFactoryInterface` for `cel::Expr` AST nodes.
32+
33+
template <>
34+
class ListNodeBuilder<cel::Expr> {
35+
public:
36+
explicit ListNodeBuilder(int64_t id) {
37+
expr_.set_id(id);
38+
expr_.mutable_list_expr();
39+
}
40+
41+
ListNodeBuilder& Add(cel::Expr element, bool optional = false) {
42+
cel::ListExpr& list_val = expr_.mutable_list_expr();
43+
cel::ListExprElement expr_element;
44+
expr_element.set_expr(std::move(element));
45+
expr_element.set_optional(optional);
46+
list_val.mutable_elements().push_back(std::move(expr_element));
47+
return *this;
48+
}
49+
50+
cel::Expr Build() { return std::move(expr_); }
51+
52+
private:
53+
cel::Expr expr_;
54+
};
55+
56+
template <>
57+
class MapNodeBuilder<cel::Expr> {
58+
public:
59+
explicit MapNodeBuilder(int64_t id) {
60+
expr_.set_id(id);
61+
expr_.mutable_map_expr();
62+
}
63+
64+
MapNodeBuilder& Add(int64_t id, cel::Expr key, cel::Expr value,
65+
bool optional = false) {
66+
cel::MapExpr& map_val = expr_.mutable_map_expr();
67+
cel::MapExprEntry entry;
68+
entry.set_id(id);
69+
entry.set_key(std::move(key));
70+
entry.set_value(std::move(value));
71+
entry.set_optional(optional);
72+
map_val.mutable_entries().push_back(std::move(entry));
73+
return *this;
74+
}
75+
76+
cel::Expr Build() { return std::move(expr_); }
77+
78+
private:
79+
cel::Expr expr_;
80+
};
81+
82+
template <>
83+
class StructNodeBuilder<cel::Expr> {
84+
public:
85+
explicit StructNodeBuilder(int64_t id, std::string name) {
86+
expr_.set_id(id);
87+
expr_.mutable_struct_expr().set_name(std::move(name));
88+
}
89+
90+
StructNodeBuilder& Add(int64_t id, std::string name, cel::Expr value,
91+
bool optional = false) {
92+
cel::StructExpr& struct_val = expr_.mutable_struct_expr();
93+
cel::StructExprField field;
94+
field.set_id(id);
95+
field.set_name(std::move(name));
96+
field.set_value(std::move(value));
97+
field.set_optional(optional);
98+
struct_val.mutable_fields().push_back(std::move(field));
99+
return *this;
100+
}
101+
102+
cel::Expr Build() { return std::move(expr_); }
103+
104+
private:
105+
cel::Expr expr_;
106+
};
107+
108+
template <>
109+
class AstFactoryInterface<cel::Expr> : public cel::ExprFactory {
110+
public:
111+
AstFactoryInterface() = default;
112+
AstFactoryInterface(const AstFactoryInterface&) = delete;
113+
AstFactoryInterface(AstFactoryInterface&&) = delete;
114+
AstFactoryInterface& operator=(const AstFactoryInterface&) = delete;
115+
AstFactoryInterface& operator=(AstFactoryInterface&&) = delete;
116+
117+
~AstFactoryInterface() override = default;
118+
119+
// Node inspection and encapsulation API
120+
int64_t GetId(const cel::Expr& expr) const { return expr.id(); }
121+
122+
bool IsEmpty(const cel::Expr& expr) const { return expr.id() == 0; }
123+
124+
bool IsConst(const cel::Expr& expr) const { return expr.has_const_expr(); }
125+
126+
bool IsIdent(const cel::Expr& expr) const { return expr.has_ident_expr(); }
127+
128+
absl::string_view GetIdentName(const cel::Expr& expr) const {
129+
return expr.has_ident_expr() ? absl::string_view(expr.ident_expr().name())
130+
: absl::string_view();
131+
}
132+
133+
bool IsSelect(const cel::Expr& expr) const { return expr.has_select_expr(); }
134+
135+
bool IsPresenceTest(const cel::Expr& expr) const {
136+
return expr.has_select_expr() && expr.select_expr().test_only();
137+
}
138+
139+
const cel::Expr* GetSelectOperand(const cel::Expr& expr) const {
140+
return expr.has_select_expr() ? &expr.select_expr().operand() : nullptr;
141+
}
142+
143+
absl::string_view GetSelectField(const cel::Expr& expr) const {
144+
return expr.has_select_expr()
145+
? absl::string_view(expr.select_expr().field())
146+
: absl::string_view();
147+
}
148+
149+
// Node creation API
150+
using cel::ExprFactory::NewBoolConst;
151+
using cel::ExprFactory::NewBytesConst;
152+
using cel::ExprFactory::NewCall;
153+
using cel::ExprFactory::NewDoubleConst;
154+
using cel::ExprFactory::NewIdent;
155+
using cel::ExprFactory::NewIntConst;
156+
using cel::ExprFactory::NewMemberCall;
157+
using cel::ExprFactory::NewNullConst;
158+
using cel::ExprFactory::NewPresenceTest;
159+
using cel::ExprFactory::NewSelect;
160+
using cel::ExprFactory::NewStringConst;
161+
using cel::ExprFactory::NewUintConst;
162+
using cel::ExprFactory::NewUnspecified;
163+
164+
ListNodeBuilder<cel::Expr> NewListBuilder(int64_t id) {
165+
return ListNodeBuilder<cel::Expr>(id);
166+
}
167+
168+
StructNodeBuilder<cel::Expr> NewStructBuilder(int64_t id, std::string name) {
169+
return StructNodeBuilder<cel::Expr>(id, std::move(name));
170+
}
171+
172+
MapNodeBuilder<cel::Expr> NewMapBuilder(int64_t id) {
173+
return MapNodeBuilder<cel::Expr>(id);
174+
}
175+
};
176+
177+
using AstFactory = AstFactoryInterface<cel::Expr>;
178+
179+
} // namespace cel::parser_internal
180+
181+
#endif // THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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_PARSER_INTERNAL_AST_FACTORY_INTERFACE_H_
16+
#define THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_INTERFACE_H_
17+
18+
#include <cstdint>
19+
#include <string>
20+
#include <string_view>
21+
#include <vector>
22+
23+
namespace cel::parser_internal {
24+
25+
// Interface for decoupling parser logic from the underlying AST node
26+
// data structures.
27+
//
28+
// By parameterizing the parser and factory on `ExprNode`, alternative AST node
29+
// representations (such as `cel::Expr`) can be constructed without modifying
30+
// parser rules.
31+
//
32+
// To implement AST construction using an alternative AST structure:
33+
// 1. Define or specify your custom node type `MyNode`.
34+
// 2. Implement a concrete factory specialization `AstFactoryInterface<MyNode>`
35+
// that provides inspection (`GetId`, `IsSelect`, etc.) and creation
36+
// (`NewCall`, `NewListBuilder`, etc.) operations for `MyNode`.
37+
// 3. Instantiate the parser worker with your node type:
38+
// `PrattParserWorker<MyNode>`.
39+
40+
template <typename ExprNode>
41+
class ListNodeBuilder {
42+
public:
43+
ListNodeBuilder& Add(ExprNode element, bool optional = false);
44+
ExprNode Build();
45+
};
46+
47+
template <typename ExprNode>
48+
class MapNodeBuilder {
49+
public:
50+
MapNodeBuilder& Add(int64_t id, ExprNode key, ExprNode value,
51+
bool optional = false);
52+
ExprNode Build();
53+
};
54+
55+
template <typename ExprNode>
56+
class StructNodeBuilder {
57+
public:
58+
StructNodeBuilder& Add(int64_t id, std::string name, ExprNode value,
59+
bool optional = false);
60+
ExprNode Build();
61+
};
62+
63+
template <typename ExprNode>
64+
class AstFactoryInterface {
65+
public:
66+
AstFactoryInterface() = default;
67+
AstFactoryInterface(const AstFactoryInterface&) = delete;
68+
AstFactoryInterface(AstFactoryInterface&&) = delete;
69+
AstFactoryInterface& operator=(const AstFactoryInterface&) = delete;
70+
AstFactoryInterface& operator=(AstFactoryInterface&&) = delete;
71+
72+
int64_t GetId(const ExprNode& expr) const;
73+
bool IsEmpty(const ExprNode& expr) const;
74+
bool IsConst(const ExprNode& expr) const;
75+
bool IsIdent(const ExprNode& expr) const;
76+
std::string_view GetIdentName(const ExprNode& expr) const;
77+
bool IsSelect(const ExprNode& expr) const;
78+
bool IsPresenceTest(const ExprNode& expr) const;
79+
const ExprNode* GetSelectOperand(const ExprNode& expr) const;
80+
std::string_view GetSelectField(const ExprNode& expr) const;
81+
82+
ExprNode NewUnspecified(int64_t id);
83+
ExprNode NewNullConst(int64_t id);
84+
ExprNode NewBoolConst(int64_t id, bool value);
85+
ExprNode NewIntConst(int64_t id, int64_t value);
86+
ExprNode NewUintConst(int64_t id, uint64_t value);
87+
ExprNode NewDoubleConst(int64_t id, double value);
88+
ExprNode NewBytesConst(int64_t id, std::string value);
89+
ExprNode NewStringConst(int64_t id, std::string value);
90+
ExprNode NewIdent(int64_t id, std::string name);
91+
ExprNode NewSelect(int64_t id, ExprNode operand, std::string field);
92+
ExprNode NewPresenceTest(int64_t id, ExprNode operand, std::string field);
93+
ExprNode NewCall(int64_t id, std::string function,
94+
std::vector<ExprNode> args);
95+
ExprNode NewMemberCall(int64_t id, std::string function, ExprNode target,
96+
std::vector<ExprNode> args);
97+
ListNodeBuilder<ExprNode> NewListBuilder(int64_t id);
98+
MapNodeBuilder<ExprNode> NewMapBuilder(int64_t id);
99+
StructNodeBuilder<ExprNode> NewStructBuilder(int64_t id, std::string name);
100+
};
101+
102+
} // namespace cel::parser_internal
103+
104+
#endif // THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_INTERFACE_H_

0 commit comments

Comments
 (0)