From 3fc4ceb7180f0d14486a63ff214b475cf96bd99d Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Sat, 5 Feb 2011 03:48:49 +0000 Subject: [PATCH] Spirit: unified handling of sequences and container components for container attributes, modified hold_any to enable streaming with wchar_t, added extract_from_container CP, fixed integral generators for const data types [SVN r68645] --- doc/what_s_new.qbk | 4 +- include/boost/spirit/home/karma/auto/auto.hpp | 2 +- .../spirit/home/karma/detail/attributes.hpp | 2 +- .../spirit/home/karma/detail/extract_from.hpp | 122 +++++++++++++++- .../home/karma/detail/pass_container.hpp | 59 +++++++- .../boost/spirit/home/karma/numeric/bool.hpp | 6 +- .../boost/spirit/home/karma/numeric/int.hpp | 9 +- .../boost/spirit/home/karma/numeric/real.hpp | 9 +- .../boost/spirit/home/karma/numeric/uint.hpp | 8 +- .../spirit/home/karma/operator/kleene.hpp | 67 ++++++--- .../boost/spirit/home/karma/operator/list.hpp | 76 +++++----- .../spirit/home/karma/operator/optional.hpp | 4 +- .../boost/spirit/home/karma/operator/plus.hpp | 85 ++++++++---- .../spirit/home/karma/operator/sequence.hpp | 83 +---------- .../boost/spirit/home/karma/stream/stream.hpp | 2 +- .../boost/spirit/home/qi/detail/assign_to.hpp | 12 +- .../spirit/home/qi/detail/pass_container.hpp | 36 ++++- .../boost/spirit/home/qi/directive/repeat.hpp | 90 +++--------- include/boost/spirit/home/qi/numeric/int.hpp | 20 +-- .../boost/spirit/home/qi/operator/expect.hpp | 5 +- .../boost/spirit/home/qi/operator/kleene.hpp | 37 ++--- .../boost/spirit/home/qi/operator/list.hpp | 47 ++++--- .../spirit/home/qi/operator/optional.hpp | 33 ++++- .../boost/spirit/home/qi/operator/plus.hpp | 42 +++--- .../spirit/home/qi/operator/sequence.hpp | 5 +- .../spirit/home/qi/operator/sequence_base.hpp | 1 + .../boost/spirit/home/qi/stream/stream.hpp | 2 +- .../boost/spirit/home/support/attributes.hpp | 5 +- .../spirit/home/support/attributes_fwd.hpp | 3 + .../boost/spirit/home/support/container.hpp | 2 +- .../spirit/home/support/detail/hold_any.hpp | 130 +++++++++++------- .../spirit/home/support/utree/operators.hpp | 1 + .../home/support/utree/utree_traits.hpp | 44 ++++-- test/Jamfile | 1 + test/karma/kleene.cpp | 53 +++++++ test/karma/list.cpp | 7 + test/karma/lit.cpp | 4 + test/karma/plus.cpp | 49 +++++++ test/karma/regression_const_real_policies.cpp | 25 ++++ test/karma/repeat2.cpp | 9 ++ test/karma/stream.cpp | 2 +- test/karma/utree2.cpp | 4 +- test/karma/wstream.cpp | 2 +- test/qi/alternative.cpp | 8 ++ test/qi/debug.cpp | 2 +- test/qi/kleene.cpp | 8 +- test/qi/list.cpp | 15 ++ test/qi/optional.cpp | 6 + test/qi/plus.cpp | 8 +- test/qi/regression_repeat.cpp | 10 +- test/qi/repeat.cpp | 46 +++++-- test/qi/sequence.cpp | 33 ++++- test/qi/utree1.cpp | 12 +- test/qi/utree2.cpp | 5 +- 54 files changed, 906 insertions(+), 456 deletions(-) create mode 100644 test/karma/regression_const_real_policies.cpp diff --git a/doc/what_s_new.qbk b/doc/what_s_new.qbk index edcb933f4..1248b0e6b 100644 --- a/doc/what_s_new.qbk +++ b/doc/what_s_new.qbk @@ -149,8 +149,8 @@ [heading Known Problems] -* Integer literals consume input on failure, which can lead to problems with - the alternative operator: +* Integer literals (like `int_(10)`) consume input on failure, which can lead to + problems with the alternative operator: [endsect] diff --git a/include/boost/spirit/home/karma/auto/auto.hpp b/include/boost/spirit/home/karma/auto/auto.hpp index f10778fc1..ea6469974 100644 --- a/include/boost/spirit/home/karma/auto/auto.hpp +++ b/include/boost/spirit/home/karma/auto/auto.hpp @@ -60,7 +60,7 @@ namespace boost { namespace spirit { namespace karma template struct attribute { - typedef spirit::hold_any type; + typedef spirit::basic_hold_any type; }; auto_generator(Modifiers const& modifiers) diff --git a/include/boost/spirit/home/karma/detail/attributes.hpp b/include/boost/spirit/home/karma/detail/attributes.hpp index b4c252668..c63faace3 100644 --- a/include/boost/spirit/home/karma/detail/attributes.hpp +++ b/include/boost/spirit/home/karma/detail/attributes.hpp @@ -20,7 +20,7 @@ namespace boost { namespace spirit { namespace karma typedef Transformed type; static Transformed pre(Exposed& val) { - return Transformed(traits::extract_from(val, unused)); + return Transformed(traits::extract_from(val, unused)); } // Karma only, no post() and no fail() required }; diff --git a/include/boost/spirit/home/karma/detail/extract_from.hpp b/include/boost/spirit/home/karma/detail/extract_from.hpp index a3c245673..2f401b096 100644 --- a/include/boost/spirit/home/karma/detail/extract_from.hpp +++ b/include/boost/spirit/home/karma/detail/extract_from.hpp @@ -117,8 +117,109 @@ namespace boost { namespace spirit { namespace traits }; /////////////////////////////////////////////////////////////////////////// + template + struct extract_from_container + { + typedef typename traits::container_value::type + value_type; + typedef typename is_convertible::type + is_convertible_to_value_type; + + typedef typename mpl::if_< + mpl::or_< + is_same, is_same > + , Exposed const&, Exposed + >::type type; + + // handle case where container value type is convertible to result type + // we simply return the front element of the container + template + static type call(Attribute const& attr, Context& ctx, mpl::true_, Pred) + { + // return first element from container + typedef typename traits::container_iterator::type + iterator_type; + + iterator_type it = boost::begin(attr); + type result = *it; + ++it; + return result; + } + + // handle strings + template + static void append_to_string(Exposed& result, Iterator begin, Iterator end) + { + for (Iterator i = begin; i != end; ++i) + push_back(result, *i); + } + + template + static type call(Attribute const& attr, Context& ctx, mpl::false_, mpl::true_) + { + typedef typename char_type_of::type char_type; + + Exposed result; + append_to_string(result, traits::get_begin(attr) + , traits::get_end(attr)); + return result; + } + + // everything else gets just passed through + template + static type call(Attribute const& attr, Context& ctx, mpl::false_, mpl::false_) + { + return type(attr); + } + + template + static type call(Attribute const& attr, Context& ctx) + { + typedef typename mpl::and_< + traits::is_string, traits::is_string + >::type handle_strings; + + // return first element from container + return call(attr, ctx, is_convertible_to_value_type() + , handle_strings()); + } + }; + + template + struct extract_from_container + { + typedef Attribute const& type; + + template + static type call(Attribute const& attr, Context& ctx) + { + return attr; + } + }; + + /////////////////////////////////////////////////////////////////////////// + namespace detail + { + // overload for non-container attributes + template + inline typename spirit::result_of::extract_from::type + extract_from(Attribute const& attr, Context& ctx, mpl::false_) + { + return extract_from_attribute::call(attr, ctx); + } + + // overload for containers (but not for variants or optionals + // holding containers) + template + inline typename spirit::result_of::extract_from::type + extract_from(Attribute const& attr, Context& ctx, mpl::true_) + { + return extract_from_container::call(attr, ctx); + } + } + template - typename spirit::result_of::extract_from::type + inline typename spirit::result_of::extract_from::type extract_from(Attribute const& attr, Context& ctx #if (defined(__GNUC__) && (__GNUC__ < 4)) || \ (defined(__APPLE__) && defined(__INTEL_COMPILER)) @@ -126,11 +227,18 @@ namespace boost { namespace spirit { namespace traits #endif ) { - return extract_from_attribute::call(attr, ctx); + typedef typename mpl::and_< + traits::is_container + , traits::not_is_variant + , traits::not_is_optional + >::type is_not_wrapped_container; + + return detail::extract_from(attr, ctx + , is_not_wrapped_container()); } template - unused_type extract_from(unused_type, Context&) + inline unused_type extract_from(unused_type, Context&) { return unused; } @@ -141,7 +249,13 @@ namespace boost { namespace spirit { namespace result_of { template struct extract_from - : traits::extract_from_attribute + : mpl::if_< + mpl::and_< + traits::is_container + , traits::not_is_variant + , traits::not_is_optional > + , traits::extract_from_container + , traits::extract_from_attribute >::type {}; template diff --git a/include/boost/spirit/home/karma/detail/pass_container.hpp b/include/boost/spirit/home/karma/detail/pass_container.hpp index be3e2d410..d95328a2f 100644 --- a/include/boost/spirit/home/karma/detail/pass_container.hpp +++ b/include/boost/spirit/home/karma/detail/pass_container.hpp @@ -32,18 +32,27 @@ namespace boost { namespace spirit { namespace karma { namespace detail // to the RHS. template ::value> + , bool IsContainer = traits::is_container::value + , bool IsSequence = fusion::traits::is_sequence::value> struct has_same_elements : mpl::false_ {}; template - struct has_same_elements + struct has_same_elements : mpl::or_< is_convertible - , is_same + , traits::is_hold_any > {}; template - struct has_same_elements, true> + struct has_same_elements, false, false> + : has_same_elements {}; + + template + struct has_same_elements, true, false> + : has_same_elements {}; + + template + struct has_same_elements, false, true> : has_same_elements {}; #define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \ @@ -54,12 +63,26 @@ namespace boost { namespace spirit { namespace karma { namespace detail // container (see support/container.hpp). template struct has_same_elements< - RHS, boost::variant, true> + RHS, boost::variant, true, false> : mpl::bool_ {}; #undef BOOST_SPIRIT_IS_CONVERTIBLE + // Specialization for fusion sequences, in this case we check whether the + // lhs attribute is convertible to the types in the sequence. + // We return false if the rhs attribute itself is a fusion sequence. + template + struct has_same_elements + { + typedef typename mpl::find_if< + LHSAttribute, mpl::not_ > + >::type iter; + typedef typename mpl::end::type end; + + typedef typename is_same::type type; + }; + /////////////////////////////////////////////////////////////////////////// // This function handles the case where the attribute (Attr) given // to the sequence is an STL container. This is a wrapper around F. @@ -73,18 +96,34 @@ namespace boost { namespace spirit { namespace karma { namespace detail : f(f), iter(begin), end(end) {} + bool is_at_end() const + { + return traits::compare(iter, end); + } + + void next() + { + traits::next(iter); + } + // this is for the case when the current element expects an attribute // which is taken from the next entry in the container template bool dispatch_attribute_element(Component const& component, mpl::false_) const { // get the next value to generate from container - if (!traits::compare(iter, end) && !f(component, traits::deref(iter))) + if (!is_at_end() && !f(component, traits::deref(iter))) { // needs to return false as long as everything is ok traits::next(iter); return false; } + +// // in non-strict mode increment iterator if the underlying +// // generator failed +// if (!Strict::value && !is_at_end()) +// traits::next(iter); + // either no elements available any more or generation failed return true; } @@ -180,6 +219,14 @@ namespace boost { namespace spirit { namespace karma { namespace detail // silence MSVC warning C4512: assignment operator could not be generated pass_container& operator= (pass_container const&); }; + + // Utility function to make a pass_container + template + pass_container + inline make_pass_container(F const& f, Attr& attr, Iterator b, Iterator e) + { + return pass_container(f, attr, b, e); + } }}}} #endif diff --git a/include/boost/spirit/home/karma/numeric/bool.hpp b/include/boost/spirit/home/karma/numeric/bool.hpp index b6469e147..d969f6df2 100644 --- a/include/boost/spirit/home/karma/numeric/bool.hpp +++ b/include/boost/spirit/home/karma/numeric/bool.hpp @@ -312,7 +312,8 @@ namespace boost { namespace spirit { namespace karma template struct make_primitive< tag::stateful_tag, Modifiers> - : detail::make_bool {}; + : detail::make_bool::type, Policies> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -356,7 +357,8 @@ namespace boost { namespace spirit { namespace karma terminal_ex , fusion::vector1 > , Modifiers> - : detail::make_bool_direct {}; + : detail::make_bool_direct::type, Policies> {}; /////////////////////////////////////////////////////////////////////////// namespace detail diff --git a/include/boost/spirit/home/karma/numeric/int.hpp b/include/boost/spirit/home/karma/numeric/int.hpp index e394bca6e..5a755325f 100644 --- a/include/boost/spirit/home/karma/numeric/int.hpp +++ b/include/boost/spirit/home/karma/numeric/int.hpp @@ -378,7 +378,8 @@ namespace boost { namespace spirit { namespace karma template struct make_primitive, Modifiers> - : detail::make_int {}; + : detail::make_int::type + , Modifiers, Radix, force_sign> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -436,7 +437,8 @@ namespace boost { namespace spirit { namespace karma struct make_primitive< terminal_ex , fusion::vector1 >, Modifiers> - : detail::make_int_direct {}; + : detail::make_int_direct::type + , Modifiers, Radix, force_sign> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -489,7 +491,6 @@ namespace boost { namespace spirit { namespace karma terminal_ex > , Modifiers , typename enable_if >::type> - : detail::basic_int_literal { static bool const lower = has_modifier >::value; @@ -497,7 +498,7 @@ namespace boost { namespace spirit { namespace karma has_modifier >::value; typedef literal_int_generator< - A0 + typename remove_const::type , typename spirit::detail::get_encoding_with_case< Modifiers, unused_type, lower || upper>::type , typename detail::get_casetag::type diff --git a/include/boost/spirit/home/karma/numeric/real.hpp b/include/boost/spirit/home/karma/numeric/real.hpp index 5df512773..a937d4c10 100644 --- a/include/boost/spirit/home/karma/numeric/real.hpp +++ b/include/boost/spirit/home/karma/numeric/real.hpp @@ -322,7 +322,8 @@ namespace boost { namespace spirit { namespace karma template struct make_primitive< tag::stateful_tag, Modifiers> - : detail::make_real {}; + : detail::make_real::type + , Modifiers, Policies> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -376,7 +377,8 @@ namespace boost { namespace spirit { namespace karma terminal_ex , fusion::vector1 > , Modifiers> - : detail::make_real_direct {}; + : detail::make_real_direct::type + , Modifiers, Policies> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -423,7 +425,6 @@ namespace boost { namespace spirit { namespace karma terminal_ex > , Modifiers , typename enable_if >::type> - : detail::basic_real_literal { static bool const lower = has_modifier >::value; @@ -431,7 +432,7 @@ namespace boost { namespace spirit { namespace karma has_modifier >::value; typedef literal_real_generator< - A0, real_policies + typename remove_const::type, real_policies , typename spirit::detail::get_encoding_with_case< Modifiers, unused_type, lower || upper>::type , typename detail::get_casetag::type diff --git a/include/boost/spirit/home/karma/numeric/uint.hpp b/include/boost/spirit/home/karma/numeric/uint.hpp index 2a6437f13..689a8a1c5 100644 --- a/include/boost/spirit/home/karma/numeric/uint.hpp +++ b/include/boost/spirit/home/karma/numeric/uint.hpp @@ -417,7 +417,7 @@ namespace boost { namespace spirit { namespace karma template struct make_primitive, Modifiers> - : detail::make_uint {}; + : detail::make_uint::type, Modifiers, Radix> {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -487,7 +487,8 @@ namespace boost { namespace spirit { namespace karma struct make_primitive< terminal_ex, fusion::vector1 > , Modifiers> - : detail::make_uint_direct {}; + : detail::make_uint_direct::type, Modifiers, Radix> + {}; /////////////////////////////////////////////////////////////////////////// namespace detail @@ -542,7 +543,6 @@ namespace boost { namespace spirit { namespace karma terminal_ex > , Modifiers , typename enable_if >::type> - : detail::basic_uint_literal { static bool const lower = has_modifier >::value; @@ -550,7 +550,7 @@ namespace boost { namespace spirit { namespace karma has_modifier >::value; typedef literal_uint_generator< - A0 + typename remove_const::type , typename spirit::detail::get_encoding_with_case< Modifiers, unused_type, lower || upper>::type , typename detail::get_casetag::type diff --git a/include/boost/spirit/home/karma/operator/kleene.hpp b/include/boost/spirit/home/karma/operator/kleene.hpp index 6c7538115..ad68ee54e 100644 --- a/include/boost/spirit/home/karma/operator/kleene.hpp +++ b/include/boost/spirit/home/karma/operator/kleene.hpp @@ -15,7 +15,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -41,29 +44,39 @@ namespace boost { namespace spirit { namespace karma struct base_kleene : unary_generator { private: - template < - typename OutputIterator, typename Context, typename Delimiter - , typename Attribute> - bool generate_subject(OutputIterator& sink, Context& ctx - , Delimiter const& d, Attribute const& attr) const + // Ignore return value in relaxed mode (failing subject generators + // are just skipped). This allows to selectively generate items in + // the provided attribute. + template + bool generate_subject(F f, Attribute const&, mpl::false_) const { - // Ignore return value, failing subject generators are just - // skipped. This allows to selectively generate items in the - // provided attribute. - bool r = subject.generate(sink, ctx, d, attr); - return !Strict::value || r; + bool r = !f(subject); + if (!r && !f.is_at_end()) + f.next(); + return true; } - template - bool generate_subject(OutputIterator& sink, Context& ctx - , Delimiter const& d, unused_type) const + template + bool generate_subject(F f, Attribute const&, mpl::true_) const { - // There is no way to distinguish a failed generator from a - // generator to be skipped. We assume the user takes responsibility - // for ending the loop if no attribute is specified. - return subject.generate(sink, ctx, d, unused); + return !f(subject); } + // There is no way to distinguish a failed generator from a + // generator to be skipped. We assume the user takes responsibility + // for ending the loop if no attribute is specified. + template + bool generate_subject(F f, unused_type, mpl::false_) const + { + return !f(subject); + } + +// template +// bool generate_subject(F f, unused_type, mpl::true_) const +// { +// return !f(subject); +// } + public: typedef Subject subject_type; typedef typename subject_type::properties properties; @@ -87,18 +100,28 @@ namespace boost { namespace spirit { namespace karma bool generate(OutputIterator& sink, Context& ctx , Delimiter const& d, Attribute const& attr) const { + typedef detail::fail_function< + OutputIterator, Context, Delimiter> fail_function; + typedef typename traits::container_iterator< typename add_const::type >::type iterator_type; + typedef typename detail::make_indirect_iterator::type + indirect_iterator_type; + typedef detail::pass_container< + fail_function, Attribute, indirect_iterator_type, Strict> + pass_container; iterator_type it = traits::begin(attr); iterator_type end = traits::end(attr); + pass_container pass(fail_function(sink, ctx, d), + indirect_iterator_type(it), indirect_iterator_type(end)); + // kleene fails only if the underlying output fails - for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end); - traits::next(it)) + while (!pass.is_at_end()) { - if (!generate_subject(sink, ctx, d, traits::deref(it))) + if (!generate_subject(pass, attr, Strict())) break; } return detail::sink_is_good(sink); @@ -170,13 +193,13 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute - , Context, Iterator> + , Context, Iterator> : mpl::true_ {}; template struct handles_container, Attribute - , Context, Iterator> + , Context, Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/karma/operator/list.hpp b/include/boost/spirit/home/karma/operator/list.hpp index 6fe688204..92fca5871 100644 --- a/include/boost/spirit/home/karma/operator/list.hpp +++ b/include/boost/spirit/home/karma/operator/list.hpp @@ -15,7 +15,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -41,39 +44,35 @@ namespace boost { namespace spirit { namespace karma private: // iterate over the given container until its exhausted or the embedded // (left) generator succeeds - template < - typename OutputIterator, typename Context, typename Delimiter - , typename Iterator, typename Attribute> - bool generate_left(OutputIterator& sink, Context& ctx - , Delimiter const& d, Iterator& it, Iterator& end, Attribute const&) const + template + bool generate_left(F f, Attribute const&, mpl::false_) const { - if (Strict::value) { - if (!traits::compare(it, end)) - return left.generate(sink, ctx, d, traits::deref(it)); - } - else { - // Failing subject generators are just skipped. This allows to - // selectively generate items in the provided attribute. - while (!traits::compare(it, end)) - { - if (left.generate(sink, ctx, d, traits::deref(it))) - return true; - traits::next(it); - } + // Failing subject generators are just skipped. This allows to + // selectively generate items in the provided attribute. + while (!f.is_at_end()) + { + bool r = !f(left); + if (r) + return true; + if (!f.is_at_end()) + f.next(); } return false; } - template < - typename OutputIterator, typename Context, typename Delimiter - , typename Iterator> - bool generate_left(OutputIterator& sink, Context& ctx - , Delimiter const& d, Iterator&, Iterator&, unused_type) const + template + bool generate_left(F f, Attribute const&, mpl::true_) const { - // There is no way to distinguish a failed generator from a - // generator to be skipped. We assume the user takes responsibility - // for ending the loop if no attribute is specified. - return left.generate(sink, ctx, d, unused); + return !f(left); + } + + // There is no way to distinguish a failed generator from a + // generator to be skipped. We assume the user takes responsibility + // for ending the loop if no attribute is specified. + template + bool generate_left(F f, unused_type, mpl::false_) const + { + return !f(left); } public: @@ -106,16 +105,29 @@ namespace boost { namespace spirit { namespace karma bool generate(OutputIterator& sink, Context& ctx , Delimiter const& d, Attribute const& attr) const { + typedef detail::fail_function< + OutputIterator, Context, Delimiter + > fail_function; + typedef typename traits::container_iterator< typename add_const::type >::type iterator_type; + typedef + typename detail::make_indirect_iterator::type + indirect_iterator_type; + typedef detail::pass_container< + fail_function, Attribute, indirect_iterator_type, Strict> + pass_container; iterator_type it = traits::begin(attr); iterator_type end = traits::end(attr); - if (generate_left(sink, ctx, d, it, end, attr)) + pass_container pass(fail_function(sink, ctx, d), + indirect_iterator_type(it), indirect_iterator_type(end)); + + if (generate_left(pass, attr, Strict())) { - for (traits::next(it); !traits::compare(it, end); traits::next(it)) + while (!pass.is_at_end()) { // wrap the given output iterator as generate_left might fail detail::enable_buffering buffering(sink); @@ -125,7 +137,7 @@ namespace boost { namespace spirit { namespace karma if (!right.generate(sink, ctx, d, unused)) return false; // shouldn't happen - if (!generate_left(sink, ctx, d, it, end, attr)) + if (!generate_left(pass, attr, Strict())) break; // return true as one item succeeded } buffering.buffer_copy(); @@ -203,13 +215,13 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute - , Context, Iterator> + , Context, Iterator> : mpl::true_ {}; template struct handles_container, Attribute - , Context, Iterator> + , Context, Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/karma/operator/optional.hpp b/include/boost/spirit/home/karma/operator/optional.hpp index bfa39fc7d..983142d5e 100644 --- a/include/boost/spirit/home/karma/operator/optional.hpp +++ b/include/boost/spirit/home/karma/operator/optional.hpp @@ -98,8 +98,8 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> - : unary_handles_container {}; + , Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/karma/operator/plus.hpp b/include/boost/spirit/home/karma/operator/plus.hpp index 9674ecd43..53721baba 100644 --- a/include/boost/spirit/home/karma/operator/plus.hpp +++ b/include/boost/spirit/home/karma/operator/plus.hpp @@ -14,8 +14,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -42,36 +45,50 @@ namespace boost { namespace spirit { namespace karma struct base_plus : unary_generator { private: - template < - typename OutputIterator, typename Context, typename Delimiter - , typename Attribute> - bool generate_subject(OutputIterator& sink, Context& ctx - , Delimiter const& d, Attribute const& attr, bool& result) const + // Ignore return value in relaxed mode (failing subject generators + // are just skipped). This allows to selectively generate items in + // the provided attribute. + template + bool generate_subject(F f, Attribute const& attr, bool& result, mpl::false_) const { - // Ignore return value, failing subject generators are just - // skipped. This allows to selectively generate items in the - // provided attribute. - if (subject.generate(sink, ctx, d, attr)) { + bool r = !f(subject); + if (r) result = true; - return true; - } - return !Strict::value; + else if (!f.is_at_end()) + f.next(); + return true; } - template - bool generate_subject(OutputIterator& sink, Context& ctx - , Delimiter const& d, unused_type, bool& result) const + template + bool generate_subject(F f, Attribute const& attr, bool& result, mpl::true_) const { - // There is no way to distinguish a failed generator from a - // generator to be skipped. We assume the user takes responsibility - // for ending the loop if no attribute is specified. - if (subject.generate(sink, ctx, d, unused)) { + bool r = !f(subject); + if (r) result = true; - return true; - } - return false; + return r; } + // There is no way to distinguish a failed generator from a + // generator to be skipped. We assume the user takes responsibility + // for ending the loop if no attribute is specified. + template + bool generate_subject(F f, unused_type, bool& result, mpl::false_) const + { + bool r = f(subject); + if (!r) + result = true; + return !r; + } + +// template +// bool generate_subject(F f, unused_type, bool& result, mpl::true_) const +// { +// bool r = f(subject); +// if (!r) +// result = true; +// return !r; +// } + public: typedef Subject subject_type; typedef typename subject_type::properties properties; @@ -95,9 +112,17 @@ namespace boost { namespace spirit { namespace karma bool generate(OutputIterator& sink, Context& ctx , Delimiter const& d, Attribute const& attr) const { + typedef detail::fail_function< + OutputIterator, Context, Delimiter> fail_function; + typedef typename traits::container_iterator< typename add_const::type >::type iterator_type; + typedef typename detail::make_indirect_iterator::type + indirect_iterator_type; + typedef detail::pass_container< + fail_function, Attribute, indirect_iterator_type, Strict> + pass_container; iterator_type it = traits::begin(attr); iterator_type end = traits::end(attr); @@ -106,13 +131,15 @@ namespace boost { namespace spirit { namespace karma if (traits::compare(it, end)) return false; + pass_container pass(fail_function(sink, ctx, d), + indirect_iterator_type(it), indirect_iterator_type(end)); + // from now on plus fails if the underlying output fails or overall // no subject generators succeeded bool result = false; - for (/**/; detail::sink_is_good(sink) && !traits::compare(it, end); - traits::next(it)) + while (!pass.is_at_end()) { - if (!generate_subject(sink, ctx, d, traits::deref(it), result)) + if (!generate_subject(pass, attr, result, Strict())) break; } return result && detail::sink_is_good(sink); @@ -184,14 +211,14 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute - , Context, Iterator> - : unary_handles_container {}; + , Context, Iterator> + : mpl::true_ {}; template struct handles_container, Attribute - , Context, Iterator> - : unary_handles_container {}; + , Context, Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/karma/operator/sequence.hpp b/include/boost/spirit/home/karma/operator/sequence.hpp index 0133554f1..54bd5b63b 100644 --- a/include/boost/spirit/home/karma/operator/sequence.hpp +++ b/include/boost/spirit/home/karma/operator/sequence.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -83,83 +84,11 @@ namespace boost { namespace spirit { namespace traits , mpl::bitor_ >::type type; }; - }}} /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace karma { - namespace detail - { - - /////////////////////////////////////////////////////////////////////// - // This is a wrapper for any iterator allowing to pass a reference of it - // to the components of the sequence - template - class indirect_iterator - : public boost::iterator_facade< - indirect_iterator - , typename boost::detail::iterator_traits::value_type - , boost::forward_traversal_tag - , typename boost::detail::iterator_traits::value_type const&> - { - typedef typename boost::detail::iterator_traits::value_type - base_value_type; - - typedef boost::iterator_facade< - indirect_iterator, base_value_type - , boost::forward_traversal_tag, base_value_type const& - > base_type; - - public: - indirect_iterator(Iterator& iter) - : iter_(&iter) - {} - indirect_iterator(indirect_iterator const& iter) - : iter_(iter.iter_) - {} - - private: - friend class boost::iterator_core_access; - - void increment() - { - ++*iter_; - } - - bool equal(indirect_iterator const& other) const - { - return *iter_ == *other.iter_; - } - - typename base_type::reference dereference() const - { - return **iter_; - } - - private: - Iterator* iter_; - }; - - template - struct make_indirect_iterator - { - typedef indirect_iterator type; - }; - - template - struct make_indirect_iterator > - { - typedef indirect_iterator type; - }; - - template <> - struct make_indirect_iterator - { - typedef unused_type const* type; - }; - } - template struct base_sequence : nary_generator { @@ -365,14 +294,14 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> - : nary_handles_container {}; - + , Iterator> + : mpl::true_ {}; + template struct handles_container, Attribute - , Context, Iterator> - : nary_handles_container {}; + , Context, Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/karma/stream/stream.hpp b/include/boost/spirit/home/karma/stream/stream.hpp index 3ecfe5f18..949647838 100644 --- a/include/boost/spirit/home/karma/stream/stream.hpp +++ b/include/boost/spirit/home/karma/stream/stream.hpp @@ -113,7 +113,7 @@ namespace boost { namespace spirit { namespace karma template struct attribute { - typedef spirit::hold_any type; + typedef spirit::basic_hold_any type; }; // any_stream_generator has an attached attribute diff --git a/include/boost/spirit/home/qi/detail/assign_to.hpp b/include/boost/spirit/home/qi/detail/assign_to.hpp index 73d361737..585d71dd8 100644 --- a/include/boost/spirit/home/qi/detail/assign_to.hpp +++ b/include/boost/spirit/home/qi/detail/assign_to.hpp @@ -227,9 +227,9 @@ namespace boost { namespace spirit { namespace traits namespace detail { // overload for non-container attributes - template + template inline void - assign_to(T const& val, Attribute& attr, P1, P2) + assign_to(T const& val, Attribute& attr, mpl::false_) { assign_to_attribute_from_value::call(val, attr); } @@ -238,7 +238,7 @@ namespace boost { namespace spirit { namespace traits // holding containers) template inline void - assign_to(T const& val, Attribute& attr, mpl::true_, mpl::true_) + assign_to(T const& val, Attribute& attr, mpl::true_) { assign_to_container_from_value::call(val, attr); } @@ -248,13 +248,13 @@ namespace boost { namespace spirit { namespace traits inline void assign_to(T const& val, Attribute& attr) { - typedef typename traits::is_container::type is_container; typedef typename mpl::and_< - traits::not_is_variant + traits::is_container + , traits::not_is_variant , traits::not_is_optional >::type is_not_wrapped_container; - detail::assign_to(val, attr, is_container(), is_not_wrapped_container()); + detail::assign_to(val, attr, is_not_wrapped_container()); } template diff --git a/include/boost/spirit/home/qi/detail/pass_container.hpp b/include/boost/spirit/home/qi/detail/pass_container.hpp index dc98104bb..de54f9822 100644 --- a/include/boost/spirit/home/qi/detail/pass_container.hpp +++ b/include/boost/spirit/home/qi/detail/pass_container.hpp @@ -26,15 +26,24 @@ namespace boost { namespace spirit { namespace qi { namespace detail // to the LHS. template ::value> + , bool IsContainer = traits::is_container::value + , bool IsSequence = fusion::traits::is_sequence::value> struct has_same_elements : mpl::false_ {}; template - struct has_same_elements + struct has_same_elements : is_convertible {}; template - struct has_same_elements, true> + struct has_same_elements, false, false> + : has_same_elements {}; + + template + struct has_same_elements, true, false> + : has_same_elements {}; + + template + struct has_same_elements, false, true> : has_same_elements {}; #define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \ @@ -45,12 +54,28 @@ namespace boost { namespace spirit { namespace qi { namespace detail // container (see support/container.hpp). template struct has_same_elements< - LHS, boost::variant, true> + LHS, boost::variant, true, false> : mpl::bool_ {}; #undef BOOST_SPIRIT_IS_CONVERTIBLE + // Specialization for fusion sequences, in this case we check whether all + // the types in the sequence are convertible to the lhs attribute. + // We return false if the lhs attribute itself is a fusion sequence. + template + struct has_same_elements + { + typedef typename mpl::find_if< + RHSAttribute, mpl::not_ > + >::type iter; + typedef typename mpl::end::type end; + + typedef typename mpl::and_< + mpl::not_ >, is_same + >::type type; + }; + // This function handles the case where the attribute (Attr) given // the sequence is an STL container. This is a wrapper around F. // The function F does the actual parsing. @@ -163,6 +188,9 @@ namespace boost { namespace spirit { namespace qi { namespace detail , iterator_type> > predicate; +// // ensure the attribute is actually a container type +// traits::make_container(attr); + return dispatch_main(component, predicate()); } diff --git a/include/boost/spirit/home/qi/directive/repeat.hpp b/include/boost/spirit/home/qi/directive/repeat.hpp index 436cd1bc1..3150c0c74 100644 --- a/include/boost/spirit/home/qi/directive/repeat.hpp +++ b/include/boost/spirit/home/qi/directive/repeat.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,11 +19,12 @@ #include #include #include +#include +#include #include #include #include #include -#include #include namespace boost { namespace spirit @@ -152,57 +154,26 @@ namespace boost { namespace spirit { namespace qi repeat_parser(Subject const& subject, LoopIter const& iter) : subject(subject), iter(iter) {} - template - bool parse_minimal(Iterator &first, Iterator const& last - , Context& context, Skipper const& skipper - , Attribute& attr, ValueType& val, LoopVar& i) const + template + bool parse_container(F f) const { - // this scope allows save and required_attr to be reclaimed - // immediately after we're done with the required minimum - // iteration. - Iterator save = first; - std::vector required_attr; - for (; !iter.got_min(i); ++i) + typename LoopIter::type i = iter.start(); + for (/**/; !iter.got_min(i); ++i) { - if (!subject.parse(save, last, context, skipper, val) || - !traits::push_back(required_attr, val)) - { + if (f (subject)) return false; - } - - first = save; - traits::clear(val); } - // if we got the required number of items, these are copied - // over (appended) to the 'real' attribute - BOOST_FOREACH(ValueType const& v, required_attr) + // parse some more up to the maximum specified + typename F::iterator_type save = f.f.first; + for (/**/; !iter.got_max(i); ++i) { - traits::push_back(attr, v); + if (f (subject)) + break; + save = f.f.first; } - return true; - } - template - bool parse_minimal(Iterator &first, Iterator const& last - , Context& context, Skipper const& skipper - , unused_type, unused_type, LoopVar& i) const - { - // this scope allows save and required_attr to be reclaimed - // immediately after we're done with the required minimum - // iteration. - Iterator save = first; - for (; !iter.got_min(i); ++i) - { - if (!subject.parse(save, last, context, skipper, unused)) - { - return false; - } - first = save; - } + f.f.first = save; return true; } @@ -212,35 +183,18 @@ namespace boost { namespace spirit { namespace qi , Context& context, Skipper const& skipper , Attribute& attr) const { - // create a local value if Attribute is not unused_type - typedef typename traits::container_value::type - value_type; - value_type val = value_type(); - typename LoopIter::type i = iter.start(); + typedef detail::fail_function + fail_function; // ensure the attribute is actually a container type traits::make_container(attr); - // parse the minimum required - Iterator save = first; - if (!iter.got_min(i) && - !parse_minimal(save, last, context, skipper, attr, val, i)) - { + Iterator iter = first; + fail_function f(iter, last, context, skipper); + if (!parse_container(detail::make_pass_container(f, attr))) return false; - } - // parse some more up to the maximum specified - for (/**/; !iter.got_max(i); ++i) { - if (!subject.parse(save, last, context, skipper, val) || - !traits::push_back(attr, val)) - { - break; - } - first = save; - traits::clear(val); - } - - first = save; + first = f.first; return true; } @@ -334,7 +288,7 @@ namespace boost { namespace spirit { namespace traits template struct handles_container - , Attribute, Context, Iterator> + , Attribute, Context, Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/qi/numeric/int.hpp b/include/boost/spirit/home/qi/numeric/int.hpp index 163afa4dd..8037ae966 100644 --- a/include/boost/spirit/home/qi/numeric/int.hpp +++ b/include/boost/spirit/home/qi/numeric/int.hpp @@ -56,7 +56,7 @@ namespace boost { namespace spirit , terminal_ex > , typename enable_if >::type> : mpl::true_ {}; - + template // enables short_(n) struct use_terminal > > @@ -69,7 +69,7 @@ namespace boost { namespace spirit //[primitive_parsers_enable_int template <> // enables int_ struct use_terminal : mpl::true_ {}; - //] + //] template // enables lit(n) struct use_terminal // enables *lazy* int_(n) struct use_lazy_terminal : mpl::true_ {}; - + /////////////////////////////////////////////////////////////////////////// //[primitive_parsers_enable_long template <> // enables long_ struct use_terminal : mpl::true_ {}; - //] - + //] + template // enables lit(n) struct use_terminal > @@ -104,7 +104,7 @@ namespace boost { namespace spirit template <> // enables *lazy* long_(n) struct use_lazy_terminal : mpl::true_ {}; - + /////////////////////////////////////////////////////////////////////////// #ifdef BOOST_HAS_LONG_LONG //[primitive_parsers_enable_long_long @@ -236,7 +236,7 @@ namespace boost { namespace spirit { namespace qi { typedef extract_int extract; qi::skip_over(first, last, skipper); - + Iterator save = first; T attr_; @@ -277,7 +277,7 @@ namespace boost { namespace spirit { namespace qi } }; //] - + template struct make_direct_int @@ -290,7 +290,7 @@ namespace boost { namespace spirit { namespace qi return result_type(fusion::at_c<0>(term.args)); } }; - + template struct make_literal_int @@ -302,7 +302,7 @@ namespace boost { namespace spirit { namespace qi return result_type(fusion::at_c<0>(term.args)); } }; - + /////////////////////////////////////////////////////////////////////////// template struct make_primitive< diff --git a/include/boost/spirit/home/qi/operator/expect.hpp b/include/boost/spirit/home/qi/operator/expect.hpp index 4df1dd000..c42b2defc 100644 --- a/include/boost/spirit/home/qi/operator/expect.hpp +++ b/include/boost/spirit/home/qi/operator/expect.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -95,8 +96,8 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> - : nary_handles_container {}; + , Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/qi/operator/kleene.hpp b/include/boost/spirit/home/qi/operator/kleene.hpp index b106c9245..ae778f0bf 100644 --- a/include/boost/spirit/home/qi/operator/kleene.hpp +++ b/include/boost/spirit/home/qi/operator/kleene.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -33,7 +36,6 @@ namespace boost { namespace spirit namespace boost { namespace spirit { namespace qi { - //[composite_parsers_kleene template struct kleene : unary_parser > @@ -57,28 +59,31 @@ namespace boost { namespace spirit { namespace qi kleene(Subject const& subject) : subject(subject) {} + template + bool parse_container(F f) const + { + while (!f (subject)) + ; + return true; + } + template bool parse(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr) const { - // create a local value if Attribute is not unused_type - typedef typename traits::container_value::type - value_type; - value_type val = value_type(); - // ensure the attribute is actually a container type traits::make_container(attr); - // Repeat while subject parses ok - Iterator save = first; - while (subject.parse(save, last, context, skipper, val) && - traits::push_back(attr, val)) // push the parsed value into our attribute - { - first = save; - traits::clear(val); - } + typedef detail::fail_function + fail_function; + + Iterator iter = first; + fail_function f(iter, last, context, skipper); + parse_container(detail::make_pass_container(f, attr)); + + first = f.first; return true; } @@ -120,9 +125,9 @@ namespace boost { namespace spirit { namespace traits /////////////////////////////////////////////////////////////////////////// template + , typename Iterator> struct handles_container, Attribute - , Context, Iterator> + , Context, Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/qi/operator/list.hpp b/include/boost/spirit/home/qi/operator/list.hpp index 65904aa28..cc067cd34 100644 --- a/include/boost/spirit/home/qi/operator/list.hpp +++ b/include/boost/spirit/home/qi/operator/list.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -55,36 +58,42 @@ namespace boost { namespace spirit { namespace qi list(Left const& left, Right const& right) : left(left), right(right) {} + template + bool parse_container(F f) const + { + // in order to succeed we need to match at least one element + if (f (left)) + return false; + + typename F::iterator_type save = f.f.first; + while (right.parse(f.f.first, f.f.last, f.f.context, f.f.skipper, unused) + && !f (left)) + { + save = f.f.first; + } + + f.f.first = save; + return true; + } + template bool parse(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr) const { - // create a local value if Attribute is not unused_type - typedef typename traits::container_value::type - value_type; - value_type val = value_type(); + typedef detail::fail_function + fail_function; // ensure the attribute is actually a container type traits::make_container(attr); - Iterator save = first; - if (!left.parse(save, last, context, skipper, val) || - !traits::push_back(attr, val)) - { + Iterator iter = first; + fail_function f(iter, last, context, skipper); + if (!parse_container(detail::make_pass_container(f, attr))) return false; - } - first = save; - while (right.parse(save, last, context, skipper, unused) - && (traits::clear(val), true) - && left.parse(save, last, context, skipper, val)) - { - if (!traits::push_back(attr, val)) - break; - first = save; - } + first = f.first; return true; } @@ -119,7 +128,7 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> + , Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/qi/operator/optional.hpp b/include/boost/spirit/home/qi/operator/optional.hpp index 883a95552..552b7e131 100644 --- a/include/boost/spirit/home/qi/operator/optional.hpp +++ b/include/boost/spirit/home/qi/operator/optional.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -16,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -58,9 +60,9 @@ namespace boost { namespace spirit { namespace qi template - bool parse(Iterator& first, Iterator const& last + bool parse_impl(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper - , Attribute& attr) const + , Attribute& attr, mpl::false_) const { // create a local value if Attribute is not unused_type typename spirit::result_of::optional_value::type val; @@ -73,6 +75,29 @@ namespace boost { namespace spirit { namespace qi return true; } + template + bool parse_impl(Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper + , Attribute& attr, mpl::true_) const + { + subject.parse(first, last, context, skipper, attr); + return true; + } + + template + bool parse(Iterator& first, Iterator const& last + , Context& context, Skipper const& skipper + , Attribute& attr) const + { + typedef typename spirit::result_of::optional_value::type + attribute_type; + + return parse_impl(first, last, context, skipper, attr + , traits::is_container()); + } + template info what(Context& context) const { @@ -102,8 +127,8 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute - , Context, Iterator> - : unary_handles_container {}; + , Context, Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/qi/operator/plus.hpp b/include/boost/spirit/home/qi/operator/plus.hpp index 2b9b5b289..780403a2c 100644 --- a/include/boost/spirit/home/qi/operator/plus.hpp +++ b/include/boost/spirit/home/qi/operator/plus.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -15,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -53,37 +56,36 @@ namespace boost { namespace spirit { namespace qi plus(Subject const& subject) : subject(subject) {} + template + bool parse_container(F f) const + { + // in order to succeed we need to match at least one element + if (f (subject)) + return false; + + while (!f (subject)) + ; + return true; + } + template bool parse(Iterator& first, Iterator const& last , Context& context, Skipper const& skipper , Attribute& attr) const { - // create a local value if Attribute is not unused_type - typedef typename traits::container_value::type - value_type; - value_type val = value_type(); + typedef detail::fail_function + fail_function; // ensure the attribute is actually a container type traits::make_container(attr); - Iterator save = first; - if (!subject.parse(save, last, context, skipper, val) || - !traits::push_back(attr, val)) - { + Iterator iter = first; + fail_function f(iter, last, context, skipper); + if (!parse_container(detail::make_pass_container(f, attr))) return false; - } - first = save; - traits::clear(val); - while (subject.parse(save, last, context, skipper, val)) - { - if (!traits::push_back(attr, val)) - break; - - first = save; - traits::clear(val); - } + first = f.first; return true; } @@ -116,7 +118,7 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> + , Iterator> : mpl::true_ {}; }}} diff --git a/include/boost/spirit/home/qi/operator/sequence.hpp b/include/boost/spirit/home/qi/operator/sequence.hpp index 843f4ec7e..817b7dc7c 100644 --- a/include/boost/spirit/home/qi/operator/sequence.hpp +++ b/include/boost/spirit/home/qi/operator/sequence.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -88,8 +89,8 @@ namespace boost { namespace spirit { namespace traits template struct handles_container, Attribute, Context - , Iterator> - : nary_handles_container {}; + , Iterator> + : mpl::true_ {}; }}} #endif diff --git a/include/boost/spirit/home/qi/operator/sequence_base.hpp b/include/boost/spirit/home/qi/operator/sequence_base.hpp index 03b022c4a..74d5a933d 100644 --- a/include/boost/spirit/home/qi/operator/sequence_base.hpp +++ b/include/boost/spirit/home/qi/operator/sequence_base.hpp @@ -1,5 +1,6 @@ /*============================================================================= Copyright (c) 2001-2011 Joel de Guzman + Copyright (c) 2001-2011 Hartmut Kaiser Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/include/boost/spirit/home/qi/stream/stream.hpp b/include/boost/spirit/home/qi/stream/stream.hpp index dc17fe6fa..0e4be9683 100644 --- a/include/boost/spirit/home/qi/stream/stream.hpp +++ b/include/boost/spirit/home/qi/stream/stream.hpp @@ -40,7 +40,7 @@ namespace boost { namespace spirit { namespace qi using spirit::stream; using spirit::wstream; - template + template > struct stream_parser : primitive_parser > { diff --git a/include/boost/spirit/home/support/attributes.hpp b/include/boost/spirit/home/support/attributes.hpp index fc8cd338c..5a81db38b 100644 --- a/include/boost/spirit/home/support/attributes.hpp +++ b/include/boost/spirit/home/support/attributes.hpp @@ -45,6 +45,7 @@ #include #include #include +#include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits @@ -115,7 +116,7 @@ namespace boost { namespace spirit { namespace traits template struct is_hold_any_container - : is_same::type> + : traits::is_hold_any::type> {}; } @@ -124,7 +125,7 @@ namespace boost { namespace spirit { namespace traits struct compute_compatible_component_variant : mpl::or_< traits::detail::attribute_is_compatible - , is_same + , traits::is_hold_any , mpl::eval_if< is_container , traits::detail::is_hold_any_container diff --git a/include/boost/spirit/home/support/attributes_fwd.hpp b/include/boost/spirit/home/support/attributes_fwd.hpp index 601ed762f..d97d4f726 100644 --- a/include/boost/spirit/home/support/attributes_fwd.hpp +++ b/include/boost/spirit/home/support/attributes_fwd.hpp @@ -132,6 +132,9 @@ namespace boost { namespace spirit { namespace traits template struct extract_from_attribute; + template + struct extract_from_container; + template typename spirit::result_of::extract_from::type extract_from(Attribute const& attr, Context& ctx diff --git a/include/boost/spirit/home/support/container.hpp b/include/boost/spirit/home/support/container.hpp index f18372147..70711331f 100644 --- a/include/boost/spirit/home/support/container.hpp +++ b/include/boost/spirit/home/support/container.hpp @@ -70,7 +70,7 @@ namespace boost { namespace spirit { namespace traits {}; #undef BOOST_SPIRIT_IS_CONTAINER - + template struct is_iterator_range : mpl::false_ diff --git a/include/boost/spirit/home/support/detail/hold_any.hpp b/include/boost/spirit/home/support/detail/hold_any.hpp index ed2756d7c..f305bcbca 100644 --- a/include/boost/spirit/home/support/detail/hold_any.hpp +++ b/include/boost/spirit/home/support/detail/hold_any.hpp @@ -58,6 +58,7 @@ namespace boost { namespace spirit namespace detail { // function pointer table + template struct fxn_ptr_table { boost::detail::sp_typeinfo const& (*get_type)(); @@ -65,18 +66,18 @@ namespace boost { namespace spirit void (*destruct)(void**); void (*clone)(void* const*, void**); void (*move)(void* const*, void**); - std::istream& (*stream_in)(std::istream&, void**); - std::ostream& (*stream_out)(std::ostream&, void* const*); + std::basic_istream& (*stream_in)(std::basic_istream&, void**); + std::basic_ostream& (*stream_out)(std::basic_ostream&, void* const*); }; // static functions for small value-types - template + template struct fxns; - template<> + template <> struct fxns { - template + template struct type { static boost::detail::sp_typeinfo const& get_type() @@ -101,12 +102,14 @@ namespace boost { namespace spirit *reinterpret_cast(dest) = *reinterpret_cast(src); } - static std::istream& stream_in (std::istream& i, void** obj) + static std::basic_istream& + stream_in (std::basic_istream& i, void** obj) { i >> *reinterpret_cast(obj); return i; } - static std::ostream& stream_out(std::ostream& o, void* const* obj) + static std::basic_ostream& + stream_out(std::basic_ostream& o, void* const* obj) { o << *reinterpret_cast(obj); return o; @@ -115,10 +118,10 @@ namespace boost { namespace spirit }; // static functions for big value-types (bigger than a void*) - template<> + template <> struct fxns { - template + template struct type { static boost::detail::sp_typeinfo const& get_type() @@ -145,12 +148,14 @@ namespace boost { namespace spirit **reinterpret_cast(dest) = **reinterpret_cast(src); } - static std::istream& stream_in(std::istream& i, void** obj) + static std::basic_istream& + stream_in(std::basic_istream& i, void** obj) { i >> **reinterpret_cast(obj); return i; } - static std::ostream& stream_out(std::ostream& o, void* const* obj) + static std::basic_ostream& + stream_out(std::basic_ostream& o, void* const* obj) { o << **reinterpret_cast(obj); return o; @@ -158,22 +163,23 @@ namespace boost { namespace spirit }; }; - template + template struct get_table { typedef mpl::bool_<(sizeof(T) <= sizeof(void*))> is_small; - static fxn_ptr_table* get() + template + static fxn_ptr_table* get() { - static fxn_ptr_table static_table = + static fxn_ptr_table static_table = { - fxns::template type::get_type, - fxns::template type::static_delete, - fxns::template type::destruct, - fxns::template type::clone, - fxns::template type::move, - fxns::template type::stream_in, - fxns::template type::stream_out + fxns::template type::get_type, + fxns::template type::static_delete, + fxns::template type::destruct, + fxns::template type::clone, + fxns::template type::move, + fxns::template type::stream_in, + fxns::template type::stream_out }; return &static_table; } @@ -207,13 +213,14 @@ namespace boost { namespace spirit } /////////////////////////////////////////////////////////////////////////// - class hold_any + template + class basic_hold_any { public: // constructors template - explicit hold_any(T const& x) - : table(spirit::detail::get_table::get()), object(0) + explicit basic_hold_any(T const& x) + : table(spirit::detail::get_table::template get()), object(0) { if (spirit::detail::get_table::is_small::value) new (&object) T(x); @@ -221,26 +228,26 @@ namespace boost { namespace spirit object = new T(x); } - hold_any() - : table(spirit::detail::get_table::get()), + basic_hold_any() + : table(spirit::detail::get_table::template get()), object(0) { } - hold_any(hold_any const& x) - : table(spirit::detail::get_table::get()), + basic_hold_any(basic_hold_any const& x) + : table(spirit::detail::get_table::template get()), object(0) { assign(x); } - ~hold_any() + ~basic_hold_any() { table->static_delete(&object); } // assignment - hold_any& assign(hold_any const& x) + basic_hold_any& assign(basic_hold_any const& x) { if (&x != this) { // are we copying between the same type? @@ -258,11 +265,11 @@ namespace boost { namespace spirit } template - hold_any& assign(T const& x) + basic_hold_any& assign(T const& x) { // are we copying between the same type? - spirit::detail::fxn_ptr_table* x_table = - spirit::detail::get_table::get(); + spirit::detail::fxn_ptr_table* x_table = + spirit::detail::get_table::template get(); if (table == x_table) { // if so, we can avoid deallocating and re-use memory table->destruct(&object); // first destruct the old content @@ -292,13 +299,13 @@ namespace boost { namespace spirit // assignment operator template - hold_any& operator=(T const& x) + basic_hold_any& operator=(T const& x) { return assign(x); } // utility functions - hold_any& swap(hold_any& x) + basic_hold_any& swap(basic_hold_any& x) { std::swap(table, x.table); std::swap(object, x.object); @@ -330,7 +337,7 @@ namespace boost { namespace spirit bool empty() const { - return table == spirit::detail::get_table::get(); + return table == spirit::detail::get_table::template get(); } void reset() @@ -338,7 +345,7 @@ namespace boost { namespace spirit if (!empty()) { table->static_delete(&object); - table = spirit::detail::get_table::get(); + table = spirit::detail::get_table::template get(); object = 0; } } @@ -347,31 +354,35 @@ namespace boost { namespace spirit // type has a corresponding operator defined, which is completely safe // because spirit::hold_any is used only in contexts where these operators // do exist - friend std::istream& operator>> (std::istream& i, hold_any& obj) + template + friend inline std::basic_istream& + operator>> (std::basic_istream& i, basic_hold_any& obj) { return obj.table->stream_in(i, &obj.object); } - friend std::ostream& operator<< (std::ostream& o, hold_any const& obj) + template + friend inline std::basic_ostream& + operator<< (std::basic_ostream& o, basic_hold_any const& obj) { return obj.table->stream_out(o, &obj.object); } #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS private: // types - template - friend T* any_cast(hold_any *); + template + friend T* any_cast(basic_hold_any *); #else public: // types (public so any_cast can be non-friend) #endif // fields - spirit::detail::fxn_ptr_table* table; + spirit::detail::fxn_ptr_table* table; void* object; }; // boost::any-like casting - template - inline T* any_cast (hold_any* operand) + template + inline T* any_cast (basic_hold_any* operand) { if (operand && operand->type() == BOOST_SP_TYPEID(T)) { return spirit::detail::get_table::is_small::value ? @@ -381,14 +392,14 @@ namespace boost { namespace spirit return 0; } - template - inline T const* any_cast(hold_any const* operand) + template + inline T const* any_cast(basic_hold_any const* operand) { - return any_cast(const_cast(operand)); + return any_cast(const_cast*>(operand)); } - template - T any_cast(hold_any& operand) + template + T any_cast(basic_hold_any& operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; @@ -408,8 +419,8 @@ namespace boost { namespace spirit return *result; } - template - T const& any_cast(hold_any const& operand) + template + T const& any_cast(basic_hold_any const& operand) { typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; @@ -419,10 +430,23 @@ namespace boost { namespace spirit BOOST_STATIC_ASSERT(!is_reference::value); #endif - return any_cast(const_cast(operand)); + return any_cast(const_cast &>(operand)); + } + + /////////////////////////////////////////////////////////////////////////////// + // backwards compatibility + typedef basic_hold_any hold_any; + typedef basic_hold_any whold_any; + + namespace traits + { + template + struct is_hold_any : mpl::false_ {}; + + template + struct is_hold_any > : mpl::true_ {}; } -/////////////////////////////////////////////////////////////////////////////// }} // namespace boost::spirit /////////////////////////////////////////////////////////////////////////////// diff --git a/include/boost/spirit/home/support/utree/operators.hpp b/include/boost/spirit/home/support/utree/operators.hpp index 63e3d115c..0ae347722 100644 --- a/include/boost/spirit/home/support/utree/operators.hpp +++ b/include/boost/spirit/home/support/utree/operators.hpp @@ -15,6 +15,7 @@ #endif #include +#include #include #include #include diff --git a/include/boost/spirit/home/support/utree/utree_traits.hpp b/include/boost/spirit/home/support/utree/utree_traits.hpp index de964c043..3e3321947 100644 --- a/include/boost/spirit/home/support/utree/utree_traits.hpp +++ b/include/boost/spirit/home/support/utree/utree_traits.hpp @@ -38,6 +38,11 @@ namespace boost } } +namespace boost { namespace spirit { namespace qi +{ + template struct kleene; +}}} + /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { @@ -59,6 +64,11 @@ namespace boost { namespace spirit { namespace traits } return false; } + + inline bool is_uninitialized(utree const& ut) + { + return traits::which(ut) == utree_type::invalid_type; + } } // this specialization tells Spirit how to extract the type of the value @@ -507,8 +517,15 @@ namespace boost { namespace spirit { namespace traits { static void call(utree& ut) { - if (!detail::is_list(ut)) - ut = empty_list; + if (!detail::is_list(ut)) { + if (detail::is_uninitialized(ut)) + ut = empty_list; + else { + utree retval (empty_list); + retval.push_back(ut); + ut.swap(retval); + } + } } }; @@ -644,7 +661,7 @@ namespace boost { namespace spirit { namespace traits // only 'invalid_type' utree nodes are not valid static bool is_valid(utree const& val) { - return traits::which(val) != utree_type::invalid_type; + return !detail::is_uninitialized(val); } }; @@ -943,7 +960,7 @@ namespace boost { namespace spirit { namespace traits } template <> - struct extract_from_attribute + struct extract_from_container { typedef utree::nil_type type; @@ -955,7 +972,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef char type; @@ -968,7 +985,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef bool type; @@ -980,7 +997,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef int type; @@ -992,7 +1009,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef double type; @@ -1004,7 +1021,7 @@ namespace boost { namespace spirit { namespace traits }; template - struct extract_from_attribute > + struct extract_from_container > { typedef std::basic_string type; @@ -1017,7 +1034,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef std::string type; @@ -1030,7 +1047,7 @@ namespace boost { namespace spirit { namespace traits }; template <> - struct extract_from_attribute + struct extract_from_container { typedef std::string type; @@ -1123,7 +1140,10 @@ namespace boost { namespace spirit { namespace traits static type pre(iterator_range const& t) { // return utree the begin iterator points to - return utree(boost::ref(t.front())); + Iterator it = boost::begin(t); + utree result(boost::ref(*it)); + ++it; + return result; } }; diff --git a/test/Jamfile b/test/Jamfile index 6d38de36f..c6a9a01a7 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -194,6 +194,7 @@ import testing ; [ run karma/regression_optional_double.cpp : : : : karma_regression_optional_double ] [ run karma/regression_semantic_action_attribute.cpp : : : : karma_regression_semantic_action_attribute ] [ run karma/regression_real_scientific.cpp : : : : karma_regression_real_scientific ] + [ compile karma/regression_const_real_policies.cpp : : regression_const_real_policies ] ; diff --git a/test/karma/kleene.cpp b/test/karma/kleene.cpp index b1bf4a52d..ec468a72e 100644 --- a/test/karma/kleene.cpp +++ b/test/karma/kleene.cpp @@ -23,6 +23,8 @@ #include #include +#include + #include "test.hpp" using namespace spirit_test; @@ -62,6 +64,57 @@ int main() BOOST_TEST(test_delimited("", *char_, s2, ' ')); } + { + std::string s1("aaaaa"); + BOOST_TEST(test("aaaaa", char_ << *(char_ << char_), s1)); + BOOST_TEST(test_delimited("a a a a a ", + char_ << *(char_ << char_), s1, ' ')); + + s1 = "a"; + BOOST_TEST(test("a", char_ << *(char_ << char_), s1)); + s1 = "aa"; + BOOST_TEST(!test("", char_ << *(char_ << char_), s1)); +// BOOST_TEST(test("aa", char_ << *buffer[char_ << char_] << char_, s1)); + s1 = "aaaa"; + BOOST_TEST(!test("", char_ << *(char_ << char_), s1)); +// BOOST_TEST(test("aaaa", char_ << *buffer[char_ << char_] << char_, s1)); + } + + { + using boost::spirit::karma::strict; + using boost::spirit::karma::relaxed; + using namespace boost::assign; + + typedef std::pair data; + std::vector v1; + v1 += std::make_pair('a', 'a'), + std::make_pair('b', 'b'), + std::make_pair('c', 'c'), + std::make_pair('d', 'd'), + std::make_pair('e', 'e'), + std::make_pair('f', 'f'), + std::make_pair('g', 'g'); + + karma::rule::type, data()> r; + r = &char_('a') << char_; + + BOOST_TEST(test("a", r << *(r << r), v1)); + BOOST_TEST(test("a", relaxed[r << *(r << r)], v1)); + BOOST_TEST(!test("", strict[r << *(r << r)], v1)); + + v1 += std::make_pair('a', 'a'); + + BOOST_TEST(!test("", r << *(r << r), v1)); + BOOST_TEST(!test("", relaxed[r << *(r << r)], v1)); + BOOST_TEST(!test("", strict[r << *(r << r)], v1)); + + v1 += std::make_pair('a', 'a'); + + BOOST_TEST(test("aaa", r << *(r << r), v1)); + BOOST_TEST(test("aaa", relaxed[r << *(r << r)], v1)); + BOOST_TEST(!test("", strict[r << *(r << r)], v1)); + } + { using namespace boost::assign; diff --git a/test/karma/list.cpp b/test/karma/list.cpp index 4d1956d90..1aaab1f92 100644 --- a/test/karma/list.cpp +++ b/test/karma/list.cpp @@ -75,6 +75,13 @@ int main() char_ % ',', s, space)); } + { + std::string s ("abcdefg"); + BOOST_TEST(test("abc,de,fg", char_ << ((char_ << char_) % ','), s)); + BOOST_TEST(test_delimited("a b c , d e , f g ", + char_ << ((char_ << char_) % ','), s, space)); + } + { // actions namespace phx = boost::phoenix; diff --git a/test/karma/lit.cpp b/test/karma/lit.cpp index 34b655418..0b365e882 100644 --- a/test/karma/lit.cpp +++ b/test/karma/lit.cpp @@ -63,6 +63,10 @@ main() BOOST_TEST(test("abc", str)); BOOST_TEST(!test("abcd", str)); + } + + { + using namespace boost::spirit::standard_wide; std::basic_string wstr(L"abc"); BOOST_TEST(test(L"abc", lit(wstr))); diff --git a/test/karma/plus.cpp b/test/karma/plus.cpp index d6a1c8eda..dbd6ab121 100644 --- a/test/karma/plus.cpp +++ b/test/karma/plus.cpp @@ -66,6 +66,55 @@ int main() BOOST_TEST(!test_delimited("", +char_, s3, ' ')); } + { + std::string s1("aaaaa"); + BOOST_TEST(test("aaaaa", char_ << +(char_ << char_), s1)); + BOOST_TEST(test_delimited("a a a a a ", + char_ << +(char_ << char_), s1, ' ')); + + s1 = "a"; + BOOST_TEST(!test("", char_ << +(char_ << char_), s1)); + s1 = "aa"; + BOOST_TEST(!test("", char_ << +(char_ << char_), s1)); + s1 = "aaaa"; + BOOST_TEST(!test("", char_ << +(char_ << char_), s1)); + } + + { + using boost::spirit::karma::strict; + using boost::spirit::karma::relaxed; + using namespace boost::assign; + + typedef std::pair data; + std::vector v1; + v1 += std::make_pair('a', 'a'), + std::make_pair('b', 'b'), + std::make_pair('c', 'c'), + std::make_pair('d', 'd'), + std::make_pair('e', 'e'), + std::make_pair('f', 'f'), + std::make_pair('g', 'g'); + + karma::rule::type, data()> r; + r = &char_('a') << char_; + + BOOST_TEST(!test("", r << +(r << r), v1)); + BOOST_TEST(!test("", relaxed[r << +(r << r)], v1)); + BOOST_TEST(!test("", strict[r << +(r << r)], v1)); + + v1 += std::make_pair('a', 'a'); + + BOOST_TEST(!test("", r << *(r << r), v1)); + BOOST_TEST(!test("", relaxed[r << +(r << r)], v1)); + BOOST_TEST(!test("", strict[r << +(r << r)], v1)); + + v1 += std::make_pair('a', 'a'); + + BOOST_TEST(test("aaa", r << +(r << r), v1)); + BOOST_TEST(test("aaa", relaxed[r << +(r << r)], v1)); + BOOST_TEST(!test("", strict[r << +(r << r)], v1)); + } + { using namespace boost::assign; diff --git a/test/karma/regression_const_real_policies.cpp b/test/karma/regression_const_real_policies.cpp new file mode 100644 index 000000000..122ceea16 --- /dev/null +++ b/test/karma/regression_const_real_policies.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2001-2011 Hartmut Kaiser +// Copyright (c) 2011 Jeroen Habraken +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// compile test verifying it's possible to use const types for real_policies. + +#include + +#include +#include + +int main() +{ + using namespace boost::spirit::karma; + + typedef real_generator > + double_const_type; + + std::string generated; + generate(std::back_inserter(generated), double_const_type(), 1.0); + + return 0; +} diff --git a/test/karma/repeat2.cpp b/test/karma/repeat2.cpp index 03e491808..4453eeab6 100644 --- a/test/karma/repeat2.cpp +++ b/test/karma/repeat2.cpp @@ -49,6 +49,15 @@ int main() BOOST_TEST(test_delimited("A B C D E F G H ", upper[repeat(8)[char_]], str, space)); } +// { +// std::string s1 = "aaaaa"; +// BOOST_TEST(test("aaaaa", char_ << repeat(2)[char_ << char_], s1)); +// s1 = "aaa"; +// BOOST_TEST(test("aaa", char_ << repeat(1, 2)[char_ << char_], s1)); +// s1 = "aa"; +// BOOST_TEST(!test("", char_ << repeat(1)[char_ << char_], s1)); +// } + { // actions namespace phx = boost::phoenix; diff --git a/test/karma/stream.cpp b/test/karma/stream.cpp index 9da58eebe..36ab6e6c4 100644 --- a/test/karma/stream.cpp +++ b/test/karma/stream.cpp @@ -3,13 +3,13 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include #include #include #include #include #include +#include #include #include diff --git a/test/karma/utree2.cpp b/test/karma/utree2.cpp index 0699d4b38..da8473d7d 100644 --- a/test/karma/utree2.cpp +++ b/test/karma/utree2.cpp @@ -62,8 +62,8 @@ int main() rule r1list; r1 = double_ | int_ | r1str | r1list | r1ref; - - r1ref = r1; + + r1ref = r1.alias(); r1str = string; diff --git a/test/karma/wstream.cpp b/test/karma/wstream.cpp index 9da8f10ed..029b9d950 100644 --- a/test/karma/wstream.cpp +++ b/test/karma/wstream.cpp @@ -3,13 +3,13 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include #include #include #include #include #include +#include #include #include diff --git a/test/qi/alternative.cpp b/test/qi/alternative.cpp index a21ee4ae4..f2c0282d0 100644 --- a/test/qi/alternative.cpp +++ b/test/qi/alternative.cpp @@ -216,6 +216,14 @@ main() BOOST_TEST(s == "abc"); } + { + using boost::spirit::qi::int_; + + int i = 0; + BOOST_TEST( (test_attr("10", int_(5) | int_(10), i)) ); + BOOST_TEST(i == 10); + } + return boost::report_errors(); } diff --git a/test/qi/debug.cpp b/test/qi/debug.cpp index 3b359a7fe..f32dacf9e 100644 --- a/test/qi/debug.cpp +++ b/test/qi/debug.cpp @@ -88,7 +88,7 @@ main() BOOST_TEST(test(" a a a a b a b a b a a a b b a ", start, space, false)); } - { // std::contaner attributes + { // std::container attributes typedef boost::fusion::vector fs; rule(), space_type> start; diff --git a/test/qi/kleene.cpp b/test/qi/kleene.cpp index ca0e8cf3c..c49c3eea9 100644 --- a/test/qi/kleene.cpp +++ b/test/qi/kleene.cpp @@ -87,16 +87,10 @@ main() s.clear(); BOOST_TEST(test_attr("b b b b ", *char_, s, space) && s == "bbbb"); - // The following 4 tests show that omit does not inhibit explicit attributes - s.clear(); - BOOST_TEST(test_attr("bbbb", *omit[char_('b')], s) && s == "bbbb"); - + // The following 2 tests show that omit does not inhibit explicit attributes s.clear(); BOOST_TEST(test_attr("bbbb", omit[*char_('b')], s) && s == "bbbb"); - s.clear(); - BOOST_TEST(test_attr("b b b b", *omit[char_('b')], s, space) && s == "bbbb"); - s.clear(); BOOST_TEST(test_attr("b b b b", omit[*char_('b')], s, space) && s == "bbbb"); } diff --git a/test/qi/list.cpp b/test/qi/list.cpp index 32aeb1f89..b0e9886a9 100644 --- a/test/qi/list.cpp +++ b/test/qi/list.cpp @@ -49,6 +49,21 @@ main() std::string s; BOOST_TEST(test_attr("a,b,c,d,e,f,g,h", char_ % ',', s)); BOOST_TEST(s == "abcdefgh"); + + BOOST_TEST(!test("a,b,c,d,e,f,g,h,", char_ % ',')); + } + + { + std::string s; + BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> char_) % ',', s)); + BOOST_TEST(s == "abcdefgh"); + + BOOST_TEST(!test("ab,cd,ef,gh,", (char_ >> char_) % ',')); + BOOST_TEST(!test("ab,cd,ef,g", (char_ >> char_) % ',')); + + s.clear(); + BOOST_TEST(test_attr("ab,cd,efg", (char_ >> char_) % ',' >> char_, s)); + BOOST_TEST(s == "abcdefg"); } { diff --git a/test/qi/optional.cpp b/test/qi/optional.cpp index 1de5afdf8..22855deeb 100644 --- a/test/qi/optional.cpp +++ b/test/qi/optional.cpp @@ -80,6 +80,12 @@ main() BOOST_TEST((n.get() == 1234)); } + { + std::string s; + BOOST_TEST((test_attr("abc", char_ >> -(char_ >> char_), s))); + BOOST_TEST(s == "abc"); + } + { namespace phx = boost::phoenix; diff --git a/test/qi/plus.cpp b/test/qi/plus.cpp index 9f2ba8774..3207d8c30 100644 --- a/test/qi/plus.cpp +++ b/test/qi/plus.cpp @@ -94,17 +94,11 @@ main() } { - // The following 4 tests show that omit does not inhibit explicit attributes + // The following 2 tests show that omit does not inhibit explicit attributes std::string s; - BOOST_TEST(test_attr("bbbb", +omit[char_('b')], s) && s == "bbbb"); - - s.clear(); BOOST_TEST(test_attr("bbbb", omit[+char_('b')], s) && s == "bbbb"); - s.clear(); - BOOST_TEST(test_attr("b b b b ", +omit[char_('b')], s, space) && s == "bbbb"); - s.clear(); BOOST_TEST(test_attr("b b b b ", omit[+char_('b')], s, space) && s == "bbbb"); } diff --git a/test/qi/regression_repeat.cpp b/test/qi/regression_repeat.cpp index 2a96cb335..8db616b9f 100644 --- a/test/qi/regression_repeat.cpp +++ b/test/qi/regression_repeat.cpp @@ -32,12 +32,12 @@ int main() omit[-qi::char_(" \t")]; strrule_type correct_year = repeat(4)[qi::digit]; - test("1776", correct_year | repeat(2)[qi::digit], "1776"); + test("1776", qi::hold[correct_year] | repeat(2)[qi::digit], "1776"); test("76", obsolete_year, "76"); - test("76", obsolete_year | correct_year, "76"); - test(" 76", correct_year | obsolete_year, "76"); - test("76", correct_year | obsolete_year, "76"); - test("76", correct_year | repeat(2)[qi::digit], "76"); + test("76", qi::hold[obsolete_year] | correct_year, "76"); + test(" 76", qi::hold[correct_year] | obsolete_year, "76"); + test("76", qi::hold[correct_year] | obsolete_year, "76"); + test("76", qi::hold[correct_year] | repeat(2)[qi::digit], "76"); return boost::report_errors(); } diff --git a/test/qi/repeat.cpp b/test/qi/repeat.cpp index 531777533..8bd13656e 100644 --- a/test/qi/repeat.cpp +++ b/test/qi/repeat.cpp @@ -77,6 +77,40 @@ main() BOOST_TEST(!test("aa", repeat(3, inf)[char_])); } + { + std::string s; + BOOST_TEST(test_attr("aaaaaaaa", repeat[char_ >> char_], s)); // kleene synonym + BOOST_TEST(s == "aaaaaaaa"); + + s.clear(); + BOOST_TEST(test_attr("aaaaaaaa", repeat(4)[char_ >> char_], s)); + BOOST_TEST(s == "aaaaaaaa"); + + BOOST_TEST(!test("aa", repeat(3)[char_ >> char_])); + BOOST_TEST(!test("a", repeat(1)[char_ >> char_])); + + s.clear(); + BOOST_TEST(test_attr("aa", repeat(1, 3)[char_ >> char_], s)); + BOOST_TEST(s == "aa"); + + s.clear(); + BOOST_TEST(test_attr("aaaaaa", repeat(1, 3)[char_ >> char_], s)); + BOOST_TEST(s == "aaaaaa"); + + BOOST_TEST(!test("aaaaaaa", repeat(1, 3)[char_ >> char_])); + BOOST_TEST(!test("a", repeat(1, 3)[char_ >> char_])); + + s.clear(); + BOOST_TEST(test_attr("aaaa", repeat(2, inf)[char_ >> char_], s)); + BOOST_TEST(s == "aaaa"); + + s.clear(); + BOOST_TEST(test_attr("aaaaaa", repeat(2, inf)[char_ >> char_], s)); + BOOST_TEST(s == "aaaaaa"); + + BOOST_TEST(!test("aa", repeat(2, inf)[char_ >> char_])); + } + { // from classic spirit tests BOOST_TEST(test("", repeat(0, inf)['x'])); @@ -142,16 +176,10 @@ main() s.clear(); BOOST_TEST(test_attr("b b b b", repeat(4)[char_], s, space) && s == "bbbb"); - // The following 4 tests show that omit does not inhibit explicit attributes - s.clear(); - BOOST_TEST(test_attr("bbbb", repeat(4)[omit[char_('b')]], s) && s == "bbbb"); - + // The following 2 tests show that omit does not inhibit explicit attributes s.clear(); BOOST_TEST(test_attr("bbbb", omit[repeat(4)[char_('b')]], s) && s == "bbbb"); - s.clear(); - BOOST_TEST(test_attr("b b b b", repeat(4)[omit[char_('b')]], s, space) && s == "bbbb"); - s.clear(); BOOST_TEST(test_attr("b b b b", omit[repeat(4)[char_('b')]], s, space) && s == "bbbb"); } @@ -166,9 +194,7 @@ main() BOOST_TEST(test_attr("1 2 3", int_ >> repeat(2)[int_], v, space)); BOOST_TEST(v.size() == 3 && v[0] == 1 && v[1] == 2 && v[2] == 3); - v.clear(); - BOOST_TEST(!test_attr("1 2", int_ >> repeat(2)[int_], v, space)); - BOOST_TEST(v.size() == 1 && v[0] == 1); + BOOST_TEST(!test("1 2", int_ >> repeat(2)[int_], space)); } { // actions diff --git a/test/qi/sequence.cpp b/test/qi/sequence.cpp index 25737c6e1..a3ce0f6a7 100644 --- a/test/qi/sequence.cpp +++ b/test/qi/sequence.cpp @@ -172,6 +172,38 @@ main() BOOST_TEST(v[2] == 'c'); } + { // alternative forms of attributes. Allow sequences to take in + // stl containers. + using boost::spirit::qi::hold; + + std::vector v; + BOOST_TEST(test_attr("abc", char_ >> *(char_ >> char_), v)); + BOOST_TEST(v.size() == 3); + BOOST_TEST(v[0] == 'a'); + BOOST_TEST(v[1] == 'b'); + BOOST_TEST(v[2] == 'c'); + + v.clear(); + BOOST_TEST(!test_attr("abcd", char_ >> *(char_ >> char_), v)); + + v.clear(); + BOOST_TEST(test_attr("abcdef", char_ >> *hold[char_ >> char_] >> char_, v)); + BOOST_TEST(v.size() == 6); + BOOST_TEST(v[0] == 'a'); + BOOST_TEST(v[1] == 'b'); + BOOST_TEST(v[2] == 'c'); + BOOST_TEST(v[3] == 'd'); + BOOST_TEST(v[4] == 'e'); + BOOST_TEST(v[5] == 'f'); + + v.clear(); + BOOST_TEST(test_attr("abc", char_ >> +(char_ >> char_), v)); + BOOST_TEST(v.size() == 3); + BOOST_TEST(v[0] == 'a'); + BOOST_TEST(v[1] == 'b'); + BOOST_TEST(v[2] == 'c'); + } + { // alternative forms of attributes. Allow sequences to take in // stl containers. @@ -248,7 +280,6 @@ main() } { // testing "what" - print_info(what(alpha | char_('x') >> lit("hello") >> int_)); } diff --git a/test/qi/utree1.cpp b/test/qi/utree1.cpp index 8a7122d82..19b83e4e7 100644 --- a/test/qi/utree1.cpp +++ b/test/qi/utree1.cpp @@ -165,26 +165,22 @@ int main() BOOST_TEST(test_attr("a25.5b", r1 > r2 >> r3, ut)); BOOST_TEST(ut.which() == utree_type::list_type); - BOOST_TEST(check(ut, "( \"a\" ( ( 25.5 ) ( \"b\" ) ) )")); - // FIXME: "( \"a\" ( 25.5 ) ( \"b\" ) )" + BOOST_TEST(check(ut, "( \"a\" ( 25.5 ) ( \"b\" ) )")); ut.clear(); BOOST_TEST(test_attr("a25.5b", r3 >> r2 > r1, ut)); BOOST_TEST(ut.which() == utree_type::list_type); - BOOST_TEST(check(ut, "( ( ( \"a\" ) ( 25.5 ) ) \"b\" )")); - // FIXME: "( ( \"a\" ) ( 25.5 ) \"b\" )" + BOOST_TEST(check(ut, "( ( \"a\" ) ( 25.5 ) \"b\" )")); ut.clear(); BOOST_TEST(test_attr("a25.5b", char_ > r2 >> r3, ut)); BOOST_TEST(ut.which() == utree_type::list_type); - BOOST_TEST(check(ut, "( \"a\" ( ( 25.5 ) ( \"b\" ) ) )")); - // FIXME: "( \"a\" ( 25.5 ) ( \"b\" ) )" + BOOST_TEST(check(ut, "( \"a\" ( 25.5 ) ( \"b\" ) )")); ut.clear(); BOOST_TEST(test_attr("a25.5b", r3 >> r2 > char_, ut)); BOOST_TEST(ut.which() == utree_type::list_type); - BOOST_TEST(check(ut, "( ( ( \"a\" ) ( 25.5 ) ) \"b\" )")); - // FIXME: "( ( \"a\" ) ( 25.5 ) \"b\" )" + BOOST_TEST(check(ut, "( ( \"a\" ) ( 25.5 ) \"b\" )")); } return boost::report_errors(); diff --git a/test/qi/utree2.cpp b/test/qi/utree2.cpp index e04b5e421..cf8165edd 100644 --- a/test/qi/utree2.cpp +++ b/test/qi/utree2.cpp @@ -86,8 +86,9 @@ int main() ut.which() == utree_type::list_type && check(ut, "( 1.23 4.56 )")); ut.clear(); - rule r1 = - strict_double | int_ | ~char_("()") | ('(' >> *r1 >> ')'); + rule r1; + rule r2 = '(' >> *r1 >> ')'; + r1 = strict_double | int_ | ~char_("()") | r2; BOOST_TEST(test_attr("(x y)", r1, ut, space) && ut.which() == utree_type::list_type && check(ut, "( \"x\" \"y\" )"));