1*f88b2170SEd Tanous #pragma once 2*f88b2170SEd Tanous 3*f88b2170SEd Tanous #include "filter_expr_parser_ast.hpp" 4*f88b2170SEd Tanous 5*f88b2170SEd Tanous #include <boost/spirit/home/x3.hpp> 6*f88b2170SEd Tanous 7*f88b2170SEd Tanous namespace redfish::filter_grammar 8*f88b2170SEd Tanous { 9*f88b2170SEd Tanous 10*f88b2170SEd Tanous // The below rules very intentionally use the same naming as section 7.3.4 of 11*f88b2170SEd Tanous // the redfish specification and are declared in the order of the precedence 12*f88b2170SEd Tanous // that the standard requires. 13*f88b2170SEd Tanous 14*f88b2170SEd Tanous namespace details 15*f88b2170SEd Tanous { 16*f88b2170SEd Tanous using boost::spirit::x3::char_; 17*f88b2170SEd Tanous using boost::spirit::x3::int64; 18*f88b2170SEd Tanous using boost::spirit::x3::lit; 19*f88b2170SEd Tanous using boost::spirit::x3::real_parser; 20*f88b2170SEd Tanous using boost::spirit::x3::rule; 21*f88b2170SEd Tanous using boost::spirit::x3::strict_real_policies; 22*f88b2170SEd Tanous using boost::spirit::x3::symbols; 23*f88b2170SEd Tanous 24*f88b2170SEd Tanous using filter_ast::BooleanOp; 25*f88b2170SEd Tanous using filter_ast::Comparison; 26*f88b2170SEd Tanous using filter_ast::ComparisonOpEnum; 27*f88b2170SEd Tanous using filter_ast::LogicalAnd; 28*f88b2170SEd Tanous using filter_ast::LogicalNot; 29*f88b2170SEd Tanous using filter_ast::LogicalOr; 30*f88b2170SEd Tanous using filter_ast::QuotedString; 31*f88b2170SEd Tanous using filter_ast::UnquotedString; 32*f88b2170SEd Tanous 33*f88b2170SEd Tanous // Clang format makes a mess of these rules and makes them hard to read 34*f88b2170SEd Tanous // clang-format on 35*f88b2170SEd Tanous 36*f88b2170SEd Tanous // Basic argument types 37*f88b2170SEd Tanous const rule<class QuotedStringId, QuotedString> quotedString("QuotedString"); 38*f88b2170SEd Tanous const rule<class UnquotedStrId, UnquotedString> unquotedString("UnquotedStr"); 39*f88b2170SEd Tanous 40*f88b2170SEd Tanous // Value comparisons -> boolean (value eq value) (value lt number) 41*f88b2170SEd Tanous const rule<class BooleanOpId, BooleanOp> booleanOp("BooleanOp"); 42*f88b2170SEd Tanous const rule<class ComparisonId, Comparison> comparison("Comparison"); 43*f88b2170SEd Tanous 44*f88b2170SEd Tanous // Logical Comparisons (bool eq bool) 45*f88b2170SEd Tanous const rule<class LogicalAndId, LogicalAnd> logicalAnd("LogicalAnd"); 46*f88b2170SEd Tanous const rule<class LogicalOrId, LogicalOr> logicalOr("LogicalOr"); 47*f88b2170SEd Tanous const rule<class LogicalNotId, LogicalNot> logicalNot("LogicalNot"); 48*f88b2170SEd Tanous 49*f88b2170SEd Tanous ///// BEGIN GRAMMAR 50*f88b2170SEd Tanous 51*f88b2170SEd Tanous // Two types of strings. 52*f88b2170SEd Tanous const auto quotedString_def = '\'' >> *('\\' >> char_ | ~char_('\'')) >> '\''; 53*f88b2170SEd Tanous const auto unquotedString_def = char_("a-zA-Z") >> *(char_("a-zA-Z0-9[]/")); 54*f88b2170SEd Tanous 55*f88b2170SEd Tanous // Spaces 56*f88b2170SEd Tanous // Filter examples have unclear guidelines about between which arguments spaces 57*f88b2170SEd Tanous // are allowed or disallowed. Specification is not clear, so in almost all 58*f88b2170SEd Tanous // cases we allow zero or more 59*f88b2170SEd Tanous const auto sp = *lit(' '); 60*f88b2170SEd Tanous 61*f88b2170SEd Tanous // Make sure we only parse true floating points as doubles 62*f88b2170SEd Tanous // This requires we have a "." which causes 1 to parse as int64, and 1.0 to 63*f88b2170SEd Tanous // parse as double 64*f88b2170SEd Tanous constexpr const real_parser<double, strict_real_policies<double>> strictDouble; 65*f88b2170SEd Tanous 66*f88b2170SEd Tanous // Argument 67*f88b2170SEd Tanous const auto arg = strictDouble | int64 | unquotedString | quotedString; 68*f88b2170SEd Tanous 69*f88b2170SEd Tanous // Note, unlike most other comparisons, spaces are required here (one or more) 70*f88b2170SEd Tanous // to differentiate keys from values (ex Fooeq eq foo) 71*f88b2170SEd Tanous const auto rsp = +lit(' '); 72*f88b2170SEd Tanous 73*f88b2170SEd Tanous // Greater Than/Less Than/Equals 74*f88b2170SEd Tanous const symbols<ComparisonOpEnum> compare{ 75*f88b2170SEd Tanous {"gt", ComparisonOpEnum::GreaterThan}, 76*f88b2170SEd Tanous {"ge", ComparisonOpEnum::GreaterThanOrEqual}, 77*f88b2170SEd Tanous {"lt", ComparisonOpEnum::LessThan}, 78*f88b2170SEd Tanous {"le", ComparisonOpEnum::LessThanOrEqual}, 79*f88b2170SEd Tanous {"ne", ComparisonOpEnum::NotEquals}, 80*f88b2170SEd Tanous {"eq", ComparisonOpEnum::Equals}}; 81*f88b2170SEd Tanous 82*f88b2170SEd Tanous const auto comparison_def = arg >> rsp >> compare >> rsp >> arg; 83*f88b2170SEd Tanous 84*f88b2170SEd Tanous // Parenthesis 85*f88b2170SEd Tanous const auto parens = lit('(') >> sp >> logicalAnd >> sp >> lit(')'); 86*f88b2170SEd Tanous 87*f88b2170SEd Tanous // Logical values 88*f88b2170SEd Tanous const auto booleanOp_def = comparison | parens; 89*f88b2170SEd Tanous 90*f88b2170SEd Tanous // Not 91*f88b2170SEd Tanous const auto logicalNot_def = -(char_('n') >> lit("ot") >> sp) >> booleanOp; 92*f88b2170SEd Tanous 93*f88b2170SEd Tanous // Or 94*f88b2170SEd Tanous const auto logicalOr_def = logicalNot >> *(sp >> lit("or") >> sp >> logicalNot); 95*f88b2170SEd Tanous 96*f88b2170SEd Tanous // And 97*f88b2170SEd Tanous const auto logicalAnd_def = logicalOr >> *(sp >> lit("and") >> sp >> logicalOr); 98*f88b2170SEd Tanous 99*f88b2170SEd Tanous BOOST_SPIRIT_DEFINE(booleanOp, logicalAnd, logicalNot, logicalOr, quotedString, 100*f88b2170SEd Tanous comparison, unquotedString); 101*f88b2170SEd Tanous ///// END GRAMMAR 102*f88b2170SEd Tanous 103*f88b2170SEd Tanous // Make the grammar and AST available outside of the system 104*f88b2170SEd Tanous static constexpr auto& grammar = logicalAnd; 105*f88b2170SEd Tanous using program = filter_ast::LogicalAnd; 106*f88b2170SEd Tanous 107*f88b2170SEd Tanous } // namespace details 108*f88b2170SEd Tanous 109*f88b2170SEd Tanous using details::grammar; 110*f88b2170SEd Tanous using details::program; 111*f88b2170SEd Tanous 112*f88b2170SEd Tanous } // namespace redfish::filter_grammar 113