|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r70224 - in trunk/boost/spirit/home: karma/detail karma/directive karma/operator qi/detail support/utree
From: hartmut.kaiser_at_[hidden]
Date: 2011-03-20 14:23:50
Author: hkaiser
Date: 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
New Revision: 70224
URL: http://svn.boost.org/trac/boost/changeset/70224
Log:
Spirit: new container attribute handling for Karma, aligned with latest changes to Qi, minor tweaks to attribute handling in Qi, added comments, etc.
Text files modified:
trunk/boost/spirit/home/karma/detail/pass_container.hpp | 347 ++++++++++++++++++++++++++-------------
trunk/boost/spirit/home/karma/directive/repeat.hpp | 2
trunk/boost/spirit/home/karma/operator/kleene.hpp | 2
trunk/boost/spirit/home/karma/operator/list.hpp | 2
trunk/boost/spirit/home/karma/operator/plus.hpp | 2
trunk/boost/spirit/home/karma/operator/sequence.hpp | 2
trunk/boost/spirit/home/qi/detail/pass_container.hpp | 21 +-
trunk/boost/spirit/home/support/utree/utree_traits.hpp | 76 +++++---
8 files changed, 289 insertions(+), 165 deletions(-)
Modified: trunk/boost/spirit/home/karma/detail/pass_container.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/detail/pass_container.hpp (original)
+++ trunk/boost/spirit/home/karma/detail/pass_container.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -24,70 +24,222 @@
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/range/iterator_range.hpp>
+#include <boost/fusion/include/deduce_sequence.hpp>
+
+#include <boost/mpl/print.hpp>
namespace boost { namespace spirit { namespace karma { namespace detail
{
- // has_same_elements: utility to check if the LHS attribute
- // is an STL container and that its value_type is convertible
- // to the RHS.
-
- template <typename RHS, typename LHSAttribute
- , bool IsContainer = traits::is_container<LHSAttribute>::value
- , bool IsSequence = fusion::traits::is_sequence<LHSAttribute>::value>
- struct has_same_elements : mpl::false_ {};
-
- template <typename RHS, typename LHSAttribute>
- struct has_same_elements<RHS, LHSAttribute, true, false>
- : mpl::or_<
- is_convertible<RHS, typename LHSAttribute::value_type>
- , traits::is_hold_any<typename LHSAttribute::value_type>
- > {};
-
- template <typename RHS, typename T>
- struct has_same_elements<RHS, boost::optional<T>, false, false>
- : has_same_elements<RHS, T> {};
-
- template <typename RHS, typename T>
- struct has_same_elements<RHS, boost::optional<T>, true, false>
- : has_same_elements<RHS, T> {};
-
- template <typename RHS, typename T>
- struct has_same_elements<RHS, boost::optional<T>, false, true>
- : has_same_elements<RHS, T> {};
-
-#define BOOST_SPIRIT_IS_CONVERTIBLE(z, N, data) \
- has_same_elements<RHS, 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 RHS, BOOST_VARIANT_ENUM_PARAMS(typename T)>
- struct has_same_elements<
- RHS, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, true, false>
- : mpl::bool_<BOOST_PP_REPEAT(BOOST_VARIANT_LIMIT_TYPES
- , BOOST_SPIRIT_IS_CONVERTIBLE, _) false> {};
+ // Helper meta-function allowing to evaluate weak substitutability and
+ // negate the result if the predicate (Sequence) is not true
+ template <typename Sequence, typename Attribute, typename ValueType>
+ struct negate_weak_substitute_if_not
+ : mpl::if_<
+ Sequence
+ , typename traits::is_weak_substitute<Attribute, ValueType>::type
+ , typename mpl::not_<
+ traits::is_weak_substitute<Attribute, ValueType>
+ >::type>
+ {};
+
+ // 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 Sequence, typename Enable = void>
+ struct pass_through_container_base
+ : negate_weak_substitute_if_not<Sequence, ValueType, Attribute>
+ {};
+
+ // 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 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
+ , typename Sequence = mpl::true_>
+ struct not_compatible_element
+ : mpl::and_<
+ negate_weak_substitute_if_not<Sequence, Container, Attribute>
+ , negate_weak_substitute_if_not<Sequence, ValueType, Attribute> >
+ {};
+
+ // 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
+ {
+ typedef typename mpl::find_if<
+ Attribute, not_compatible_element<Container, ValueType, mpl::_1>
+ >::type iter;
+ typedef typename mpl::end<Attribute>::type end;
-#undef BOOST_SPIRIT_IS_CONVERTIBLE
+ typedef typename is_same<iter, end>::type type;
+ };
- // Specialization for fusion sequences, in this case we check whether the
- // lhs attribute is convertible to the types in the sequence.
- // We return false if the rhs attribute itself is a fusion sequence.
- template <typename RHS, typename LHSAttribute>
- struct has_same_elements<RHS, LHSAttribute, false, true>
+ // 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
+ , typename Sequence>
+ struct pass_through_container_fusion_sequence<
+ Container, ValueType, Attribute, Sequence, true>
{
typedef typename mpl::find_if<
- LHSAttribute, mpl::not_<is_convertible<RHS, mpl::_1> >
+ Attribute
+ , not_compatible_element<Container, ValueType, mpl::_1, Sequence>
>::type iter;
- typedef typename mpl::end<LHSAttribute>::type end;
+ typedef typename mpl::end<Attribute>::type end;
typedef typename is_same<iter, end>::type type;
};
+ 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, Sequence>
+ {};
+
+ // 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 Sequence, typename AttributeValueType
+ , bool IsSequence = fusion::traits::is_sequence<AttributeValueType>::value>
+ struct pass_through_container_container
+ : mpl::or_<
+ traits::is_weak_substitute<Container, Attribute>
+ , traits::is_weak_substitute<Container, AttributeValueType> >
+ {};
+
+ // 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 Sequence, typename AttributeValueType>
+ struct pass_through_container_container<
+ Container, ValueType, Attribute, Sequence, AttributeValueType, true>
+ : pass_through_container_fusion_sequence<
+ Container, ValueType, AttributeValueType, Sequence>
+ {};
+
+ 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, Sequence
+ , typename traits::container_value<Attribute>::type>
+ {};
+
+ // 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 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_<
+ traits::is_weak_substitute<Container, Attribute>
+ , traits::is_weak_substitute<ValueType, Attribute> >
+ {};
+
+ // 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
+ , typename Sequence>
+ struct pass_through_container_optional<
+ Container, ValueType, Attribute, Sequence, true>
+ : pass_through_container_fusion_sequence<
+ Container, ValueType, Attribute, Sequence>
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container
+ : pass_through_container_base<Container, ValueType, Attribute, Sequence>
+ {};
+
+ // Handle optional attributes
+ 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
+ , typename Sequence>
+ struct pass_through_container<
+ Container, boost::optional<ValueType>, boost::optional<Attribute>
+ , Sequence>
+ : mpl::not_<traits::is_weak_substitute<ValueType, Attribute> >
+ {};
+
+ // Specialization for exposed variant attributes
+ //
+ // We pass through the container attribute if at least one of the embedded
+ // types in the variant requires to pass through the attribute
+
+#define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \
+ pass_through_container<Container, ValueType, \
+ BOOST_PP_CAT(T, N), Sequence>::type::value || \
+ /***/
+
+ 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)>, 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 karma::domain
+ template <typename Container, typename ValueType, typename Attribute
+ , typename Sequence>
+ struct pass_through_container<
+ Container, ValueType, Attribute, Sequence, karma::domain>
+ : karma::detail::pass_through_container<
+ Container, ValueType, Attribute, Sequence>
+ {};
+}}}
+
+namespace boost { namespace spirit { namespace karma { namespace detail
+{
///////////////////////////////////////////////////////////////////////////
// This function handles the case where the attribute (Attr) given
// to the sequence is an STL container. This is a wrapper around F.
// The function F does the actual generating.
- template <typename F, typename Attr, typename Iterator, typename Strict>
+ template <typename F, typename Attr, typename Iterator, typename Sequence>
struct pass_container
{
typedef typename F::context_type context_type;
@@ -109,7 +261,7 @@
// this is for the case when the current element expects an attribute
// which is taken from the next entry in the container
template <typename Component>
- bool dispatch_attribute_element(Component const& component, mpl::false_) const
+ bool dispatch_container(Component const& component, mpl::false_) const
{
// get the next value to generate from container
if (!is_at_end() && !f(component, traits::deref(iter)))
@@ -119,46 +271,20 @@
return false;
}
-// // in non-strict mode increment iterator if the underlying
-// // generator failed
-// if (!Strict::value && !is_at_end())
-// traits::next(iter);
-
// either no elements available any more or generation failed
return true;
}
- // This is for the case when the current element expects an attribute
- // which is a container itself, this element will get the rest of 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, make_iterator_range(iter, end));
}
- // 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>::type attribute_type;
-
-// typedef mpl::and_<
-// traits::is_container<attribute_type>
-// , is_convertible<Attr, attribute_type> > predicate;
-
- typedef mpl::and_<
- traits::is_container<attribute_type>
- , traits::handles_container<Component, Attr, context_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>
@@ -167,30 +293,25 @@
return f(component, unused);
}
- // This handles the case where the attribute of the component
- // is not a STL container or which elements are not
- // convertible to the target attribute (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 use an element of the container but unused_type
- // instead
- typedef traits::not_is_unused<
- typename traits::attribute_of<Component, context_type>::type
+ typedef typename traits::container_value<Attr>::type value_type;
+ typedef typename
+ traits::attribute_of<Component, context_type>::type
+ lhs_attribute;
+
+ // this predicate detects, whether the value type of the container
+ // attribute is a substitute for the attribute of the current
+ // element
+ typedef mpl::and_<
+ traits::handles_container<Component, Attr, context_type>
+ , traits::pass_through_container<
+ Attr, value_type, lhs_attribute, Sequence, karma::domain>
> predicate;
- return dispatch_attribute(component, predicate());
- }
-
- // This handles the case where the attribute of the component is
- // an STL container *and* its value_type is convertible to the
- // target attribute's (Attr) value_type.
- template <typename Component>
- bool dispatch_main(Component const& component, mpl::true_) const
- {
- return f(component, make_iterator_range(iter, end));
+ return dispatch_container(component, predicate());
}
// Dispatches to dispatch_main depending on the attribute type
@@ -198,19 +319,15 @@
template <typename Component>
bool operator()(Component const& component) const
{
- typedef typename traits::container_value<Attr>::type rhs;
- typedef typename traits::attribute_of<
- Component, context_type>::type lhs_attribute;
-
- typedef mpl::and_<
- mpl::or_<
- has_same_elements<rhs, lhs_attribute>
- , has_same_elements<Attr, lhs_attribute> >
- , traits::handles_container<Component, Attr, context_type>
+ // 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 use an element of the container but unused_type
+ // instead
+ typedef traits::not_is_unused<
+ typename traits::attribute_of<Component, context_type>::type
> predicate;
- // false means everything went ok
- return dispatch_main(component, predicate());
+ return dispatch_attribute(component, predicate());
}
F f;
@@ -221,14 +338,6 @@
// silence MSVC warning C4512: assignment operator could not be generated
pass_container& operator= (pass_container const&);
};
-
- // Utility function to make a pass_container
- template <typename Strict, typename F, typename Attr, typename Iterator>
- pass_container<F, Attr, Iterator, Strict>
- inline make_pass_container(F const& f, Attr& attr, Iterator b, Iterator e)
- {
- return pass_container<F, Attr, Iterator, Strict>(f, attr, b, e);
- }
}}}}
#endif
Modified: trunk/boost/spirit/home/karma/directive/repeat.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/directive/repeat.hpp (original)
+++ trunk/boost/spirit/home/karma/directive/repeat.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -211,7 +211,7 @@
indirect_iterator_type;
typedef detail::pass_container<
- fail_function, Attribute, indirect_iterator_type, Strict>
+ fail_function, Attribute, indirect_iterator_type, mpl::false_>
pass_container;
iterator_type it = traits::begin(attr);
Modified: trunk/boost/spirit/home/karma/operator/kleene.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/kleene.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/kleene.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -111,7 +111,7 @@
typename traits::make_indirect_iterator<iterator_type>::type
indirect_iterator_type;
typedef detail::pass_container<
- fail_function, Attribute, indirect_iterator_type, Strict>
+ fail_function, Attribute, indirect_iterator_type, mpl::false_>
pass_container;
iterator_type it = traits::begin(attr);
Modified: trunk/boost/spirit/home/karma/operator/list.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/list.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/list.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -117,7 +117,7 @@
typename traits::make_indirect_iterator<iterator_type>::type
indirect_iterator_type;
typedef detail::pass_container<
- fail_function, Attribute, indirect_iterator_type, Strict>
+ fail_function, Attribute, indirect_iterator_type, mpl::false_>
pass_container;
iterator_type it = traits::begin(attr);
Modified: trunk/boost/spirit/home/karma/operator/plus.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/plus.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/plus.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -123,7 +123,7 @@
typename traits::make_indirect_iterator<iterator_type>::type
indirect_iterator_type;
typedef detail::pass_container<
- fail_function, Attribute, indirect_iterator_type, Strict>
+ fail_function, Attribute, indirect_iterator_type, mpl::false_>
pass_container;
iterator_type it = traits::begin(attr);
Modified: trunk/boost/spirit/home/karma/operator/sequence.hpp
==============================================================================
--- trunk/boost/spirit/home/karma/operator/sequence.hpp (original)
+++ trunk/boost/spirit/home/karma/operator/sequence.hpp 2011-03-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -185,7 +185,7 @@
typename traits::make_indirect_iterator<iterator_type>::type
indirect_iterator_type;
typedef detail::pass_container<
- fail_function, Attribute, indirect_iterator_type, Strict>
+ fail_function, Attribute, indirect_iterator_type, mpl::true_>
pass_container;
iterator_type begin = traits::begin(attr_);
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-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -26,13 +26,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
+ // negate the result if the predicate (Sequence) is not true
template <typename Sequence, typename Attribute, typename ValueType>
struct negate_weak_substitute_if_not
: mpl::if_<
Sequence
, typename traits::is_weak_substitute<Attribute, ValueType>::type
- , typename mpl::not_<traits::is_weak_substitute<Attribute, ValueType> >::type>
+ , typename mpl::not_<
+ traits::is_weak_substitute<Attribute, ValueType>
+ >::type>
{};
// pass_through_container: utility to check decide whether a provided
@@ -115,8 +117,8 @@
, 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> >
+ traits::is_weak_substitute<Attribute, Container>
+ , traits::is_weak_substitute<AttributeValueType, Container> >
{};
// If the value type of the exposed container attribute is a Fusion
@@ -150,8 +152,8 @@
, 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> >
+ traits::is_weak_substitute<Attribute, Container>
+ , traits::is_weak_substitute<Attribute, ValueType> >
{};
// If the embedded type of the exposed optional attribute is a Fusion
@@ -171,6 +173,7 @@
: pass_through_container_base<Container, ValueType, Attribute, Sequence>
{};
+ // Handle optional attributes
template <typename Container, typename ValueType, typename Attribute
, typename Sequence>
struct pass_through_container<
@@ -292,10 +295,10 @@
// element is a substitute for the value type of the container
// attribute
typedef mpl::and_<
- traits::pass_through_container<
- Attr, value_type, rhs_attribute, Sequence, qi::domain>
- , traits::handles_container<
+ traits::handles_container<
Component, Attr, context_type, iterator_type>
+ , traits::pass_through_container<
+ Attr, value_type, rhs_attribute, Sequence, qi::domain>
> predicate;
return dispatch_container(component, predicate());
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-20 14:23:49 EDT (Sun, 20 Mar 2011)
@@ -38,11 +38,6 @@
}
}
-namespace boost { namespace spirit { namespace qi
-{
- template <typename Subject> struct kleene;
-}}}
-
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace traits
{
@@ -590,6 +585,9 @@
// 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.
+
+ // The purpose of using utree::list_type as an attribute is to force a
+ // new sub-node in the result.
template <typename Attribute, typename Enable = void>
struct handles_utree_list_container
: mpl::and_<
@@ -597,6 +595,9 @@
traits::is_container<Attribute> >
{};
+ // The following specializations make sure that the actual handling of
+ // an utree (or utree::list_type) attribute is deferred to the embedded
+ // parsers of a sequence, alternative or optional component.
template <typename Attribute>
struct handles_utree_list_container<Attribute
, typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
@@ -671,13 +672,39 @@
///////////////////////////////////////////////////////////////////////////
namespace detail
{
- // checks if the attr is utree
- template <typename Attribute>
- struct attribute_is_not_utree
+ // 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.
+
+ // The purpose of using utree::list_type as an attribute is to force a
+ // new sub-node in the result.
+ template <typename Attribute, typename Enable = void>
+ struct handles_utree_container
: mpl::and_<
mpl::not_<is_same<utree, Attribute> >,
traits::is_container<Attribute> >
{};
+
+ // The following specializations make sure that the actual handling of
+ // an utree (or utree::list_type) attribute is deferred to the embedded
+ // parsers of a sequence, alternative or optional component.
+ template <typename Attribute>
+ struct handles_utree_container<Attribute
+ , typename enable_if<fusion::traits::is_sequence<Attribute> >::type>
+ : mpl::true_
+ {};
+
+ template <typename Attribute>
+ struct handles_utree_container<boost::optional<Attribute> >
+ : mpl::true_
+ {};
+
+ template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+ struct handles_utree_container<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+ : mpl::true_
+ {};
}
template <
@@ -685,7 +712,7 @@
, typename T1, typename T2, typename T3, typename T4>
struct handles_container<karma::rule<IteratorA, T1, T2, T3, T4>
, utree, Context, IteratorB>
- : detail::attribute_is_not_utree<typename attribute_of<
+ : detail::handles_utree_container<typename attribute_of<
karma::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
{};
@@ -695,12 +722,19 @@
, typename T1, typename T2, typename T3, typename T4>
struct handles_container<karma::grammar<IteratorA, T1, T2, T3, T4>
, utree, Context, IteratorB>
- : detail::attribute_is_not_utree<typename attribute_of<
+ : detail::handles_utree_container<typename attribute_of<
karma::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB
>::type>
{};
///////////////////////////////////////////////////////////////////////////
+ template <typename Attribute, typename Sequence>
+ struct pass_through_container<
+ utree, utree, Attribute, Sequence, karma::domain>
+ : detail::handles_utree_container<Attribute>
+ {};
+
+ ///////////////////////////////////////////////////////////////////////////
// the specialization below tells Spirit how to handle utree if it is used
// with an optional component
template <>
@@ -1231,28 +1265,6 @@
struct transform_attribute<utree::list_type const, Attribute, karma::domain>
: transform_attribute<utree const, Attribute, karma::domain>
{};
-
-#if 0
- // If a rule takes an utree attribute and that utree instance holds nothing
- // more than a list, we dereference this to simplify attribute handling
- // down the stream, i.e. ( ( 1 2 3 ) ) --> ( 1 2 3 ).
- template <>
- struct transform_attribute<utree const, utree, karma::domain>
- {
- typedef utree const& type;
- static utree const& pre(utree const& val)
- {
- if (detail::is_list(val) && 1 == val.size())
- return val.front();
- return val;
- }
- };
-
- template <>
- struct transform_attribute<utree const&, utree, karma::domain>
- : transform_attribute<utree const, utree, karma::domain>
- {};
-#endif
}}}
#endif
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