Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I stringify a Boost Phoenix expression?

Can I convert a Boost Phoenix expression into a representative string of C++? I could have:

stringify(_1<_2);

which might then produce a string containing something like:

template <class T1, class T2>
struct foo {
  auto operator()(T1 x1, T2 x2)
  -> decltype(x1 < x2)
  { return    x1 < x2; }
};

I appreciate this example has some rough edges, but I wonder if anything along these lines has been attempted?

like image 710
user2023370 Avatar asked Nov 12 '22 08:11

user2023370


1 Answers

Using the transform eval that you can find here as "inspiration".

Live example.

#include <iostream>
#include <string>
#include <sstream>

#include <boost/phoenix.hpp>
#include <boost/phoenix/core/arity.hpp>
#include <boost/lexical_cast.hpp>

namespace phx=boost::phoenix;
namespace proto=boost::proto;

struct do_print : proto::callable
{
    typedef std::string result_type;

    template <typename NotArgument>
    std::string operator()(NotArgument n)
    {
       return boost::lexical_cast<std::string>(n);
    }

    template <int I>
    std::string operator()(phx::argument<I>)
    {
       return std::string("x")+boost::lexical_cast<std::string>(I-1);
    }

#define UNARY_OP(TAG, OP)                                                       \
    template<typename Arg>                                                      \
    std::string operator()(proto::tag::TAG, Arg arg) const                           \
    {                                                                           \
        return std::string("(") + OP + arg + ")";                                                          \
    }                                                                           \
    /**/

#define BINARY_OP(TAG, OP)                                                      \
    template<typename Left, typename Right>                                     \
    std::string operator()(proto::tag::TAG, Left left, Right right) const            \
    {                                                                           \
        return std::string("(") + left + OP + right + ")";                                                   \
    }                                                                           \
    /**/

    UNARY_OP(negate, "-")
    BINARY_OP(plus, "+")
    BINARY_OP(minus, "-")
    BINARY_OP(multiplies, "*")
    BINARY_OP(divides, "/")
    BINARY_OP(less, "<")
    BINARY_OP(greater, ">")
    /*... others ...*/
};

struct print_expression
  : proto::or_<
        proto::when<proto::terminal<proto::_>, do_print(proto::_value)>
      , proto::otherwise<do_print(proto::tag_of<proto::_>(), print_expression(proto::pack(proto::_))...)>
    >
{};

struct do_get_arity : proto::callable
{
    typedef int result_type;

    template <typename NotArgument>
    int operator()(NotArgument)
    {
       return 0;
    }

    template <int I>
    int operator()(phx::argument<I>)
    {
       return I;
    }


    template<typename Tag, typename Arg>                                                      
    int operator()(Tag, Arg arg) const                           
    {                                                                           
        return arg;                                                         
    }                                                                           
    /**/

    template<typename Tag, typename Left, typename Right>                                    
    int operator()(Tag, Left left, Right right) const           
    {                                                                          
        return std::max(left,right);                                                   \
    }                                                                           

};

struct get_arity
  : proto::or_<
        proto::when<proto::terminal<proto::_>, do_get_arity(proto::_value)>
      , proto::otherwise<do_get_arity(proto::tag_of<proto::_>(),get_arity(proto::pack(proto::_))...)>
    >
{};




template <typename Expr>
std::string stringify(const Expr& expr, const std::string& name="foo")
{
   std::stringstream result;
   int current_arg;
   int arity= get_arity()(expr); 

   result << "template <";

   for(current_arg=0;current_arg<arity-1; ++current_arg)
      result << " typename T" << current_arg << ",";
   result << " typename T" << current_arg;

   result << " >\n";
   result << "struct " << name << " {\n\t";
   result << "auto operator()(";

   for(current_arg=0;current_arg<arity-1; ++current_arg)
      result << " T" << current_arg << " x" << current_arg << ",";
   result << " T" << current_arg << " x" << current_arg;
   result << " )\n\t\t-> typename std::remove_reference< decltype( " << print_expression()(expr) << " ) >::type\n";
   result << "\t{ return " << print_expression()(expr) << "; }\n";
   result << "};\n";

   return result.str();
}

int main()
{
   using phx::placeholders::_1; 
   using phx::placeholders::_2;
   using phx::placeholders::_3;
   std::cout << stringify(-_1) << std::endl;
   std::cout << stringify(_1+_2) << std::endl;
   std::cout << stringify(_1+_2*_3) << std::endl;

   std::cout << stringify((_1+_2)*_3) << std::endl;
   std::cout << stringify(_1>2) << std::endl;
   std::cout << stringify(_1*(-_2)) << std::endl;
   return 0;
}
like image 59
user2224125 Avatar answered Nov 15 '22 06:11

user2224125