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