/*============================================================================= Copyright (c) 2001-2010 Joel de Guzman Copyright (c) 2001-2010 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 /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { /////////////////////////////////////////////////////////////////////////// // This file deals with attribute related functions and meta-functions // including generalized attribute transformation utilities for Spirit // components. /////////////////////////////////////////////////////////////////////////// template struct is_proxy : mpl::false_ {}; template struct is_proxy, fusion::traits::is_view > >::type> : mpl::true_ {}; template struct not_is_variant : mpl::true_ {}; 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 : is_same::type> {}; } template struct compute_compatible_component_variant : mpl::or_< traits::detail::attribute_is_compatible , is_same , 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 {}; /////////////////////////////////////////////////////////////////////////// // 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 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 > {}; /////////////////////////////////////////////////////////////////////////// // 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> struct build_attribute_sequence { struct element_attribute { template struct result; template struct result { typedef typename Transform< typename attribute_of::type >::type type; }; // never called, but needed for decltype-based result_of (C++0x) template typename result::type operator()(Element&) const; }; // 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 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 optional< typename mpl::deref< typename mpl::next< typename mpl::begin::type >::type >::type > type; }; } /////////////////////////////////////////////////////////////////////////// // 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. /////////////////////////////////////////////////////////////////////////// template struct make_attribute { typedef typename mpl::if_< is_same::type, unused_type> , typename remove_const::type , ActualAttribute&>::type type; typedef typename mpl::if_< is_same::type, unused_type> , typename remove_const::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) { using namespace std; swap(a, b); } template void swap_impl(A& a, unused_type) { } template void swap_impl(unused_type, A& 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; }; template struct strip_single_element_vector > { typedef T type; }; template struct strip_single_element_vector > { typedef T type; }; /////////////////////////////////////////////////////////////////////////// // meta function to return whether the argument is a one element fusion // sequence /////////////////////////////////////////////////////////////////////////// template ::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(optional& val) { if (val) val = none_t(); // 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& 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 < 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