d52fad2c3a71be65c7e3519a090ba0b1ab54d90d
[platform/upstream/boost.git] / boost / spirit / home / support / terminal.hpp
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
36         terminal_ex(Args const& args)
37           : args(args) {}
38         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
53         lazy_terminal(Actor const& actor)
54           : actor(actor) {}
55         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
107         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
132         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
157         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
262         terminal() {}
263
264         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
371         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
385         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
399         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
415         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
425         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
437         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
502             stateful_tag() {}
503             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
521         stateful_tag_type() {}
522         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_>
541             static data_type call(Tag_) { return data_type(); }
542
543             // this is invoked if given tag is same as'Tag'
544             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>
564         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