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