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