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