]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2001-2014 Joel de Guzman | |
3 | ||
4 | Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | =============================================================================*/ | |
11fdf7f2 TL |
7 | #if !defined(BOOST_SPIRIT_X3_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM) |
8 | #define BOOST_SPIRIT_X3_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM | |
7c673cae FG |
9 | |
10 | #include <boost/spirit/home/x3/support/traits/attribute_of.hpp> | |
11 | #include <boost/spirit/home/x3/support/traits/is_variant.hpp> | |
12 | #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp> | |
13 | #include <boost/spirit/home/x3/support/traits/move_to.hpp> | |
14 | #include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp> | |
15 | #include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp> | |
16 | #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp> | |
17 | #include <boost/variant/variant.hpp> | |
18 | ||
19 | #include <boost/mpl/copy_if.hpp> | |
20 | #include <boost/mpl/not.hpp> | |
21 | #include <boost/mpl/if.hpp> | |
22 | #include <boost/mpl/insert_range.hpp> | |
23 | #include <boost/mpl/eval_if.hpp> | |
24 | #include <boost/mpl/vector.hpp> | |
25 | ||
26 | #include <boost/fusion/include/front.hpp> | |
27 | ||
28 | #include <boost/type_traits/is_same.hpp> | |
29 | ||
30 | namespace boost { namespace spirit { namespace x3 | |
31 | { | |
32 | template <typename Left, typename Right> | |
33 | struct alternative; | |
34 | }}} | |
35 | ||
36 | namespace boost { namespace spirit { namespace x3 { namespace detail | |
37 | { | |
38 | struct pass_variant_unused | |
39 | { | |
40 | typedef unused_type type; | |
41 | ||
42 | template <typename T> | |
43 | static unused_type | |
44 | call(T&) | |
45 | { | |
46 | return unused_type(); | |
47 | } | |
48 | }; | |
49 | ||
50 | template <typename Attribute> | |
51 | struct pass_variant_used | |
52 | { | |
53 | typedef Attribute& type; | |
54 | ||
55 | static Attribute& | |
56 | call(Attribute& v) | |
57 | { | |
58 | return v; | |
59 | } | |
60 | }; | |
61 | ||
62 | template <> | |
63 | struct pass_variant_used<unused_type> : pass_variant_unused {}; | |
64 | ||
65 | template <typename Parser, typename Attribute, typename Context | |
66 | , typename Enable = void> | |
67 | struct pass_parser_attribute | |
68 | { | |
69 | typedef typename | |
70 | traits::attribute_of<Parser, Context>::type | |
71 | attribute_type; | |
72 | typedef typename | |
73 | traits::variant_find_substitute<Attribute, attribute_type>::type | |
74 | substitute_type; | |
75 | ||
76 | typedef typename | |
77 | mpl::if_< | |
78 | is_same<Attribute, substitute_type> | |
79 | , Attribute& | |
80 | , substitute_type | |
81 | >::type | |
82 | type; | |
83 | ||
84 | template <typename Attribute_> | |
85 | static Attribute_& | |
86 | call(Attribute_& attr, mpl::true_) | |
87 | { | |
88 | return attr; | |
89 | } | |
90 | ||
91 | template <typename Attribute_> | |
92 | static type | |
93 | call(Attribute_&, mpl::false_) | |
94 | { | |
95 | return type(); | |
96 | } | |
97 | ||
98 | template <typename Attribute_> | |
99 | static type | |
100 | call(Attribute_& attr) | |
101 | { | |
102 | return call(attr, is_same<Attribute_, typename remove_reference<type>::type>()); | |
103 | } | |
104 | }; | |
105 | ||
106 | // Pass non-variant attributes as-is | |
107 | template <typename Parser, typename Attribute, typename Context | |
108 | , typename Enable = void> | |
109 | struct pass_non_variant_attribute | |
110 | { | |
111 | typedef Attribute& type; | |
112 | ||
113 | static Attribute& | |
114 | call(Attribute& attr) | |
115 | { | |
116 | return attr; | |
117 | } | |
118 | }; | |
119 | ||
120 | // Unwrap single element sequences | |
121 | template <typename Parser, typename Attribute, typename Context> | |
122 | struct pass_non_variant_attribute<Parser, Attribute, Context, | |
123 | typename enable_if<traits::is_size_one_sequence<Attribute>>::type> | |
124 | { | |
125 | typedef typename remove_reference< | |
126 | typename fusion::result_of::front<Attribute>::type>::type | |
127 | attr_type; | |
128 | ||
129 | typedef pass_parser_attribute<Parser, attr_type, Context> pass; | |
130 | typedef typename pass::type type; | |
131 | ||
132 | template <typename Attribute_> | |
133 | static type | |
134 | call(Attribute_& attr) | |
135 | { | |
136 | return pass::call(fusion::front(attr)); | |
137 | } | |
138 | }; | |
139 | ||
140 | template <typename Parser, typename Attribute, typename Context> | |
141 | struct pass_parser_attribute<Parser, Attribute, Context, | |
142 | typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type> | |
143 | : pass_non_variant_attribute<Parser, Attribute, Context> | |
144 | {}; | |
145 | ||
146 | template <typename Parser, typename Context> | |
147 | struct pass_parser_attribute<Parser, unused_type, Context> | |
148 | : pass_variant_unused {}; | |
149 | ||
150 | template <typename Parser, typename Attribute, typename Context> | |
151 | struct pass_variant_attribute : | |
152 | mpl::if_c<traits::has_attribute<Parser, Context>::value | |
153 | , pass_parser_attribute<Parser, Attribute, Context> | |
154 | , pass_variant_unused>::type | |
155 | { | |
156 | typedef typename mpl::false_ is_alternative; | |
157 | }; | |
158 | ||
159 | template <typename L, typename R, typename Attribute, typename Context> | |
160 | struct pass_variant_attribute<alternative<L, R>, Attribute, Context> : | |
161 | mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value | |
162 | , pass_variant_used<Attribute> | |
163 | , pass_variant_unused>::type | |
164 | { | |
165 | typedef typename mpl::true_ is_alternative; | |
166 | }; | |
167 | ||
168 | template <typename L, typename R, typename C> | |
169 | struct get_alternative_types | |
170 | { | |
171 | typedef | |
172 | mpl::vector< | |
173 | typename traits::attribute_of<L, C>::type | |
174 | , typename traits::attribute_of<R, C>::type | |
175 | > | |
176 | type; | |
177 | }; | |
178 | ||
179 | template <typename LL, typename LR, typename R, typename C> | |
180 | struct get_alternative_types<alternative<LL, LR>, R, C> | |
181 | : mpl::push_back< typename get_alternative_types<LL, LR, C>::type | |
182 | , typename traits::attribute_of<R, C>::type> {}; | |
183 | ||
184 | template <typename L, typename RL, typename RR, typename C> | |
185 | struct get_alternative_types<L, alternative<RL, RR>, C> | |
186 | : mpl::push_front< typename get_alternative_types<RL, RR, C>::type | |
187 | , typename traits::attribute_of<L, C>::type> {}; | |
188 | ||
189 | template <typename LL, typename LR, typename RL, typename RR, typename C> | |
190 | struct get_alternative_types<alternative<LL, LR>, alternative<RL, RR>, C> | |
191 | { | |
192 | typedef typename get_alternative_types<LL, LR, C>::type left; | |
193 | typedef typename get_alternative_types<RL, RR, C>::type right; | |
194 | typedef typename | |
195 | mpl::insert_range<left, typename mpl::end<left>::type, right>::type | |
196 | type; | |
197 | }; | |
198 | ||
199 | template <typename L, typename R, typename C> | |
200 | struct attribute_of_alternative | |
201 | { | |
202 | // Get all alternative attribute types | |
203 | typedef typename get_alternative_types<L, R, C>::type all_types; | |
204 | ||
205 | // Filter all unused_types | |
206 | typedef typename | |
207 | mpl::copy_if< | |
208 | all_types | |
209 | , mpl::not_<is_same<mpl::_1, unused_type>> | |
210 | , mpl::back_inserter<mpl::vector<>> | |
211 | >::type | |
212 | filtered_types; | |
213 | ||
214 | // Build a variant if filtered_types is not empty, | |
215 | // else just return unused_type | |
216 | typedef typename | |
217 | mpl::eval_if< | |
218 | mpl::empty<filtered_types> | |
219 | , mpl::identity<unused_type> | |
220 | , make_variant_over<filtered_types> | |
221 | >::type | |
222 | type; | |
223 | }; | |
224 | ||
225 | template <typename IsAlternative> | |
226 | struct move_if_not_alternative | |
227 | { | |
228 | template<typename T1, typename T2> | |
b32b8144 | 229 | static void call(T1& /* attr_ */, T2& /* attr */) {} |
7c673cae FG |
230 | }; |
231 | ||
232 | template <> | |
233 | struct move_if_not_alternative<mpl::false_ /*is alternative*/> | |
234 | { | |
235 | template<typename T1, typename T2> | |
236 | static void call(T1& attr_, T2& attr) | |
237 | { | |
238 | traits::move_to(attr_, attr); | |
239 | } | |
240 | }; | |
241 | ||
242 | template <typename Parser, typename Iterator, typename Context | |
243 | , typename RContext, typename Attribute> | |
244 | bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last | |
245 | , Context const& context, RContext& rcontext, Attribute& attr) | |
246 | { | |
247 | typedef detail::pass_variant_attribute<Parser, Attribute, Context> pass; | |
248 | ||
249 | typename pass::type attr_ = pass::call(attr); | |
250 | if (p.parse(first, last, context, rcontext, attr_)) | |
251 | { | |
252 | move_if_not_alternative<typename pass::is_alternative>::call(attr_, attr); | |
253 | return true; | |
254 | } | |
255 | return false; | |
256 | } | |
257 | ||
258 | ||
259 | template <typename Left, typename Right, typename Context, typename RContext> | |
260 | struct parse_into_container_impl<alternative<Left, Right>, Context, RContext> | |
261 | { | |
262 | typedef alternative<Left, Right> parser_type; | |
263 | ||
264 | template <typename Iterator, typename Attribute> | |
265 | static bool call( | |
266 | parser_type const& parser | |
267 | , Iterator& first, Iterator const& last | |
268 | , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) | |
269 | { | |
270 | return parse_alternative(parser, first, last, context, rcontext, attr); | |
271 | } | |
272 | ||
273 | template <typename Iterator, typename Attribute> | |
274 | static bool call( | |
275 | parser_type const& parser | |
276 | , Iterator& first, Iterator const& last | |
277 | , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_) | |
278 | { | |
279 | return parse_into_container_base_impl<parser_type>::call( | |
280 | parser, first, last, context, rcontext, attr); | |
281 | } | |
282 | ||
283 | template <typename Iterator, typename Attribute> | |
284 | static bool call( | |
285 | parser_type const& parser | |
286 | , Iterator& first, Iterator const& last | |
287 | , Context const& context, RContext& rcontext, Attribute& attr) | |
288 | { | |
289 | typedef typename | |
290 | traits::attribute_of<parser_type, Context>::type | |
291 | attribute_type; | |
292 | ||
293 | return call(parser, first, last, context, rcontext, attr | |
294 | , traits::variant_has_substitute<attribute_type, Attribute>()); | |
295 | } | |
296 | }; | |
297 | ||
298 | }}}} | |
299 | ||
300 | #endif |