Orcus
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 
16 namespace orcus {
17 
19 {
20 public:
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 
113 template<typename HandlerT>
115 {
116 public:
117  typedef HandlerT handler_type;
118 
125  json_parser(std::string_view content, handler_type& hdl);
126 
130  void parse();
131 
132 private:
133  void root_value();
134  void value();
135  void array();
136  void end_array();
137  void object();
138  void number();
139  void string();
140 
141 private:
142  handler_type& m_handler;
143 };
144 
145 template<typename _Handler>
147  std::string_view content, handler_type& hdl) :
148  json::parser_base(content), m_handler(hdl) {}
149 
150 template<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 
167 template<typename _Handler>
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 
186 template<typename _Handler>
187 void 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 
227 template<typename _Handler>
228 void 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 
277 template<typename _Handler>
278 void json_parser<_Handler>::end_array()
279 {
280  m_handler.end_array();
281  next();
282  skip_ws();
283 }
284 
285 template<typename _Handler>
286 void 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  if (res.length == parse_quoted_string_state::error_no_closing_quote)
323  throw parse_error("object: stream ended prematurely before reaching the closing quote of a key.", offset());
324  else if (res.length == parse_quoted_string_state::error_illegal_escape_char)
325  parse_error::throw_with(
326  "object: illegal escape character '", cur_char(), "' in key value.", offset());
327  else
328  throw parse_error("object: unknown error while parsing a key value.", offset());
329  }
330 
331  m_handler.object_key({res.str, res.length}, res.transient);
332 
333  skip_ws();
334  if (cur_char() != ':')
335  parse_error::throw_with(
336  "object: ':' was expected, but '", cur_char(), "' found.", offset());
337 
338  next();
339  skip_ws();
340 
341  if (!has_char())
342  throw parse_error("object: stream ended prematurely before reaching a value.", offset());
343 
344  value();
345 
346  skip_ws();
347  if (!has_char())
348  throw parse_error("object: stream ended prematurely before reaching either '}' or ','.", offset());
349 
350  switch (cur_char())
351  {
352  case '}':
353  m_handler.end_object();
354  next();
355  skip_ws();
356  return;
357  case ',':
358  require_new_key = true;
359  continue;
360  default:
361  parse_error::throw_with(
362  "object: either '}' or ',' expected, but '", cur_char(), "' found.", offset());
363  }
364  }
365 
366  throw parse_error("object: closing '}' was never reached.", offset());
367 }
368 
369 template<typename _Handler>
370 void json_parser<_Handler>::number()
371 {
372  assert(is_numeric(cur_char()) || cur_char() == '-');
373 
374  double val = parse_double_or_throw();
375  m_handler.number(val);
376  skip_ws();
377 }
378 
379 template<typename _Handler>
380 void json_parser<_Handler>::string()
381 {
382  parse_quoted_string_state res = parse_string();
383  if (res.str)
384  {
385  m_handler.string({res.str, res.length}, res.transient);
386  return;
387  }
388 
389  // Parsing was unsuccessful.
390  if (res.length == parse_quoted_string_state::error_no_closing_quote)
391  throw parse_error("string: stream ended prematurely before reaching the closing quote.", offset());
392  else if (res.length == parse_quoted_string_state::error_illegal_escape_char)
393  parse_error::throw_with("string: illegal escape character '", cur_char(), "'.", offset());
394  else
395  throw parse_error("string: unknown error.", offset());
396 }
397 
398 }
399 
400 #endif
401 
402 /* 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 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
Definition: json_parser.hpp:115
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
Definition: parser_base.hpp:23