Chris@16
|
1 // Copyright (c) 2001-2011 Joel de Guzman
|
Chris@16
|
2 // Copyright (c) 2001-2011 Hartmut Kaiser
|
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(BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM)
|
Chris@16
|
8 #define BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM
|
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/output_iterator.hpp>
|
Chris@16
|
18 #include <boost/spirit/home/karma/detail/indirect_iterator.hpp>
|
Chris@16
|
19 #include <boost/spirit/home/karma/detail/get_stricttag.hpp>
|
Chris@16
|
20 #include <boost/spirit/home/karma/detail/pass_container.hpp>
|
Chris@16
|
21 #include <boost/spirit/home/karma/detail/fail_function.hpp>
|
Chris@16
|
22 #include <boost/spirit/home/support/info.hpp>
|
Chris@16
|
23 #include <boost/spirit/home/support/unused.hpp>
|
Chris@16
|
24 #include <boost/spirit/home/support/container.hpp>
|
Chris@16
|
25 #include <boost/spirit/home/support/handles_container.hpp>
|
Chris@16
|
26 #include <boost/spirit/home/karma/detail/attributes.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/type_traits/add_const.hpp>
|
Chris@16
|
29
|
Chris@16
|
30 namespace boost { namespace spirit
|
Chris@16
|
31 {
|
Chris@16
|
32 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
33 // Enablers
|
Chris@16
|
34 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
35 template <>
|
Chris@16
|
36 struct use_operator<karma::domain, proto::tag::dereference> // enables *g
|
Chris@16
|
37 : mpl::true_ {};
|
Chris@16
|
38 }}
|
Chris@16
|
39
|
Chris@16
|
40 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
41 namespace boost { namespace spirit { namespace karma
|
Chris@16
|
42 {
|
Chris@16
|
43 template <typename Subject, typename Strict, typename Derived>
|
Chris@16
|
44 struct base_kleene : unary_generator<Derived>
|
Chris@16
|
45 {
|
Chris@16
|
46 private:
|
Chris@16
|
47 // Ignore return value in relaxed mode (failing subject generators
|
Chris@16
|
48 // are just skipped). This allows to selectively generate items in
|
Chris@16
|
49 // the provided attribute.
|
Chris@16
|
50 template <typename F, typename Attribute>
|
Chris@16
|
51 bool generate_subject(F f, Attribute const&, mpl::false_) const
|
Chris@16
|
52 {
|
Chris@16
|
53 bool r = !f(subject);
|
Chris@16
|
54 if (!r && !f.is_at_end())
|
Chris@16
|
55 f.next();
|
Chris@16
|
56 return true;
|
Chris@16
|
57 }
|
Chris@16
|
58
|
Chris@16
|
59 template <typename F, typename Attribute>
|
Chris@16
|
60 bool generate_subject(F f, Attribute const&, mpl::true_) const
|
Chris@16
|
61 {
|
Chris@16
|
62 return !f(subject);
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 // There is no way to distinguish a failed generator from a
|
Chris@16
|
66 // generator to be skipped. We assume the user takes responsibility
|
Chris@16
|
67 // for ending the loop if no attribute is specified.
|
Chris@16
|
68 template <typename F>
|
Chris@16
|
69 bool generate_subject(F f, unused_type, mpl::false_) const
|
Chris@16
|
70 {
|
Chris@16
|
71 return !f(subject);
|
Chris@16
|
72 }
|
Chris@16
|
73
|
Chris@16
|
74 // template <typename F>
|
Chris@16
|
75 // bool generate_subject(F f, unused_type, mpl::true_) const
|
Chris@16
|
76 // {
|
Chris@16
|
77 // return !f(subject);
|
Chris@16
|
78 // }
|
Chris@16
|
79
|
Chris@16
|
80 public:
|
Chris@16
|
81 typedef Subject subject_type;
|
Chris@16
|
82 typedef typename subject_type::properties properties;
|
Chris@16
|
83
|
Chris@16
|
84 // Build a std::vector from the subject's attribute. Note
|
Chris@16
|
85 // that build_std_vector may return unused_type if the
|
Chris@16
|
86 // subject's attribute is an unused_type.
|
Chris@16
|
87 template <typename Context, typename Iterator>
|
Chris@16
|
88 struct attribute
|
Chris@16
|
89 : traits::build_std_vector<
|
Chris@16
|
90 typename traits::attribute_of<Subject, Context, Iterator>::type
|
Chris@16
|
91 >
|
Chris@16
|
92 {};
|
Chris@16
|
93
|
Chris@16
|
94 base_kleene(Subject const& subject)
|
Chris@16
|
95 : subject(subject) {}
|
Chris@16
|
96
|
Chris@16
|
97 template <
|
Chris@16
|
98 typename OutputIterator, typename Context, typename Delimiter
|
Chris@16
|
99 , typename Attribute>
|
Chris@16
|
100 bool generate(OutputIterator& sink, Context& ctx
|
Chris@16
|
101 , Delimiter const& d, Attribute const& attr) const
|
Chris@16
|
102 {
|
Chris@16
|
103 typedef detail::fail_function<
|
Chris@16
|
104 OutputIterator, Context, Delimiter> fail_function;
|
Chris@16
|
105
|
Chris@16
|
106 typedef typename traits::container_iterator<
|
Chris@16
|
107 typename add_const<Attribute>::type
|
Chris@16
|
108 >::type iterator_type;
|
Chris@16
|
109
|
Chris@16
|
110 typedef
|
Chris@16
|
111 typename traits::make_indirect_iterator<iterator_type>::type
|
Chris@16
|
112 indirect_iterator_type;
|
Chris@16
|
113 typedef detail::pass_container<
|
Chris@16
|
114 fail_function, Attribute, indirect_iterator_type, mpl::false_>
|
Chris@16
|
115 pass_container;
|
Chris@16
|
116
|
Chris@16
|
117 iterator_type it = traits::begin(attr);
|
Chris@16
|
118 iterator_type end = traits::end(attr);
|
Chris@16
|
119
|
Chris@16
|
120 pass_container pass(fail_function(sink, ctx, d),
|
Chris@16
|
121 indirect_iterator_type(it), indirect_iterator_type(end));
|
Chris@16
|
122
|
Chris@16
|
123 // kleene fails only if the underlying output fails
|
Chris@16
|
124 while (!pass.is_at_end())
|
Chris@16
|
125 {
|
Chris@16
|
126 if (!generate_subject(pass, attr, Strict()))
|
Chris@16
|
127 break;
|
Chris@16
|
128 }
|
Chris@16
|
129 return detail::sink_is_good(sink);
|
Chris@16
|
130 }
|
Chris@16
|
131
|
Chris@16
|
132 template <typename Context>
|
Chris@16
|
133 info what(Context& context) const
|
Chris@16
|
134 {
|
Chris@16
|
135 return info("kleene", subject.what(context));
|
Chris@16
|
136 }
|
Chris@16
|
137
|
Chris@16
|
138 Subject subject;
|
Chris@16
|
139 };
|
Chris@16
|
140
|
Chris@16
|
141 template <typename Subject>
|
Chris@16
|
142 struct kleene
|
Chris@16
|
143 : base_kleene<Subject, mpl::false_, kleene<Subject> >
|
Chris@16
|
144 {
|
Chris@16
|
145 typedef base_kleene<Subject, mpl::false_, kleene> base_kleene_;
|
Chris@16
|
146
|
Chris@16
|
147 kleene(Subject const& subject)
|
Chris@16
|
148 : base_kleene_(subject) {}
|
Chris@16
|
149 };
|
Chris@16
|
150
|
Chris@16
|
151 template <typename Subject>
|
Chris@16
|
152 struct strict_kleene
|
Chris@16
|
153 : base_kleene<Subject, mpl::true_, strict_kleene<Subject> >
|
Chris@16
|
154 {
|
Chris@16
|
155 typedef base_kleene<Subject, mpl::true_, strict_kleene> base_kleene_;
|
Chris@16
|
156
|
Chris@16
|
157 strict_kleene(Subject const& subject)
|
Chris@16
|
158 : base_kleene_(subject) {}
|
Chris@16
|
159 };
|
Chris@16
|
160
|
Chris@16
|
161 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
162 // Generator generators: make_xxx function (objects)
|
Chris@16
|
163 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
164 namespace detail
|
Chris@16
|
165 {
|
Chris@16
|
166 template <typename Subject, bool strict_mode = false>
|
Chris@16
|
167 struct make_kleene
|
Chris@16
|
168 : make_unary_composite<Subject, kleene>
|
Chris@16
|
169 {};
|
Chris@16
|
170
|
Chris@16
|
171 template <typename Subject>
|
Chris@16
|
172 struct make_kleene<Subject, true>
|
Chris@16
|
173 : make_unary_composite<Subject, strict_kleene>
|
Chris@16
|
174 {};
|
Chris@16
|
175 }
|
Chris@16
|
176
|
Chris@16
|
177 template <typename Subject, typename Modifiers>
|
Chris@16
|
178 struct make_composite<proto::tag::dereference, Subject, Modifiers>
|
Chris@16
|
179 : detail::make_kleene<Subject, detail::get_stricttag<Modifiers>::value>
|
Chris@16
|
180 {};
|
Chris@16
|
181 }}}
|
Chris@16
|
182
|
Chris@16
|
183 namespace boost { namespace spirit { namespace traits
|
Chris@16
|
184 {
|
Chris@16
|
185 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
186 template <typename Subject>
|
Chris@16
|
187 struct has_semantic_action<karma::kleene<Subject> >
|
Chris@16
|
188 : unary_has_semantic_action<Subject> {};
|
Chris@16
|
189
|
Chris@16
|
190 template <typename Subject>
|
Chris@16
|
191 struct has_semantic_action<karma::strict_kleene<Subject> >
|
Chris@16
|
192 : unary_has_semantic_action<Subject> {};
|
Chris@16
|
193
|
Chris@16
|
194 ///////////////////////////////////////////////////////////////////////////
|
Chris@16
|
195 template <typename Subject, typename Attribute, typename Context
|
Chris@16
|
196 , typename Iterator>
|
Chris@16
|
197 struct handles_container<karma::kleene<Subject>, Attribute
|
Chris@16
|
198 , Context, Iterator>
|
Chris@16
|
199 : mpl::true_ {};
|
Chris@16
|
200
|
Chris@16
|
201 template <typename Subject, typename Attribute, typename Context
|
Chris@16
|
202 , typename Iterator>
|
Chris@16
|
203 struct handles_container<karma::strict_kleene<Subject>, Attribute
|
Chris@16
|
204 , Context, Iterator>
|
Chris@16
|
205 : mpl::true_ {};
|
Chris@16
|
206 }}}
|
Chris@16
|
207
|
Chris@16
|
208 #endif
|