/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman 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) =============================================================================*/ #if !defined(SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM) #define SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM #if defined(_MSC_VER) #pragma once #endif #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace qi { namespace detail { // Helper meta-function allowing to evaluate weak substitutability and // negate the result if the predicate (Sequence) is not true template struct negate_weak_substitute_if_not : mpl::if_< Sequence , typename traits::is_weak_substitute::type , typename mpl::not_< traits::is_weak_substitute >::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 struct pass_through_container_base : negate_weak_substitute_if_not {}; // 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 struct not_compatible_element : mpl::and_< negate_weak_substitute_if_not , negate_weak_substitute_if_not > {}; // 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 ::value> struct pass_through_container_fusion_sequence { typedef typename mpl::find_if< Attribute, not_compatible_element >::type iter; typedef typename mpl::end::type end; typedef typename is_same::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 struct pass_through_container_fusion_sequence< Container, ValueType, Attribute, Sequence, true> { typedef typename mpl::find_if< Attribute , not_compatible_element >::type iter; typedef typename mpl::end::type end; typedef typename is_same::type type; }; template struct pass_through_container_base >::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 ::value> struct pass_through_container_container : mpl::or_< traits::is_weak_substitute , traits::is_weak_substitute > {}; // If the value type of the exposed container attribute is a Fusion // sequence, we use the already existing logic for those. template struct pass_through_container_container< Container, ValueType, Attribute, Sequence, AttributeValueType, true> : pass_through_container_fusion_sequence< Container, ValueType, AttributeValueType, Sequence> {}; template struct pass_through_container_base< Container, ValueType, Attribute, Sequence , typename enable_if >::type> : detail::pass_through_container_container< Container, ValueType, Attribute, Sequence , typename traits::container_value::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 ::value> struct pass_through_container_optional : mpl::or_< traits::is_weak_substitute , traits::is_weak_substitute > {}; // If the embedded type of the exposed optional attribute is a Fusion // sequence, we use the already existing logic for those. template struct pass_through_container_optional< Container, ValueType, Attribute, Sequence, true> : pass_through_container_fusion_sequence< Container, ValueType, Attribute, Sequence> {}; /////////////////////////////////////////////////////////////////////////// template struct pass_through_container : pass_through_container_base {}; // Handle optional attributes template struct pass_through_container< Container, ValueType, boost::optional, 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 struct pass_through_container< Container, boost::optional, boost::optional , Sequence> : mpl::not_ > {}; // 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::type::value || \ /***/ // make sure unused variant parameters do not affect the outcome template struct pass_through_container : mpl::false_ {}; template struct pass_through_container, Sequence> : mpl::bool_ {}; #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER }}}} /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { /////////////////////////////////////////////////////////////////////////// // forwarding customization point for domain qi::domain template 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 struct pass_container { typedef typename F::context_type context_type; typedef typename F::iterator_type iterator_type; pass_container(F const& f, Attr& attr) : f(f), attr(attr) {} // this is for the case when the current element exposes an attribute // which is pushed back onto the container template bool dispatch_container(Component const& component, mpl::false_) const { // synthesized attribute needs to be default constructed typename traits::container_value::type val = typename traits::container_value::type(); iterator_type save = f.first; bool r = f(component, val); if (!r) { // push the parsed value into our attribute r = !traits::push_back(attr, val); if (r) f.first = save; } return r; } // 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 bool dispatch_container(Component const& component, mpl::true_) const { return f(component, attr); } /////////////////////////////////////////////////////////////////////// // this is for the case when the current element doesn't expect an // attribute template bool dispatch_attribute(Component const& component, mpl::false_) const { return f(component, unused); } // the current element expects an attribute template bool dispatch_attribute(Component const& component, mpl::true_) const { typedef typename traits::container_value::type value_type; typedef typename traits::attribute_of< Component, context_type, iterator_type>::type rhs_attribute; // this predicate detects, whether the attribute of the current // element is a substitute for the value type of the container // attribute typedef mpl::and_< 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()); } // Dispatches to dispatch_main depending on the attribute type // of the Component template bool operator()(Component const& component) const { // 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_attribute(component, predicate()); } F f; Attr& attr; private: // silence MSVC warning C4512: assignment operator could not be generated pass_container& operator= (pass_container const&); }; /////////////////////////////////////////////////////////////////////////// // Utility function to make a pass_container for container components // (kleene, list, plus, repeat) template inline pass_container make_pass_container(F const& f, Attr& attr) { return pass_container(f, attr); } // Utility function to make a pass_container for sequences template inline pass_container make_sequence_pass_container(F const& f, Attr& attr) { return pass_container(f, attr); } }}}} #endif