/*=============================================================================
    Copyright (c) 2003 Hartmut Kaiser
    http://spirit.sourceforge.net/

  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)
=============================================================================*/
#ifndef BOOST_SPIRIT_SWITCH_HPP
#define BOOST_SPIRIT_SWITCH_HPP

///////////////////////////////////////////////////////////////////////////////
//
//  The default_p parser generator template uses the following magic number
//  as the corresponding case label value inside the generated switch()
//  statements. If this number conflicts with your code, please pick a
//  different one.
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_DEFAULTCASE_MAGIC)
#define BOOST_SPIRIT_DEFAULTCASE_MAGIC 0x15F97A7
#endif

///////////////////////////////////////////////////////////////////////////////
//
//  Spirit predefined maximum number of possible case_p/default_p case branch
//  parsers.
//
///////////////////////////////////////////////////////////////////////////////
#if !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)
#define BOOST_SPIRIT_SWITCH_CASE_LIMIT 3
#endif // !defined(BOOST_SPIRIT_SWITCH_CASE_LIMIT)

///////////////////////////////////////////////////////////////////////////////
#include <boost/static_assert.hpp>

///////////////////////////////////////////////////////////////////////////////
//
// Ensure   BOOST_SPIRIT_SELECT_LIMIT > 0
//
///////////////////////////////////////////////////////////////////////////////
BOOST_STATIC_ASSERT(BOOST_SPIRIT_SWITCH_CASE_LIMIT > 0);

#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/config.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/spirit/home/classic/core/parser.hpp>
#include <boost/spirit/home/classic/core/composite/epsilon.hpp>
#include <boost/spirit/home/classic/dynamic/impl/switch.ipp>

///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace spirit {

BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN

///////////////////////////////////////////////////////////////////////////////
//
//  The switch_parser allows to build switch like parsing constructs, which
//  will have much better perfomance as comparable straight solutions.
//
//  Input stream driven syntax:
//
//      switch_p
//      [
//          case_p<'a'>
//              (...parser to use, if the next character is 'a'...),
//          case_p<'b'>
//              (...parser to use, if the next character is 'b'...),
//          default_p
//              (...parser to use, if nothing was matched before...)
//      ]
//
//  General syntax:
//
//      switch_p(...lazy expression returning the switch condition value...)
//      [
//          case_p<1>
//              (...parser to use, if the switch condition value is 1...),
//          case_p<2>
//              (...parser to use, if the switch condition value is 2...),
//          default_p
//              (...parser to use, if nothing was matched before...)
//      ]
//
//  The maximum number of possible case_p branches is defined by the p constant
//  BOOST_SPIRIT_SWITCH_CASE_LIMIT (this value defaults to 3 if not otherwise
//  defined).
//
///////////////////////////////////////////////////////////////////////////////
template <typename CaseT, typename CondT = impl::get_next_token_cond>
struct switch_parser
:   public unary<CaseT, parser<switch_parser<CaseT, CondT> > >
{
    typedef switch_parser<CaseT, CondT>     self_t;
    typedef unary_parser_category           parser_category_t;
    typedef unary<CaseT, parser<self_t> >   base_t;

    switch_parser(CaseT const &case_)
    :   base_t(case_), cond(CondT())
    {}

    switch_parser(CaseT const &case_, CondT const &cond_)
    :   base_t(case_), cond(cond_)
    {}

    template <typename ScannerT>
    struct result
    {
        typedef typename match_result<ScannerT, nil_t>::type type;
    };

    template <typename ScannerT>
    typename parser_result<self_t, ScannerT>::type
    parse(ScannerT const& scan) const
    {
        return this->subject().parse(scan,
            impl::make_cond_functor<CondT>::do_(cond));
    }

    CondT cond;
};

///////////////////////////////////////////////////////////////////////////////
template <typename CondT>
struct switch_cond_parser
{
    switch_cond_parser(CondT const &cond_)
    :   cond(cond_)
    {}

    template <typename ParserT>
    switch_parser<ParserT, CondT>
    operator[](parser<ParserT> const &p) const
    {
        return switch_parser<ParserT, CondT>(p.derived(), cond);
    }

    CondT const &cond;
};

///////////////////////////////////////////////////////////////////////////////
template <int N, typename ParserT, bool IsDefault>
struct case_parser
:   public unary<ParserT, parser<case_parser<N, ParserT, IsDefault> > >
{
    typedef case_parser<N, ParserT, IsDefault> self_t;
    typedef unary_parser_category               parser_category_t;
    typedef unary<ParserT, parser<self_t> >     base_t;

    typedef typename base_t::subject_t          self_subject_t;

    BOOST_STATIC_CONSTANT(int, value = N);
    BOOST_STATIC_CONSTANT(bool, is_default = IsDefault);
    BOOST_STATIC_CONSTANT(bool, is_simple = true);
    BOOST_STATIC_CONSTANT(bool, is_epsilon = (
        is_default && boost::is_same<self_subject_t, epsilon_parser>::value
    ));

    case_parser(parser<ParserT> const &p)
    :   base_t(p.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
    {
        typedef impl::default_case<self_t> default_t;

        if (!scan.at_end()) {
            typedef impl::default_delegate_parse<
                value, is_default, default_t::value> default_parse_t;

            typename ScannerT::iterator_t const save(scan.first);
            return default_parse_t::parse(cond(scan), *this,
                *this, scan, save);
        }

        return default_t::is_epsilon ? scan.empty_match() : scan.no_match();
    }

    template <int N1, typename ParserT1, bool IsDefault1>
    impl::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(!is_default || !IsDefault1);

        typedef case_parser<N1, ParserT1, IsDefault1> right_t;
        return impl::compound_case_parser<self_t, right_t, IsDefault1>(*this, p);
    }
};

///////////////////////////////////////////////////////////////////////////////
struct switch_parser_gen {

//  This generates a switch parser, which is driven by the condition value
//  returned by the lazy parameter expression 'cond'. This may be a parser,
//  which result is used or a phoenix actor, which will be dereferenced to
//  obtain the switch condition value.
    template <typename CondT>
    switch_cond_parser<CondT>
    operator()(CondT const &cond) const
    {
        return switch_cond_parser<CondT>(cond);
    }

//  This generates a switch parser, which is driven by the next character/token
//  found in the input stream.
    template <typename CaseT>
    switch_parser<CaseT>
    operator[](parser<CaseT> const &p) const
    {
        return switch_parser<CaseT>(p.derived());
    }
};

switch_parser_gen const switch_p = switch_parser_gen();

///////////////////////////////////////////////////////////////////////////////
template <int N, typename ParserT>
inline case_parser<N, ParserT, false>
case_p(parser<ParserT> const &p)
{
    return case_parser<N, ParserT, false>(p);
}

///////////////////////////////////////////////////////////////////////////////
struct default_parser_gen
:   public case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
{
    default_parser_gen()
    :   case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, epsilon_parser, true>
            (epsilon_p)
    {}

    template <typename ParserT>
    case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>
    operator()(parser<ParserT> const &p) const
    {
        return case_parser<BOOST_SPIRIT_DEFAULTCASE_MAGIC, ParserT, true>(p);
    }
};

default_parser_gen const default_p = default_parser_gen();

///////////////////////////////////////////////////////////////////////////////
BOOST_SPIRIT_CLASSIC_NAMESPACE_END

}}  // namespace BOOST_SPIRIT_CLASSIC_NS

#endif // BOOST_SPIRIT_SWITCH_HPP
