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