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