]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 parser_error_base : public std::exception | |
38 | { | |
39 | protected: | |
40 | ||
41 | parser_error_base() {} | |
42 | virtual ~parser_error_base() throw() {} | |
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() throw() {} | |
91 | ||
92 | virtual const char* | |
93 | what() const throw() | |
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 | typedef typename ScannerT::iterator_t iterator_t; | |
144 | ||
145 | result_t hit = this->subject().parse(scan); | |
146 | if (!hit) | |
147 | { | |
148 | throw_(scan.first, descriptor); | |
149 | } | |
150 | return hit; | |
151 | } | |
152 | ||
153 | ErrorDescrT descriptor; | |
154 | }; | |
155 | ||
156 | /////////////////////////////////////////////////////////////////////////// | |
157 | // | |
158 | // assertion class | |
159 | // | |
160 | // assertive_parsers are never instantiated directly. The assertion | |
161 | // class is used to indirectly create an assertive_parser object. | |
162 | // Before declaring the grammar, we declare some assertion objects. | |
163 | // Examples: | |
164 | // | |
165 | // enum Errors | |
166 | // { | |
167 | // program_expected, begin_expected, end_expected | |
168 | // }; | |
169 | // | |
170 | // assertion<Errors> expect_program(program_expected); | |
171 | // assertion<Errors> expect_begin(begin_expected); | |
172 | // assertion<Errors> expect_end(end_expected); | |
173 | // | |
174 | // Now, we can use these assertions as wrappers around parsers: | |
175 | // | |
176 | // expect_end(str_p("end")) | |
177 | // | |
178 | // Take note that although the example uses enums to hold the | |
179 | // information regarding the error (error desccriptor), we are free | |
180 | // to use other types such as integers and strings. Enums are | |
181 | // convenient for error handlers to easily catch since C++ treats | |
182 | // enums as unique types. | |
183 | // | |
184 | /////////////////////////////////////////////////////////////////////////// | |
185 | template <typename ErrorDescrT> | |
186 | struct assertion | |
187 | { | |
188 | assertion(ErrorDescrT descriptor_) | |
189 | : descriptor(descriptor_) {} | |
190 | ||
191 | template <typename ParserT> | |
192 | assertive_parser<ErrorDescrT, ParserT> | |
193 | operator()(ParserT const& parser) const | |
194 | { | |
195 | return assertive_parser<ErrorDescrT, ParserT>(parser, descriptor); | |
196 | } | |
197 | ||
198 | ErrorDescrT descriptor; | |
199 | }; | |
200 | ||
201 | /////////////////////////////////////////////////////////////////////////// | |
202 | // | |
203 | // error_status<T> | |
204 | // | |
205 | // Where T is an attribute type compatible with the match attribute | |
206 | // of the fallback_parser's subject (defaults to nil_t). The class | |
207 | // error_status reports the result of an error handler (see | |
208 | // fallback_parser). result can be one of: | |
209 | // | |
210 | // fail: quit and fail (return a no_match) | |
211 | // retry: attempt error recovery, possibly moving the scanner | |
212 | // accept: force success returning a matching length, moving | |
213 | // the scanner appropriately and returning an attribute | |
214 | // value | |
215 | // rethrow: rethrows the error. | |
216 | // | |
217 | /////////////////////////////////////////////////////////////////////////// | |
218 | template <typename T> | |
219 | struct error_status | |
220 | { | |
221 | enum result_t { fail, retry, accept, rethrow }; | |
222 | ||
223 | error_status( | |
224 | result_t result_ = fail, | |
225 | std::ptrdiff_t length_ = -1, | |
226 | T const& value_ = T()) | |
227 | : result(result_), length(length_), value(value_) {} | |
228 | ||
229 | result_t result; | |
230 | std::ptrdiff_t length; | |
231 | T value; | |
232 | }; | |
233 | ||
234 | /////////////////////////////////////////////////////////////////////////// | |
235 | // | |
236 | // fallback_parser class | |
237 | // | |
238 | // Handles exceptions of type parser_error<ErrorDescrT, IteratorT> | |
239 | // thrown somewhere inside its embedded ParserT object. The class | |
240 | // sets up a try block before delegating parsing to its subject. | |
241 | // When an exception is caught, the catch block then calls the | |
242 | // HandlerT object. HandlerT may be a function or a functor (with | |
243 | // an operator() member function) compatible with the interface: | |
244 | // | |
245 | // error_status<T> | |
246 | // handler(ScannerT const& scan, ErrorT error); | |
247 | // | |
248 | // Where scan points to the scanner state prior to parsing and error | |
249 | // is the error that arose (see parser_error). The handler must | |
250 | // return an error_status<T> object (see above). | |
251 | // | |
252 | /////////////////////////////////////////////////////////////////////////// | |
253 | namespace impl | |
254 | { | |
255 | template <typename RT, typename ParserT, typename ScannerT> | |
256 | RT fallback_parser_parse(ParserT const& p, ScannerT const& scan); | |
257 | } | |
258 | ||
259 | template <typename ErrorDescrT, typename ParserT, typename HandlerT> | |
260 | struct fallback_parser | |
261 | : public unary<ParserT, | |
262 | parser<fallback_parser<ErrorDescrT, ParserT, HandlerT> > > | |
263 | { | |
264 | typedef fallback_parser<ErrorDescrT, ParserT, HandlerT> | |
265 | self_t; | |
266 | typedef ErrorDescrT | |
267 | error_descr_t; | |
268 | typedef unary<ParserT, parser<self_t> > | |
269 | base_t; | |
270 | typedef unary_parser_category | |
271 | parser_category_t; | |
272 | ||
273 | fallback_parser(ParserT const& parser, HandlerT const& handler_) | |
274 | : base_t(parser), handler(handler_) {} | |
275 | ||
276 | template <typename ScannerT> | |
277 | struct result | |
278 | { | |
279 | typedef typename parser_result<ParserT, ScannerT>::type type; | |
280 | }; | |
281 | ||
282 | template <typename ScannerT> | |
283 | typename parser_result<self_t, ScannerT>::type | |
284 | parse(ScannerT const& scan) const | |
285 | { | |
286 | typedef typename parser_result<self_t, ScannerT>::type result_t; | |
287 | return impl::fallback_parser_parse<result_t>(*this, scan); | |
288 | } | |
289 | ||
290 | HandlerT handler; | |
291 | }; | |
292 | ||
293 | /////////////////////////////////////////////////////////////////////////// | |
294 | // | |
295 | // guard class | |
296 | // | |
297 | // fallback_parser objects are not instantiated directly. The guard | |
298 | // class is used to indirectly create a fallback_parser object. | |
299 | // guards are typically predeclared just like assertions (see the | |
300 | // assertion class above; the example extends the previous example | |
301 | // introduced in the assertion class above): | |
302 | // | |
303 | // guard<Errors> my_guard; | |
304 | // | |
305 | // Errors, in this example is the error descriptor type we want to | |
306 | // detect; This is essentially the ErrorDescrT template parameter | |
307 | // of the fallback_parser class. | |
308 | // | |
309 | // my_guard may now be used in a grammar declaration as: | |
310 | // | |
311 | // my_guard(p)[h] | |
312 | // | |
313 | // where p is a parser, h is a function or functor compatible with | |
314 | // fallback_parser's HandlerT (see above). | |
315 | // | |
316 | /////////////////////////////////////////////////////////////////////////// | |
317 | template <typename ErrorDescrT, typename ParserT> | |
318 | struct guard_gen : public unary<ParserT, nil_t> | |
319 | { | |
320 | typedef guard<ErrorDescrT> parser_generator_t; | |
321 | typedef unary_parser_category parser_category_t; | |
322 | ||
323 | guard_gen(ParserT const& p) | |
324 | : unary<ParserT, nil_t>(p) {} | |
325 | ||
326 | template <typename HandlerT> | |
327 | fallback_parser<ErrorDescrT, ParserT, HandlerT> | |
328 | operator[](HandlerT const& handler) const | |
329 | { | |
330 | return fallback_parser<ErrorDescrT, ParserT, HandlerT> | |
331 | (this->subject(), handler); | |
332 | } | |
333 | }; | |
334 | ||
335 | template <typename ErrorDescrT> | |
336 | struct guard | |
337 | { | |
338 | template <typename ParserT> | |
339 | struct result | |
340 | { | |
341 | typedef guard_gen<ErrorDescrT, ParserT> type; | |
342 | }; | |
343 | ||
344 | template <typename ParserT> | |
345 | static guard_gen<ErrorDescrT, ParserT> | |
346 | generate(ParserT const& parser) | |
347 | { | |
348 | return guard_gen<ErrorDescrT, ParserT>(parser); | |
349 | } | |
350 | ||
351 | template <typename ParserT> | |
352 | guard_gen<ErrorDescrT, ParserT> | |
353 | operator()(ParserT const& parser) const | |
354 | { | |
355 | return guard_gen<ErrorDescrT, ParserT>(parser); | |
356 | } | |
357 | }; | |
358 | ||
359 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
360 | ||
361 | }} // namespace BOOST_SPIRIT_CLASSIC_NS | |
362 | ||
363 | #include <boost/spirit/home/classic/error_handling/impl/exceptions.ipp> | |
364 | #endif | |
365 |