/*=============================================================================
    Spirit v1.6.0
    Copyright (c) 2001-2003 Joel de Guzman
    http://spirit.sourceforge.net/

    Permission to copy, use, modify, sell and distribute this software is
    granted provided this copyright notice appears in all copies. This
    software is provided "as is" without express or implied warranty, and
    with no claim as to its suitability for any purpose.
=============================================================================*/
#ifndef BOOST_SPIRIT_EXCEPTIONS_HPP
#define BOOST_SPIRIT_EXCEPTIONS_HPP

#include "boost/config.hpp"
#include "boost/throw_exception.hpp"
#include "boost/spirit/core/parser.hpp"
#include "boost/spirit/core/composite/composite.hpp"
#include <exception>

namespace boost { namespace spirit {

    ///////////////////////////////////////////////////////////////////////////
    //
    //  parser_error_base class
    //
    //      This is the base class of parser_error (see below). This may be
    //      used to catch any type of parser error.
    //
    //      This exception shouldn't propagate outside the parser. However to
    //      avoid quirks of many platforms/implementations which fall outside
    //      the C++ standard, we derive parser_error_base from std::exception
    //      to allow a single catch handler to catch all exceptions.
    //
    ///////////////////////////////////////////////////////////////////////////
    class parser_error_base : public std::exception
    {
    protected:

        parser_error_base() {}
        virtual ~parser_error_base() throw() {}
        parser_error_base(parser_error_base const&) {}
        parser_error_base& operator=(parser_error_base const&)
        { return *this; }
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  parser_error class
    //
    //      Generic parser exception class. This is the base class for all
    //      parser exceptions. The exception holds the iterator position
    //      where the error was encountered in its member variable "where".
    //      The parser_error also holds information regarding the error
    //      (error descriptor) in its member variable "descriptor".
    //
    //      The throw_ function creates and throws a parser_error given
    //      an iterator and an error descriptor.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename ErrorDescrT, typename IteratorT = char const*>
    struct parser_error : public parser_error_base
    {
        typedef ErrorDescrT error_descr_t;
        typedef IteratorT iterator_t;

        parser_error(IteratorT where_, ErrorDescrT descriptor_)
        : where(where_), descriptor(descriptor_) {}

        virtual
        ~parser_error() throw() {}

        virtual const char*
        what() const throw()
        { return "boost::spirit::parser_error"; }

        IteratorT const   where;
        ErrorDescrT const descriptor;
    };

    //////////////////////////////////
    template <typename ErrorDescrT, typename IteratorT>
    inline void
    throw_(IteratorT where, ErrorDescrT descriptor)
    {
         boost::throw_exception(
            parser_error<ErrorDescrT, IteratorT>(where, descriptor));
    }

    ///////////////////////////////////////////////////////////////////////////
    //
    //  assertive_parser class
    //
    //      An assertive_parser class is a parser that throws an exception
    //      in response to a parsing failure. The assertive_parser throws a
    //      parser_error exception rather than returning an unsuccessful
    //      match to signal that the parser failed to match the input.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename ErrorDescrT, typename ParserT>
    struct assertive_parser
    :   public unary<ParserT, parser<assertive_parser<ErrorDescrT, ParserT> > >
    {
        typedef assertive_parser<ErrorDescrT, ParserT>  self_t;
        typedef unary<ParserT, parser<self_t> >         base_t;
        typedef unary_parser_category                   parser_category_t;

        assertive_parser(ParserT const& parser, ErrorDescrT descriptor)
        : base_t(parser), descriptor(descriptor) {}

        template <typename ScannerT>
        struct result
        { typedef typename parser_result<ParserT, ScannerT>::type type; };

        template <typename ScannerT>
        typename parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename parser_result<ParserT, ScannerT>::type result_t;
            typedef typename ScannerT::iterator_t iterator_t;

            result_t hit = this->subject().parse(scan);
            if (!hit)
            {
            #ifndef __BORLANDC__
                throw_(scan.first, descriptor);
            #else
                throw_(scan.first, const_cast<ErrorDescrT &>(descriptor));
            #endif
            }
            return hit;
        }

        ErrorDescrT descriptor;
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  assertion class
    //
    //      assertive_parsers are never instantiated directly. The assertion
    //      class is used to indirectly create an assertive_parser object.
    //      Before declaring the grammar, we declare some assertion objects.
    //      Examples:
    //
    //          enum Errors
    //          {
    //              program_expected, begin_expected, end_expected
    //          };
    //
    //          assertion<Errors>   expect_program(program_expected);
    //          assertion<Errors>   expect_begin(begin_expected);
    //          assertion<Errors>   expect_end(end_expected);
    //
    //      Now, we can use these assertions as wrappers around parsers:
    //
    //          expect_end(str_p("end"))
    //
    //      Take note that although the example uses enums to hold the
    //      information regarding the error (error desccriptor), we are free
    //      to use other types such as integers and strings. Enums are
    //      convenient for error handlers to easily catch since C++ treats
    //      enums as unique types.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename ErrorDescrT>
    struct assertion
    {
        assertion(ErrorDescrT descriptor_)
        : descriptor(descriptor_) {}

        template <typename ParserT>
        assertive_parser<ErrorDescrT, ParserT>
        operator()(ParserT const& parser) const
        { return assertive_parser<ErrorDescrT, ParserT>(parser, descriptor); }

        ErrorDescrT descriptor;
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  error_status<T>
    //
    //      Where T is an attribute type compatible with the match attribute
    //      of the fallback_parser's subject (defaults to nil_t). The class
    //      error_status reports the result of an error handler (see
    //      fallback_parser). result can be one of:
    //
    //          fail:       quit and fail (return a no_match)
    //          retry:      attempt error recovery, possibly moving the scanner
    //          accept:     force success returning a matching length, moving
    //                      the scanner appropriately and returning an attribute
    //                      value
    //          rethrow:    rethrows the error.
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename T = nil_t>
    struct error_status
    {
        enum result_t { fail, retry, accept, rethrow };

        error_status(
            result_t result_ = fail,
            int length = -1,
            T const& value_ = T())
        : result(result_), length(length), value(value_) {}

        result_t    result;
        int         length;
        T           value;
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  fallback_parser class
    //
    //      Handles exceptions of type parser_error<ErrorDescrT, IteratorT>
    //      thrown somewhere inside its embedded ParserT object. The class
    //      sets up a try block before delegating parsing to its subject.
    //      When an exception is caught, the catch block then calls the
    //      HandlerT object. HandlerT may be a function or a functor (with
    //      an operator() member function) compatible with the interface:
    //
    //          error_status<T>
    //          handler(ScannerT const& scan, ErrorT error);
    //
    //      Where scan points to the scanner state prior to parsing and error
    //      is the error that arose (see parser_error). The handler must
    //      return an error_status<T> object (see above).
    //
    ///////////////////////////////////////////////////////////////////////////
    namespace impl
    {
        template <typename RT, typename ParserT, typename ScannerT>
        RT fallback_parser_parse(ParserT const& p, ScannerT const& scan);
    }

    template <typename ErrorDescrT, typename ParserT, typename HandlerT>
    struct fallback_parser
    :   public unary<ParserT,
        parser<fallback_parser<ErrorDescrT, ParserT, HandlerT> > >
    {
        typedef fallback_parser<ErrorDescrT, ParserT, HandlerT>
            self_t;
        typedef ErrorDescrT
            error_descr_t;
        typedef unary<ParserT, parser<self_t> >
            base_t;
        typedef unary_parser_category
            parser_category_t;

        fallback_parser(ParserT const& parser, HandlerT const& handler_)
        : base_t(parser), handler(handler_) {}

        template <typename ScannerT>
        struct result
        { typedef typename parser_result<ParserT, ScannerT>::type type; };

        template <typename ScannerT>
        typename parser_result<self_t, ScannerT>::type
        parse(ScannerT const& scan) const
        {
            typedef typename parser_result<self_t, ScannerT>::type result_t;
            return impl::fallback_parser_parse<result_t>(*this, scan);
        }

        HandlerT handler;
    };

    ///////////////////////////////////////////////////////////////////////////
    //
    //  guard class
    //
    //      fallback_parser objects are not instantiated directly. The guard
    //      class is used to indirectly create a fallback_parser object.
    //      guards are typically predeclared just like assertions (see the
    //      assertion class above; the example extends the previous example
    //      introduced in the assertion class above):
    //
    //          guard<Errors>   my_guard;
    //
    //      Errors, in this example is the error descriptor type we want to
    //      detect; This is essentially the ErrorDescrT template parameter
    //      of the fallback_parser class.
    //
    //      my_guard may now be used in a grammar declaration as:
    //
    //          my_guard(p)[h]
    //
    //      where p is a parser, h is a function or functor compatible with
    //      fallback_parser's HandlerT (see above).
    //
    ///////////////////////////////////////////////////////////////////////////
    template <typename ErrorDescrT>
    struct guard;

    template <typename ErrorDescrT, typename ParserT>
    struct guard_gen : public unary<ParserT, nil_t>
    {
        typedef guard<ErrorDescrT>      parser_generator_t;
        typedef unary_parser_category   parser_category_t;

        guard_gen(ParserT const& p)
        : unary<ParserT, nil_t>(p) {}

        template <typename HandlerT>
        fallback_parser<ErrorDescrT, ParserT, HandlerT>
        operator[](HandlerT const& handler) const
        {
            return fallback_parser<ErrorDescrT, ParserT, HandlerT>
                (this->subject(), handler);
        }
    };

    template <typename ErrorDescrT>
    struct guard
    {
        template <typename ParserT>
        struct result {

            typedef guard_gen<ErrorDescrT, ParserT> type;
        };

        template <typename ParserT>
        static guard_gen<ErrorDescrT, ParserT>
        generate(ParserT const& parser)
        {
            return guard_gen<ErrorDescrT, ParserT>(parser);
        }

        template <typename ParserT>
        guard_gen<ErrorDescrT, ParserT>
        operator()(ParserT const& parser) const
        {
            return guard_gen<ErrorDescrT, ParserT>(parser);
        }
    };

}} // namespace boost::spirit

#include "boost/spirit/error_handling/impl/exceptions.ipp"
#endif

