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 : char const*
438 : parse_number(
439 : char const* p,
440 : std::integral_constant<bool, StackEmpty_> stack_empty,
441 : std::integral_constant<char, First_> first,
442 : std::integral_constant<number_precision, Numbers_> numbers);
443 :
444 : template<bool StackEmpty_, char First_>
445 : char const*
446 : skip_number(
447 : char const* p,
448 : std::integral_constant<bool, StackEmpty_> stack_empty,
449 : std::integral_constant<char, First_> first);
450 :
451 : // intentionally private
452 : std::size_t
453 HIT 173103 : depth() const noexcept
454 : {
455 173103 : return opt_.max_depth - depth_;
456 : }
457 :
458 : public:
459 : /** Destructor.
460 :
461 : All dynamically allocated internal memory is freed.
462 :
463 : @par Effects
464 : @code
465 : handler().~Handler()
466 : @endcode
467 :
468 : @par Complexity
469 : Same as `~Handler()`.
470 :
471 : @par Exception Safety
472 : Same as `~Handler()`.
473 : */
474 2164608 : ~basic_parser() = default;
475 :
476 : /** Constructors.
477 :
478 : Overload **(1)** constructs the parser with the specified options, with
479 : any additional arguments forwarded to the handler's constructor.
480 :
481 : `basic_parser` is not copyable or movable, so the copy constructor is
482 : deleted.
483 :
484 : @par Complexity
485 : Same as `Handler( std::forward< Args >( args )... )`.
486 :
487 : @par Exception Safety
488 : Same as `Handler( std::forward< Args >( args )... )`.
489 :
490 : @param opt Configuration settings for the parser. If this structure is
491 : default constructed, the parser will accept only standard JSON.
492 : @param args Optional additional arguments forwarded to the handler's
493 : constructor.
494 :
495 : @{
496 : */
497 : template<class... Args>
498 : explicit
499 : basic_parser(
500 : parse_options const& opt,
501 : Args&&... args);
502 :
503 : /// Overload
504 : basic_parser(
505 : basic_parser const&) = delete;
506 : /// @}
507 :
508 : /** Assignment.
509 :
510 : This type cannot be copied or moved. The copy assignment is deleted.
511 : */
512 : basic_parser& operator=(
513 : basic_parser const&) = delete;
514 :
515 : /** Return a reference to the handler.
516 :
517 : This function provides access to the constructed
518 : instance of the handler owned by the parser.
519 :
520 : @par Complexity
521 : Constant.
522 :
523 : @par Exception Safety
524 : No-throw guarantee.
525 :
526 : @{
527 : */
528 : Handler&
529 6310639 : handler() noexcept
530 : {
531 6310639 : return h_;
532 : }
533 :
534 : Handler const&
535 24 : handler() const noexcept
536 : {
537 24 : return h_;
538 : }
539 : /// @}
540 :
541 : /** Return the last error.
542 :
543 : This returns the last error code which
544 : was generated in the most recent call
545 : to @ref write_some.
546 :
547 : @par Complexity
548 : Constant.
549 :
550 : @par Exception Safety
551 : No-throw guarantee.
552 : */
553 : system::error_code
554 8 : last_error() const noexcept
555 : {
556 8 : return ec_;
557 : }
558 :
559 : /** Check if a complete JSON text has been parsed.
560 :
561 : This function returns `true` when all of these conditions are met:
562 :
563 : @li A complete serialized JSON text has been presented to the parser,
564 : and
565 : @li No error or exception has occurred since the parser was
566 : constructed, or since the last call to @ref reset.
567 :
568 : @par Complexity
569 : Constant.
570 :
571 : @par Exception Safety
572 : No-throw guarantee.
573 : */
574 : bool
575 4078231 : done() const noexcept
576 : {
577 4078231 : return done_;
578 : }
579 :
580 : /** Reset the state, to parse a new document.
581 :
582 : This function discards the current parsing
583 : state, to prepare for parsing a new document.
584 : Dynamically allocated temporary memory used
585 : by the implementation is not deallocated.
586 :
587 : @par Complexity
588 : Constant.
589 :
590 : @par Exception Safety
591 : No-throw guarantee.
592 : */
593 : void
594 : reset() noexcept;
595 :
596 : /** Indicate a parsing failure.
597 :
598 : This changes the state of the parser to indicate that the parse has
599 : failed. A parser implementation can use this to fail the parser if
600 : needed due to external inputs.
601 :
602 : @attention
603 : If `! ec.failed()`, an implementation-defined error code that indicates
604 : failure will be stored instead.
605 :
606 : @par Complexity
607 : Constant.
608 :
609 : @par Exception Safety
610 : No-throw guarantee.
611 :
612 : @param ec The error code to set.
613 : */
614 : void
615 : fail(system::error_code ec) noexcept;
616 :
617 : /** Parse some of input characters as JSON, incrementally.
618 :
619 : This function parses the JSON text in the specified buffer, calling the
620 : handler to emit each SAX parsing event. The parse proceeds from the
621 : current state, which is at the beginning of a new JSON or in the middle
622 : of the current JSON if any characters were already parsed.
623 :
624 : The characters in the buffer are processed starting from the beginning,
625 : until one of the following conditions is met:
626 :
627 : @li All of the characters in the buffer have been parsed, or
628 : @li Some of the characters in the buffer have been parsed and the JSON
629 : is complete, or
630 : @li A parsing error occurs.
631 :
632 : The supplied buffer does not need to contain the entire JSON.
633 : Subsequent calls can provide more serialized data, allowing JSON to be
634 : processed incrementally. The end of the serialized JSON can be
635 : indicated by passing `more = false`.
636 :
637 : @par Complexity
638 : Linear in `size`.
639 :
640 : @par Exception Safety
641 : Basic guarantee. Calls to the handler may throw.
642 :
643 : Upon error or exception, subsequent calls will fail until @ref reset
644 : is called to parse a new JSON.
645 :
646 : @return The number of characters successfully
647 : parsed, which may be smaller than `size`.
648 :
649 : @param more `true` if there are possibly more buffers in the current
650 : JSON, otherwise `false`.
651 :
652 : @param data A pointer to a buffer of `size` characters to parse.
653 :
654 : @param size The number of characters pointed to by `data`.
655 :
656 : @param ec Set to the error, if any occurred.
657 :
658 : @{
659 : */
660 : std::size_t
661 : write_some(
662 : bool more,
663 : char const* data,
664 : std::size_t size,
665 : system::error_code& ec);
666 :
667 : std::size_t
668 : write_some(
669 : bool more,
670 : char const* data,
671 : std::size_t size,
672 : std::error_code& ec);
673 : /// @}
674 : };
675 :
676 : } // namespace json
677 : } // namespace boost
678 :
679 : #endif
|