]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright (c) 2001-2011 Hartmut Kaiser |
2 | // Copyright (c) 2001-2011 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 | ||
7 | #if !defined(SPIRIT_KARMA_SEQUENCE_FEB_28_2007_0247PM) | |
8 | #define SPIRIT_KARMA_SEQUENCE_FEB_28_2007_0247PM | |
9 | ||
10 | #if defined(_MSC_VER) | |
11 | #pragma once | |
12 | #endif | |
13 | ||
14 | #include <boost/spirit/home/karma/domain.hpp> | |
15 | #include <boost/spirit/home/karma/generator.hpp> | |
16 | #include <boost/spirit/home/karma/meta_compiler.hpp> | |
17 | #include <boost/spirit/home/karma/detail/fail_function.hpp> | |
18 | #include <boost/spirit/home/karma/detail/pass_container.hpp> | |
19 | #include <boost/spirit/home/karma/detail/get_stricttag.hpp> | |
20 | #include <boost/spirit/home/support/info.hpp> | |
21 | #include <boost/spirit/home/support/detail/what_function.hpp> | |
22 | #include <boost/spirit/home/karma/detail/attributes.hpp> | |
23 | #include <boost/spirit/home/karma/detail/indirect_iterator.hpp> | |
24 | #include <boost/spirit/home/support/algorithm/any_if.hpp> | |
25 | #include <boost/spirit/home/support/unused.hpp> | |
26 | #include <boost/spirit/home/support/sequence_base_id.hpp> | |
27 | #include <boost/spirit/home/support/has_semantic_action.hpp> | |
28 | #include <boost/spirit/home/support/handles_container.hpp> | |
29 | #include <boost/spirit/home/support/attributes.hpp> | |
30 | #include <boost/fusion/include/vector.hpp> | |
31 | #include <boost/fusion/include/as_vector.hpp> | |
32 | #include <boost/fusion/include/for_each.hpp> | |
33 | #include <boost/type_traits/is_same.hpp> | |
34 | #include <boost/mpl/bitor.hpp> | |
35 | #include <boost/mpl/int.hpp> | |
36 | #include <boost/mpl/and.hpp> | |
37 | #include <boost/mpl/not.hpp> | |
38 | #include <boost/fusion/include/transform.hpp> | |
39 | #include <boost/mpl/accumulate.hpp> | |
40 | #include <boost/config.hpp> | |
41 | ||
42 | /////////////////////////////////////////////////////////////////////////////// | |
43 | namespace boost { namespace spirit | |
44 | { | |
45 | /////////////////////////////////////////////////////////////////////////// | |
46 | // Enablers | |
47 | /////////////////////////////////////////////////////////////////////////// | |
48 | template <> | |
49 | struct use_operator<karma::domain, proto::tag::shift_left> // enables << | |
50 | : mpl::true_ {}; | |
51 | ||
52 | template <> | |
53 | struct flatten_tree<karma::domain, proto::tag::shift_left> // flattens << | |
54 | : mpl::true_ {}; | |
55 | }} | |
56 | ||
57 | /////////////////////////////////////////////////////////////////////////////// | |
58 | namespace boost { namespace spirit { namespace traits | |
59 | { | |
60 | // specialization for sequences | |
61 | template <typename Elements> | |
62 | struct sequence_properties | |
63 | { | |
64 | struct element_properties | |
65 | { | |
66 | template <typename T> | |
67 | struct result; | |
68 | ||
69 | template <typename F, typename Element> | |
70 | struct result<F(Element)> | |
71 | { | |
72 | typedef properties_of<Element> type; | |
73 | }; | |
74 | ||
75 | // never called, but needed for decltype-based result_of (C++0x) | |
76 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES | |
77 | template <typename Element> | |
78 | typename result<element_properties(Element)>::type | |
79 | operator()(Element&&) const; | |
80 | #endif | |
81 | }; | |
82 | ||
83 | typedef typename mpl::accumulate< | |
84 | typename fusion::result_of::transform< | |
85 | Elements, element_properties>::type | |
86 | , mpl::int_<karma::generator_properties::no_properties> | |
87 | , mpl::bitor_<mpl::_2, mpl::_1> | |
88 | >::type type; | |
89 | }; | |
90 | }}} | |
91 | ||
92 | /////////////////////////////////////////////////////////////////////////////// | |
93 | namespace boost { namespace spirit { namespace karma | |
94 | { | |
95 | template <typename Elements, typename Strict, typename Derived> | |
96 | struct base_sequence : nary_generator<Derived> | |
97 | { | |
98 | typedef typename traits::sequence_properties<Elements>::type properties; | |
99 | ||
100 | base_sequence(Elements const& elements) | |
101 | : elements(elements) {} | |
102 | ||
103 | typedef Elements elements_type; | |
104 | struct sequence_base_id; | |
105 | ||
106 | template <typename Context, typename Iterator = unused_type> | |
107 | struct attribute | |
108 | { | |
109 | // Put all the element attributes in a tuple | |
110 | typedef typename traits::build_attribute_sequence< | |
111 | Elements, Context, traits::sequence_attribute_transform | |
112 | , Iterator, karma::domain | |
113 | >::type all_attributes; | |
114 | ||
115 | // Now, build a fusion vector over the attributes. Note | |
116 | // that build_fusion_vector 1) removes all unused attributes | |
117 | // and 2) may return unused_type if all elements have | |
118 | // unused_type(s). | |
119 | typedef typename | |
120 | traits::build_fusion_vector<all_attributes>::type | |
121 | type_; | |
122 | ||
123 | // Finally, strip single element vectors into its | |
124 | // naked form: vector1<T> --> T | |
125 | typedef typename | |
126 | traits::strip_single_element_vector<type_>::type | |
127 | type; | |
128 | }; | |
129 | ||
130 | // standard case. Attribute is a fusion tuple | |
131 | template < | |
132 | typename OutputIterator, typename Context, typename Delimiter | |
133 | , typename Attribute, typename Pred1, typename Pred2> | |
134 | bool generate_impl(OutputIterator& sink, Context& ctx | |
135 | , Delimiter const& d, Attribute& attr_, Pred1, Pred2) const | |
136 | { | |
137 | typedef detail::fail_function< | |
138 | OutputIterator, Context, Delimiter> fail_function; | |
139 | typedef traits::attribute_not_unused<Context> predicate; | |
140 | ||
141 | // wrap the attribute in a tuple if it is not a tuple or if the | |
142 | // attribute of this sequence is a single element tuple | |
143 | typedef typename attribute<Context>::type_ attr_type_; | |
144 | typename traits::wrap_if_not_tuple<Attribute | |
145 | , typename mpl::and_< | |
146 | traits::one_element_sequence<attr_type_> | |
147 | , mpl::not_<traits::one_element_sequence<Attribute> > | |
148 | >::type | |
149 | >::type attr(attr_); | |
150 | ||
151 | // return false if *any* of the generators fail | |
152 | bool r = spirit::any_if(elements, attr | |
153 | , fail_function(sink, ctx, d), predicate()); | |
154 | ||
155 | typedef typename traits::attribute_size<Attribute>::type size_type; | |
156 | ||
157 | // fail generating if sequences have not the same (logical) length | |
158 | return !r && (!Strict::value || | |
159 | // This ignores container element count (which is not good), | |
160 | // but allows valid attributes to succeed. This will lead to | |
161 | // false positives (failing generators, even if they shouldn't) | |
162 | // if the embedded component is restricting the number of | |
163 | // container elements it consumes (i.e. repeat). This solution | |
164 | // is not optimal but much better than letting _all_ repetitive | |
165 | // components fail. | |
166 | Pred1::value || | |
167 | size_type(traits::sequence_size<attr_type_>::value) == traits::size(attr_)); | |
168 | } | |
169 | ||
170 | // Special case when Attribute is an stl container and the sequence's | |
171 | // attribute is not a one element sequence | |
172 | template < | |
173 | typename OutputIterator, typename Context, typename Delimiter | |
174 | , typename Attribute> | |
175 | bool generate_impl(OutputIterator& sink, Context& ctx | |
176 | , Delimiter const& d, Attribute const& attr_ | |
177 | , mpl::true_, mpl::false_) const | |
178 | { | |
179 | // return false if *any* of the generators fail | |
180 | typedef detail::fail_function< | |
181 | OutputIterator, Context, Delimiter> fail_function; | |
182 | ||
183 | typedef typename traits::container_iterator< | |
184 | typename add_const<Attribute>::type | |
185 | >::type iterator_type; | |
186 | ||
187 | typedef | |
188 | typename traits::make_indirect_iterator<iterator_type>::type | |
189 | indirect_iterator_type; | |
190 | typedef detail::pass_container< | |
191 | fail_function, Attribute, indirect_iterator_type, mpl::true_> | |
192 | pass_container; | |
193 | ||
194 | iterator_type begin = traits::begin(attr_); | |
195 | iterator_type end = traits::end(attr_); | |
196 | ||
197 | pass_container pass(fail_function(sink, ctx, d), | |
198 | indirect_iterator_type(begin), indirect_iterator_type(end)); | |
199 | bool r = fusion::any(elements, pass); | |
200 | ||
201 | // fail generating if sequences have not the same (logical) length | |
202 | return !r && (!Strict::value || begin == end); | |
203 | } | |
204 | ||
205 | // main generate function. Dispatches to generate_impl depending | |
206 | // on the Attribute type. | |
207 | template < | |
208 | typename OutputIterator, typename Context, typename Delimiter | |
209 | , typename Attribute> | |
210 | bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d | |
211 | , Attribute const& attr) const | |
212 | { | |
213 | typedef typename traits::is_container<Attribute>::type | |
214 | is_container; | |
215 | ||
216 | typedef typename attribute<Context>::type_ attr_type_; | |
217 | typedef typename traits::one_element_sequence<attr_type_>::type | |
218 | is_one_element_sequence; | |
219 | ||
220 | return generate_impl(sink, ctx, d, attr, is_container() | |
221 | , is_one_element_sequence()); | |
222 | } | |
223 | ||
224 | template <typename Context> | |
225 | info what(Context& context) const | |
226 | { | |
227 | info result("sequence"); | |
228 | fusion::for_each(elements, | |
229 | spirit::detail::what_function<Context>(result, context)); | |
230 | return result; | |
231 | } | |
232 | ||
233 | Elements elements; | |
234 | }; | |
235 | ||
236 | template <typename Elements> | |
237 | struct sequence | |
238 | : base_sequence<Elements, mpl::false_, sequence<Elements> > | |
239 | { | |
240 | typedef base_sequence<Elements, mpl::false_, sequence> base_sequence_; | |
241 | ||
242 | sequence(Elements const& subject) | |
243 | : base_sequence_(subject) {} | |
244 | }; | |
245 | ||
246 | template <typename Elements> | |
247 | struct strict_sequence | |
248 | : base_sequence<Elements, mpl::true_, strict_sequence<Elements> > | |
249 | { | |
250 | typedef base_sequence<Elements, mpl::true_, strict_sequence> | |
251 | base_sequence_; | |
252 | ||
253 | strict_sequence(Elements const& subject) | |
254 | : base_sequence_(subject) {} | |
255 | }; | |
256 | ||
257 | /////////////////////////////////////////////////////////////////////////// | |
258 | // Generator generators: make_xxx function (objects) | |
259 | /////////////////////////////////////////////////////////////////////////// | |
260 | namespace detail | |
261 | { | |
262 | template <typename Elements, bool strict_mode = false> | |
263 | struct make_sequence | |
264 | : make_nary_composite<Elements, sequence> | |
265 | {}; | |
266 | ||
267 | template <typename Elements> | |
268 | struct make_sequence<Elements, true> | |
269 | : make_nary_composite<Elements, strict_sequence> | |
270 | {}; | |
271 | } | |
272 | ||
273 | template <typename Elements, typename Modifiers> | |
274 | struct make_composite<proto::tag::shift_left, Elements, Modifiers> | |
275 | : detail::make_sequence<Elements, detail::get_stricttag<Modifiers>::value> | |
276 | {}; | |
277 | ||
278 | /////////////////////////////////////////////////////////////////////////// | |
279 | // Helper template allowing to get the required container type for a rule | |
280 | // attribute, which is part of a sequence. | |
281 | template <typename Iterator> | |
282 | struct make_sequence_iterator_range | |
283 | { | |
284 | typedef iterator_range<detail::indirect_iterator<Iterator> > type; | |
285 | }; | |
286 | }}} | |
287 | ||
288 | namespace boost { namespace spirit { namespace traits | |
289 | { | |
290 | /////////////////////////////////////////////////////////////////////////// | |
291 | template <typename Elements> | |
292 | struct has_semantic_action<karma::sequence<Elements> > | |
293 | : nary_has_semantic_action<Elements> {}; | |
294 | ||
295 | template <typename Elements> | |
296 | struct has_semantic_action<karma::strict_sequence<Elements> > | |
297 | : nary_has_semantic_action<Elements> {}; | |
298 | ||
299 | /////////////////////////////////////////////////////////////////////////// | |
300 | template <typename Elements, typename Attribute, typename Context | |
301 | , typename Iterator> | |
302 | struct handles_container<karma::sequence<Elements>, Attribute, Context | |
303 | , Iterator> | |
304 | : mpl::true_ {}; | |
305 | ||
306 | template <typename Elements, typename Attribute, typename Context | |
307 | , typename Iterator> | |
308 | struct handles_container<karma::strict_sequence<Elements>, Attribute | |
309 | , Context, Iterator> | |
310 | : mpl::true_ {}; | |
311 | }}} | |
312 | ||
313 | #endif |