1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM)
7 #define BOOST_SPIRIT_SUPPORT_META_CREATE_NOV_21_2009_0327PM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/support/unused.hpp>
14 
15 #include <boost/version.hpp>
16 #include <boost/proto/make_expr.hpp>
17 #include <boost/proto/traits.hpp>
18 #include <boost/utility/result_of.hpp>
19 #include <boost/type_traits/add_const.hpp>
20 #include <boost/type_traits/add_reference.hpp>
21 #include <boost/type_traits/remove_const.hpp>
22 #include <boost/type_traits/remove_reference.hpp>
23 #include <boost/fusion/include/fold.hpp>
24 #include <boost/mpl/and.hpp>
25 #include <boost/mpl/not.hpp>
26 
27 // needed for workaround below
28 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
29 #include <boost/type_traits/is_same.hpp>
30 #endif
31 
32 namespace boost { namespace spirit { namespace traits
33 {
34     ///////////////////////////////////////////////////////////////////////////
35     // This is the main dispatch point for meta_create to the correct domain
36     template <typename Domain, typename T, typename Enable = void>
37     struct meta_create;
38 
39     ///////////////////////////////////////////////////////////////////////////
40     // This allows to query whether a valid mapping exists for the given data
41     // type to a component in the given domain
42     template <typename Domain, typename T, typename Enable = void>
43     struct meta_create_exists : mpl::false_ {};
44 }}}
45 
46 namespace boost { namespace spirit
47 {
48     ///////////////////////////////////////////////////////////////////////////
49     namespace detail
50     {
51         template <typename T>
52         struct add_const_ref
53           : add_reference<typename add_const<T>::type> {};
54 
55         template <typename T>
56         struct remove_const_ref
57           : remove_const<typename remove_reference<T>::type> {};
58 
59 // starting with Boost V1.42 fusion::fold has been changed to be compatible
60 // with mpl::fold (the sequence of template parameters for the meta-function
61 // object has been changed)
62 #if BOOST_VERSION < 104200
63         ///////////////////////////////////////////////////////////////////////
64         template <typename OpTag, typename Domain>
65         struct nary_proto_expr_function
66         {
67             template <typename T>
68             struct result;
69 
70 // this is a workaround for older versions of g++ (< V4.3) which apparently have
71 // problems with the following template specialization
72 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
73             template <typename F, typename T1, typename T2>
74             struct result<F(T1, T2)>
75             {
76                 BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value));
77 #else
78             template <typename T1, typename T2>
79             struct result<nary_proto_expr_function(T1, T2)>
80             {
81 #endif
82                 typedef typename remove_const_ref<T2>::type left_type;
83                 typedef typename
84                     spirit::traits::meta_create<Domain, T1>::type
85                 right_type;
86 
87                 typedef typename mpl::eval_if<
88                     traits::not_is_unused<left_type>
89                   , proto::result_of::make_expr<OpTag, left_type, right_type>
90                   , mpl::identity<right_type>
91                 >::type type;
92             };
93 
94             template <typename T>
95             typename result<nary_proto_expr_function(T, unused_type const&)>::type
operator ()boost::spirit::detail::nary_proto_expr_function96             operator()(T, unused_type const&) const
97             {
98                 typedef spirit::traits::meta_create<Domain, T> right_type;
99                 return right_type::call();
100             }
101 
102             template <typename T1, typename T2>
103             typename result<nary_proto_expr_function(T1, T2)>::type
operator ()boost::spirit::detail::nary_proto_expr_function104             operator()(T1, T2 const& t2) const
105             {
106                 // we variants to the alternative operator
107                 typedef spirit::traits::meta_create<Domain, T1> right_type;
108                 return proto::make_expr<OpTag>(t2, right_type::call());
109             }
110         };
111 #else
112         ///////////////////////////////////////////////////////////////////////
113         template <typename OpTag, typename Domain>
114         struct nary_proto_expr_function
115         {
116             template <typename T>
117             struct result;
118 
119 // this is a workaround for older versions of g++ (< V4.3) which apparently have
120 // problems with the following template specialization
121 #if defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ < 3))
122             template <typename F, typename T1, typename T2>
123             struct result<F(T1, T2)>
124             {
125                 BOOST_STATIC_ASSERT((is_same<F, nary_proto_expr_function>::value));
126 #else
127             template <typename T1, typename T2>
128             struct result<nary_proto_expr_function(T1, T2)>
129             {
130 #endif
131                 typedef typename remove_const_ref<T1>::type left_type;
132                 typedef typename
133                     spirit::traits::meta_create<Domain, T2>::type
134                 right_type;
135 
136                 typedef typename mpl::eval_if<
137                     traits::not_is_unused<left_type>
138                   , proto::result_of::make_expr<OpTag, left_type, right_type>
139                   , mpl::identity<right_type>
140                 >::type type;
141             };
142 
143             template <typename T>
144             typename result<nary_proto_expr_function(unused_type const&, T)>::type
operator ()boost::spirit::detail::nary_proto_expr_function145             operator()(unused_type const&, T) const
146             {
147                 typedef spirit::traits::meta_create<Domain, T> right_type;
148                 return right_type::call();
149             }
150 
151             template <typename T1, typename T2>
152             typename result<nary_proto_expr_function(T1, T2)>::type
operator ()boost::spirit::detail::nary_proto_expr_function153             operator()(T1 const& t1, T2) const
154             {
155                 // we variants to the alternative operator
156                 typedef spirit::traits::meta_create<Domain, T2> right_type;
157                 return proto::make_expr<OpTag>(t1, right_type::call());
158             }
159         };
160 #endif
161     }
162 
163     ///////////////////////////////////////////////////////////////////////
164     template <typename T, typename OpTag, typename Domain>
165     struct make_unary_proto_expr
166     {
167         typedef spirit::traits::meta_create<Domain, T> subject_type;
168 
169         typedef typename proto::result_of::make_expr<
170             OpTag, typename subject_type::type
171         >::type type;
172 
callboost::spirit::make_unary_proto_expr173         static type call()
174         {
175             return proto::make_expr<OpTag>(subject_type::call());
176         }
177     };
178 
179     ///////////////////////////////////////////////////////////////////////////
180     template <typename Sequence, typename OpTag, typename Domain>
181     struct make_nary_proto_expr
182     {
183         typedef detail::nary_proto_expr_function<OpTag, Domain>
184             make_proto_expr;
185 
186         typedef typename fusion::result_of::fold<
187             Sequence, unused_type, make_proto_expr
188         >::type type;
189 
callboost::spirit::make_nary_proto_expr190         static type call()
191         {
192             return fusion::fold(Sequence(), unused, make_proto_expr());
193         }
194     };
195 
196     ///////////////////////////////////////////////////////////////////////////
197     namespace detail
198     {
199         // Starting with newer versions of Proto, all Proto expressions are at
200         // the same time Fusion sequences. This is the correct behavior, but
201         // we need to distinguish between Fusion sequences and Proto
202         // expressions. This meta-function does exactly that.
203         template <typename T>
204         struct is_fusion_sequence_but_not_proto_expr
205           : mpl::and_<
206                 fusion::traits::is_sequence<T>
207               , mpl::not_<proto::is_expr<T> > >
208         {};
209     }
210 }}
211 
212 #endif
213