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