blob: d6b25c000ec55e5487b3e54086411a9977055ecd [file] [log] [blame]
/*=============================================================================
Copyright (c) 2001-2003 Joel de Guzman
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_EXCEPTIONS_HPP
#define BOOST_SPIRIT_EXCEPTIONS_HPP
#include <boost/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/spirit/home/classic/namespace.hpp>
#include <boost/spirit/home/classic/core/parser.hpp>
#include <boost/spirit/home/classic/core/composite/composite.hpp>
#include <exception>
#include <boost/spirit/home/classic/error_handling/exceptions_fwd.hpp>
namespace boost { namespace spirit {
BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////
//
// 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() {}
public:
parser_error_base(parser_error_base const& rhs)
: std::exception(rhs) {}
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>
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_) {}
parser_error(parser_error const& rhs)
: parser_error_base(rhs)
, where(rhs.where), descriptor(rhs.descriptor) {}
parser_error&
operator=(parser_error const& rhs)
{
where = rhs.where;
descriptor = rhs.descriptor;
return *this;
}
virtual
~parser_error() throw() {}
virtual const char*
what() const throw()
{
return "BOOST_SPIRIT_CLASSIC_NS::parser_error";
}
IteratorT where;
ErrorDescrT 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)
{
throw_(scan.first, descriptor);
}
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>
struct error_status
{
enum result_t { fail, retry, accept, rethrow };
error_status(
result_t result_ = fail,
std::ptrdiff_t length_ = -1,
T const& value_ = T())
: result(result_), length(length_), value(value_) {}
result_t result;
std::ptrdiff_t 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, 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);
}
};
BOOST_SPIRIT_CLASSIC_NAMESPACE_END
}} // namespace BOOST_SPIRIT_CLASSIC_NS
#include <boost/spirit/home/classic/error_handling/impl/exceptions.ipp>
#endif