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 value();
134 void array();
135 void end_array();
136 void object();
137 void number();
138 void string();
139
140private:
141 handler_type& m_handler;
142};
143
144template<typename _Handler>
146 std::string_view content, handler_type& hdl) :
147 json::parser_base(content), m_handler(hdl) {}
148
149template<typename _Handler>
151{
152 m_handler.begin_parse();
153
154 skip_ws();
155 if (has_char())
156 value();
157 else
158 throw parse_error("parse: no json content could be found in file", offset());
159
160 if (has_char())
161 throw parse_error("parse: unexpected trailing string segment.", offset());
162
163 m_handler.end_parse();
164}
165
166template<typename _Handler>
167void json_parser<_Handler>::value()
168{
169 char c = cur_char();
170 if (is_numeric(c))
171 {
172 number();
173 return;
174 }
175
176 switch (c)
177 {
178 case '-':
179 number();
180 break;
181 case '[':
182 array();
183 break;
184 case '{':
185 object();
186 break;
187 case 't':
188 parse_true();
189 m_handler.boolean_true();
190 break;
191 case 'f':
192 parse_false();
193 m_handler.boolean_false();
194 break;
195 case 'n':
196 parse_null();
197 m_handler.null();
198 break;
199 case '"':
200 string();
201 break;
202 default:
203 parse_error::throw_with("value: failed to parse '", cur_char(), "'.", offset());
204 }
205}
206
207template<typename _Handler>
208void json_parser<_Handler>::array()
209{
210 assert(cur_char() == '[');
211
212 m_handler.begin_array();
213 for (next(); has_char(); next())
214 {
215 skip_ws();
216
217 if (cur_char() == ']')
218 {
219 end_array();
220 return;
221 }
222
223 value();
224 skip_ws();
225
226 if (has_char())
227 {
228 switch (cur_char())
229 {
230 case ']':
231 end_array();
232 return;
233 case ',':
234 if (peek_char() == ']')
235 {
236 parse_error::throw_with(
237 "array: ']' expected but '", cur_char(), "' found.", offset() );
238 }
239 continue;
240 default:
241 parse_error::throw_with(
242 "array: either ']' or ',' expected, but '", cur_char(), "' found.", offset());
243 }
244 }
245 else
246 {
247 // needs to be handled here,
248 // we would call next() before checking again with has_char() which
249 // is already past the end
250 break;
251 }
252 }
253
254 throw parse_error("array: failed to parse array.", offset());
255}
256
257template<typename _Handler>
258void json_parser<_Handler>::end_array()
259{
260 m_handler.end_array();
261 next();
262 skip_ws();
263}
264
265template<typename _Handler>
266void json_parser<_Handler>::object()
267{
268 assert(cur_char() == '{');
269
270 bool require_new_key = false;
271 m_handler.begin_object();
272 for (next(); has_char(); next())
273 {
274 skip_ws();
275 if (!has_char())
276 throw parse_error("object: stream ended prematurely before reaching a key.", offset());
277
278 switch (cur_char())
279 {
280 case '}':
281 if (require_new_key)
282 {
283 parse_error::throw_with(
284 "object: new key expected, but '", cur_char(), "' found.", offset());
285 }
286 m_handler.end_object();
287 next();
288 skip_ws();
289 return;
290 case '"':
291 break;
292 default:
293 parse_error::throw_with(
294 "object: '\"' was expected, but '", cur_char(), "' found.", offset());
295 }
296 require_new_key = false;
297
298 parse_quoted_string_state res = parse_string();
299 if (!res.str)
300 {
301 // Parsing was unsuccessful.
302 switch (res.length)
303 {
304 case parse_quoted_string_state::error_no_closing_quote:
305 throw parse_error("object: stream ended prematurely before reaching the closing quote of a key", offset());
306 case parse_quoted_string_state::error_illegal_escape_char:
307 parse_error::throw_with(
308 "object: illegal escape character '", cur_char(), "' in key value", offset());
309 break;
310 case parse_quoted_string_state::error_invalid_hex_digits:
311 throw parse_error("object: hex digits in escaped surrogate is invalid", offset());
312 default:
313 throw parse_error("object: unknown error while parsing a key value", offset());
314 }
315 }
316
317 m_handler.object_key({res.str, res.length}, res.transient);
318
319 skip_ws();
320 if (cur_char() != ':')
321 parse_error::throw_with(
322 "object: ':' was expected, but '", cur_char(), "' found.", offset());
323
324 next();
325 skip_ws();
326
327 if (!has_char())
328 throw parse_error("object: stream ended prematurely before reaching a value.", offset());
329
330 value();
331
332 skip_ws();
333 if (!has_char())
334 throw parse_error("object: stream ended prematurely before reaching either '}' or ','.", offset());
335
336 switch (cur_char())
337 {
338 case '}':
339 m_handler.end_object();
340 next();
341 skip_ws();
342 return;
343 case ',':
344 require_new_key = true;
345 continue;
346 default:
347 parse_error::throw_with(
348 "object: either '}' or ',' expected, but '", cur_char(), "' found.", offset());
349 }
350 }
351
352 throw parse_error("object: closing '}' was never reached.", offset());
353}
354
355template<typename _Handler>
356void json_parser<_Handler>::number()
357{
358 assert(is_numeric(cur_char()) || cur_char() == '-');
359
360 double val = parse_double_or_throw();
361 m_handler.number(val);
362 skip_ws();
363}
364
365template<typename _Handler>
366void json_parser<_Handler>::string()
367{
368 parse_quoted_string_state res = parse_string();
369 if (res.str)
370 {
371 m_handler.string({res.str, res.length}, res.transient);
372 return;
373 }
374
375 // Parsing was unsuccessful.
376 switch (res.length)
377 {
378 case parse_quoted_string_state::error_no_closing_quote:
379 throw parse_error("string: stream ended prematurely before reaching the closing quote", offset());
380 break;
381 case parse_quoted_string_state::error_illegal_escape_char:
382 parse_error::throw_with("string: illegal escape character '", cur_char(), "'", offset());
383 break;
384 case parse_quoted_string_state::error_invalid_hex_digits:
385 throw parse_error("string: invalid hex digits for unicode", offset());
386 break;
387 default:
388 {
389 std::ostringstream os;
390 os << "string: unknown error (code=" << res.length << ")";
391 throw parse_error(os.str(), offset());
392 }
393 }
394}
395
396}
397
398#endif
399
400/* 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:145
void parse()
Definition json_parser.hpp:150
Definition exception.hpp:94
std::ptrdiff_t offset() const
Definition parser_global.hpp:40