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