1 // Copyright (c) 2001-2011 Joel de Guzman
2 // Copyright (c) 2001-2011 Hartmut Kaiser
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)
7 #if !defined(BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM)
8 #define BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM
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/output_iterator.hpp>
18 #include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
19 #include <boost/spirit/home/karma/detail/get_stricttag.hpp>
20 #include <boost/spirit/home/karma/detail/pass_container.hpp>
21 #include <boost/spirit/home/karma/detail/fail_function.hpp>
22 #include <boost/spirit/home/support/info.hpp>
23 #include <boost/spirit/home/support/unused.hpp>
24 #include <boost/spirit/home/support/container.hpp>
25 #include <boost/spirit/home/support/handles_container.hpp>
26 #include <boost/spirit/home/karma/detail/attributes.hpp>
28 #include <boost/type_traits/add_const.hpp>
30 namespace boost { namespace spirit
32 ///////////////////////////////////////////////////////////////////////////
34 ///////////////////////////////////////////////////////////////////////////
36 struct use_operator<karma::domain, proto::tag::dereference> // enables *g
40 ///////////////////////////////////////////////////////////////////////////////
41 namespace boost { namespace spirit { namespace karma
43 template <typename Subject, typename Strict, typename Derived>
44 struct base_kleene : unary_generator<Derived>
47 // Ignore return value in relaxed mode (failing subject generators
48 // are just skipped). This allows to selectively generate items in
49 // the provided attribute.
50 template <typename F, typename Attribute>
51 bool generate_subject(F f, Attribute const&, mpl::false_) const
54 if (!r && !f.is_at_end())
59 template <typename F, typename Attribute>
60 bool generate_subject(F f, Attribute const&, mpl::true_) const
65 // There is no way to distinguish a failed generator from a
66 // generator to be skipped. We assume the user takes responsibility
67 // for ending the loop if no attribute is specified.
69 bool generate_subject(F f, unused_type, mpl::false_) const
74 // template <typename F>
75 // bool generate_subject(F f, unused_type, mpl::true_) const
77 // return !f(subject);
81 typedef Subject subject_type;
82 typedef typename subject_type::properties properties;
84 // Build a std::vector from the subject's attribute. Note
85 // that build_std_vector may return unused_type if the
86 // subject's attribute is an unused_type.
87 template <typename Context, typename Iterator>
89 : traits::build_std_vector<
90 typename traits::attribute_of<Subject, Context, Iterator>::type
94 base_kleene(Subject const& subject)
98 typename OutputIterator, typename Context, typename Delimiter
100 bool generate(OutputIterator& sink, Context& ctx
101 , Delimiter const& d, Attribute const& attr) const
103 typedef detail::fail_function<
104 OutputIterator, Context, Delimiter> fail_function;
106 typedef typename traits::container_iterator<
107 typename add_const<Attribute>::type
108 >::type iterator_type;
111 typename traits::make_indirect_iterator<iterator_type>::type
112 indirect_iterator_type;
113 typedef detail::pass_container<
114 fail_function, Attribute, indirect_iterator_type, mpl::false_>
117 iterator_type it = traits::begin(attr);
118 iterator_type end = traits::end(attr);
120 pass_container pass(fail_function(sink, ctx, d),
121 indirect_iterator_type(it), indirect_iterator_type(end));
123 // kleene fails only if the underlying output fails
124 while (!pass.is_at_end())
126 if (!generate_subject(pass, attr, Strict()))
129 return detail::sink_is_good(sink);
132 template <typename Context>
133 info what(Context& context) const
135 return info("kleene", subject.what(context));
141 template <typename Subject>
143 : base_kleene<Subject, mpl::false_, kleene<Subject> >
145 typedef base_kleene<Subject, mpl::false_, kleene> base_kleene_;
147 kleene(Subject const& subject)
148 : base_kleene_(subject) {}
151 template <typename Subject>
153 : base_kleene<Subject, mpl::true_, strict_kleene<Subject> >
155 typedef base_kleene<Subject, mpl::true_, strict_kleene> base_kleene_;
157 strict_kleene(Subject const& subject)
158 : base_kleene_(subject) {}
161 ///////////////////////////////////////////////////////////////////////////
162 // Generator generators: make_xxx function (objects)
163 ///////////////////////////////////////////////////////////////////////////
166 template <typename Subject, bool strict_mode = false>
168 : make_unary_composite<Subject, kleene>
171 template <typename Subject>
172 struct make_kleene<Subject, true>
173 : make_unary_composite<Subject, strict_kleene>
177 template <typename Subject, typename Modifiers>
178 struct make_composite<proto::tag::dereference, Subject, Modifiers>
179 : detail::make_kleene<Subject, detail::get_stricttag<Modifiers>::value>
183 namespace boost { namespace spirit { namespace traits
185 ///////////////////////////////////////////////////////////////////////////
186 template <typename Subject>
187 struct has_semantic_action<karma::kleene<Subject> >
188 : unary_has_semantic_action<Subject> {};
190 template <typename Subject>
191 struct has_semantic_action<karma::strict_kleene<Subject> >
192 : unary_has_semantic_action<Subject> {};
194 ///////////////////////////////////////////////////////////////////////////
195 template <typename Subject, typename Attribute, typename Context
197 struct handles_container<karma::kleene<Subject>, Attribute
201 template <typename Subject, typename Attribute, typename Context
203 struct handles_container<karma::strict_kleene<Subject>, Attribute