1*f88b2170SEd Tanous #include "filter_expr_printer.hpp"
2*f88b2170SEd Tanous 
3*f88b2170SEd Tanous #include "filter_expr_parser_ast.hpp"
4*f88b2170SEd Tanous #include "filter_expr_parser_grammar.hpp"
5*f88b2170SEd Tanous #include "logging.hpp"
6*f88b2170SEd Tanous 
7*f88b2170SEd Tanous #include <iostream>
8*f88b2170SEd Tanous #include <list>
9*f88b2170SEd Tanous #include <numeric>
10*f88b2170SEd Tanous #include <optional>
11*f88b2170SEd Tanous #include <string>
12*f88b2170SEd Tanous 
13*f88b2170SEd Tanous namespace redfish
14*f88b2170SEd Tanous {
15*f88b2170SEd Tanous 
16*f88b2170SEd Tanous ///////////////////////////////////////////////////////////////////////////
17*f88b2170SEd Tanous //  The AST Printer
18*f88b2170SEd Tanous //  Prints a $filter AST as a string to be compared, including explicit braces
19*f88b2170SEd Tanous //  around all operations to help debugging AST issues.
20*f88b2170SEd Tanous ///////////////////////////////////////////////////////////////////////////
21*f88b2170SEd Tanous 
22*f88b2170SEd Tanous using result_type = std::string;
23*f88b2170SEd Tanous std::string FilterExpressionPrinter::operator()(double x) const
24*f88b2170SEd Tanous {
25*f88b2170SEd Tanous     return std::format("double({})", x);
26*f88b2170SEd Tanous }
27*f88b2170SEd Tanous std::string FilterExpressionPrinter::operator()(int64_t x) const
28*f88b2170SEd Tanous {
29*f88b2170SEd Tanous     return std::format("int({})", x);
30*f88b2170SEd Tanous }
31*f88b2170SEd Tanous std::string
32*f88b2170SEd Tanous     FilterExpressionPrinter::operator()(const filter_ast::QuotedString& x) const
33*f88b2170SEd Tanous {
34*f88b2170SEd Tanous     return std::format("quoted_string(\"{}\")", static_cast<std::string>(x));
35*f88b2170SEd Tanous }
36*f88b2170SEd Tanous std::string FilterExpressionPrinter::operator()(
37*f88b2170SEd Tanous     const filter_ast::UnquotedString& x) const
38*f88b2170SEd Tanous {
39*f88b2170SEd Tanous     return std::format("unquoted_string(\"{}\")", static_cast<std::string>(x));
40*f88b2170SEd Tanous }
41*f88b2170SEd Tanous 
42*f88b2170SEd Tanous std::string
43*f88b2170SEd Tanous     FilterExpressionPrinter::operator()(const filter_ast::LogicalNot& x) const
44*f88b2170SEd Tanous {
45*f88b2170SEd Tanous     std::string prefix;
46*f88b2170SEd Tanous     std::string postfix;
47*f88b2170SEd Tanous     if (x.isLogicalNot)
48*f88b2170SEd Tanous     {
49*f88b2170SEd Tanous         prefix = "not(";
50*f88b2170SEd Tanous         postfix = ")";
51*f88b2170SEd Tanous     }
52*f88b2170SEd Tanous     return std::format("{}{}{}", prefix, (*this)(x.operand), postfix);
53*f88b2170SEd Tanous }
54*f88b2170SEd Tanous std::string
55*f88b2170SEd Tanous     FilterExpressionPrinter::operator()(const filter_ast::LogicalOr& x) const
56*f88b2170SEd Tanous {
57*f88b2170SEd Tanous     std::string prefix;
58*f88b2170SEd Tanous     std::string postfix;
59*f88b2170SEd Tanous     if (!x.rest.empty())
60*f88b2170SEd Tanous     {
61*f88b2170SEd Tanous         prefix = "(";
62*f88b2170SEd Tanous         postfix = ")";
63*f88b2170SEd Tanous     }
64*f88b2170SEd Tanous     std::string out = std::format("{}{}{}", prefix, (*this)(x.first), postfix);
65*f88b2170SEd Tanous 
66*f88b2170SEd Tanous     for (const filter_ast::LogicalNot& oper : x.rest)
67*f88b2170SEd Tanous     {
68*f88b2170SEd Tanous         out += std::format(" or ({})", (*this)(oper));
69*f88b2170SEd Tanous     }
70*f88b2170SEd Tanous     return out;
71*f88b2170SEd Tanous }
72*f88b2170SEd Tanous 
73*f88b2170SEd Tanous std::string
74*f88b2170SEd Tanous     FilterExpressionPrinter::operator()(const filter_ast::LogicalAnd& x) const
75*f88b2170SEd Tanous {
76*f88b2170SEd Tanous     std::string prefix;
77*f88b2170SEd Tanous     std::string postfix;
78*f88b2170SEd Tanous     if (!x.rest.empty())
79*f88b2170SEd Tanous     {
80*f88b2170SEd Tanous         prefix = "(";
81*f88b2170SEd Tanous         postfix = ")";
82*f88b2170SEd Tanous     }
83*f88b2170SEd Tanous     std::string out = std::format("{}{}{}", prefix, (*this)(x.first), postfix);
84*f88b2170SEd Tanous 
85*f88b2170SEd Tanous     for (const filter_ast::LogicalOr& oper : x.rest)
86*f88b2170SEd Tanous     {
87*f88b2170SEd Tanous         out += std::format(" and ({})", (*this)(oper));
88*f88b2170SEd Tanous     }
89*f88b2170SEd Tanous     return out;
90*f88b2170SEd Tanous }
91*f88b2170SEd Tanous 
92*f88b2170SEd Tanous static std::string toString(filter_ast::ComparisonOpEnum rel)
93*f88b2170SEd Tanous {
94*f88b2170SEd Tanous     switch (rel)
95*f88b2170SEd Tanous     {
96*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::GreaterThan:
97*f88b2170SEd Tanous             return "Greater Than";
98*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::GreaterThanOrEqual:
99*f88b2170SEd Tanous             return "Greater Than Or Equal";
100*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::LessThan:
101*f88b2170SEd Tanous             return "Less Than";
102*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::LessThanOrEqual:
103*f88b2170SEd Tanous             return "Less Than Or Equal";
104*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::Equals:
105*f88b2170SEd Tanous             return "Equals";
106*f88b2170SEd Tanous         case filter_ast::ComparisonOpEnum::NotEquals:
107*f88b2170SEd Tanous             return "Not Equal";
108*f88b2170SEd Tanous         default:
109*f88b2170SEd Tanous             return "Invalid";
110*f88b2170SEd Tanous     }
111*f88b2170SEd Tanous }
112*f88b2170SEd Tanous 
113*f88b2170SEd Tanous std::string
114*f88b2170SEd Tanous     FilterExpressionPrinter::operator()(const filter_ast::Comparison& x) const
115*f88b2170SEd Tanous {
116*f88b2170SEd Tanous     std::string left = boost::apply_visitor(*this, x.left);
117*f88b2170SEd Tanous     std::string right = boost::apply_visitor(*this, x.right);
118*f88b2170SEd Tanous 
119*f88b2170SEd Tanous     return std::format("{} {} {}", left, toString(x.token), right);
120*f88b2170SEd Tanous }
121*f88b2170SEd Tanous 
122*f88b2170SEd Tanous std::string FilterExpressionPrinter::operator()(
123*f88b2170SEd Tanous     const filter_ast::BooleanOp& operation) const
124*f88b2170SEd Tanous {
125*f88b2170SEd Tanous     return boost::apply_visitor(*this, operation);
126*f88b2170SEd Tanous }
127*f88b2170SEd Tanous 
128*f88b2170SEd Tanous std::optional<filter_grammar::program> parseFilter(std::string_view expr)
129*f88b2170SEd Tanous {
130*f88b2170SEd Tanous     const auto& grammar = filter_grammar::grammar;
131*f88b2170SEd Tanous     filter_grammar::program program;
132*f88b2170SEd Tanous 
133*f88b2170SEd Tanous     std::string_view::iterator iter = expr.begin();
134*f88b2170SEd Tanous     const std::string_view::iterator end = expr.end();
135*f88b2170SEd Tanous     BMCWEB_LOG_DEBUG("Parsing input string \"{}\"", expr);
136*f88b2170SEd Tanous     bool r = boost::spirit::x3::parse(iter, end, grammar, program);
137*f88b2170SEd Tanous 
138*f88b2170SEd Tanous     if (!r)
139*f88b2170SEd Tanous     {
140*f88b2170SEd Tanous         std::string rest(iter, end);
141*f88b2170SEd Tanous 
142*f88b2170SEd Tanous         BMCWEB_LOG_ERROR("Parsing failed stopped at \"{}\"", rest);
143*f88b2170SEd Tanous         return std::nullopt;
144*f88b2170SEd Tanous     }
145*f88b2170SEd Tanous     BMCWEB_LOG_DEBUG("Parsed AST: \"{}\"", FilterExpressionPrinter()(program));
146*f88b2170SEd Tanous     return {std::move(program)};
147*f88b2170SEd Tanous }
148*f88b2170SEd Tanous } // namespace redfish
149