From d336d8b357f0d6a7a310d40198b8c3d917d8a7f4 Mon Sep 17 00:00:00 2001 From: Justin King Date: Wed, 24 Apr 2024 08:10:40 -0700 Subject: [PATCH] Introduce `cel::Expr` PiperOrigin-RevId: 627733102 --- common/BUILD | 48 ++ common/ast.cc | 66 ++ common/ast.h | 1494 +++++++++++++++++++++++++++++++++++++++ common/ast_test.cc | 559 +++++++++++++++ common/constant.cc | 36 + common/constant.h | 301 ++++++++ common/constant_test.cc | 217 ++++++ 7 files changed, 2721 insertions(+) create mode 100644 common/ast.cc create mode 100644 common/ast.h create mode 100644 common/ast_test.cc create mode 100644 common/constant.cc create mode 100644 common/constant.h create mode 100644 common/constant_test.cc diff --git a/common/BUILD b/common/BUILD index 4e63d00d6..573d93093 100644 --- a/common/BUILD +++ b/common/BUILD @@ -16,6 +16,54 @@ package(default_visibility = ["//visibility:public"]) licenses(["notice"]) +cc_library( + name = "ast", + srcs = ["ast.cc"], + hdrs = ["ast.h"], + deps = [ + ":constant", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:no_destructor", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + "@com_google_absl//absl/types:variant", + ], +) + +cc_test( + name = "ast_test", + srcs = ["ast_test.cc"], + deps = [ + ":ast", + "//internal:testing", + ], +) + +cc_library( + name = "constant", + srcs = ["constant.cc"], + hdrs = ["constant.h"], + deps = [ + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:no_destructor", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:variant", + ], +) + +cc_test( + name = "constant_test", + srcs = ["constant_test.cc"], + deps = [ + ":constant", + "//internal:testing", + "@com_google_absl//absl/time", + ], +) + cc_library( name = "operators", srcs = [ diff --git a/common/ast.cc b/common/ast.cc new file mode 100644 index 000000000..7daaee6b1 --- /dev/null +++ b/common/ast.cc @@ -0,0 +1,66 @@ +// Copyright 2024 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. + +#include "common/ast.h" + +#include "absl/base/no_destructor.h" + +namespace cel { + +const UnspecifiedExpr& UnspecifiedExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const IdentExpr& IdentExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const SelectExpr& SelectExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const CallExpr& CallExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const ListExpr& ListExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const StructExpr& StructExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const MapExpr& MapExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const ComprehensionExpr& ComprehensionExpr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const Expr& Expr::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +} // namespace cel diff --git a/common/ast.h b/common/ast.h new file mode 100644 index 000000000..3cf38486b --- /dev/null +++ b/common/ast.h @@ -0,0 +1,1494 @@ +// Copyright 2024 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_COMMON_AST_H_ +#define THIRD_PARTY_CEL_CPP_COMMON_AST_H_ + +#include +#include +#include +#include +#include + +#include "absl/algorithm/container.h" +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" +#include "absl/types/variant.h" +#include "common/constant.h" + +namespace cel { + +using ExprId = int64_t; + +class Expr; +class UnspecifiedExpr; +class IdentExpr; +class SelectExpr; +class CallExpr; +class ListExprElement; +class ListExpr; +class StructExprField; +class StructExpr; +class MapExprEntry; +class MapExpr; +class ComprehensionExpr; + +bool operator==(const Expr& lhs, const Expr& rhs); + +inline bool operator!=(const Expr& lhs, const Expr& rhs) { + return !operator==(lhs, rhs); +} + +bool operator==(const ListExprElement& lhs, const ListExprElement& rhs); + +inline bool operator!=(const ListExprElement& lhs, const ListExprElement& rhs) { + return !operator==(lhs, rhs); +} + +bool operator==(const StructExprField& lhs, const StructExprField& rhs); + +inline bool operator!=(const StructExprField& lhs, const StructExprField& rhs) { + return !operator==(lhs, rhs); +} + +bool operator==(const MapExprEntry& lhs, const MapExprEntry& rhs); + +inline bool operator!=(const MapExprEntry& lhs, const MapExprEntry& rhs) { + return !operator==(lhs, rhs); +} + +// `UnspecifiedExpr` is the default alternative of `Expr`. It is used for +// default construction of `Expr` or as a placeholder for when errors occur. +class UnspecifiedExpr final { + public: + UnspecifiedExpr() = default; + UnspecifiedExpr(UnspecifiedExpr&&) = default; + UnspecifiedExpr& operator=(UnspecifiedExpr&&) = default; + + UnspecifiedExpr(const UnspecifiedExpr&) = delete; + UnspecifiedExpr& operator=(const UnspecifiedExpr&) = delete; + + void Clear() {} + + friend void swap(UnspecifiedExpr&, UnspecifiedExpr&) noexcept {} + + private: + friend class Expr; + + static const UnspecifiedExpr& default_instance(); +}; + +inline bool operator==(const UnspecifiedExpr&, const UnspecifiedExpr&) { + return true; +} + +inline bool operator!=(const UnspecifiedExpr& lhs, const UnspecifiedExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `IdentExpr` is an alternative of `Expr`, representing an identifier. +class IdentExpr final { + public: + IdentExpr() = default; + IdentExpr(IdentExpr&&) = default; + IdentExpr& operator=(IdentExpr&&) = default; + + IdentExpr(const IdentExpr&) = delete; + IdentExpr& operator=(const IdentExpr&) = delete; + + void Clear() { name_.clear(); } + + // Holds a single, unqualified identifier, possibly preceded by a '.'. + // + // Qualified names are represented by the [Expr.Select][] expression. + ABSL_MUST_USE_RESULT const std::string& name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return name_; + } + + void set_name(std::string name) { name_ = std::move(name); } + + void set_name(absl::string_view name) { + name_.assign(name.data(), name.size()); + } + + void set_name(const char* name) { set_name(absl::NullSafeStringView(name)); } + + ABSL_MUST_USE_RESULT std::string release_name() { return release(name_); } + + friend void swap(IdentExpr& lhs, IdentExpr& rhs) noexcept { + using std::swap; + swap(lhs.name_, rhs.name_); + } + + private: + friend class Expr; + + static const IdentExpr& default_instance(); + + static std::string release(std::string& property) { + std::string result; + result.swap(property); + return result; + } + + std::string name_; +}; + +inline bool operator==(const IdentExpr& lhs, const IdentExpr& rhs) { + return lhs.name() == rhs.name(); +} + +inline bool operator!=(const IdentExpr& lhs, const IdentExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `SelectExpr` is an alternative of `Expr`, representing field access. +class SelectExpr final { + public: + SelectExpr() = default; + SelectExpr(SelectExpr&&) = default; + SelectExpr& operator=(SelectExpr&&) = default; + + SelectExpr(const SelectExpr&) = delete; + SelectExpr& operator=(const SelectExpr&) = delete; + + void Clear() { + operand_.reset(); + field_.clear(); + test_only_ = false; + } + + ABSL_MUST_USE_RESULT bool has_operand() const { return operand_ != nullptr; } + + // The target of the selection expression. + // + // For example, in the select expression `request.auth`, the `request` + // portion of the expression is the `operand`. + ABSL_MUST_USE_RESULT const Expr& operand() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_operand() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_operand(Expr operand); + + void set_operand(std::unique_ptr operand); + + ABSL_MUST_USE_RESULT std::unique_ptr release_operand() { + return release(operand_); + } + + // The name of the field to select. + // + // For example, in the select expression `request.auth`, the `auth` portion + // of the expression would be the `field`. + ABSL_MUST_USE_RESULT const std::string& field() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return field_; + } + + void set_field(std::string field) { field_ = std::move(field); } + + void set_field(absl::string_view field) { + field_.assign(field.data(), field.size()); + } + + void set_field(const char* field) { + set_field(absl::NullSafeStringView(field)); + } + + ABSL_MUST_USE_RESULT std::string release_field() { return release(field_); } + + // Whether the select is to be interpreted as a field presence test. + // + // This results from the macro `has(request.auth)`. + ABSL_MUST_USE_RESULT bool test_only() const { return test_only_; } + + void set_test_only(bool test_only) { test_only_ = test_only; } + + friend void swap(SelectExpr& lhs, SelectExpr& rhs) noexcept { + using std::swap; + swap(lhs.operand_, rhs.operand_); + swap(lhs.field_, rhs.field_); + swap(lhs.test_only_, rhs.test_only_); + } + + private: + friend class Expr; + + static const SelectExpr& default_instance(); + + static std::string release(std::string& property) { + std::string result; + result.swap(property); + return result; + } + + static std::unique_ptr release(std::unique_ptr& property) { + std::unique_ptr result; + result.swap(property); + return result; + } + + std::unique_ptr operand_; + std::string field_; + bool test_only_ = false; +}; + +inline bool operator==(const SelectExpr& lhs, const SelectExpr& rhs) { + return lhs.operand() == rhs.operand() && lhs.field() == rhs.field() && + lhs.test_only() == rhs.test_only(); +} + +inline bool operator!=(const SelectExpr& lhs, const SelectExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `CallExpr` is an alternative of `Expr`, representing a function call. +class CallExpr final { + public: + CallExpr() = default; + CallExpr(CallExpr&&) = default; + CallExpr& operator=(CallExpr&&) = default; + + CallExpr(const CallExpr&) = delete; + CallExpr& operator=(const CallExpr&) = delete; + + void Clear(); + + // The name of the function or method being called. + ABSL_MUST_USE_RESULT const std::string& function() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return function_; + } + + void set_function(std::string function) { function_ = std::move(function); } + + void set_function(absl::string_view function) { + function_.assign(function.data(), function.size()); + } + + void set_function(const char* function) { + set_function(absl::NullSafeStringView(function)); + } + + ABSL_MUST_USE_RESULT std::string release_function() { + return release(function_); + } + + ABSL_MUST_USE_RESULT bool has_target() const { return target_ != nullptr; } + + // The target of an method call-style expression. For example, `x` in `x.f()`. + ABSL_MUST_USE_RESULT const Expr& target() const ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_target() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_target(Expr target); + + void set_target(std::unique_ptr target); + + ABSL_MUST_USE_RESULT std::unique_ptr release_target() { + return release(target_); + } + + // The arguments. + ABSL_MUST_USE_RESULT const std::vector& args() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return args_; + } + + ABSL_MUST_USE_RESULT std::vector& mutable_args() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return args_; + } + + void set_args(std::vector args); + + void set_args(absl::Span args); + + ABSL_MUST_USE_RESULT std::vector release_args(); + + friend void swap(CallExpr& lhs, CallExpr& rhs) noexcept { + using std::swap; + swap(lhs.function_, rhs.function_); + swap(lhs.target_, rhs.target_); + swap(lhs.args_, rhs.args_); + } + + private: + friend class Expr; + + static const CallExpr& default_instance(); + + static std::string release(std::string& property) { + std::string result; + result.swap(property); + return result; + } + + static std::unique_ptr release(std::unique_ptr& property) { + std::unique_ptr result; + result.swap(property); + return result; + } + + std::string function_; + std::unique_ptr target_; + std::vector args_; +}; + +inline bool operator==(const CallExpr& lhs, const CallExpr& rhs) { + return lhs.function() == rhs.function() && lhs.target() == rhs.target() && + absl::c_equal(lhs.args(), rhs.args()); +} + +inline bool operator!=(const CallExpr& lhs, const CallExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `ListExpr` is an alternative of `Expr`, representing a list. +class ListExpr final { + public: + ListExpr() = default; + ListExpr(ListExpr&&) = default; + ListExpr& operator=(ListExpr&&) = default; + + ListExpr(const ListExpr&) = delete; + ListExpr& operator=(const ListExpr&) = delete; + + void Clear(); + + // The elements of the list. + ABSL_MUST_USE_RESULT const std::vector& elements() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return elements_; + } + + ABSL_MUST_USE_RESULT std::vector& mutable_elements() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return elements_; + } + + void set_elements(std::vector elements); + + void set_elements(absl::Span elements); + + ABSL_MUST_USE_RESULT std::vector release_elements(); + + friend void swap(ListExpr& lhs, ListExpr& rhs) noexcept { + using std::swap; + swap(lhs.elements_, rhs.elements_); + } + + private: + friend class Expr; + + static const ListExpr& default_instance(); + + std::vector elements_; +}; + +inline bool operator==(const ListExpr& lhs, const ListExpr& rhs) { + return absl::c_equal(lhs.elements(), rhs.elements()); +} + +inline bool operator!=(const ListExpr& lhs, const ListExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `StructExpr` is an alternative of `Expr`, representing a struct. +class StructExpr final { + public: + StructExpr() = default; + StructExpr(StructExpr&&) = default; + StructExpr& operator=(StructExpr&&) = default; + + StructExpr(const StructExpr&) = delete; + StructExpr& operator=(const StructExpr&) = delete; + + void Clear(); + + // The type name of the struct to be created. + ABSL_MUST_USE_RESULT const std::string& name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return name_; + } + + void set_name(std::string name) { name_ = std::move(name); } + + void set_name(absl::string_view name) { + name_.assign(name.data(), name.size()); + } + + void set_name(const char* name) { set_name(absl::NullSafeStringView(name)); } + + ABSL_MUST_USE_RESULT std::string release_name() { return release(name_); } + + // The fields of the struct. + ABSL_MUST_USE_RESULT const std::vector& fields() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return fields_; + } + + ABSL_MUST_USE_RESULT std::vector& mutable_fields() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return fields_; + } + + void set_fields(std::vector fields); + + void set_fields(absl::Span fields); + + ABSL_MUST_USE_RESULT std::vector release_fields(); + + friend void swap(StructExpr& lhs, StructExpr& rhs) noexcept { + using std::swap; + swap(lhs.name_, rhs.name_); + swap(lhs.fields_, rhs.fields_); + } + + private: + friend class Expr; + + static const StructExpr& default_instance(); + + static std::string release(std::string& property) { + std::string result; + result.swap(property); + return result; + } + + std::string name_; + std::vector fields_; +}; + +inline bool operator==(const StructExpr& lhs, const StructExpr& rhs) { + return lhs.name() == rhs.name() && absl::c_equal(lhs.fields(), rhs.fields()); +} + +inline bool operator!=(const StructExpr& lhs, const StructExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `MapExpr` is an alternative of `Expr`, representing a map. +class MapExpr final { + public: + MapExpr() = default; + MapExpr(MapExpr&&) = default; + MapExpr& operator=(MapExpr&&) = default; + + MapExpr(const MapExpr&) = delete; + MapExpr& operator=(const MapExpr&) = delete; + + void Clear(); + + // The entries of the map. + ABSL_MUST_USE_RESULT const std::vector& entries() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return entries_; + } + + ABSL_MUST_USE_RESULT std::vector& mutable_entries() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return entries_; + } + + void set_entries(std::vector entries); + + void set_entries(absl::Span entries); + + ABSL_MUST_USE_RESULT std::vector release_entries(); + + friend void swap(MapExpr& lhs, MapExpr& rhs) noexcept { + using std::swap; + swap(lhs.entries_, rhs.entries_); + } + + private: + friend class Expr; + + static const MapExpr& default_instance(); + + std::vector entries_; +}; + +inline bool operator==(const MapExpr& lhs, const MapExpr& rhs) { + return absl::c_equal(lhs.entries(), rhs.entries()); +} + +inline bool operator!=(const MapExpr& lhs, const MapExpr& rhs) { + return !operator==(lhs, rhs); +} + +// `ComprehensionExpr` is an alternative of `Expr`, representing a +// comprehension. These are always synthetic as there is no way to express them +// directly in the Common Expression Language, and are created by macros. +class ComprehensionExpr final { + public: + ComprehensionExpr() = default; + ComprehensionExpr(ComprehensionExpr&&) = default; + ComprehensionExpr& operator=(ComprehensionExpr&&) = default; + + ComprehensionExpr(const ComprehensionExpr&) = delete; + ComprehensionExpr& operator=(const ComprehensionExpr&) = delete; + + void Clear() { + iter_var_.clear(); + iter_range_.reset(); + accu_var_.clear(); + accu_init_.reset(); + loop_condition_.reset(); + loop_step_.reset(); + result_.reset(); + } + + ABSL_MUST_USE_RESULT const std::string& iter_var() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return iter_var_; + } + + void set_iter_var(std::string iter_var) { iter_var_ = std::move(iter_var); } + + void set_iter_var(absl::string_view iter_var) { + iter_var_.assign(iter_var.data(), iter_var.size()); + } + + void set_iter_var(const char* iter_var) { + set_iter_var(absl::NullSafeStringView(iter_var)); + } + + ABSL_MUST_USE_RESULT std::string release_iter_var() { + return release(iter_var_); + } + + ABSL_MUST_USE_RESULT bool has_iter_range() const { + return iter_range_ != nullptr; + } + + ABSL_MUST_USE_RESULT const Expr& iter_range() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_iter_range() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_iter_range(Expr iter_range); + + void set_iter_range(std::unique_ptr iter_range); + + ABSL_MUST_USE_RESULT std::unique_ptr release_iter_range() { + return release(iter_range_); + } + + ABSL_MUST_USE_RESULT const std::string& accu_var() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return accu_var_; + } + + void set_accu_var(std::string accu_var) { accu_var_ = std::move(accu_var); } + + void set_accu_var(absl::string_view accu_var) { + accu_var_.assign(accu_var.data(), accu_var.size()); + } + + void set_accu_var(const char* accu_var) { + set_accu_var(absl::NullSafeStringView(accu_var)); + } + + ABSL_MUST_USE_RESULT std::string release_accu_var() { + return release(accu_var_); + } + + ABSL_MUST_USE_RESULT bool has_accu_init() const { + return accu_init_ != nullptr; + } + + ABSL_MUST_USE_RESULT const Expr& accu_init() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_accu_init() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_accu_init(Expr accu_init); + + void set_accu_init(std::unique_ptr accu_init); + + ABSL_MUST_USE_RESULT std::unique_ptr release_accu_init() { + return release(accu_init_); + } + + ABSL_MUST_USE_RESULT bool has_loop_condition() const { + return loop_condition_ != nullptr; + } + + ABSL_MUST_USE_RESULT const Expr& loop_condition() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_loop_condition() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_loop_condition(Expr loop_condition); + + void set_loop_condition(std::unique_ptr loop_condition); + + ABSL_MUST_USE_RESULT std::unique_ptr release_loop_condition() { + return release(loop_condition_); + } + + ABSL_MUST_USE_RESULT bool has_loop_step() const { + return loop_step_ != nullptr; + } + + ABSL_MUST_USE_RESULT const Expr& loop_step() const + ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_loop_step() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_loop_step(Expr loop_step); + + void set_loop_step(std::unique_ptr loop_step); + + ABSL_MUST_USE_RESULT std::unique_ptr release_loop_step() { + return release(loop_step_); + } + + ABSL_MUST_USE_RESULT bool has_result() const { return result_ != nullptr; } + + ABSL_MUST_USE_RESULT const Expr& result() const ABSL_ATTRIBUTE_LIFETIME_BOUND; + + Expr& mutable_result() ABSL_ATTRIBUTE_LIFETIME_BOUND; + + void set_result(Expr result); + + void set_result(std::unique_ptr result); + + ABSL_MUST_USE_RESULT std::unique_ptr release_result() { + return release(result_); + } + + friend void swap(ComprehensionExpr& lhs, ComprehensionExpr& rhs) noexcept { + using std::swap; + swap(lhs.iter_var_, rhs.iter_var_); + swap(lhs.iter_range_, rhs.iter_range_); + swap(lhs.accu_var_, rhs.accu_var_); + swap(lhs.accu_init_, rhs.accu_init_); + swap(lhs.loop_condition_, rhs.loop_condition_); + swap(lhs.loop_step_, rhs.loop_step_); + swap(lhs.result_, rhs.result_); + } + + private: + friend class Expr; + + static const ComprehensionExpr& default_instance(); + + static std::string release(std::string& property) { + std::string result; + result.swap(property); + return result; + } + + static std::unique_ptr release(std::unique_ptr& property) { + std::unique_ptr result; + result.swap(property); + return result; + } + + std::string iter_var_; + std::unique_ptr iter_range_; + std::string accu_var_; + std::unique_ptr accu_init_; + std::unique_ptr loop_condition_; + std::unique_ptr loop_step_; + std::unique_ptr result_; +}; + +inline bool operator==(const ComprehensionExpr& lhs, + const ComprehensionExpr& rhs) { + return lhs.iter_var() == rhs.iter_var() && + lhs.iter_range() == rhs.iter_range() && + lhs.accu_var() == rhs.accu_var() && + lhs.accu_init() == rhs.accu_init() && + lhs.loop_condition() == rhs.loop_condition() && + lhs.loop_step() == rhs.loop_step() && lhs.result() == rhs.result(); +} + +inline bool operator!=(const ComprehensionExpr& lhs, + const ComprehensionExpr& rhs) { + return !operator==(lhs, rhs); +} + +using ExprKind = + absl::variant; + +// `Expr` is a node in the Common Expression Language's abstract syntax tree. It +// is composed of a numeric ID and a kind variant. +class Expr final { + public: + Expr() = default; + Expr(Expr&&) = default; + Expr& operator=(Expr&&) = default; + + Expr(const Expr&) = delete; + Expr& operator=(const Expr&) = delete; + + void Clear() { + id_ = 0; + mutable_kind().emplace(); + } + + ABSL_MUST_USE_RESULT ExprId id() const { return id_; } + + void set_id(ExprId id) { id_ = id; } + + ABSL_MUST_USE_RESULT const ExprKind& kind() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return kind_; + } + + ABSL_MUST_USE_RESULT ExprKind& mutable_kind() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return kind_; + } + + void set_kind(ExprKind kind) { kind_ = std::move(kind); } + + ABSL_MUST_USE_RESULT ExprKind release_kind() { + ExprKind kind = std::move(kind_); + kind_.emplace(); + return kind; + } + + ABSL_MUST_USE_RESULT bool has_const_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const Constant& const_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + Constant& mutable_const_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_const_expr(Constant const_expr) { + try_emplace_kind() = std::move(const_expr); + } + + ABSL_MUST_USE_RESULT Constant release_const_expr() { + return release_kind(); + } + + ABSL_MUST_USE_RESULT bool has_ident_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const IdentExpr& ident_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + IdentExpr& mutable_ident_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_ident_expr(IdentExpr ident_expr) { + try_emplace_kind() = std::move(ident_expr); + } + + ABSL_MUST_USE_RESULT IdentExpr release_ident_expr() { + return release_kind(); + } + + ABSL_MUST_USE_RESULT bool has_select_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const SelectExpr& select_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + SelectExpr& mutable_select_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_select_expr(SelectExpr select_expr) { + try_emplace_kind() = std::move(select_expr); + } + + ABSL_MUST_USE_RESULT SelectExpr release_select_expr() { + return release_kind(); + } + + ABSL_MUST_USE_RESULT bool has_call_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const CallExpr& call_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + CallExpr& mutable_call_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_call_expr(CallExpr call_expr) { + try_emplace_kind() = std::move(call_expr); + } + + ABSL_MUST_USE_RESULT CallExpr release_call_expr() { + return release_kind(); + } + + ABSL_MUST_USE_RESULT bool has_list_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const ListExpr& list_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + ListExpr& mutable_list_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_list_expr(ListExpr list_expr); + + ABSL_MUST_USE_RESULT ListExpr release_list_expr(); + + ABSL_MUST_USE_RESULT bool has_struct_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const StructExpr& struct_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + StructExpr& mutable_struct_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_struct_expr(StructExpr struct_expr); + + ABSL_MUST_USE_RESULT StructExpr release_struct_expr(); + + ABSL_MUST_USE_RESULT bool has_map_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const MapExpr& map_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + MapExpr& mutable_map_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_map_expr(MapExpr map_expr); + + ABSL_MUST_USE_RESULT MapExpr release_map_expr(); + + ABSL_MUST_USE_RESULT bool has_comprehension_expr() const { + return absl::holds_alternative(kind()); + } + + ABSL_MUST_USE_RESULT const ComprehensionExpr& comprehension_expr() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return get_kind(); + } + + ComprehensionExpr& mutable_comprehension_expr() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return try_emplace_kind(); + } + + void set_comprehension_expr(ComprehensionExpr comprehension_expr) { + try_emplace_kind() = std::move(comprehension_expr); + } + + ABSL_MUST_USE_RESULT ComprehensionExpr release_comprehension_expr() { + return release_kind(); + } + + friend void swap(Expr& lhs, Expr& rhs) noexcept { + using std::swap; + swap(lhs.id_, rhs.id_); + swap(lhs.kind_, rhs.kind_); + } + + private: + friend class IdentExpr; + friend class SelectExpr; + friend class CallExpr; + friend class ListExpr; + friend class StructExpr; + friend class MapExpr; + friend class ComprehensionExpr; + friend class ListExprElement; + friend class StructExprField; + friend class MapExprEntry; + + static const Expr& default_instance(); + + template + ABSL_MUST_USE_RESULT T& try_emplace_kind(Args&&... args) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (auto* alt = absl::get_if(&mutable_kind()); alt) { + return *alt; + } + return kind_.emplace(std::forward(args)...); + } + + template + ABSL_MUST_USE_RESULT const T& get_kind() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (const auto* alt = absl::get_if(&kind()); alt) { + return *alt; + } + return T::default_instance(); + } + + template + ABSL_MUST_USE_RESULT T release_kind() { + T result; + if (auto* alt = absl::get_if(&mutable_kind()); alt) { + result = std::move(*alt); + } + kind_.emplace(); + return result; + } + + ExprId id_ = 0; + ExprKind kind_; +}; + +inline bool operator==(const Expr& lhs, const Expr& rhs) { + return lhs.id() == rhs.id() && lhs.kind() == rhs.kind(); +} + +inline const Expr& SelectExpr::operand() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_operand() ? *operand_ : Expr::default_instance(); +} + +inline Expr& SelectExpr::mutable_operand() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_operand()) { + operand_ = std::make_unique(); + } + return *operand_; +} + +inline void SelectExpr::set_operand(Expr operand) { + mutable_operand() = std::move(operand); +} + +inline void SelectExpr::set_operand(std::unique_ptr operand) { + operand_ = std::move(operand); +} + +inline void CallExpr::Clear() { + function_.clear(); + target_.reset(); + args_.clear(); +} + +inline const Expr& CallExpr::target() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_target() ? *target_ : Expr::default_instance(); +} + +inline Expr& CallExpr::mutable_target() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_target()) { + target_ = std::make_unique(); + } + return *target_; +} + +inline void CallExpr::set_target(Expr target) { + mutable_target() = std::move(target); +} + +inline void CallExpr::set_target(std::unique_ptr target) { + target_ = std::move(target); +} + +inline void CallExpr::set_args(std::vector args) { + args_ = std::move(args); +} + +inline void CallExpr::set_args(absl::Span args) { + args_.clear(); + args_.reserve(args.size()); + for (auto& arg : args) { + args_.push_back(std::move(arg)); + } +} + +inline std::vector CallExpr::release_args() { + std::vector args; + args.swap(args_); + return args; +} + +inline const Expr& ComprehensionExpr::iter_range() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_iter_range() ? *iter_range_ : Expr::default_instance(); +} + +inline Expr& ComprehensionExpr::mutable_iter_range() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_iter_range()) { + iter_range_ = std::make_unique(); + } + return *iter_range_; +} + +inline void ComprehensionExpr::set_iter_range(Expr iter_range) { + mutable_iter_range() = std::move(iter_range); +} + +inline void ComprehensionExpr::set_iter_range( + std::unique_ptr iter_range) { + iter_range_ = std::move(iter_range); +} + +inline const Expr& ComprehensionExpr::accu_init() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_accu_init() ? *accu_init_ : Expr::default_instance(); +} + +inline Expr& ComprehensionExpr::mutable_accu_init() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_accu_init()) { + accu_init_ = std::make_unique(); + } + return *accu_init_; +} + +inline void ComprehensionExpr::set_accu_init(Expr accu_init) { + mutable_accu_init() = std::move(accu_init); +} + +inline void ComprehensionExpr::set_accu_init(std::unique_ptr accu_init) { + accu_init_ = std::move(accu_init); +} + +inline const Expr& ComprehensionExpr::loop_step() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_loop_step() ? *loop_step_ : Expr::default_instance(); +} + +inline Expr& ComprehensionExpr::mutable_loop_step() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_loop_step()) { + loop_step_ = std::make_unique(); + } + return *loop_step_; +} + +inline void ComprehensionExpr::set_loop_step(Expr loop_step) { + mutable_loop_step() = std::move(loop_step); +} + +inline void ComprehensionExpr::set_loop_step(std::unique_ptr loop_step) { + loop_step_ = std::move(loop_step); +} + +inline const Expr& ComprehensionExpr::loop_condition() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_loop_condition() ? *loop_condition_ : Expr::default_instance(); +} + +inline Expr& ComprehensionExpr::mutable_loop_condition() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_loop_condition()) { + loop_condition_ = std::make_unique(); + } + return *loop_condition_; +} + +inline void ComprehensionExpr::set_loop_condition(Expr loop_condition) { + mutable_loop_condition() = std::move(loop_condition); +} + +inline void ComprehensionExpr::set_loop_condition( + std::unique_ptr loop_condition) { + loop_condition_ = std::move(loop_condition); +} + +inline const Expr& ComprehensionExpr::result() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_result() ? *result_ : Expr::default_instance(); +} + +inline Expr& ComprehensionExpr::mutable_result() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_result()) { + result_ = std::make_unique(); + } + return *result_; +} + +inline void ComprehensionExpr::set_result(Expr result) { + mutable_result() = std::move(result); +} + +inline void ComprehensionExpr::set_result(std::unique_ptr result) { + result_ = std::move(result); +} + +// `ListExprElement` represents an element in `ListExpr`. +class ListExprElement final { + public: + ListExprElement() = default; + ListExprElement(ListExprElement&&) = default; + ListExprElement& operator=(ListExprElement&&) = default; + + ListExprElement(const ListExprElement&) = delete; + ListExprElement& operator=(const ListExprElement&) = delete; + + void Clear() { + expr_.reset(); + optional_ = false; + } + + ABSL_MUST_USE_RESULT bool has_expr() const { return expr_.has_value(); } + + ABSL_MUST_USE_RESULT const Expr& expr() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_expr() ? *expr_ : Expr::default_instance(); + ; + } + + ABSL_MUST_USE_RESULT Expr& mutable_expr() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_expr()) { + expr_.emplace(); + } + return *expr_; + } + + void set_expr(Expr expr) { expr_ = std::move(expr); } + + void set_expr(std::unique_ptr expr) { + if (expr) { + set_expr(std::move(*expr)); + } else { + expr_.reset(); + } + } + + ABSL_MUST_USE_RESULT Expr release_expr() { return release(expr_); } + + ABSL_MUST_USE_RESULT bool optional() const { return optional_; } + + void set_optional(bool optional) { optional_ = optional; } + + friend void swap(ListExprElement& lhs, ListExprElement& rhs) noexcept { + using std::swap; + swap(lhs.expr_, rhs.expr_); + swap(lhs.optional_, rhs.optional_); + } + + private: + static Expr release(absl::optional& property) { + absl::optional result; + result.swap(property); + return std::move(result).value_or(Expr{}); + } + + absl::optional expr_; + bool optional_ = false; +}; + +inline bool operator==(const ListExprElement& lhs, const ListExprElement& rhs) { + return lhs.expr() == rhs.expr() && lhs.optional() == rhs.optional(); +} + +inline void ListExpr::Clear() { elements_.clear(); } + +inline void ListExpr::set_elements(std::vector elements) { + elements_ = std::move(elements); +} + +inline void ListExpr::set_elements(absl::Span elements) { + elements_.clear(); + elements_.reserve(elements.size()); + for (auto& element : elements) { + elements_.push_back(std::move(element)); + } +} + +inline std::vector ListExpr::release_elements() { + std::vector elements; + elements.swap(elements_); + return elements; +} + +// `StructExprField` represents a field in `StructExpr`. +class StructExprField final { + public: + StructExprField() = default; + StructExprField(StructExprField&&) = default; + StructExprField& operator=(StructExprField&&) = default; + + StructExprField(const StructExprField&) = delete; + StructExprField& operator=(const StructExprField&) = delete; + + void Clear() { + id_ = 0; + name_.clear(); + value_.reset(); + optional_ = false; + } + + ABSL_MUST_USE_RESULT ExprId id() const { return id_; } + + void set_id(ExprId id) { id_ = id; } + + ABSL_MUST_USE_RESULT absl::string_view name() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return name_; + } + + void set_name(std::string name) { name_ = std::move(name); } + + void set_name(absl::string_view name) { + name_.assign(name.data(), name.size()); + } + + void set_name(const char* name) { set_name(absl::NullSafeStringView(name)); } + + ABSL_MUST_USE_RESULT std::string release_name() { return std::move(name_); } + + ABSL_MUST_USE_RESULT bool has_value() const { return value_.has_value(); } + + ABSL_MUST_USE_RESULT const Expr& value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_value() ? *value_ : Expr::default_instance(); + } + + ABSL_MUST_USE_RESULT Expr& mutable_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_value()) { + value_.emplace(); + } + return *value_; + } + + void set_value(Expr value) { value_ = std::move(value); } + + void set_value(std::unique_ptr value) { + if (value) { + set_value(std::move(*value)); + } else { + value_.reset(); + } + } + + ABSL_MUST_USE_RESULT Expr release_value() { return release(value_); } + + ABSL_MUST_USE_RESULT bool optional() const { return optional_; } + + void set_optional(bool optional) { optional_ = optional; } + + friend void swap(StructExprField& lhs, StructExprField& rhs) noexcept { + using std::swap; + swap(lhs.id_, rhs.id_); + swap(lhs.name_, rhs.name_); + swap(lhs.value_, rhs.value_); + swap(lhs.optional_, rhs.optional_); + } + + private: + static Expr release(absl::optional& property) { + absl::optional result; + result.swap(property); + return std::move(result).value_or(Expr{}); + } + + ExprId id_ = 0; + std::string name_; + absl::optional value_; + bool optional_ = false; +}; + +inline bool operator==(const StructExprField& lhs, const StructExprField& rhs) { + return lhs.id() == rhs.id() && lhs.name() == rhs.name() && + lhs.value() == rhs.value() && lhs.optional() == rhs.optional(); +} + +inline void StructExpr::Clear() { + name_.clear(); + fields_.clear(); +} + +inline void StructExpr::set_fields(std::vector fields) { + fields_ = std::move(fields); +} + +inline void StructExpr::set_fields(absl::Span fields) { + fields_.clear(); + fields_.reserve(fields.size()); + for (auto& field : fields) { + fields_.push_back(std::move(field)); + } +} + +inline std::vector StructExpr::release_fields() { + std::vector fields; + fields.swap(fields_); + return fields; +} + +// `MapExprEntry` represents an entry in `MapExpr`. +class MapExprEntry final { + public: + MapExprEntry() = default; + MapExprEntry(MapExprEntry&&) = default; + MapExprEntry& operator=(MapExprEntry&&) = default; + + MapExprEntry(const MapExprEntry&) = delete; + MapExprEntry& operator=(const MapExprEntry&) = delete; + + void Clear() { + id_ = 0; + key_.reset(); + value_.reset(); + optional_ = false; + } + + ABSL_MUST_USE_RESULT ExprId id() const { return id_; } + + void set_id(ExprId id) { id_ = id; } + + ABSL_MUST_USE_RESULT bool has_key() const { return key_.has_value(); } + + ABSL_MUST_USE_RESULT const Expr& key() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_key() ? *key_ : Expr::default_instance(); + } + + ABSL_MUST_USE_RESULT Expr& mutable_key() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_key()) { + key_.emplace(); + } + return *key_; + } + + void set_key(Expr key) { key_ = std::move(key); } + + void set_key(std::unique_ptr key) { + if (key) { + set_key(std::move(*key)); + } else { + key_.reset(); + } + } + + ABSL_MUST_USE_RESULT Expr release_key() { return release(key_); } + + ABSL_MUST_USE_RESULT bool has_value() const { return value_.has_value(); } + + ABSL_MUST_USE_RESULT const Expr& value() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return has_value() ? *value_ : Expr::default_instance(); + } + + ABSL_MUST_USE_RESULT Expr& mutable_value() ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (!has_value()) { + value_.emplace(); + } + return *value_; + } + + void set_value(Expr value) { value_ = std::move(value); } + + void set_value(std::unique_ptr value) { + if (value) { + set_value(std::move(*value)); + } else { + value_.reset(); + } + } + + ABSL_MUST_USE_RESULT Expr release_value() { return release(value_); } + + ABSL_MUST_USE_RESULT bool optional() const { return optional_; } + + void set_optional(bool optional) { optional_ = optional; } + + friend void swap(MapExprEntry& lhs, MapExprEntry& rhs) noexcept { + using std::swap; + swap(lhs.id_, rhs.id_); + swap(lhs.key_, rhs.key_); + swap(lhs.value_, rhs.value_); + swap(lhs.optional_, rhs.optional_); + } + + private: + static Expr release(absl::optional& property) { + absl::optional result; + result.swap(property); + return std::move(result).value_or(Expr{}); + } + + ExprId id_ = 0; + absl::optional key_; + absl::optional value_; + bool optional_ = false; +}; + +inline bool operator==(const MapExprEntry& lhs, const MapExprEntry& rhs) { + return lhs.id() == rhs.id() && lhs.key() == rhs.key() && + lhs.value() == rhs.value() && lhs.optional() == rhs.optional(); +} + +inline void MapExpr::Clear() { entries_.clear(); } + +inline void MapExpr::set_entries(std::vector entries) { + entries_ = std::move(entries); +} + +inline void MapExpr::set_entries(absl::Span entries) { + entries_.clear(); + entries_.reserve(entries.size()); + for (auto& entry : entries) { + entries_.push_back(std::move(entry)); + } +} + +inline std::vector MapExpr::release_entries() { + std::vector entries; + entries.swap(entries_); + return entries; +} + +inline void Expr::set_list_expr(ListExpr list_expr) { + try_emplace_kind() = std::move(list_expr); +} + +inline ListExpr Expr::release_list_expr() { return release_kind(); } + +inline void Expr::set_struct_expr(StructExpr struct_expr) { + try_emplace_kind() = std::move(struct_expr); +} + +inline StructExpr Expr::release_struct_expr() { + return release_kind(); +} + +inline void Expr::set_map_expr(MapExpr map_expr) { + try_emplace_kind() = std::move(map_expr); +} + +inline MapExpr Expr::release_map_expr() { return release_kind(); } + +} // namespace cel + +#endif // THIRD_PARTY_CEL_CPP_COMMON_AST_H_ diff --git a/common/ast_test.cc b/common/ast_test.cc new file mode 100644 index 000000000..c3f87c79c --- /dev/null +++ b/common/ast_test.cc @@ -0,0 +1,559 @@ +// Copyright 2024 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. + +#include "common/ast.h" + +#include +#include + +#include "internal/testing.h" + +namespace cel { +namespace { + +using testing::_; +using testing::Eq; +using testing::IsEmpty; +using testing::IsFalse; +using testing::IsTrue; +using testing::SizeIs; +using testing::VariantWith; + +Expr MakeUnspecifiedExpr(ExprId id) { + Expr expr; + expr.set_id(id); + return expr; +} + +ListExprElement MakeListExprElement(Expr expr, bool optional = false) { + ListExprElement element; + element.set_expr(std::move(expr)); + element.set_optional(optional); + return element; +} + +StructExprField MakeStructExprField(ExprId id, const char* name, Expr value, + bool optional = false) { + StructExprField field; + field.set_id(id); + field.set_name(name); + field.set_value(std::move(value)); + field.set_optional(optional); + return field; +} + +MapExprEntry MakeMapExprEntry(ExprId id, Expr key, Expr value, + bool optional = false) { + MapExprEntry entry; + entry.set_id(id); + entry.set_key(std::move(key)); + entry.set_value(std::move(value)); + entry.set_optional(optional); + return entry; +} + +TEST(UnspecifiedExpr, Equality) { + EXPECT_EQ(UnspecifiedExpr{}, UnspecifiedExpr{}); +} + +TEST(IdentExpr, Name) { + IdentExpr ident_expr; + EXPECT_THAT(ident_expr.name(), IsEmpty()); + ident_expr.set_name("foo"); + EXPECT_THAT(ident_expr.name(), Eq("foo")); + auto name = ident_expr.release_name(); + EXPECT_THAT(name, Eq("foo")); + EXPECT_THAT(ident_expr.name(), IsEmpty()); +} + +TEST(IdentExpr, Equality) { + EXPECT_EQ(IdentExpr{}, IdentExpr{}); + IdentExpr ident_expr; + ident_expr.set_name(std::string("foo")); + EXPECT_NE(IdentExpr{}, ident_expr); +} + +TEST(SelectExpr, Operand) { + SelectExpr select_expr; + EXPECT_THAT(select_expr.has_operand(), IsFalse()); + EXPECT_EQ(select_expr.operand(), Expr{}); + select_expr.set_operand(MakeUnspecifiedExpr(1)); + EXPECT_THAT(select_expr.has_operand(), IsTrue()); + EXPECT_EQ(select_expr.operand(), MakeUnspecifiedExpr(1)); + auto operand = select_expr.release_operand(); + EXPECT_THAT(select_expr.has_operand(), IsFalse()); + EXPECT_EQ(select_expr.operand(), Expr{}); +} + +TEST(SelectExpr, Field) { + SelectExpr select_expr; + EXPECT_THAT(select_expr.field(), IsEmpty()); + select_expr.set_field("foo"); + EXPECT_THAT(select_expr.field(), Eq("foo")); + auto field = select_expr.release_field(); + EXPECT_THAT(field, Eq("foo")); + EXPECT_THAT(select_expr.field(), IsEmpty()); +} + +TEST(SelectExpr, TestOnly) { + SelectExpr select_expr; + EXPECT_THAT(select_expr.test_only(), IsFalse()); + select_expr.set_test_only(true); + EXPECT_THAT(select_expr.test_only(), IsTrue()); +} + +TEST(SelectExpr, Equality) { + EXPECT_EQ(SelectExpr{}, SelectExpr{}); + SelectExpr select_expr; + select_expr.set_test_only(true); + EXPECT_NE(SelectExpr{}, select_expr); +} + +TEST(CallExpr, Function) { + CallExpr call_expr; + EXPECT_THAT(call_expr.function(), IsEmpty()); + call_expr.set_function("foo"); + EXPECT_THAT(call_expr.function(), Eq("foo")); + auto function = call_expr.release_function(); + EXPECT_THAT(function, Eq("foo")); + EXPECT_THAT(call_expr.function(), IsEmpty()); +} + +TEST(CallExpr, Target) { + CallExpr call_expr; + EXPECT_THAT(call_expr.has_target(), IsFalse()); + EXPECT_EQ(call_expr.target(), Expr{}); + call_expr.set_target(MakeUnspecifiedExpr(1)); + EXPECT_THAT(call_expr.has_target(), IsTrue()); + EXPECT_EQ(call_expr.target(), MakeUnspecifiedExpr(1)); + auto operand = call_expr.release_target(); + EXPECT_THAT(call_expr.has_target(), IsFalse()); + EXPECT_EQ(call_expr.target(), Expr{}); +} + +TEST(CallExpr, Args) { + CallExpr call_expr; + EXPECT_THAT(call_expr.args(), IsEmpty()); + call_expr.mutable_args().push_back(MakeUnspecifiedExpr(1)); + ASSERT_THAT(call_expr.args(), SizeIs(1)); + EXPECT_EQ(call_expr.args()[0], MakeUnspecifiedExpr(1)); + auto args = call_expr.release_args(); + static_cast(args); + EXPECT_THAT(call_expr.args(), IsEmpty()); +} + +TEST(CallExpr, Equality) { + EXPECT_EQ(CallExpr{}, CallExpr{}); + CallExpr call_expr; + call_expr.mutable_args().push_back(MakeUnspecifiedExpr(1)); + EXPECT_NE(CallExpr{}, call_expr); +} + +TEST(ListExprElement, Expr) { + ListExprElement element; + EXPECT_THAT(element.has_expr(), IsFalse()); + EXPECT_EQ(element.expr(), Expr{}); + element.set_expr(MakeUnspecifiedExpr(1)); + EXPECT_THAT(element.has_expr(), IsTrue()); + EXPECT_EQ(element.expr(), MakeUnspecifiedExpr(1)); + auto operand = element.release_expr(); + EXPECT_THAT(element.has_expr(), IsFalse()); + EXPECT_EQ(element.expr(), Expr{}); +} + +TEST(ListExprElement, Optional) { + ListExprElement element; + EXPECT_THAT(element.optional(), IsFalse()); + element.set_optional(true); + EXPECT_THAT(element.optional(), IsTrue()); +} + +TEST(ListExprElement, Equality) { + EXPECT_EQ(ListExprElement{}, ListExprElement{}); + ListExprElement element; + element.set_optional(true); + EXPECT_NE(ListExprElement{}, element); +} + +TEST(ListExpr, Elements) { + ListExpr list_expr; + EXPECT_THAT(list_expr.elements(), IsEmpty()); + list_expr.mutable_elements().push_back( + MakeListExprElement(MakeUnspecifiedExpr(1))); + ASSERT_THAT(list_expr.elements(), SizeIs(1)); + EXPECT_EQ(list_expr.elements()[0], + MakeListExprElement(MakeUnspecifiedExpr(1))); + auto elements = list_expr.release_elements(); + static_cast(elements); + EXPECT_THAT(list_expr.elements(), IsEmpty()); +} + +TEST(ListExpr, Equality) { + EXPECT_EQ(ListExpr{}, ListExpr{}); + ListExpr list_expr; + list_expr.mutable_elements().push_back( + MakeListExprElement(MakeUnspecifiedExpr(0), true)); + EXPECT_NE(ListExpr{}, list_expr); +} + +TEST(StructExprField, Id) { + StructExprField field; + EXPECT_THAT(field.id(), Eq(0)); + field.set_id(1); + EXPECT_THAT(field.id(), Eq(1)); +} + +TEST(StructExprField, Name) { + StructExprField field; + EXPECT_THAT(field.name(), IsEmpty()); + field.set_name("foo"); + EXPECT_THAT(field.name(), Eq("foo")); + auto name = field.release_name(); + EXPECT_THAT(name, Eq("foo")); + EXPECT_THAT(field.name(), IsEmpty()); +} + +TEST(StructExprField, Value) { + StructExprField field; + EXPECT_THAT(field.has_value(), IsFalse()); + EXPECT_EQ(field.value(), Expr{}); + field.set_value(MakeUnspecifiedExpr(1)); + EXPECT_THAT(field.has_value(), IsTrue()); + EXPECT_EQ(field.value(), MakeUnspecifiedExpr(1)); + auto value = field.release_value(); + EXPECT_THAT(field.has_value(), IsFalse()); + EXPECT_EQ(field.value(), Expr{}); +} + +TEST(StructExprField, Optional) { + StructExprField field; + EXPECT_THAT(field.optional(), IsFalse()); + field.set_optional(true); + EXPECT_THAT(field.optional(), IsTrue()); +} + +TEST(StructExprField, Equality) { + EXPECT_EQ(StructExprField{}, StructExprField{}); + StructExprField field; + field.set_optional(true); + EXPECT_NE(StructExprField{}, field); +} + +TEST(StructExpr, Name) { + StructExpr struct_expr; + EXPECT_THAT(struct_expr.name(), IsEmpty()); + struct_expr.set_name("foo"); + EXPECT_THAT(struct_expr.name(), Eq("foo")); + auto name = struct_expr.release_name(); + EXPECT_THAT(name, Eq("foo")); + EXPECT_THAT(struct_expr.name(), IsEmpty()); +} + +TEST(StructExpr, Fields) { + StructExpr struct_expr; + EXPECT_THAT(struct_expr.fields(), IsEmpty()); + struct_expr.mutable_fields().push_back( + MakeStructExprField(1, "foo", MakeUnspecifiedExpr(1))); + ASSERT_THAT(struct_expr.fields(), SizeIs(1)); + EXPECT_EQ(struct_expr.fields()[0], + MakeStructExprField(1, "foo", MakeUnspecifiedExpr(1))); + auto fields = struct_expr.release_fields(); + static_cast(fields); + EXPECT_THAT(struct_expr.fields(), IsEmpty()); +} + +TEST(StructExpr, Equality) { + EXPECT_EQ(StructExpr{}, StructExpr{}); + StructExpr struct_expr; + struct_expr.mutable_fields().push_back( + MakeStructExprField(0, "", MakeUnspecifiedExpr(0), true)); + EXPECT_NE(StructExpr{}, struct_expr); +} + +TEST(MapExprEntry, Id) { + MapExprEntry entry; + EXPECT_THAT(entry.id(), Eq(0)); + entry.set_id(1); + EXPECT_THAT(entry.id(), Eq(1)); +} + +TEST(MapExprEntry, Key) { + MapExprEntry entry; + EXPECT_THAT(entry.has_key(), IsFalse()); + EXPECT_EQ(entry.key(), Expr{}); + entry.set_key(MakeUnspecifiedExpr(1)); + EXPECT_THAT(entry.has_key(), IsTrue()); + EXPECT_EQ(entry.key(), MakeUnspecifiedExpr(1)); + auto key = entry.release_key(); + static_cast(key); + EXPECT_THAT(entry.has_key(), IsFalse()); + EXPECT_EQ(entry.key(), Expr{}); +} + +TEST(MapExprEntry, Value) { + MapExprEntry entry; + EXPECT_THAT(entry.has_value(), IsFalse()); + EXPECT_EQ(entry.value(), Expr{}); + entry.set_value(MakeUnspecifiedExpr(1)); + EXPECT_THAT(entry.has_value(), IsTrue()); + EXPECT_EQ(entry.value(), MakeUnspecifiedExpr(1)); + auto value = entry.release_value(); + static_cast(value); + EXPECT_THAT(entry.has_value(), IsFalse()); + EXPECT_EQ(entry.value(), Expr{}); +} + +TEST(MapExprEntry, Optional) { + MapExprEntry entry; + EXPECT_THAT(entry.optional(), IsFalse()); + entry.set_optional(true); + EXPECT_THAT(entry.optional(), IsTrue()); +} + +TEST(MapExprEntry, Equality) { + EXPECT_EQ(StructExprField{}, StructExprField{}); + StructExprField field; + field.set_optional(true); + EXPECT_NE(StructExprField{}, field); +} + +TEST(MapExpr, Entries) { + MapExpr map_expr; + EXPECT_THAT(map_expr.entries(), IsEmpty()); + map_expr.mutable_entries().push_back( + MakeMapExprEntry(1, MakeUnspecifiedExpr(1), MakeUnspecifiedExpr(1))); + ASSERT_THAT(map_expr.entries(), SizeIs(1)); + EXPECT_EQ(map_expr.entries()[0], MakeMapExprEntry(1, MakeUnspecifiedExpr(1), + MakeUnspecifiedExpr(1))); + auto entries = map_expr.release_entries(); + static_cast(entries); + EXPECT_THAT(map_expr.entries(), IsEmpty()); +} + +TEST(MapExpr, Equality) { + EXPECT_EQ(MapExpr{}, MapExpr{}); + MapExpr map_expr; + map_expr.mutable_entries().push_back(MakeMapExprEntry( + 0, MakeUnspecifiedExpr(0), MakeUnspecifiedExpr(0), true)); + EXPECT_NE(MapExpr{}, map_expr); +} + +TEST(ComprehensionExpr, IterVar) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.iter_var(), IsEmpty()); + comprehension_expr.set_iter_var("foo"); + EXPECT_THAT(comprehension_expr.iter_var(), Eq("foo")); + auto iter_var = comprehension_expr.release_iter_var(); + EXPECT_THAT(iter_var, Eq("foo")); + EXPECT_THAT(comprehension_expr.iter_var(), IsEmpty()); +} + +TEST(ComprehensionExpr, IterRange) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.has_iter_range(), IsFalse()); + EXPECT_EQ(comprehension_expr.iter_range(), Expr{}); + comprehension_expr.set_iter_range(MakeUnspecifiedExpr(1)); + EXPECT_THAT(comprehension_expr.has_iter_range(), IsTrue()); + EXPECT_EQ(comprehension_expr.iter_range(), MakeUnspecifiedExpr(1)); + auto operand = comprehension_expr.release_iter_range(); + EXPECT_THAT(comprehension_expr.has_iter_range(), IsFalse()); + EXPECT_EQ(comprehension_expr.iter_range(), Expr{}); +} + +TEST(ComprehensionExpr, AccuVar) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.accu_var(), IsEmpty()); + comprehension_expr.set_accu_var("foo"); + EXPECT_THAT(comprehension_expr.accu_var(), Eq("foo")); + auto accu_var = comprehension_expr.release_accu_var(); + EXPECT_THAT(accu_var, Eq("foo")); + EXPECT_THAT(comprehension_expr.accu_var(), IsEmpty()); +} + +TEST(ComprehensionExpr, AccuInit) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.has_accu_init(), IsFalse()); + EXPECT_EQ(comprehension_expr.accu_init(), Expr{}); + comprehension_expr.set_accu_init(MakeUnspecifiedExpr(1)); + EXPECT_THAT(comprehension_expr.has_accu_init(), IsTrue()); + EXPECT_EQ(comprehension_expr.accu_init(), MakeUnspecifiedExpr(1)); + auto operand = comprehension_expr.release_accu_init(); + EXPECT_THAT(comprehension_expr.has_accu_init(), IsFalse()); + EXPECT_EQ(comprehension_expr.accu_init(), Expr{}); +} + +TEST(ComprehensionExpr, LoopCondition) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.has_loop_condition(), IsFalse()); + EXPECT_EQ(comprehension_expr.loop_condition(), Expr{}); + comprehension_expr.set_loop_condition(MakeUnspecifiedExpr(1)); + EXPECT_THAT(comprehension_expr.has_loop_condition(), IsTrue()); + EXPECT_EQ(comprehension_expr.loop_condition(), MakeUnspecifiedExpr(1)); + auto operand = comprehension_expr.release_loop_condition(); + EXPECT_THAT(comprehension_expr.has_loop_condition(), IsFalse()); + EXPECT_EQ(comprehension_expr.loop_condition(), Expr{}); +} + +TEST(ComprehensionExpr, LoopStep) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.has_loop_step(), IsFalse()); + EXPECT_EQ(comprehension_expr.loop_step(), Expr{}); + comprehension_expr.set_loop_step(MakeUnspecifiedExpr(1)); + EXPECT_THAT(comprehension_expr.has_loop_step(), IsTrue()); + EXPECT_EQ(comprehension_expr.loop_step(), MakeUnspecifiedExpr(1)); + auto operand = comprehension_expr.release_loop_step(); + EXPECT_THAT(comprehension_expr.has_loop_step(), IsFalse()); + EXPECT_EQ(comprehension_expr.loop_step(), Expr{}); +} + +TEST(ComprehensionExpr, Result) { + ComprehensionExpr comprehension_expr; + EXPECT_THAT(comprehension_expr.has_result(), IsFalse()); + EXPECT_EQ(comprehension_expr.result(), Expr{}); + comprehension_expr.set_result(MakeUnspecifiedExpr(1)); + EXPECT_THAT(comprehension_expr.has_result(), IsTrue()); + EXPECT_EQ(comprehension_expr.result(), MakeUnspecifiedExpr(1)); + auto operand = comprehension_expr.release_result(); + EXPECT_THAT(comprehension_expr.has_result(), IsFalse()); + EXPECT_EQ(comprehension_expr.result(), Expr{}); +} + +TEST(ComprehensionExpr, Equality) { + EXPECT_EQ(ComprehensionExpr{}, ComprehensionExpr{}); + ComprehensionExpr comprehension_expr; + comprehension_expr.set_result(MakeUnspecifiedExpr(1)); + EXPECT_NE(ComprehensionExpr{}, comprehension_expr); +} + +TEST(Expr, Unspecified) { + Expr expr; + EXPECT_THAT(expr.id(), Eq(ExprId{0})); + EXPECT_THAT(expr.kind(), VariantWith(_)); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Ident) { + Expr expr; + EXPECT_THAT(expr.has_ident_expr(), IsFalse()); + EXPECT_EQ(expr.ident_expr(), IdentExpr{}); + auto& ident_expr = expr.mutable_ident_expr(); + EXPECT_THAT(expr.has_ident_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + ident_expr.set_name("foo"); + EXPECT_NE(expr.ident_expr(), IdentExpr{}); + static_cast(expr.release_ident_expr()); + EXPECT_THAT(expr.has_ident_expr(), IsFalse()); + EXPECT_EQ(expr.ident_expr(), IdentExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Select) { + Expr expr; + EXPECT_THAT(expr.has_select_expr(), IsFalse()); + EXPECT_EQ(expr.select_expr(), SelectExpr{}); + auto& select_expr = expr.mutable_select_expr(); + EXPECT_THAT(expr.has_select_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + select_expr.set_field("foo"); + EXPECT_NE(expr.select_expr(), SelectExpr{}); + static_cast(expr.release_select_expr()); + EXPECT_THAT(expr.has_select_expr(), IsFalse()); + EXPECT_EQ(expr.select_expr(), SelectExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Call) { + Expr expr; + EXPECT_THAT(expr.has_call_expr(), IsFalse()); + EXPECT_EQ(expr.call_expr(), CallExpr{}); + auto& call_expr = expr.mutable_call_expr(); + EXPECT_THAT(expr.has_call_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + call_expr.set_function("foo"); + EXPECT_NE(expr.call_expr(), CallExpr{}); + static_cast(expr.release_call_expr()); + EXPECT_THAT(expr.has_call_expr(), IsFalse()); + EXPECT_EQ(expr.call_expr(), CallExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, List) { + Expr expr; + EXPECT_THAT(expr.has_list_expr(), IsFalse()); + EXPECT_EQ(expr.list_expr(), ListExpr{}); + auto& list_expr = expr.mutable_list_expr(); + EXPECT_THAT(expr.has_list_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + list_expr.mutable_elements().push_back(MakeListExprElement(Expr{}, true)); + EXPECT_NE(expr.list_expr(), ListExpr{}); + static_cast(expr.release_list_expr()); + EXPECT_THAT(expr.has_list_expr(), IsFalse()); + EXPECT_EQ(expr.list_expr(), ListExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Struct) { + Expr expr; + EXPECT_THAT(expr.has_struct_expr(), IsFalse()); + EXPECT_EQ(expr.struct_expr(), StructExpr{}); + auto& struct_expr = expr.mutable_struct_expr(); + EXPECT_THAT(expr.has_struct_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + struct_expr.set_name("foo"); + EXPECT_NE(expr.struct_expr(), StructExpr{}); + static_cast(expr.release_struct_expr()); + EXPECT_THAT(expr.has_struct_expr(), IsFalse()); + EXPECT_EQ(expr.struct_expr(), StructExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Map) { + Expr expr; + EXPECT_THAT(expr.has_map_expr(), IsFalse()); + EXPECT_EQ(expr.map_expr(), MapExpr{}); + auto& map_expr = expr.mutable_map_expr(); + EXPECT_THAT(expr.has_map_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + map_expr.mutable_entries().push_back(MakeMapExprEntry(1, Expr{}, Expr{})); + EXPECT_NE(expr.map_expr(), MapExpr{}); + static_cast(expr.release_map_expr()); + EXPECT_THAT(expr.has_map_expr(), IsFalse()); + EXPECT_EQ(expr.map_expr(), MapExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Comprehension) { + Expr expr; + EXPECT_THAT(expr.has_comprehension_expr(), IsFalse()); + EXPECT_EQ(expr.comprehension_expr(), ComprehensionExpr{}); + auto& comprehension_expr = expr.mutable_comprehension_expr(); + EXPECT_THAT(expr.has_comprehension_expr(), IsTrue()); + EXPECT_NE(expr, Expr{}); + comprehension_expr.set_iter_var("foo"); + EXPECT_NE(expr.comprehension_expr(), ComprehensionExpr{}); + static_cast(expr.release_comprehension_expr()); + EXPECT_THAT(expr.has_comprehension_expr(), IsFalse()); + EXPECT_EQ(expr.comprehension_expr(), ComprehensionExpr{}); + EXPECT_EQ(expr, Expr{}); +} + +TEST(Expr, Id) { + Expr expr; + EXPECT_THAT(expr.id(), Eq(0)); + expr.set_id(1); + EXPECT_THAT(expr.id(), Eq(1)); +} + +} // namespace +} // namespace cel diff --git a/common/constant.cc b/common/constant.cc new file mode 100644 index 000000000..f04810d47 --- /dev/null +++ b/common/constant.cc @@ -0,0 +1,36 @@ +// Copyright 2024 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. + +#include "common/constant.h" + +#include "absl/base/no_destructor.h" + +namespace cel { + +const BytesConstant& BytesConstant::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const StringConstant& StringConstant::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +const Constant& Constant::default_instance() { + static const absl::NoDestructor instance; + return *instance; +} + +} // namespace cel diff --git a/common/constant.h b/common/constant.h new file mode 100644 index 000000000..eed4327e9 --- /dev/null +++ b/common/constant.h @@ -0,0 +1,301 @@ +// Copyright 2024 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_COMMON_CONSTANT_H_ +#define THIRD_PARTY_CEL_CPP_COMMON_CONSTANT_H_ + +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "absl/types/variant.h" + +namespace cel { + +class Expr; +class Constant; +class BytesConstant; +class StringConstant; + +class BytesConstant final : public std::string { + public: + explicit BytesConstant(std::string string) : std::string(std::move(string)) {} + + explicit BytesConstant(absl::string_view string) + : BytesConstant(std::string(string)) {} + + explicit BytesConstant(const char* string) + : BytesConstant(absl::NullSafeStringView(string)) {} + + BytesConstant() = default; + BytesConstant(const BytesConstant&) = default; + BytesConstant(BytesConstant&&) = default; + BytesConstant& operator=(const BytesConstant&) = default; + BytesConstant& operator=(BytesConstant&&) = default; + + BytesConstant(const StringConstant&) = delete; + BytesConstant(StringConstant&&) = delete; + BytesConstant& operator=(const StringConstant&) = delete; + BytesConstant& operator=(StringConstant&&) = delete; + + private: + static const BytesConstant& default_instance(); + + friend class Constant; +}; + +class StringConstant final : public std::string { + public: + explicit StringConstant(std::string string) + : std::string(std::move(string)) {} + + explicit StringConstant(absl::string_view string) + : StringConstant(std::string(string)) {} + + explicit StringConstant(const char* string) + : StringConstant(absl::NullSafeStringView(string)) {} + + StringConstant() = default; + StringConstant(const StringConstant&) = default; + StringConstant(StringConstant&&) = default; + StringConstant& operator=(const StringConstant&) = default; + StringConstant& operator=(StringConstant&&) = default; + + StringConstant(const BytesConstant&) = delete; + StringConstant(BytesConstant&&) = delete; + StringConstant& operator=(const BytesConstant&) = delete; + StringConstant& operator=(BytesConstant&&) = delete; + + private: + static const StringConstant& default_instance(); + + friend class Constant; +}; + +// Constant is a variant composed of all the literal types support by the Common +// Expression Language. +using ConstantKind = absl::variant; + +// Represents a primitive literal. +// +// This is similar as the primitives supported in the well-known type +// `google.protobuf.Value`, but richer so it can represent CEL's full range of +// primitives. +// +// Lists and structs are not included as constants as these aggregate types may +// contain [Expr][] elements which require evaluation and are thus not constant. +// +// Examples of constants include: `"hello"`, `b'bytes'`, `1u`, `4.2`, `-2`, +// `true`, `null`. +class Constant final { + public: + Constant() = default; + Constant(const Constant&) = default; + Constant(Constant&&) = default; + Constant& operator=(const Constant&) = default; + Constant& operator=(Constant&&) = default; + + ABSL_MUST_USE_RESULT const ConstantKind& kind() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return kind_; + } + + ABSL_MUST_USE_RESULT bool has_null_value() const { + return absl::holds_alternative(kind()); + } + + void set_null_value() { mutable_kind().emplace(); } + + ABSL_MUST_USE_RESULT bool has_bool_value() const { + return absl::holds_alternative(kind()); + } + + void set_bool_value(bool value) { mutable_kind().emplace(value); } + + ABSL_MUST_USE_RESULT bool bool_value() const { return get_value(); } + + ABSL_MUST_USE_RESULT bool has_int_value() const { + return absl::holds_alternative(kind()); + } + + void set_int_value(int64_t value) { mutable_kind().emplace(value); } + + ABSL_MUST_USE_RESULT int64_t int_value() const { + return get_value(); + } + + ABSL_MUST_USE_RESULT bool has_uint_value() const { + return absl::holds_alternative(kind()); + } + + void set_uint_value(uint64_t value) { + mutable_kind().emplace(value); + } + + ABSL_MUST_USE_RESULT uint64_t uint_value() const { + return get_value(); + } + + ABSL_MUST_USE_RESULT bool has_double_value() const { + return absl::holds_alternative(kind()); + } + + void set_double_value(double value) { mutable_kind().emplace(value); } + + ABSL_MUST_USE_RESULT double double_value() const { + return get_value(); + } + + ABSL_MUST_USE_RESULT bool has_bytes_value() const { + return absl::holds_alternative(kind()); + } + + void set_bytes_value(BytesConstant value) { + mutable_kind().emplace(std::move(value)); + } + + void set_bytes_value(std::string value) { + set_bytes_value(BytesConstant{std::move(value)}); + } + + void set_bytes_value(absl::string_view value) { + set_bytes_value(BytesConstant{value}); + } + + void set_bytes_value(const char* value) { + set_bytes_value(absl::NullSafeStringView(value)); + } + + ABSL_MUST_USE_RESULT const std::string& bytes_value() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (const auto* alt = absl::get_if(&kind()); alt) { + return *alt; + } + return BytesConstant::default_instance(); + } + + ABSL_MUST_USE_RESULT std::string release_bytes_value() { + std::string string; + if (auto* alt = absl::get_if(&mutable_kind()); alt) { + string.swap(*alt); + } + mutable_kind().emplace(); + return string; + } + + ABSL_MUST_USE_RESULT bool has_string_value() const { + return absl::holds_alternative(kind()); + } + + void set_string_value(StringConstant value) { + mutable_kind().emplace(std::move(value)); + } + + void set_string_value(std::string value) { + set_string_value(StringConstant{std::move(value)}); + } + + void set_string_value(absl::string_view value) { + set_string_value(StringConstant{value}); + } + + void set_string_value(const char* value) { + set_string_value(absl::NullSafeStringView(value)); + } + + ABSL_MUST_USE_RESULT const std::string& string_value() const + ABSL_ATTRIBUTE_LIFETIME_BOUND { + if (const auto* alt = absl::get_if(&kind()); alt) { + return *alt; + } + return StringConstant::default_instance(); + } + + ABSL_MUST_USE_RESULT std::string release_string_value() { + std::string string; + if (auto* alt = absl::get_if(&mutable_kind()); alt) { + string.swap(*alt); + } + mutable_kind().emplace(); + return string; + } + + ABSL_DEPRECATED("duration is no longer considered a builtin type") + ABSL_MUST_USE_RESULT bool has_duration_value() const { + return absl::holds_alternative(kind()); + } + + ABSL_DEPRECATED("duration is no longer considered a builtin type") + void set_duration_value(absl::Duration value) { + mutable_kind().emplace(value); + } + + ABSL_DEPRECATED("duration is no longer considered a builtin type") + ABSL_MUST_USE_RESULT absl::Duration duration_value() const { + return get_value(); + } + + ABSL_DEPRECATED("timestamp is no longer considered a builtin type") + ABSL_MUST_USE_RESULT bool has_timestamp_value() const { + return absl::holds_alternative(kind()); + } + + ABSL_DEPRECATED("timestamp is no longer considered a builtin type") + void set_timestamp_value(absl::Time value) { + mutable_kind().emplace(value); + } + + ABSL_DEPRECATED("timestamp is no longer considered a builtin type") + ABSL_MUST_USE_RESULT absl::Time timestamp_value() const { + return get_value(); + } + + private: + friend class Expr; + + static const Constant& default_instance(); + + ABSL_MUST_USE_RESULT ConstantKind& mutable_kind() + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return kind_; + } + + template + T get_value() const { + if (const auto* alt = absl::get_if(&kind()); alt) { + return *alt; + } + return T{}; + } + + ConstantKind kind_; +}; + +inline bool operator==(const Constant& lhs, const Constant& rhs) { + return lhs.kind() == rhs.kind(); +} + +inline bool operator!=(const Constant& lhs, const Constant& rhs) { + return lhs.kind() != rhs.kind(); +} + +} // namespace cel + +#endif // THIRD_PARTY_CEL_CPP_COMMON_CONSTANT_H_ diff --git a/common/constant_test.cc b/common/constant_test.cc new file mode 100644 index 000000000..f56bdfafd --- /dev/null +++ b/common/constant_test.cc @@ -0,0 +1,217 @@ +// Copyright 2024 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. + +#include "common/constant.h" + +#include "absl/time/time.h" +#include "internal/testing.h" + +namespace cel { +namespace { + +using testing::IsEmpty; +using testing::IsFalse; +using testing::IsTrue; + +TEST(Constant, NullValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_null_value(), IsFalse()); + const_expr.set_null_value(); + EXPECT_THAT(const_expr.has_null_value(), IsTrue()); +} + +TEST(Constant, BoolValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_bool_value(), IsFalse()); + EXPECT_EQ(const_expr.bool_value(), false); + const_expr.set_bool_value(false); + EXPECT_THAT(const_expr.has_bool_value(), IsTrue()); + EXPECT_EQ(const_expr.bool_value(), false); +} + +TEST(Constant, IntValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_int_value(), IsFalse()); + EXPECT_EQ(const_expr.int_value(), 0); + const_expr.set_int_value(0); + EXPECT_THAT(const_expr.has_int_value(), IsTrue()); + EXPECT_EQ(const_expr.int_value(), 0); +} + +TEST(Constant, UintValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_uint_value(), IsFalse()); + EXPECT_EQ(const_expr.uint_value(), 0); + const_expr.set_uint_value(0); + EXPECT_THAT(const_expr.has_uint_value(), IsTrue()); + EXPECT_EQ(const_expr.uint_value(), 0); +} + +TEST(Constant, DoubleValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_double_value(), IsFalse()); + EXPECT_EQ(const_expr.double_value(), 0); + const_expr.set_double_value(0); + EXPECT_THAT(const_expr.has_double_value(), IsTrue()); + EXPECT_EQ(const_expr.double_value(), 0); +} + +TEST(Constant, BytesValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_bytes_value(), IsFalse()); + EXPECT_THAT(const_expr.bytes_value(), IsEmpty()); + const_expr.set_bytes_value("foo"); + EXPECT_THAT(const_expr.has_bytes_value(), IsTrue()); + EXPECT_EQ(const_expr.bytes_value(), "foo"); +} + +TEST(Constant, StringValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_string_value(), IsFalse()); + EXPECT_THAT(const_expr.string_value(), IsEmpty()); + const_expr.set_string_value("foo"); + EXPECT_THAT(const_expr.has_string_value(), IsTrue()); + EXPECT_EQ(const_expr.string_value(), "foo"); +} + +TEST(Constant, DurationValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_duration_value(), IsFalse()); + EXPECT_EQ(const_expr.duration_value(), absl::ZeroDuration()); + const_expr.set_duration_value(absl::ZeroDuration()); + EXPECT_THAT(const_expr.has_duration_value(), IsTrue()); + EXPECT_EQ(const_expr.duration_value(), absl::ZeroDuration()); +} + +TEST(Constant, TimestampValue) { + Constant const_expr; + EXPECT_THAT(const_expr.has_timestamp_value(), IsFalse()); + EXPECT_EQ(const_expr.timestamp_value(), absl::UnixEpoch()); + const_expr.set_timestamp_value(absl::UnixEpoch()); + EXPECT_THAT(const_expr.has_timestamp_value(), IsTrue()); + EXPECT_EQ(const_expr.timestamp_value(), absl::UnixEpoch()); +} + +TEST(Constant, Equality) { + EXPECT_EQ(Constant{}, Constant{}); + + Constant lhs_const_expr; + Constant rhs_const_expr; + + lhs_const_expr.set_null_value(); + rhs_const_expr.set_null_value(); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_bool_value(false); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_bool_value(false); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_int_value(0); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_int_value(0); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_uint_value(0); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_uint_value(0); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_double_value(0); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_double_value(0); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_bytes_value("foo"); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_bytes_value("foo"); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_string_value("foo"); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_string_value("foo"); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_duration_value(absl::ZeroDuration()); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_duration_value(absl::ZeroDuration()); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + + lhs_const_expr.set_timestamp_value(absl::UnixEpoch()); + rhs_const_expr.set_null_value(); + EXPECT_NE(lhs_const_expr, rhs_const_expr); + EXPECT_NE(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); + rhs_const_expr.set_timestamp_value(absl::UnixEpoch()); + EXPECT_EQ(lhs_const_expr, rhs_const_expr); + EXPECT_EQ(rhs_const_expr, lhs_const_expr); + EXPECT_NE(lhs_const_expr, Constant{}); + EXPECT_NE(Constant{}, rhs_const_expr); +} + +} // namespace +} // namespace cel