blob: b4f9e3ffe047e580063d1c2379ae8070e6b93960 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2001-2011 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 <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/has_semantic_action.hpp>
#include <boost/spirit/home/support/attributes_fwd.hpp>
#include <boost/spirit/home/support/container.hpp>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <boost/spirit/home/support/detail/as_variant.hpp>
#include <boost/optional/optional.hpp>
#include <boost/fusion/include/transform.hpp>
#include <boost/fusion/include/filter_if.hpp>
#include <boost/fusion/include/as_vector.hpp>
#include <boost/fusion/include/push_front.hpp>
#include <boost/fusion/include/pop_front.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/is_view.hpp>
#include <boost/foreach.hpp>
#include <boost/utility/value_init.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/end.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/proto/proto_fwd.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/variant.hpp>
#include <boost/range/iterator_range.hpp>
#include <vector>
#include <utility>
///////////////////////////////////////////////////////////////////////////////
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 <typename T, typename Enable/* = void*/>
struct is_proxy : mpl::false_ {};
template <typename T>
struct is_proxy<T,
typename enable_if<
mpl::and_<
fusion::traits::is_sequence<T>,
fusion::traits::is_view<T>
>
>::type>
: mpl::true_ {};
template <typename T, typename Domain, typename Enable/* = void*/>
struct not_is_variant
: mpl::true_
{};
template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Domain>
struct not_is_variant<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Domain>
: mpl::false_
{};
template <typename T, typename Domain>
struct not_is_variant<boost::optional<T>, Domain>
: not_is_variant<T, Domain>
{};
// we treat every type as if it where the variant (as this meta function is
// invoked for variant types only)
template <typename T>
struct variant_type
: mpl::identity<T>
{};
template <typename T>
struct variant_type<boost::optional<T> >
: variant_type<T>
{};
///////////////////////////////////////////////////////////////////////////
// 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 <typename Expected, typename Attribute>
struct attribute_is_compatible
: is_convertible<Attribute, Expected>
{};
template <typename Expected, typename Attribute>
struct attribute_is_compatible<Expected, boost::optional<Attribute> >
: is_convertible<Attribute, Expected>
{};
template <typename Container>
struct is_hold_any_container
: is_same<hold_any, typename traits::container_value<Container>::type>
{};
}
template <typename Attribute, typename Expected
, typename IsNotVariant = mpl::false_, typename Enable = void>
struct compute_compatible_component_variant
: mpl::or_<
traits::detail::attribute_is_compatible<Expected, Attribute>
, is_same<hold_any, Expected>
, mpl::eval_if<
is_container<Expected>
, traits::detail::is_hold_any_container<Expected>
, mpl::false_> >
{};
namespace detail
{
BOOST_MPL_HAS_XXX_TRAIT_DEF(types)
}
template <typename Variant, typename Expected>
struct compute_compatible_component_variant<Variant, Expected, mpl::false_
, typename enable_if<detail::has_types<Variant> >::type>
{
typedef typename traits::variant_type<Variant>::type variant_type;
typedef typename variant_type::types types;
typedef typename mpl::end<types>::type end;
typedef typename
mpl::find_if<types, is_same<Expected, mpl::_1> >::type
iter;
typedef typename mpl::distance<
typename mpl::begin<types>::type, iter
>::type distance;
// true_ if the attribute matches one of the types in the variant
typedef typename mpl::not_<is_same<iter, end> >::type type;
enum { value = type::value };
// return the type in the variant the attribute is compatible with
typedef typename
mpl::eval_if<type, mpl::deref<iter>, mpl::identity<unused_type> >::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 <typename Expected, typename Attribute, typename Domain>
struct compute_compatible_component
: compute_compatible_component_variant<Attribute, Expected
, typename spirit::traits::not_is_variant<Attribute, Domain>::type> {};
template <typename Expected, typename Domain>
struct compute_compatible_component<Expected, unused_type, Domain>
: mpl::false_ {};
template <typename Attribute, typename Domain>
struct compute_compatible_component<unused_type, Attribute, Domain>
: mpl::false_ {};
template <typename Domain>
struct compute_compatible_component<unused_type, unused_type, Domain>
: mpl::false_ {};
///////////////////////////////////////////////////////////////////////////
// return the type currently stored in the given variant
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct variant_which<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
static int call(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& v)
{
return v.which();
}
};
template <typename T>
int which(T const& v)
{
return variant_which<T>::call(v);
}
///////////////////////////////////////////////////////////////////////////
template <typename T, typename Domain, typename Enable/* = void*/>
struct not_is_optional
: mpl::true_
{};
template <typename T, typename Domain>
struct not_is_optional<boost::optional<T>, Domain>
: mpl::false_
{};
///////////////////////////////////////////////////////////////////////////
// attribute_of
//
// Get the component's attribute
///////////////////////////////////////////////////////////////////////////
template <typename Component
, typename Context = unused_type, typename Iterator = unused_type>
struct attribute_of
{
typedef typename Component::template
attribute<Context, Iterator>::type type;
};
///////////////////////////////////////////////////////////////////////////
// attribute_not_unused
//
// An mpl meta-function class that determines whether a component's
// attribute is not unused.
///////////////////////////////////////////////////////////////////////////
template <typename Context, typename Iterator = unused_type>
struct attribute_not_unused
{
template <typename Component>
struct apply
: not_is_unused<typename
attribute_of<Component, Context, Iterator>::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 <typename Attribute, typename Enable/* = void*/>
struct attribute_type : mpl::identity<Attribute> {};
///////////////////////////////////////////////////////////////////////////
// Retrieve the size of a fusion sequence (compile time)
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct sequence_size
: fusion::result_of::size<T>
{};
template <>
struct sequence_size<unused_type>
: mpl::int_<0>
{};
///////////////////////////////////////////////////////////////////////////
// Retrieve the size of an attribute (runtime)
///////////////////////////////////////////////////////////////////////////
template <typename Attribute, typename Enable/* = void*/>
struct attribute_size
{
typedef std::size_t type;
static type call(Attribute const&)
{
return 1;
}
};
template <typename Attribute>
struct attribute_size<Attribute
, typename enable_if<
mpl::and_<
fusion::traits::is_sequence<Attribute>
, mpl::not_<traits::is_container<Attribute> >
>
>::type
> {
typedef typename fusion::result_of::size<Attribute>::value_type type;
static type call(Attribute const& attr)
{
return fusion::size(attr);
}
};
template <typename Attribute>
struct attribute_size<Attribute
, typename enable_if<
mpl::and_<
traits::is_container<Attribute>
, mpl::not_<traits::is_iterator_range<Attribute> >
>
>::type
> {
typedef typename Attribute::size_type type;
static type call(Attribute const& attr)
{
return attr.size();
}
};
template <typename Iterator>
struct attribute_size<iterator_range<Iterator> >
{
typedef typename boost::detail::iterator_traits<Iterator>::
difference_type type;
static type call(iterator_range<Iterator> const& r)
{
return boost::detail::distance(r.begin(), r.end());
}
};
template <>
struct attribute_size<unused_type>
{
typedef std::size_t type;
static type call(unused_type)
{
return 0;
}
};
template <typename Attribute>
typename attribute_size<Attribute>::type
size(Attribute const& attr)
{
return attribute_size<Attribute>::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 <typename Component, typename Attribute, typename Enable/* = void*/>
struct pass_attribute
{
typedef fusion::vector1<Attribute&> 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 <typename Attribute, typename Force = mpl::false_>
struct wrap_if_not_tuple
: mpl::if_<
fusion::traits::is_sequence<Attribute>
, Attribute&, fusion::vector1<Attribute&> >
{};
template <typename Attribute>
struct wrap_if_not_tuple<Attribute, mpl::true_>
{
typedef fusion::vector1<Attribute&> type;
};
template <>
struct wrap_if_not_tuple<unused_type, mpl::false_>
{
typedef unused_type type;
};
template <>
struct wrap_if_not_tuple<unused_type const, mpl::false_>
{
typedef unused_type type;
};
///////////////////////////////////////////////////////////////////////////
// build_optional
//
// Build a boost::optional from T. Return unused_type if T is unused_type.
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct build_optional
{
typedef optional<T> type;
};
template <>
struct build_optional<unused_type>
{
typedef unused_type type;
};
///////////////////////////////////////////////////////////////////////////
// build_std_vector
//
// Build a std::vector from T. Return unused_type if T is unused_type.
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct build_std_vector
{
typedef std::vector<T> type;
};
template <>
struct build_std_vector<unused_type>
{
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 <typename Sequence>
struct filter_unused_attributes
: fusion::result_of::filter_if<Sequence, not_is_unused<mpl::_> >
{};
///////////////////////////////////////////////////////////////////////////
// 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 <typename Attribute, typename Domain>
struct sequence_attribute_transform
: mpl::identity<Attribute>
{};
///////////////////////////////////////////////////////////////////////////
// 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 <typename Attribute, typename Domain>
struct permutation_attribute_transform
: traits::build_optional<Attribute>
{};
///////////////////////////////////////////////////////////////////////////
// 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 <typename Attribute, typename Domain>
struct sequential_or_attribute_transform
: traits::build_optional<Attribute>
{};
///////////////////////////////////////////////////////////////////////////
// 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 <typename Sequence>
struct build_fusion_vector
{
// Remove all unused attributes
typedef typename
filter_unused_attributes<Sequence>::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<filtered_attributes>
, mpl::identity<unused_type>
, fusion::result_of::as_vector<filtered_attributes>
>::type
type;
};
template <>
struct build_fusion_vector<unused_type>
{
typedef unused_type type;
};
///////////////////////////////////////////////////////////////////////////
// build_attribute_sequence
//
// Build a fusion sequence attribute sequence from a sequence of
// components. Transform<T>::type is called on each element.
///////////////////////////////////////////////////////////////////////////
template <typename Sequence, typename Context
, template <typename T, typename D> class Transform
, typename Iterator = unused_type, typename Domain = unused_type>
struct build_attribute_sequence
{
struct element_attribute
{
template <typename T>
struct result;
template <typename F, typename Element>
struct result<F(Element)>
{
typedef typename
Transform<
typename attribute_of<Element, Context, Iterator>::type
, Domain
>::type
type;
};
// never called, but needed for decltype-based result_of (C++0x)
template <typename Element>
typename result<element_attribute(Element)>::type
operator()(Element&) const;
};
// Compute the list of attributes of all sub-components
typedef typename
fusion::result_of::transform<Sequence, element_attribute>::type
type;
};
///////////////////////////////////////////////////////////////////////////
// has_no_unused
//
// Test if there are no unused attributes in Sequence
///////////////////////////////////////////////////////////////////////////
template <typename Sequence>
struct has_no_unused
: is_same<
typename mpl::find_if<Sequence, is_same<mpl::_, unused_type> >::type
, typename mpl::end<Sequence>::type>
{};
namespace detail
{
template <typename Sequence, bool no_unused
, int size = mpl::size<Sequence>::value>
struct build_collapsed_variant;
// N element case, no unused
template <typename Sequence, int size>
struct build_collapsed_variant<Sequence, true, size>
: spirit::detail::as_variant<Sequence> {};
// N element case with unused
template <typename Sequence, int size>
struct build_collapsed_variant<Sequence, false, size>
{
typedef optional<
typename spirit::detail::as_variant<
typename fusion::result_of::pop_front<Sequence>::type
>::type
> type;
};
// 1 element case, no unused
template <typename Sequence>
struct build_collapsed_variant<Sequence, true, 1>
: mpl::front<Sequence> {};
// 1 element case, with unused
template <typename Sequence>
struct build_collapsed_variant<Sequence, false, 1>
: mpl::front<Sequence> {};
// 2 element case, no unused
template <typename Sequence>
struct build_collapsed_variant<Sequence, true, 2>
: spirit::detail::as_variant<Sequence> {};
// 2 element case, with unused
template <typename Sequence>
struct build_collapsed_variant<Sequence, false, 2>
{
typedef optional<
typename mpl::deref<
typename mpl::next<
typename mpl::begin<Sequence>::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 <typename Attribute, typename Domain>
struct alternative_attribute_transform
: mpl::identity<Attribute>
{};
///////////////////////////////////////////////////////////////////////////
// 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<T> to T.
///////////////////////////////////////////////////////////////////////////
template <typename Sequence>
struct build_variant
{
// Remove all unused attributes.
typedef typename
filter_unused_attributes<Sequence>::type
filtered_attributes;
typedef has_no_unused<Sequence> 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<Sequence>,
fusion::result_of::push_front<filtered_attributes, unused_type>
>::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::_2>,
mpl::_1, mpl::push_back<mpl::_1, mpl::_2>
>
>::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<T> to T.
// Take note that this also collapses variant<unused_type, T> 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 <typename Exposed, typename Transformed, typename Domain
, typename Enable/* = void*/>
struct transform_attribute;
///////////////////////////////////////////////////////////////////////////
template <typename Domain, typename Transformed, typename Exposed>
typename spirit::result_of::pre_transform<Exposed, Transformed, Domain>::type
pre_transform(Exposed& attr BOOST_PROTO_DISABLE_IF_IS_CONST(Exposed))
{
return transform_attribute<Exposed, Transformed, Domain>::pre(attr);
}
template <typename Domain, typename Transformed, typename Exposed>
typename spirit::result_of::pre_transform<Exposed const, Transformed, Domain>::type
pre_transform(Exposed const& attr)
{
return transform_attribute<Exposed const, Transformed, Domain>::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 <typename Attribute, typename ActualAttribute>
struct make_attribute
{
typedef typename remove_const<Attribute>::type attribute_type;
typedef typename
mpl::if_<
is_same<typename remove_const<ActualAttribute>::type, unused_type>
, attribute_type
, ActualAttribute&>::type
type;
typedef typename
mpl::if_<
is_same<typename remove_const<ActualAttribute>::type, unused_type>
, attribute_type
, ActualAttribute>::type
value_type;
static Attribute call(unused_type)
{
// synthesize the attribute/parameter
return boost::get(value_initialized<attribute_type>());
}
template <typename T>
static T& call(T& value)
{
return value; // just pass the one provided
}
};
template <typename Attribute, typename ActualAttribute>
struct make_attribute<Attribute&, ActualAttribute>
: make_attribute<Attribute, ActualAttribute>
{};
template <typename Attribute, typename ActualAttribute>
struct make_attribute<Attribute const&, ActualAttribute>
: make_attribute<Attribute const, ActualAttribute>
{};
template <typename ActualAttribute>
struct make_attribute<unused_type, ActualAttribute>
{
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 <typename A, typename B>
void swap_impl(A& a, B& b)
{
A temp = a;
a = b;
b = temp;
}
template <typename T>
void swap_impl(T& a, T& b)
{
using namespace std;
swap(a, b);
}
template <typename A>
void swap_impl(A& a, unused_type)
{
}
template <typename A>
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> --> T
///////////////////////////////////////////////////////////////////////////
template <typename T>
struct strip_single_element_vector
{
typedef T type;
};
template <typename T>
struct strip_single_element_vector<fusion::vector1<T> >
{
typedef T type;
};
template <typename T>
struct strip_single_element_vector<fusion::vector<T> >
{
typedef T type;
};
///////////////////////////////////////////////////////////////////////////
// meta function to return whether the argument is a one element fusion
// sequence
///////////////////////////////////////////////////////////////////////////
template <typename T
, bool IsFusionSeq = fusion::traits::is_sequence<T>::value
, bool IsProtoExpr = proto::is_expr<T>::value>
struct one_element_sequence
: mpl::false_
{};
template <typename T>
struct one_element_sequence<T, true, false>
: mpl::bool_<mpl::size<T>::value == 1>
{};
///////////////////////////////////////////////////////////////////////////
// clear
//
// Clear data efficiently
///////////////////////////////////////////////////////////////////////////
template <typename T>
void clear(T& val);
namespace detail
{
// this is used by the variant and fusion sequence dispatch
struct clear_visitor : static_visitor<>
{
template <typename T>
void operator()(T& val) const
{
spirit::traits::clear(val);
}
};
// default
template <typename T>
void clear_impl2(T& val, mpl::false_)
{
val = T();
}
// for fusion sequences
template <typename T>
void clear_impl2(T& val, mpl::true_)
{
fusion::for_each(val, clear_visitor());
}
// dispatch default or fusion sequence
template <typename T>
void clear_impl(T& val, mpl::false_)
{
clear_impl2(val, fusion::traits::is_sequence<T>());
}
// STL containers
template <typename T>
void clear_impl(T& val, mpl::true_)
{
val.clear();
}
}
template <typename T, typename Enable/* = void*/>
struct clear_value
{
static void call(T& val)
{
detail::clear_impl(val, typename is_container<T>::type());
}
};
// optionals
template <typename T>
struct clear_value<optional<T> >
{
static void call(optional<T>& val)
{
if (val)
val = none_t(); // leave optional uninitialized
}
};
// variants
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct clear_value<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
static void call(variant<BOOST_VARIANT_ENUM_PARAMS(T)>& val)
{
apply_visitor(detail::clear_visitor(), val);
}
};
// iterator range
template <typename T>
struct clear_value<iterator_range<T> >
{
static void call(iterator_range<T>& val)
{
val = iterator_range<T>(val.end(), val.end());
}
};
// main dispatch
template <typename T>
void clear(T& val)
{
clear_value<T>::call(val);
}
// for unused
inline void clear(unused_type)
{
}
///////////////////////////////////////////////////////////////////////////
namespace detail
{
template <typename Out>
struct print_fusion_sequence
{
print_fusion_sequence(Out& out)
: out(out), is_first(true) {}
typedef void result_type;
template <typename T>
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 <typename Out>
struct print_visitor : static_visitor<>
{
print_visitor(Out& out) : out(out) {}
template <typename T>
void operator()(T const& val) const
{
spirit::traits::print_attribute(out, val);
}
Out& out;
};
}
template <typename Out, typename T, typename Enable>
struct print_attribute_debug
{
// for plain data types
template <typename T_>
static void call_impl3(Out& out, T_ const& val, mpl::false_)
{
out << val;
}
// for fusion data types
template <typename T_>
static void call_impl3(Out& out, T_ const& val, mpl::true_)
{
out << '[';
fusion::for_each(val, detail::print_fusion_sequence<Out>(out));
out << ']';
}
// non-stl container
template <typename T_>
static void call_impl2(Out& out, T_ const& val, mpl::false_)
{
call_impl3(out, val, fusion::traits::is_sequence<T_>());
}
// stl container
template <typename T_>
static void call_impl2(Out& out, T_ const& val, mpl::true_)
{
out << '[';
if (!traits::is_empty(val))
{
bool first = true;
typename container_iterator<T_ const>::type iend = traits::end(val);
for (typename container_iterator<T_ const>::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 <typename T_>
static void call_impl(Out& out, T_ const& val, mpl::false_)
{
apply_visitor(detail::print_visitor<Out>(out), val);
}
// for non-variant types
template <typename T_>
static void call_impl(Out& out, T_ const& val, mpl::true_)
{
call_impl2(out, val, is_container<T_>());
}
// main entry point
static void call(Out& out, T const& val)
{
call_impl(out, val, not_is_variant<T>());
}
};
template <typename Out, typename T>
struct print_attribute_debug<Out, boost::optional<T> >
{
static void call(Out& out, boost::optional<T> const& val)
{
if (val)
spirit::traits::print_attribute(out, *val);
else
out << "[empty]";
}
};
///////////////////////////////////////////////////////////////////////////
template <typename Out, typename T>
inline void print_attribute(Out& out, T const& val)
{
print_attribute_debug<Out, T>::call(out, val);
}
template <typename Out>
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<typename Out, typename Char>
static void print(Out& o, Char c)
{
using namespace std; // allow for ADL to find the proper iscntrl
if (c == static_cast<Char>('\a'))
o << "\\a";
else if (c == static_cast<Char>('\b'))
o << "\\b";
else if (c == static_cast<Char>('\f'))
o << "\\f";
else if (c == static_cast<Char>('\n'))
o << "\\n";
else if (c == static_cast<Char>('\r'))
o << "\\r";
else if (c == static_cast<Char>('\t'))
o << "\\t";
else if (c == static_cast<Char>('\v'))
o << "\\v";
else if (c < 127 && iscntrl(c))
o << "\\" << std::oct << static_cast<int>(c);
else
o << static_cast<char>(c);
}
};
// for token types where the comparison with char constants wouldn't work
struct token_printer_debug
{
template<typename Out, typename T>
static void print(Out& o, T const& val)
{
o << val;
}
};
}
template <typename T, typename Enable>
struct token_printer_debug
: mpl::if_<
mpl::and_<
is_convertible<T, char>, is_convertible<char, T> >
, detail::token_printer_debug_for_chars
, detail::token_printer_debug>::type
{};
template <typename Out, typename T>
inline void print_token(Out& out, T const& val)
{
// allow to customize the token printer routine
token_printer_debug<T>::print(out, val);
}
}}}
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit { namespace result_of
{
template <typename Exposed, typename Transformed, typename Domain>
struct pre_transform
: traits::transform_attribute<Exposed, Transformed, Domain>
{};
}}}
#endif