/*=============================================================================

    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/core/parser.hpp>

#include <boost/spirit/core/primitives/primitives.hpp>

#include <boost/spirit/core/composite/composite.hpp>

#include <boost/spirit/meta/as_parser.hpp>



#include <boost/spirit/phoenix/actor.hpp>

#include <boost/spirit/phoenix/tuples.hpp>



///////////////////////////////////////////////////////////////////////////////

namespace boost { namespace spirit {



// 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

}}  // namespace boost::spirit



#endif  // BOOST_SPIRIT_SWITCH_IPP

