$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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();
 }