blob: 3ef8c83ae29a7c7edd4febb8a73fea76269bbff5 [file] [log] [blame]
/*=============================================================================
Copyright (c) 2001-2011 Joel de Guzman
Copyright (c) 2001-2011 Hartmut Kaiser
Copyright (c) 2011 Thomas Heller
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_TERMINAL_NOVEMBER_04_2008_0906AM)
#define BOOST_SPIRIT_TERMINAL_NOVEMBER_04_2008_0906AM
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/proto/proto.hpp>
#include <boost/fusion/include/void.hpp>
#include <boost/spirit/home/support/meta_compiler.hpp>
#include <boost/spirit/home/support/detail/make_vector.hpp>
#include <boost/spirit/home/support/unused.hpp>
#include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/spirit/home/support/terminal_expression.hpp>
namespace boost { namespace spirit
{
template <typename Terminal, typename Args>
struct terminal_ex
{
typedef Terminal terminal_type;
typedef Args args_type;
terminal_ex(Args const& args_)
: args(args_) {}
terminal_ex(Args const& args_, Terminal const& term_)
: args(args_), term(term_) {}
Args args; // Args is guaranteed to be a fusion::vectorN so you
// can use that template for detection and specialization
Terminal term;
};
template <typename Terminal, typename Actor, int Arity>
struct lazy_terminal
{
typedef Terminal terminal_type;
typedef Actor actor_type;
static int const arity = Arity;
lazy_terminal(Actor const& actor_)
: actor(actor_) {}
lazy_terminal(Actor const& actor_, Terminal const& term_)
: actor(actor_), term(term_) {}
Actor actor;
Terminal term;
};
template <typename Domain, typename Terminal, int Arity, typename Enable = void>
struct use_lazy_terminal : mpl::false_ {};
template <typename Domain, typename Terminal, int Arity, typename Enable = void>
struct use_lazy_directive : mpl::false_ {};
template <typename Terminal>
struct terminal;
template <typename Domain, typename Terminal>
struct use_terminal<Domain, terminal<Terminal> >
: use_terminal<Domain, Terminal> {};
template <typename Domain, typename Terminal, int Arity, typename Actor>
struct use_terminal<Domain, lazy_terminal<Terminal, Actor, Arity> >
: use_lazy_terminal<Domain, Terminal, Arity> {};
template <typename Domain, typename Terminal, int Arity, typename Actor>
struct use_directive<Domain, lazy_terminal<Terminal, Actor, Arity> >
: use_lazy_directive<Domain, Terminal, Arity> {};
template <
typename F
, typename A0 = unused_type
, typename A1 = unused_type
, typename A2 = unused_type
, typename Unused = unused_type
>
struct make_lazy;
template <typename F, typename A0>
struct make_lazy<F, A0>
{
typedef typename
proto::terminal<
lazy_terminal<
typename F::terminal_type
, typename phoenix::detail::expression::function_eval<F, A0>::type
, 1 // arity
>
>::type
result_type;
typedef result_type type;
result_type
operator()(F f, A0 const& _0_) const
{
typedef typename result_type::proto_child0 child_type;
return result_type::make(child_type(
phoenix::detail::expression::function_eval<F, A0>::make(f, _0_)
, f.proto_base().child0
));
}
};
template <typename F, typename A0, typename A1>
struct make_lazy<F, A0, A1>
{
typedef typename
proto::terminal<
lazy_terminal<
typename F::terminal_type
, typename phoenix::detail::expression::function_eval<F, A0, A1>::type
, 2 // arity
>
>::type
result_type;
typedef result_type type;
result_type
operator()(F f, A0 const& _0_, A1 const& _1_) const
{
typedef typename result_type::proto_child0 child_type;
return result_type::make(child_type(
phoenix::detail::expression::function_eval<F, A0, A1>::make(f, _0_, _1_)
, f.proto_base().child0
));
}
};
template <typename F, typename A0, typename A1, typename A2>
struct make_lazy<F, A0, A1, A2>
{
typedef typename
proto::terminal<
lazy_terminal<
typename F::terminal_type
, typename phoenix::detail::expression::function_eval<F, A0, A1, A2>::type
, 3 // arity
>
>::type
result_type;
typedef result_type type;
result_type
operator()(F f, A0 const& _0_, A1 const& _1_, A2 const& _2_) const
{
typedef typename result_type::proto_child0 child_type;
return result_type::make(child_type(
phoenix::detail::expression::function_eval<F, A0, A1, A2>::make(f, _0_, _1_, _2_)
, f.proto_base().child0
));
}
};
namespace detail
{
// Helper struct for SFINAE purposes
template <bool C> struct bool_;
template <>
struct bool_<true> : mpl::bool_<true>
{
typedef bool_<true>* is_true;
};
template <>
struct bool_<false> : mpl::bool_<false>
{
typedef bool_<false>* is_false;
};
// Metafunction to detect if at least one arg is a Phoenix actor
template <
typename A0
, typename A1 = unused_type
, typename A2 = unused_type
>
struct contains_actor
: bool_<
phoenix::is_actor<A0>::value
|| phoenix::is_actor<A1>::value
|| phoenix::is_actor<A2>::value
>
{};
// to_lazy_arg: convert a terminal arg type to the type make_lazy needs
template <typename A>
struct to_lazy_arg
: phoenix::as_actor<A> // wrap A in a Phoenix actor if not already one
{};
template <typename A>
struct to_lazy_arg<const A>
: to_lazy_arg<A>
{};
template <typename A>
struct to_lazy_arg<A &>
: to_lazy_arg<A>
{};
template <>
struct to_lazy_arg<unused_type>
{
// unused arg: make_lazy wants unused_type
typedef unused_type type;
};
// to_nonlazy_arg: convert a terminal arg type to the type make_vector needs
template <typename A>
struct to_nonlazy_arg
{
// identity
typedef A type;
};
template <typename A>
struct to_nonlazy_arg<const A>
: to_nonlazy_arg<A>
{};
template <typename A>
struct to_nonlazy_arg<A &>
: to_nonlazy_arg<A>
{};
template <>
struct to_nonlazy_arg<unused_type>
{
// unused arg: make_vector wants fusion::void_
typedef fusion::void_ type;
};
}
template <typename Terminal>
struct terminal
: proto::extends<
typename proto::terminal<Terminal>::type
, terminal<Terminal>
>
{
typedef terminal<Terminal> this_type;
typedef Terminal terminal_type;
typedef proto::extends<
typename proto::terminal<Terminal>::type
, terminal<Terminal>
> base_type;
terminal() {}
terminal(Terminal const& t)
: base_type(proto::terminal<Terminal>::type::make(t))
{}
template <
bool Lazy
, typename A0
, typename A1
, typename A2
>
struct result_helper;
template <
typename A0
, typename A1
, typename A2
>
struct result_helper<false, A0, A1, A2>
{
typedef typename
proto::terminal<
terminal_ex<
Terminal
, typename detail::result_of::make_vector<
typename detail::to_nonlazy_arg<A0>::type
, typename detail::to_nonlazy_arg<A1>::type
, typename detail::to_nonlazy_arg<A2>::type>::type>
>::type
type;
};
template <
typename A0
, typename A1
, typename A2
>
struct result_helper<true, A0, A1, A2>
{
typedef typename
make_lazy<this_type
, typename detail::to_lazy_arg<A0>::type
, typename detail::to_lazy_arg<A1>::type
, typename detail::to_lazy_arg<A2>::type>::type
type;
};
// FIXME: we need to change this to conform to the result_of protocol
template <
typename A0
, typename A1 = unused_type
, typename A2 = unused_type // Support up to 3 args
>
struct result
{
typedef typename
result_helper<
detail::contains_actor<A0, A1, A2>::value
, A0, A1, A2
>::type
type;
};
template <typename This, typename A0>
struct result<This(A0)>
{
typedef typename
result_helper<
detail::contains_actor<A0, unused_type, unused_type>::value
, A0, unused_type, unused_type
>::type
type;
};
template <typename This, typename A0, typename A1>
struct result<This(A0, A1)>
{
typedef typename
result_helper<
detail::contains_actor<A0, A1, unused_type>::value
, A0, A1, unused_type
>::type
type;
};
template <typename This, typename A0, typename A1, typename A2>
struct result<This(A0, A1, A2)>
{
typedef typename
result_helper<
detail::contains_actor<A0, A1, A2>::value
, A0, A1, A2
>::type
type;
};
// Note: in the following overloads, SFINAE cannot
// be done on return type because of gcc bug #24915:
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24915
// Hence an additional, fake argument is used for SFINAE,
// using a type which can never be a real argument type.
// Non-lazy overloads. Only enabled when all
// args are immediates (no Phoenix actor).
template <typename A0>
typename result<A0>::type
operator()(A0 const& _0_
, typename detail::contains_actor<A0>::is_false = 0) const
{
typedef typename result<A0>::type result_type;
typedef typename result_type::proto_child0 child_type;
return result_type::make(
child_type(
detail::make_vector(_0_)
, this->proto_base().child0)
);
}
template <typename A0, typename A1>
typename result<A0, A1>::type
operator()(A0 const& _0_, A1 const& _1_
, typename detail::contains_actor<A0, A1>::is_false = 0) const
{
typedef typename result<A0, A1>::type result_type;
typedef typename result_type::proto_child0 child_type;
return result_type::make(
child_type(
detail::make_vector(_0_, _1_)
, this->proto_base().child0)
);
}
template <typename A0, typename A1, typename A2>
typename result<A0, A1, A2>::type
operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
, typename detail::contains_actor<A0, A1, A2>::is_false = 0) const
{
typedef typename result<A0, A1, A2>::type result_type;
typedef typename result_type::proto_child0 child_type;
return result_type::make(
child_type(
detail::make_vector(_0_, _1_, _2_)
, this->proto_base().child0)
);
}
// Lazy overloads. Enabled when at
// least one arg is a Phoenix actor.
template <typename A0>
typename result<A0>::type
operator()(A0 const& _0_
, typename detail::contains_actor<A0>::is_true = 0) const
{
return make_lazy<this_type
, typename phoenix::as_actor<A0>::type>()(*this
, phoenix::as_actor<A0>::convert(_0_));
}
template <typename A0, typename A1>
typename result<A0, A1>::type
operator()(A0 const& _0_, A1 const& _1_
, typename detail::contains_actor<A0, A1>::is_true = 0) const
{
return make_lazy<this_type
, typename phoenix::as_actor<A0>::type
, typename phoenix::as_actor<A1>::type>()(*this
, phoenix::as_actor<A0>::convert(_0_)
, phoenix::as_actor<A1>::convert(_1_));
}
template <typename A0, typename A1, typename A2>
typename result<A0, A1, A2>::type
operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_
, typename detail::contains_actor<A0, A1, A2>::is_true = 0) const
{
return make_lazy<this_type
, typename phoenix::as_actor<A0>::type
, typename phoenix::as_actor<A1>::type
, typename phoenix::as_actor<A2>::type>()(*this
, phoenix::as_actor<A0>::convert(_0_)
, phoenix::as_actor<A1>::convert(_1_)
, phoenix::as_actor<A2>::convert(_2_));
}
private:
// silence MSVC warning C4512: assignment operator could not be generated
terminal& operator= (terminal const&);
};
///////////////////////////////////////////////////////////////////////////
namespace result_of
{
// Calculate the type of the compound terminal if generated by one of
// the spirit::terminal::operator() overloads above
// The terminal type itself is passed through without modification
template <typename Tag>
struct terminal
{
typedef spirit::terminal<Tag> type;
};
template <typename Tag, typename A0>
struct terminal<Tag(A0)>
{
typedef typename spirit::terminal<Tag>::
template result<A0>::type type;
};
template <typename Tag, typename A0, typename A1>
struct terminal<Tag(A0, A1)>
{
typedef typename spirit::terminal<Tag>::
template result<A0, A1>::type type;
};
template <typename Tag, typename A0, typename A1, typename A2>
struct terminal<Tag(A0, A1, A2)>
{
typedef typename spirit::terminal<Tag>::
template result<A0, A1, A2>::type type;
};
}
///////////////////////////////////////////////////////////////////////////
// support for stateful tag types
namespace tag
{
template <
typename Data, typename Tag
, typename DataTag1 = unused_type, typename DataTag2 = unused_type>
struct stateful_tag
{
BOOST_SPIRIT_IS_TAG()
typedef Data data_type;
stateful_tag() {}
stateful_tag(data_type const& data) : data_(data) {}
data_type data_;
private:
// silence MSVC warning C4512: assignment operator could not be generated
stateful_tag& operator= (stateful_tag const&);
};
}
template <
typename Data, typename Tag
, typename DataTag1 = unused_type, typename DataTag2 = unused_type>
struct stateful_tag_type
: spirit::terminal<tag::stateful_tag<Data, Tag, DataTag1, DataTag2> >
{
typedef tag::stateful_tag<Data, Tag, DataTag1, DataTag2> tag_type;
stateful_tag_type() {}
stateful_tag_type(Data const& data)
: spirit::terminal<tag_type>(data)
{}
private:
// silence MSVC warning C4512: assignment operator could not be generated
stateful_tag_type& operator= (stateful_tag_type const&);
};
namespace detail
{
// extract expression if this is a Tag
template <typename StatefulTag>
struct get_stateful_data
{
typedef typename StatefulTag::data_type data_type;
// is invoked if given tag is != Tag
template <typename Tag_>
static data_type call(Tag_) { return data_type(); }
// this is invoked if given tag is same as'Tag'
static data_type const& call(StatefulTag const& t) { return t.data_; }
};
}
}}
namespace boost { namespace phoenix
{
template <typename Tag>
struct is_custom_terminal<Tag, typename Tag::is_spirit_tag>
: mpl::true_
{};
template <typename Tag>
struct custom_terminal<Tag, typename Tag::is_spirit_tag>
{
#ifndef BOOST_PHOENIX_NO_SPECIALIZE_CUSTOM_TERMINAL
typedef void _is_default_custom_terminal; // fix for #7730
#endif
typedef spirit::terminal<Tag> result_type;
template <typename Context>
result_type operator()(Tag const & t, Context const &)
{
return spirit::terminal<Tag>(t);
}
};
}}
// Define a spirit terminal. This macro may be placed in any namespace.
// Common placeholders are placed in the main boost::spirit namespace
// (see common_terminals.hpp)
#define BOOST_SPIRIT_TERMINAL_X(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_Y
#define BOOST_SPIRIT_TERMINAL_Y(x, y) ((x, y)) BOOST_SPIRIT_TERMINAL_X
#define BOOST_SPIRIT_TERMINAL_X0
#define BOOST_SPIRIT_TERMINAL_Y0
#ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
#define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \
namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
typedef boost::proto::terminal<tag::name>::type type_name; \
type_name const name = {{}}; \
inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
/***/
#else
#define BOOST_SPIRIT_TERMINAL_NAME(name, type_name) \
namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
typedef boost::proto::terminal<tag::name>::type type_name; \
/***/
#endif
#define BOOST_SPIRIT_TERMINAL(name) \
BOOST_SPIRIT_TERMINAL_NAME(name, name ## _type) \
/***/
#define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A(r, _, names) \
BOOST_SPIRIT_TERMINAL_NAME( \
BOOST_PP_TUPLE_ELEM(2, 0, names), \
BOOST_PP_TUPLE_ELEM(2, 1, names) \
) \
/***/
#define BOOST_SPIRIT_DEFINE_TERMINALS_NAME(seq) \
BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_A, _, \
BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \
/***/
// Define a spirit extended terminal. This macro may be placed in any namespace.
// Common placeholders are placed in the main boost::spirit namespace
// (see common_terminals.hpp)
#ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
#define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \
namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
typedef boost::spirit::terminal<tag::name> type_name; \
type_name const name = type_name(); \
inline void BOOST_PP_CAT(silence_unused_warnings_, name)() { (void) name; } \
/***/
#else
#define BOOST_SPIRIT_TERMINAL_NAME_EX(name, type_name) \
namespace tag { struct name { BOOST_SPIRIT_IS_TAG() }; } \
typedef boost::spirit::terminal<tag::name> type_name; \
/***/
#endif
#define BOOST_SPIRIT_TERMINAL_EX(name) \
BOOST_SPIRIT_TERMINAL_NAME_EX(name, name ## _type) \
/***/
#define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A(r, _, names) \
BOOST_SPIRIT_TERMINAL_NAME_EX( \
BOOST_PP_TUPLE_ELEM(2, 0, names), \
BOOST_PP_TUPLE_ELEM(2, 1, names) \
) \
/***/
#define BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX(seq) \
BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_NAME_EX_A, _, \
BOOST_PP_CAT(BOOST_SPIRIT_TERMINAL_X seq, 0)) \
/***/
#endif