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