You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
655 lines
21 KiB
655 lines
21 KiB
/*============================================================================= |
|
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_; } |
|
}; |
|
} |
|
|
|
}} |
|
|
|
#ifdef BOOST_SPIRIT_USE_PHOENIX_V3 |
|
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> |
|
{ |
|
typedef spirit::terminal<Tag> result_type; |
|
|
|
template <typename Context> |
|
result_type operator()(Tag const & t, Context const &) |
|
{ |
|
return spirit::terminal<Tag>(t); |
|
} |
|
}; |
|
}} |
|
#endif |
|
|
|
// 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 |
|
|
|
|
|
|