]>
Commit | Line | Data |
---|---|---|
1 | // Copyright (c) 2001-2011 Joel de Guzman | |
2 | // Copyright (c) 2001-2011 Hartmut Kaiser | |
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(BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM) | |
8 | #define BOOST_SPIRIT_KARMA_KLEENE_MAR_03_2007_0337AM | |
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/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> | |
27 | ||
28 | #include <boost/type_traits/add_const.hpp> | |
29 | ||
30 | namespace boost { namespace spirit | |
31 | { | |
32 | /////////////////////////////////////////////////////////////////////////// | |
33 | // Enablers | |
34 | /////////////////////////////////////////////////////////////////////////// | |
35 | template <> | |
36 | struct use_operator<karma::domain, proto::tag::dereference> // enables *g | |
37 | : mpl::true_ {}; | |
38 | }} | |
39 | ||
40 | /////////////////////////////////////////////////////////////////////////////// | |
41 | namespace boost { namespace spirit { namespace karma | |
42 | { | |
43 | template <typename Subject, typename Strict, typename Derived> | |
44 | struct base_kleene : unary_generator<Derived> | |
45 | { | |
46 | private: | |
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 | |
52 | { | |
53 | bool r = !f(subject); | |
54 | if (!r && !f.is_at_end()) | |
55 | f.next(); | |
56 | return true; | |
57 | } | |
58 | ||
59 | template <typename F, typename Attribute> | |
60 | bool generate_subject(F f, Attribute const&, mpl::true_) const | |
61 | { | |
62 | return !f(subject); | |
63 | } | |
64 | ||
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. | |
68 | template <typename F> | |
69 | bool generate_subject(F f, unused_type, mpl::false_) const | |
70 | { | |
71 | return !f(subject); | |
72 | } | |
73 | ||
74 | // template <typename F> | |
75 | // bool generate_subject(F f, unused_type, mpl::true_) const | |
76 | // { | |
77 | // return !f(subject); | |
78 | // } | |
79 | ||
80 | public: | |
81 | typedef Subject subject_type; | |
82 | typedef typename subject_type::properties properties; | |
83 | ||
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> | |
88 | struct attribute | |
89 | : traits::build_std_vector< | |
90 | typename traits::attribute_of<Subject, Context, Iterator>::type | |
91 | > | |
92 | {}; | |
93 | ||
94 | base_kleene(Subject const& subject) | |
95 | : subject(subject) {} | |
96 | ||
97 | template < | |
98 | typename OutputIterator, typename Context, typename Delimiter | |
99 | , typename Attribute> | |
100 | bool generate(OutputIterator& sink, Context& ctx | |
101 | , Delimiter const& d, Attribute const& attr) const | |
102 | { | |
103 | typedef detail::fail_function< | |
104 | OutputIterator, Context, Delimiter> fail_function; | |
105 | ||
106 | typedef typename traits::container_iterator< | |
107 | typename add_const<Attribute>::type | |
108 | >::type iterator_type; | |
109 | ||
110 | typedef | |
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_> | |
115 | pass_container; | |
116 | ||
117 | iterator_type it = traits::begin(attr); | |
118 | iterator_type end = traits::end(attr); | |
119 | ||
120 | pass_container pass(fail_function(sink, ctx, d), | |
121 | indirect_iterator_type(it), indirect_iterator_type(end)); | |
122 | ||
123 | // kleene fails only if the underlying output fails | |
124 | while (!pass.is_at_end()) | |
125 | { | |
126 | if (!generate_subject(pass, attr, Strict())) | |
127 | break; | |
128 | } | |
129 | return detail::sink_is_good(sink); | |
130 | } | |
131 | ||
132 | template <typename Context> | |
133 | info what(Context& context) const | |
134 | { | |
135 | return info("kleene", subject.what(context)); | |
136 | } | |
137 | ||
138 | Subject subject; | |
139 | }; | |
140 | ||
141 | template <typename Subject> | |
142 | struct kleene | |
143 | : base_kleene<Subject, mpl::false_, kleene<Subject> > | |
144 | { | |
145 | typedef base_kleene<Subject, mpl::false_, kleene> base_kleene_; | |
146 | ||
147 | kleene(Subject const& subject) | |
148 | : base_kleene_(subject) {} | |
149 | }; | |
150 | ||
151 | template <typename Subject> | |
152 | struct strict_kleene | |
153 | : base_kleene<Subject, mpl::true_, strict_kleene<Subject> > | |
154 | { | |
155 | typedef base_kleene<Subject, mpl::true_, strict_kleene> base_kleene_; | |
156 | ||
157 | strict_kleene(Subject const& subject) | |
158 | : base_kleene_(subject) {} | |
159 | }; | |
160 | ||
161 | /////////////////////////////////////////////////////////////////////////// | |
162 | // Generator generators: make_xxx function (objects) | |
163 | /////////////////////////////////////////////////////////////////////////// | |
164 | namespace detail | |
165 | { | |
166 | template <typename Subject, bool strict_mode = false> | |
167 | struct make_kleene | |
168 | : make_unary_composite<Subject, kleene> | |
169 | {}; | |
170 | ||
171 | template <typename Subject> | |
172 | struct make_kleene<Subject, true> | |
173 | : make_unary_composite<Subject, strict_kleene> | |
174 | {}; | |
175 | } | |
176 | ||
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> | |
180 | {}; | |
181 | }}} | |
182 | ||
183 | namespace boost { namespace spirit { namespace traits | |
184 | { | |
185 | /////////////////////////////////////////////////////////////////////////// | |
186 | template <typename Subject> | |
187 | struct has_semantic_action<karma::kleene<Subject> > | |
188 | : unary_has_semantic_action<Subject> {}; | |
189 | ||
190 | template <typename Subject> | |
191 | struct has_semantic_action<karma::strict_kleene<Subject> > | |
192 | : unary_has_semantic_action<Subject> {}; | |
193 | ||
194 | /////////////////////////////////////////////////////////////////////////// | |
195 | template <typename Subject, typename Attribute, typename Context | |
196 | , typename Iterator> | |
197 | struct handles_container<karma::kleene<Subject>, Attribute | |
198 | , Context, Iterator> | |
199 | : mpl::true_ {}; | |
200 | ||
201 | template <typename Subject, typename Attribute, typename Context | |
202 | , typename Iterator> | |
203 | struct handles_container<karma::strict_kleene<Subject>, Attribute | |
204 | , Context, Iterator> | |
205 | : mpl::true_ {}; | |
206 | }}} | |
207 | ||
208 | #endif |