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