Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Copyright (c) 2001-2011 Joel de Guzman
|
Chris@16
|
3 Copyright (c) 2001-2011 Hartmut Kaiser
|
Chris@16
|
4 Copyright (c) 2011 Thomas Heller
|
Chris@16
|
5
|
Chris@16
|
6 Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8 ==============================================================================*/
|
Chris@16
|
9 #if !defined(BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM)
|
Chris@16
|
10 #define BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM
|
Chris@16
|
11
|
Chris@16
|
12 #if defined(_MSC_VER)
|
Chris@16
|
13 #pragma once
|
Chris@16
|
14 #endif
|
Chris@16
|
15
|
Chris@16
|
16 #include <boost/spirit/include/phoenix_core.hpp>
|
Chris@16
|
17 #include <boost/spirit/include/phoenix_function.hpp>
|
Chris@16
|
18 #include <boost/proto/proto.hpp>
|
Chris@16
|
19 #include <boost/fusion/include/void.hpp>
|
Chris@16
|
20 #include <boost/spirit/home/support/meta_compiler.hpp>
|
Chris@16
|
21 #include <boost/spirit/home/support/detail/make_vector.hpp>
|
Chris@16
|
22 #include <boost/spirit/home/support/unused.hpp>
|
Chris@16
|
23 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
|
Chris@16
|
24 #include <boost/preprocessor/tuple/elem.hpp>
|
Chris@16
|
25
|
Chris@16
|
26 #include <boost/spirit/home/support/terminal_expression.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost { namespace spirit
|
Chris@16
|
29 {
|
Chris@16
|
30 template <typename Terminal, typename Args>
|
Chris@16
|
31 struct terminal_ex
|
Chris@16
|
32 {
|
Chris@16
|
33 typedef Terminal terminal_type;
|
Chris@16
|
34 typedef Args args_type;
|
Chris@16
|
35
|
Chris@16
|
36 terminal_ex(Args const& args_)
|
Chris@16
|
37 : args(args_) {}
|
Chris@16
|
38 terminal_ex(Args const& args_, Terminal const& term_)
|
Chris@16
|
39 : args(args_), term(term_) {}
|
Chris@16
|
40
|
Chris@16
|
41 Args args; // Args is guaranteed to be a fusion::vectorN so you
|
Chris@16
|
42 // can use that template for detection and specialization
|
Chris@16
|
43 Terminal term;
|
Chris@16
|
44 };
|
Chris@16
|
45
|
Chris@16
|
46 template <typename Terminal, typename Actor, int Arity>
|
Chris@16
|
47 struct lazy_terminal
|
Chris@16
|
48 {
|
Chris@16
|
49 typedef Terminal terminal_type;
|
Chris@16
|
50 typedef Actor actor_type;
|
Chris@16
|
51 static int const arity = Arity;
|
Chris@16
|
52
|
Chris@16
|
53 lazy_terminal(Actor const& actor_)
|
Chris@16
|
54 : actor(actor_) {}
|
Chris@16
|
55 lazy_terminal(Actor const& actor_, Terminal const& term_)
|
Chris@16
|
56 : actor(actor_), term(term_) {}
|
Chris@16
|
57
|
Chris@16
|
58 Actor actor;
|
Chris@16
|
59 Terminal term;
|
Chris@16
|
60 };
|
Chris@16
|
61
|
Chris@16
|
62 template <typename Domain, typename Terminal, int Arity, typename Enable = void>
|
Chris@16
|
63 struct use_lazy_terminal : mpl::false_ {};
|
Chris@16
|
64
|
Chris@16
|
65 template <typename Domain, typename Terminal, int Arity, typename Enable = void>
|
Chris@16
|
66 struct use_lazy_directive : mpl::false_ {};
|
Chris@16
|
67
|
Chris@16
|
68 template <typename Terminal>
|
Chris@16
|
69 struct terminal;
|
Chris@16
|
70
|
Chris@16
|
71 template <typename Domain, typename Terminal>
|
Chris@16
|
72 struct use_terminal<Domain, terminal<Terminal> >
|
Chris@16
|
73 : use_terminal<Domain, Terminal> {};
|
Chris@16
|
74
|
Chris@16
|
75 template <typename Domain, typename Terminal, int Arity, typename Actor>
|
Chris@16
|
76 struct use_terminal<Domain, lazy_terminal<Terminal, Actor, Arity> >
|
Chris@16
|
77 : use_lazy_terminal<Domain, Terminal, Arity> {};
|
Chris@16
|
78
|
Chris@16
|
79 template <typename Domain, typename Terminal, int Arity, typename Actor>
|
Chris@16
|
80 struct use_directive<Domain, lazy_terminal<Terminal, Actor, Arity> >
|
Chris@16
|
81 : use_lazy_directive<Domain, Terminal, Arity> {};
|
Chris@16
|
82
|
Chris@16
|
83 template <
|
Chris@16
|
84 typename F
|
Chris@16
|
85 , typename A0 = unused_type
|
Chris@16
|
86 , typename A1 = unused_type
|
Chris@16
|
87 , typename A2 = unused_type
|
Chris@16
|
88 , typename Unused = unused_type
|
Chris@16
|
89 >
|
Chris@16
|
90 struct make_lazy;
|
Chris@16
|
91
|
Chris@16
|
92 template <typename F, typename A0>
|
Chris@16
|
93 struct make_lazy<F, A0>
|
Chris@16
|
94 {
|
Chris@16
|
95 typedef typename
|
Chris@16
|
96 proto::terminal<
|
Chris@16
|
97 lazy_terminal<
|
Chris@16
|
98 typename F::terminal_type
|
Chris@16
|
99 , typename phoenix::detail::expression::function_eval<F, A0>::type
|
Chris@16
|
100 , 1 // arity
|
Chris@16
|
101 >
|
Chris@16
|
102 >::type
|
Chris@16
|
103 result_type;
|
Chris@16
|
104 typedef result_type type;
|
Chris@16
|
105
|
Chris@16
|
106 result_type
|
Chris@16
|
107 operator()(F f, A0 const& _0_) const
|
Chris@16
|
108 {
|
Chris@16
|
109 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
110 return result_type::make(child_type(
|
Chris@16
|
111 phoenix::detail::expression::function_eval<F, A0>::make(f, _0_)
|
Chris@16
|
112 , f.proto_base().child0
|
Chris@16
|
113 ));
|
Chris@16
|
114 }
|
Chris@16
|
115 };
|
Chris@16
|
116
|
Chris@16
|
117 template <typename F, typename A0, typename A1>
|
Chris@16
|
118 struct make_lazy<F, A0, A1>
|
Chris@16
|
119 {
|
Chris@16
|
120 typedef typename
|
Chris@16
|
121 proto::terminal<
|
Chris@16
|
122 lazy_terminal<
|
Chris@16
|
123 typename F::terminal_type
|
Chris@16
|
124 , typename phoenix::detail::expression::function_eval<F, A0, A1>::type
|
Chris@16
|
125 , 2 // arity
|
Chris@16
|
126 >
|
Chris@16
|
127 >::type
|
Chris@16
|
128 result_type;
|
Chris@16
|
129 typedef result_type type;
|
Chris@16
|
130
|
Chris@16
|
131 result_type
|
Chris@16
|
132 operator()(F f, A0 const& _0_, A1 const& _1_) const
|
Chris@16
|
133 {
|
Chris@16
|
134 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
135 return result_type::make(child_type(
|
Chris@16
|
136 phoenix::detail::expression::function_eval<F, A0, A1>::make(f, _0_, _1_)
|
Chris@16
|
137 , f.proto_base().child0
|
Chris@16
|
138 ));
|
Chris@16
|
139 }
|
Chris@16
|
140 };
|
Chris@16
|
141
|
Chris@16
|
142 template <typename F, typename A0, typename A1, typename A2>
|
Chris@16
|
143 struct make_lazy<F, A0, A1, A2>
|
Chris@16
|
144 {
|
Chris@16
|
145 typedef typename
|
Chris@16
|
146 proto::terminal<
|
Chris@16
|
147 lazy_terminal<
|
Chris@16
|
148 typename F::terminal_type
|
Chris@16
|
149 , typename phoenix::detail::expression::function_eval<F, A0, A1, A2>::type
|
Chris@16
|
150 , 3 // arity
|
Chris@16
|
151 >
|
Chris@16
|
152 >::type
|
Chris@16
|
153 result_type;
|
Chris@16
|
154 typedef result_type type;
|
Chris@16
|
155
|
Chris@16
|
156 result_type
|
Chris@16
|
157 operator()(F f, A0 const& _0_, A1 const& _1_, A2 const& _2_) const
|
Chris@16
|
158 {
|
Chris@16
|
159 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
160 return result_type::make(child_type(
|
Chris@16
|
161 phoenix::detail::expression::function_eval<F, A0, A1, A2>::make(f, _0_, _1_, _2_)
|
Chris@16
|
162 , f.proto_base().child0
|
Chris@16
|
163 ));
|
Chris@16
|
164 }
|
Chris@16
|
165 };
|
Chris@16
|
166
|
Chris@16
|
167 namespace detail
|
Chris@16
|
168 {
|
Chris@16
|
169 // Helper struct for SFINAE purposes
|
Chris@16
|
170 template <bool C> struct bool_;
|
Chris@16
|
171
|
Chris@16
|
172 template <>
|
Chris@16
|
173 struct bool_<true> : mpl::bool_<true>
|
Chris@16
|
174 {
|
Chris@16
|
175 typedef bool_<true>* is_true;
|
Chris@16
|
176 };
|
Chris@16
|
177
|
Chris@16
|
178 template <>
|
Chris@16
|
179 struct bool_<false> : mpl::bool_<false>
|
Chris@16
|
180 {
|
Chris@16
|
181 typedef bool_<false>* is_false;
|
Chris@16
|
182 };
|
Chris@16
|
183
|
Chris@16
|
184 // Metafunction to detect if at least one arg is a Phoenix actor
|
Chris@16
|
185 template <
|
Chris@16
|
186 typename A0
|
Chris@16
|
187 , typename A1 = unused_type
|
Chris@16
|
188 , typename A2 = unused_type
|
Chris@16
|
189 >
|
Chris@16
|
190 struct contains_actor
|
Chris@16
|
191 : bool_<
|
Chris@16
|
192 phoenix::is_actor<A0>::value
|
Chris@16
|
193 || phoenix::is_actor<A1>::value
|
Chris@16
|
194 || phoenix::is_actor<A2>::value
|
Chris@16
|
195 >
|
Chris@16
|
196 {};
|
Chris@16
|
197
|
Chris@16
|
198 // to_lazy_arg: convert a terminal arg type to the type make_lazy needs
|
Chris@16
|
199 template <typename A>
|
Chris@16
|
200 struct to_lazy_arg
|
Chris@16
|
201 : phoenix::as_actor<A> // wrap A in a Phoenix actor if not already one
|
Chris@16
|
202 {};
|
Chris@16
|
203
|
Chris@16
|
204 template <typename A>
|
Chris@16
|
205 struct to_lazy_arg<const A>
|
Chris@16
|
206 : to_lazy_arg<A>
|
Chris@16
|
207 {};
|
Chris@16
|
208
|
Chris@16
|
209 template <typename A>
|
Chris@16
|
210 struct to_lazy_arg<A &>
|
Chris@16
|
211 : to_lazy_arg<A>
|
Chris@16
|
212 {};
|
Chris@16
|
213
|
Chris@16
|
214 template <>
|
Chris@16
|
215 struct to_lazy_arg<unused_type>
|
Chris@16
|
216 {
|
Chris@16
|
217 // unused arg: make_lazy wants unused_type
|
Chris@16
|
218 typedef unused_type type;
|
Chris@16
|
219 };
|
Chris@16
|
220
|
Chris@16
|
221 // to_nonlazy_arg: convert a terminal arg type to the type make_vector needs
|
Chris@16
|
222 template <typename A>
|
Chris@16
|
223 struct to_nonlazy_arg
|
Chris@16
|
224 {
|
Chris@16
|
225 // identity
|
Chris@16
|
226 typedef A type;
|
Chris@16
|
227 };
|
Chris@16
|
228
|
Chris@16
|
229 template <typename A>
|
Chris@16
|
230 struct to_nonlazy_arg<const A>
|
Chris@16
|
231 : to_nonlazy_arg<A>
|
Chris@16
|
232 {};
|
Chris@16
|
233
|
Chris@16
|
234 template <typename A>
|
Chris@16
|
235 struct to_nonlazy_arg<A &>
|
Chris@16
|
236 : to_nonlazy_arg<A>
|
Chris@16
|
237 {};
|
Chris@16
|
238
|
Chris@16
|
239 template <>
|
Chris@16
|
240 struct to_nonlazy_arg<unused_type>
|
Chris@16
|
241 {
|
Chris@16
|
242 // unused arg: make_vector wants fusion::void_
|
Chris@16
|
243 typedef fusion::void_ type;
|
Chris@16
|
244 };
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 template <typename Terminal>
|
Chris@16
|
248 struct terminal
|
Chris@16
|
249 : proto::extends<
|
Chris@16
|
250 typename proto::terminal<Terminal>::type
|
Chris@16
|
251 , terminal<Terminal>
|
Chris@16
|
252 >
|
Chris@16
|
253 {
|
Chris@16
|
254 typedef terminal<Terminal> this_type;
|
Chris@16
|
255 typedef Terminal terminal_type;
|
Chris@16
|
256
|
Chris@16
|
257 typedef proto::extends<
|
Chris@16
|
258 typename proto::terminal<Terminal>::type
|
Chris@16
|
259 , terminal<Terminal>
|
Chris@16
|
260 > base_type;
|
Chris@16
|
261
|
Chris@16
|
262 terminal() {}
|
Chris@16
|
263
|
Chris@16
|
264 terminal(Terminal const& t)
|
Chris@16
|
265 : base_type(proto::terminal<Terminal>::type::make(t))
|
Chris@16
|
266 {}
|
Chris@16
|
267
|
Chris@16
|
268 template <
|
Chris@16
|
269 bool Lazy
|
Chris@16
|
270 , typename A0
|
Chris@16
|
271 , typename A1
|
Chris@16
|
272 , typename A2
|
Chris@16
|
273 >
|
Chris@16
|
274 struct result_helper;
|
Chris@16
|
275
|
Chris@16
|
276 template <
|
Chris@16
|
277 typename A0
|
Chris@16
|
278 , typename A1
|
Chris@16
|
279 , typename A2
|
Chris@16
|
280 >
|
Chris@16
|
281 struct result_helper<false, A0, A1, A2>
|
Chris@16
|
282 {
|
Chris@16
|
283 typedef typename
|
Chris@16
|
284 proto::terminal<
|
Chris@16
|
285 terminal_ex<
|
Chris@16
|
286 Terminal
|
Chris@16
|
287 , typename detail::result_of::make_vector<
|
Chris@16
|
288 typename detail::to_nonlazy_arg<A0>::type
|
Chris@16
|
289 , typename detail::to_nonlazy_arg<A1>::type
|
Chris@16
|
290 , typename detail::to_nonlazy_arg<A2>::type>::type>
|
Chris@16
|
291 >::type
|
Chris@16
|
292 type;
|
Chris@16
|
293 };
|
Chris@16
|
294
|
Chris@16
|
295 template <
|
Chris@16
|
296 typename A0
|
Chris@16
|
297 , typename A1
|
Chris@16
|
298 , typename A2
|
Chris@16
|
299 >
|
Chris@16
|
300 struct result_helper<true, A0, A1, A2>
|
Chris@16
|
301 {
|
Chris@16
|
302 typedef typename
|
Chris@16
|
303 make_lazy<this_type
|
Chris@16
|
304 , typename detail::to_lazy_arg<A0>::type
|
Chris@16
|
305 , typename detail::to_lazy_arg<A1>::type
|
Chris@16
|
306 , typename detail::to_lazy_arg<A2>::type>::type
|
Chris@16
|
307 type;
|
Chris@16
|
308 };
|
Chris@16
|
309
|
Chris@16
|
310 // FIXME: we need to change this to conform to the result_of protocol
|
Chris@16
|
311 template <
|
Chris@16
|
312 typename A0
|
Chris@16
|
313 , typename A1 = unused_type
|
Chris@16
|
314 , typename A2 = unused_type // Support up to 3 args
|
Chris@16
|
315 >
|
Chris@16
|
316 struct result
|
Chris@16
|
317 {
|
Chris@16
|
318 typedef typename
|
Chris@16
|
319 result_helper<
|
Chris@16
|
320 detail::contains_actor<A0, A1, A2>::value
|
Chris@16
|
321 , A0, A1, A2
|
Chris@16
|
322 >::type
|
Chris@16
|
323 type;
|
Chris@16
|
324 };
|
Chris@16
|
325
|
Chris@16
|
326 template <typename This, typename A0>
|
Chris@16
|
327 struct result<This(A0)>
|
Chris@16
|
328 {
|
Chris@16
|
329 typedef typename
|
Chris@16
|
330 result_helper<
|
Chris@16
|
331 detail::contains_actor<A0, unused_type, unused_type>::value
|
Chris@16
|
332 , A0, unused_type, unused_type
|
Chris@16
|
333 >::type
|
Chris@16
|
334 type;
|
Chris@16
|
335 };
|
Chris@16
|
336
|
Chris@16
|
337 template <typename This, typename A0, typename A1>
|
Chris@16
|
338 struct result<This(A0, A1)>
|
Chris@16
|
339 {
|
Chris@16
|
340 typedef typename
|
Chris@16
|
341 result_helper<
|
Chris@16
|
342 detail::contains_actor<A0, A1, unused_type>::value
|
Chris@16
|
343 , A0, A1, unused_type
|
Chris@16
|
344 >::type
|
Chris@16
|
345 type;
|
Chris@16
|
346 };
|
Chris@16
|
347
|
Chris@16
|
348
|
Chris@16
|
349 template <typename This, typename A0, typename A1, typename A2>
|
Chris@16
|
350 struct result<This(A0, A1, A2)>
|
Chris@16
|
351 {
|
Chris@16
|
352 typedef typename
|
Chris@16
|
353 result_helper<
|
Chris@16
|
354 detail::contains_actor<A0, A1, A2>::value
|
Chris@16
|
355 , A0, A1, A2
|
Chris@16
|
356 >::type
|
Chris@16
|
357 type;
|
Chris@16
|
358 };
|
Chris@16
|
359
|
Chris@16
|
360 // Note: in the following overloads, SFINAE cannot
|
Chris@16
|
361 // be done on return type because of gcc bug #24915:
|
Chris@16
|
362 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915
|
Chris@16
|
363 // Hence an additional, fake argument is used for SFINAE,
|
Chris@16
|
364 // using a type which can never be a real argument type.
|
Chris@16
|
365
|
Chris@16
|
366 // Non-lazy overloads. Only enabled when all
|
Chris@16
|
367 // args are immediates (no Phoenix actor).
|
Chris@16
|
368
|
Chris@16
|
369 template <typename A0>
|
Chris@16
|
370 typename result<A0>::type
|
Chris@16
|
371 operator()(A0 const& _0_
|
Chris@16
|
372 , typename detail::contains_actor<A0>::is_false = 0) const
|
Chris@16
|
373 {
|
Chris@16
|
374 typedef typename result<A0>::type result_type;
|
Chris@16
|
375 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
376 return result_type::make(
|
Chris@16
|
377 child_type(
|
Chris@16
|
378 detail::make_vector(_0_)
|
Chris@16
|
379 , this->proto_base().child0)
|
Chris@16
|
380 );
|
Chris@16
|
381 }
|
Chris@16
|
382
|
Chris@16
|
383 template <typename A0, typename A1>
|
Chris@16
|
384 typename result<A0, A1>::type
|
Chris@16
|
385 operator()(A0 const& _0_, A1 const& _1_
|
Chris@16
|
386 , typename detail::contains_actor<A0, A1>::is_false = 0) const
|
Chris@16
|
387 {
|
Chris@16
|
388 typedef typename result<A0, A1>::type result_type;
|
Chris@16
|
389 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
390 return result_type::make(
|
Chris@16
|
391 child_type(
|
Chris@16
|
392 detail::make_vector(_0_, _1_)
|
Chris@16
|
393 , this->proto_base().child0)
|
Chris@16
|
394 );
|
Chris@16
|
395 }
|
Chris@16
|
396
|
Chris@16
|
397 template <typename A0, typename A1, typename A2>
|
Chris@16
|
398 typename result<A0, A1, A2>::type
|
Chris@16
|
399 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
|
Chris@16
|
400 , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const
|
Chris@16
|
401 {
|
Chris@16
|
402 typedef typename result<A0, A1, A2>::type result_type;
|
Chris@16
|
403 typedef typename result_type::proto_child0 child_type;
|
Chris@16
|
404 return result_type::make(
|
Chris@16
|
405 child_type(
|
Chris@16
|
406 detail::make_vector(_0_, _1_, _2_)
|
Chris@16
|
407 , this->proto_base().child0)
|
Chris@16
|
408 );
|
Chris@16
|
409 }
|
Chris@16
|
410
|
Chris@16
|
411 // Lazy overloads. Enabled when at
|
Chris@16
|
412 // least one arg is a Phoenix actor.
|
Chris@16
|
413 template <typename A0>
|
Chris@16
|
414 typename result<A0>::type
|
Chris@16
|
415 operator()(A0 const& _0_
|
Chris@16
|
416 , typename detail::contains_actor<A0>::is_true = 0) const
|
Chris@16
|
417 {
|
Chris@16
|
418 return make_lazy<this_type
|
Chris@16
|
419 , typename phoenix::as_actor<A0>::type>()(*this
|
Chris@16
|
420 , phoenix::as_actor<A0>::convert(_0_));
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 template <typename A0, typename A1>
|
Chris@16
|
424 typename result<A0, A1>::type
|
Chris@16
|
425 operator()(A0 const& _0_, A1 const& _1_
|
Chris@16
|
426 , typename detail::contains_actor<A0, A1>::is_true = 0) const
|
Chris@16
|
427 {
|
Chris@16
|
428 return make_lazy<this_type
|
Chris@16
|
429 , typename phoenix::as_actor<A0>::type
|
Chris@16
|
430 , typename phoenix::as_actor<A1>::type>()(*this
|
Chris@16
|
431 , phoenix::as_actor<A0>::convert(_0_)
|
Chris@16
|
432 , phoenix::as_actor<A1>::convert(_1_));
|
Chris@16
|
433 }
|
Chris@16
|
434
|
Chris@16
|
435 template <typename A0, typename A1, typename A2>
|
Chris@16
|
436 typename result<A0, A1, A2>::type
|
Chris@16
|
437 operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
|
Chris@16
|
438 , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const
|
Chris@16
|
439 {
|
Chris@16
|
440 return make_lazy<this_type
|
Chris@16
|
441 , typename phoenix::as_actor<A0>::type
|
Chris@16
|
442 , typename phoenix::as_actor<A1>::type
|
Chris@16
|
443 , typename phoenix::as_actor<A2>::type>()(*this
|
Chris@16
|
444 , phoenix::as_actor<A0>::convert(_0_)
|
Chris@16
|
445 , phoenix::as_actor<A1>::convert(_1_)
|
Chris@16
|
446 , phoenix::as_actor<A2>::convert(_2_));
|
Chris@16
|
447 }
|
Chris@16
|
448
|
Chris@16
|
449 private:
|
Chris@16
|
450 // silence MSVC warning C4512: assignment operator could not be generated
|
Chris@16
|
451 terminal& operator= (terminal const&);
|
Chris@16
|
452 };
|
Chris@16
|
453
|
Chris@16
|
454 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
455 namespace result_of
|
Chris@16
|
456 {
|
Chris@16
|
457 // Calculate the type of the compound terminal if generated by one of
|
Chris@16
|
458 // the spirit::terminal::operator() overloads above
|
Chris@16
|
459
|
Chris@16
|
460 // The terminal type itself is passed through without modification
|
Chris@16
|
461 template <typename Tag>
|
Chris@16
|
462 struct terminal
|
Chris@16
|
463 {
|
Chris@16
|
464 typedef spirit::terminal<Tag> type;
|
Chris@16
|
465 };
|
Chris@16
|
466
|
Chris@16
|
467 template <typename Tag, typename A0>
|
Chris@16
|
468 struct terminal<Tag(A0)>
|
Chris@16
|
469 {
|
Chris@16
|
470 typedef typename spirit::terminal<Tag>::
|
Chris@16
|
471 template result<A0>::type type;
|
Chris@16
|
472 };
|
Chris@16
|
473
|
Chris@16
|
474 template <typename Tag, typename A0, typename A1>
|
Chris@16
|
475 struct terminal<Tag(A0, A1)>
|
Chris@16
|
476 {
|
Chris@16
|
477 typedef typename spirit::terminal<Tag>::
|
Chris@16
|
478 template result<A0, A1>::type type;
|
Chris@16
|
479 };
|
Chris@16
|
480
|
Chris@16
|
481 template <typename Tag, typename A0, typename A1, typename A2>
|
Chris@16
|
482 struct terminal<Tag(A0, A1, A2)>
|
Chris@16
|
483 {
|
Chris@16
|
484 typedef typename spirit::terminal<Tag>::
|
Chris@16
|
485 template result<A0, A1, A2>::type type;
|
Chris@16
|
486 };
|
Chris@16
|
487 }
|
Chris@16
|
488
|
Chris@16
|
489 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
490 // support for stateful tag types
|
Chris@16
|
491 namespace tag
|
Chris@16
|
492 {
|
Chris@16
|
493 template <
|
Chris@16
|
494 typename Data, typename Tag
|
Chris@16
|
495 , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
|
Chris@16
|
496 struct stateful_tag
|
Chris@16
|
497 {
|
Chris@16
|
498 BOOST_SPIRIT_IS_TAG()
|
Chris@16
|
499
|
Chris@16
|
500 typedef Data data_type;
|
Chris@16
|
501
|
Chris@16
|
502 stateful_tag() {}
|
Chris@16
|
503 stateful_tag(data_type const& data) : data_(data) {}
|
Chris@16
|
504
|
Chris@16
|
505 data_type data_;
|
Chris@16
|
506
|
Chris@16
|
507 private:
|
Chris@16
|
508 // silence MSVC warning C4512: assignment operator could not be generated
|
Chris@16
|
509 stateful_tag& operator= (stateful_tag const&);
|
Chris@16
|
510 };
|
Chris@16
|
511 }
|
Chris@16
|
512
|
Chris@16
|
513 template <
|
Chris@16
|
514 typename Data, typename Tag
|
Chris@16
|
515 , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
|
Chris@16
|
516 struct stateful_tag_type
|
Chris@16
|
517 : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> >
|
Chris@16
|
518 {
|
Chris@16
|
519 typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type;
|
Chris@16
|
520
|
Chris@16
|
521 stateful_tag_type() {}
|
Chris@16
|
522 stateful_tag_type(Data const& data)
|
Chris@16
|
523 : spirit::terminal<tag_type>(data)
|
Chris@16
|
524 {}
|
Chris@16
|
525
|
Chris@16
|
526 private:
|
Chris@16
|
527 // silence MSVC warning C4512: assignment operator could not be generated
|
Chris@16
|
528 stateful_tag_type& operator= (stateful_tag_type const&);
|
Chris@16
|
529 };
|
Chris@16
|
530
|
Chris@16
|
531 namespace detail
|
Chris@16
|
532 {
|
Chris@16
|
533 // extract expression if this is a Tag
|
Chris@16
|
534 template <typename StatefulTag>
|
Chris@16
|
535 struct get_stateful_data
|
Chris@16
|
536 {
|
Chris@16
|
537 typedef typename StatefulTag::data_type data_type;
|
Chris@16
|
538
|
Chris@16
|
539 // is invoked if given tag is != Tag
|
Chris@16
|
540 template <typename Tag_>
|
Chris@16
|
541 static data_type call(Tag_) { return data_type(); }
|
Chris@16
|
542
|
Chris@16
|
543 // this is invoked if given tag is same as'Tag'
|
Chris@16
|
544 static data_type const& call(StatefulTag const& t) { return t.data_; }
|
Chris@16
|
545 };
|
Chris@16
|
546 }
|
Chris@16
|
547
|
Chris@16
|
548 }}
|
Chris@16
|
549
|
Chris@16
|
550 namespace boost { namespace phoenix
|
Chris@16
|
551 {
|
Chris@16
|
552 template <typename Tag>
|
Chris@16
|
553 struct is_custom_terminal<Tag, typename Tag::is_spirit_tag>
|
Chris@16
|
554 : mpl::true_
|
Chris@16
|
555 {};
|
Chris@16
|
556
|
Chris@16
|
557 template <typename Tag>
|
Chris@16
|
558 struct custom_terminal<Tag, typename Tag::is_spirit_tag>
|
Chris@16
|
559 {
|
Chris@101
|
560 #ifndef BOOST_PHOENIX_NO_SPECIALIZE_CUSTOM_TERMINAL
|
Chris@101
|
561 typedef void _is_default_custom_terminal; // fix for #7730
|
Chris@101
|
562 #endif
|
Chris@101
|
563
|
Chris@16
|
564 typedef spirit::terminal<Tag> result_type;
|
Chris@16
|
565
|
Chris@16
|
566 template <typename Context>
|
Chris@16
|
567 result_type operator()(Tag const & t, Context const &)
|
Chris@16
|
568 {
|
Chris@16
|
569 return spirit::terminal<Tag>(t);
|
Chris@16
|
570 }
|
Chris@16
|
571 };
|
Chris@16
|
572 }}
|
Chris@16
|
573
|
Chris@16
|
574 // Define a spirit terminal. This macro may be placed in any namespace.
|
Chris@16
|
575 // Common placeholders are placed in the main boost::spirit namespace
|
Chris@16
|
576 // (see common_terminals.hpp)
|
Chris@16
|
577
|
Chris@16
|
578 #define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
|
Chris@16
|
579 #define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
|
Chris@16
|
580 #define BOOST_SPIRIT_TERMINAL_X0
|
Chris@16
|
581 #define BOOST_SPIRIT_TERMINAL_Y0
|
Chris@16
|
582
|
Chris@16
|
583 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
|
Chris@16
|
584
|
Chris@16
|
585 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \
|
Chris@16
|
586 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
|
Chris@16
|
587 typedef boost::proto::terminal<tag::name>::type type_name; \
|
Chris@16
|
588 type_name const name = {{}}; \
|
Chris@16
|
589 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
|
Chris@16
|
590 /***/
|
Chris@16
|
591
|
Chris@16
|
592 #else
|
Chris@16
|
593
|
Chris@16
|
594 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \
|
Chris@16
|
595 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
|
Chris@16
|
596 typedef boost::proto::terminal<tag::name>::type type_name; \
|
Chris@16
|
597 /***/
|
Chris@16
|
598
|
Chris@16
|
599 #endif
|
Chris@16
|
600
|
Chris@16
|
601 #define BOOST_SPIRIT_TERMINAL(name) \
|
Chris@16
|
602 BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type) \
|
Chris@16
|
603 /***/
|
Chris@16
|
604
|
Chris@16
|
605 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names) \
|
Chris@16
|
606 BOOST_SPIRIT_TERMINAL_NAME( \
|
Chris@16
|
607 BOOST_PP_TUPLE_ELEM(2, 0, names), \
|
Chris@16
|
608 BOOST_PP_TUPLE_ELEM(2, 1, names) \
|
Chris@16
|
609 ) \
|
Chris@16
|
610 /***/
|
Chris@16
|
611
|
Chris@16
|
612 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq) \
|
Chris@16
|
613 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _, \
|
Chris@16
|
614 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \
|
Chris@16
|
615 /***/
|
Chris@16
|
616
|
Chris@16
|
617 // Define a spirit extended terminal. This macro may be placed in any namespace.
|
Chris@16
|
618 // Common placeholders are placed in the main boost::spirit namespace
|
Chris@16
|
619 // (see common_terminals.hpp)
|
Chris@16
|
620
|
Chris@16
|
621 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
|
Chris@16
|
622
|
Chris@16
|
623 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \
|
Chris@16
|
624 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
|
Chris@16
|
625 typedef boost::spirit::terminal<tag::name> type_name; \
|
Chris@16
|
626 type_name const name = type_name(); \
|
Chris@16
|
627 inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
|
Chris@16
|
628 /***/
|
Chris@16
|
629
|
Chris@16
|
630 #else
|
Chris@16
|
631
|
Chris@16
|
632 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \
|
Chris@16
|
633 namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
|
Chris@16
|
634 typedef boost::spirit::terminal<tag::name> type_name; \
|
Chris@16
|
635 /***/
|
Chris@16
|
636
|
Chris@16
|
637 #endif
|
Chris@16
|
638
|
Chris@16
|
639 #define BOOST_SPIRIT_TERMINAL_EX(name) \
|
Chris@16
|
640 BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type) \
|
Chris@16
|
641 /***/
|
Chris@16
|
642
|
Chris@16
|
643 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names) \
|
Chris@16
|
644 BOOST_SPIRIT_TERMINAL_NAME_EX( \
|
Chris@16
|
645 BOOST_PP_TUPLE_ELEM(2, 0, names), \
|
Chris@16
|
646 BOOST_PP_TUPLE_ELEM(2, 1, names) \
|
Chris@16
|
647 ) \
|
Chris@16
|
648 /***/
|
Chris@16
|
649
|
Chris@16
|
650 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq) \
|
Chris@16
|
651 BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _, \
|
Chris@16
|
652 BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \
|
Chris@16
|
653 /***/
|
Chris@16
|
654
|
Chris@16
|
655 #endif
|
Chris@16
|
656
|
Chris@16
|
657
|