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