365 lines
13 KiB
C++
365 lines
13 KiB
C++
/*=============================================================================
|
|
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 BOOST_SYMBOL_VISIBLE parser_error_base : public std::exception
|
|
{
|
|
protected:
|
|
|
|
parser_error_base() {}
|
|
virtual ~parser_error_base() BOOST_NOEXCEPT_OR_NOTHROW {}
|
|
|
|
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() BOOST_NOEXCEPT_OR_NOTHROW {}
|
|
|
|
virtual const char*
|
|
what() const BOOST_NOEXCEPT_OR_NOTHROW
|
|
{
|
|
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;
|
|
|
|
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
|
|
|