/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman Copyright (c) 2001-2011 Hartmut Kaiser Copyright (c) 2010-2011 Bryce Lelbach 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_OUTPUT_UTREE_TRAITS_APR_16_2010_0655AM) #define BOOST_SPIRIT_OUTPUT_UTREE_TRAITS_APR_16_2010_0655AM #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace boost { template inline T get(boost::spirit::utree const& x) { return x.get(); } } /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace traits { namespace detail { inline bool is_list(utree const& ut) { switch (traits::which(ut)) { case utree_type::reference_type: return is_list(ut.deref()); case utree_type::list_type: case utree_type::range_type: return true; default: break; } return false; } inline bool is_uninitialized(utree const& ut) { return traits::which(ut) == utree_type::invalid_type; } } // this specialization tells Spirit how to extract the type of the value // stored in the given utree node template <> struct variant_which { static int call(utree const& u) { return u.which(); } }; template <> struct variant_which { static int call(utree::list_type const& u) { return u.which(); } }; /////////////////////////////////////////////////////////////////////////// // Make sure all components of an alternative expose utree, even if they // actually expose a utree::list_type template struct alternative_attribute_transform : mpl::identity {}; /////////////////////////////////////////////////////////////////////////// // Make sure all components of a sequence expose utree, even if they // actually expose a utree::list_type template struct sequence_attribute_transform : mpl::identity {}; /////////////////////////////////////////////////////////////////////////// // this specialization lets Spirit know that typed basic_strings // are strings template struct is_string > : mpl::true_ {}; /////////////////////////////////////////////////////////////////////////// // these specializations extract the character type of a utree typed string template struct char_type_of, I> > : char_type_of {}; template struct char_type_of > : mpl::identity {}; /////////////////////////////////////////////////////////////////////////// // these specializations extract a c string from a utree typed string template struct extract_c_string; template struct extract_c_string< spirit::basic_string, I> > { typedef T char_type; typedef spirit::basic_string, I> string; static T const* call (string& s) { return s.begin(); } static T const* call (string const& s) { return s.begin(); } }; template struct extract_c_string > { typedef char char_type; typedef spirit::basic_string string; static char const* call (string& s) { return s.c_str(); } static char const* call (string const& s) { return s.c_str(); } }; /////////////////////////////////////////////////////////////////////////// // these specializations are needed because utree::value_type == utree template <> struct is_substitute : mpl::true_ {}; template <> struct is_weak_substitute : mpl::true_ {}; template <> struct is_substitute : mpl::true_ {}; template <> struct is_weak_substitute : mpl::true_ {}; /////////////////////////////////////////////////////////////////////////// // this specialization tells Spirit.Qi to allow assignment to an utree from // a variant namespace detail { struct assign_to_utree_visitor : static_visitor<> { assign_to_utree_visitor(utree& ut) : ut_(ut) {} template void operator()(T& val) const { ut_ = val; } utree& ut_; }; } template struct assign_to_container_from_value< utree, variant > { static void call(variant const& val, utree& attr) { apply_visitor(detail::assign_to_utree_visitor(attr), val); } }; /////////////////////////////////////////////////////////////////////////// // this specialization tells Spirit.Qi to allow assignment to an utree from // a STL container template struct assign_to_container_from_value { // any non-container type will be either directly assigned or appended static void call(Attribute const& val, utree& attr, mpl::false_) { if (attr.empty()) attr = val; else push_back(attr, val); } // any container type will be converted into a list_type utree static void call(Attribute const& val, utree& attr, mpl::true_) { typedef typename traits::container_iterator::type iterator_type; // make sure the attribute is a list, at least an empty one if (attr.empty()) attr = empty_list; iterator_type end = traits::end(val); for (iterator_type i = traits::begin(val); i != end; traits::next(i)) push_back(attr, traits::deref(i)); } static void call(Attribute const& val, utree& attr) { call(val, attr, is_container()); } }; /////////////////////////////////////////////////////////////////////////// // this specialization is required to disambiguate the specializations // related to utree template <> struct assign_to_container_from_value { static void call(utree const& val, utree& attr) { if (attr.empty()) { attr = val; } else if (detail::is_list(val)) { typedef utree::const_iterator iterator_type; iterator_type end = traits::end(val); for (iterator_type i = traits::begin(val); i != end; traits::next(i)) push_back(attr, traits::deref(i)); } else { push_back(attr, val); } } }; template <> struct assign_to_container_from_value : assign_to_container_from_value {}; // If the destination is a utree_list, we need to force the right hand side // value into a new sub-node, always, no questions asked. template <> struct assign_to_container_from_value { static void call(utree const& val, utree& attr) { push_back(attr, val); } }; // If both, the right hand side and the left hand side are utree_lists // we have a lhs rule which has a single rule exposing a utree_list as its // rhs (optionally wrapped into a directive or other unary parser). In this // case we do not create a new sub-node. template <> struct assign_to_container_from_value : assign_to_container_from_value {}; /////////////////////////////////////////////////////////////////////////// // this specialization makes sure strings get assigned as a whole and are // not converted into a utree list template <> struct assign_to_container_from_value { static void call(utf8_string_type const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; // this specialization keeps symbols from being transformed into strings template<> struct assign_to_container_from_value { static void call (utf8_symbol_type const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; template <> struct assign_to_container_from_value { static void call(binary_string_type const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; template<> struct assign_to_container_from_value { static void call (utf8_symbol_range_type const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; template <> struct assign_to_container_from_value { static void call(binary_range_type const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; template <> struct assign_to_container_from_value { static void call(std::string const& val, utree& attr) { if (attr.empty()) attr = val; else push_back(attr, val); } }; /////////////////////////////////////////////////////////////////////////// // this specialization tells Spirit.Qi to allow assignment to an utree from // generic iterators template struct assign_to_attribute_from_iterators { static void call(Iterator const& first, Iterator const& last, utree& attr) { if (attr.empty()) attr.assign(first, last); else { for (Iterator i = first; i != last; ++i) push_back(attr, traits::deref(i)); } } }; /////////////////////////////////////////////////////////////////////////// // Karma only: convert utree node to string namespace detail { struct attribute_as_string_type { typedef utf8_string_range_type type; static type call(utree const& attr) { return boost::get(attr); } static bool is_valid(utree const& attr) { switch (traits::which(attr)) { case utree_type::reference_type: return is_valid(attr.deref()); case utree_type::string_range_type: case utree_type::string_type: return true; default: return false; } } }; } template <> struct attribute_as : detail::attribute_as_string_type {}; template <> struct attribute_as : detail::attribute_as_string_type {}; template <> struct attribute_as : detail::attribute_as_string_type {}; /////////////////////////////////////////////////////////////////////////// namespace detail { struct attribute_as_symbol_type { typedef utf8_symbol_range_type type; static type call(utree const& attr) { return boost::get(attr); } static bool is_valid(utree const& attr) { switch (traits::which(attr)) { case utree_type::reference_type: return is_valid(attr.deref()); case utree_type::symbol_type: return true; default: return false; } } }; } template <> struct attribute_as : detail::attribute_as_symbol_type {}; template <> struct attribute_as : detail::attribute_as_symbol_type {}; template struct attribute_as : attribute_as {}; /////////////////////////////////////////////////////////////////////////// namespace detail { struct attribute_as_binary_string_type { typedef binary_range_type type; static type call(utree const& attr) { return boost::get(attr); } static bool is_valid(utree const& attr) { switch (traits::which(attr)) { case utree_type::reference_type: return is_valid(attr.deref()); case utree_type::binary_type: return true; default: return false; } } }; } template <> struct attribute_as : detail::attribute_as_binary_string_type {}; template <> struct attribute_as : detail::attribute_as_binary_string_type {}; /////////////////////////////////////////////////////////////////////////// // push_back support for utree template struct push_back_container { static bool call(utree& c, T const& val) { switch (traits::which(c)) { case utree_type::invalid_type: case utree_type::nil_type: case utree_type::list_type: c.push_back(val); break; default: { utree ut; ut.push_back(c); ut.push_back(val); c.swap(ut); } break; } return true; } }; template struct push_back_container : push_back_container {}; /////////////////////////////////////////////////////////////////////////// // ensure the utree attribute is an empty list template <> struct make_container_attribute { static void call(utree& ut) { if (!detail::is_list(ut)) { if (detail::is_uninitialized(ut)) ut = empty_list; else { utree retval (empty_list); retval.push_back(ut); ut.swap(retval); } } } }; template <> struct make_container_attribute : make_container_attribute {}; /////////////////////////////////////////////////////////////////////////// // an utree is a container on its own template <> struct build_std_vector { typedef utree type; }; template <> struct build_std_vector { typedef utree::list_type type; }; /////////////////////////////////////////////////////////////////////////// // debug support for utree template struct print_attribute_debug { static void call(Out& out, utree const& val) { out << val; } }; /////////////////////////////////////////////////////////////////////////// // force utree list attribute in a sequence to be dereferenced if a rule // or a grammar exposes an utree as it's attribute namespace detail { // Checks whether the exposed Attribute allows to handle utree or // utree::list_type directly. Returning mpl::false_ from this meta // function will force a new utree instance to be created for each // invocation of the embedded parser. // The purpose of using utree::list_type as an attribute is to force a // new sub-node in the result. template struct handles_utree_list_container : mpl::and_< mpl::not_ >, traits::is_container > {}; // The following specializations make sure that the actual handling of // an utree (or utree::list_type) attribute is deferred to the embedded // parsers of a sequence, alternative or optional component. template struct handles_utree_list_container >::type> : mpl::true_ {}; template struct handles_utree_list_container > : mpl::true_ {}; template struct handles_utree_list_container< boost::variant > : mpl::true_ {}; } template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree, Context, IteratorB> : detail::handles_utree_list_container, Context, IteratorB >::type> {}; template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree, Context, IteratorB> : detail::handles_utree_list_container, Context, IteratorB >::type> {}; template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree::list_type, Context, IteratorB> : detail::handles_utree_list_container, Context, IteratorB >::type> {}; template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree::list_type, Context, IteratorB> : detail::handles_utree_list_container, Context, IteratorB >::type> {}; /////////////////////////////////////////////////////////////////////////// template struct pass_through_container< utree, utree, Attribute, Sequence, qi::domain> : detail::handles_utree_list_container {}; template struct pass_through_container< utree::list_type, utree, Attribute, Sequence, qi::domain> : detail::handles_utree_list_container {}; /////////////////////////////////////////////////////////////////////////// namespace detail { // Checks whether the exposed Attribute allows to handle utree or // utree::list_type directly. Returning mpl::false_ from this meta // function will force a new utree instance to be created for each // invocation of the embedded parser. // The purpose of using utree::list_type as an attribute is to force a // new sub-node in the result. template struct handles_utree_container : mpl::and_< mpl::not_ >, traits::is_container > {}; // The following specializations make sure that the actual handling of // an utree (or utree::list_type) attribute is deferred to the embedded // parsers of a sequence, alternative or optional component. template struct handles_utree_container >::type> : mpl::true_ {}; template struct handles_utree_container > : mpl::true_ {}; template struct handles_utree_container< boost::variant > : mpl::true_ {}; } template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree, Context, IteratorB> : detail::handles_utree_container, Context, IteratorB >::type> {}; template < typename IteratorA, typename IteratorB, typename Context , typename T1, typename T2, typename T3, typename T4> struct handles_container , utree, Context, IteratorB> : detail::handles_utree_container, Context, IteratorB >::type> {}; /////////////////////////////////////////////////////////////////////////// template struct pass_through_container< utree, utree, Attribute, Sequence, karma::domain> : detail::handles_utree_container {}; /////////////////////////////////////////////////////////////////////////// // the specialization below tells Spirit how to handle utree if it is used // with an optional component template <> struct optional_attribute { typedef utree const& type; static type call(utree const& val) { return val; } // only 'invalid_type' utree nodes are not valid static bool is_valid(utree const& val) { return !detail::is_uninitialized(val); } }; template <> struct build_optional { typedef utree type; }; template <> struct build_optional { typedef utree::list_type type; }; // an utree is an optional (in any domain) template <> struct not_is_optional : mpl::false_ {}; template <> struct not_is_optional : mpl::false_ {}; template <> struct not_is_optional : mpl::false_ {}; template <> struct not_is_optional : mpl::false_ {}; /////////////////////////////////////////////////////////////////////////// // the specialization below tells Spirit to handle utree as if it // where a 'real' variant (in the context of karma) template <> struct not_is_variant : mpl::false_ {}; template <> struct not_is_variant : mpl::false_ {}; // The specializations below tell Spirit to verify whether an attribute // type is compatible with a given variant type template <> struct compute_compatible_component_variant< utree, iterator_range > : mpl::true_ { typedef iterator_range compatible_type; static bool is_compatible(int d) { return d == utree_type::list_type; } }; template <> struct compute_compatible_component_variant< utree, iterator_range > : mpl::true_ { typedef iterator_range compatible_type; static bool is_compatible(int d) { return d == utree_type::list_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef utree::invalid_type compatible_type; static bool is_compatible(int d) { return d == utree_type::invalid_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef utree::nil_type compatible_type; static bool is_compatible(int d) { return d == utree_type::nil_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef bool compatible_type; static bool is_compatible(int d) { return d == utree_type::bool_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef int compatible_type; static bool is_compatible(int d) { return d == utree_type::int_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef double compatible_type; static bool is_compatible(int d) { return d == utree_type::double_type; } }; template <> struct compute_compatible_component_variant< utree, utf8_string_range_type> : mpl::true_ { typedef utf8_string_range_type compatible_type; static bool is_compatible(int d) { return d == utree_type::string_type; } }; template <> struct compute_compatible_component_variant< utree, utf8_string_type> : mpl::true_ { typedef utf8_string_type compatible_type; static bool is_compatible(int d) { return d == utree_type::string_type; } }; template <> struct compute_compatible_component_variant< utree, utf8_symbol_range_type> : mpl::true_ { typedef utf8_symbol_range_type compatible_type; static bool is_compatible(int d) { return d == utree_type::symbol_type; } }; template <> struct compute_compatible_component_variant< utree, utf8_symbol_type> : mpl::true_ { typedef utf8_symbol_type compatible_type; static bool is_compatible(int d) { return d == utree_type::symbol_type; } }; template <> struct compute_compatible_component_variant< utree, binary_range_type> : mpl::true_ { typedef binary_range_type compatible_type; static bool is_compatible(int d) { return d == utree_type::binary_type; } }; template <> struct compute_compatible_component_variant< utree, binary_string_type> : mpl::true_ { typedef binary_string_type compatible_type; static bool is_compatible(int d) { return d == utree_type::binary_type; } }; template <> struct compute_compatible_component_variant : mpl::true_ { typedef utree compatible_type; static bool is_compatible(int d) { return d >= utree_type::invalid_type && d <= utree_type::reference_type; } }; template <> struct compute_compatible_component_variant< utree, std::vector > : mpl::true_ { typedef utree compatible_type; static bool is_compatible(int d) { return d >= utree_type::invalid_type && d <= utree_type::reference_type; } }; template struct compute_compatible_component_variant >::type> : mpl::true_ { typedef iterator_range compatible_type; static bool is_compatible(int d) { return d == utree_type::list_type; } }; template struct compute_compatible_component_variant : compute_compatible_component_variant {}; /////////////////////////////////////////////////////////////////////////// template <> struct symbols_lookup { typedef std::string type; static type call(utree const& t) { utf8_symbol_range_type r = boost::get(t); return std::string(traits::begin(r), traits::end(r)); } }; template <> struct symbols_lookup { typedef std::string type; static type call(utf8_symbol_type const& t) { return t; } }; /////////////////////////////////////////////////////////////////////////// namespace detail { template inline T get_or_deref(utree const& t) { if (detail::is_list(t)) return boost::get(t.front()); return boost::get(t); } } template <> struct extract_from_container { typedef utree::nil_type type; template static type call(utree const&, Context&) { return nil; } }; template <> struct extract_from_container { typedef char type; template static type call(utree const& t, Context&) { utf8_symbol_range_type r = detail::get_or_deref(t); return r.front(); } }; template <> struct extract_from_container { typedef bool type; template static type call(utree const& t, Context&) { return detail::get_or_deref(t); } }; template <> struct extract_from_container { typedef int type; template static type call(utree const& t, Context&) { return detail::get_or_deref(t); } }; template <> struct extract_from_container { typedef double type; template static type call(utree const& t, Context&) { return detail::get_or_deref(t); } }; template struct extract_from_container > { typedef std::basic_string type; template static type call(utree const& t, Context&) { utf8_string_range_type r = detail::get_or_deref(t); return type(traits::begin(r), traits::end(r)); } }; template <> struct extract_from_container { typedef std::string type; template static type call(utree const& t, Context&) { utf8_symbol_range_type r = detail::get_or_deref(t); return std::string(traits::begin(r), traits::end(r)); } }; template <> struct extract_from_container { typedef std::string type; template static type call(utree const& t, Context&) { utf8_string_range_type r = detail::get_or_deref(t); return std::string(traits::begin(r), traits::end(r)); } }; /////////////////////////////////////////////////////////////////////////// template <> struct transform_attribute { typedef utree::nil_type type; static type pre(utree const&) { return nil; } }; template <> struct transform_attribute { typedef char type; static type pre(utree const& t) { utf8_string_range_type r = detail::get_or_deref(t); return r.front(); } }; template <> struct transform_attribute { typedef bool type; static type pre(utree const& t) { return detail::get_or_deref(t); } }; template <> struct transform_attribute { typedef int type; static type pre(utree const& t) { return detail::get_or_deref(t); } }; template <> struct transform_attribute { typedef double type; static type pre(utree const& t) { return detail::get_or_deref(t); } }; template struct transform_attribute< utree const, std::basic_string, karma::domain> { typedef std::basic_string type; static type pre(utree const& t) { utf8_string_range_type r = detail::get_or_deref(t); return type(traits::begin(r), traits::end(r)); } }; // this specialization is used whenever a utree is passed to a rule as part // of a sequence template struct transform_attribute< iterator_range const, utree, karma::domain> { typedef utree type; static type pre(iterator_range const& t) { // return utree the begin iterator points to Iterator it = boost::begin(t); utree result(boost::ref(*it)); ++it; return result; } }; /////////////////////////////////////////////////////////////////////////// template <> struct transform_attribute { typedef std::string type; static type pre(utree const& t) { utf8_string_range_type r = detail::get_or_deref(t); return std::string(traits::begin(r), traits::end(r)); } }; template <> struct transform_attribute { typedef std::string type; static type pre(utree const& t) { utf8_symbol_range_type r = detail::get_or_deref(t); return std::string(traits::begin(r), traits::end(r)); } }; template struct transform_attribute : transform_attribute {}; }}} #endif