Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2011 Joel de Guzman Chris@16: Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: Chris@16: Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: =============================================================================*/ Chris@16: #if !defined(SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM) Chris@16: #define SPIRIT_PASS_CONTAINER_JANUARY_06_2009_0802PM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace spirit { namespace qi { namespace detail Chris@16: { Chris@16: // Helper meta-function allowing to evaluate weak substitutability and Chris@16: // negate the result if the predicate (Sequence) is not true Chris@16: template Chris@16: struct negate_weak_substitute_if_not Chris@16: : mpl::if_< Chris@16: Sequence Chris@16: , typename traits::is_weak_substitute::type Chris@16: , typename mpl::not_< Chris@101: traits::is_weak_substitute Chris@16: >::type> Chris@16: {}; Chris@16: Chris@101: // pass_through_container: utility to check decide whether a provided Chris@101: // container attribute needs to be passed through to the current component Chris@16: // or of we need to split the container by passing along instances of its Chris@16: // value type Chris@16: Chris@101: // if the expected attribute of the current component is neither a Fusion Chris@101: // sequence nor a container, we will pass through the provided container Chris@16: // only if its value type is not compatible with the component Chris@16: template Chris@16: struct pass_through_container_base Chris@16: : negate_weak_substitute_if_not Chris@16: {}; Chris@16: Chris@16: // Specialization for fusion sequences, in this case we check whether all Chris@16: // the types in the sequence are convertible to the lhs attribute. Chris@101: // Chris@16: // We return false if the rhs attribute itself is a fusion sequence, which Chris@101: // is compatible with the LHS sequence (we want to pass through this Chris@16: // attribute without it being split apart). Chris@16: template Chris@16: struct not_compatible_element Chris@16: : mpl::and_< Chris@16: negate_weak_substitute_if_not Chris@16: , negate_weak_substitute_if_not > Chris@16: {}; Chris@16: Chris@16: // If the value type of the container is not a Fusion sequence, we pass Chris@101: // through the container if each of the elements of the Attribute Chris@16: // sequence is compatible with either the container or its value type. Chris@16: template ::value> Chris@16: struct pass_through_container_fusion_sequence Chris@16: { Chris@16: typedef typename mpl::find_if< Chris@16: Attribute, not_compatible_element Chris@16: >::type iter; Chris@16: typedef typename mpl::end::type end; Chris@16: Chris@16: typedef typename is_same::type type; Chris@16: }; Chris@16: Chris@16: // If both, the Attribute and the value type of the provided container Chris@101: // are Fusion sequences, we pass the container only if the two Chris@16: // sequences are not compatible. Chris@16: template Chris@16: struct pass_through_container_fusion_sequence< Chris@16: Container, ValueType, Attribute, Sequence, true> Chris@16: { Chris@16: typedef typename mpl::find_if< Chris@16: Attribute Chris@16: , not_compatible_element Chris@16: >::type iter; Chris@16: typedef typename mpl::end::type end; Chris@16: Chris@16: typedef typename is_same::type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct pass_through_container_base >::type> Chris@16: : pass_through_container_fusion_sequence< Chris@16: Container, ValueType, Attribute, Sequence> Chris@16: {}; Chris@16: Chris@16: // Specialization for containers Chris@16: // Chris@16: // If the value type of the attribute of the current component is not Chris@101: // a Fusion sequence, we have to pass through the provided container if Chris@16: // both are compatible. Chris@16: template ::value> Chris@16: struct pass_through_container_container Chris@16: : mpl::or_< Chris@101: traits::is_weak_substitute Chris@16: , traits::is_weak_substitute > Chris@16: {}; Chris@16: Chris@16: // If the value type of the exposed container attribute is a Fusion Chris@16: // sequence, we use the already existing logic for those. Chris@16: template Chris@16: struct pass_through_container_container< Chris@16: Container, ValueType, Attribute, Sequence, AttributeValueType, true> Chris@16: : pass_through_container_fusion_sequence< Chris@16: Container, ValueType, AttributeValueType, Sequence> Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct pass_through_container_base< Chris@16: Container, ValueType, Attribute, Sequence Chris@16: , typename enable_if >::type> Chris@16: : detail::pass_through_container_container< Chris@16: Container, ValueType, Attribute, Sequence Chris@16: , typename traits::container_value::type> Chris@16: {}; Chris@16: Chris@16: // Specialization for exposed optional attributes Chris@16: // Chris@101: // If the type embedded in the exposed optional is not a Fusion Chris@16: // sequence we pass through the container attribute if it is compatible Chris@101: // either to the optionals embedded type or to the containers value Chris@16: // type. Chris@16: template ::value> Chris@16: struct pass_through_container_optional Chris@16: : mpl::or_< Chris@101: traits::is_weak_substitute Chris@16: , traits::is_weak_substitute > Chris@16: {}; Chris@16: Chris@16: // If the embedded type of the exposed optional attribute is a Fusion Chris@16: // sequence, we use the already existing logic for those. Chris@16: template Chris@16: struct pass_through_container_optional< Chris@16: Container, ValueType, Attribute, Sequence, true> Chris@16: : pass_through_container_fusion_sequence< Chris@16: Container, ValueType, Attribute, Sequence> Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct pass_through_container Chris@101: : pass_through_container_base Chris@16: {}; Chris@16: Chris@16: // Handle optional attributes Chris@16: template Chris@16: struct pass_through_container< Chris@16: Container, ValueType, boost::optional, Sequence> Chris@16: : pass_through_container_optional< Chris@101: Container, ValueType, Attribute, Sequence> Chris@16: {}; Chris@16: Chris@16: // If both, the containers value type and the exposed attribute type are Chris@101: // optionals we are allowed to pass through the container only if the Chris@16: // embedded types of those optionals are not compatible. Chris@16: template Chris@16: struct pass_through_container< Chris@16: Container, boost::optional, boost::optional Chris@16: , Sequence> Chris@101: : mpl::not_ > Chris@16: {}; Chris@16: Chris@16: // Specialization for exposed variant attributes Chris@101: // Chris@101: // We pass through the container attribute if at least one of the embedded Chris@16: // types in the variant requires to pass through the attribute Chris@16: Chris@101: #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) Chris@101: template Chris@101: struct pass_through_container Chris@101: , Sequence> Chris@101: : pass_through_container Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct pass_through_container, Sequence> Chris@101: : mpl::bool_::type::value || pass_through_container< Chris@101: Container, ValueType, boost::variant, Sequence Chris@101: >::type::value> Chris@101: {}; Chris@101: #else Chris@16: #define BOOST_SPIRIT_PASS_THROUGH_CONTAINER(z, N, _) \ Chris@16: pass_through_container::type::value || \ Chris@16: /***/ Chris@16: Chris@16: // make sure unused variant parameters do not affect the outcome Chris@16: template Chris@16: struct pass_through_container Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct pass_through_container, Sequence> Chris@16: : mpl::bool_ Chris@16: {}; Chris@16: Chris@16: #undef BOOST_SPIRIT_PASS_THROUGH_CONTAINER Chris@101: #endif Chris@16: }}}} Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // forwarding customization point for domain qi::domain Chris@16: template Chris@16: struct pass_through_container< Chris@16: Container, ValueType, Attribute, Sequence, qi::domain> Chris@16: : qi::detail::pass_through_container< Chris@16: Container, ValueType, Attribute, Sequence> Chris@16: {}; Chris@16: }}} Chris@16: Chris@16: namespace boost { namespace spirit { namespace qi { namespace detail Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This function handles the case where the attribute (Attr) given Chris@16: // the sequence is an STL container. This is a wrapper around F. Chris@16: // The function F does the actual parsing. Chris@16: template Chris@16: struct pass_container Chris@16: { Chris@16: typedef typename F::context_type context_type; Chris@16: typedef typename F::iterator_type iterator_type; Chris@16: Chris@16: pass_container(F const& f_, Attr& attr_) Chris@16: : f(f_), attr(attr_) {} Chris@16: Chris@16: // this is for the case when the current element exposes an attribute Chris@16: // which is pushed back onto the container Chris@16: template Chris@16: bool dispatch_container(Component const& component, mpl::false_) const Chris@16: { Chris@16: // synthesized attribute needs to be default constructed Chris@16: typename traits::container_value::type val = Chris@16: typename traits::container_value::type(); Chris@16: Chris@16: iterator_type save = f.first; Chris@16: bool r = f(component, val); Chris@16: if (!r) Chris@16: { Chris@16: // push the parsed value into our attribute Chris@16: r = !traits::push_back(attr, val); Chris@16: if (r) Chris@16: f.first = save; Chris@16: } Chris@16: return r; Chris@16: } Chris@16: Chris@101: // this is for the case when the current element is able to handle an Chris@101: // attribute which is a container itself, this element will push its Chris@16: // data directly into the attribute container Chris@16: template Chris@16: bool dispatch_container(Component const& component, mpl::true_) const Chris@16: { Chris@16: return f(component, attr); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////// Chris@101: // this is for the case when the current element doesn't expect an Chris@16: // attribute Chris@16: template Chris@16: bool dispatch_attribute(Component const& component, mpl::false_) const Chris@16: { Chris@16: return f(component, unused); Chris@16: } Chris@16: Chris@16: // the current element expects an attribute Chris@16: template Chris@16: bool dispatch_attribute(Component const& component, mpl::true_) const Chris@16: { Chris@16: typedef typename traits::container_value::type value_type; Chris@16: typedef typename traits::attribute_of< Chris@16: Component, context_type, iterator_type>::type Chris@16: rhs_attribute; Chris@16: Chris@101: // this predicate detects, whether the attribute of the current Chris@16: // element is a substitute for the value type of the container Chris@101: // attribute Chris@16: typedef mpl::and_< Chris@16: traits::handles_container< Chris@101: Component, Attr, context_type, iterator_type> Chris@16: , traits::pass_through_container< Chris@16: Attr, value_type, rhs_attribute, Sequence, qi::domain> Chris@16: > predicate; Chris@16: Chris@16: return dispatch_container(component, predicate()); Chris@16: } Chris@16: Chris@16: // Dispatches to dispatch_main depending on the attribute type Chris@16: // of the Component Chris@16: template Chris@16: bool operator()(Component const& component) const Chris@16: { Chris@16: // we need to dispatch depending on the type of the attribute Chris@16: // of the current element (component). If this is has no attribute Chris@16: // we shouldn't pass an attribute at all. Chris@16: typedef typename traits::not_is_unused< Chris@16: typename traits::attribute_of< Chris@16: Component, context_type, iterator_type Chris@16: >::type Chris@16: >::type predicate; Chris@16: Chris@16: // ensure the attribute is actually a container type Chris@16: traits::make_container(attr); Chris@16: Chris@16: return dispatch_attribute(component, predicate()); Chris@16: } Chris@16: Chris@16: F f; Chris@16: Attr& attr; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: pass_container& operator= (pass_container const&); Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@101: // Utility function to make a pass_container for container components Chris@16: // (kleene, list, plus, repeat) Chris@16: template Chris@16: inline pass_container Chris@16: make_pass_container(F const& f, Attr& attr) Chris@16: { Chris@16: return pass_container(f, attr); Chris@16: } Chris@16: Chris@16: // Utility function to make a pass_container for sequences Chris@16: template Chris@16: inline pass_container Chris@16: make_sequence_pass_container(F const& f, Attr& attr) Chris@16: { Chris@16: return pass_container(f, attr); Chris@16: } Chris@16: }}}} Chris@16: Chris@16: #endif Chris@16: