1 /*=============================================================================
2     Copyright (c) 2005-2010 Joel de Guzman
3     Copyright (c) 2010 Eric Niebler
4     Copyright (c) 2010 Thomas Heller
5     Copyright (c) 2014 John Fletcher
6 
7     Distributed under the Boost Software License, Version 1.0. (See accompanying
8     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 ==============================================================================*/
10 #ifndef BOOST_PHOENIX_CORE_ACTOR_HPP
11 #define BOOST_PHOENIX_CORE_ACTOR_HPP
12 
13 #include <boost/phoenix/core/limits.hpp>
14 
15 #include <boost/is_placeholder.hpp>
16 #include <boost/mpl/identity.hpp>
17 #include <boost/mpl/eval_if.hpp>
18 #include <boost/phoenix/core/domain.hpp>
19 #include <boost/phoenix/core/environment.hpp>
20 #include <boost/phoenix/core/is_nullary.hpp>
21 #include <boost/phoenix/core/meta_grammar.hpp>
22 #include <boost/phoenix/support/iterate.hpp>
23 #include <boost/phoenix/support/vector.hpp>
24 #include <boost/proto/extends.hpp>
25 #include <boost/proto/make_expr.hpp>
26 #include <boost/utility/result_of.hpp>
27 #include <boost/mpl/void.hpp>
28 #include <cstring>
29 #ifndef BOOST_PHOENIX_NO_VARIADIC_ACTOR
30 #   include <boost/mpl/if.hpp>
31 #   include <boost/type_traits/is_reference.hpp>
32 #   include <boost/phoenix/core/detail/index_sequence.hpp>
33 #endif
34 
35 #ifdef BOOST_MSVC
36 #pragma warning(push)
37 #pragma warning(disable: 4522) // 'this' used in base member initializer list
38 #pragma warning(disable: 4510) // default constructor could not be generated
39 #pragma warning(disable: 4610) // can never be instantiated - user defined cons
40 #endif
41 
42 namespace boost { namespace phoenix
43 {
44     template <typename Expr>
45     struct actor;
46 
47     namespace detail
48     {
49         struct error_expecting_arguments
50         {
51             template <typename T>
error_expecting_argumentsboost::phoenix::detail::error_expecting_arguments52             error_expecting_arguments(T const&) {}
53         };
54 
55         struct error_invalid_lambda_expr
56         {
57             template <typename T>
error_invalid_lambda_exprboost::phoenix::detail::error_invalid_lambda_expr58             error_invalid_lambda_expr(T const&) {}
59         };
60 
61         template <typename T>
62         struct result_type_deduction_helper
63         {
64             typedef T const & type;
65         };
66 
67         template <typename T>
68         struct result_type_deduction_helper<T &>
69         {
70             typedef T & type;
71         };
72 
73         template <typename T>
74         struct result_type_deduction_helper<T const &>
75         {
76             typedef T const & type;
77         };
78 
79         struct do_assign
80         {
81             BOOST_PROTO_CALLABLE()
82 
83             typedef void result_type;
84 
85             template <typename T1, typename T2>
operator ()boost::phoenix::detail::do_assign86             void operator()(T1 & t1, T2 const & t2) const
87             {
88                 proto::value(t1) = proto::value(t2);
89             }
90         };
91 
92 #ifdef BOOST_PHOENIX_NO_VARIADIC_ACTOR
93         #include <boost/phoenix/core/detail/cpp03/assign.hpp>
94 #else
95         struct assign : proto::transform<assign>
96         {
97             typedef assign proto_grammer;
98 
99             template <typename Expr, typename State, typename Data
100                     , typename Indices = typename detail::make_index_sequence<proto::arity_of<Expr>::value>::type >
101             struct impl;
102 
103             template <std::size_t>
104             struct proto_expr { typedef proto::_ type; };
105 
106             template <std::size_t Index>
107             struct nth_assign
108             {
109                 typedef
110                     assign type(
111                         proto::_child_c<Index>
112                       , proto::call<proto::_child_c<Index>(proto::_state)>
113                     )
114                 ;
115             };
116 
117             template <typename Expr, typename State, typename Data>
118             struct impl<Expr, State, Data, detail::index_sequence<> >
119                 : proto::when<
120                     proto::terminal<proto::_>
121                   , do_assign(proto::_, proto::_state)
122                 >::template impl<Expr, State, Data>
123             {
124             };
125 
126             template <typename Expr, typename State, typename Data
127                     , std::size_t... Indices>
128             struct impl<Expr, State, Data, detail::index_sequence<Indices...> >
129                 : proto::when<
130                     proto::nary_expr<typename proto_expr<Indices>::type...>
131                   , proto::and_<typename nth_assign<Indices>::type...>
132                 >::template impl<Expr, State, Data>
133             {
134             };
135         };
136 #endif
137     }
138 
139     namespace result_of
140     {
141 #ifdef BOOST_PHOENIX_NO_VARIADIC_ACTOR
142         // Bring in the result_of::actor<>
143         #include <boost/phoenix/core/detail/cpp03/actor_result_of.hpp>
144 #else
145         template <typename Expr, typename... A>
146         struct actor_impl
147         {
148             typedef
149                 typename boost::phoenix::evaluator::impl<
150                     Expr const&
151                   , vector2<
152                         typename vector_chooser<sizeof...(A) + 1>::
153                           template apply<const ::boost::phoenix::actor<Expr> *, A...>::type&
154                       , default_actions
155                     > const &
156                   , proto::empty_env
157                 >::result_type
158                 type;
159         };
160 
161         template <typename Expr, typename... A>
162         struct actor : actor_impl<Expr, A...> {};
163 
164         template <typename Expr>
165         struct nullary_actor_result : actor_impl<Expr> {};
166 #endif
167 
168         template <typename Expr>
169         struct actor<Expr>
170         {
171             typedef
172                 // avoid calling result_of::actor when this is false
173                 typename mpl::eval_if_c<
174                     result_of::is_nullary<Expr>::value
175                   , nullary_actor_result<Expr>
176                   , mpl::identity<detail::error_expecting_arguments>
177                 >::type
178             type;
179         };
180     }
181 
182     ////////////////////////////////////////////////////////////////////////////
183     //
184     //  actor
185     //
186     //      The actor class. The main thing! In phoenix, everything is an actor
187     //      This class is responsible for full function evaluation. Partial
188     //      function evaluation involves creating a hierarchy of actor objects.
189     //
190     ////////////////////////////////////////////////////////////////////////////
191     template <typename Expr>
192     struct actor
193     {
194         typedef typename
195             mpl::eval_if_c<
196                 mpl::or_<
197                     is_custom_terminal<Expr>
198                   , mpl::bool_<is_placeholder<Expr>::value>
199                 >::value
200               , proto::terminal<Expr>
201               , mpl::identity<Expr>
202             >::type
203             expr_type;
204 
BOOST_PROTO_BASIC_EXTENDSboost::phoenix::actor205         BOOST_PROTO_BASIC_EXTENDS(expr_type, actor<expr_type>, phoenix_domain)
206 
207         // providing operator= to be assignable
208         actor& operator=(actor const& other)
209         {
210             detail::assign()(*this, other);
211             return *this;
212         }
operator =boost::phoenix::actor213         actor& operator=(actor & other)
214         {
215             detail::assign()(*this, other);
216             return *this;
217         }
218 
219         template <typename A0>
220         typename proto::result_of::make_expr<
221             proto::tag::assign
222           , phoenix_domain
223           , proto_base_expr
224           , A0
225         >::type const
operator =boost::phoenix::actor226         operator=(A0 const & a0) const
227         {
228             return proto::make_expr<proto::tag::assign, phoenix_domain>(this->proto_expr_, a0);
229         }
230 
231         template <typename A0>
232         typename proto::result_of::make_expr<
233             proto::tag::assign
234           , phoenix_domain
235           , proto_base_expr
236           , A0
237         >::type const
operator =boost::phoenix::actor238         operator=(A0 & a0) const
239         {
240             return proto::make_expr<proto::tag::assign, phoenix_domain>(this->proto_expr_, a0);
241         }
242 
243         template <typename A0>
244         typename proto::result_of::make_expr<
245             proto::tag::subscript
246           , phoenix_domain
247           , proto_base_expr
248           , A0
249         >::type const
operator []boost::phoenix::actor250         operator[](A0 const & a0) const
251         {
252             return proto::make_expr<proto::tag::subscript, phoenix_domain>(this->proto_expr_, a0);
253         }
254 
255         template <typename A0>
256         typename proto::result_of::make_expr<
257             proto::tag::subscript
258           , phoenix_domain
259           , proto_base_expr
260           , A0
261         >::type const
operator []boost::phoenix::actor262         operator[](A0 & a0) const
263         {
264             return proto::make_expr<proto::tag::subscript, phoenix_domain>(this->proto_expr_, a0);
265         }
266 
267         template <typename Sig>
268         struct result;
269 
270         typename result_of::actor<proto_base_expr>::type
operator ()boost::phoenix::actor271         operator()()
272         {
273             typedef vector1<const actor<Expr> *> env_type;
274             env_type env = {this};
275 
276             return phoenix::eval(*this, phoenix::context(env, default_actions()));
277         }
278 
279         typename result_of::actor<proto_base_expr>::type
operator ()boost::phoenix::actor280         operator()() const
281         {
282             typedef vector1<const actor<Expr> *> env_type;
283             env_type env = {this};
284 
285             return phoenix::eval(*this, phoenix::context(env, default_actions()));
286         }
287 
288         template <typename Env>
289         typename evaluator::impl<
290             proto_base_expr const &
291           , typename result_of::context<
292                 Env const &
293               , default_actions const &
294             >::type
295           , proto::empty_env
296         >::result_type
evalboost::phoenix::actor297         eval(Env const & env) const
298         {
299             return phoenix::eval(*this, phoenix::context(env, default_actions()));
300         }
301 
302 #ifdef BOOST_PHOENIX_NO_VARIADIC_ACTOR
303         // Bring in the rest
304         #include <boost/phoenix/core/detail/cpp03/actor_operator.hpp>
305 #else
306         template <typename This, typename... A>
307         struct result<This(A...)>
308             : result_of::actor<
309                 proto_base_expr
310               , typename mpl::if_<is_reference<A>, A, A const &>::type...
311             >
312         {};
313 
314         template <typename... A>
315         typename result<actor(A...)>::type
operator ()boost::phoenix::actor316         operator()(A &&... a)
317         {
318             typedef
319                 typename vector_chooser<sizeof...(A) + 1>::template apply<
320                     const actor<Expr> *
321                   , typename mpl::if_<is_reference<A>, A, A const &>::type...
322                 >::type
323             env_type;
324 
325             env_type env = {this, a...};
326             return phoenix::eval(*this, phoenix::context(env, default_actions()));
327         }
328 
329         template <typename... A>
330         typename result<actor(A...)>::type
operator ()boost::phoenix::actor331         operator()(A &&... a) const
332         {
333             typedef
334                 typename vector_chooser<sizeof...(A) + 1>::template apply<
335                     const actor<Expr> *
336                   , typename mpl::if_<is_reference<A>, A, A const &>::type...
337                 >::type
338             env_type;
339 
340             env_type env = {this, a...};
341             return phoenix::eval(*this, phoenix::context(env, default_actions()));
342         }
343 #endif
344     };
345 }}
346 
347 namespace boost
348 {
349     // specialize boost::result_of to return the proper result type
350     template <typename Expr>
351     struct result_of<phoenix::actor<Expr>()>
352         : phoenix::result_of::actor<typename phoenix::actor<Expr>::proto_base_expr>
353     {};
354 
355     template <typename Expr>
356     struct result_of<phoenix::actor<Expr> const()>
357         : phoenix::result_of::actor<typename phoenix::actor<Expr>::proto_base_expr>
358     {};
359 }
360 
361 
362 #ifdef BOOST_MSVC
363 #pragma warning(pop)
364 #endif
365 
366 #endif
367 
368