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