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