| /*============================================================================= |
| Copyright (c) 2003 Hartmut Kaiser |
| http://spirit.sourceforge.net/ |
| |
| Use, modification and distribution is subject to 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) |
| =============================================================================*/ |
| #ifndef BOOST_SPIRIT_SWITCH_IPP |
| #define BOOST_SPIRIT_SWITCH_IPP |
| |
| #include <boost/mpl/if.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/static_assert.hpp> |
| |
| #include <boost/preprocessor/cat.hpp> |
| #include <boost/preprocessor/inc.hpp> |
| #include <boost/preprocessor/repeat.hpp> |
| #include <boost/preprocessor/repeat_from_to.hpp> |
| |
| #include <boost/spirit/home/classic/core/parser.hpp> |
| #include <boost/spirit/home/classic/core/primitives/primitives.hpp> |
| #include <boost/spirit/home/classic/core/composite/composite.hpp> |
| #include <boost/spirit/home/classic/meta/as_parser.hpp> |
| |
| #include <boost/spirit/home/classic/phoenix/actor.hpp> |
| #include <boost/spirit/home/classic/phoenix/tuples.hpp> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { |
| |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN |
| |
| // forward declaration |
| template <int N, typename ParserT, bool IsDefault> struct case_parser; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace impl { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // parse helper functions |
| template <typename ParserT, typename ScannerT> |
| inline typename parser_result<ParserT, ScannerT>::type |
| delegate_parse(ParserT const &p, ScannerT const &scan, |
| typename ScannerT::iterator_t const save) |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type result_t; |
| |
| result_t result (p.subject().parse(scan)); |
| if (!result) |
| scan.first = save; |
| return result; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // General default case handling (no default_p case branch given). |
| // First try to match the current parser node (if the condition value is |
| // matched) and, if that fails, return a no_match |
| template <int N, bool IsDefault, bool HasDefault> |
| struct default_delegate_parse { |
| |
| template < |
| typename ParserT, typename DefaultT, |
| typename ValueT, typename ScannerT |
| > |
| static typename parser_result<ParserT, ScannerT>::type |
| parse (ValueT const &value, ParserT const &p, DefaultT const &, |
| ScannerT const &scan, typename ScannerT::iterator_t const save) |
| { |
| if (value == N) |
| return delegate_parse(p, scan, save); |
| return scan.no_match(); |
| } |
| }; |
| |
| // The current case parser node is the default parser. |
| // Ignore the given case value and try to match the given default parser. |
| template <int N, bool HasDefault> |
| struct default_delegate_parse<N, true, HasDefault> { |
| |
| template < |
| typename ParserT, typename DefaultT, |
| typename ValueT, typename ScannerT |
| > |
| static typename parser_result<ParserT, ScannerT>::type |
| parse (ValueT const& /*value*/, ParserT const &, DefaultT const &d, |
| ScannerT const &scan, typename ScannerT::iterator_t const save) |
| { |
| // Since there is a default_p case branch defined, the corresponding |
| // parser shouldn't be the nothing_parser |
| BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value)); |
| return delegate_parse(d, scan, save); |
| } |
| }; |
| |
| // The current case parser node is not the default parser, but there is a |
| // default_p branch given inside the switch_p parser. |
| // First try to match the current parser node (if the condition value is |
| // matched) and, if that fails, match the given default_p parser. |
| template <int N> |
| struct default_delegate_parse<N, false, true> { |
| |
| template < |
| typename ParserT, typename DefaultT, |
| typename ValueT, typename ScannerT |
| > |
| static typename parser_result<ParserT, ScannerT>::type |
| parse (ValueT const &value, ParserT const &p, DefaultT const &d, |
| ScannerT const &scan, typename ScannerT::iterator_t const save) |
| { |
| // Since there is a default_p case branch defined, the corresponding |
| // parser shouldn't be the nothing_parser |
| BOOST_STATIC_ASSERT((!boost::is_same<DefaultT, nothing_parser>::value)); |
| if (value == N) |
| return delegate_parse(p, scan, save); |
| |
| return delegate_parse(d, scan, save); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Look through the case parser chain to test, if there is a default case |
| // branch defined (returned by 'value'). |
| template <typename CaseT, bool IsSimple = CaseT::is_simple> |
| struct default_case; |
| |
| //////////////////////////////////////// |
| template <typename ResultT, bool IsDefault> |
| struct get_default_parser { |
| |
| template <typename ParserT> |
| static ResultT |
| get(parser<ParserT> const &p) |
| { |
| return default_case<typename ParserT::derived_t::left_t>:: |
| get(p.derived().left()); |
| } |
| }; |
| |
| template <typename ResultT> |
| struct get_default_parser<ResultT, true> { |
| |
| template <typename ParserT> |
| static ResultT |
| get(parser<ParserT> const &p) { return p.derived().right(); } |
| }; |
| |
| //////////////////////////////////////// |
| template <typename CaseT, bool IsSimple> |
| struct default_case { |
| |
| // The 'value' constant is true, if the current case_parser or one of its |
| // left siblings is a default_p generated case_parser. |
| BOOST_STATIC_CONSTANT(bool, value = |
| (CaseT::is_default || default_case<typename CaseT::left_t>::value)); |
| |
| // The 'is_epsilon' constant is true, if the current case_parser or one of |
| // its left siblings is a default_p generated parser with an attached |
| // epsilon_p (this is generated by the plain default_p). |
| BOOST_STATIC_CONSTANT(bool, is_epsilon = ( |
| (CaseT::is_default && CaseT::is_epsilon) || |
| default_case<typename CaseT::left_t>::is_epsilon |
| )); |
| |
| // The computed 'type' represents the type of the default case branch |
| // parser (if there is one) or nothing_parser (if there isn't any default |
| // case branch). |
| typedef typename boost::mpl::if_c< |
| CaseT::is_default, typename CaseT::right_embed_t, |
| typename default_case<typename CaseT::left_t>::type |
| >::type type; |
| |
| // The get function returns the parser attached to the default case branch |
| // (if there is one) or an instance of a nothing_parser (if there isn't |
| // any default case branch). |
| template <typename ParserT> |
| static type |
| get(parser<ParserT> const &p) |
| { return get_default_parser<type, CaseT::is_default>::get(p); } |
| }; |
| |
| //////////////////////////////////////// |
| template <typename ResultT, bool IsDefault> |
| struct get_default_parser_simple { |
| |
| template <typename ParserT> |
| static ResultT |
| get(parser<ParserT> const &p) { return p.derived(); } |
| }; |
| |
| template <typename ResultT> |
| struct get_default_parser_simple<ResultT, false> { |
| |
| template <typename ParserT> |
| static nothing_parser |
| get(parser<ParserT> const &) { return nothing_p; } |
| }; |
| |
| //////////////////////////////////////// |
| // Specialization of the default_case template for the last (leftmost) element |
| // of the case parser chain. |
| template <typename CaseT> |
| struct default_case<CaseT, true> { |
| |
| // The 'value' and 'is_epsilon' constant, the 'type' type and the function |
| // 'get' are described above. |
| |
| BOOST_STATIC_CONSTANT(bool, value = CaseT::is_default); |
| BOOST_STATIC_CONSTANT(bool, is_epsilon = ( |
| CaseT::is_default && CaseT::is_epsilon |
| )); |
| |
| typedef typename boost::mpl::if_c< |
| CaseT::is_default, CaseT, nothing_parser |
| >::type type; |
| |
| template <typename ParserT> |
| static type |
| get(parser<ParserT> const &p) |
| { return get_default_parser_simple<type, value>::get(p); } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The case_chain template calculates recursivly the depth of the left |
| // subchain of the given case branch node. |
| template <typename CaseT, bool IsSimple = CaseT::is_simple> |
| struct case_chain { |
| |
| BOOST_STATIC_CONSTANT(int, depth = ( |
| case_chain<typename CaseT::left_t>::depth + 1 |
| )); |
| }; |
| |
| template <typename CaseT> |
| struct case_chain<CaseT, true> { |
| |
| BOOST_STATIC_CONSTANT(int, depth = 0); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The chain_parser template is used to extract the type and the instance of |
| // a left or a right parser, burried arbitrary deep inside the case parser |
| // chain. |
| template <int Depth, typename CaseT> |
| struct chain_parser { |
| |
| typedef typename CaseT::left_t our_left_t; |
| |
| typedef typename chain_parser<Depth-1, our_left_t>::left_t left_t; |
| typedef typename chain_parser<Depth-1, our_left_t>::right_t right_t; |
| |
| static left_t |
| left(CaseT const &p) |
| { return chain_parser<Depth-1, our_left_t>::left(p.left()); } |
| |
| static right_t |
| right(CaseT const &p) |
| { return chain_parser<Depth-1, our_left_t>::right(p.left()); } |
| }; |
| |
| template <typename CaseT> |
| struct chain_parser<1, CaseT> { |
| |
| typedef typename CaseT::left_t left_t; |
| typedef typename CaseT::right_t right_t; |
| |
| static left_t left(CaseT const &p) { return p.left(); } |
| static right_t right(CaseT const &p) { return p.right(); } |
| }; |
| |
| template <typename CaseT> |
| struct chain_parser<0, CaseT>; // shouldn't be instantiated |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Type computing meta function for calculating the type of the return value |
| // of the used conditional switch expression |
| template <typename TargetT, typename ScannerT> |
| struct condition_result { |
| |
| typedef typename TargetT::template result<ScannerT>::type type; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| template <typename LeftT, typename RightT, bool IsDefault> |
| struct compound_case_parser |
| : public binary<LeftT, RightT, |
| parser<compound_case_parser<LeftT, RightT, IsDefault> > > |
| { |
| typedef compound_case_parser<LeftT, RightT, IsDefault> self_t; |
| typedef binary_parser_category parser_category_t; |
| typedef binary<LeftT, RightT, parser<self_t> > base_t; |
| |
| BOOST_STATIC_CONSTANT(int, value = RightT::value); |
| BOOST_STATIC_CONSTANT(bool, is_default = IsDefault); |
| BOOST_STATIC_CONSTANT(bool, is_simple = false); |
| BOOST_STATIC_CONSTANT(bool, is_epsilon = ( |
| is_default && |
| boost::is_same<typename RightT::subject_t, epsilon_parser>::value |
| )); |
| |
| compound_case_parser(parser<LeftT> const &lhs, parser<RightT> const &rhs) |
| : base_t(lhs.derived(), rhs.derived()) |
| {} |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename match_result<ScannerT, nil_t>::type type; |
| }; |
| |
| template <typename ScannerT, typename CondT> |
| typename parser_result<self_t, ScannerT>::type |
| parse(ScannerT const& scan, CondT const &cond) const; |
| |
| template <int N1, typename ParserT1, bool IsDefault1> |
| compound_case_parser< |
| self_t, case_parser<N1, ParserT1, IsDefault1>, IsDefault1 |
| > |
| operator, (case_parser<N1, ParserT1, IsDefault1> const &p) const |
| { |
| // If the following compile time assertion fires, you've probably used |
| // more than one default_p case inside the switch_p parser construct. |
| BOOST_STATIC_ASSERT(!default_case<self_t>::value || !IsDefault1); |
| |
| // If this compile time assertion fires, you've probably want to use |
| // more case_p/default_p case branches, than possible. |
| BOOST_STATIC_ASSERT( |
| case_chain<self_t>::depth < BOOST_SPIRIT_SWITCH_CASE_LIMIT |
| ); |
| |
| typedef case_parser<N1, ParserT1, IsDefault1> right_t; |
| return compound_case_parser<self_t, right_t, IsDefault1>(*this, p); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The parse_switch::do_ functions dispatch to the correct parser, which is |
| // selected through the given conditional switch value. |
| template <int Value, int Depth, bool IsDefault> |
| struct parse_switch; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // The following generates a couple of parse_switch template specializations |
| // with an increasing number of handled case branches (for 1..N). |
| // |
| // template <int Value, bool IsDefault> |
| // struct parse_switch<Value, N, IsDefault> { |
| // |
| // template <typename ParserT, typename ScannerT> |
| // static typename parser_result<ParserT, ScannerT>::type |
| // do_(ParserT const &p, ScannerT const &scan, long cond_value, |
| // typename ScannerT::iterator_t const &save) |
| // { |
| // typedef ParserT left_t0; |
| // typedef typename left_t0::left left_t1; |
| // ... |
| // |
| // switch (cond_value) { |
| // case left_tN::value: |
| // return delegate_parse(chain_parser< |
| // case_chain<ParserT>::depth, ParserT |
| // >::left(p), scan, save); |
| // ... |
| // case left_t1::value: |
| // return delegate_parse(chain_parser< |
| // 1, left_t1 |
| // >::right(p.left()), scan, save); |
| // |
| // case left_t0::value: |
| // default: |
| // typedef default_case<ParserT> default_t; |
| // typedef default_delegate_parse< |
| // Value, IsDefault, default_t::value> |
| // default_parse_t; |
| // |
| // return default_parse_t::parse(cond_value, p.right(), |
| // default_t::get(p), scan, save); |
| // } |
| // } |
| // }; |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| #define BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS(z, N, _) \ |
| typedef typename BOOST_PP_CAT(left_t, N)::left_t \ |
| BOOST_PP_CAT(left_t, BOOST_PP_INC(N)); \ |
| /**/ |
| |
| #define BOOST_SPIRIT_PARSE_SWITCH_CASES(z, N, _) \ |
| case (long)(BOOST_PP_CAT(left_t, N)::value): \ |
| return delegate_parse(chain_parser<N, left_t1>::right(p.left()), \ |
| scan, save); \ |
| /**/ |
| |
| #define BOOST_SPIRIT_PARSE_SWITCHES(z, N, _) \ |
| template <int Value, bool IsDefault> \ |
| struct parse_switch<Value, BOOST_PP_INC(N), IsDefault> { \ |
| \ |
| template <typename ParserT, typename ScannerT> \ |
| static typename parser_result<ParserT, ScannerT>::type \ |
| do_(ParserT const &p, ScannerT const &scan, long cond_value, \ |
| typename ScannerT::iterator_t const &save) \ |
| { \ |
| typedef ParserT left_t0; \ |
| BOOST_PP_REPEAT_FROM_TO_ ## z(0, BOOST_PP_INC(N), \ |
| BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS, _) \ |
| \ |
| switch (cond_value) { \ |
| case (long)(BOOST_PP_CAT(left_t, BOOST_PP_INC(N))::value): \ |
| return delegate_parse( \ |
| chain_parser< \ |
| case_chain<ParserT>::depth, ParserT \ |
| >::left(p), scan, save); \ |
| \ |
| BOOST_PP_REPEAT_FROM_TO_ ## z(1, BOOST_PP_INC(N), \ |
| BOOST_SPIRIT_PARSE_SWITCH_CASES, _) \ |
| \ |
| case (long)(left_t0::value): \ |
| default: \ |
| typedef default_case<ParserT> default_t; \ |
| typedef \ |
| default_delegate_parse<Value, IsDefault, default_t::value> \ |
| default_parse_t; \ |
| \ |
| return default_parse_t::parse(cond_value, p.right(), \ |
| default_t::get(p), scan, save); \ |
| } \ |
| } \ |
| }; \ |
| /**/ |
| |
| BOOST_PP_REPEAT(BOOST_PP_DEC(BOOST_SPIRIT_SWITCH_CASE_LIMIT), |
| BOOST_SPIRIT_PARSE_SWITCHES, _) |
| |
| #undef BOOST_SPIRIT_PARSE_SWITCH_TYPEDEFS |
| #undef BOOST_SPIRIT_PARSE_SWITCH_CASES |
| #undef BOOST_SPIRIT_PARSE_SWITCHES |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| template <typename LeftT, typename RightT, bool IsDefault> |
| template <typename ScannerT, typename CondT> |
| inline typename parser_result< |
| compound_case_parser<LeftT, RightT, IsDefault>, ScannerT |
| >::type |
| compound_case_parser<LeftT, RightT, IsDefault>:: |
| parse(ScannerT const& scan, CondT const &cond) const |
| { |
| scan.at_end(); // allow skipper to take effect |
| return parse_switch<value, case_chain<self_t>::depth, is_default>:: |
| do_(*this, scan, cond(scan), scan.first); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The switch condition is to be evaluated from a parser result value. |
| template <typename ParserT> |
| struct cond_functor { |
| |
| typedef cond_functor<ParserT> self_t; |
| |
| cond_functor(ParserT const &p_) |
| : p(p_) |
| {} |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type::attr_t type; |
| }; |
| |
| template <typename ScannerT> |
| typename condition_result<self_t, ScannerT>::type |
| operator()(ScannerT const &scan) const |
| { |
| typedef typename parser_result<ParserT, ScannerT>::type result_t; |
| typedef typename result_t::attr_t attr_t; |
| |
| result_t result(p.parse(scan)); |
| return !result ? attr_t() : result.value(); |
| } |
| |
| typename ParserT::embed_t p; |
| }; |
| |
| template <typename ParserT> |
| struct make_cond_functor { |
| |
| typedef as_parser<ParserT> as_parser_t; |
| |
| static cond_functor<typename as_parser_t::type> |
| do_(ParserT const &cond) |
| { |
| return cond_functor<typename as_parser_t::type>( |
| as_parser_t::convert(cond)); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The switch condition is to be evaluated from a phoenix actor |
| template <typename ActorT> |
| struct cond_actor { |
| |
| typedef cond_actor<ActorT> self_t; |
| |
| cond_actor(ActorT const &actor_) |
| : actor(actor_) |
| {} |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename phoenix::actor_result<ActorT, phoenix::tuple<> >::type |
| type; |
| }; |
| |
| template <typename ScannerT> |
| typename condition_result<self_t, ScannerT>::type |
| operator()(ScannerT const& /*scan*/) const |
| { |
| return actor(); |
| } |
| |
| ActorT const &actor; |
| }; |
| |
| template <typename ActorT> |
| struct make_cond_functor<phoenix::actor<ActorT> > { |
| |
| static cond_actor<phoenix::actor<ActorT> > |
| do_(phoenix::actor<ActorT> const &actor) |
| { |
| return cond_actor<phoenix::actor<ActorT> >(actor); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // The switch condition is to be taken directly from the input stream |
| struct get_next_token_cond { |
| |
| typedef get_next_token_cond self_t; |
| |
| template <typename ScannerT> |
| struct result |
| { |
| typedef typename ScannerT::value_t type; |
| }; |
| |
| template <typename ScannerT> |
| typename condition_result<self_t, ScannerT>::type |
| operator()(ScannerT const &scan) const |
| { |
| typename ScannerT::value_t val(*scan); |
| ++scan.first; |
| return val; |
| } |
| }; |
| |
| template <> |
| struct make_cond_functor<get_next_token_cond> { |
| |
| static get_next_token_cond |
| do_(get_next_token_cond const &cond) |
| { |
| return cond; |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| } // namespace impl |
| |
| BOOST_SPIRIT_CLASSIC_NAMESPACE_END |
| |
| }} // namespace boost::spirit |
| |
| #endif // BOOST_SPIRIT_SWITCH_IPP |