]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
239 | 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 | |
248 | 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 | |
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 | |
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; | |
282 | 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 | ||
299 | 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; | |
312 | result_type operator()(Elements const& elements, unused_type) const | |
313 | { | |
314 | return result_type(elements); | |
315 | } | |
316 | }; | |
317 | ||
318 | }} | |
319 | ||
320 | #endif |