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