/*============================================================================= Copyright (c) 2001-2011 Joel de Guzman 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 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 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 , phoenix::actor< typename phoenix::as_composite< phoenix::detail::function_eval<1>, 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::compose >(f, _0) , f.proto_base().child0 )); } }; template struct make_lazy { typedef typename proto::terminal< lazy_terminal< typename F::terminal_type , phoenix::actor< typename phoenix::as_composite< phoenix::detail::function_eval<2>, 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::compose >(f, _0, _1) , f.proto_base().child0 )); } }; template struct make_lazy { typedef typename proto::terminal< lazy_terminal< typename F::terminal_type , phoenix::actor< typename phoenix::as_composite< phoenix::detail::function_eval<3>, 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::compose >(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 { // 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 { // unused arg: make_vector wants fusion::void_ typedef fusion::void_ type; }; } 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)) {} template < bool Lazy , typename A0 , typename A1 , typename A2 > struct result_helper; 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; }; // 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)); } 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 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 struct stateful_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 struct stateful_tag_type : spirit::terminal > { typedef tag::stateful_tag tag_type; stateful_tag_type() {} stateful_tag_type(Data const& data) : spirit::terminal(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 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_; } }; } }} // 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(name) \ namespace tag { struct name {}; } \ typedef boost::proto::terminal::type name##_type; \ name##_type const name = {{}}; \ inline void silence_unused_warnings__##name() { (void) name; } \ /***/ #define BOOST_SPIRIT_DEFINE_TERMINALS_A(r, _, name) \ BOOST_SPIRIT_TERMINAL(name) \ /***/ #define BOOST_SPIRIT_DEFINE_TERMINALS(seq) \ BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_A, _, seq) \ /***/ // 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) #define BOOST_SPIRIT_TERMINAL_EX(name) \ namespace tag { struct name {}; } \ typedef boost::spirit::terminal name##_type; \ name##_type const name = name##_type(); \ inline void silence_unused_warnings__##name() { (void) name; } \ /***/ #define BOOST_SPIRIT_DEFINE_TERMINALS_EX_A(r, _, name) \ BOOST_SPIRIT_TERMINAL_EX(name) \ /***/ #define BOOST_SPIRIT_DEFINE_TERMINALS_EX(seq) \ BOOST_PP_SEQ_FOR_EACH(BOOST_SPIRIT_DEFINE_TERMINALS_EX_A, _, seq) \ /***/ #endif