Chris@16: /*============================================================================= Chris@16: Copyright (c) 2001-2011 Joel de Guzman Chris@16: Copyright (c) 2001-2012 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(BOOST_SPIRIT_ATTRIBUTES_JANUARY_29_2007_0954AM) Chris@16: #define BOOST_SPIRIT_ATTRIBUTES_JANUARY_29_2007_0954AM 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: #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: #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: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This file deals with attribute related functions and meta-functions Chris@16: // including generalized attribute transformation utilities for Spirit Chris@16: // components. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Find out if T can be a (strong) substitute for Expected attribute Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct value_type_is_substitute Chris@16: : is_substitute< Chris@16: typename container_value::type Chris@16: , typename container_value::type> Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_substitute_impl : is_same {}; Chris@16: Chris@16: template Chris@16: struct is_substitute_impl, Chris@16: fusion::traits::is_sequence, Chris@16: mpl::equal > Chris@16: > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: template Chris@16: struct is_substitute_impl, Chris@16: is_container, Chris@16: detail::value_type_is_substitute Chris@16: > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: } Chris@16: Chris@16: template Chris@16: struct is_substitute Chris@16: : detail::is_substitute_impl {}; Chris@16: Chris@16: template Chris@16: struct is_substitute, optional > Chris@16: : is_substitute {}; Chris@16: Chris@16: template Chris@16: struct is_substitute >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Find out if T can be a weak substitute for Expected attribute Chris@16: namespace detail Chris@16: { Chris@16: // A type, which is convertible to the attribute is at the same time Chris@16: // usable as its weak substitute. Chris@16: template Chris@16: struct is_weak_substitute_impl : is_convertible {}; Chris@16: Chris@16: // // An exposed attribute is a weak substitute for a supplied container Chris@16: // // attribute if it is a weak substitute for its value_type. This is Chris@16: // // true as all character parsers are compatible with a container Chris@16: // // attribute having the corresponding character type as its value_type. Chris@16: // template Chris@16: // struct is_weak_substitute_for_value_type Chris@16: // : is_weak_substitute::type> Chris@16: // {}; Chris@16: // Chris@16: // template Chris@16: // struct is_weak_substitute_impl > Chris@16: // , is_string Chris@16: // , is_weak_substitute_for_value_type > Chris@16: // >::type> Chris@16: // : mpl::true_ Chris@16: // {}; Chris@16: Chris@16: // An exposed container attribute is a weak substitute for a supplied Chris@16: // container attribute if and only if their value_types are weak Chris@16: // substitutes. Chris@16: template Chris@16: struct value_type_is_weak_substitute Chris@16: : is_weak_substitute< Chris@16: typename container_value::type Chris@16: , typename container_value::type> Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_weak_substitute_impl Chris@16: , is_container Chris@16: , value_type_is_weak_substitute > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: // Two fusion sequences are weak substitutes if and only if their Chris@16: // elements are pairwise weak substitutes. Chris@16: template Chris@16: struct is_weak_substitute_impl Chris@16: , fusion::traits::is_sequence Chris@16: , mpl::equal > > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: // If this is not defined, the main template definition above will return Chris@16: // true if T is convertible to the first type in a fusion::vector. We Chris@16: // globally declare any non-Fusion sequence T as not compatible with any Chris@16: // Fusion sequence 'Expected'. Chris@16: template Chris@16: struct is_weak_substitute_impl > Chris@16: , fusion::traits::is_sequence > Chris@16: >::type> Chris@16: : mpl::false_ {}; Chris@16: } Chris@16: Chris@16: // main template forwards to detail namespace, this helps older compilers Chris@16: // to disambiguate things Chris@16: template Chris@16: struct is_weak_substitute Chris@16: : detail::is_weak_substitute_impl {}; Chris@16: Chris@16: template Chris@16: struct is_weak_substitute, optional > Chris@16: : is_weak_substitute {}; Chris@16: Chris@16: template Chris@16: struct is_weak_substitute, Expected> Chris@16: : is_weak_substitute {}; Chris@16: Chris@16: template Chris@16: struct is_weak_substitute > Chris@16: : is_weak_substitute {}; Chris@16: Chris@101: #if !defined(BOOST_VARIANT_DO_NOT_USE_VARIADIC_TEMPLATES) Chris@101: template Chris@101: struct is_weak_substitute, Expected> Chris@101: : is_weak_substitute Chris@101: {}; Chris@101: Chris@101: template Chris@101: struct is_weak_substitute, Chris@101: Expected> Chris@101: : mpl::bool_::type::value && Chris@101: is_weak_substitute, Expected>::type::value> Chris@101: {}; Chris@101: #else Chris@16: #define BOOST_SPIRIT_IS_WEAK_SUBSTITUTE(z, N, _) \ Chris@16: is_weak_substitute::type::value && \ Chris@16: /***/ Chris@16: Chris@16: // make sure unused variant parameters do not affect the outcome Chris@16: template Chris@16: struct is_weak_substitute Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_weak_substitute< Chris@16: boost::variant, Expected> Chris@16: : mpl::bool_ Chris@16: {}; Chris@16: Chris@16: #undef BOOST_SPIRIT_IS_WEAK_SUBSTITUTE Chris@101: #endif Chris@16: Chris@16: template Chris@16: struct is_weak_substitute, not_is_variant > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct is_proxy : mpl::false_ {}; Chris@16: Chris@16: template Chris@16: struct is_proxy, Chris@16: fusion::traits::is_view Chris@16: > Chris@16: >::type> Chris@16: : mpl::true_ {}; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // By declaring a nested struct in your class/struct, you tell Chris@16: // spirit that it is regarded as a variant type. The minimum Chris@16: // required interface for such a variant is that it has constructors Chris@16: // for various types supported by your variant and a typedef 'types' Chris@16: // which is an mpl sequence of the contained types. Chris@16: // Chris@16: // This is an intrusive interface. For a non-intrusive interface, Chris@16: // use the not_is_variant trait. Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(adapted_variant_tag) Chris@16: } Chris@16: Chris@16: template Chris@16: struct not_is_variant Chris@16: : mpl::not_ > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct not_is_variant, Domain> Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct not_is_variant, Domain> Chris@16: : not_is_variant Chris@16: {}; Chris@16: Chris@16: // we treat every type as if it where the variant (as this meta function is Chris@16: // invoked for variant types only) Chris@16: template Chris@16: struct variant_type Chris@16: : mpl::identity Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct variant_type > Chris@16: : variant_type Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // The compute_compatible_component_variant Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: // A component is compatible to a given Attribute type if the Chris@16: // Attribute is the same as the expected type of the component or if Chris@16: // it is convertible to the expected type. Chris@16: template Chris@16: struct attribute_is_compatible Chris@16: : is_convertible Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct attribute_is_compatible > Chris@16: : is_convertible Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_hold_any_container Chris@16: : traits::is_hold_any::type> Chris@16: {}; Chris@16: } Chris@16: Chris@16: template Chris@16: struct compute_compatible_component_variant Chris@16: : mpl::or_< Chris@16: traits::detail::attribute_is_compatible Chris@16: , traits::is_hold_any Chris@16: , mpl::eval_if< Chris@16: is_container Chris@16: , traits::detail::is_hold_any_container Chris@16: , mpl::false_> > Chris@16: {}; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: BOOST_MPL_HAS_XXX_TRAIT_DEF(types) Chris@16: } Chris@16: Chris@16: template Chris@16: struct compute_compatible_component_variant >::type> Chris@16: { Chris@16: typedef typename traits::variant_type::type variant_type; Chris@16: typedef typename variant_type::types types; Chris@16: typedef typename mpl::end::type end; Chris@16: Chris@16: typedef typename Chris@16: mpl::find_if >::type Chris@16: iter; Chris@16: Chris@16: typedef typename mpl::distance< Chris@16: typename mpl::begin::type, iter Chris@16: >::type distance; Chris@16: Chris@16: // true_ if the attribute matches one of the types in the variant Chris@16: typedef typename mpl::not_ >::type type; Chris@16: enum { value = type::value }; Chris@16: Chris@16: // return the type in the variant the attribute is compatible with Chris@16: typedef typename Chris@16: mpl::eval_if, mpl::identity >::type Chris@16: compatible_type; Chris@16: Chris@16: // return whether the given type is compatible with the Expected type Chris@16: static bool is_compatible(int which) Chris@16: { Chris@16: return which == distance::value; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct compute_compatible_component Chris@16: : compute_compatible_component_variant::type> {}; Chris@16: Chris@16: template Chris@16: struct compute_compatible_component Chris@16: : mpl::false_ {}; Chris@16: Chris@16: template Chris@16: struct compute_compatible_component Chris@16: : mpl::false_ {}; Chris@16: Chris@16: template Chris@16: struct compute_compatible_component Chris@16: : mpl::false_ {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // return the type currently stored in the given variant Chris@16: template Chris@16: struct variant_which > Chris@16: { Chris@16: static int call(boost::variant const& v) Chris@16: { Chris@16: return v.which(); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: int which(T const& v) Chris@16: { Chris@16: return variant_which::call(v); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct not_is_optional Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct not_is_optional, Domain> Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // attribute_of Chris@16: // Chris@16: // Get the component's attribute Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct attribute_of Chris@16: { Chris@16: typedef typename Component::template Chris@16: attribute::type type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // attribute_not_unused Chris@16: // Chris@16: // An mpl meta-function class that determines whether a component's Chris@16: // attribute is not unused. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct attribute_not_unused Chris@16: { Chris@16: template Chris@16: struct apply Chris@16: : not_is_unused::type> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Retrieve the attribute type to use from the given type Chris@16: // Chris@16: // This is needed to extract the correct attribute type from proxy classes Chris@16: // as utilized in FUSION_ADAPT_ADT et. al. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct attribute_type : mpl::identity {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Retrieve the size of a fusion sequence (compile time) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct sequence_size Chris@16: : fusion::result_of::size Chris@16: {}; Chris@16: Chris@16: template <> Chris@16: struct sequence_size Chris@16: : mpl::int_<0> Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Retrieve the size of an attribute (runtime) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct attribute_size_impl Chris@16: { Chris@16: typedef std::size_t type; Chris@16: Chris@16: static type call(Attribute const&) Chris@16: { Chris@16: return 1; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct attribute_size_impl Chris@16: , mpl::not_ > Chris@16: > Chris@16: >::type> Chris@16: { Chris@16: typedef typename fusion::result_of::size::value_type type; Chris@16: Chris@16: static type call(Attribute const& attr) Chris@16: { Chris@16: return fusion::size(attr); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct attribute_size_impl Chris@16: , mpl::not_ > Chris@16: > Chris@16: >::type> Chris@16: { Chris@16: typedef typename Attribute::size_type type; Chris@16: Chris@16: static type call(Attribute const& attr) Chris@16: { Chris@16: return attr.size(); Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: struct attribute_size Chris@16: : detail::attribute_size_impl Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct attribute_size > Chris@16: { Chris@16: typedef typename attribute_size::type type; Chris@16: Chris@16: static type call(optional const& val) Chris@16: { Chris@16: if (!val) Chris@16: return 0; Chris@101: return traits::size(val.get()); Chris@16: } Chris@16: }; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: struct attribute_size_visitor : static_visitor Chris@16: { Chris@16: template Chris@16: std::size_t operator()(T const& val) const Chris@16: { Chris@16: return spirit::traits::size(val); Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: struct attribute_size > Chris@16: { Chris@16: typedef std::size_t type; Chris@16: Chris@16: static type call(variant const& val) Chris@16: { Chris@16: return apply_visitor(detail::attribute_size_visitor(), val); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct attribute_size > Chris@16: { Chris@16: typedef typename boost::detail::iterator_traits:: Chris@16: difference_type type; Chris@16: Chris@16: static type call(iterator_range const& r) Chris@16: { Chris@16: return boost::detail::distance(r.begin(), r.end()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct attribute_size Chris@16: { Chris@16: typedef std::size_t type; Chris@16: Chris@16: static type call(unused_type) Chris@16: { Chris@16: return 0; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: typename attribute_size::type Chris@16: size (Attribute const& attr) Chris@16: { Chris@16: return attribute_size::call(attr); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // pass_attribute Chris@16: // Chris@16: // Determines how we pass attributes to semantic actions. This Chris@16: // may be specialized. By default, all attributes are wrapped in Chris@16: // a fusion sequence, because the attribute has to be treated as being Chris@16: // a single value in any case (even if it actually already is a fusion Chris@16: // sequence in its own). Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct pass_attribute Chris@16: { Chris@16: typedef fusion::vector1 type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Subclass a pass_attribute specialization from this to wrap Chris@16: // the attribute in a tuple only IFF it is not already a fusion tuple. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct wrap_if_not_tuple Chris@16: : mpl::if_< Chris@16: fusion::traits::is_sequence Chris@16: , Attribute&, fusion::vector1 > Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct wrap_if_not_tuple Chris@16: { Chris@16: typedef fusion::vector1 type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct wrap_if_not_tuple Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct wrap_if_not_tuple Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // build_optional Chris@16: // Chris@16: // Build a boost::optional from T. Return unused_type if T is unused_type. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct build_optional Chris@16: { Chris@16: typedef boost::optional type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct build_optional > Chris@16: { Chris@16: typedef boost::optional type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct build_optional Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // build_std_vector Chris@16: // Chris@16: // Build a std::vector from T. Return unused_type if T is unused_type. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct build_std_vector Chris@16: { Chris@16: typedef std::vector type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct build_std_vector Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // filter_unused_attributes Chris@16: // Chris@16: // Remove unused_types from a sequence Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: // Compute the list of all *used* attributes of sub-components Chris@16: // (filter all unused attributes from the list) Chris@16: template Chris@16: struct filter_unused_attributes Chris@16: : fusion::result_of::filter_if > Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // sequence_attribute_transform Chris@16: // Chris@16: // This transform is invoked for every attribute in a sequence allowing Chris@16: // to modify the attribute type exposed by a component to the enclosing Chris@16: // sequence component. By default no transformation is performed. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct sequence_attribute_transform Chris@16: : mpl::identity Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // permutation_attribute_transform Chris@16: // Chris@16: // This transform is invoked for every attribute in a sequence allowing Chris@16: // to modify the attribute type exposed by a component to the enclosing Chris@16: // permutation component. By default a build_optional transformation is Chris@16: // performed. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct permutation_attribute_transform Chris@16: : traits::build_optional Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // sequential_or_attribute_transform Chris@16: // Chris@16: // This transform is invoked for every attribute in a sequential_or allowing Chris@16: // to modify the attribute type exposed by a component to the enclosing Chris@16: // sequential_or component. By default a build_optional transformation is Chris@16: // performed. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct sequential_or_attribute_transform Chris@16: : traits::build_optional Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // build_fusion_vector Chris@16: // Chris@16: // Build a fusion vector from a fusion sequence. All unused attributes Chris@16: // are filtered out. If the result is empty after the removal of unused Chris@16: // types, return unused_type. If the input sequence is an unused_type, Chris@16: // also return unused_type. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct build_fusion_vector Chris@16: { Chris@16: // Remove all unused attributes Chris@16: typedef typename Chris@16: filter_unused_attributes::type Chris@16: filtered_attributes; Chris@16: Chris@16: // Build a fusion vector from a fusion sequence (Sequence), Chris@16: // But *only if* the sequence is not empty. i.e. if the Chris@16: // sequence is empty, our result will be unused_type. Chris@16: Chris@16: typedef typename Chris@16: mpl::eval_if< Chris@16: fusion::result_of::empty Chris@16: , mpl::identity Chris@16: , fusion::result_of::as_vector Chris@16: >::type Chris@16: type; Chris@16: }; Chris@16: Chris@16: template <> Chris@16: struct build_fusion_vector Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // build_attribute_sequence Chris@16: // Chris@16: // Build a fusion sequence attribute sequence from a sequence of Chris@16: // components. Transform::type is called on each element. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template class Transform Chris@16: , typename Iterator = unused_type, typename Domain = unused_type> Chris@16: struct build_attribute_sequence Chris@16: { Chris@16: struct element_attribute Chris@16: { Chris@16: template Chris@16: struct result; Chris@16: Chris@16: template Chris@16: struct result Chris@16: { Chris@16: typedef typename Chris@16: Transform< Chris@16: typename attribute_of::type Chris@16: , Domain Chris@16: >::type Chris@16: type; Chris@16: }; Chris@16: Chris@16: // never called, but needed for decltype-based result_of (C++0x) Chris@16: #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES Chris@16: template Chris@16: typename result::type Chris@16: operator()(Element&&) const; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: // Compute the list of attributes of all sub-components Chris@16: typedef typename Chris@16: fusion::result_of::transform::type Chris@16: type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // has_no_unused Chris@16: // Chris@16: // Test if there are no unused attributes in Sequence Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct has_no_unused Chris@16: : is_same< Chris@16: typename mpl::find_if >::type Chris@16: , typename mpl::end::type> Chris@16: {}; Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: template ::value> Chris@16: struct build_collapsed_variant; Chris@16: Chris@16: // N element case, no unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: : spirit::detail::as_variant {}; Chris@16: Chris@16: // N element case with unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: { Chris@16: typedef boost::optional< Chris@16: typename spirit::detail::as_variant< Chris@16: typename fusion::result_of::pop_front::type Chris@16: >::type Chris@16: > type; Chris@16: }; Chris@16: Chris@16: // 1 element case, no unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: : mpl::front {}; Chris@16: Chris@16: // 1 element case, with unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: : mpl::front {}; Chris@16: Chris@16: // 2 element case, no unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: : spirit::detail::as_variant {}; Chris@16: Chris@16: // 2 element case, with unused Chris@16: template Chris@16: struct build_collapsed_variant Chris@16: { Chris@16: typedef boost::optional< Chris@16: typename mpl::deref< Chris@16: typename mpl::next< Chris@16: typename mpl::begin::type Chris@16: >::type Chris@16: >::type Chris@16: > Chris@16: type; Chris@16: }; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // alternative_attribute_transform Chris@16: // Chris@16: // This transform is invoked for every attribute in an alternative allowing Chris@16: // to modify the attribute type exposed by a component to the enclosing Chris@16: // alternative component. By default no transformation is performed. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct alternative_attribute_transform Chris@16: : mpl::identity Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // build_variant Chris@16: // Chris@16: // Build a boost::variant from a fusion sequence. build_variant makes sure Chris@16: // that 1) all attributes in the variant are unique 2) puts the unused Chris@16: // attribute, if there is any, to the front and 3) collapses single element Chris@16: // variants, variant to T. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct build_variant Chris@16: { Chris@16: // Remove all unused attributes. Chris@16: typedef typename Chris@16: filter_unused_attributes::type Chris@16: filtered_attributes; Chris@16: Chris@16: typedef has_no_unused no_unused; Chris@16: Chris@16: // If the original attribute list does not contain any unused Chris@16: // attributes, it is used, otherwise a single unused_type is Chris@16: // pushed to the front of the list. This is to make sure that if Chris@16: // there is an unused_type in the list, it is the first one. Chris@16: typedef typename Chris@16: mpl::eval_if< Chris@16: no_unused, Chris@16: mpl::identity, Chris@16: fusion::result_of::push_front Chris@16: >::type Chris@16: attribute_sequence; Chris@16: Chris@16: // Make sure each of the types occur only once in the type list Chris@16: typedef typename Chris@16: mpl::fold< Chris@16: attribute_sequence, mpl::vector<>, Chris@16: mpl::if_< Chris@16: mpl::contains, Chris@16: mpl::_1, mpl::push_back Chris@16: > Chris@16: >::type Chris@16: no_duplicates; Chris@16: Chris@16: // If there is only one type in the list of types we strip off the Chris@16: // variant. IOTW, collapse single element variants, variant to T. Chris@16: // Take note that this also collapses variant to T. Chris@16: typedef typename Chris@16: traits::detail::build_collapsed_variant< Chris@16: no_duplicates, no_unused::value>::type Chris@16: type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // transform_attribute Chris@16: // Chris@16: // Sometimes the user needs to transform the attribute types for certain Chris@16: // attributes. This template can be used as a customization point, where Chris@16: // the user is able specify specific transformation rules for any attribute Chris@16: // type. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct transform_attribute; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: typename spirit::result_of::pre_transform::type Chris@16: pre_transform(Exposed& attr BOOST_PROTO_DISABLE_IF_IS_CONST(Exposed)) Chris@16: { Chris@16: return transform_attribute::pre(attr); Chris@16: } Chris@16: Chris@16: template Chris@16: typename spirit::result_of::pre_transform::type Chris@16: pre_transform(Exposed const& attr) Chris@16: { Chris@16: return transform_attribute::pre(attr); Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // make_attribute Chris@16: // Chris@16: // All parsers and generators have specific attribute types. Chris@16: // Spirit parsers and generators are passed an attribute; these are either Chris@16: // references to the expected type, or an unused_type -- to flag that we do Chris@16: // not care about the attribute. For semantic actions, however, we need to Chris@16: // have a real value to pass to the semantic action. If the client did not Chris@16: // provide one, we will have to synthesize the value. This class takes care Chris@16: // of that. *Note that this behavior has changed. From Boost 1.47, semantic Chris@16: // actions always take in the passed attribute as-is if the PP constant: Chris@16: // BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT is defined. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct make_attribute Chris@16: { Chris@16: typedef typename remove_const::type attribute_type; Chris@16: typedef typename Chris@16: mpl::if_< Chris@16: is_same::type, unused_type> Chris@16: , attribute_type Chris@16: , ActualAttribute&>::type Chris@16: type; Chris@16: Chris@16: typedef typename Chris@16: mpl::if_< Chris@16: is_same::type, unused_type> Chris@16: , attribute_type Chris@16: , ActualAttribute>::type Chris@16: value_type; Chris@16: Chris@16: static Attribute call(unused_type) Chris@16: { Chris@16: // synthesize the attribute/parameter Chris@16: return boost::get(value_initialized()); Chris@16: } Chris@16: Chris@16: template Chris@16: static T& call(T& value) Chris@16: { Chris@16: return value; // just pass the one provided Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct make_attribute Chris@16: : make_attribute Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct make_attribute Chris@16: : make_attribute Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct make_attribute Chris@16: { Chris@16: typedef unused_type type; Chris@16: typedef unused_type value_type; Chris@16: static unused_type call(unused_type) Chris@16: { Chris@16: return unused; Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // swap_impl Chris@16: // Chris@16: // Swap (with proper handling of unused_types) Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: void swap_impl(A& a, B& b) Chris@16: { Chris@16: A temp = a; Chris@16: a = b; Chris@16: b = temp; Chris@16: } Chris@16: Chris@16: template Chris@16: void swap_impl(T& a, T& b) Chris@16: { Chris@16: using namespace std; Chris@16: swap(a, b); Chris@16: } Chris@16: Chris@16: template Chris@16: void swap_impl(A&, unused_type) Chris@16: { Chris@16: } Chris@16: Chris@16: template Chris@16: void swap_impl(unused_type, A&) Chris@16: { Chris@16: } Chris@16: Chris@16: inline void swap_impl(unused_type, unused_type) Chris@16: { Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // Strips single element fusion vectors into its 'naked' Chris@16: // form: vector --> T Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct strip_single_element_vector Chris@16: { Chris@16: typedef T type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct strip_single_element_vector > Chris@16: { Chris@16: typedef T type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct strip_single_element_vector > Chris@16: { Chris@16: typedef T type; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // meta function to return whether the argument is a one element fusion Chris@16: // sequence Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template ::value Chris@16: , bool IsProtoExpr = proto::is_expr::value> Chris@16: struct one_element_sequence Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct one_element_sequence Chris@16: : mpl::bool_::value == 1> Chris@16: {}; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // clear Chris@16: // Chris@16: // Clear data efficiently Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: void clear(T& val); Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // this is used by the variant and fusion sequence dispatch Chris@16: struct clear_visitor : static_visitor<> Chris@16: { Chris@16: template Chris@16: void operator()(T& val) const Chris@16: { Chris@16: spirit::traits::clear(val); Chris@16: } Chris@16: }; Chris@16: Chris@16: // default Chris@16: template Chris@16: void clear_impl2(T& val, mpl::false_) Chris@16: { Chris@16: val = T(); Chris@16: } Chris@16: Chris@16: // for fusion sequences Chris@16: template Chris@16: void clear_impl2(T& val, mpl::true_) Chris@16: { Chris@16: fusion::for_each(val, clear_visitor()); Chris@16: } Chris@16: Chris@16: // dispatch default or fusion sequence Chris@16: template Chris@16: void clear_impl(T& val, mpl::false_) Chris@16: { Chris@16: clear_impl2(val, fusion::traits::is_sequence()); Chris@16: } Chris@16: Chris@16: // STL containers Chris@16: template Chris@16: void clear_impl(T& val, mpl::true_) Chris@16: { Chris@16: val.clear(); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: struct clear_value Chris@16: { Chris@16: static void call(T& val) Chris@16: { Chris@16: detail::clear_impl(val, typename is_container::type()); Chris@16: } Chris@16: }; Chris@16: Chris@16: // optionals Chris@16: template Chris@16: struct clear_value > Chris@16: { Chris@16: static void call(boost::optional& val) Chris@16: { Chris@16: if (val) Chris@16: val = none_t(); // leave optional uninitialized Chris@16: } Chris@16: }; Chris@16: Chris@16: // variants Chris@16: template Chris@16: struct clear_value > Chris@16: { Chris@16: static void call(variant& val) Chris@16: { Chris@16: apply_visitor(detail::clear_visitor(), val); Chris@16: } Chris@16: }; Chris@16: Chris@16: // iterator range Chris@16: template Chris@16: struct clear_value > Chris@16: { Chris@16: static void call(iterator_range& val) Chris@16: { Chris@16: val = iterator_range(val.end(), val.end()); Chris@16: } Chris@16: }; Chris@16: Chris@16: // main dispatch Chris@16: template Chris@16: void clear(T& val) Chris@16: { Chris@16: clear_value::call(val); Chris@16: } Chris@16: Chris@16: // for unused Chris@16: inline void clear(unused_type) Chris@16: { Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct print_fusion_sequence Chris@16: { Chris@16: print_fusion_sequence(Out& out_) Chris@16: : out(out_), is_first(true) {} Chris@16: Chris@16: typedef void result_type; Chris@16: Chris@16: template Chris@16: void operator()(T const& val) const Chris@16: { Chris@16: if (is_first) Chris@16: is_first = false; Chris@16: else Chris@16: out << ", "; Chris@16: spirit::traits::print_attribute(out, val); Chris@16: } Chris@16: Chris@16: Out& out; Chris@16: mutable bool is_first; Chris@16: }; Chris@16: Chris@16: // print elements in a variant Chris@16: template Chris@16: struct print_visitor : static_visitor<> Chris@16: { Chris@16: print_visitor(Out& out_) : out(out_) {} Chris@16: Chris@16: template Chris@16: void operator()(T const& val) const Chris@16: { Chris@16: spirit::traits::print_attribute(out, val); Chris@16: } Chris@16: Chris@16: Out& out; Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: struct print_attribute_debug Chris@16: { Chris@16: // for plain data types Chris@16: template Chris@16: static void call_impl3(Out& out, T_ const& val, mpl::false_) Chris@16: { Chris@16: out << val; Chris@16: } Chris@16: Chris@16: // for fusion data types Chris@16: template Chris@16: static void call_impl3(Out& out, T_ const& val, mpl::true_) Chris@16: { Chris@16: out << '['; Chris@16: fusion::for_each(val, detail::print_fusion_sequence(out)); Chris@16: out << ']'; Chris@16: } Chris@16: Chris@16: // non-stl container Chris@16: template Chris@16: static void call_impl2(Out& out, T_ const& val, mpl::false_) Chris@16: { Chris@16: call_impl3(out, val, fusion::traits::is_sequence()); Chris@16: } Chris@16: Chris@16: // stl container Chris@16: template Chris@16: static void call_impl2(Out& out, T_ const& val, mpl::true_) Chris@16: { Chris@16: out << '['; Chris@16: if (!traits::is_empty(val)) Chris@16: { Chris@16: bool first = true; Chris@16: typename container_iterator::type iend = traits::end(val); Chris@16: for (typename container_iterator::type i = traits::begin(val); Chris@16: !traits::compare(i, iend); traits::next(i)) Chris@16: { Chris@16: if (!first) Chris@16: out << ", "; Chris@16: first = false; Chris@16: spirit::traits::print_attribute(out, traits::deref(i)); Chris@16: } Chris@16: } Chris@16: out << ']'; Chris@16: } Chris@16: Chris@16: // for variant types Chris@16: template Chris@16: static void call_impl(Out& out, T_ const& val, mpl::false_) Chris@16: { Chris@16: apply_visitor(detail::print_visitor(out), val); Chris@16: } Chris@16: Chris@16: // for non-variant types Chris@16: template Chris@16: static void call_impl(Out& out, T_ const& val, mpl::true_) Chris@16: { Chris@16: call_impl2(out, val, is_container()); Chris@16: } Chris@16: Chris@16: // main entry point Chris@16: static void call(Out& out, T const& val) Chris@16: { Chris@16: call_impl(out, val, not_is_variant()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct print_attribute_debug > Chris@16: { Chris@16: static void call(Out& out, boost::optional const& val) Chris@16: { Chris@16: if (val) Chris@16: spirit::traits::print_attribute(out, *val); Chris@16: else Chris@16: out << "[empty]"; Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: inline void print_attribute(Out& out, T const& val) Chris@16: { Chris@16: print_attribute_debug::call(out, val); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void print_attribute(Out&, unused_type) Chris@16: { Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // generate debug output for lookahead token (character) stream Chris@16: namespace detail Chris@16: { Chris@16: struct token_printer_debug_for_chars Chris@16: { Chris@16: template Chris@16: static void print(Out& o, Char c) Chris@16: { Chris@16: using namespace std; // allow for ADL to find the proper iscntrl Chris@16: Chris@16: if (c == static_cast('\a')) Chris@16: o << "\\a"; Chris@16: else if (c == static_cast('\b')) Chris@16: o << "\\b"; Chris@16: else if (c == static_cast('\f')) Chris@16: o << "\\f"; Chris@16: else if (c == static_cast('\n')) Chris@16: o << "\\n"; Chris@16: else if (c == static_cast('\r')) Chris@16: o << "\\r"; Chris@16: else if (c == static_cast('\t')) Chris@16: o << "\\t"; Chris@16: else if (c == static_cast('\v')) Chris@16: o << "\\v"; Chris@16: else if (c >= 0 && c < 127 && iscntrl(c)) Chris@16: o << "\\" << std::oct << static_cast(c); Chris@16: else Chris@16: o << static_cast(c); Chris@16: } Chris@16: }; Chris@16: Chris@16: // for token types where the comparison with char constants wouldn't work Chris@16: struct token_printer_debug Chris@16: { Chris@16: template Chris@16: static void print(Out& o, T const& val) Chris@16: { Chris@16: o << val; Chris@16: } Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: struct token_printer_debug Chris@16: : mpl::if_< Chris@16: mpl::and_< Chris@16: is_convertible, is_convertible > Chris@16: , detail::token_printer_debug_for_chars Chris@16: , detail::token_printer_debug>::type Chris@16: {}; Chris@16: Chris@16: template Chris@16: inline void print_token(Out& out, T const& val) Chris@16: { Chris@16: // allow to customize the token printer routine Chris@16: token_printer_debug::print(out, val); Chris@16: } Chris@16: }}} Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace result_of Chris@16: { Chris@16: template Chris@16: struct pre_transform Chris@16: : traits::transform_attribute Chris@16: {}; Chris@16: }}} Chris@16: Chris@16: Chris@16: #endif