Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r70211 - in trunk: boost/spirit/home/qi/detail boost/spirit/home/qi/operator boost/spirit/home/support boost/spirit/home/support/utree libs/spirit/test/qi
From: hartmut.kaiser_at_[hidden]
Date: 2011-03-19 19:42:11


Author: hkaiser
Date: 2011-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
New Revision: 70211
URL: http://svn.boost.org/trac/boost/changeset/70211

Log:
Spirit: more work on Qi container attributes
Text files modified:
   trunk/boost/spirit/home/qi/detail/pass_container.hpp | 148 ++++++++++++++++++++++++++++-----------
   trunk/boost/spirit/home/qi/operator/sequence_base.hpp | 2
   trunk/boost/spirit/home/support/attributes_fwd.hpp | 4 +
   trunk/boost/spirit/home/support/utree/utree_traits.hpp | 49 ++++++++++--
   trunk/libs/spirit/test/qi/pass_container2.cpp | 94 ++++++++++++++++++++++++-
   trunk/libs/spirit/test/qi/utree1.cpp | 2
   6 files changed, 238 insertions(+), 61 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 2011-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -25,6 +25,15 @@
 
 namespace boost { namespace spirit { namespace qi { namespace detail
 {
+ // Helper meta-function allowing to evaluate weak substitutability and
+ // negate the result if the predicate is not true
+ template <typename Sequence, typename Attribute, typename ValueType>
+ struct negate_weak_substitute_if_not
+ : mpl::if_<
+ Sequence, traits::is_weak_substitute<Attribute, ValueType>
+ , mpl::not_<traits::is_weak_substitute<Attribute, ValueType> > >
+ {};
+
     // 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
@@ -34,9 +43,9 @@
     // 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>
+ , typename Sequence, typename Enable = void>
     struct pass_through_container_base
- : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
+ : negate_weak_substitute_if_not<Sequence, Attribute, ValueType>
     {};
 
     // Specialization for fusion sequences, in this case we check whether all
@@ -45,17 +54,19 @@
     // 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>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence = mpl::true_>
     struct not_compatible_element
       : mpl::and_<
- mpl::not_<traits::is_weak_substitute<Attribute, Container> >
- , mpl::not_<traits::is_weak_substitute<Attribute, ValueType> > >
+ negate_weak_substitute_if_not<Sequence, Attribute, Container>
+ , negate_weak_substitute_if_not<Sequence, 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
+ , typename Sequence
       , bool IsSequence = fusion::traits::is_sequence<ValueType>::value>
     struct pass_through_container_fusion_sequence
     {
@@ -70,16 +81,27 @@
     // 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>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
     struct pass_through_container_fusion_sequence<
- Container, ValueType, Attribute, true>
- : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
- {};
+ Container, ValueType, Attribute, Sequence, true>
+ {
+ typedef typename mpl::find_if<
+ Attribute
+ , not_compatible_element<Container, ValueType, mpl::_1, Sequence>
+ >::type iter;
+ typedef typename mpl::end<Attribute>::type end;
+
+ typedef typename is_same<iter, end>::type type;
+ };
 
- template <typename Container, typename ValueType, typename Attribute>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
     struct pass_through_container_base<Container, ValueType, Attribute
+ , Sequence
           , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
- : pass_through_container_fusion_sequence<Container, ValueType, Attribute>
+ : pass_through_container_fusion_sequence<
+ Container, ValueType, Attribute, Sequence>
     {};
 
     // Specialization for containers
@@ -88,7 +110,7 @@
     // a Fusion sequence, we have to pass through the provided container if
     // both are compatible.
     template <typename Container, typename ValueType, typename Attribute
- , typename AttributeValueType
+ , typename Sequence, typename AttributeValueType
       , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
     struct pass_through_container_container
       : mpl::or_<
@@ -98,26 +120,22 @@
 
     // 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>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence, typename AttributeValueType>
     struct pass_through_container_container<
- Container, ValueType, Attribute, AttributeValueType, true>
+ Container, ValueType, Attribute, Sequence, AttributeValueType, true>
       : pass_through_container_fusion_sequence<
- Container, ValueType, AttributeValueType>
+ Container, ValueType, AttributeValueType, Sequence>
     {};
 
- template <typename Container, typename ValueType, typename Attribute>
- struct pass_through_container_base<Container, ValueType, Attribute
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container_base<
+ Container, ValueType, Attribute, Sequence
           , 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>
+ Container, ValueType, Attribute, Sequence
+ , typename traits::container_value<Attribute>::type>
     {};
 
     // Specialization for exposed optional attributes
@@ -127,6 +145,7 @@
     // either to the optionals embedded type or to the containers value
     // type.
     template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence
       , bool IsSequence = fusion::traits::is_sequence<Attribute>::value>
     struct pass_through_container_optional
       : mpl::or_<
@@ -136,25 +155,38 @@
 
     // 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>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
     struct pass_through_container_optional<
- Container, ValueType, Attribute, true>
+ Container, ValueType, Attribute, Sequence, true>
       : pass_through_container_fusion_sequence<
- Container, ValueType, Attribute>
+ Container, ValueType, Attribute, Sequence>
     {};
 
- template <typename Container, typename ValueType, typename Attribute>
- struct pass_through_container<Container, ValueType, boost::optional<Attribute> >
- : pass_through_container_optional<Container, ValueType, Attribute>
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container
+ : pass_through_container_base<Container, ValueType, Attribute, Sequence>
+ {};
+
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container<
+ Container, ValueType, boost::optional<Attribute>, Sequence>
+ : pass_through_container_optional<
+ Container, ValueType, Attribute, Sequence>
     {};
 
     // 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>
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
     struct pass_through_container<
- Container, boost::optional<ValueType>, boost::optional<Attribute> >
- : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
+ Container, boost::optional<ValueType>, boost::optional<Attribute>
+ , Sequence>
+ : mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >
     {};
 
     // Specialization for exposed variant attributes
@@ -164,24 +196,41 @@
 
 #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \
     pass_through_container<Container, ValueType, \
- BOOST_PP_CAT(T, N)>::type::value || \
+ BOOST_PP_CAT(T, N), Sequence>::type::value || \
     /***/
 
- template <typename Container, typename ValueType
+ template <typename Container, typename ValueType, typename Sequence
       , BOOST_VARIANT_ENUM_PARAMS(typename T)>
     struct pass_through_container<Container, ValueType
- , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+ , boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Sequence>
       : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
           , BOOST_SPIRIT_PASS_THROUGH_CONTAINER, _) false>
     {};
 
 #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER
+}}}}
 
+///////////////////////////////////////////////////////////////////////////////
+namespace boost { namespace spirit { namespace traits
+{
+ ///////////////////////////////////////////////////////////////////////////
+ // forwarding customization point for domain qi::domain
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container<
+ Container, ValueType, Attribute, Sequence, qi::domain>
+ : qi::detail::pass_through_container<
+ Container, ValueType, Attribute, Sequence>
+ {};
+}}}
+
+namespace boost { namespace spirit { namespace qi { namespace detail
+{
     ///////////////////////////////////////////////////////////////////////////
     // 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.
- template <typename F, typename Attr>
+ template <typename F, typename Attr, typename Sequence>
     struct pass_container
     {
         typedef typename F::context_type context_type;
@@ -242,7 +291,8 @@
             // element is a substitute for the value type of the container
             // attribute
             typedef mpl::and_<
- pass_through_container<Attr, value_type, rhs_attribute>
+ traits::pass_through_container<
+ Attr, value_type, rhs_attribute, Sequence, qi::domain>
               , traits::handles_container<
                     Component, Attr, context_type, iterator_type>
> predicate;
@@ -278,12 +328,22 @@
         pass_container& operator= (pass_container const&);
     };
 
- // Utility function to make a pass_container
+ ///////////////////////////////////////////////////////////////////////////
+ // Utility function to make a pass_container for container components
+ // (kleene, list, plus, repeat)
+ template <typename F, typename Attr>
+ inline pass_container<F, Attr, mpl::false_>
+ make_pass_container(F const& f, Attr& attr)
+ {
+ return pass_container<F, Attr, mpl::false_>(f, attr);
+ }
+
+ // Utility function to make a pass_container for sequences
     template <typename F, typename Attr>
- pass_container<F, Attr>
- inline make_pass_container(F const& f, Attr& attr)
+ inline pass_container<F, Attr, mpl::true_>
+ make_sequence_pass_container(F const& f, Attr& attr)
     {
- return pass_container<F, Attr>(f, attr);
+ return pass_container<F, Attr, mpl::true_>(f, attr);
     }
 }}}}
 

Modified: trunk/boost/spirit/home/qi/operator/sequence_base.hpp
==============================================================================
--- trunk/boost/spirit/home/qi/operator/sequence_base.hpp (original)
+++ trunk/boost/spirit/home/qi/operator/sequence_base.hpp 2011-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -104,7 +104,7 @@
             Iterator iter = first;
             // return false if *any* of the parsers fail
             if (fusion::any(elements
- , detail::make_pass_container(
+ , detail::make_sequence_pass_container(
                     Derived::fail_function(iter, last, context, skipper), attr_))
                 )
                 return false;

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-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -215,6 +215,10 @@
             , typename Iterator = unused_type, typename Enable = void>
     struct handles_container;
 
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence, typename Domain, typename Enable = void>
+ struct pass_through_container;
+
     ///////////////////////////////////////////////////////////////////////////
     // Qi only
     template <typename Container, 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-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -586,21 +586,35 @@
     // or a grammar exposes an utree as it's attribute
     namespace detail
     {
- // checks if the attr is the explicit utree list type, utree::list_type
- template <typename Attribute>
- struct attribute_is_not_utree_list
+ // Checks whether the exposed Attribute allows to handle utree or
+ // utree::list_type directly. Returning mpl::false_ from this meta
+ // function will force a new utree instance to be created for each
+ // invocation of the embedded parser.
+ template <typename Attribute, typename Enable = void>
+ struct handles_utree_list_container
           : mpl::and_<
                 mpl::not_<is_same<utree::list_type, Attribute> >,
                 traits::is_container<Attribute> >
         {};
+
+ template <typename Attribute>
+ struct handles_utree_list_container<Attribute
+ , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
+ : mpl::true_
+ {};
+
+ template <typename Attribute>
+ struct handles_utree_list_container<optional<Attribute> >
+ : mpl::true_
+ {};
     }
 
     template <
         typename IteratorA, typename IteratorB, typename Context
       , typename T1, typename T2, typename T3, typename T4>
     struct handles_container<qi::rule<IteratorA, T1, T2, T3, T4>
- , utree, Context, IteratorB>
- : detail::attribute_is_not_utree_list<typename attribute_of<
+ , utree, Context, IteratorB>
+ : detail::handles_utree_list_container<typename attribute_of<
             qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
     {};
@@ -609,8 +623,8 @@
         typename IteratorA, typename IteratorB, typename Context
       , typename T1, typename T2, typename T3, typename T4>
     struct handles_container<qi::grammar<IteratorA, T1, T2, T3, T4>
- , utree, Context, IteratorB>
- : detail::attribute_is_not_utree_list<typename attribute_of<
+ , utree, Context, IteratorB>
+ : detail::handles_utree_list_container<typename attribute_of<
             qi::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
     {};
@@ -619,8 +633,8 @@
         typename IteratorA, typename IteratorB, typename Context
       , typename T1, typename T2, typename T3, typename T4>
     struct handles_container<qi::rule<IteratorA, T1, T2, T3, T4>
- , utree::list_type, Context, IteratorB>
- : detail::attribute_is_not_utree_list<typename attribute_of<
+ , utree::list_type, Context, IteratorB>
+ : detail::handles_utree_list_container<typename attribute_of<
             qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
     {};
@@ -629,13 +643,26 @@
         typename IteratorA, typename IteratorB, typename Context
       , typename T1, typename T2, typename T3, typename T4>
     struct handles_container<qi::grammar<IteratorA, T1, T2, T3, T4>
- , utree::list_type, Context, IteratorB>
- : detail::attribute_is_not_utree_list<typename attribute_of<
+ , utree::list_type, Context, IteratorB>
+ : detail::handles_utree_list_container<typename attribute_of<
             qi::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
     {};
 
     ///////////////////////////////////////////////////////////////////////////
+ template <typename Attribute, typename Sequence>
+ struct pass_through_container<
+ utree, utree, Attribute, Sequence, qi::domain>
+ : detail::handles_utree_list_container<Attribute>
+ {};
+
+ template <typename Attribute, typename Sequence>
+ struct pass_through_container<
+ utree::list_type, utree, Attribute, Sequence, qi::domain>
+ : detail::handles_utree_list_container<Attribute>
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
     namespace detail
     {
         // checks if the attr is utree

Modified: trunk/libs/spirit/test/qi/pass_container2.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/pass_container2.cpp (original)
+++ trunk/libs/spirit/test/qi/pass_container2.cpp 2011-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -19,12 +19,15 @@
 #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/qi_nonterminal.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/adapt_struct.hpp>
 #include <boost/fusion/include/std_pair.hpp>
+#include <boost/fusion/include/vector.hpp>
 
 #include "test.hpp"
 
@@ -35,6 +38,18 @@
     return v.size() == s.size() && std::equal(v.begin(), v.end(), s.begin());
 }
 
+struct A
+{
+ int i1;
+ double d2;
+};
+
+BOOST_FUSION_ADAPT_STRUCT(
+ A,
+ (int, i1)
+ (double, d2)
+)
+
 int main()
 {
     using boost::spirit::qi::char_;
@@ -157,8 +172,82 @@
         s1.clear();
         BOOST_TEST(test_attr("ab1cd2", *(alpha >> alpha | digit), s1) &&
             s1 == "ab1cd2");
+ }
+
+ {
+ using boost::spirit::qi::rule;
+ using boost::spirit::qi::space;
+ using boost::spirit::qi::space_type;
+ using boost::spirit::qi::int_;
+ using boost::spirit::qi::double_;
+
+ std::vector<A> v;
+ BOOST_TEST(test_attr("A 1 2.0", 'A' >> *(int_ >> double_), v, space) &&
+ v.size() == 1 && v[0].i1 == 1 && v[0].d2 == 2.0);
+
+ v.clear();
+ BOOST_TEST(test_attr("1 2.0", *(int_ >> double_), v, space) &&
+ v.size() == 1 && v[0].i1 == 1 && v[0].d2 == 2.0);
+
+ v.clear();
+ rule<char const*, std::vector<A>()> r = *(int_ >> ',' >> double_);
+ BOOST_TEST(test_attr("1,2.0", r, v) &&
+ v.size() == 1 && v[0].i1 == 1 && v[0].d2 == 2.0);
+ }
+
+ {
+ using boost::spirit::qi::rule;
+ using boost::spirit::qi::int_;
+ using boost::spirit::qi::double_;
+
+ rule<char const*, A()> r = int_ >> ',' >> double_;
+ rule<char const*, std::vector<A>()> r2 = 'A' >> *(r >> ',' >> r);
+
+ std::vector<A> v;
+ BOOST_TEST(test_attr("A1,2.0,3,4.0", r2, v) &&
+ v.size() == 2 && v[0].i1 == 1.0 && v[0].d2 == 2.0 &&
+ v[1].i1 == 3.0 && v[1].d2 == 4.0);
+
+ v.clear();
+ BOOST_TEST(test_attr("A1,2.0,3,4.0", 'A' >> *(r >> ',' >> r), v) &&
+ v.size() == 2 && v[0].i1 == 1.0 && v[0].d2 == 2.0 &&
+ v[1].i1 == 3.0 && v[1].d2 == 4.0);
+
+ v.clear();
+ BOOST_TEST(test_attr("1,2.0,3,4.0", *(r >> ',' >> r), v) &&
+ v.size() == 2 && v[0].i1 == 1.0 && v[0].d2 == 2.0 &&
+ v[1].i1 == 3.0 && v[1].d2 == 4.0);
+ }
+
+ {
+ using boost::spirit::qi::rule;
+ using boost::spirit::qi::int_;
+ using boost::spirit::qi::double_;
+ using boost::fusion::at_c;
+
+ typedef boost::fusion::vector<int, double> data_type;
+
+ rule<char const*, data_type()> r = int_ >> ',' >> double_;
+ rule<char const*, std::vector<data_type>()> r2 = 'A' >> *(r >> ',' >> r);
+
+ std::vector<data_type> v;
+ BOOST_TEST(test_attr("A1,2.0,3,4.0", r2, v) &&
+ v.size() == 2 && at_c<0>(v[0]) == 1 && at_c<1>(v[0]) == 2.0 &&
+ at_c<0>(v[1]) == 3 && at_c<1>(v[1]) == 4.0);
+
+ v.clear();
+ BOOST_TEST(test_attr("A1,2.0,3,4.0", 'A' >> *(r >> ',' >> r), v) &&
+ v.size() == 2 && at_c<0>(v[0]) == 1 && at_c<1>(v[0]) == 2.0 &&
+ at_c<0>(v[1]) == 3 && at_c<1>(v[1]) == 4.0);
+
+ v.clear();
+ BOOST_TEST(test_attr("1,2.0,3,4.0", *(r >> ',' >> r), v) &&
+ v.size() == 2 && at_c<0>(v[0]) == 1 && at_c<1>(v[0]) == 2.0 &&
+ at_c<0>(v[1]) == 3 && at_c<1>(v[1]) == 4.0);
+ }
 
 // doesn't work yet
+// {
 // std::vector<std::vector<char> > v2;
 // BOOST_TEST(test_attr("ab1cd123", *(alpha >> alpha | +digit), v2) &&
 // v2.size() == 4 &&
@@ -174,10 +263,7 @@
 // v3[1] == "1" &&
 // v3[2] == "cd" &&
 // v3[3] == "123");
- }
-
- {
- }
+// }
 
     return boost::report_errors();
 }

Modified: trunk/libs/spirit/test/qi/utree1.cpp
==============================================================================
--- trunk/libs/spirit/test/qi/utree1.cpp (original)
+++ trunk/libs/spirit/test/qi/utree1.cpp 2011-03-19 19:42:09 EDT (Sat, 19 Mar 2011)
@@ -8,9 +8,9 @@
 #include <boost/config/warning_disable.hpp>
 #include <boost/detail/lightweight_test.hpp>
 
+#include <boost/mpl/print.hpp>
 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/support_utree.hpp>
-#include <boost/mpl/print.hpp>
 
 #include <sstream>
 


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