Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions common/expr_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ namespace tools {
class ProtoToPredicateBuilder;
}

namespace parser_internal {
template <typename ExprNode>
class AstFactoryInterface;
}

class ExprFactory {
protected:
// `IsExprLike` determines whether `T` is some `Expr`. Currently that means
Expand Down Expand Up @@ -385,6 +390,7 @@ class ExprFactory {
friend class ParserMacroExprFactory;
friend class OptimizerExprFactory;
friend class tools::ProtoToPredicateBuilder;
friend class parser_internal::AstFactoryInterface<Expr>;

ExprFactory() : accu_var_(kAccumulatorVariableName) {}

Expand Down
130 changes: 130 additions & 0 deletions parser/internal/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,30 @@
# limitations under the License.

load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("//bazel:antlr.bzl", "antlr_cc_library")

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

licenses(["notice"])

cc_library(
name = "ast_factory_interface",
hdrs = ["ast_factory_interface.h"],
)

cc_library(
name = "ast_factory",
hdrs = ["ast_factory.h"],
deps = [
":ast_factory_interface",
"//common:constant",
"//common:expr",
"//common:expr_factory",
"@com_google_absl//absl/strings:string_view",
],
)

cc_library(
name = "options",
hdrs = ["options.h"],
Expand All @@ -29,3 +47,115 @@ antlr_cc_library(
src = "Cel.g4",
package = "cel_parser_internal",
)

cc_library(
name = "lexer",
srcs = ["lexer.cc"],
hdrs = ["lexer.h"],
deps = [
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/base:no_destructor",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:function_ref",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
],
)

cc_library(
name = "pratt_parser_worker",
srcs = ["pratt_parser_worker.cc"],
hdrs = ["pratt_parser_worker.h"],
deps = [
":ast_factory_interface",
":lexer",
"//common:operators",
"//common:source",
"//internal:lexis",
"//internal:strings",
"//parser:options",
"//parser:parser_interface",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/types:optional",
],
)

cc_library(
name = "pratt_parser",
srcs = ["pratt_parser.cc"],
hdrs = ["pratt_parser.h"],
deps = [
":ast_factory",
":pratt_parser_worker",
"//common:ast",
"//common:expr",
"//common:source",
"//internal:status_macros",
"//parser:macro",
"//parser:macro_registry",
"//parser:options",
"//parser:parser_interface",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/types:span",
],
)

cc_test(
name = "ast_factory_test",
srcs = ["ast_factory_test.cc"],
deps = [
":ast_factory",
"//common:expr",
"//internal:testing",
"@com_google_absl//absl/strings:string_view",
],
)

cc_test(
name = "lexer_test",
srcs = ["lexer_test.cc"],
deps = [
":lexer",
"//internal:testing",
],
)

cc_test(
name = "pratt_parser_test",
srcs = ["pratt_parser_test.cc"],
deps = [
":lexer",
":pratt_parser",
":pratt_parser_worker",
"//common:ast",
"//common:constant",
"//common:expr",
"//common:source",
"//internal:status_macros",
"//internal:testing",
"//parser:options",
"//parser:parser_interface",
"//testutil:expr_printer",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/strings:string_view",
],
)
182 changes: 182 additions & 0 deletions parser/internal/ast_factory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
#define THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_

#include <cstdint>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "absl/strings/string_view.h"
#include "common/constant.h"
#include "common/expr.h"
#include "common/expr_factory.h"
#include "parser/internal/ast_factory_interface.h"

namespace cel::parser_internal {

// Explicit specialization of `AstFactoryInterface` for `cel::Expr` AST nodes.

template <>
class ListNodeBuilder<cel::Expr> {
public:
explicit ListNodeBuilder(int64_t id) {
expr_.set_id(id);
expr_.mutable_list_expr();
}

ListNodeBuilder& Add(cel::Expr element, bool optional = false) {
cel::ListExpr& list_val = expr_.mutable_list_expr();
cel::ListExprElement expr_element;
expr_element.set_expr(std::move(element));
expr_element.set_optional(optional);
list_val.mutable_elements().push_back(std::move(expr_element));
return *this;
}

cel::Expr Build() { return std::move(expr_); }

private:
cel::Expr expr_;
};

template <>
class MapNodeBuilder<cel::Expr> {
public:
explicit MapNodeBuilder(int64_t id) {
expr_.set_id(id);
expr_.mutable_map_expr();
}

MapNodeBuilder& Add(int64_t id, cel::Expr key, cel::Expr value,
bool optional = false) {
cel::MapExpr& map_val = expr_.mutable_map_expr();
cel::MapExprEntry entry;
entry.set_id(id);
entry.set_key(std::move(key));
entry.set_value(std::move(value));
entry.set_optional(optional);
map_val.mutable_entries().push_back(std::move(entry));
return *this;
}

cel::Expr Build() { return std::move(expr_); }

private:
cel::Expr expr_;
};

template <>
class StructNodeBuilder<cel::Expr> {
public:
explicit StructNodeBuilder(int64_t id, std::string name) {
expr_.set_id(id);
expr_.mutable_struct_expr().set_name(std::move(name));
}

StructNodeBuilder& Add(int64_t id, std::string name, cel::Expr value,
bool optional = false) {
cel::StructExpr& struct_val = expr_.mutable_struct_expr();
cel::StructExprField field;
field.set_id(id);
field.set_name(std::move(name));
field.set_value(std::move(value));
field.set_optional(optional);
struct_val.mutable_fields().push_back(std::move(field));
return *this;
}

cel::Expr Build() { return std::move(expr_); }

private:
cel::Expr expr_;
};

template <>
class AstFactoryInterface<cel::Expr> : public cel::ExprFactory {
public:
AstFactoryInterface() = default;
AstFactoryInterface(const AstFactoryInterface&) = delete;
AstFactoryInterface(AstFactoryInterface&&) = delete;
AstFactoryInterface& operator=(const AstFactoryInterface&) = delete;
AstFactoryInterface& operator=(AstFactoryInterface&&) = delete;

~AstFactoryInterface() = default;

// Node inspection and encapsulation API
int64_t GetId(const cel::Expr& expr) const { return expr.id(); }

bool IsEmpty(const cel::Expr& expr) const { return expr.id() == 0; }

bool IsConst(const cel::Expr& expr) const { return expr.has_const_expr(); }

bool IsIdent(const cel::Expr& expr) const { return expr.has_ident_expr(); }

absl::string_view GetIdentName(const cel::Expr& expr) const {
return expr.has_ident_expr() ? absl::string_view(expr.ident_expr().name())
: absl::string_view();
}

bool IsSelect(const cel::Expr& expr) const { return expr.has_select_expr(); }

bool IsPresenceTest(const cel::Expr& expr) const {
return expr.has_select_expr() && expr.select_expr().test_only();
}

const cel::Expr* GetSelectOperand(const cel::Expr& expr) const {
return expr.has_select_expr() ? &expr.select_expr().operand() : nullptr;
}

absl::string_view GetSelectField(const cel::Expr& expr) const {
return expr.has_select_expr()
? absl::string_view(expr.select_expr().field())
: absl::string_view();
}

// Node creation API
using cel::ExprFactory::NewBoolConst;
using cel::ExprFactory::NewBytesConst;
using cel::ExprFactory::NewCall;
using cel::ExprFactory::NewDoubleConst;
using cel::ExprFactory::NewIdent;
using cel::ExprFactory::NewIntConst;
using cel::ExprFactory::NewMemberCall;
using cel::ExprFactory::NewNullConst;
using cel::ExprFactory::NewPresenceTest;
using cel::ExprFactory::NewSelect;
using cel::ExprFactory::NewStringConst;
using cel::ExprFactory::NewUintConst;
using cel::ExprFactory::NewUnspecified;

ListNodeBuilder<cel::Expr> NewListBuilder(int64_t id) {
return ListNodeBuilder<cel::Expr>(id);
}

StructNodeBuilder<cel::Expr> NewStructBuilder(int64_t id, std::string name) {
return StructNodeBuilder<cel::Expr>(id, std::move(name));
}

MapNodeBuilder<cel::Expr> NewMapBuilder(int64_t id) {
return MapNodeBuilder<cel::Expr>(id);
}
};

using AstFactory = AstFactoryInterface<cel::Expr>;

} // namespace cel::parser_internal

#endif // THIRD_PARTY_CEL_CPP_PARSER_INTERNAL_AST_FACTORY_H_
Loading
Loading