TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/boostorg/json
9 : //
10 :
11 : #ifndef BOOST_JSON_BASIC_PARSER_HPP
12 : #define BOOST_JSON_BASIC_PARSER_HPP
13 :
14 : #include <boost/json/detail/config.hpp>
15 : #include <boost/json/detail/except.hpp>
16 : #include <boost/json/error.hpp>
17 : #include <boost/json/kind.hpp>
18 : #include <boost/json/parse_options.hpp>
19 : #include <boost/json/detail/stack.hpp>
20 : #include <boost/json/detail/stream.hpp>
21 : #include <boost/json/detail/utf8.hpp>
22 : #include <boost/json/detail/sbo_buffer.hpp>
23 :
24 : namespace boost {
25 : namespace json {
26 :
27 : /** An incremental SAX parser for serialized JSON.
28 :
29 : This implements a SAX-style parser, invoking a caller-supplied handler with
30 : each parsing event. To use, first declare a variable of type
31 : `basic_parser<T>` where `T` meets the handler requirements specified below.
32 : Then call @ref write_some one or more times with the input, setting
33 : `more = false` on the final buffer. The parsing events are realized through
34 : member function calls on the handler, which exists as a data member of the
35 : parser.
36 :
37 : The parser may dynamically allocate intermediate storage as needed to
38 : accommodate the nesting level of the input JSON. On subsequent invocations,
39 : the parser can cheaply re-use this memory, improving performance. This
40 : storage is freed when the parser is destroyed
41 :
42 : @par Usage
43 : To get the declaration and function definitions for this class it is
44 : necessary to include this file instead:
45 : @code
46 : #include <boost/json/basic_parser_impl.hpp>
47 : @endcode
48 :
49 : Users who wish to parse JSON into the DOM container @ref value will not use
50 : this class directly; instead they will create an instance of @ref parser or
51 : @ref stream_parser and use that instead. Alternatively, they may call the
52 : function @ref parse. This class is designed for users who wish to perform
53 : custom actions instead of building a @ref value. For example, to produce a
54 : DOM from an external library.
55 :
56 : @note
57 : By default, only conforming JSON using UTF-8 encoding is accepted. However,
58 : select non-compliant syntax can be allowed by construction using a
59 : @ref parse_options set to desired values.
60 :
61 : @par Handler
62 : The handler provided must be implemented as an object of class type which
63 : defines each of the required event member functions below. The event
64 : functions return a `bool` where `true` indicates success, and `false`
65 : indicates failure. If the member function returns `false`, it must set the
66 : error code to a suitable value. This error code will be returned by the
67 : write function to the caller.
68 :
69 : Handlers are required to declare the maximum limits on various elements. If
70 : these limits are exceeded during parsing, then parsing fails with an error.
71 :
72 : The following declaration meets the parser's handler requirements:
73 :
74 : @code
75 : struct handler
76 : {
77 : /// The maximum number of elements allowed in an array
78 : static constexpr std::size_t max_array_size = -1;
79 :
80 : /// The maximum number of elements allowed in an object
81 : static constexpr std::size_t max_object_size = -1;
82 :
83 : /// The maximum number of characters allowed in a string
84 : static constexpr std::size_t max_string_size = -1;
85 :
86 : /// The maximum number of characters allowed in a key
87 : static constexpr std::size_t max_key_size = -1;
88 :
89 : /// Called once when the JSON parsing begins.
90 : ///
91 : /// @return `true` on success.
92 : /// @param ec Set to the error, if any occurred.
93 : ///
94 : bool on_document_begin( error_code& ec );
95 :
96 : /// Called when the JSON parsing is done.
97 : ///
98 : /// @return `true` on success.
99 : /// @param ec Set to the error, if any occurred.
100 : ///
101 : bool on_document_end( error_code& ec );
102 :
103 : /// Called when the beginning of an array is encountered.
104 : ///
105 : /// @return `true` on success.
106 : /// @param ec Set to the error, if any occurred.
107 : ///
108 : bool on_array_begin( error_code& ec );
109 :
110 : /// Called when the end of the current array is encountered.
111 : ///
112 : /// @return `true` on success.
113 : /// @param n The number of elements in the array.
114 : /// @param ec Set to the error, if any occurred.
115 : ///
116 : bool on_array_end( std::size_t n, error_code& ec );
117 :
118 : /// Called when the beginning of an object is encountered.
119 : ///
120 : /// @return `true` on success.
121 : /// @param ec Set to the error, if any occurred.
122 : ///
123 : bool on_object_begin( error_code& ec );
124 :
125 : /// Called when the end of the current object is encountered.
126 : ///
127 : /// @return `true` on success.
128 : /// @param n The number of elements in the object.
129 : /// @param ec Set to the error, if any occurred.
130 : ///
131 : bool on_object_end( std::size_t n, error_code& ec );
132 :
133 : /// Called with characters corresponding to part of the current string.
134 : ///
135 : /// @return `true` on success.
136 : /// @param s The partial characters
137 : /// @param n The total size of the string thus far
138 : /// @param ec Set to the error, if any occurred.
139 : ///
140 : bool on_string_part( string_view s, std::size_t n, error_code& ec );
141 :
142 : /// Called with the last characters corresponding to the current string.
143 : ///
144 : /// @return `true` on success.
145 : /// @param s The remaining characters
146 : /// @param n The total size of the string
147 : /// @param ec Set to the error, if any occurred.
148 : ///
149 : bool on_string( string_view s, std::size_t n, error_code& ec );
150 :
151 : /// Called with characters corresponding to part of the current key.
152 : ///
153 : /// @return `true` on success.
154 : /// @param s The partial characters
155 : /// @param n The total size of the key thus far
156 : /// @param ec Set to the error, if any occurred.
157 : ///
158 : bool on_key_part( string_view s, std::size_t n, error_code& ec );
159 :
160 : /// Called with the last characters corresponding to the current key.
161 : ///
162 : /// @return `true` on success.
163 : /// @param s The remaining characters
164 : /// @param n The total size of the key
165 : /// @param ec Set to the error, if any occurred.
166 : ///
167 : bool on_key( string_view s, std::size_t n, error_code& ec );
168 :
169 : /// Called with the characters corresponding to part of the current number.
170 : ///
171 : /// @return `true` on success.
172 : /// @param s The partial characters
173 : /// @param ec Set to the error, if any occurred.
174 : ///
175 : bool on_number_part( string_view s, error_code& ec );
176 :
177 : /// Called when a signed integer is parsed.
178 : ///
179 : /// @return `true` on success.
180 : /// @param i The value
181 : /// @param s The remaining characters
182 : /// @param ec Set to the error, if any occurred.
183 : ///
184 : bool on_int64( int64_t i, string_view s, error_code& ec );
185 :
186 : /// Called when an unsigend integer is parsed.
187 : ///
188 : /// @return `true` on success.
189 : /// @param u The value
190 : /// @param s The remaining characters
191 : /// @param ec Set to the error, if any occurred.
192 : ///
193 : bool on_uint64( uint64_t u, string_view s, error_code& ec );
194 :
195 : /// Called when a double is parsed.
196 : ///
197 : /// @return `true` on success.
198 : /// @param d The value
199 : /// @param s The remaining characters
200 : /// @param ec Set to the error, if any occurred.
201 : ///
202 : bool on_double( double d, string_view s, error_code& ec );
203 :
204 : /// Called when a boolean is parsed.
205 : ///
206 : /// @return `true` on success.
207 : /// @param b The value
208 : /// @param ec Set to the error, if any occurred.
209 : ///
210 : bool on_bool( bool b, error_code& ec );
211 :
212 : /// Called when a null is parsed.
213 : ///
214 : /// @return `true` on success.
215 : /// @param ec Set to the error, if any occurred.
216 : ///
217 : bool on_null( error_code& ec );
218 :
219 : /// Called with characters corresponding to part of the current comment.
220 : ///
221 : /// @return `true` on success.
222 : /// @param s The partial characters.
223 : /// @param ec Set to the error, if any occurred.
224 : ///
225 : bool on_comment_part( string_view s, error_code& ec );
226 :
227 : /// Called with the last characters corresponding to the current comment.
228 : ///
229 : /// @return `true` on success.
230 : /// @param s The remaining characters
231 : /// @param ec Set to the error, if any occurred.
232 : ///
233 : bool on_comment( string_view s, error_code& ec );
234 : };
235 : @endcode
236 :
237 : @see
238 : @ref parse,
239 : @ref stream_parser,
240 : \<\<examples_validate, validating parser example\>\>.
241 : */
242 : template<class Handler>
243 : class basic_parser
244 : {
245 : enum class state : char
246 : {
247 : doc1, doc3,
248 : com1, com2, com3, com4,
249 : lit1,
250 : str1, str2, str3, str4,
251 : str5, str6, str7, str8,
252 : sur1, sur2, sur3,
253 : sur4, sur5, sur6,
254 : obj1, obj2, obj3, obj4,
255 : obj5, obj6, obj7, obj8,
256 : obj9, obj10, obj11,
257 : arr1, arr2, arr3,
258 : arr4, arr5, arr6,
259 : num1, num2, num3, num4,
260 : num5, num6, num7, num8,
261 : exp1, exp2, exp3,
262 : val1, val2, val3
263 : };
264 :
265 : struct number
266 : {
267 : uint64_t mant;
268 : int bias;
269 : int exp;
270 : bool frac;
271 : bool neg;
272 : };
273 :
274 : template< bool StackEmpty_, char First_ >
275 : struct parse_number_helper;
276 :
277 : // optimization: must come first
278 : Handler h_;
279 :
280 : number num_;
281 : system::error_code ec_;
282 : detail::stack st_;
283 : detail::utf8_sequence seq_;
284 : unsigned u1_;
285 : unsigned u2_;
286 : bool more_; // false for final buffer
287 : bool done_ = false; // true on complete parse
288 : bool clean_ = true; // write_some exited cleanly
289 : const char* end_;
290 : detail::sbo_buffer<16 + 16 + 1 + 1> num_buf_;
291 : parse_options opt_;
292 : // how many levels deeper the parser can go
293 : std::size_t depth_ = opt_.max_depth;
294 : unsigned char cur_lit_ = 0;
295 : unsigned char lit_offset_ = 0;
296 :
297 : inline void reserve();
298 : inline const char* sentinel();
299 : inline bool incomplete(
300 : const detail::const_stream_wrapper& cs);
301 :
302 : #ifdef __INTEL_COMPILER
303 : #pragma warning push
304 : #pragma warning disable 2196
305 : #endif
306 :
307 : BOOST_NOINLINE
308 : inline
309 : const char*
310 : suspend_or_fail(state st);
311 :
312 : BOOST_NOINLINE
313 : inline
314 : const char*
315 : suspend_or_fail(
316 : state st,
317 : std::size_t n);
318 :
319 : BOOST_NOINLINE
320 : inline
321 : const char*
322 : fail(const char* p) noexcept;
323 :
324 : BOOST_NOINLINE
325 : inline
326 : const char*
327 : fail(
328 : const char* p,
329 : error ev,
330 : source_location const* loc) noexcept;
331 :
332 : BOOST_NOINLINE
333 : inline
334 : const char*
335 : maybe_suspend(
336 : const char* p,
337 : state st);
338 :
339 : BOOST_NOINLINE
340 : inline
341 : const char*
342 : maybe_suspend(
343 : const char* p,
344 : state st,
345 : std::size_t n);
346 :
347 : BOOST_NOINLINE
348 : inline
349 : const char*
350 : maybe_suspend(
351 : const char* p,
352 : state st,
353 : const number& num);
354 :
355 : BOOST_NOINLINE
356 : inline
357 : const char*
358 : suspend(
359 : const char* p,
360 : state st);
361 :
362 : BOOST_NOINLINE
363 : inline
364 : const char*
365 : suspend(
366 : const char* p,
367 : state st,
368 : const number& num);
369 :
370 : #ifdef __INTEL_COMPILER
371 : #pragma warning pop
372 : #endif
373 :
374 : template<bool StackEmpty_/*, bool Terminal_*/>
375 : const char* parse_comment(const char* p,
376 : std::integral_constant<bool, StackEmpty_> stack_empty,
377 : /*std::integral_constant<bool, Terminal_>*/ bool terminal);
378 :
379 : template<bool StackEmpty_>
380 : const char* parse_document(const char* p,
381 : std::integral_constant<bool, StackEmpty_> stack_empty);
382 :
383 : template<bool StackEmpty_, bool AllowComments_/*,
384 : bool AllowTrailing_, bool AllowBadUTF8_*/>
385 : const char* parse_value(const char* p,
386 : std::integral_constant<bool, StackEmpty_> stack_empty,
387 : std::integral_constant<bool, AllowComments_> allow_comments,
388 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
389 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
390 : bool allow_bad_utf16);
391 :
392 : template<bool AllowComments_/*,
393 : bool AllowTrailing_, bool AllowBadUTF8_*/>
394 : const char* resume_value(const char* p,
395 : std::integral_constant<bool, AllowComments_> allow_comments,
396 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
397 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
398 : bool allow_bad_utf16);
399 :
400 : template<bool StackEmpty_, bool AllowComments_/*,
401 : bool AllowTrailing_, bool AllowBadUTF8_*/>
402 : const char* parse_object(const char* p,
403 : std::integral_constant<bool, StackEmpty_> stack_empty,
404 : std::integral_constant<bool, AllowComments_> allow_comments,
405 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
406 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
407 : bool allow_bad_utf16);
408 :
409 : template<bool StackEmpty_, bool AllowComments_/*,
410 : bool AllowTrailing_, bool AllowBadUTF8_*/>
411 : const char* parse_array(const char* p,
412 : std::integral_constant<bool, StackEmpty_> stack_empty,
413 : std::integral_constant<bool, AllowComments_> allow_comments,
414 : /*std::integral_constant<bool, AllowTrailing_>*/ bool allow_trailing,
415 : /*std::integral_constant<bool, AllowBadUTF8_>*/ bool allow_bad_utf8,
416 : bool allow_bad_utf16);
417 :
418 : template<class Literal>
419 : const char* parse_literal(const char* p, Literal literal);
420 :
421 : template<bool StackEmpty_, bool IsKey_>
422 : const char* parse_string(const char* p,
423 : std::integral_constant<bool, StackEmpty_> stack_empty,
424 : std::integral_constant<bool, IsKey_> is_key,
425 : bool allow_bad_utf8,
426 : bool allow_bad_utf16);
427 :
428 : template<bool StackEmpty_>
429 : const char* parse_escaped(
430 : const char* p,
431 : std::size_t& total,
432 : std::integral_constant<bool, StackEmpty_> stack_empty,
433 : bool is_key,
434 : bool allow_bad_utf16);
435 :
436 : template<bool StackEmpty_, char First_, number_precision Numbers_>
437 : const char* parse_number(const char* p,
438 : std::integral_constant<bool, StackEmpty_> stack_empty,
439 : std::integral_constant<char, First_> first,
440 : std::integral_constant<number_precision, Numbers_> numbers);
441 :
442 : // intentionally private
443 : std::size_t
444 HIT 173075 : depth() const noexcept
445 : {
446 173075 : return opt_.max_depth - depth_;
447 : }
448 :
449 : public:
450 : /** Destructor.
451 :
452 : All dynamically allocated internal memory is freed.
453 :
454 : @par Effects
455 : @code
456 : handler().~Handler()
457 : @endcode
458 :
459 : @par Complexity
460 : Same as `~Handler()`.
461 :
462 : @par Exception Safety
463 : Same as `~Handler()`.
464 : */
465 2164604 : ~basic_parser() = default;
466 :
467 : /** Constructors.
468 :
469 : Overload **(1)** constructs the parser with the specified options, with
470 : any additional arguments forwarded to the handler's constructor.
471 :
472 : `basic_parser` is not copyable or movable, so the copy constructor is
473 : deleted.
474 :
475 : @par Complexity
476 : Same as `Handler( std::forward< Args >( args )... )`.
477 :
478 : @par Exception Safety
479 : Same as `Handler( std::forward< Args >( args )... )`.
480 :
481 : @param opt Configuration settings for the parser. If this structure is
482 : default constructed, the parser will accept only standard JSON.
483 : @param args Optional additional arguments forwarded to the handler's
484 : constructor.
485 :
486 : @{
487 : */
488 : template<class... Args>
489 : explicit
490 : basic_parser(
491 : parse_options const& opt,
492 : Args&&... args);
493 :
494 : /// Overload
495 : basic_parser(
496 : basic_parser const&) = delete;
497 : /// @}
498 :
499 : /** Assignment.
500 :
501 : This type cannot be copied or moved. The copy assignment is deleted.
502 : */
503 : basic_parser& operator=(
504 : basic_parser const&) = delete;
505 :
506 : /** Return a reference to the handler.
507 :
508 : This function provides access to the constructed
509 : instance of the handler owned by the parser.
510 :
511 : @par Complexity
512 : Constant.
513 :
514 : @par Exception Safety
515 : No-throw guarantee.
516 :
517 : @{
518 : */
519 : Handler&
520 6310634 : handler() noexcept
521 : {
522 6310634 : return h_;
523 : }
524 :
525 : Handler const&
526 24 : handler() const noexcept
527 : {
528 24 : return h_;
529 : }
530 : /// @}
531 :
532 : /** Return the last error.
533 :
534 : This returns the last error code which
535 : was generated in the most recent call
536 : to @ref write_some.
537 :
538 : @par Complexity
539 : Constant.
540 :
541 : @par Exception Safety
542 : No-throw guarantee.
543 : */
544 : system::error_code
545 8 : last_error() const noexcept
546 : {
547 8 : return ec_;
548 : }
549 :
550 : /** Check if a complete JSON text has been parsed.
551 :
552 : This function returns `true` when all of these conditions are met:
553 :
554 : @li A complete serialized JSON text has been presented to the parser,
555 : and
556 : @li No error or exception has occurred since the parser was
557 : constructed, or since the last call to @ref reset.
558 :
559 : @par Complexity
560 : Constant.
561 :
562 : @par Exception Safety
563 : No-throw guarantee.
564 : */
565 : bool
566 4078231 : done() const noexcept
567 : {
568 4078231 : return done_;
569 : }
570 :
571 : /** Reset the state, to parse a new document.
572 :
573 : This function discards the current parsing
574 : state, to prepare for parsing a new document.
575 : Dynamically allocated temporary memory used
576 : by the implementation is not deallocated.
577 :
578 : @par Complexity
579 : Constant.
580 :
581 : @par Exception Safety
582 : No-throw guarantee.
583 : */
584 : void
585 : reset() noexcept;
586 :
587 : /** Indicate a parsing failure.
588 :
589 : This changes the state of the parser to indicate that the parse has
590 : failed. A parser implementation can use this to fail the parser if
591 : needed due to external inputs.
592 :
593 : @attention
594 : If `! ec.failed()`, an implementation-defined error code that indicates
595 : failure will be stored instead.
596 :
597 : @par Complexity
598 : Constant.
599 :
600 : @par Exception Safety
601 : No-throw guarantee.
602 :
603 : @param ec The error code to set.
604 : */
605 : void
606 : fail(system::error_code ec) noexcept;
607 :
608 : /** Parse some of input characters as JSON, incrementally.
609 :
610 : This function parses the JSON text in the specified buffer, calling the
611 : handler to emit each SAX parsing event. The parse proceeds from the
612 : current state, which is at the beginning of a new JSON or in the middle
613 : of the current JSON if any characters were already parsed.
614 :
615 : The characters in the buffer are processed starting from the beginning,
616 : until one of the following conditions is met:
617 :
618 : @li All of the characters in the buffer have been parsed, or
619 : @li Some of the characters in the buffer have been parsed and the JSON
620 : is complete, or
621 : @li A parsing error occurs.
622 :
623 : The supplied buffer does not need to contain the entire JSON.
624 : Subsequent calls can provide more serialized data, allowing JSON to be
625 : processed incrementally. The end of the serialized JSON can be
626 : indicated by passing `more = false`.
627 :
628 : @par Complexity
629 : Linear in `size`.
630 :
631 : @par Exception Safety
632 : Basic guarantee. Calls to the handler may throw.
633 :
634 : Upon error or exception, subsequent calls will fail until @ref reset
635 : is called to parse a new JSON.
636 :
637 : @return The number of characters successfully
638 : parsed, which may be smaller than `size`.
639 :
640 : @param more `true` if there are possibly more buffers in the current
641 : JSON, otherwise `false`.
642 :
643 : @param data A pointer to a buffer of `size` characters to parse.
644 :
645 : @param size The number of characters pointed to by `data`.
646 :
647 : @param ec Set to the error, if any occurred.
648 :
649 : @{
650 : */
651 : std::size_t
652 : write_some(
653 : bool more,
654 : char const* data,
655 : std::size_t size,
656 : system::error_code& ec);
657 :
658 : std::size_t
659 : write_some(
660 : bool more,
661 : char const* data,
662 : std::size_t size,
663 : std::error_code& ec);
664 : /// @}
665 : };
666 :
667 : } // namespace json
668 : } // namespace boost
669 :
670 : #endif
|