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