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
29namespace 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
240 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
249 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
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
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;
283 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
300 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;
313 result_type operator()(Elements const& elements, unused_type) const
314 {
315 return result_type(elements);
316 }
317 };
318
319}}
320
321#endif
322