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