]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/spirit/home/classic/error_handling/exceptions.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / spirit / home / classic / error_handling / exceptions.hpp
1 /*=============================================================================
2 Copyright (c) 2001-2003 Joel de Guzman
3 http://spirit.sourceforge.net/
4
5 Distributed under the Boost Software License, Version 1.0. (See accompanying
6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 #ifndef BOOST_SPIRIT_EXCEPTIONS_HPP
9 #define BOOST_SPIRIT_EXCEPTIONS_HPP
10
11 #include <boost/config.hpp>
12 #include <boost/throw_exception.hpp>
13 #include <boost/spirit/home/classic/namespace.hpp>
14 #include <boost/spirit/home/classic/core/parser.hpp>
15 #include <boost/spirit/home/classic/core/composite/composite.hpp>
16 #include <exception>
17
18 #include <boost/spirit/home/classic/error_handling/exceptions_fwd.hpp>
19
20 namespace boost { namespace spirit {
21
22 BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN
23
24 ///////////////////////////////////////////////////////////////////////////
25 //
26 // parser_error_base class
27 //
28 // This is the base class of parser_error (see below). This may be
29 // used to catch any type of parser error.
30 //
31 // This exception shouldn't propagate outside the parser. However to
32 // avoid quirks of many platforms/implementations which fall outside
33 // the C++ standard, we derive parser_error_base from std::exception
34 // to allow a single catch handler to catch all exceptions.
35 //
36 ///////////////////////////////////////////////////////////////////////////
37 class BOOST_SYMBOL_VISIBLE parser_error_base : public std::exception
38 {
39 protected:
40
41 parser_error_base() {}
42 virtual ~parser_error_base() BOOST_NOEXCEPT_OR_NOTHROW {}
43
44 public:
45
46 parser_error_base(parser_error_base const& rhs)
47 : std::exception(rhs) {}
48 parser_error_base& operator=(parser_error_base const&)
49 {
50 return *this;
51 }
52 };
53
54 ///////////////////////////////////////////////////////////////////////////
55 //
56 // parser_error class
57 //
58 // Generic parser exception class. This is the base class for all
59 // parser exceptions. The exception holds the iterator position
60 // where the error was encountered in its member variable "where".
61 // The parser_error also holds information regarding the error
62 // (error descriptor) in its member variable "descriptor".
63 //
64 // The throw_ function creates and throws a parser_error given
65 // an iterator and an error descriptor.
66 //
67 ///////////////////////////////////////////////////////////////////////////
68 template <typename ErrorDescrT, typename IteratorT>
69 struct parser_error : public parser_error_base
70 {
71 typedef ErrorDescrT error_descr_t;
72 typedef IteratorT iterator_t;
73
74 parser_error(IteratorT where_, ErrorDescrT descriptor_)
75 : where(where_), descriptor(descriptor_) {}
76
77 parser_error(parser_error const& rhs)
78 : parser_error_base(rhs)
79 , where(rhs.where), descriptor(rhs.descriptor) {}
80
81 parser_error&
82 operator=(parser_error const& rhs)
83 {
84 where = rhs.where;
85 descriptor = rhs.descriptor;
86 return *this;
87 }
88
89 virtual
90 ~parser_error() BOOST_NOEXCEPT_OR_NOTHROW {}
91
92 virtual const char*
93 what() const BOOST_NOEXCEPT_OR_NOTHROW
94 {
95 return "BOOST_SPIRIT_CLASSIC_NS::parser_error";
96 }
97
98 IteratorT where;
99 ErrorDescrT descriptor;
100 };
101
102 //////////////////////////////////
103 template <typename ErrorDescrT, typename IteratorT>
104 inline void
105 throw_(IteratorT where, ErrorDescrT descriptor)
106 {
107 boost::throw_exception(
108 parser_error<ErrorDescrT, IteratorT>(where, descriptor));
109 }
110
111 ///////////////////////////////////////////////////////////////////////////
112 //
113 // assertive_parser class
114 //
115 // An assertive_parser class is a parser that throws an exception
116 // in response to a parsing failure. The assertive_parser throws a
117 // parser_error exception rather than returning an unsuccessful
118 // match to signal that the parser failed to match the input.
119 //
120 ///////////////////////////////////////////////////////////////////////////
121 template <typename ErrorDescrT, typename ParserT>
122 struct assertive_parser
123 : public unary<ParserT, parser<assertive_parser<ErrorDescrT, ParserT> > >
124 {
125 typedef assertive_parser<ErrorDescrT, ParserT> self_t;
126 typedef unary<ParserT, parser<self_t> > base_t;
127 typedef unary_parser_category parser_category_t;
128
129 assertive_parser(ParserT const& parser, ErrorDescrT descriptor_)
130 : base_t(parser), descriptor(descriptor_) {}
131
132 template <typename ScannerT>
133 struct result
134 {
135 typedef typename parser_result<ParserT, ScannerT>::type type;
136 };
137
138 template <typename ScannerT>
139 typename parser_result<self_t, ScannerT>::type
140 parse(ScannerT const& scan) const
141 {
142 typedef typename parser_result<ParserT, ScannerT>::type result_t;
143
144 result_t hit = this->subject().parse(scan);
145 if (!hit)
146 {
147 throw_(scan.first, descriptor);
148 }
149 return hit;
150 }
151
152 ErrorDescrT descriptor;
153 };
154
155 ///////////////////////////////////////////////////////////////////////////
156 //
157 // assertion class
158 //
159 // assertive_parsers are never instantiated directly. The assertion
160 // class is used to indirectly create an assertive_parser object.
161 // Before declaring the grammar, we declare some assertion objects.
162 // Examples:
163 //
164 // enum Errors
165 // {
166 // program_expected, begin_expected, end_expected
167 // };
168 //
169 // assertion<Errors> expect_program(program_expected);
170 // assertion<Errors> expect_begin(begin_expected);
171 // assertion<Errors> expect_end(end_expected);
172 //
173 // Now, we can use these assertions as wrappers around parsers:
174 //
175 // expect_end(str_p("end"))
176 //
177 // Take note that although the example uses enums to hold the
178 // information regarding the error (error desccriptor), we are free
179 // to use other types such as integers and strings. Enums are
180 // convenient for error handlers to easily catch since C++ treats
181 // enums as unique types.
182 //
183 ///////////////////////////////////////////////////////////////////////////
184 template <typename ErrorDescrT>
185 struct assertion
186 {
187 assertion(ErrorDescrT descriptor_)
188 : descriptor(descriptor_) {}
189
190 template <typename ParserT>
191 assertive_parser<ErrorDescrT, ParserT>
192 operator()(ParserT const& parser) const
193 {
194 return assertive_parser<ErrorDescrT, ParserT>(parser, descriptor);
195 }
196
197 ErrorDescrT descriptor;
198 };
199
200 ///////////////////////////////////////////////////////////////////////////
201 //
202 // error_status<T>
203 //
204 // Where T is an attribute type compatible with the match attribute
205 // of the fallback_parser's subject (defaults to nil_t). The class
206 // error_status reports the result of an error handler (see
207 // fallback_parser). result can be one of:
208 //
209 // fail: quit and fail (return a no_match)
210 // retry: attempt error recovery, possibly moving the scanner
211 // accept: force success returning a matching length, moving
212 // the scanner appropriately and returning an attribute
213 // value
214 // rethrow: rethrows the error.
215 //
216 ///////////////////////////////////////////////////////////////////////////
217 template <typename T>
218 struct error_status
219 {
220 enum result_t { fail, retry, accept, rethrow };
221
222 error_status(
223 result_t result_ = fail,
224 std::ptrdiff_t length_ = -1,
225 T const& value_ = T())
226 : result(result_), length(length_), value(value_) {}
227
228 result_t result;
229 std::ptrdiff_t length;
230 T value;
231 };
232
233 ///////////////////////////////////////////////////////////////////////////
234 //
235 // fallback_parser class
236 //
237 // Handles exceptions of type parser_error<ErrorDescrT, IteratorT>
238 // thrown somewhere inside its embedded ParserT object. The class
239 // sets up a try block before delegating parsing to its subject.
240 // When an exception is caught, the catch block then calls the
241 // HandlerT object. HandlerT may be a function or a functor (with
242 // an operator() member function) compatible with the interface:
243 //
244 // error_status<T>
245 // handler(ScannerT const& scan, ErrorT error);
246 //
247 // Where scan points to the scanner state prior to parsing and error
248 // is the error that arose (see parser_error). The handler must
249 // return an error_status<T> object (see above).
250 //
251 ///////////////////////////////////////////////////////////////////////////
252 namespace impl
253 {
254 template <typename RT, typename ParserT, typename ScannerT>
255 RT fallback_parser_parse(ParserT const& p, ScannerT const& scan);
256 }
257
258 template <typename ErrorDescrT, typename ParserT, typename HandlerT>
259 struct fallback_parser
260 : public unary<ParserT,
261 parser<fallback_parser<ErrorDescrT, ParserT, HandlerT> > >
262 {
263 typedef fallback_parser<ErrorDescrT, ParserT, HandlerT>
264 self_t;
265 typedef ErrorDescrT
266 error_descr_t;
267 typedef unary<ParserT, parser<self_t> >
268 base_t;
269 typedef unary_parser_category
270 parser_category_t;
271
272 fallback_parser(ParserT const& parser, HandlerT const& handler_)
273 : base_t(parser), handler(handler_) {}
274
275 template <typename ScannerT>
276 struct result
277 {
278 typedef typename parser_result<ParserT, ScannerT>::type type;
279 };
280
281 template <typename ScannerT>
282 typename parser_result<self_t, ScannerT>::type
283 parse(ScannerT const& scan) const
284 {
285 typedef typename parser_result<self_t, ScannerT>::type result_t;
286 return impl::fallback_parser_parse<result_t>(*this, scan);
287 }
288
289 HandlerT handler;
290 };
291
292 ///////////////////////////////////////////////////////////////////////////
293 //
294 // guard class
295 //
296 // fallback_parser objects are not instantiated directly. The guard
297 // class is used to indirectly create a fallback_parser object.
298 // guards are typically predeclared just like assertions (see the
299 // assertion class above; the example extends the previous example
300 // introduced in the assertion class above):
301 //
302 // guard<Errors> my_guard;
303 //
304 // Errors, in this example is the error descriptor type we want to
305 // detect; This is essentially the ErrorDescrT template parameter
306 // of the fallback_parser class.
307 //
308 // my_guard may now be used in a grammar declaration as:
309 //
310 // my_guard(p)[h]
311 //
312 // where p is a parser, h is a function or functor compatible with
313 // fallback_parser's HandlerT (see above).
314 //
315 ///////////////////////////////////////////////////////////////////////////
316 template <typename ErrorDescrT, typename ParserT>
317 struct guard_gen : public unary<ParserT, nil_t>
318 {
319 typedef guard<ErrorDescrT> parser_generator_t;
320 typedef unary_parser_category parser_category_t;
321
322 guard_gen(ParserT const& p)
323 : unary<ParserT, nil_t>(p) {}
324
325 template <typename HandlerT>
326 fallback_parser<ErrorDescrT, ParserT, HandlerT>
327 operator[](HandlerT const& handler) const
328 {
329 return fallback_parser<ErrorDescrT, ParserT, HandlerT>
330 (this->subject(), handler);
331 }
332 };
333
334 template <typename ErrorDescrT>
335 struct guard
336 {
337 template <typename ParserT>
338 struct result
339 {
340 typedef guard_gen<ErrorDescrT, ParserT> type;
341 };
342
343 template <typename ParserT>
344 static guard_gen<ErrorDescrT, ParserT>
345 generate(ParserT const& parser)
346 {
347 return guard_gen<ErrorDescrT, ParserT>(parser);
348 }
349
350 template <typename ParserT>
351 guard_gen<ErrorDescrT, ParserT>
352 operator()(ParserT const& parser) const
353 {
354 return guard_gen<ErrorDescrT, ParserT>(parser);
355 }
356 };
357
358 BOOST_SPIRIT_CLASSIC_NAMESPACE_END
359
360 }} // namespace BOOST_SPIRIT_CLASSIC_NS
361
362 #include <boost/spirit/home/classic/error_handling/impl/exceptions.ipp>
363 #endif
364