summaryrefslogtreecommitdiff
path: root/boost/spirit/home/classic/error_handling/exceptions.hpp
blob: 0fb036a2057b73d7c71bf0735eb6b21c162dc208 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
/*=============================================================================
    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;

            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