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