1 /*==============================================================================
2     Copyright (c) 2005-2010 Joel de Guzman
3     Copyright (c) 2010 Thomas Heller
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 
9 #include <boost/phoenix/phoenix.hpp>
10 #include <boost/proto/proto.hpp>
11 #include <boost/proto/debug.hpp>
12 
13 namespace phoenix = boost::phoenix;
14 namespace proto = boost::proto;
15 
16 using phoenix::evaluator;
17 
18 #ifdef _MSC_VER
19 // redifining evaluator, this is because MSVC chokes on function types like:
20 // F(G(...))
21 #define evaluator(A0, A1) proto::call<phoenix::evaluator(A0, A1)>
22 #endif
23 
24 struct invert_actions
25 {
26     template <typename Rule>
27     struct when
28         : proto::nary_expr<
29               proto::_
30             , proto::vararg<
31                   proto::when<proto::_, evaluator(proto::_, phoenix::_context)>
32               >
33           >
34     {};
35 };
36 
37 template <>
38 struct invert_actions::when<phoenix::rule::plus>
39     : proto::call<
40         phoenix::functional::make_minus(
41             evaluator(proto::_left, phoenix::_context)
42           , evaluator(proto::_right, phoenix::_context)
43         )
44     >
45 {};
46 
47 template <>
48 struct invert_actions::when<phoenix::rule::minus>
49     : proto::call<
50         phoenix::functional::make_plus(
51             evaluator(proto::_left, phoenix::_context)
52           , evaluator(proto::_right, phoenix::_context)
53         )
54     >
55 {};
56 
57 template <>
58 struct invert_actions::when<phoenix::rule::multiplies>
59     : proto::call<
60         phoenix::functional::make_divides(
61             evaluator(proto::_left, phoenix::_context)
62           , evaluator(proto::_right, phoenix::_context)
63         )
64     >
65 {};
66 
67 template <>
68 struct invert_actions::when<phoenix::rule::divides>
69     : proto::call<
70         phoenix::functional::make_multiplies(
71             evaluator(proto::_left, phoenix::_context)
72           , evaluator(proto::_right, phoenix::_context)
73         )
74     >
75 {};
76 
77 #ifdef _MSC_VER
78 #undef evaluator
79 #endif
80 
81 template <typename Expr>
print_expr(Expr const & expr)82 void print_expr(Expr const & expr)
83 {
84     std::cout << "before inversion:\n";
85     proto::display_expr(expr);
86     std::cout << "after inversion:\n";
87     proto::display_expr(
88         phoenix::eval(
89             expr
90           , phoenix::context(
91                 phoenix::nothing
92               , invert_actions()
93             )
94         )
95     );
96     std::cout << "\n";
97 }
98 
99 template <typename Expr>
100 typename
101     boost::phoenix::result_of::eval<
102         Expr const&
103       , phoenix::result_of::make_context<
104             phoenix::result_of::make_env<>::type
105           , invert_actions
106         >::type
107     >::type
invert(Expr const & expr)108 invert(Expr const & expr)
109 {
110     return
111         phoenix::eval(
112             expr
113           , phoenix::make_context(
114                 phoenix::make_env()
115               , invert_actions()
116             )
117         );
118 }
119 
main()120 int main()
121 {
122     using phoenix::placeholders::_1;
123     using phoenix::placeholders::_2;
124     using phoenix::placeholders::_3;
125     using phoenix::placeholders::_4;
126 
127     print_expr(_1);
128     print_expr(_1 + _2);
129     print_expr(_1 + _2 - _3);
130     print_expr(_1 * _2);
131     print_expr(_1 * _2 / _3);
132     print_expr(_1 * _2 + _3);
133     print_expr(_1 * _2 - _3);
134     print_expr(if_(_1 * _4)[_2 - _3]);
135 
136     print_expr(_1 * invert(_2 - _3));
137 }
138 
139