/*============================================================================= 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