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