Branch data Line data Source code
1 : : #pragma once
2 : :
3 : : #include <cassert> // assert
4 : : #include <cmath> // isfinite
5 : : #include <cstdint> // uint8_t
6 : : #include <functional> // function
7 : : #include <string> // string
8 : : #include <utility> // move
9 : : #include <vector> // vector
10 : :
11 : : #include <nlohmann/detail/exceptions.hpp>
12 : : #include <nlohmann/detail/input/input_adapters.hpp>
13 : : #include <nlohmann/detail/input/json_sax.hpp>
14 : : #include <nlohmann/detail/input/lexer.hpp>
15 : : #include <nlohmann/detail/macro_scope.hpp>
16 : : #include <nlohmann/detail/meta/is_sax.hpp>
17 : : #include <nlohmann/detail/value_t.hpp>
18 : :
19 : : namespace nlohmann
20 : : {
21 : : namespace detail
22 : : {
23 : : ////////////
24 : : // parser //
25 : : ////////////
26 : :
27 : : /*!
28 : : @brief syntax analysis
29 : :
30 : : This class implements a recursive decent parser.
31 : : */
32 : : template<typename BasicJsonType>
33 : 0 : class parser
34 : : {
35 : : using number_integer_t = typename BasicJsonType::number_integer_t;
36 : : using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
37 : : using number_float_t = typename BasicJsonType::number_float_t;
38 : : using string_t = typename BasicJsonType::string_t;
39 : : using lexer_t = lexer<BasicJsonType>;
40 : : using token_type = typename lexer_t::token_type;
41 : :
42 : : public:
43 : : enum class parse_event_t : uint8_t
44 : : {
45 : : /// the parser read `{` and started to process a JSON object
46 : : object_start,
47 : : /// the parser read `}` and finished processing a JSON object
48 : : object_end,
49 : : /// the parser read `[` and started to process a JSON array
50 : : array_start,
51 : : /// the parser read `]` and finished processing a JSON array
52 : : array_end,
53 : : /// the parser read a key of a value in an object
54 : : key,
55 : : /// the parser finished reading a JSON value
56 : : value
57 : : };
58 : :
59 : : using parser_callback_t =
60 : : std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
61 : :
62 : : /// a parser reading from an input adapter
63 : 0 : explicit parser(detail::input_adapter_t&& adapter,
64 : : const parser_callback_t cb = nullptr,
65 : : const bool allow_exceptions_ = true)
66 : 0 : : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
67 : : {
68 : : // read first token
69 : 0 : get_token();
70 : 0 : }
71 : :
72 : : /*!
73 : : @brief public parser interface
74 : :
75 : : @param[in] strict whether to expect the last token to be EOF
76 : : @param[in,out] result parsed JSON value
77 : :
78 : : @throw parse_error.101 in case of an unexpected token
79 : : @throw parse_error.102 if to_unicode fails or surrogate error
80 : : @throw parse_error.103 if to_unicode fails
81 : : */
82 : 0 : void parse(const bool strict, BasicJsonType& result)
83 : : {
84 : 0 : if (callback)
85 : : {
86 : 0 : json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
87 : 0 : sax_parse_internal(&sdp);
88 : 0 : result.assert_invariant();
89 : :
90 : : // in strict mode, input must be completely read
91 : 0 : if (strict and (get_token() != token_type::end_of_input))
92 : : {
93 : 0 : sdp.parse_error(m_lexer.get_position(),
94 : 0 : m_lexer.get_token_string(),
95 : 0 : parse_error::create(101, m_lexer.get_position(),
96 : 0 : exception_message(token_type::end_of_input, "value")));
97 : 0 : }
98 : :
99 : : // in case of an error, return discarded value
100 : 0 : if (sdp.is_errored())
101 : : {
102 : 0 : result = value_t::discarded;
103 : 0 : return;
104 : : }
105 : :
106 : : // set top-level value to null if it was discarded by the callback
107 : : // function
108 : 0 : if (result.is_discarded())
109 : : {
110 : 0 : result = nullptr;
111 : 0 : }
112 : 0 : }
113 : : else
114 : : {
115 : 0 : json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
116 : 0 : sax_parse_internal(&sdp);
117 : 0 : result.assert_invariant();
118 : :
119 : : // in strict mode, input must be completely read
120 : 0 : if (strict and (get_token() != token_type::end_of_input))
121 : : {
122 : 0 : sdp.parse_error(m_lexer.get_position(),
123 : 0 : m_lexer.get_token_string(),
124 : 0 : parse_error::create(101, m_lexer.get_position(),
125 : 0 : exception_message(token_type::end_of_input, "value")));
126 : 0 : }
127 : :
128 : : // in case of an error, return discarded value
129 : 0 : if (sdp.is_errored())
130 : : {
131 : 0 : result = value_t::discarded;
132 : 0 : return;
133 : : }
134 : 0 : }
135 : 0 : }
136 : :
137 : : /*!
138 : : @brief public accept interface
139 : :
140 : : @param[in] strict whether to expect the last token to be EOF
141 : : @return whether the input is a proper JSON text
142 : : */
143 : : bool accept(const bool strict = true)
144 : : {
145 : : json_sax_acceptor<BasicJsonType> sax_acceptor;
146 : : return sax_parse(&sax_acceptor, strict);
147 : : }
148 : :
149 : : template <typename SAX>
150 : : bool sax_parse(SAX* sax, const bool strict = true)
151 : : {
152 : : (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
153 : : const bool result = sax_parse_internal(sax);
154 : :
155 : : // strict mode: next byte must be EOF
156 : : if (result and strict and (get_token() != token_type::end_of_input))
157 : : {
158 : : return sax->parse_error(m_lexer.get_position(),
159 : : m_lexer.get_token_string(),
160 : : parse_error::create(101, m_lexer.get_position(),
161 : : exception_message(token_type::end_of_input, "value")));
162 : : }
163 : :
164 : : return result;
165 : : }
166 : :
167 : : private:
168 : : template <typename SAX>
169 : 0 : bool sax_parse_internal(SAX* sax)
170 : : {
171 : : // stack to remember the hierarchy of structured values we are parsing
172 : : // true = array; false = object
173 : 0 : std::vector<bool> states;
174 : : // value to avoid a goto (see comment where set to true)
175 : 0 : bool skip_to_state_evaluation = false;
176 : :
177 : 0 : while (true)
178 : : {
179 : 0 : if (not skip_to_state_evaluation)
180 : : {
181 : : // invariant: get_token() was called before each iteration
182 : 0 : switch (last_token)
183 : : {
184 : : case token_type::begin_object:
185 : : {
186 : 0 : if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
187 : : {
188 : 0 : return false;
189 : : }
190 : :
191 : : // closing } -> we are done
192 : 0 : if (get_token() == token_type::end_object)
193 : : {
194 : 0 : if (JSON_UNLIKELY(not sax->end_object()))
195 : : {
196 : 0 : return false;
197 : : }
198 : 0 : break;
199 : : }
200 : :
201 : : // parse key
202 : 0 : if (JSON_UNLIKELY(last_token != token_type::value_string))
203 : : {
204 : 0 : return sax->parse_error(m_lexer.get_position(),
205 : 0 : m_lexer.get_token_string(),
206 : 0 : parse_error::create(101, m_lexer.get_position(),
207 : 0 : exception_message(token_type::value_string, "object key")));
208 : : }
209 : 0 : if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
210 : : {
211 : 0 : return false;
212 : : }
213 : :
214 : : // parse separator (:)
215 : 0 : if (JSON_UNLIKELY(get_token() != token_type::name_separator))
216 : : {
217 : 0 : return sax->parse_error(m_lexer.get_position(),
218 : 0 : m_lexer.get_token_string(),
219 : 0 : parse_error::create(101, m_lexer.get_position(),
220 : 0 : exception_message(token_type::name_separator, "object separator")));
221 : : }
222 : :
223 : : // remember we are now inside an object
224 : 0 : states.push_back(false);
225 : :
226 : : // parse values
227 : 0 : get_token();
228 : 0 : continue;
229 : : }
230 : :
231 : : case token_type::begin_array:
232 : : {
233 : 0 : if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
234 : : {
235 : 0 : return false;
236 : : }
237 : :
238 : : // closing ] -> we are done
239 : 0 : if (get_token() == token_type::end_array)
240 : : {
241 : 0 : if (JSON_UNLIKELY(not sax->end_array()))
242 : : {
243 : 0 : return false;
244 : : }
245 : 0 : break;
246 : : }
247 : :
248 : : // remember we are now inside an array
249 : 0 : states.push_back(true);
250 : :
251 : : // parse values (no need to call get_token)
252 : 0 : continue;
253 : : }
254 : :
255 : : case token_type::value_float:
256 : : {
257 : 0 : const auto res = m_lexer.get_number_float();
258 : :
259 : 0 : if (JSON_UNLIKELY(not std::isfinite(res)))
260 : : {
261 : 0 : return sax->parse_error(m_lexer.get_position(),
262 : 0 : m_lexer.get_token_string(),
263 : 0 : out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
264 : : }
265 : :
266 : 0 : if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
267 : : {
268 : 0 : return false;
269 : : }
270 : :
271 : 0 : break;
272 : : }
273 : :
274 : : case token_type::literal_false:
275 : : {
276 : 0 : if (JSON_UNLIKELY(not sax->boolean(false)))
277 : : {
278 : 0 : return false;
279 : : }
280 : 0 : break;
281 : : }
282 : :
283 : : case token_type::literal_null:
284 : : {
285 : 0 : if (JSON_UNLIKELY(not sax->null()))
286 : : {
287 : 0 : return false;
288 : : }
289 : 0 : break;
290 : : }
291 : :
292 : : case token_type::literal_true:
293 : : {
294 : 0 : if (JSON_UNLIKELY(not sax->boolean(true)))
295 : : {
296 : 0 : return false;
297 : : }
298 : 0 : break;
299 : : }
300 : :
301 : : case token_type::value_integer:
302 : : {
303 : 0 : if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
304 : : {
305 : 0 : return false;
306 : : }
307 : 0 : break;
308 : : }
309 : :
310 : : case token_type::value_string:
311 : : {
312 : 0 : if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
313 : : {
314 : 0 : return false;
315 : : }
316 : 0 : break;
317 : : }
318 : :
319 : : case token_type::value_unsigned:
320 : : {
321 : 0 : if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
322 : : {
323 : 0 : return false;
324 : : }
325 : 0 : break;
326 : : }
327 : :
328 : : case token_type::parse_error:
329 : : {
330 : : // using "uninitialized" to avoid "expected" message
331 : 0 : return sax->parse_error(m_lexer.get_position(),
332 : 0 : m_lexer.get_token_string(),
333 : 0 : parse_error::create(101, m_lexer.get_position(),
334 : 0 : exception_message(token_type::uninitialized, "value")));
335 : : }
336 : :
337 : : default: // the last token was unexpected
338 : : {
339 : 0 : return sax->parse_error(m_lexer.get_position(),
340 : 0 : m_lexer.get_token_string(),
341 : 0 : parse_error::create(101, m_lexer.get_position(),
342 : 0 : exception_message(token_type::literal_or_value, "value")));
343 : : }
344 : : }
345 : 0 : }
346 : : else
347 : : {
348 : 0 : skip_to_state_evaluation = false;
349 : : }
350 : :
351 : : // we reached this line after we successfully parsed a value
352 : 0 : if (states.empty())
353 : : {
354 : : // empty stack: we reached the end of the hierarchy: done
355 : 0 : return true;
356 : : }
357 : :
358 : 0 : if (states.back()) // array
359 : : {
360 : : // comma -> next value
361 : 0 : if (get_token() == token_type::value_separator)
362 : : {
363 : : // parse a new value
364 : 0 : get_token();
365 : 0 : continue;
366 : : }
367 : :
368 : : // closing ]
369 : 0 : if (JSON_LIKELY(last_token == token_type::end_array))
370 : : {
371 : 0 : if (JSON_UNLIKELY(not sax->end_array()))
372 : : {
373 : 0 : return false;
374 : : }
375 : :
376 : : // We are done with this array. Before we can parse a
377 : : // new value, we need to evaluate the new state first.
378 : : // By setting skip_to_state_evaluation to false, we
379 : : // are effectively jumping to the beginning of this if.
380 : 0 : assert(not states.empty());
381 : 0 : states.pop_back();
382 : 0 : skip_to_state_evaluation = true;
383 : 0 : continue;
384 : : }
385 : :
386 : 0 : return sax->parse_error(m_lexer.get_position(),
387 : 0 : m_lexer.get_token_string(),
388 : 0 : parse_error::create(101, m_lexer.get_position(),
389 : 0 : exception_message(token_type::end_array, "array")));
390 : : }
391 : : else // object
392 : : {
393 : : // comma -> next value
394 : 0 : if (get_token() == token_type::value_separator)
395 : : {
396 : : // parse key
397 : 0 : if (JSON_UNLIKELY(get_token() != token_type::value_string))
398 : : {
399 : 0 : return sax->parse_error(m_lexer.get_position(),
400 : 0 : m_lexer.get_token_string(),
401 : 0 : parse_error::create(101, m_lexer.get_position(),
402 : 0 : exception_message(token_type::value_string, "object key")));
403 : : }
404 : :
405 : 0 : if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
406 : : {
407 : 0 : return false;
408 : : }
409 : :
410 : : // parse separator (:)
411 : 0 : if (JSON_UNLIKELY(get_token() != token_type::name_separator))
412 : : {
413 : 0 : return sax->parse_error(m_lexer.get_position(),
414 : 0 : m_lexer.get_token_string(),
415 : 0 : parse_error::create(101, m_lexer.get_position(),
416 : 0 : exception_message(token_type::name_separator, "object separator")));
417 : : }
418 : :
419 : : // parse values
420 : 0 : get_token();
421 : 0 : continue;
422 : : }
423 : :
424 : : // closing }
425 : 0 : if (JSON_LIKELY(last_token == token_type::end_object))
426 : : {
427 : 0 : if (JSON_UNLIKELY(not sax->end_object()))
428 : : {
429 : 0 : return false;
430 : : }
431 : :
432 : : // We are done with this object. Before we can parse a
433 : : // new value, we need to evaluate the new state first.
434 : : // By setting skip_to_state_evaluation to false, we
435 : : // are effectively jumping to the beginning of this if.
436 : 0 : assert(not states.empty());
437 : 0 : states.pop_back();
438 : 0 : skip_to_state_evaluation = true;
439 : 0 : continue;
440 : : }
441 : :
442 : 0 : return sax->parse_error(m_lexer.get_position(),
443 : 0 : m_lexer.get_token_string(),
444 : 0 : parse_error::create(101, m_lexer.get_position(),
445 : 0 : exception_message(token_type::end_object, "object")));
446 : : }
447 : : }
448 : 0 : }
449 : :
450 : : /// get next token from lexer
451 : 0 : token_type get_token()
452 : : {
453 : 0 : return last_token = m_lexer.scan();
454 : : }
455 : :
456 : 0 : std::string exception_message(const token_type expected, const std::string& context)
457 : : {
458 : 0 : std::string error_msg = "syntax error ";
459 : :
460 : 0 : if (not context.empty())
461 : : {
462 : 0 : error_msg += "while parsing " + context + " ";
463 : 0 : }
464 : :
465 : 0 : error_msg += "- ";
466 : :
467 : 0 : if (last_token == token_type::parse_error)
468 : : {
469 : 0 : error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
470 : 0 : m_lexer.get_token_string() + "'";
471 : 0 : }
472 : : else
473 : : {
474 : 0 : error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
475 : : }
476 : :
477 : 0 : if (expected != token_type::uninitialized)
478 : : {
479 : 0 : error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
480 : 0 : }
481 : :
482 : 0 : return error_msg;
483 : 0 : }
484 : :
485 : : private:
486 : : /// callback function
487 : : const parser_callback_t callback = nullptr;
488 : : /// the type of the last read token
489 : 0 : token_type last_token = token_type::uninitialized;
490 : : /// the lexer
491 : : lexer_t m_lexer;
492 : : /// whether to throw exceptions in case of errors
493 : : const bool allow_exceptions = true;
494 : : };
495 : : } // namespace detail
496 : : } // namespace nlohmann
|