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