- fix a bug introduced by a perl bug workaround that would cause incremental parsing to fail with a sv_chop panic. #### End of document 1 panic: sv_chop ptr=4488b1, start=422038, end=4221f8 at parse_json.pl line 40, chunk 886. #### #!/usr/bin/perl use 5.024; use JSON::XS; use strict; use warnings; ################# # CHUNK_LENGTH is intentionally tiny to highlight the error my $CHUNK_LENGTH = \1; ################# ################### ## MAIN { my $json = new JSON::XS; my $buffer; my $statement_count = 0; # Incrementally parse an array of JSON objects local $/ = $CHUNK_LENGTH; # first parse the initial "[" INITIAL_PARSE_LOOP: while ( 1 ) { $buffer = ; $json->incr_parse($buffer); # void context, so no parsing # Exit the loop once we found the initial "[". # In essence, we are (ab-)using the $json object as a simple scalar # we append data to. last INITIAL_PARSE_LOOP if $json->incr_text =~ s/^.*?\[//msx; } # now we have the skipped the initial "[", so continue # parsing all the elements. PARSE_LOOP: while ( 1 ) { # clean up whitespace and padding $json->incr_text =~ s/^\s*(.+)\n/$1/gms; # in this loop we read data until we got a single JSON object STATEMENT_PARSE_LOOP: while ( 1 ) { if ( my $obj = $json->incr_parse ) { say "End of document ".++$statement_count; last STATEMENT_PARSE_LOOP; } # add more data $buffer = ; $json->incr_parse($buffer); # void context, so no parsing } # in this loop we read data until we either found and parsed the # separating "," between elements, or the final "]" CLEAN_UP_LOOP: while ( 1 ) { # first skip whitespace $json->incr_text =~ s/^\s*//; # if we find "]", we are done with the file last PARSE_LOOP if $json->incr_text =~ s/^\]//; # if we find ",", we can continue with the next element last CLEAN_UP_LOOP if $json->incr_text =~ s/^,//; # if we find anything else, we have a parse error! if ( length $json->incr_text ) { die "parse error near ".$json->incr_text; } # else add more data $buffer = ; $json->incr_parse($buffer); # void context, so no parsing } } } __DATA__ [ { "name": "xxxxxxxxxxxxxxx", "id": "xxxxxxxxxxxxxx", "previousBalance": "xxxxx", "currentMonth": "xxxxxxx", "total": "xxxxxxxx", "billingDate": "xxxxxxxxxxxxxx", "billingPeriod": "xxxxxxxxxxxxxxxxxxxxxxx", "invoiceDate": "xxxxxxxxxxx", "dueDate": "xxxxxxxxxxx", "autopay": false, "address": { "line1": "xxxxxxxxxxxxx", "line2": null, "city": "xxxxxxxxxxxx", "state": "xx", "zip": "xxxxxxxxxxx" } }, { "name": "xxxxxxxxxxxxxxx", "id": "xxxxxxxxxxxxxx", "previousBalance": "xxxxx", "currentMonth": "xxxxxxx", "total": "xxxxxxxx", "billingDate": "xxxxxxxxxxxxxx", "billingPeriod": "xxxxxxxxxxxxxxxxxxxxxxx", "invoiceDate": "xxxxxxxxxxx", "dueDate": "xxxxxxxxxxx", "autopay": false, "address": { "line1": "xxxxxxxxxxxxx", "line2": null, "city": "xxxxxxxxxxxx", "state": "xx", "zip": "xxxxxxxxxxx" } } ]