/*============================================================================= 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 #include #include #include #include #include #include #include #include #include // includes as_actor specialization #include #include #include #include namespace boost { namespace spirit { template 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 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 struct use_lazy_terminal : mpl::false_ {}; template struct use_lazy_directive : mpl::false_ {}; template struct terminal; template struct use_terminal > : use_terminal {}; template struct use_terminal > : use_lazy_terminal {}; template struct use_directive > : use_lazy_directive {}; template < typename F , typename A0 = unused_type , typename A1 = unused_type , typename A2 = unused_type , typename Unused = unused_type > struct make_lazy; template struct make_lazy { typedef typename proto::terminal< lazy_terminal< typename F::terminal_type , typename phoenix::detail::expression::function_eval::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::make(f, _0_) , f.proto_base().child0 )); } }; template struct make_lazy { typedef typename proto::terminal< lazy_terminal< typename F::terminal_type , typename phoenix::detail::expression::function_eval::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::make(f, _0_, _1_) , f.proto_base().child0 )); } }; template struct make_lazy { typedef typename proto::terminal< lazy_terminal< typename F::terminal_type , typename phoenix::detail::expression::function_eval::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::make(f, _0_, _1_, _2_) , f.proto_base().child0 )); } }; namespace detail { // Helper struct for SFINAE purposes template struct bool_; template <> struct bool_ : mpl::bool_ { typedef bool_* is_true; }; template <> struct bool_ : mpl::bool_ { typedef bool_* 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::value || phoenix::is_actor::value || phoenix::is_actor::value > {}; // to_lazy_arg: convert a terminal arg type to the type make_lazy needs template struct to_lazy_arg : phoenix::as_actor // wrap A in a Phoenix actor if not already one {}; template struct to_lazy_arg : to_lazy_arg {}; template struct to_lazy_arg : to_lazy_arg {}; template <> struct to_lazy_arg { // 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 struct to_nonlazy_arg { // identity typedef A type; }; template struct to_nonlazy_arg : to_nonlazy_arg {}; template struct to_nonlazy_arg : to_nonlazy_arg {}; // incomplete type: should not be appeared unused_type in nonlazy arg. template <> struct to_nonlazy_arg; } template struct terminal : proto::extends< typename proto::terminal::type , terminal > { typedef terminal this_type; typedef Terminal terminal_type; typedef proto::extends< typename proto::terminal::type , terminal > base_type; terminal() {} terminal(Terminal const& t) : base_type(proto::terminal::type::make(t)) {} #if defined(BOOST_MSVC) #pragma warning(push) // warning C4348: 'boost::spirit::terminal<...>::result_helper': redefinition of default parameter: parameter 3, 4 #pragma warning(disable: 4348) #endif template < bool Lazy , typename A0 , typename A1 = unused_type , typename A2 = unused_type > struct result_helper; #if defined(BOOST_MSVC) #pragma warning(pop) #endif template < typename A0 > struct result_helper { typedef typename proto::terminal< terminal_ex< Terminal , typename detail::result_of::make_vector< typename detail::to_nonlazy_arg::type>::type> >::type type; }; template < typename A0 , typename A1 > struct result_helper { typedef typename proto::terminal< terminal_ex< Terminal , typename detail::result_of::make_vector< typename detail::to_nonlazy_arg::type , typename detail::to_nonlazy_arg::type>::type> >::type type; }; template < typename A0 , typename A1 , typename A2 > struct result_helper { typedef typename proto::terminal< terminal_ex< Terminal , typename detail::result_of::make_vector< typename detail::to_nonlazy_arg::type , typename detail::to_nonlazy_arg::type , typename detail::to_nonlazy_arg::type>::type> >::type type; }; template < typename A0 , typename A1 , typename A2 > struct result_helper { typedef typename make_lazy::type , typename detail::to_lazy_arg::type , typename detail::to_lazy_arg::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::value , A0, A1, A2 >::type type; }; template struct result { typedef typename result_helper< detail::contains_actor::value , A0, unused_type, unused_type >::type type; }; template struct result { typedef typename result_helper< detail::contains_actor::value , A0, A1, unused_type >::type type; }; template struct result { typedef typename result_helper< detail::contains_actor::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 result::type operator()(A0 const& _0_ , typename detail::contains_actor::is_false = 0) const { typedef typename result::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 result::type operator()(A0 const& _0_, A1 const& _1_ , typename detail::contains_actor::is_false = 0) const { typedef typename result::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 result::type operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ , typename detail::contains_actor::is_false = 0) const { typedef typename result::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 result::type operator()(A0 const& _0_ , typename detail::contains_actor::is_true = 0) const { return make_lazy::type>()(*this , phoenix::as_actor::convert(_0_)); } template typename result::type operator()(A0 const& _0_, A1 const& _1_ , typename detail::contains_actor::is_true = 0) const { return make_lazy::type , typename phoenix::as_actor::type>()(*this , phoenix::as_actor::convert(_0_) , phoenix::as_actor::convert(_1_)); } template typename result::type operator()(A0 const& _0_, A1 const& _1_, A2 const& _2_ , typename detail::contains_actor::is_true = 0) const { return make_lazy::type , typename phoenix::as_actor::type , typename phoenix::as_actor::type>()(*this , phoenix::as_actor::convert(_0_) , phoenix::as_actor::convert(_1_) , phoenix::as_actor::convert(_2_)); } // silence MSVC warning C4512: assignment operator could not be generated BOOST_DELETED_FUNCTION(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 struct terminal { typedef spirit::terminal type; }; template struct terminal { typedef typename spirit::terminal:: template result::type type; }; template struct terminal { typedef typename spirit::terminal:: template result::type type; }; template struct terminal { typedef typename spirit::terminal:: template result::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_; // silence MSVC warning C4512: assignment operator could not be generated BOOST_DELETED_FUNCTION(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 > { typedef tag::stateful_tag tag_type; stateful_tag_type() {} stateful_tag_type(Data const& data) : spirit::terminal(data) {} // silence MSVC warning C4512: assignment operator could not be generated BOOST_DELETED_FUNCTION(stateful_tag_type& operator= (stateful_tag_type const&)) }; namespace detail { // extract expression if this is a Tag template struct get_stateful_data { typedef typename StatefulTag::data_type data_type; // is invoked if given tag is != Tag template 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 struct is_custom_terminal : mpl::true_ {}; template struct custom_terminal { #ifndef BOOST_PHOENIX_NO_SPECIALIZE_CUSTOM_TERMINAL typedef void _is_default_custom_terminal; // fix for #7730 #endif typedef spirit::terminal result_type; template result_type operator()(Tag const & t, Context const &) { return spirit::terminal(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::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::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 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 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