Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r69405 - in trunk: boost/spirit boost/spirit/home/lex/qi boost/spirit/home/qi/detail boost/spirit/home/support boost/spirit/home/support/utree libs/spirit/test libs/spirit/test/qi
From: hartmut.kaiser_at_[hidden]
Date: 2011-02-28 17:43:28


Author: hkaiser
Date: 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
New Revision: 69405
URL: http://svn.boost.org/trac/boost/changeset/69405

Log:
Spirit: fixing container attribute handling of sequences and container parser components
Added:
   trunk/libs/spirit/test/qi/pass_container.cpp (contents, props changed)
Text files modified:
   trunk/boost/spirit/home/lex/qi/state_switcher.hpp | 4
   trunk/boost/spirit/home/qi/detail/alternative_function.hpp | 19 ++
   trunk/boost/spirit/home/qi/detail/pass_container.hpp | 258 +++++++++++++++++++++++----------------
   trunk/boost/spirit/home/support/attributes.hpp | 44 ++++++
   trunk/boost/spirit/home/support/attributes_fwd.hpp | 8 +
   trunk/boost/spirit/home/support/utree/utree_traits.hpp | 22 +++
   trunk/boost/spirit/version.hpp | 4
   trunk/libs/spirit/test/Jamfile | 1
   trunk/libs/spirit/test/qi/alternative.cpp | 10 -
   trunk/libs/spirit/test/qi/list.cpp | 10
   trunk/libs/spirit/test/qi/sequence.cpp | 28 ++-
   trunk/libs/spirit/test/qi/utree3.cpp | 24 +-
   12 files changed, 286 insertions(+), 146 deletions(-)

Modified: trunk/boost/spirit/home/lex/qi/state_switcher.hpp
==============================================================================
--- trunk/boost/spirit/home/lex/qi/state_switcher.hpp (original)
+++ trunk/boost/spirit/home/lex/qi/state_switcher.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -138,13 +138,13 @@
             template <typename State>
             reset_state_on_exit(Iterator& it_, State state_)
               : it(it_)
- , state(detail::set_lexer_state(it_, traits::get_c_string(state_)))
+ , state(set_lexer_state(it_, traits::get_c_string(state_)))
             {}
 
             ~reset_state_on_exit()
             {
                 // reset the state of the underlying lexer instance
- detail::set_lexer_state(it, state);
+ set_lexer_state(it, state);
             }
 
             Iterator& it;

Modified: trunk/boost/spirit/home/qi/detail/alternative_function.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/detail/alternative_function.hpp (original)
+++ trunk/boost/spirit/home/qi/detail/alternative_function.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -114,7 +114,7 @@
         }
 
         template <typename Component>
- bool operator()(Component const& component) const
+ bool call_unused(Component const& component, mpl::true_) const
         {
             // return true if the parser succeeds
             return call(component,
@@ -124,6 +124,23 @@
>());
         }
 
+ template <typename Component>
+ bool call_unused(Component const& component, mpl::false_) const
+ {
+ return component.parse(first, last, context, skipper, unused);
+ }
+
+ template <typename Component>
+ bool operator()(Component const& component) const
+ {
+ // return true if the parser succeeds
+ typedef typename traits::not_is_unused<
+ typename traits::attribute_of<Component, Context, Iterator>::type
+ >::type predicate;
+
+ return call_unused(component, predicate());
+ }
+
         Iterator& first;
         Iterator const& last;
         Context& context;

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 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -25,61 +25,139 @@
 
 namespace boost { namespace spirit { namespace qi { namespace detail
 {
- // has_same_elements: utility to check if the RHS attribute
- // is an STL container and that its value_type is convertible
- // to the LHS.
-
- template <typename LHS, typename RHSAttribute
- , bool IsContainer = traits::is_container<RHSAttribute>::value
- , bool IsSequence = fusion::traits::is_sequence<RHSAttribute>::value>
- struct has_same_elements : mpl::false_ {};
-
- template <typename LHS, typename RHSAttribute>
- struct has_same_elements<LHS, RHSAttribute, true, false>
- : is_convertible<typename RHSAttribute::value_type, LHS> {};
-
- template <typename LHS, typename T>
- struct has_same_elements<LHS, boost::optional<T>, false, false>
- : has_same_elements<LHS, T> {};
-
- template <typename LHS, typename T>
- struct has_same_elements<LHS, boost::optional<T>, true, false>
- : has_same_elements<LHS, T> {};
-
- template <typename LHS, typename T>
- struct has_same_elements<LHS, boost::optional<T>, false, 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, false>
- : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
- , BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
-
-#undef BOOST_SPIRIT_IS_CONVERTIBLE
+ // pass_through_container: utility to check decide whether a provided
+ // container attribute needs to be passed through to the current component
+ // or of we need to split the container by passing along instances of its
+ // value type
+
+ // if the expected attribute of the current component is neither a Fusion
+ // sequence nor a container, we will pass through the provided container
+ // only if its value type is not compatible with the component
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Enable = void>
+ struct pass_through_container_base
+ : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
+ {};
 
     // 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 <typename LHS, typename RHSAttribute>
- struct has_same_elements<LHS, RHSAttribute, false, true>
+ //
+ // We return false if the rhs attribute itself is a fusion sequence, which
+ // is compatible with the LHS sequence (we want to pass through this
+ // attribute without it being split apart).
+ template <typename Container, typename ValueType, typename Attribute>
+ struct not_compatible_element
+ : mpl::and_<
+ mpl::not_<traits::is_weak_substitute<Attribute, Container> >
+ , mpl::not_<traits::is_weak_substitute<Attribute, ValueType> > >
+ {};
+
+ // If the value type of the container is not a Fusion sequence, we pass
+ // through the container if each of the elements of the Attribute
+ // sequence is compatible with either the container or its value type.
+ template <typename Container, typename ValueType, typename Attribute
+ , bool IsSequence = fusion::traits::is_sequence<ValueType>::value>
+ struct pass_through_container_fusion_sequence
     {
         typedef typename mpl::find_if<
- RHSAttribute, mpl::not_<is_convertible<mpl::_1, LHS> >
+ Attribute, not_compatible_element<Container, ValueType, mpl::_1>
>::type iter;
- typedef typename mpl::end<RHSAttribute>::type end;
+ typedef typename mpl::end<Attribute>::type end;
 
- typedef typename mpl::and_<
- mpl::not_<fusion::traits::is_sequence<LHS> >, is_same<iter, end>
- >::type type;
+ typedef typename is_same<iter, end>::type type;
     };
 
+ // If both, the Attribute and the value type of the provided container
+ // are Fusion sequences, we pass the container only if the two
+ // sequences are not compatible.
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container_fusion_sequence<
+ Container, ValueType, Attribute, true>
+ : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
+ {};
+
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container_base<Container, ValueType, Attribute
+ , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
+ : detail::pass_through_container_fusion_sequence<Container, ValueType, Attribute>
+ {};
+
+ // Specialization for containers
+ //
+ // If the value type of the attribute of the current component is not
+ // a Fusion sequence, we have to pass through the provided container if
+ // both are compatible.
+ template <typename Container, typename ValueType, typename Attribute
+ , typename AttributeValueType
+ , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
+ struct pass_through_container_container
+ : mpl::or_<
+ traits::is_weak_substitute<Attribute, Container>
+ , traits::is_weak_substitute<AttributeValueType, Container> >
+ {};
+
+ // If the value type of the exposed container attribute is a Fusion
+ // sequence, we use the already existing logic for those.
+ template <typename Container, typename ValueType
+ , typename Attribute, typename AttributeValueType>
+ struct pass_through_container_container<
+ Container, ValueType, Attribute, AttributeValueType, true>
+ : pass_through_container_fusion_sequence<
+ Container, ValueType, AttributeValueType>
+ {};
+
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container_base<Container, ValueType, Attribute
+ , typename enable_if<traits::is_container<Attribute> >::type>
+ : detail::pass_through_container_container<
+ Container, ValueType
+ , Attribute, typename traits::container_value<Attribute>::type>
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container
+ : pass_through_container_base<Container, ValueType, Attribute>
+ {};
+
+ // Specialization for exposed optional attributes
+ //
+ // If the type embedded in the exposed optional is not a Fusion
+ // sequence we pass through the container attribute if it is compatible
+ // either to the optionals embedded type or to the containrs value
+ // type.
+ template <typename Container, typename ValueType, typename Attribute
+ , bool IsSequence = fusion::traits::is_sequence<Attribute>::value>
+ struct pass_through_container_optional
+ : mpl::or_<
+ traits::is_weak_substitute<Attribute, Container>
+ , traits::is_weak_substitute<Attribute, ValueType> >
+ {};
+
+ // If the embedded type of the exposed optional attribute is a Fusion
+ // sequence, we use the already existing logic for those.
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container_optional<
+ Container, ValueType, Attribute, true>
+ : pass_through_container_fusion_sequence<
+ Container, ValueType, Attribute>
+ {};
+
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container<Container, ValueType, boost::optional<Attribute> >
+ : detail::pass_through_container_optional<Container, ValueType, Attribute>
+ {};
+
+ // If both, the containers value type and the exposed attribute type are
+ // optionals we are allowed to pass through the the container only if the
+ // embedded types of those optionals are not compatible.
+ template <typename Container, typename ValueType, typename Attribute>
+ struct pass_through_container<
+ Container, boost::optional<ValueType>, boost::optional<Attribute> >
+ : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
     // 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.
@@ -95,7 +173,7 @@
         // 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_element(Component const& component, mpl::false_) const
+ bool dispatch_container(Component const& component, mpl::false_) const
         {
             // synthesized attribute needs to be default constructed
             typename traits::container_value<Attr>::type val =
@@ -113,34 +191,16 @@
             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
+ // this is for the case when the current element is able to handle 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
+ bool dispatch_container(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 typename traits::attribute_of<
- Component, context_type, iterator_type>::type attribute_type;
-
- typedef mpl::and_<
- traits::is_container<attribute_type>
- , traits::handles_container<Component, Attr, context_type
- , iterator_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>
@@ -149,31 +209,25 @@
             return f(component, unused);
         }
 
- // This handles the case where the attribute of the component
- // is not an STL container or its element is not convertible
- // to the target attribute's (Attr) value_type.
+ // the current element expects an attribute
         template <typename Component>
- bool dispatch_main(Component const& component, mpl::false_) const
+ bool dispatch_attribute(Component const& component, mpl::true_) const
         {
- // 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 traits::not_is_unused<
- typename traits::attribute_of<
- Component, context_type, iterator_type
- >::type
- > predicate;
+ typedef typename traits::container_value<Attr>::type value_type;
+ typedef typename traits::attribute_of<
+ Component, context_type, iterator_type>::type
+ rhs_attribute;
 
- return dispatch_attribute(component, predicate());
- }
+ // this predicate detects, whether the attribute of the current
+ // element is a substitute for the value type of the container
+ // attribute
+ typedef mpl::and_<
+ pass_through_container<Attr, value_type, rhs_attribute>
+ , traits::handles_container<
+ Component, Attr, context_type, iterator_type>
+ > predicate;
 
- // This handles the case where the attribute of the component is
- // an STL container *and* its value_type is convertible to the
- // target's attribute (Attr) value_type.
- template <typename Component>
- bool dispatch_main(Component const& component, mpl::true_) const
- {
- return f(component, attr);
+ return dispatch_container(component, predicate());
         }
 
         // Dispatches to dispatch_main depending on the attribute type
@@ -181,23 +235,19 @@
         template <typename Component>
         bool operator()(Component const& component) const
         {
- typedef typename traits::container_value<Attr>::type lhs;
- typedef typename traits::attribute_of<
- Component, context_type, iterator_type>::type
- rhs_attribute;
-
- typedef mpl::and_<
- mpl::or_<
- has_same_elements<lhs, rhs_attribute>
- , has_same_elements<Attr, rhs_attribute> >
- , traits::handles_container<Component, Attr, context_type
- , iterator_type>
- > predicate;
+ // we need to dispatch depending on the type of the attribute
+ // of the current element (component). If this is has no attribute
+ // we shouldn't pass an attribute at all.
+ typedef typename traits::not_is_unused<
+ typename traits::attribute_of<
+ Component, context_type, iterator_type
+ >::type
+ >::type predicate;
 
             // ensure the attribute is actually a container type
             traits::make_container(attr);
 
- return dispatch_main(component, predicate());
+ return dispatch_attribute(component, predicate());
         }
 
         F f;

Modified: trunk/boost/spirit/home/support/attributes.hpp
==============================================================================
--- trunk/boost/spirit/home/support/attributes.hpp (original)
+++ trunk/boost/spirit/home/support/attributes.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -58,7 +58,8 @@
     // components.
     ///////////////////////////////////////////////////////////////////////////
 
- // Find out if T can be a substitute for Expected attribute
+ ///////////////////////////////////////////////////////////////////////////
+ // Find out if T can be a (strong) substitute for Expected attribute
     template <typename T, typename Expected, typename Enable /*= void*/>
     struct is_substitute : is_same<T, Expected> {};
 
@@ -96,6 +97,46 @@
>::type>
       : mpl::true_ {};
 
+ ///////////////////////////////////////////////////////////////////////////
+ // Find out if T can be a weak substitute for Expected attribute
+ template <typename T, typename Expected, typename Enable /*= void*/>
+ struct is_weak_substitute : is_convertible<T, Expected> {};
+
+ template <typename T, typename Expected>
+ struct is_weak_substitute<optional<T>, optional<Expected> >
+ : is_weak_substitute<T, Expected> {};
+
+ template <typename T, typename Expected>
+ struct is_weak_substitute<T, Expected,
+ typename enable_if<
+ mpl::and_<
+ fusion::traits::is_sequence<T>,
+ fusion::traits::is_sequence<Expected>,
+ mpl::equal<T, Expected, is_weak_substitute<mpl::_1, mpl::_2> >
+ >
+ >::type>
+ : mpl::true_ {};
+
+ namespace detail
+ {
+ template <typename T, typename Expected>
+ struct value_type_is_weak_substitute
+ : is_weak_substitute<typename T::value_type, typename Expected::value_type>
+ {};
+ }
+
+ template <typename T, typename Expected>
+ struct is_weak_substitute<T, Expected,
+ typename enable_if<
+ mpl::and_<
+ is_container<T>,
+ is_container<Expected>,
+ detail::value_type_is_weak_substitute<T, Expected>
+ >
+ >::type>
+ : mpl::true_ {};
+
+ ///////////////////////////////////////////////////////////////////////////
     template <typename T, typename Enable/* = void*/>
     struct is_proxy : mpl::false_ {};
 
@@ -292,7 +333,6 @@
     template <typename Attribute, typename Enable/* = void*/>
     struct attribute_type : mpl::identity<Attribute> {};
 
-
     ///////////////////////////////////////////////////////////////////////////
     // Retrieve the size of a fusion sequence (compile time)
     ///////////////////////////////////////////////////////////////////////////

Modified: trunk/boost/spirit/home/support/attributes_fwd.hpp
==============================================================================
--- trunk/boost/spirit/home/support/attributes_fwd.hpp (original)
+++ trunk/boost/spirit/home/support/attributes_fwd.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -50,12 +50,18 @@
 namespace boost { namespace spirit { namespace traits
 {
     ///////////////////////////////////////////////////////////////////////////
- // Find out if T can be a substitute for Expected attribute
+ // Find out if T can be a strong substitute for Expected attribute
     ///////////////////////////////////////////////////////////////////////////
     template <typename T, typename Expected, typename Enable = void>
     struct is_substitute;
 
     ///////////////////////////////////////////////////////////////////////////
+ // Find out if T can be a weak substitute for Expected attribute
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename Expected, typename Enable = void>
+ struct is_weak_substitute;
+
+ ///////////////////////////////////////////////////////////////////////////
     // Determine if T is a proxy
     ///////////////////////////////////////////////////////////////////////////
     template <typename T, typename Enable = void>

Modified: trunk/boost/spirit/home/support/utree/utree_traits.hpp
==============================================================================
--- trunk/boost/spirit/home/support/utree/utree_traits.hpp (original)
+++ trunk/boost/spirit/home/support/utree/utree_traits.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -164,6 +164,28 @@
     };
 
     ///////////////////////////////////////////////////////////////////////////
+ // these specializations are needed because utree::value_type == utree
+ template <>
+ struct is_substitute<utree, utree>
+ : mpl::true_
+ {};
+
+ template <>
+ struct is_weak_substitute<utree, utree>
+ : mpl::true_
+ {};
+
+ template <>
+ struct is_substitute<utree::list_type, utree::list_type>
+ : mpl::true_
+ {};
+
+ template <>
+ struct is_weak_substitute<utree::list_type, utree::list_type>
+ : mpl::true_
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
     // this specialization tells Spirit.Qi to allow assignment to an utree from
     // a variant
     namespace detail

Modified: trunk/boost/spirit/version.hpp
==============================================================================
--- trunk/boost/spirit/version.hpp (original)
+++ trunk/boost/spirit/version.hpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -1,6 +1,6 @@
 /*=============================================================================
- Copyright (c) 2001-2010 Joel de Guzman
- Copyright (c) 2001-2010 Hartmut Kaiser
+ Copyright (c) 2001-2011 Joel de Guzman
+ Copyright (c) 2001-2011 Hartmut Kaiser
   http://spirit.sourceforge.net/
 
   Distributed under the Boost Software License, Version 1.0. (See accompanying

Modified: trunk/libs/spirit/test/Jamfile
==============================================================================
--- trunk/libs/spirit/test/Jamfile (original)
+++ trunk/libs/spirit/test/Jamfile 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -66,6 +66,7 @@
      [ run qi/not_predicate.cpp : : : : qi_not_predicate ]
      [ run qi/optional.cpp : : : : qi_optional ]
      [ run qi/parse_attr.cpp : : : : qi_parse_attr ]
+ [ run qi/pass_container.cpp : : : : qi_pass_container ]
      [ run qi/permutation.cpp : : : : qi_permutation ]
      [ run qi/plus.cpp : : : : qi_plus ]
      [ run qi/range_run.cpp : : : : qi_range_run ]

Modified: trunk/libs/spirit/test/qi/alternative.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/alternative.cpp (original)
+++ trunk/libs/spirit/test/qi/alternative.cpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -50,13 +50,8 @@
       , boost::spirit::unused_type
       , boost::spirit::unused_type) const
     {
- using boost::get;
-
         BOOST_TEST(v.size() == 5 &&
- v[1] == 'a' &&
- v[2] == 'b' &&
- v[3] == '1' &&
- v[4] == '2');
+ !v[0] && v[1] == 'a' && v[2] == 'b' && v[3] == '1' && v[4] == '2');
     }
 };
 
@@ -91,8 +86,7 @@
         BOOST_TEST(boost::get<int>(v) == 12345);
 
         BOOST_TEST((test_attr("rock", lit("rock") | int_ | char_, v)));
- BOOST_TEST(boost::get<int>(&v) == 0);
- BOOST_TEST(boost::get<char>(&v) == 0);
+ BOOST_TEST(v.which() == 1);
 
         BOOST_TEST((test_attr("x", lit("rock") | int_ | char_, v)));
         BOOST_TEST(boost::get<char>(v) == 'x');

Modified: trunk/libs/spirit/test/qi/list.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/list.cpp (original)
+++ trunk/libs/spirit/test/qi/list.cpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -90,12 +90,14 @@
     }
 
     {
- std::vector<boost::optional<std::string> > v;
+ std::vector<boost::optional<char> > v;
         BOOST_TEST(test_attr("#a,#", ('#' >> -alpha) % ',', v));
         BOOST_TEST(2 == v.size() &&
- !!v[0] && "a" == boost::get<std::string>(v[0]) &&
- !!v[1] && boost::get<std::string>(v[1]).size() == 1 &&
- boost::get<std::string>(v[1])[0] == '\0');
+ !!v[0] && 'a' == boost::get<char>(v[0]) && !v[1]);
+
+ std::vector<char> v2;
+ BOOST_TEST(test_attr("#a,#", ('#' >> -alpha) % ',', v2));
+ BOOST_TEST(1 == v2.size() && 'a' == v2[0]);
     }
 
     {

Added: trunk/libs/spirit/test/qi/pass_container.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/spirit/test/qi/pass_container.cpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -0,0 +1,291 @@
+// 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)
+
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+
+#include <boost/detail/lightweight_test.hpp>
+
+#include <boost/spirit/include/qi_operator.hpp>
+#include <boost/spirit/include/qi_char.hpp>
+#include <boost/spirit/include/qi_string.hpp>
+#include <boost/spirit/include/qi_numeric.hpp>
+#include <boost/spirit/include/qi_directive.hpp>
+#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_auxiliary.hpp>
+#include <boost/spirit/include/support_argument.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_object.hpp>
+#include <boost/spirit/include/phoenix_stl.hpp>
+#include <boost/fusion/include/std_pair.hpp>
+
+#include <string>
+#include <iostream>
+#include "test.hpp"
+
+using namespace spirit_test;
+
+inline bool compare(std::vector<char> const& v, std::string const& s)
+{
+ return v.size() == s.size() && std::equal(v.begin(), v.end(), s.begin());
+}
+
+int main()
+{
+ using boost::spirit::qi::char_;
+ using boost::spirit::qi::omit;
+
+ {
+ std::vector<char> v;
+ BOOST_TEST(test_attr("a,b,c,d,e,f,g,h", char_ % ',', v) &&
+ compare(v, "abcdefgh"));
+
+ std::string s;
+ BOOST_TEST(test_attr("a,b,c,d,e,f,g,h", char_ % ',', s) &&
+ s == "abcdefgh");
+
+ BOOST_TEST(test("a,b,c,d,e,f,g,h", char_ % ','));
+ BOOST_TEST(test("a,b,c,d,e,f,g,h", omit[char_] % ','));
+ }
+
+ {
+ std::vector<char> v1;
+ BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> char_) % ',', v1) &&
+ compare(v1, "abcdefgh"));
+ v1.clear();
+ BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> omit[char_]) % ',', v1) &&
+ compare(v1, "aceg"));
+
+ std::string s;
+ BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> char_) % ',', s) &&
+ s == "abcdefgh");
+ s.clear();
+ BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> omit[char_]) % ',', s) &&
+ s == "aceg");
+
+ std::vector<std::pair<char, char> > v2;
+ BOOST_TEST(test_attr("ab,cd,ef,gh", (char_ >> char_) % ',', v2) &&
+ v2.size() == 4 &&
+ v2[0] == std::make_pair('a', 'b') &&
+ v2[1] == std::make_pair('c', 'd') &&
+ v2[2] == std::make_pair('e', 'f') &&
+ v2[3] == std::make_pair('g', 'h'));
+
+ s.clear();
+ BOOST_TEST(test_attr("ab,cd,efg", (char_ >> char_) % ',' >> char_, s) &&
+ s == "abcdefg");
+
+ BOOST_TEST(test("ab,cd,ef,gh", (char_ >> char_) % ','));
+ BOOST_TEST(test("ab,cd,ef,gh", (omit[char_ >> char_]) % ','));
+ }
+
+ {
+ std::vector<char> v1;
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> *~char_(',')) % ',', v1) &&
+ compare(v1, "abcdefgh"));
+ v1.clear();
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> omit[*~char_(',')]) % ',', v1) &&
+ compare(v1, "adg"));
+ v1.clear();
+ BOOST_TEST(test_attr("abc,def,gh", (omit[char_] >> *~char_(',')) % ',', v1) &&
+ compare(v1, "bcefh"));
+
+ std::string s1;
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> *~char_(',')) % ',', s1) &&
+ s1 == "abcdefgh");
+ s1.clear();
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> omit[*~char_(',')]) % ',', s1) &&
+ s1 == "adg");
+ s1.clear();
+ BOOST_TEST(test_attr("abc,def,gh", (omit[char_] >> *~char_(',')) % ',', s1) &&
+ s1 == "bcefh");
+
+ std::vector<std::pair<char, std::vector<char> > > v2;
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> *~char_(',')) % ',', v2) &&
+ v2.size() == 3 &&
+ v2[0].first == 'a' && compare(v2[0].second, "bc") &&
+ v2[1].first == 'd' && compare(v2[1].second, "ef") &&
+ v2[2].first == 'g' && compare(v2[2].second, "h"));
+
+ std::vector<std::vector<char> > v3;
+ BOOST_TEST(test_attr("abc,def,gh", (omit[char_] >> *~char_(',')) % ',', v3) &&
+ v3.size() == 3 &&
+ compare(v3[0], "bc") && compare(v3[1], "ef") &&
+ compare(v3[2], "h"));
+
+ std::vector<char> v4;
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> omit[*~char_(',')]) % ',', v4) &&
+ v4.size() == 3 &&
+ v4[0] == 'a' && v4[1] == 'd' && v4[2] == 'g');
+
+ std::vector<std::string> v5;
+ BOOST_TEST(test_attr("abc,def,gh", (omit[char_] >> *~char_(',')) % ',', v5) &&
+ v5.size() == 3 &&
+ v5[0] == "bc" && v5[1] == "ef" && v5[2] == "h");
+
+ std::string s2;
+ BOOST_TEST(test_attr("abc,def,gh", (char_ >> omit[*~char_(',')]) % ',', s2) &&
+ s2.size() == 3 &&
+ s2 == "adg");
+
+ BOOST_TEST(test("abc,def,gh", (char_ >> *~char_(',')) % ','));
+ BOOST_TEST(test("abc,def,gh", (omit[char_ >> *~char_(',')]) % ','));
+ }
+
+ {
+ using boost::spirit::qi::alpha;
+ using boost::spirit::qi::digit;
+
+ std::vector<char> v1;
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> *digit) % ',', v1) &&
+ compare(v1, "ab12cd34ef56"));
+ v1.clear();
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (omit[*alpha] >> *digit) % ',', v1) &&
+ compare(v1, "123456"));
+ v1.clear();
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> omit[*digit]) % ',', v1) &&
+ compare(v1, "abcdef"));
+
+ std::string s1;
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> *digit) % ',', s1) &&
+ s1 == "ab12cd34ef56");
+ s1.clear();
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (omit[*alpha] >> *digit) % ',', s1) &&
+ s1 == "123456");
+ s1.clear();
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> omit[*digit]) % ',', s1) &&
+ s1 == "abcdef");
+
+ std::vector<std::pair<std::vector<char>, std::vector<char> > > v2;
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> *digit) % ',', v2) &&
+ v2.size() == 3 &&
+ compare(v2[0].first, "ab") && compare(v2[0].second, "12") &&
+ compare(v2[1].first, "cd") && compare(v2[1].second, "34") &&
+ compare(v2[2].first, "ef") && compare(v2[2].second, "56"));
+
+ std::vector<std::pair<std::string, std::string> > v3;
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (*alpha >> *digit) % ',', v3) &&
+ v3.size() == 3 &&
+ v3[0].first == "ab" && v3[0].second == "12" &&
+ v3[1].first == "cd" && v3[1].second == "34" &&
+ v3[2].first == "ef" && v3[2].second == "56");
+
+ std::vector<std::vector<char> > v4;
+ BOOST_TEST(test_attr("ab12,cd34,ef56", (omit[*alpha] >> *digit) % ',', v4) &&
+ v4.size() == 3 &&
+ compare(v4[0], "12") &&
+ compare(v4[1], "34") &&
+ compare(v4[2], "56"));
+
+ BOOST_TEST(test("ab12,cd34,ef56", (*alpha >> *digit) % ','));
+ BOOST_TEST(test("ab12,cd34,ef56", omit[*alpha >> *digit] % ','));
+ }
+
+ {
+ std::vector<std::vector<char> > v1;
+ BOOST_TEST(test_attr("abc,def,gh", *~char_(',') % ',', v1) &&
+ v1.size() == 3 &&
+ compare(v1[0], "abc") &&
+ compare(v1[1], "def") &&
+ compare(v1[2], "gh"));
+
+ std::vector<std::string> v2;
+ BOOST_TEST(test_attr("abc,def,gh", *~char_(',') % ',', v2) &&
+ v2.size() == 3 && v2[0] == "abc" && v2[1] == "def" && v2[2] == "gh");
+
+ BOOST_TEST(test("abc,def,gh", *~char_(',') % ','));
+ BOOST_TEST(test("abc,def,gh", omit[*~char_(',')] % ','));
+ }
+
+ {
+ std::vector<char> v1;
+ BOOST_TEST(test_attr("a", char_ >> -(char_ % ','), v1) &&
+ compare(v1, "a"));
+ v1.clear();
+ BOOST_TEST(test_attr("ab,c", char_ >> -(char_ % ','), v1) &&
+ compare(v1, "abc"));
+ v1.clear();
+ BOOST_TEST(test_attr("a", char_ >> -char_, v1) &&
+ compare(v1, "a"));
+ v1.clear();
+ BOOST_TEST(test_attr("ab", char_ >> -char_, v1) &&
+ compare(v1, "ab"));
+
+ std::vector<boost::optional<char> > v2;
+ BOOST_TEST(test_attr("a", char_ >> -char_, v2) &&
+ v2.size() == 2 &&
+ boost::get<char>(v2[0]) == 'a' &&
+ !v2[1]);
+ v2.clear();
+ BOOST_TEST(test_attr("ab", char_ >> -char_, v2) &&
+ v2.size() == 2 &&
+ boost::get<char>(v2[0]) == 'a' &&
+ boost::get<char>(v2[1]) == 'b');
+
+ std::string s;
+ BOOST_TEST(test_attr("a", char_ >> -(char_ % ','), s) &&
+ s == "a");
+ s.clear();
+ BOOST_TEST(test_attr("ab,c", char_ >> -(char_ % ','), s) &&
+ s == "abc");
+ s.clear();
+ BOOST_TEST(test_attr("ab", char_ >> -char_, s) &&
+ s == "ab");
+ s.clear();
+ BOOST_TEST(test_attr("a", char_ >> -char_, s) &&
+ s == "a");
+
+ BOOST_TEST(test("a", char_ >> -(char_ % ',')));
+ BOOST_TEST(test("ab,c", char_ >> -(char_ % ',')));
+ BOOST_TEST(test("a", char_ >> -char_));
+ BOOST_TEST(test("ab", char_ >> -char_));
+ }
+
+ {
+ using boost::spirit::qi::eps;
+
+ std::vector<char> v;
+ BOOST_TEST(test_attr("a", char_ >> ((char_ % ',') | eps), v) &&
+ compare(v, "a"));
+ v.clear();
+ BOOST_TEST(test_attr("ab,c", char_ >> ((char_ % ',') | eps), v) &&
+ compare(v, "abc"));
+
+ std::string s;
+ BOOST_TEST(test_attr("a", char_ >> ((char_ % ',') | eps), s) &&
+ s == "a");
+ s.clear();
+ BOOST_TEST(test_attr("ab,c", char_ >> ((char_ % ',') | eps), s) &&
+ s == "abc");
+
+ BOOST_TEST(test("a", char_ >> ((char_ % ',') | eps)));
+ BOOST_TEST(test("ab,c", char_ >> ((char_ % ',') | eps)));
+ }
+
+ {
+ std::vector<char> v1;
+ BOOST_TEST(test_attr("abc1,abc2",
+ *~char_(',') >> *(',' >> *~char_(',')), v1) &&
+ compare(v1, "abc1abc2"));
+
+ std::vector<std::string> v2;
+ BOOST_TEST(test_attr("abc1,abc2",
+ *~char_(',') >> *(',' >> *~char_(',')), v2) &&
+ v2.size() == 2 &&
+ v2[0] == "abc1" &&
+ v2[1] == "abc2");
+
+ std::string s;
+ BOOST_TEST(test_attr("abc1,abc2",
+ *~char_(',') >> *(',' >> *~char_(',')), s) &&
+ s == "abc1abc2");
+ }
+
+ return boost::report_errors();
+}
+

Modified: trunk/libs/spirit/test/qi/sequence.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/sequence.cpp (original)
+++ trunk/libs/spirit/test/qi/sequence.cpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -234,15 +234,10 @@
     // alternative forms of attributes. Allow sequences to take in
     // stl containers of stl containers.
     {
- // this use case seem1 to verify wrong behavior, but it is correct,
- // think about it!
-
         std::vector<std::string> v;
         BOOST_TEST(test_attr("abc1,abc2",
             *~char_(',') >> *(',' >> *~char_(',')), v));
- BOOST_TEST(v.size() == 8 &&
- v[0] == "a" && v[1] == "b" && v[2] == "c" && v[3] == "1" &&
- v[4] == "a" && v[5] == "b" && v[6] == "c" && v[7] == "2");
+ BOOST_TEST(v.size() == 2 && v[0] == "abc1" && v[1] == "abc2");
     }
 
     {
@@ -279,10 +274,23 @@
         BOOST_TEST(test_attr("ab", char_ >> -char_, v));
         BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b');
 
-// this is still failing
-// v.clear();
-// BOOST_TEST(test_attr("a", char_ >> -char_, v));
-// BOOST_TEST(v.size() == 1 && v[0] == 'a');
+ v.clear();
+ BOOST_TEST(test_attr("a", char_ >> -char_, v));
+ BOOST_TEST(v.size() == 1 && v[0] == 'a');
+
+ v.clear();
+ BOOST_TEST(test_attr("a", char_, v));
+ BOOST_TEST(v.size() == 1 && v[0] == 'a');
+ }
+
+ {
+ std::vector<boost::optional<char> > v;
+ BOOST_TEST(test_attr("ab", char_ >> -char_, v));
+ BOOST_TEST(v.size() == 2 && v[0] == 'a' && v[1] == 'b');
+
+ v.clear();
+ BOOST_TEST(test_attr("a", char_ >> -char_, v));
+ BOOST_TEST(v.size() == 2 && v[0] == 'a' && !v[1]);
 
         v.clear();
         BOOST_TEST(test_attr("a", char_, v));

Modified: trunk/libs/spirit/test/qi/utree3.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/utree3.cpp (original)
+++ trunk/libs/spirit/test/qi/utree3.cpp 2011-02-28 17:43:13 EST (Mon, 28 Feb 2011)
@@ -78,7 +78,7 @@
         ut.clear();
         BOOST_TEST(test_attr("10.2", r2, ut) &&
             ut.which() == utree_type::double_type && check(ut, "10.2"));
-
+
         rule<char const*, utree::list_type()> r3 = strict_double | int_;
         ut.clear();
         BOOST_TEST(test_attr("10", r3, ut) &&
@@ -109,9 +109,9 @@
 
         BOOST_TEST(test_attr("1", int_ >> -char_, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
- BOOST_TEST(check(ut, "( 1 <invalid> )"));
+ BOOST_TEST(check(ut, "( 1 )"));
         ut.clear();
-
+
         BOOST_TEST(test_attr("1x", -int_ >> char_, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
         BOOST_TEST(check(ut, "( 1 \"x\" )"));
@@ -119,23 +119,23 @@
 
         BOOST_TEST(test_attr("x", -int_ >> char_, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
- BOOST_TEST(check(ut, "( <invalid> \"x\" )"));
+ BOOST_TEST(check(ut, "( \"x\" )"));
         ut.clear();
 
         rule<char const*, utree::list_type()> r1 = int_ >> -char_;
-
+
         BOOST_TEST(test_attr("1x", r1, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
         BOOST_TEST(check(ut, "( 1 \"x\" )"));
         ut.clear();
-
+
         BOOST_TEST(test_attr("1", r1, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
- BOOST_TEST(check(ut, "( 1 <invalid> )"));
+ BOOST_TEST(check(ut, "( 1 )"));
         ut.clear();
-
+
         rule<char const*, utree::list_type()> r2 = -int_ >> char_;
-
+
         BOOST_TEST(test_attr("1x", r2, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
         BOOST_TEST(check(ut, "( 1 \"x\" )"));
@@ -143,11 +143,11 @@
 
         BOOST_TEST(test_attr("x", r2, ut));
         BOOST_TEST(ut.which() == utree_type::list_type);
- BOOST_TEST(check(ut, "( <invalid> \"x\" )"));
+ BOOST_TEST(check(ut, "( \"x\" )"));
         ut.clear();
-
+
         rule<char const*, utree()> r3 = int_;
-
+
         BOOST_TEST(test_attr("1", -r3, ut));
         BOOST_TEST(ut.which() == utree_type::int_type);
         BOOST_TEST(check(ut, "1"));


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