1 /*=============================================================================
2   Copyright (c) 2001-2011 Joel de Guzman
3   http://spirit.sourceforge.net/
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 #ifndef BOOST_SPIRIT_MAKE_COMPONENT_OCTOBER_16_2008_1250PM
9 #define BOOST_SPIRIT_MAKE_COMPONENT_OCTOBER_16_2008_1250PM
10 
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14 
15 #include <boost/spirit/home/support/detail/make_cons.hpp>
16 #include <boost/spirit/home/support/modify.hpp>
17 #include <boost/phoenix/core/actor.hpp>
18 #include <boost/phoenix/core/is_actor.hpp>
19 #include <boost/proto/tags.hpp>
20 #include <boost/proto/traits.hpp>
21 #include <boost/proto/transform.hpp>
22 
23 namespace boost { namespace spirit
24 {
25     // There is no real "component" class. Each domain is responsible
26     // for creating its own components. You need to specialize this for
27     // each component in your domain. Use this as a guide.
28 
29     template <typename Domain, typename Tag, typename Enable = void>
30     struct make_component
31     {
32         template <typename Sig>
33         struct result;
34 
35         template <typename This, typename Elements, typename Modifiers>
36         struct result<This(Elements, Modifiers)>;
37 
38         template <typename Elements, typename Modifiers>
39         typename result<make_component(Elements, Modifiers)>::type
40         operator()(Elements const& elements, Modifiers const& modifiers) const;
41     };
42 
43     namespace tag
44     {
45         // Normally, we use proto tags as-is to distinguish operators.
46         // The special case is proto::tag::subscript. Spirit uses this
47         // as either sementic actions or directives. To distinguish between
48         // the two, we use these special tags below.
49 
50         struct directive;
51         struct action;
52     }
53 
54     template <typename Domain, typename T, typename Enable = void>
55     struct flatten_tree;
56 }}
57 
58 namespace boost { namespace spirit { namespace detail
59 {
60     template <typename Expr, typename State, typename Data, typename Domain>
61     struct make_terminal_impl
62       : proto::transform_impl<Expr, State, Data>
63     {
64         typedef typename
65             proto::result_of::value<Expr>::type
66         value;
67 
68         typedef typename result_of::make_cons<value>::type elements;
69 
70         typedef
71             make_component<Domain, proto::tag::terminal>
72         make_component_;
73 
74         typedef typename
75             make_component_::template
76                 result<make_component_(elements, Data)>::type
77         result_type;
78 
operator ()boost::spirit::detail::make_terminal_impl79         result_type operator()(
80             typename make_terminal_impl::expr_param expr
81           , typename make_terminal_impl::state_param /*state*/
82           , typename make_terminal_impl::data_param data
83         ) const
84         {
85             return typename make_terminal_impl::make_component_()(
86                 detail::make_cons(proto::value(expr))
87               , data
88             );
89         }
90     };
91 
92     template <typename Expr, typename State, typename Data, typename Domain>
93     struct make_terminal_impl<phoenix::actor<Expr>, State, Data, Domain>
94       : proto::transform_impl<phoenix::actor<Expr>, State, Data>
95     {
96         typedef phoenix::actor<Expr> value;
97         typedef typename result_of::make_cons<value>::type elements;
98         typedef make_component<Domain, proto::tag::terminal> make_component_;
99 
100         typedef typename
101             make_component_::template
102                 result<make_component_(elements, Data)>::type
103         result_type;
104 
operator ()boost::spirit::detail::make_terminal_impl105         result_type operator()(
106             typename make_terminal_impl::expr_param expr
107           , typename make_terminal_impl::state_param /*state*/
108           , typename make_terminal_impl::data_param data
109         ) const
110         {
111             return typename make_terminal_impl::make_component_()(
112                 detail::make_cons(expr)
113               , data
114             );
115         }
116     };
117 
118     template <typename Expr, typename State, typename Data, typename Domain>
119     struct make_terminal_impl<phoenix::actor<Expr> &, State, Data, Domain>
120         : make_terminal_impl<phoenix::actor<Expr>, State, Data, Domain>
121     {};
122 
123     template <typename Expr, typename State, typename Data, typename Domain>
124     struct make_terminal_impl<phoenix::actor<Expr> const &, State, Data, Domain>
125         : make_terminal_impl<phoenix::actor<Expr>, State, Data, Domain>
126     {};
127 
128     template <typename Domain>
129     struct make_terminal : proto::transform<make_terminal<Domain> >
130     {
131         template<typename Expr, typename State, typename Data>
132         struct impl : make_terminal_impl<Expr, State, Data, Domain> {};
133     };
134 
135     template <typename Domain, typename Tag, typename Grammar>
136     struct make_unary : proto::transform<make_unary<Domain, Tag, Grammar> >
137     {
138         template<typename Expr, typename State, typename Data>
139         struct impl : proto::transform_impl<Expr, State, Data>
140         {
141             typedef typename
142                 proto::result_of::child_c<Expr, 0>::type
143             child;
144 
145             typedef typename Grammar::
146                 template result<Grammar(child, State, Data)>::type
147             child_component;
148 
149             typedef typename
150                 result_of::make_cons<child_component>::type
151             elements;
152 
153             typedef make_component<Domain, Tag> make_component_;
154 
155             typedef typename
156                 make_component_::template
157                     result<make_component_(elements, Data)>::type
158             result_type;
159 
operator ()boost::spirit::detail::make_unary::impl160             result_type operator()(
161                 typename impl::expr_param expr
162               , typename impl::state_param state
163               , typename impl::data_param data
164             ) const
165             {
166                 return typename impl::make_component_()(
167                     detail::make_cons(
168                         Grammar()(proto::child(expr), state, data))
169                   , data
170                 );
171             }
172         };
173     };
174 
175     // un-flattened version
176     template <typename Domain, typename Tag, typename Grammar,
177         bool flatten = flatten_tree<Domain, Tag>::value>
178     struct make_binary
179     {
180         template<typename Expr, typename State, typename Data>
181         struct impl : proto::transform_impl<Expr, State, Data>
182         {
183             typedef typename Grammar::
184                 template result<Grammar(
185                     typename proto::result_of::child_c<Expr, 0>::type
186                   , State, Data)>::type
187             lhs_component;
188 
189             typedef typename Grammar::
190                 template result<Grammar(
191                     typename proto::result_of::child_c<Expr, 1>::type
192                   , State, Data)>::type
193             rhs_component;
194 
195             typedef typename
196                 result_of::make_cons<
197                     lhs_component
198                   , typename result_of::make_cons<rhs_component>::type
199                 >::type
200             elements_type;
201 
202             typedef make_component<Domain, Tag> make_component_;
203 
204             typedef typename
205                 make_component_::template
206                     result<make_component_(elements_type, Data)>::type
207             result_type;
208 
operator ()boost::spirit::detail::make_binary::impl209             result_type operator()(
210                 typename impl::expr_param expr
211               , typename impl::state_param state
212               , typename impl::data_param data
213             ) const
214             {
215                 elements_type elements =
216                     detail::make_cons(
217                         Grammar()(
218                             proto::child_c<0>(expr), state, data)       // LHS
219                       , detail::make_cons(
220                             Grammar()(
221                                 proto::child_c<1>(expr), state, data)   // RHS
222                         )
223                     );
224 
225                 return make_component_()(elements, data);
226             }
227         };
228     };
229 
230     template <typename Grammar>
231     struct make_binary_helper : proto::transform<make_binary_helper<Grammar> >
232     {
233         template<typename Expr, typename State, typename Data>
234         struct impl : proto::transform_impl<Expr, State, Data>
235         {
236             typedef typename Grammar::
237                 template result<Grammar(Expr, State, Data)>::type
238             lhs;
239 
240             typedef typename result_of::make_cons<lhs, State>::type result_type;
241 
operator ()boost::spirit::detail::make_binary_helper::impl242             result_type operator()(
243                 typename impl::expr_param expr
244               , typename impl::state_param state
245               , typename impl::data_param data
246             ) const
247             {
248                 return detail::make_cons(Grammar()(expr, state, data), state);
249             }
250         };
251     };
252 
253     // Flattened version
254     template <typename Domain, typename Tag, typename Grammar>
255     struct make_binary<Domain, Tag, Grammar, true>
256       : proto::transform<make_binary<Domain, Tag, Grammar> >
257     {
258         template<typename Expr, typename State, typename Data>
259         struct impl : proto::transform_impl<Expr, State, Data>
260         {
261             typedef typename
262                 proto::reverse_fold_tree<
263                     proto::_
264                   , proto::make<fusion::nil_>
265                   , make_binary_helper<Grammar>
266                 >::template impl<Expr, State, Data>
267             reverse_fold_tree;
268 
269             typedef typename reverse_fold_tree::result_type elements;
270             typedef make_component<Domain, Tag> make_component_;
271 
272             typedef typename
273                 make_component_::template
274                     result<make_component_(elements, Data)>::type
275             result_type;
276 
operator ()boost::spirit::detail::make_binary::impl277             result_type operator()(
278                 typename impl::expr_param expr
279               , typename impl::state_param state
280               , typename impl::data_param data
281             ) const
282             {
283                 return make_component_()(
284                     reverse_fold_tree()(expr, state, data), data);
285             }
286         };
287     };
288 
289     template <typename Domain, typename Grammar>
290     struct make_directive : proto::transform<make_directive<Domain, Grammar> >
291     {
292         template<typename Expr, typename State, typename Data>
293         struct impl : proto::transform_impl<Expr, State, Data>
294         {
295             typedef typename
296                 proto::result_of::child_c<Expr, 0>::type
297             lhs;
298 
299             typedef typename
300                 proto::result_of::value<lhs>::type
301             tag_type;
302 
303             typedef typename modify<Domain>::
304                 template result<modify<Domain>(tag_type, Data)>::type
305             modifier_type;
306 
307             typedef typename Grammar::
308                 template result<Grammar(
309                     typename proto::result_of::child_c<Expr, 1>::type
310                   , State
311                   , modifier_type
312                 )>::type
313             rhs_component;
314 
315             typedef typename
316                 result_of::make_cons<
317                     tag_type
318                   , typename result_of::make_cons<rhs_component>::type
319                 >::type
320             elements_type;
321 
322             typedef make_component<Domain, tag::directive> make_component_;
323 
324             typedef typename
325                 make_component_::template
326                     result<make_component_(elements_type, Data)>::type
327             result_type;
328 
operator ()boost::spirit::detail::make_directive::impl329             result_type operator()(
330                 typename impl::expr_param expr
331               , typename impl::state_param state
332               , typename impl::data_param data
333             ) const
334             {
335                 tag_type tag = proto::value(proto::child_c<0>(expr));
336                 typename remove_reference<modifier_type>::type
337                     modifier = modify<Domain>()(tag, data);
338 
339                 elements_type elements =
340                     detail::make_cons(
341                         tag                                 // LHS
342                       , detail::make_cons(
343                             Grammar()(
344                                 proto::child_c<1>(expr)     // RHS
345                               , state, modifier)
346                         )
347                     );
348 
349                 return make_component_()(elements, data);
350             }
351         };
352     };
353 
354     template <typename Domain, typename Grammar>
355     struct make_action : proto::transform<make_action<Domain, Grammar> >
356     {
357         template<typename Expr, typename State, typename Data>
358         struct impl : proto::transform_impl<Expr, State, Data>
359         {
360             typedef typename Grammar::
361                 template result<Grammar(
362                     typename proto::result_of::child_c<Expr, 0>::type
363                   , State
364                   , Data
365                 )>::type
366             lhs_component;
367 
368             typedef
369                 typename mpl::eval_if_c<
370                     phoenix::is_actor<
371                         typename proto::result_of::child_c<Expr, 1>::type
372                     >::type::value
373                   , proto::result_of::child_c<Expr, 1>
374                   , proto::result_of::value<
375                         typename proto::result_of::child_c<Expr, 1>::type
376                     >
377                 >::type
378                 rhs_component;
379 
380             typedef typename
381                 result_of::make_cons<
382                     lhs_component
383                   , typename result_of::make_cons<rhs_component>::type
384                 >::type
385             elements_type;
386 
387             typedef make_component<Domain, tag::action> make_component_;
388 
389             typedef typename
390                 make_component_::template
391                     result<make_component_(elements_type, Data)>::type
392             result_type;
393 
operator ()boost::spirit::detail::make_action::impl394             result_type operator()(
395                 typename impl::expr_param expr
396               , typename impl::state_param state
397               , typename impl::data_param data
398             ) const
399             {
400                 return
401                     (*this)(
402                         expr
403                       , state
404                       , data
405                       , typename phoenix::is_actor<
406                             typename proto::result_of::child_c<Expr, 1>::type
407                         >::type()
408                     );
409             }
410 
operator ()boost::spirit::detail::make_action::impl411             result_type operator()(
412                 typename impl::expr_param expr
413               , typename impl::state_param state
414               , typename impl::data_param data
415               , mpl::false_
416             ) const
417             {
418                 elements_type elements =
419                     detail::make_cons(
420                         Grammar()(
421                             proto::child_c<0>(expr), state, data)   // LHS
422                       , detail::make_cons(
423                             proto::value(proto::child_c<1>(expr)))  // RHS
424                     );
425 
426                 return make_component_()(elements, data);
427             }
428 
operator ()boost::spirit::detail::make_action::impl429             result_type operator()(
430                 typename impl::expr_param expr
431               , typename impl::state_param state
432               , typename impl::data_param data
433               , mpl::true_
434             ) const
435             {
436                 elements_type elements =
437                     detail::make_cons(
438                         Grammar()(
439                             proto::child_c<0>(expr), state, data)   // LHS
440                       , detail::make_cons(
441                             proto::child_c<1>(expr))               // RHS
442                     );
443 
444                 return make_component_()(elements, data);
445             }
446         };
447     };
448 }}}
449 
450 #endif
451