|
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