Skip to content

Commit 2feb2ee

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
[Pratt Parser] Add AstFactoryInterface template
Also, add AstFactoryInterface<cel::Expr> specialization PiperOrigin-RevId: 943561016
1 parent 6108479 commit 2feb2ee

10 files changed

Lines changed: 1909 additions & 12 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: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,30 @@
1313
# limitations under the License.
1414

1515
load("@rules_cc//cc:cc_library.bzl", "cc_library")
16+
load("@rules_cc//cc:cc_test.bzl", "cc_test")
1617
load("//bazel:antlr.bzl", "antlr_cc_library")
1718

1819
package(default_visibility = ["//visibility:public"])
1920

2021
licenses(["notice"])
2122

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+
2240
cc_library(
2341
name = "options",
2442
hdrs = ["options.h"],
@@ -29,3 +47,50 @@ antlr_cc_library(
2947
src = "Cel.g4",
3048
package = "cel_parser_internal",
3149
)
50+
51+
cc_library(
52+
name = "lexer",
53+
srcs = ["lexer.cc"],
54+
hdrs = ["lexer.h"],
55+
deps = [
56+
"@com_google_absl//absl/base:core_headers",
57+
"@com_google_absl//absl/base:no_destructor",
58+
"@com_google_absl//absl/base:nullability",
59+
"@com_google_absl//absl/container:flat_hash_map",
60+
"@com_google_absl//absl/functional:function_ref",
61+
"@com_google_absl//absl/log:absl_check",
62+
"@com_google_absl//absl/strings",
63+
"@com_google_absl//absl/strings:string_view",
64+
],
65+
)
66+
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+
78+
cc_test(
79+
name = "lexer_test",
80+
srcs = ["lexer_test.cc"],
81+
deps = [
82+
":lexer",
83+
"//internal:testing",
84+
],
85+
)
86+
87+
cc_test(
88+
name = "lexer_fuzzer",
89+
size = "large",
90+
srcs = ["lexer_fuzzer.cc"],
91+
deps = [
92+
":lexer",
93+
"//internal:testing",
94+
"//testing/fuzzing:fuzztest",
95+
],
96+
)

parser/internal/ast_factory.h

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