Chris@16: // Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: // Copyright (c) 2001-2011 Joel de Guzman Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #if !defined(SPIRIT_KARMA_REPEAT_MAY_18_2009_0926AM) Chris@16: #define SPIRIT_KARMA_REPEAT_MAY_18_2009_0926AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace spirit Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Enablers Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template <> Chris@16: struct use_directive // enables repeat[p] Chris@16: : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct use_directive > Chris@16: > : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct use_directive > Chris@16: > : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct use_directive > Chris@16: > : mpl::true_ {}; Chris@16: Chris@16: template <> // enables *lazy* repeat(exact)[p] Chris@16: struct use_lazy_directive< Chris@16: karma::domain Chris@16: , tag::repeat Chris@16: , 1 // arity Chris@16: > : mpl::true_ {}; Chris@16: Chris@16: template <> // enables *lazy* repeat(min, max)[p] Chris@16: struct use_lazy_directive< // and repeat(min, inf)[p] Chris@16: karma::domain Chris@16: , tag::repeat Chris@16: , 2 // arity Chris@16: > : mpl::true_ {}; Chris@16: }} Chris@16: Chris@16: namespace boost { namespace spirit { namespace karma Chris@16: { Chris@16: #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS Chris@16: using spirit::repeat; Chris@16: using spirit::inf; Chris@16: #endif Chris@16: using spirit::repeat_type; Chris@16: using spirit::inf_type; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // handles repeat(exact)[p] Chris@16: template Chris@16: struct exact_iterator Chris@16: { Chris@16: exact_iterator(T const exact) Chris@16: : exact(exact) {} Chris@16: Chris@16: typedef T type; Chris@16: T start() const { return 0; } Chris@16: bool got_max(T i) const { return i >= exact; } Chris@16: bool got_min(T i) const { return i >= exact; } Chris@16: Chris@16: T const exact; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: exact_iterator& operator= (exact_iterator const&); Chris@16: }; Chris@16: Chris@16: // handles repeat(min, max)[p] Chris@16: template Chris@16: struct finite_iterator Chris@16: { Chris@16: finite_iterator(T const min, T const max) Chris@16: : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) Chris@16: , max BOOST_PREVENT_MACRO_SUBSTITUTION (max) {} Chris@16: Chris@16: typedef T type; Chris@16: T start() const { return 0; } Chris@16: bool got_max(T i) const { return i >= max; } Chris@16: bool got_min(T i) const { return i >= min; } Chris@16: Chris@16: T const min; Chris@16: T const max; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: finite_iterator& operator= (finite_iterator const&); Chris@16: }; Chris@16: Chris@16: // handles repeat(min, inf)[p] Chris@16: template Chris@16: struct infinite_iterator Chris@16: { Chris@16: infinite_iterator(T const min) Chris@16: : min BOOST_PREVENT_MACRO_SUBSTITUTION (min) {} Chris@16: Chris@16: typedef T type; Chris@16: T start() const { return 0; } Chris@16: bool got_max(T /*i*/) const { return false; } Chris@16: bool got_min(T i) const { return i >= min; } Chris@16: Chris@16: T const min; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: infinite_iterator& operator= (infinite_iterator const&); Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct base_repeat_generator : unary_generator Chris@16: { Chris@16: private: Chris@16: // iterate over the given container until its exhausted or the embedded Chris@16: // generator succeeds Chris@16: template Chris@16: bool generate_subject(F f, Attribute const&, mpl::false_) const Chris@16: { Chris@16: // Failing subject generators are just skipped. This allows to Chris@16: // selectively generate items in the provided attribute. Chris@16: while (!f.is_at_end()) Chris@16: { Chris@16: bool r = !f(subject); Chris@16: if (r) Chris@16: return true; Chris@16: if (!f.is_at_end()) Chris@16: f.next(); Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: template Chris@16: bool generate_subject(F f, Attribute const&, mpl::true_) const Chris@16: { Chris@16: return !f(subject); Chris@16: } Chris@16: Chris@16: // There is no way to distinguish a failed generator from a Chris@16: // generator to be skipped. We assume the user takes responsibility Chris@16: // for ending the loop if no attribute is specified. Chris@16: template Chris@16: bool generate_subject(F f, unused_type, mpl::false_) const Chris@16: { Chris@16: return !f(subject); Chris@16: } Chris@16: Chris@16: public: Chris@16: typedef Subject subject_type; Chris@16: Chris@16: typedef mpl::int_ properties; Chris@16: Chris@16: // Build a std::vector from the subject's attribute. Note Chris@16: // that build_std_vector may return unused_type if the Chris@16: // subject's attribute is an unused_type. Chris@16: template Chris@16: struct attribute Chris@16: : traits::build_std_vector< Chris@16: typename traits::attribute_of::type Chris@16: > Chris@16: {}; Chris@16: Chris@16: base_repeat_generator(Subject const& subject, LoopIter const& iter) Chris@16: : subject(subject), iter(iter) {} Chris@16: Chris@16: template Chris@16: bool generate(OutputIterator& sink, Context& ctx, Delimiter const& d Chris@16: , Attribute const& attr) const Chris@16: { Chris@16: typedef detail::fail_function< Chris@16: OutputIterator, Context, Delimiter Chris@16: > fail_function; Chris@16: Chris@16: typedef typename traits::container_iterator< Chris@16: typename add_const::type Chris@16: >::type iterator_type; Chris@16: Chris@16: typedef Chris@16: typename traits::make_indirect_iterator::type Chris@16: indirect_iterator_type; Chris@16: Chris@16: typedef detail::pass_container< Chris@16: fail_function, Attribute, indirect_iterator_type, mpl::false_> Chris@16: pass_container; Chris@16: Chris@16: iterator_type it = traits::begin(attr); Chris@16: iterator_type end = traits::end(attr); Chris@16: Chris@16: pass_container pass(fail_function(sink, ctx, d), Chris@16: indirect_iterator_type(it), indirect_iterator_type(end)); Chris@16: Chris@16: // generate the minimal required amount of output Chris@16: typename LoopIter::type i = iter.start(); Chris@16: for (/**/; !pass.is_at_end() && !iter.got_min(i); ++i) Chris@16: { Chris@16: if (!generate_subject(pass, attr, Strict())) Chris@16: { Chris@16: // if we fail before reaching the minimum iteration Chris@16: // required, do not output anything and return false Chris@16: return false; Chris@16: } Chris@16: } Chris@16: Chris@16: if (pass.is_at_end() && !iter.got_min(i)) Chris@16: return false; // insufficient attribute elements Chris@16: Chris@16: // generate some more up to the maximum specified Chris@16: for (/**/; !pass.is_at_end() && !iter.got_max(i); ++i) Chris@16: { Chris@16: if (!generate_subject(pass, attr, Strict())) Chris@16: break; Chris@16: } Chris@16: return detail::sink_is_good(sink); Chris@16: } Chris@16: Chris@16: template Chris@16: info what(Context& context) const Chris@16: { Chris@16: return info("repeat", subject.what(context)); Chris@16: } Chris@16: Chris@16: Subject subject; Chris@16: LoopIter iter; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct repeat_generator Chris@16: : base_repeat_generator< Chris@16: Subject, LoopIter, mpl::false_ Chris@16: , repeat_generator > Chris@16: { Chris@16: typedef base_repeat_generator< Chris@16: Subject, LoopIter, mpl::false_, repeat_generator Chris@16: > base_repeat_generator_; Chris@16: Chris@16: repeat_generator(Subject const& subject, LoopIter const& iter) Chris@16: : base_repeat_generator_(subject, iter) {} Chris@16: }; Chris@16: Chris@16: template Chris@16: struct strict_repeat_generator Chris@16: : base_repeat_generator< Chris@16: Subject, LoopIter, mpl::true_ Chris@16: , strict_repeat_generator > Chris@16: { Chris@16: typedef base_repeat_generator< Chris@16: Subject, LoopIter, mpl::true_, strict_repeat_generator Chris@16: > base_repeat_generator_; Chris@16: Chris@16: strict_repeat_generator(Subject const& subject, LoopIter const& iter) Chris@16: : base_repeat_generator_(subject, iter) {} Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Generator generators: make_xxx function (objects) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct make_directive Chris@16: { Chris@16: typedef typename mpl::if_< Chris@16: detail::get_stricttag Chris@16: , strict_kleene, kleene Chris@16: >::type result_type; Chris@16: Chris@16: result_type operator()(unused_type, Subject const& subject Chris@16: , unused_type) const Chris@16: { Chris@16: return result_type(subject); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct make_directive< Chris@16: terminal_ex >, Subject, Modifiers> Chris@16: { Chris@16: typedef exact_iterator iterator_type; Chris@16: Chris@16: typedef typename mpl::if_< Chris@16: detail::get_stricttag Chris@16: , strict_repeat_generator Chris@16: , repeat_generator Chris@16: >::type result_type; Chris@16: Chris@16: template Chris@16: result_type operator()( Chris@16: Terminal const& term, Subject const& subject, unused_type) const Chris@16: { Chris@16: return result_type(subject, fusion::at_c<0>(term.args)); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct make_directive< Chris@16: terminal_ex >, Subject, Modifiers> Chris@16: { Chris@16: typedef finite_iterator iterator_type; Chris@16: Chris@16: typedef typename mpl::if_< Chris@16: detail::get_stricttag Chris@16: , strict_repeat_generator Chris@16: , repeat_generator Chris@16: >::type result_type; Chris@16: Chris@16: template Chris@16: result_type operator()( Chris@16: Terminal const& term, Subject const& subject, unused_type) const Chris@16: { Chris@16: return result_type(subject, Chris@16: iterator_type( Chris@16: fusion::at_c<0>(term.args) Chris@16: , fusion::at_c<1>(term.args) Chris@16: ) Chris@16: ); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct make_directive< Chris@16: terminal_ex >, Subject, Modifiers> Chris@16: { Chris@16: typedef infinite_iterator iterator_type; Chris@16: Chris@16: typedef typename mpl::if_< Chris@16: detail::get_stricttag Chris@16: , strict_repeat_generator Chris@16: , repeat_generator Chris@16: >::type result_type; Chris@16: Chris@16: template Chris@16: result_type operator()( Chris@16: Terminal const& term, Subject const& subject, unused_type) const Chris@16: { Chris@16: return result_type(subject, fusion::at_c<0>(term.args)); Chris@16: } Chris@16: }; Chris@16: }}} Chris@16: Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct has_semantic_action > Chris@16: : unary_has_semantic_action {}; Chris@16: Chris@16: template Chris@16: struct has_semantic_action > Chris@16: : unary_has_semantic_action {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct handles_container< Chris@16: karma::repeat_generator, Attribute Chris@16: , Context, Iterator> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct handles_container< Chris@16: karma::strict_repeat_generator, Attribute Chris@16: , Context, Iterator> Chris@16: : mpl::true_ {}; Chris@16: }}} Chris@16: Chris@16: #endif