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