See More

// Copyright 2021 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 "parser/macro.h" #include #include #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "common/operators.h" #include "internal/lexis.h" #include "parser/source_factory.h" namespace cel { namespace { using google::api::expr::v1alpha1::Expr; using google::api::expr::common::CelOperator; absl::StatusOr MakeMacro(absl::string_view name, size_t argument_count, MacroExpander expander, bool is_receiver_style) { if (!internal::LexisIsIdentifier(name)) { return absl::InvalidArgumentError(absl::StrCat( "Macro function name \"", name, "\" is not a valid identifier")); } if (!expander) { return absl::InvalidArgumentError( absl::StrCat("Macro expander for \"", name, "\" cannot be empty")); } return Macro(name, argument_count, std::move(expander), is_receiver_style); } absl::StatusOr MakeMacro(absl::string_view name, MacroExpander expander, bool is_receiver_style) { if (!internal::LexisIsIdentifier(name)) { return absl::InvalidArgumentError(absl::StrCat( "Macro function name \"", name, "\" is not a valid identifier")); } if (!expander) { return absl::InvalidArgumentError( absl::StrCat("Macro expander for \"", name, "\" cannot be empty")); } return Macro(name, std::move(expander), is_receiver_style); } } // namespace absl::StatusOr Macro::Global(absl::string_view name, size_t argument_count, MacroExpander expander) { return MakeMacro(name, argument_count, std::move(expander), false); } absl::StatusOr Macro::GlobalVarArg(absl::string_view name, MacroExpander expander) { return MakeMacro(name, std::move(expander), false); } absl::StatusOr Macro::Receiver(absl::string_view name, size_t argument_count, MacroExpander expander) { return MakeMacro(name, argument_count, std::move(expander), true); } absl::StatusOr Macro::ReceiverVarArg(absl::string_view name, MacroExpander expander) { return MakeMacro(name, std::move(expander), true); } std::vector Macro::AllMacros() { return { // The macro "has(m.f)" which tests the presence of a field, avoiding the // need to specify the field as a string. Macro(CelOperator::HAS, 1, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { if (!args.empty() && args[0].has_select_expr()) { const auto& sel_expr = args[0].select_expr(); return sf->NewPresenceTestForMacro(macro_id, sel_expr.operand(), sel_expr.field()); } else { // error return Expr(); } }), // The macro "range.all(var, predicate)", which is true if for all // elements // in range the predicate holds. Macro( CelOperator::ALL, 2, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewQuantifierExprForMacro(SourceFactory::QUANTIFIER_ALL, macro_id, target, args); }, /* receiver style*/ true), // The macro "range.exists(var, predicate)", which is true if for at least // one element in range the predicate holds. Macro( CelOperator::EXISTS, 2, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewQuantifierExprForMacro( SourceFactory::QUANTIFIER_EXISTS, macro_id, target, args); }, /* receiver style*/ true), // The macro "range.exists_one(var, predicate)", which is true if for // exactly one element in range the predicate holds. Macro( CelOperator::EXISTS_ONE, 2, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewQuantifierExprForMacro( SourceFactory::QUANTIFIER_EXISTS_ONE, macro_id, target, args); }, /* receiver style*/ true), // The macro "range.map(var, function)", applies the function to the vars // in // the range. Macro( CelOperator::MAP, 2, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewMapForMacro(macro_id, target, args); }, /* receiver style*/ true), // The macro "range.map(var, predicate, function)", applies the function // to // the vars in the range for which the predicate holds true. The other // variables are filtered out. Macro( CelOperator::MAP, 3, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewMapForMacro(macro_id, target, args); }, /* receiver style*/ true), // The macro "range.filter(var, predicate)", filters out the variables for // which the // predicate is false. Macro( CelOperator::FILTER, 2, [](const std::shared_ptr& sf, int64_t macro_id, const Expr& target, const std::vector& args) { return sf->NewFilterExprForMacro(macro_id, target, args); }, /* receiver style*/ true), }; } } // namespace cel