Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r53609 - in trunk: boost/spirit/home/qi/detail libs/spirit/test/qi
From: hartmut.kaiser_at_[hidden]
Date: 2009-06-03 18:41:37


Author: hkaiser
Date: 2009-06-03 18:41:36 EDT (Wed, 03 Jun 2009)
New Revision: 53609
URL: http://svn.boost.org/trac/boost/changeset/53609

Log:
Spirit: fixed a problem in attribute handling for Qi sequences taking a std container as its attribute, added corresponding tests
Text files modified:
   trunk/boost/spirit/home/qi/detail/pass_container.hpp | 50 ++++++++++++++++++++++++++++++++++++----
   trunk/libs/spirit/test/qi/alternative.cpp | 26 ++++++++++++++++++++
   2 files changed, 71 insertions(+), 5 deletions(-)

Modified: trunk/boost/spirit/home/qi/detail/pass_container.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/detail/pass_container.hpp (original)
+++ trunk/boost/spirit/home/qi/detail/pass_container.hpp 2009-06-03 18:41:36 EDT (Wed, 03 Jun 2009)
@@ -29,9 +29,25 @@
 
     template <typename LHS, typename RHSAttribute>
     struct has_same_elements<LHS, RHSAttribute, true>
- : is_convertible<
- typename RHSAttribute::value_type
- , LHS> {};
+ : is_convertible<typename RHSAttribute::value_type, LHS> {};
+
+ template <typename LHS, typename T>
+ struct has_same_elements<LHS, optional<T>, true>
+ : has_same_elements<LHS, T> {};
+
+#define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \
+ has_same_elements<LHS, BOOST_PP_CAT(T, N)>::value || \
+ /***/
+
+ // Note: variants are treated as containers if one of the held types is a
+ // container (see support/container.hpp).
+ template <typename LHS, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+ struct has_same_elements<
+ LHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true>
+ : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
+ , BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
+
+#undef BOOST_SPIRIT_IS_CONVERTIBLE
 
     // This function handles the case where the attribute (Attr) given
     // the sequence is an STL container. This is a wrapper around F.
@@ -39,13 +55,15 @@
     template <typename F, typename Attr>
     struct pass_container
     {
+ typedef typename F::context_type context_type;
+
         pass_container(F const& f, Attr& attr)
           : f(f), attr(attr) {}
 
         // this is for the case when the current element exposes an attribute
         // which is pushed back onto the container
         template <typename Component>
- bool dispatch_attribute(Component const& component, mpl::true_) const
+ bool dispatch_attribute_element(Component const& component, mpl::false_) const
         {
             typename traits::result_of::value<Attr>::type val;
             bool r = f(component, val);
@@ -57,6 +75,29 @@
             return r;
         }
 
+ // this is for the case when the current element expects an attribute
+ // which is a container itself, this element will push its data
+ // directly into the attribute container
+ template <typename Component>
+ bool dispatch_attribute_element(Component const& component, mpl::true_) const
+ {
+ return f(component, attr);
+ }
+
+ // This handles the distinction between elements in a sequence expecting
+ // containers themselves and elements expecting non-containers as their
+ // attribute. Note: is_container treats optional<T>, where T is a
+ // container as a container as well.
+ template <typename Component>
+ bool dispatch_attribute(Component const& component, mpl::true_) const
+ {
+ typedef traits::is_container<
+ typename traits::attribute_of<Component, context_type>::type
+ > predicate;
+
+ return dispatch_attribute_element(component, predicate());
+ }
+
         // this is for the case when the current element doesn't expect an
         // attribute
         template <typename Component>
@@ -74,7 +115,6 @@
             // we need to dispatch again depending on the type of the attribute
             // of the current element (component). If this is has no attribute
             // we shouldn't push an element into the container.
- typedef typename F::context_type context_type;
             typedef traits::is_not_unused<
                 typename traits::attribute_of<Component, context_type>::type
> predicate;

Modified: trunk/libs/spirit/test/qi/alternative.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/alternative.cpp (original)
+++ trunk/libs/spirit/test/qi/alternative.cpp 2009-06-03 18:41:36 EDT (Wed, 03 Jun 2009)
@@ -165,6 +165,32 @@
         BOOST_TEST( (test("abcab12", lexeme[*("abc" | alnum)][test_action_2()])) );
     }
 
+ {
+ using boost::spirit::qi::eps;
+
+ // testing a sequence taking a container as attribute
+ std::string s;
+ BOOST_TEST( (test_attr("abc,a,b,c",
+ char_ >> char_ >> (char_ % ','), s )) );
+ BOOST_TEST(s == "abcabc");
+
+ // test having an optional<container> inside a sequence
+ s.erase();
+ BOOST_TEST( (test_attr("ab",
+ char_ >> char_ >> -(char_ % ','), s )) );
+ BOOST_TEST(s == "ab");
+
+ // test having an variant<container, ...> inside a sequence
+ s.erase();
+ BOOST_TEST( (test_attr("ab",
+ char_ >> char_ >> ((char_ % ',') | eps), s )) );
+ BOOST_TEST(s == "ab");
+ s.erase();
+ BOOST_TEST( (test_attr("abc",
+ char_ >> char_ >> ((char_ % ',') | eps), s )) );
+ BOOST_TEST(s == "abc");
+ }
+
     return boost::report_errors();
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk