Orcus
Loading...
Searching...
No Matches
json_parser.hpp
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 */
7
8#ifndef INCLUDED_ORCUS_JSON_PARSER_HPP
9#define INCLUDED_ORCUS_JSON_PARSER_HPP
10
11#include "json_parser_base.hpp"
12
13#include <cassert>
14#include <cmath>
15
16namespace orcus {
17
19{
20public:
24 void begin_parse() {}
25
29 void end_parse() {}
30
34 void begin_array() {}
35
39 void end_array() {}
40
44 void begin_object() {}
45
56 void object_key(std::string_view key, bool transient)
57 {
58 (void)key; (void)transient;
59 }
60
64 void end_object() {}
65
69 void boolean_true() {}
70
74 void boolean_false() {}
75
79 void null() {}
80
91 void string(std::string_view val, bool transient)
92 {
93 (void)val; (void)transient;
94 }
95
101 void number(double val)
102 {
103 (void)val;
104 }
105};
106
113template<typename HandlerT>
115{
116public:
117 typedef HandlerT handler_type;
118
125 json_parser(std::string_view content, handler_type& hdl);
126
130 void parse();
131
132private:
133 void root_value();
134 void value();
135 void array();
136 void end_array();
137 void object();
138 void number();
139 void string();
140
141private:
142 handler_type& m_handler;
143};
144
145template<typename _Handler>
147 std::string_view content, handler_type& hdl) :
148 json::parser_base(content), m_handler(hdl) {}
149
150template<typename _Handler>
152{
153 m_handler.begin_parse();
154
155 skip_ws();
156 if (has_char())
157 root_value();
158 else
159 throw parse_error("parse: no json content could be found in file", offset());
160
161 if (has_char())
162 throw parse_error("parse: unexpected trailing string segment.", offset());
163
164 m_handler.end_parse();
165}
166
167template<typename _Handler>
168void json_parser<_Handler>::root_value()
169{
170 char c = cur_char();
171
172 switch (c)
173 {
174 case '[':
175 array();
176 break;
177 case '{':
178 object();
179 break;
180 default:
181 parse_error::throw_with(
182 "root_value: either '[' or '{' was expected, but '", cur_char(), "' was found.", offset());
183 }
184}
185
186template<typename _Handler>
187void json_parser<_Handler>::value()
188{
189 char c = cur_char();
190 if (is_numeric(c))
191 {
192 number();
193 return;
194 }
195
196 switch (c)
197 {
198 case '-':
199 number();
200 break;
201 case '[':
202 array();
203 break;
204 case '{':
205 object();
206 break;
207 case 't':
208 parse_true();
209 m_handler.boolean_true();
210 break;
211 case 'f':
212 parse_false();
213 m_handler.boolean_false();
214 break;
215 case 'n':
216 parse_null();
217 m_handler.null();
218 break;
219 case '"':
220 string();
221 break;
222 default:
223 parse_error::throw_with("value: failed to parse '", cur_char(), "'.", offset());
224 }
225}
226
227template<typename _Handler>
228void json_parser<_Handler>::array()
229{
230 assert(cur_char() == '[');
231
232 m_handler.begin_array();
233 for (next(); has_char(); next())
234 {
235 skip_ws();
236
237 if (cur_char() == ']')
238 {
239 end_array();
240 return;
241 }
242
243 value();
244 skip_ws();
245
246 if (has_char())
247 {
248 switch (cur_char())
249 {
250 case ']':
251 end_array();
252 return;
253 case ',':
254 if (peek_char() == ']')
255 {
256 parse_error::throw_with(
257 "array: ']' expected but '", cur_char(), "' found.", offset() );
258 }
259 continue;
260 default:
261 parse_error::throw_with(
262 "array: either ']' or ',' expected, but '", cur_char(), "' found.", offset());
263 }
264 }
265 else
266 {
267 // needs to be handled here,
268 // we would call next() before checking again with has_char() which
269 // is already past the end
270 break;
271 }
272 }
273
274 throw parse_error("array: failed to parse array.", offset());
275}
276
277template<typename _Handler>
278void json_parser<_Handler>::end_array()
279{
280 m_handler.end_array();
281 next();
282 skip_ws();
283}
284
285template<typename _Handler>
286void json_parser<_Handler>::object()
287{
288 assert(cur_char() == '{');
289
290 bool require_new_key = false;
291 m_handler.begin_object();
292 for (next(); has_char(); next())
293 {
294 skip_ws();
295 if (!has_char())
296 throw parse_error("object: stream ended prematurely before reaching a key.", offset());
297
298 switch (cur_char())
299 {
300 case '}':
301 if (require_new_key)
302 {
303 parse_error::throw_with(
304 "object: new key expected, but '", cur_char(), "' found.", offset());
305 }
306 m_handler.end_object();
307 next();
308 skip_ws();
309 return;
310 case '"':
311 break;
312 default:
313 parse_error::throw_with(
314 "object: '\"' was expected, but '", cur_char(), "' found.", offset());
315 }
316 require_new_key = false;
317
318 parse_quoted_string_state res = parse_string();
319 if (!res.str)
320 {
321 // Parsing was unsuccessful.
322 switch (res.length)
323 {
324 case parse_quoted_string_state::error_no_closing_quote:
325 throw parse_error("object: stream ended prematurely before reaching the closing quote of a key", offset());
326 case parse_quoted_string_state::error_illegal_escape_char:
327 parse_error::throw_with(
328 "object: illegal escape character '", cur_char(), "' in key value", offset());
329 break;
330 case parse_quoted_string_state::error_invalid_hex_digits:
331 throw parse_error("object: hex digits in escaped surrogate is invalid", offset());
332 default:
333 throw parse_error("object: unknown error while parsing a key value", offset());
334 }
335 }
336
337 m_handler.object_key({res.str, res.length}, res.transient);
338
339 skip_ws();
340 if (cur_char() != ':')
341 parse_error::throw_with(
342 "object: ':' was expected, but '", cur_char(), "' found.", offset());
343
344 next();
345 skip_ws();
346
347 if (!has_char())
348 throw parse_error("object: stream ended prematurely before reaching a value.", offset());
349
350 value();
351
352 skip_ws();
353 if (!has_char())
354 throw parse_error("object: stream ended prematurely before reaching either '}' or ','.", offset());
355
356 switch (cur_char())
357 {
358 case '}':
359 m_handler.end_object();
360 next();
361 skip_ws();
362 return;
363 case ',':
364 require_new_key = true;
365 continue;
366 default:
367 parse_error::throw_with(
368 "object: either '}' or ',' expected, but '", cur_char(), "' found.", offset());
369 }
370 }
371
372 throw parse_error("object: closing '}' was never reached.", offset());
373}
374
375template<typename _Handler>
376void json_parser<_Handler>::number()
377{
378 assert(is_numeric(cur_char()) || cur_char() == '-');
379
380 double val = parse_double_or_throw();
381 m_handler.number(val);
382 skip_ws();
383}
384
385template<typename _Handler>
386void json_parser<_Handler>::string()
387{
388 parse_quoted_string_state res = parse_string();
389 if (res.str)
390 {
391 m_handler.string({res.str, res.length}, res.transient);
392 return;
393 }
394
395 // Parsing was unsuccessful.
396 switch (res.length)
397 {
398 case parse_quoted_string_state::error_no_closing_quote:
399 throw parse_error("string: stream ended prematurely before reaching the closing quote", offset());
400 break;
401 case parse_quoted_string_state::error_illegal_escape_char:
402 parse_error::throw_with("string: illegal escape character '", cur_char(), "'", offset());
403 break;
404 case parse_quoted_string_state::error_invalid_hex_digits:
405 throw parse_error("string: invalid hex digits for unicode", offset());
406 break;
407 default:
408 {
409 std::ostringstream os;
410 os << "string: unknown error (code=" << res.length << ")";
411 throw parse_error(os.str(), offset());
412 }
413 }
414}
415
416}
417
418#endif
419
420/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Definition json_parser_base.hpp:20
Definition json_parser.hpp:19
void string(std::string_view val, bool transient)
Definition json_parser.hpp:91
void null()
Definition json_parser.hpp:79
void boolean_true()
Definition json_parser.hpp:69
void end_parse()
Definition json_parser.hpp:29
void begin_object()
Definition json_parser.hpp:44
void object_key(std::string_view key, bool transient)
Definition json_parser.hpp:56
void begin_parse()
Definition json_parser.hpp:24
void boolean_false()
Definition json_parser.hpp:74
void end_array()
Definition json_parser.hpp:39
void begin_array()
Definition json_parser.hpp:34
void end_object()
Definition json_parser.hpp:64
void number(double val)
Definition json_parser.hpp:101
json_parser(std::string_view content, handler_type &hdl)
Definition json_parser.hpp:146
void parse()
Definition json_parser.hpp:151
Definition exception.hpp:94
std::ptrdiff_t offset() const
Definition parser_global.hpp:40