diff --git a/src/arm64/dom_parser_implementation.cpp b/src/arm64/dom_parser_implementation.cpp index 62609b5f2..fcdc14d7d 100644 --- a/src/arm64/dom_parser_implementation.cpp +++ b/src/arm64/dom_parser_implementation.cpp @@ -145,19 +145,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons } WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { - if (auto error = stage2::structural_parser::parse(*this, _doc)) { return error; } - - // If we didn't make it to the end, it's an error - if ( next_structural_index != n_structural_indexes ) { - logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); - return TAPE_ERROR; - } - - return SUCCESS; + doc = &_doc; + stage2::tape_builder builder(*doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { - return stage2::structural_parser::parse(*this, _doc); + doc = &_doc; + stage2::tape_builder builder(_doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept { diff --git a/src/fallback/dom_parser_implementation.cpp b/src/fallback/dom_parser_implementation.cpp index 24d4648a9..37d4ef2ca 100644 --- a/src/fallback/dom_parser_implementation.cpp +++ b/src/fallback/dom_parser_implementation.cpp @@ -322,19 +322,15 @@ namespace { namespace SIMDJSON_IMPLEMENTATION { WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { - if (auto error = stage2::structural_parser::parse(*this, _doc)) { return error; } - - // If we didn't make it to the end, it's an error - if ( next_structural_index != n_structural_indexes ) { - logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); - return TAPE_ERROR; - } - - return SUCCESS; + doc = &_doc; + stage2::tape_builder builder(*doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { - return stage2::structural_parser::parse(*this, _doc); + doc = &_doc; + stage2::tape_builder builder(_doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept { diff --git a/src/generic/stage2/structural_parser.h b/src/generic/stage2/structural_parser.h index c8e2b55a5..6fcbbeb98 100644 --- a/src/generic/stage2/structural_parser.h +++ b/src/generic/stage2/structural_parser.h @@ -12,54 +12,41 @@ namespace stage2 { #define SIMDJSON_TRY(EXPR) { auto _err = (EXPR); if (_err) { return _err; } } -template struct structural_parser : structural_iterator { - /** Receiver that actually parses the strings and builds the tape */ - T builder; /** Current depth (nested objects and arrays) */ uint32_t depth{0}; - template - WARN_UNUSED static really_inline error_code parse(dom_parser_implementation &dom_parser, dom::document &doc) noexcept; + template + WARN_UNUSED static really_inline error_code parse(dom_parser_implementation &dom_parser, T &builder) noexcept; // For non-streaming, to pass an explicit 0 as next_structural, which enables optimizations really_inline structural_parser(dom_parser_implementation &_parser, uint32_t start_structural_index) - : structural_iterator(_parser, start_structural_index), - builder{parser.doc->tape.get(), parser.doc->string_buf.get()} { + : structural_iterator(_parser, start_structural_index) { } WARN_UNUSED really_inline error_code start_document() { - builder.start_document(*this); parser.is_array[depth] = false; return SUCCESS; } - WARN_UNUSED really_inline error_code start_object() { + template + WARN_UNUSED really_inline error_code start_object(T &builder) { depth++; if (depth >= parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; } builder.start_object(*this); parser.is_array[depth] = false; return SUCCESS; } - WARN_UNUSED really_inline error_code start_array() { + template + WARN_UNUSED really_inline error_code start_array(T &builder) { depth++; if (depth >= parser.max_depth()) { log_error("Exceeded max depth!"); return DEPTH_ERROR; } builder.start_array(*this); parser.is_array[depth] = true; return SUCCESS; } - really_inline void end_object() { - builder.end_object(*this); - depth--; - } - really_inline void end_array() { - builder.end_array(*this); - depth--; - } - really_inline void end_document() { - builder.end_document(*this); - } - WARN_UNUSED really_inline bool empty_object() { + template + WARN_UNUSED really_inline bool empty_object(T &builder) { if (peek_next_char() == '}') { advance_char(); builder.empty_object(*this); @@ -67,7 +54,8 @@ struct structural_parser : structural_iterator { } return false; } - WARN_UNUSED really_inline bool empty_array() { + template + WARN_UNUSED really_inline bool empty_array(T &builder) { if (peek_next_char() == ']') { advance_char(); builder.empty_array(*this); @@ -76,53 +64,8 @@ struct structural_parser : structural_iterator { return false; } - really_inline void increment_count() { - builder.increment_count(*this); - } - - WARN_UNUSED really_inline error_code parse_key(const uint8_t *key) { - return builder.parse_key(*this, key); - } - WARN_UNUSED really_inline error_code parse_string(const uint8_t *value) { - return builder.parse_string(*this, value); - } - WARN_UNUSED really_inline error_code parse_number(const uint8_t *value) { - return builder.parse_number(*this, value); - } - WARN_UNUSED really_inline error_code parse_root_number(const uint8_t *value) { - return builder.parse_root_number(*this, value); - } - WARN_UNUSED really_inline error_code parse_true_atom(const uint8_t *value) { - return builder.parse_true_atom(*this, value); - } - WARN_UNUSED really_inline error_code parse_root_true_atom(const uint8_t *value) { - return builder.parse_root_true_atom(*this, value); - } - WARN_UNUSED really_inline error_code parse_false_atom(const uint8_t *value) { - return builder.parse_false_atom(*this, value); - } - WARN_UNUSED really_inline error_code parse_root_false_atom(const uint8_t *value) { - return builder.parse_root_false_atom(*this, value); - } - WARN_UNUSED really_inline error_code parse_null_atom(const uint8_t *value) { - return builder.parse_null_atom(*this, value); - } - WARN_UNUSED really_inline error_code parse_root_null_atom(const uint8_t *value) { - return builder.parse_root_null_atom(*this, value); - } - - WARN_UNUSED really_inline error_code start() { - logger::log_start(); - - // If there are no structurals left, return EMPTY - if (at_end()) { return EMPTY; } - - // Push the root scope (there is always at least one scope) - return start_document(); - } - + template WARN_UNUSED really_inline error_code finish() { - end_document(); parser.next_structural_index = uint32_t(next_structural - &parser.structural_indexes[0]); if (depth != 0) { @@ -130,6 +73,12 @@ struct structural_parser : structural_iterator { return TAPE_ERROR; } + // If we didn't make it to the end, it's an error + if ( !STREAMING && parser.next_structural_index != parser.n_structural_indexes ) { + logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); + return TAPE_ERROR; + } + return SUCCESS; } @@ -152,12 +101,17 @@ struct structural_parser : structural_iterator { } }; // struct structural_parser -template -template -WARN_UNUSED really_inline error_code structural_parser::parse(dom_parser_implementation &dom_parser, dom::document &doc) noexcept { - dom_parser.doc = &doc; - stage2::structural_parser parser(dom_parser, STREAMING ? dom_parser.next_structural_index : 0); - SIMDJSON_TRY( parser.start() ); +template +WARN_UNUSED really_inline error_code structural_parser::parse(dom_parser_implementation &dom_parser, T &builder) noexcept { + stage2::structural_parser parser(dom_parser, STREAMING ? dom_parser.next_structural_index : 0); + logger::log_start(); + + // + // Start the document + // + if (parser.at_end()) { return EMPTY; } + SIMDJSON_TRY( parser.start_document() ); + builder.start_document(parser); // // Read first value @@ -166,13 +120,13 @@ WARN_UNUSED really_inline error_code structural_parser::parse(dom_parser_impl const uint8_t *value = parser.advance(); switch (*value) { case '{': { - if (parser.empty_object()) { goto document_end; } - SIMDJSON_TRY( parser.start_object() ); + if (parser.empty_object(builder)) { goto document_end; } + SIMDJSON_TRY( parser.start_object(builder) ); goto object_begin; } case '[': { - if (parser.empty_array()) { goto document_end; } - SIMDJSON_TRY( parser.start_array() ); + if (parser.empty_array(builder)) { goto document_end; } + SIMDJSON_TRY( parser.start_array(builder) ); // Make sure the outer array is closed before continuing; otherwise, there are ways we could get // into memory corruption. See https://github.com/simdjson/simdjson/issues/906 if (!STREAMING) { @@ -182,14 +136,14 @@ WARN_UNUSED really_inline error_code structural_parser::parse(dom_parser_impl } goto array_begin; } - case '"': SIMDJSON_TRY( parser.parse_string(value) ); goto document_end; - case 't': SIMDJSON_TRY( parser.parse_root_true_atom(value) ); goto document_end; - case 'f': SIMDJSON_TRY( parser.parse_root_false_atom(value) ); goto document_end; - case 'n': SIMDJSON_TRY( parser.parse_root_null_atom(value) ); goto document_end; + case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); goto document_end; + case 't': SIMDJSON_TRY( builder.parse_root_true_atom(parser, value) ); goto document_end; + case 'f': SIMDJSON_TRY( builder.parse_root_false_atom(parser, value) ); goto document_end; + case 'n': SIMDJSON_TRY( builder.parse_root_null_atom(parser, value) ); goto document_end; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - SIMDJSON_TRY( parser.parse_root_number(value) ); goto document_end; + SIMDJSON_TRY( builder.parse_root_number(parser, value) ); goto document_end; default: parser.log_error("Document starts with a non-value character"); return TAPE_ERROR; @@ -205,8 +159,8 @@ object_begin: { parser.log_error("Object does not start with a key"); return TAPE_ERROR; } - parser.increment_count(); - SIMDJSON_TRY( parser.parse_key(key) ); + builder.increment_count(parser); + SIMDJSON_TRY( builder.parse_key(parser, key) ); goto object_field; } // object_begin: @@ -215,23 +169,23 @@ object_field: { const uint8_t *value = parser.advance(); switch (*value) { case '{': { - if (parser.empty_object()) { break; }; - SIMDJSON_TRY( parser.start_object() ); + if (parser.empty_object(builder)) { break; }; + SIMDJSON_TRY( parser.start_object(builder) ); goto object_begin; } case '[': { - if (parser.empty_array()) { break; }; - SIMDJSON_TRY( parser.start_array() ); + if (parser.empty_array(builder)) { break; }; + SIMDJSON_TRY( parser.start_array(builder) ); goto array_begin; } - case '"': SIMDJSON_TRY( parser.parse_string(value) ); break; - case 't': SIMDJSON_TRY( parser.parse_true_atom(value) ); break; - case 'f': SIMDJSON_TRY( parser.parse_false_atom(value) ); break; - case 'n': SIMDJSON_TRY( parser.parse_null_atom(value) ); break; + case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); break; + case 't': SIMDJSON_TRY( builder.parse_true_atom(parser, value) ); break; + case 'f': SIMDJSON_TRY( builder.parse_false_atom(parser, value) ); break; + case 'n': SIMDJSON_TRY( builder.parse_null_atom(parser, value) ); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - SIMDJSON_TRY( parser.parse_number(value) ); break; + SIMDJSON_TRY( builder.parse_number(parser, value) ); break; default: parser.log_error("Non-value found when value was expected!"); return TAPE_ERROR; @@ -241,14 +195,15 @@ object_field: { object_continue: { switch (parser.advance_char()) { case ',': { - parser.increment_count(); + builder.increment_count(parser); const uint8_t *key = parser.advance(); if (unlikely( *key != '"' )) { parser.log_error("Key string missing at beginning of field in object"); return TAPE_ERROR; } - SIMDJSON_TRY( parser.parse_key(key) ); + SIMDJSON_TRY( builder.parse_key(parser, key) ); goto object_field; } case '}': - parser.end_object(); + builder.end_object(parser); + parser.depth--; goto scope_end; default: parser.log_error("No comma between object fields"); @@ -266,30 +221,30 @@ scope_end: { // Array parser states // array_begin: { - parser.increment_count(); + builder.increment_count(parser); } // array_begin: array_value: { const uint8_t *value = parser.advance(); switch (*value) { case '{': { - if (parser.empty_object()) { break; }; - SIMDJSON_TRY( parser.start_object() ); + if (parser.empty_object(builder)) { break; }; + SIMDJSON_TRY( parser.start_object(builder) ); goto object_begin; } case '[': { - if (parser.empty_array()) { break; }; - SIMDJSON_TRY( parser.start_array() ); + if (parser.empty_array(builder)) { break; }; + SIMDJSON_TRY( parser.start_array(builder) ); goto array_begin; } - case '"': SIMDJSON_TRY( parser.parse_string(value) ); break; - case 't': SIMDJSON_TRY( parser.parse_true_atom(value) ); break; - case 'f': SIMDJSON_TRY( parser.parse_false_atom(value) ); break; - case 'n': SIMDJSON_TRY( parser.parse_null_atom(value) ); break; + case '"': SIMDJSON_TRY( builder.parse_string(parser, value) ); break; + case 't': SIMDJSON_TRY( builder.parse_true_atom(parser, value) ); break; + case 'f': SIMDJSON_TRY( builder.parse_false_atom(parser, value) ); break; + case 'n': SIMDJSON_TRY( builder.parse_null_atom(parser, value) ); break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - SIMDJSON_TRY( parser.parse_number(value) ); break; + SIMDJSON_TRY( builder.parse_number(parser, value) ); break; default: parser.log_error("Non-value found when value was expected!"); return TAPE_ERROR; @@ -299,10 +254,11 @@ array_value: { array_continue: { switch (parser.advance_char()) { case ',': - parser.increment_count(); + builder.increment_count(parser); goto array_value; case ']': - parser.end_array(); + builder.end_array(parser); + parser.depth--; goto scope_end; default: parser.log_error("Missing comma between array values"); @@ -311,7 +267,8 @@ array_continue: { } // array_continue: document_end: { - return parser.finish(); + builder.end_document(parser); + return parser.finish(); } // document_end: } // parse_structurals() diff --git a/src/generic/stage2/tape_builder.h b/src/generic/stage2/tape_builder.h index bf31295d9..022937e07 100644 --- a/src/generic/stage2/tape_builder.h +++ b/src/generic/stage2/tape_builder.h @@ -11,47 +11,52 @@ struct tape_builder { /** Next write location in the string buf for stage 2 parsing */ uint8_t *current_string_buf_loc; - really_inline void empty_object(structural_parser &parser) { + really_inline tape_builder(dom::document &doc) noexcept : tape{doc.tape.get()}, current_string_buf_loc{doc.string_buf.get()} {} + +private: + friend struct structural_parser; + + really_inline void empty_object(structural_parser &parser) { parser.log_value("empty object"); empty_container(parser, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT); } - really_inline void empty_array(structural_parser &parser) { + really_inline void empty_array(structural_parser &parser) { parser.log_value("empty array"); empty_container(parser, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY); } - really_inline void start_document(structural_parser &parser) { + really_inline void start_document(structural_parser &parser) { parser.log_start_value("document"); start_container(parser); } - really_inline void start_object(structural_parser &parser) { + really_inline void start_object(structural_parser &parser) { parser.log_start_value("object"); start_container(parser); } - really_inline void start_array(structural_parser &parser) { + really_inline void start_array(structural_parser &parser) { parser.log_start_value("array"); start_container(parser); } - really_inline void end_object(structural_parser &parser) { + really_inline void end_object(structural_parser &parser) { parser.log_end_value("object"); end_container(parser, internal::tape_type::START_OBJECT, internal::tape_type::END_OBJECT); } - really_inline void end_array(structural_parser &parser) { + really_inline void end_array(structural_parser &parser) { parser.log_end_value("array"); end_container(parser, internal::tape_type::START_ARRAY, internal::tape_type::END_ARRAY); } - really_inline void end_document(structural_parser &parser) { + really_inline void end_document(structural_parser &parser) { parser.log_end_value("document"); constexpr uint32_t start_tape_index = 0; tape.append(start_tape_index, internal::tape_type::ROOT); tape_writer::write(parser.parser.doc->tape[start_tape_index], next_tape_index(parser), internal::tape_type::ROOT); } - WARN_UNUSED really_inline error_code parse_key(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_key(structural_parser &parser, const uint8_t *value) { return parse_string(parser, value, true); } - WARN_UNUSED really_inline error_code parse_string(structural_parser &parser, const uint8_t *value, bool key = false) { + WARN_UNUSED really_inline error_code parse_string(structural_parser &parser, const uint8_t *value, bool key = false) { parser.log_value(key ? "key" : "string"); uint8_t *dst = on_start_string(parser); dst = stringparsing::parse_string(value, dst); @@ -63,13 +68,13 @@ struct tape_builder { return SUCCESS; } - WARN_UNUSED really_inline error_code parse_number(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_number(structural_parser &parser, const uint8_t *value) { parser.log_value("number"); if (!numberparsing::parse_number(value, tape)) { parser.log_error("Invalid number"); return NUMBER_ERROR; } return SUCCESS; } - really_inline error_code parse_root_number(structural_parser &parser, const uint8_t *value) { + really_inline error_code parse_root_number(structural_parser &parser, const uint8_t *value) { // // We need to make a copy to make sure that the string is space terminated. // This is not about padding the input, which should already padded up @@ -94,42 +99,42 @@ struct tape_builder { return error; } - WARN_UNUSED really_inline error_code parse_true_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_true_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("true"); if (!atomparsing::is_valid_true_atom(value)) { return T_ATOM_ERROR; } tape.append(0, internal::tape_type::TRUE_VALUE); return SUCCESS; } - WARN_UNUSED really_inline error_code parse_root_true_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_root_true_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("true"); if (!atomparsing::is_valid_true_atom(value, parser.remaining_len())) { return T_ATOM_ERROR; } tape.append(0, internal::tape_type::TRUE_VALUE); return SUCCESS; } - WARN_UNUSED really_inline error_code parse_false_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_false_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("false"); if (!atomparsing::is_valid_false_atom(value)) { return F_ATOM_ERROR; } tape.append(0, internal::tape_type::FALSE_VALUE); return SUCCESS; } - WARN_UNUSED really_inline error_code parse_root_false_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_root_false_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("false"); if (!atomparsing::is_valid_false_atom(value, parser.remaining_len())) { return F_ATOM_ERROR; } tape.append(0, internal::tape_type::FALSE_VALUE); return SUCCESS; } - WARN_UNUSED really_inline error_code parse_null_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_null_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("null"); if (!atomparsing::is_valid_null_atom(value)) { return N_ATOM_ERROR; } tape.append(0, internal::tape_type::NULL_VALUE); return SUCCESS; } - WARN_UNUSED really_inline error_code parse_root_null_atom(structural_parser &parser, const uint8_t *value) { + WARN_UNUSED really_inline error_code parse_root_null_atom(structural_parser &parser, const uint8_t *value) { parser.log_value("null"); if (!atomparsing::is_valid_null_atom(value, parser.remaining_len())) { return N_ATOM_ERROR; } tape.append(0, internal::tape_type::NULL_VALUE); @@ -137,29 +142,29 @@ struct tape_builder { } // increment_count increments the count of keys in an object or values in an array. - really_inline void increment_count(structural_parser &parser) { + really_inline void increment_count(structural_parser &parser) { parser.parser.containing_scope[parser.depth].count++; // we have a key value pair in the object at parser.parser.depth - 1 } // private: - really_inline uint32_t next_tape_index(structural_parser &parser) { + really_inline uint32_t next_tape_index(structural_parser &parser) { return uint32_t(tape.next_tape_loc - parser.parser.doc->tape.get()); } - really_inline void empty_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) { + really_inline void empty_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) { auto start_index = next_tape_index(parser); tape.append(start_index+2, start); tape.append(start_index, end); } - really_inline void start_container(structural_parser &parser) { + really_inline void start_container(structural_parser &parser) { parser.parser.containing_scope[parser.depth].tape_index = next_tape_index(parser); parser.parser.containing_scope[parser.depth].count = 0; tape.skip(); // We don't actually *write* the start element until the end. } - really_inline void end_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) noexcept { + really_inline void end_container(structural_parser &parser, internal::tape_type start, internal::tape_type end) noexcept { // Write the ending tape element, pointing at the start location const uint32_t start_tape_index = parser.parser.containing_scope[parser.depth].tape_index; tape.append(start_tape_index, end); @@ -171,7 +176,7 @@ struct tape_builder { tape_writer::write(parser.parser.doc->tape[start_tape_index], next_tape_index(parser) | (uint64_t(cntsat) << 32), start); } - really_inline uint8_t *on_start_string(structural_parser &parser) noexcept { + really_inline uint8_t *on_start_string(structural_parser &parser) noexcept { // we advance the point, accounting for the fact that we have a NULL termination tape.append(current_string_buf_loc - parser.parser.doc->string_buf.get(), internal::tape_type::STRING); return current_string_buf_loc + sizeof(uint32_t); diff --git a/src/haswell/dom_parser_implementation.cpp b/src/haswell/dom_parser_implementation.cpp index 9434ffd37..2b5af3bb6 100644 --- a/src/haswell/dom_parser_implementation.cpp +++ b/src/haswell/dom_parser_implementation.cpp @@ -108,19 +108,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons } WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { - if (auto error = stage2::structural_parser::parse(*this, _doc)) { return error; } - - // If we didn't make it to the end, it's an error - if ( next_structural_index != n_structural_indexes ) { - logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); - return TAPE_ERROR; - } - - return SUCCESS; + doc = &_doc; + stage2::tape_builder builder(_doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { - return stage2::structural_parser::parse(*this, _doc); + doc = &_doc; + stage2::tape_builder builder(_doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept { diff --git a/src/westmere/dom_parser_implementation.cpp b/src/westmere/dom_parser_implementation.cpp index 32b863a78..c3954b9d4 100644 --- a/src/westmere/dom_parser_implementation.cpp +++ b/src/westmere/dom_parser_implementation.cpp @@ -114,19 +114,15 @@ WARN_UNUSED bool implementation::validate_utf8(const char *buf, size_t len) cons } WARN_UNUSED error_code dom_parser_implementation::stage2(dom::document &_doc) noexcept { - if (auto error = stage2::structural_parser::parse(*this, _doc)) { return error; } - - // If we didn't make it to the end, it's an error - if ( next_structural_index != n_structural_indexes ) { - logger::log_string("More than one JSON value at the root of the document, or extra characters at the end of the JSON!"); - return TAPE_ERROR; - } - - return SUCCESS; + doc = &_doc; + stage2::tape_builder builder(*doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::stage2_next(dom::document &_doc) noexcept { - return stage2::structural_parser::parse(*this, _doc); + doc = &_doc; + stage2::tape_builder builder(_doc); + return stage2::structural_parser::parse(*this, builder); } WARN_UNUSED error_code dom_parser_implementation::parse(const uint8_t *_buf, size_t _len, dom::document &_doc) noexcept {