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/spirit/include/phoenix_core.hpp>
17 #include <boost/spirit/include/phoenix_function.hpp>
18 #include <boost/proto/proto.hpp>
19 #include <boost/fusion/include/void.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         template <>
240         struct to_nonlazy_arg<unused_type>
241         {
242             // unused arg: make_vector wants fusion::void_
243             typedef fusion::void_ type;
244         };
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 
terminalboost::spirit::terminal262         terminal() {}
263 
terminalboost::spirit::terminal264         terminal(Terminal const& t)
265           : base_type(proto::terminal<Terminal>::type::make(t))
266         {}
267 
268         template <
269             bool Lazy
270           , typename A0
271           , typename A1
272           , typename A2
273         >
274         struct result_helper;
275 
276         template <
277             typename A0
278           , typename A1
279           , typename A2
280         >
281         struct result_helper<false, A0, A1, A2>
282         {
283             typedef typename
284                 proto::terminal<
285                     terminal_ex<
286                         Terminal
287                       , typename detail::result_of::make_vector<
288                             typename detail::to_nonlazy_arg<A0>::type
289                           , typename detail::to_nonlazy_arg<A1>::type
290                           , typename detail::to_nonlazy_arg<A2>::type>::type>
291                 >::type
292             type;
293         };
294 
295         template <
296             typename A0
297           , typename A1
298           , typename A2
299         >
300         struct result_helper<true, A0, A1, A2>
301         {
302             typedef typename
303                 make_lazy<this_type
304                   , typename detail::to_lazy_arg<A0>::type
305                   , typename detail::to_lazy_arg<A1>::type
306                   , typename detail::to_lazy_arg<A2>::type>::type
307             type;
308         };
309 
310         // FIXME: we need to change this to conform to the result_of protocol
311         template <
312             typename A0
313           , typename A1 = unused_type
314           , typename A2 = unused_type      // Support up to 3 args
315         >
316         struct result
317         {
318             typedef typename
319                 result_helper<
320                     detail::contains_actor<A0, A1, A2>::value
321                   , A0, A1, A2
322                 >::type
323             type;
324         };
325 
326         template <typename This, typename A0>
327         struct result<This(A0)>
328         {
329             typedef typename
330                 result_helper<
331                     detail::contains_actor<A0, unused_type, unused_type>::value
332                   , A0, unused_type, unused_type
333                 >::type
334             type;
335         };
336 
337         template <typename This, typename A0, typename A1>
338         struct result<This(A0, A1)>
339         {
340             typedef typename
341                 result_helper<
342                     detail::contains_actor<A0, A1, unused_type>::value
343                   , A0, A1, unused_type
344                 >::type
345             type;
346         };
347 
348 
349         template <typename This, typename A0, typename A1, typename A2>
350         struct result<This(A0, A1, A2)>
351         {
352             typedef typename
353                 result_helper<
354                      detail::contains_actor<A0, A1, A2>::value
355                    , A0, A1, A2
356                  >::type
357                  type;
358         };
359 
360         // Note: in the following overloads, SFINAE cannot
361         // be done on return type because of gcc bug #24915:
362         //   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915
363         // Hence an additional, fake argument is used for SFINAE,
364         // using a type which can never be a real argument type.
365 
366         // Non-lazy overloads. Only enabled when all
367         // args are immediates (no Phoenix actor).
368 
369         template <typename A0>
370         typename result<A0>::type
operator ()boost::spirit::terminal371         operator()(A0 const& _0
372           , typename detail::contains_actor<A0>::is_false = 0) const
373         {
374             typedef typename result<A0>::type result_type;
375             typedef typename result_type::proto_child0 child_type;
376             return result_type::make(
377                 child_type(
378                     detail::make_vector(_0)
379                   , this->proto_base().child0)
380             );
381         }
382 
383         template <typename A0, typename A1>
384         typename result<A0, A1>::type
operator ()boost::spirit::terminal385         operator()(A0 const& _0, A1 const& _1
386           , typename detail::contains_actor<A0, A1>::is_false = 0) const
387         {
388             typedef typename result<A0, A1>::type result_type;
389             typedef typename result_type::proto_child0 child_type;
390             return result_type::make(
391                 child_type(
392                     detail::make_vector(_0, _1)
393                   , this->proto_base().child0)
394             );
395         }
396 
397         template <typename A0, typename A1, typename A2>
398         typename result<A0, A1, A2>::type
operator ()boost::spirit::terminal399         operator()(A0 const& _0, A1 const& _1, A2 const& _2
400           , typename detail::contains_actor<A0, A1, A2>::is_false = 0) const
401         {
402             typedef typename result<A0, A1, A2>::type result_type;
403             typedef typename result_type::proto_child0 child_type;
404             return result_type::make(
405                 child_type(
406                     detail::make_vector(_0, _1, _2)
407                   , this->proto_base().child0)
408             );
409         }
410 
411         // Lazy overloads. Enabled when at
412         // least one arg is a Phoenix actor.
413         template <typename A0>
414         typename result<A0>::type
operator ()boost::spirit::terminal415         operator()(A0 const& _0
416           , typename detail::contains_actor<A0>::is_true = 0) const
417         {
418             return make_lazy<this_type
419               , typename phoenix::as_actor<A0>::type>()(*this
420               , phoenix::as_actor<A0>::convert(_0));
421         }
422 
423         template <typename A0, typename A1>
424         typename result<A0, A1>::type
operator ()boost::spirit::terminal425         operator()(A0 const& _0, A1 const& _1
426           , typename detail::contains_actor<A0, A1>::is_true = 0) const
427         {
428             return make_lazy<this_type
429               , typename phoenix::as_actor<A0>::type
430               , typename phoenix::as_actor<A1>::type>()(*this
431               , phoenix::as_actor<A0>::convert(_0)
432               , phoenix::as_actor<A1>::convert(_1));
433         }
434 
435         template <typename A0, typename A1, typename A2>
436         typename result<A0, A1, A2>::type
operator ()boost::spirit::terminal437         operator()(A0 const& _0, A1 const& _1, A2 const& _2
438           , typename detail::contains_actor<A0, A1, A2>::is_true = 0) const
439         {
440             return make_lazy<this_type
441               , typename phoenix::as_actor<A0>::type
442               , typename phoenix::as_actor<A1>::type
443               , typename phoenix::as_actor<A2>::type>()(*this
444               , phoenix::as_actor<A0>::convert(_0)
445               , phoenix::as_actor<A1>::convert(_1)
446               , phoenix::as_actor<A2>::convert(_2));
447         }
448 
449     private:
450         // silence MSVC warning C4512: assignment operator could not be generated
451         terminal& operator= (terminal const&);
452     };
453 
454     ///////////////////////////////////////////////////////////////////////////
455     namespace result_of
456     {
457         // Calculate the type of the compound terminal if generated by one of
458         // the spirit::terminal::operator() overloads above
459 
460         // The terminal type itself is passed through without modification
461         template <typename Tag>
462         struct terminal
463         {
464             typedef spirit::terminal<Tag> type;
465         };
466 
467         template <typename Tag, typename A0>
468         struct terminal<Tag(A0)>
469         {
470             typedef typename spirit::terminal<Tag>::
471                 template result<A0>::type type;
472         };
473 
474         template <typename Tag, typename A0, typename A1>
475         struct terminal<Tag(A0, A1)>
476         {
477             typedef typename spirit::terminal<Tag>::
478                 template result<A0, A1>::type type;
479         };
480 
481         template <typename Tag, typename A0, typename A1, typename A2>
482         struct terminal<Tag(A0, A1, A2)>
483         {
484             typedef typename spirit::terminal<Tag>::
485                 template result<A0, A1, A2>::type type;
486         };
487     }
488 
489     ///////////////////////////////////////////////////////////////////////////
490     // support for stateful tag types
491     namespace tag
492     {
493         template <
494             typename Data, typename Tag
495           , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
496         struct stateful_tag
497         {
498             BOOST_SPIRIT_IS_TAG()
499 
500             typedef Data data_type;
501 
stateful_tagboost::spirit::tag::stateful_tag502             stateful_tag() {}
stateful_tagboost::spirit::tag::stateful_tag503             stateful_tag(data_type const& data) : data_(data) {}
504 
505             data_type data_;
506 
507         private:
508             // silence MSVC warning C4512: assignment operator could not be generated
509             stateful_tag& operator= (stateful_tag const&);
510         };
511     }
512 
513     template <
514         typename Data, typename Tag
515       , typename DataTag1 = unused_type, typename DataTag2 = unused_type>
516     struct stateful_tag_type
517       : spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> >
518     {
519         typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type;
520 
stateful_tag_typeboost::spirit::stateful_tag_type521         stateful_tag_type() {}
stateful_tag_typeboost::spirit::stateful_tag_type522         stateful_tag_type(Data const& data)
523           : spirit::terminal<tag_type>(data)
524         {}
525 
526     private:
527         // silence MSVC warning C4512: assignment operator could not be generated
528         stateful_tag_type& operator= (stateful_tag_type const&);
529     };
530 
531     namespace detail
532     {
533         // extract expression if this is a Tag
534         template <typename StatefulTag>
535         struct get_stateful_data
536         {
537             typedef typename StatefulTag::data_type data_type;
538 
539             // is invoked if given tag is != Tag
540             template <typename Tag_>
callboost::spirit::detail::get_stateful_data541             static data_type call(Tag_) { return data_type(); }
542 
543             // this is invoked if given tag is same as'Tag'
callboost::spirit::detail::get_stateful_data544             static data_type const& call(StatefulTag const& t) { return t.data_; }
545         };
546     }
547 
548 }}
549 
550 #ifdef BOOST_SPIRIT_USE_PHOENIX_V3
551 namespace boost { namespace phoenix
552 {
553     template <typename Tag>
554     struct is_custom_terminal<Tag, typename Tag::is_spirit_tag>
555       : mpl::true_
556     {};
557 
558     template <typename Tag>
559     struct custom_terminal<Tag, typename Tag::is_spirit_tag>
560     {
561         typedef spirit::terminal<Tag> result_type;
562 
563         template <typename Context>
operator ()boost::phoenix::custom_terminal564         result_type operator()(Tag const & t, Context const &)
565         {
566             return spirit::terminal<Tag>(t);
567         }
568     };
569 }}
570 #endif
571 
572 // Define a spirit terminal. This macro may be placed in any namespace.
573 // Common placeholders are placed in the main boost::spirit namespace
574 // (see common_terminals.hpp)
575 
576 #define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
577 #define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
578 #define BOOST_SPIRIT_TERMINAL_X0
579 #define BOOST_SPIRIT_TERMINAL_Y0
580 
581 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
582 
583 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name)                             \
584     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
585     typedef boost::proto::terminal<tag::name>::type type_name;                  \
586     type_name const name = {{}};                                                \
587     inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
588     /***/
589 
590 #else
591 
592 #define BOOST_SPIRIT_TERMINAL_NAME(name, type_name)                             \
593     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
594     typedef boost::proto::terminal<tag::name>::type type_name;                  \
595     /***/
596 
597 #endif
598 
599 #define BOOST_SPIRIT_TERMINAL(name)                                             \
600     BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type)                             \
601     /***/
602 
603 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names)                       \
604     BOOST_SPIRIT_TERMINAL_NAME(                                                 \
605         BOOST_PP_TUPLE_ELEM(2, 0, names),                                       \
606         BOOST_PP_TUPLE_ELEM(2, 1, names)                                        \
607     )                                                                           \
608     /***/
609 
610 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq)                                 \
611     BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _,              \
612         BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0))                           \
613     /***/
614 
615 // Define a spirit extended terminal. This macro may be placed in any namespace.
616 // Common placeholders are placed in the main boost::spirit namespace
617 // (see common_terminals.hpp)
618 
619 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
620 
621 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name)                          \
622     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
623     typedef boost::spirit::terminal<tag::name> type_name;                       \
624     type_name const name = type_name();                                         \
625     inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
626     /***/
627 
628 #else
629 
630 #define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name)                          \
631     namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; }                    \
632     typedef boost::spirit::terminal<tag::name> type_name;                       \
633     /***/
634 
635 #endif
636 
637 #define BOOST_SPIRIT_TERMINAL_EX(name)                                          \
638     BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type)                          \
639     /***/
640 
641 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names)                    \
642     BOOST_SPIRIT_TERMINAL_NAME_EX(                                              \
643         BOOST_PP_TUPLE_ELEM(2, 0, names),                                       \
644         BOOST_PP_TUPLE_ELEM(2, 1, names)                                        \
645     )                                                                           \
646     /***/
647 
648 #define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq)                              \
649     BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _,           \
650         BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0))                           \
651     /***/
652 
653 #endif
654 
655 
656