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_META_COMPILER_OCTOBER_16_2008_1258PM
9 #define BOOST_SPIRIT_META_COMPILER_OCTOBER_16_2008_1258PM
10 
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14 
15 #include <boost/config.hpp>
16 #include <boost/spirit/include/phoenix_limits.hpp>
17 #include <boost/detail/workaround.hpp>
18 #include <boost/spirit/include/phoenix_limits.hpp>      // needs to be included before proto
19 #include <boost/proto/proto.hpp>
20 #include <boost/spirit/home/support/make_component.hpp>
21 #include <boost/spirit/home/support/modify.hpp>
22 #include <boost/spirit/home/support/detail/make_cons.hpp>
23 #include <boost/spirit/home/support/unused.hpp>
24 #include <boost/spirit/home/support/assert_msg.hpp>
25 #include <boost/utility/enable_if.hpp>
26 #include <boost/type_traits/remove_reference.hpp>
27 
28 namespace boost { namespace spirit
29 {
30     // Some defaults...
31 
32     template <typename Domain, typename Tag, typename Enable = void>
33     struct use_operator : mpl::false_ {};
34 
35     template <typename Domain, typename T, typename Enable = void>
36     struct use_function : mpl::false_ {};
37 
38     template <typename Domain, typename T, typename Enable = void>
39     struct use_directive : mpl::false_ {};
40 
41     template <typename Domain, typename T, typename Enable /* = void */>
42     struct is_modifier_directive : mpl::false_ {};
43 
44     template <typename Domain, typename T, typename Enable = void>
45     struct use_terminal : mpl::false_ {};
46 
47     template <typename Domain, typename T, typename Enable /*= void*/>
48     struct flatten_tree : mpl::false_ {};
49 
50     // Our meta-compiler. This is the main engine that hooks Spirit
51     // to the proto expression template engine.
52 
53     template <typename Domain>
54     struct meta_compiler
55     {
56         struct meta_grammar;
57 
58         BOOST_SPIRIT_ASSERT_MSG((
59             !use_operator<Domain, proto::tag::subscript>::value
60         ), error_proto_tag_subscript_cannot_be_used, ());
61 
62 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1400)
63         // this is the non-broken part for compilers properly supporting
64         // partial template specialization (VC7.1 does not)
65         struct cases
66         {
67             template <typename Tag, typename Enable = void>
68             struct case_
69               : proto::not_<proto::_>
70             {};
71 
72             ///////////////////////////////////////////////////////////////////
73             // terminals
74             ///////////////////////////////////////////////////////////////////
75             template <typename Enable>
76             struct case_<proto::tag::terminal, Enable>
77               : proto::when<
78                     proto::if_<use_terminal<Domain, proto::_value>()>,
79                     detail::make_terminal<Domain>
80                 >
81             {};
82 
83             template <typename Tag>
84             struct case_<Tag, typename enable_if<use_operator<Domain, Tag> >::type>
85               : proto::or_<
86             ///////////////////////////////////////////////////////////////////
87             // binary operators
88             ///////////////////////////////////////////////////////////////////
89                     proto::when<proto::binary_expr<Tag, meta_grammar, meta_grammar>,
90                         detail::make_binary<Domain, Tag, meta_grammar>
91                     >,
92             ///////////////////////////////////////////////////////////////////
93             // unary operators
94             ///////////////////////////////////////////////////////////////////
95                     proto::when<proto::unary_expr<Tag, meta_grammar>,
96                         detail::make_unary<Domain, Tag, meta_grammar>
97                     >
98                 >
99             {};
100 
101             template <typename Enable>
102             struct case_<proto::tag::subscript, Enable>
103               : proto::or_<
104             ///////////////////////////////////////////////////////////////////
105             // directives
106             ///////////////////////////////////////////////////////////////////
107                     proto::when<proto::binary_expr<proto::tag::subscript
108                       , proto::and_<
109                             proto::terminal<proto::_>
110                           , proto::if_<use_directive<Domain, proto::_value >()> >
111                       , meta_grammar>,
112                         detail::make_directive<Domain, meta_grammar>
113                     >,
114             ///////////////////////////////////////////////////////////////////
115             // semantic actions
116             ///////////////////////////////////////////////////////////////////
117                     proto::when<proto::binary_expr<proto::tag::subscript
118                       , meta_grammar, proto::_>,
119                         detail::make_action<Domain, meta_grammar>
120                     >
121                 >
122             {};
123         };
124 #else
125         // this part actually constitutes invalid C++ code, but it allows us to
126         // convince VC7.1 to do what we want
127         struct cases
128         {
129             template <typename Tag, typename Enable = void>
130             struct case_
131               : proto::not_<proto::_>
132             {};
133 
134             ///////////////////////////////////////////////////////////////////
135             // terminals
136             ///////////////////////////////////////////////////////////////////
137             template <>
138             struct case_<proto::tag::terminal>
139               : proto::when<
140                     proto::if_<use_terminal<Domain, proto::_value>()>,
141                     detail::make_terminal<Domain>
142                 >
143             {};
144 
145             template <typename Tag>
146             struct case_<Tag>
147               : proto::or_<
148             ///////////////////////////////////////////////////////////////////
149             // binary operators
150             ///////////////////////////////////////////////////////////////////
151                     proto::when<proto::binary_expr<
152                         typename enable_if<use_operator<Domain, Tag>, Tag>::type
153                           , meta_grammar, meta_grammar>
154                       , detail::make_binary<Domain, Tag, meta_grammar>
155                     >,
156             ///////////////////////////////////////////////////////////////////
157             // unary operators
158             ///////////////////////////////////////////////////////////////////
159                     proto::when<proto::unary_expr<
160                         typename enable_if<use_operator<Domain, Tag>, Tag>::type
161                           , meta_grammar>
162                       , detail::make_unary<Domain, Tag, meta_grammar>
163                     >
164                 >
165             {};
166 
167             template <>
168             struct case_<proto::tag::subscript>
169               : proto::or_<
170             ///////////////////////////////////////////////////////////////////
171             // directives
172             ///////////////////////////////////////////////////////////////////
173                     proto::when<proto::binary_expr<proto::tag::subscript
174                       , proto::and_<
175                             proto::terminal<proto::_>
176                           , proto::if_<use_directive<Domain, proto::_value >()> >
177                       , meta_grammar>,
178                         detail::make_directive<Domain, meta_grammar>
179                     >,
180             ///////////////////////////////////////////////////////////////////
181             // semantic actions
182             ///////////////////////////////////////////////////////////////////
183                     proto::when<proto::binary_expr<proto::tag::subscript
184                       , meta_grammar, proto::_>,
185                         detail::make_action<Domain, meta_grammar>
186                     >
187                 >
188             {};
189         };
190 #endif
191 
192         struct meta_grammar
193           : proto::switch_<cases>
194         {};
195     };
196 
197     namespace result_of
198     {
199         // Default case
200         template <typename Domain, typename Expr
201           , typename Modifiers = unused_type, typename Enable = void>
202         struct compile
203         {
204             typedef typename meta_compiler<Domain>::meta_grammar meta_grammar;
205             typedef typename meta_grammar::
206                 template result<meta_grammar(Expr, mpl::void_, Modifiers)>::type
207             type;
208         };
209 
210         // If Expr is not a proto expression, make it a terminal
211         template <typename Domain, typename Expr, typename Modifiers>
212         struct compile<Domain, Expr, Modifiers,
213             typename disable_if<proto::is_expr<Expr> >::type>
214           : compile<Domain, typename proto::terminal<Expr>::type, Modifiers> {};
215     }
216 
217     namespace traits
218     {
219         // Check if Expr matches the domain's grammar
220         template <typename Domain, typename Expr>
221         struct matches :
222             proto::matches<
223                 typename proto::result_of::as_expr<
224                     typename remove_reference<Expr>::type>::type,
225                 typename meta_compiler<Domain>::meta_grammar
226             >
227         {
228         };
229     }
230 
231     namespace detail
232     {
233         template <typename Domain>
234         struct compiler
235         {
236             // Default case
237             template <typename Expr, typename Modifiers>
238             static typename spirit::result_of::compile<Domain, Expr, Modifiers>::type
compileboost::spirit::detail::compiler239             compile(Expr const& expr, Modifiers modifiers, mpl::true_)
240             {
241                 typename meta_compiler<Domain>::meta_grammar compiler;
242                 return compiler(expr, mpl::void_(), modifiers);
243             }
244 
245             // If Expr is not a proto expression, make it a terminal
246             template <typename Expr, typename Modifiers>
247             static typename spirit::result_of::compile<Domain, Expr, Modifiers>::type
compileboost::spirit::detail::compiler248             compile(Expr const& expr, Modifiers modifiers, mpl::false_)
249             {
250                 typename meta_compiler<Domain>::meta_grammar compiler;
251                 typedef typename detail::as_meta_element<Expr>::type expr_;
252                 typename proto::terminal<expr_>::type term = {expr};
253                 return compiler(term, mpl::void_(), modifiers);
254             }
255         };
256     }
257 
258     template <typename Domain, typename Expr>
259     inline typename result_of::compile<Domain, Expr, unused_type>::type
compile(Expr const & expr)260     compile(Expr const& expr)
261     {
262         typedef typename proto::is_expr<Expr>::type is_expr;
263         return detail::compiler<Domain>::compile(expr, unused, is_expr());
264     }
265 
266     template <typename Domain, typename Expr, typename Modifiers>
267     inline typename result_of::compile<Domain, Expr, Modifiers>::type
compile(Expr const & expr,Modifiers modifiers)268     compile(Expr const& expr, Modifiers modifiers)
269     {
270         typedef typename proto::is_expr<Expr>::type is_expr;
271         return detail::compiler<Domain>::compile(expr, modifiers, is_expr());
272     }
273 
274     ///////////////////////////////////////////////////////////////////////////
275     template <typename Elements, template <typename Subject> class generator>
276     struct make_unary_composite
277     {
278         typedef typename
279             fusion::result_of::value_at_c<Elements, 0>::type
280         element_type;
281         typedef generator<element_type> result_type;
operator ()boost::spirit::make_unary_composite282         result_type operator()(Elements const& elements, unused_type) const
283         {
284             return result_type(fusion::at_c<0>(elements));
285         }
286     };
287 
288     template <typename Elements, template <typename Left, typename Right> class generator>
289     struct make_binary_composite
290     {
291         typedef typename
292             fusion::result_of::value_at_c<Elements, 0>::type
293         left_type;
294         typedef typename
295             fusion::result_of::value_at_c<Elements, 1>::type
296         right_type;
297         typedef generator<left_type, right_type> result_type;
298 
operator ()boost::spirit::make_binary_composite299         result_type operator()(Elements const& elements, unused_type) const
300         {
301             return result_type(
302                 fusion::at_c<0>(elements)
303               , fusion::at_c<1>(elements)
304             );
305         }
306     };
307 
308     template <typename Elements, template <typename Elements_> class generator>
309     struct make_nary_composite
310     {
311         typedef generator<Elements> result_type;
operator ()boost::spirit::make_nary_composite312         result_type operator()(Elements const& elements, unused_type) const
313         {
314             return result_type(elements);
315         }
316     };
317 
318 }}
319 
320 #endif
321