summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2025-01-13 14:04:15 +0100
committerJean Boussier <[email protected]>2025-01-14 09:08:02 +0100
commit599fbeaffa8e029e11223c24af47a55500f23fc3 ()
treef2460eebc4afd103f29dc4ea76f580397a7a8928
parentc8d11edcf556088d10f0a245139741dcab1c7d56 (diff)
[ruby/json] Refactor JSON::Ext::Parser to split configuration and parsing state
Ref: https://.com/ruby/json/pull/718 The existing `Parser` interface is pretty bad, as it forces to instantiate a new instance for each document. Instead it's preferable to only take the config and do all the initialization needed, and then keep the parsing state on the stack on in ephemeral memory. This refactor makes the `JSON::Coder` pull request much easier to implement in a performant way. https://.com/ruby/json/commit/c8d5236a92 Co-Authored-By: Étienne Barrié <[email protected]>
-rw-r--r--ext/json/lib/json/common.rb11
-rw-r--r--ext/json/lib/json/ext.rb29
-rw-r--r--ext/json/parser/parser.c661
-rw-r--r--ext/json/parser/parser.rl309
-rw-r--r--test/json/json_ext_parser_test.rb8
5 files changed, 419 insertions, 599 deletions
@@ -232,12 +232,13 @@ module JSON
# - Option +max_nesting+, if not provided, defaults to +false+,
# which disables checking for nesting depth.
# - Option +allow_nan+, if not provided, defaults to +true+.
- def parse!(source, opts = {})
- opts = {
:max_nesting => false,
:allow_nan => true
- }.merge(opts)
- Parser.new(source, **(opts||{})).parse
end
# :call-seq:
@@ -258,7 +259,7 @@ module JSON
# JSON.parse!(File.read(path, opts))
#
# See method #parse!
- def load_file!(filespec, opts = {})
parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
end
@@ -6,15 +6,36 @@ module JSON
# This module holds all the modules/classes that implement JSON's
# functionality as C extensions.
module Ext
if RUBY_ENGINE == 'truffleruby'
- require 'json/ext/parser'
require 'json/truffle_ruby/generator'
- JSON.parser = Parser
JSON.generator = ::JSON::TruffleRuby::Generator
else
- require 'json/ext/parser'
require 'json/ext/generator'
- JSON.parser = Parser
JSON.generator = Generator
end
end
@@ -3,7 +3,7 @@
#include "ruby.h"
#include "../fbuffer/fbuffer.h"
-static VALUE mJSON, mExt, cParser, eNestingError, Encoding_UTF_8;
static VALUE CNaN, CInfinity, CMinusInfinity;
static ID i_json_creatable_p, i_json_create, i_create_id,
@@ -374,17 +374,11 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
}
typedef struct JSON_ParserStruct {
- VALUE Vsource;
- char *source;
- long len;
- char *memo;
VALUE create_id;
VALUE object_class;
VALUE array_class;
VALUE decimal_class;
VALUE match_string;
- FBuffer fbuffer;
- int in_array;
int max_nesting;
bool allow_nan;
bool allow_trailing_comma;
@@ -393,16 +387,22 @@ typedef struct JSON_ParserStruct {
bool freeze;
bool create_additions;
bool deprecated_create_additions;
- rvalue_cache name_cache;
- rvalue_stack *stack;
- VALUE stack_handle;
} JSON_Parser;
-#define GET_PARSER \
- GET_PARSER_INIT; \
- if (!json->Vsource) rb_raise(rb_eTypeError, "uninitialized instance")
-#define GET_PARSER_INIT \
JSON_Parser *json; \
TypedData_Get_Struct(self, JSON_Parser, &JSON_Parser_type, json)
@@ -410,12 +410,11 @@ typedef struct JSON_ParserStruct {
#define EVIL 0x666
static const rb_data_type_t JSON_Parser_type;
-static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
-static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result);
-static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-
#ifndef HAVE_STRNLEN
static size_t strnlen(const char *s, size_t maxlen)
@@ -447,11 +446,11 @@ static void raise_parse_error(const char *format, const char *start)
-#line 473 "parser.rl"
-#line 455 "parser.c"
enum {JSON_object_start = 1};
enum {JSON_object_first_final = 32};
enum {JSON_object_error = 0};
@@ -459,12 +458,12 @@ enum {JSON_object_error = 0};
enum {JSON_object_en_main = 1};
-#line 513 "parser.rl"
-#define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack)
-static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
@@ -472,17 +471,17 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
}
- long stack_head = json->stack->head;
-#line 479 "parser.c"
{
cs = JSON_object_start;
}
-#line 528 "parser.rl"
-#line 486 "parser.c"
{
short _widec;
if ( p == pe )
@@ -511,11 +510,11 @@ case 2:
goto st2;
goto st0;
tr2:
-#line 492 "parser.rl"
{
char *np;
json->parsing_name = true;
- np = JSON_parse_string(json, p, pe, result);
json->parsing_name = false;
if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else {
PUSH(*result);
@@ -527,7 +526,7 @@ st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 531 "parser.c"
switch( (*p) ) {
case 13: goto st3;
case 32: goto st3;
@@ -594,9 +593,9 @@ case 8:
goto st8;
goto st0;
tr11:
-#line 481 "parser.rl"
{
- char *np = JSON_parse_value(json, p, pe, result, current_nesting);
if (np == NULL) {
p--; {p++; cs = 9; goto _out;}
} else {
@@ -608,20 +607,20 @@ st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
-#line 612 "parser.c"
_widec = (*p);
if ( (*p) < 13 ) {
if ( (*p) > 9 ) {
if ( 10 <= (*p) && (*p) <= 10 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 9 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 13 ) {
@@ -629,26 +628,26 @@ case 9:
if ( 32 <= (*p) && (*p) <= 32 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 44 ) {
if ( 47 <= (*p) && (*p) <= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -669,14 +668,14 @@ case 9:
goto st10;
goto st0;
tr4:
-#line 503 "parser.rl"
{ p--; {p++; cs = 32; goto _out;} }
goto st32;
st32:
if ( ++p == pe )
goto _test_eof32;
case 32:
-#line 680 "parser.c"
goto st0;
st10:
if ( ++p == pe )
@@ -778,13 +777,13 @@ case 20:
if ( 47 <= (*p) && (*p) <= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 42 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -803,20 +802,20 @@ case 21:
if ( (*p) <= 41 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 42 ) {
if ( 43 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -839,13 +838,13 @@ case 22:
if ( 42 <= (*p) && (*p) <= 42 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 46 ) {
@@ -853,19 +852,19 @@ case 22:
if ( 48 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -889,20 +888,20 @@ case 23:
if ( (*p) <= 9 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 10 ) {
if ( 11 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 490 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -1016,15 +1015,15 @@ case 31:
_out: {}
}
-#line 529 "parser.rl"
if (cs >= JSON_object_first_final) {
- long count = json->stack->head - stack_head;
if (RB_UNLIKELY(json->object_class)) {
VALUE object = rb_class_new_instance(0, 0, json->object_class);
long index = 0;
- VALUE *items = rvalue_stack_peek(json->stack, count);
while (index < count) {
VALUE name = items[index++];
VALUE value = items[index++];
@@ -1038,10 +1037,10 @@ case 31:
#else
hash = rb_hash_new();
#endif
- rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash);
*result = hash;
}
- rvalue_stack_pop(json->stack, count);
if (RB_UNLIKELY(json->create_additions)) {
VALUE klassname;
@@ -1067,7 +1066,7 @@ case 31:
}
-#line 1071 "parser.c"
enum {JSON_value_start = 1};
enum {JSON_value_first_final = 29};
enum {JSON_value_error = 0};
@@ -1075,22 +1074,22 @@ enum {JSON_value_error = 0};
enum {JSON_value_en_main = 1};
-#line 662 "parser.rl"
-static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
-#line 1087 "parser.c"
{
cs = JSON_value_start;
}
-#line 669 "parser.rl"
-#line 1094 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1124,9 +1123,9 @@ st0:
cs = 0;
goto _out;
tr2:
-#line 607 "parser.rl"
{
- char *np = JSON_parse_string(json, p, pe, result);
if (np == NULL) {
p--;
{p++; cs = 29; goto _out;}
@@ -1136,7 +1135,7 @@ tr2:
}
goto st29;
tr3:
-#line 617 "parser.rl"
{
char *np;
if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
@@ -1148,7 +1147,7 @@ tr3:
raise_parse_error("unexpected token at '%s'", p);
}
}
- np = JSON_parse_number(json, p, pe, result);
if (np != NULL) {
{p = (( np))-1;}
}
@@ -1156,25 +1155,25 @@ tr3:
}
goto st29;
tr7:
-#line 635 "parser.rl"
{
char *np;
- json->in_array++;
- np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
- json->in_array--;
if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
}
goto st29;
tr11:
-#line 643 "parser.rl"
{
char *np;
- np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
}
goto st29;
tr25:
-#line 600 "parser.rl"
{
if (json->allow_nan) {
*result = CInfinity;
@@ -1184,7 +1183,7 @@ tr25:
}
goto st29;
tr27:
-#line 593 "parser.rl"
{
if (json->allow_nan) {
*result = CNaN;
@@ -1194,19 +1193,19 @@ tr27:
}
goto st29;
tr31:
-#line 587 "parser.rl"
{
*result = Qfalse;
}
goto st29;
tr34:
-#line 584 "parser.rl"
{
*result = Qnil;
}
goto st29;
tr37:
-#line 590 "parser.rl"
{
*result = Qtrue;
}
@@ -1215,9 +1214,9 @@ st29:
if ( ++p == pe )
goto _test_eof29;
case 29:
-#line 649 "parser.rl"
{ p--; {p++; cs = 29; goto _out;} }
-#line 1221 "parser.c"
switch( (*p) ) {
case 13: goto st29;
case 32: goto st29;
@@ -1458,7 +1457,7 @@ case 28:
_out: {}
}
-#line 670 "parser.rl"
if (json->freeze) {
OBJ_FREEZE(*result);
@@ -1473,7 +1472,7 @@ case 28:
}
-#line 1477 "parser.c"
enum {JSON_integer_start = 1};
enum {JSON_integer_first_final = 3};
enum {JSON_integer_error = 0};
@@ -1481,7 +1480,7 @@ enum {JSON_integer_error = 0};
enum {JSON_integer_en_main = 1};
-#line 691 "parser.rl"
#define MAX_FAST_INTEGER_SIZE 18
@@ -1506,22 +1505,22 @@ static inline VALUE fast_parse_integer(char *p, char *pe)
return LL2NUM(memo);
}
-static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
{
- long len = p - json->memo;
if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
- *result = fast_parse_integer(json->memo, p);
} else {
- fbuffer_clear(&json->fbuffer);
- fbuffer_append(&json->fbuffer, json->memo, len);
- fbuffer_append_char(&json->fbuffer, '\0');
- *result = rb_cstr2inum(FBUFFER_PTR(&json->fbuffer), 10);
}
return p + 1;
}
-#line 1525 "parser.c"
enum {JSON_float_start = 1};
enum {JSON_float_first_final = 6};
enum {JSON_float_error = 0};
@@ -1529,24 +1528,24 @@ enum {JSON_float_error = 0};
enum {JSON_float_en_main = 1};
-#line 743 "parser.rl"
-static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
int cs = EVIL;
bool is_float = false;
-#line 1542 "parser.c"
{
cs = JSON_float_start;
}
-#line 751 "parser.rl"
- json->memo = p;
-#line 1550 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -1586,24 +1585,24 @@ case 6:
goto st0;
goto tr7;
tr7:
-#line 735 "parser.rl"
{ p--; {p++; cs = 7; goto _out;} }
goto st7;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
-#line 1597 "parser.c"
goto st0;
tr8:
-#line 736 "parser.rl"
{ is_float = true; }
goto st3;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 1607 "parser.c"
if ( 48 <= (*p) && (*p) <= 57 )
goto st8;
goto st0;
@@ -1622,14 +1621,14 @@ case 8:
goto st0;
goto tr7;
tr9:
-#line 736 "parser.rl"
{ is_float = true; }
goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
-#line 1633 "parser.c"
switch( (*p) ) {
case 43: goto st5;
case 45: goto st5;
@@ -1686,11 +1685,11 @@ case 10:
_out: {}
}
-#line 753 "parser.rl"
if (cs >= JSON_float_first_final) {
if (!is_float) {
- return JSON_decode_integer(json, p, result);
}
VALUE mod = Qnil;
ID method_id = 0;
@@ -1722,16 +1721,16 @@ case 10:
}
}
- long len = p - json->memo;
- fbuffer_clear(&json->fbuffer);
- fbuffer_append(&json->fbuffer, json->memo, len);
- fbuffer_append_char(&json->fbuffer, '\0');
if (method_id) {
- VALUE text = rb_str_new2(FBUFFER_PTR(&json->fbuffer));
*result = rb_funcallv(mod, method_id, 1, &text);
} else {
- *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&json->fbuffer), 1));
}
return p + 1;
@@ -1742,7 +1741,7 @@ case 10:
-#line 1746 "parser.c"
enum {JSON_array_start = 1};
enum {JSON_array_first_final = 22};
enum {JSON_array_error = 0};
@@ -1750,27 +1749,27 @@ enum {JSON_array_error = 0};
enum {JSON_array_en_main = 1};
-#line 833 "parser.rl"
-static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
if (json->max_nesting && current_nesting > json->max_nesting) {
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
}
- long stack_head = json->stack->head;
-#line 1767 "parser.c"
{
cs = JSON_array_start;
}
-#line 845 "parser.rl"
-#line 1774 "parser.c"
{
short _widec;
if ( p == pe )
@@ -1810,10 +1809,10 @@ case 2:
goto st2;
goto st0;
tr2:
-#line 813 "parser.rl"
{
VALUE v = Qnil;
- char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
if (np == NULL) {
p--; {p++; cs = 3; goto _out;}
} else {
@@ -1825,12 +1824,12 @@ st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
-#line 1829 "parser.c"
_widec = (*p);
if ( 44 <= (*p) && (*p) <= 44 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -1877,14 +1876,14 @@ case 7:
goto st3;
goto st7;
tr4:
-#line 825 "parser.rl"
{ p--; {p++; cs = 22; goto _out;} }
goto st22;
st22:
if ( ++p == pe )
goto _test_eof22;
case 22:
-#line 1888 "parser.c"
goto st0;
st8:
if ( ++p == pe )
@@ -1952,13 +1951,13 @@ case 13:
if ( 10 <= (*p) && (*p) <= 10 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 9 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 13 ) {
@@ -1966,19 +1965,19 @@ case 13:
if ( 47 <= (*p) && (*p) <= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 32 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -2017,13 +2016,13 @@ case 14:
if ( 47 <= (*p) && (*p) <= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 42 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -2042,20 +2041,20 @@ case 15:
if ( (*p) <= 41 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 42 ) {
if ( 43 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -2078,13 +2077,13 @@ case 16:
if ( 42 <= (*p) && (*p) <= 42 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 46 ) {
@@ -2092,19 +2091,19 @@ case 16:
if ( 48 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) >= 47 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -2128,20 +2127,20 @@ case 17:
if ( (*p) <= 9 ) {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else if ( (*p) > 10 ) {
if ( 11 <= (*p) )
{ _widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
} else {
_widec = (short)(128 + ((*p) - -128));
if (
-#line 823 "parser.rl"
json->allow_trailing_comma ) _widec += 256;
}
switch( _widec ) {
@@ -2213,24 +2212,24 @@ case 21:
_out: {}
}
-#line 846 "parser.rl"
if(cs >= JSON_array_first_final) {
- long count = json->stack->head - stack_head;
if (RB_UNLIKELY(json->array_class)) {
VALUE array = rb_class_new_instance(0, 0, json->array_class);
- VALUE *items = rvalue_stack_peek(json->stack, count);
long index;
for (index = 0; index < count; index++) {
rb_funcall(array, i_leftshift, 1, items[index]);
}
*result = array;
} else {
- VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(json->stack, count));
*result = array;
}
- rvalue_stack_pop(json->stack, count);
return p + 1;
} else {
@@ -2265,16 +2264,16 @@ static inline VALUE build_string(const char *start, const char *end, bool intern
return result;
}
-static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
{
size_t bufferSize = stringEnd - string;
- if (is_name && json->in_array) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
} else {
- cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
}
if (RB_LIKELY(cached_key)) {
@@ -2285,19 +2284,19 @@ static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringE
return build_string(string, stringEnd, intern, symbolize);
}
-static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
{
size_t bufferSize = stringEnd - string;
char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
int unescape_len;
char buf[4];
- if (is_name && json->in_array) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
} else {
- cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
}
if (RB_LIKELY(cached_key)) {
@@ -2407,7 +2406,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE
}
-#line 2411 "parser.c"
enum {JSON_string_start = 1};
enum {JSON_string_first_final = 9};
enum {JSON_string_error = 0};
@@ -2415,7 +2414,7 @@ enum {JSON_string_error = 0};
enum {JSON_string_en_main = 1};
-#line 1069 "parser.rl"
static int
@@ -2430,21 +2429,21 @@ match_i(VALUE regexp, VALUE klass, VALUE memo)
return ST_CONTINUE;
}
-static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
int cs = EVIL;
VALUE match_string;
-#line 2440 "parser.c"
{
cs = JSON_string_start;
}
-#line 1089 "parser.rl"
- json->memo = p;
-#line 2448 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -2469,25 +2468,25 @@ case 2:
goto st0;
goto st2;
tr2:
-#line 1051 "parser.rl"
{
- *result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
{p = (( p + 1))-1;}
p--;
{p++; cs = 9; goto _out;}
}
-#line 1044 "parser.rl"
{
- *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
{p = (( p + 1))-1;}
p--;
{p++; cs = 9; goto _out;}
}
goto st9;
tr6:
-#line 1044 "parser.rl"
{
- *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
{p = (( p + 1))-1;}
p--;
{p++; cs = 9; goto _out;}
@@ -2497,7 +2496,7 @@ st9:
if ( ++p == pe )
goto _test_eof9;
case 9:
-#line 2501 "parser.c"
goto st0;
st3:
if ( ++p == pe )
@@ -2585,7 +2584,7 @@ case 8:
_out: {}
}
-#line 1091 "parser.rl"
if (json->create_additions && RTEST(match_string = json->match_string)) {
VALUE klass;
@@ -2660,13 +2659,8 @@ static int configure_parser_i(VALUE key, VALUE val, VALUE data)
return ST_CONTINUE;
}
-static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
{
- if (json->Vsource) {
- rb_raise(rb_eTypeError, "already initialized instance");
- }
-
- json->fbuffer.initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
json->max_nesting = 100;
if (!NIL_P(opts)) {
@@ -2688,17 +2682,12 @@ static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
}
}
- source = convert_encoding(StringValue(source));
- StringValue(source);
- json->len = RSTRING_LEN(source);
- json->source = RSTRING_PTR(source);
- json->Vsource = source;
}
/*
- * call-seq: new(source, opts => {})
*
- * Creates a new JSON::Ext::Parser instance for the string _source_.
*
* It will be configured by the _opts_ hash. _opts_ can have the following
* keys:
@@ -2727,18 +2716,16 @@ static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
* (Float) when parsing decimal numbers. This class must accept a single
* string argument in its constructor.
*/
-static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- GET_PARSER_INIT;
-
- rb_check_arity(argc, 1, 2);
- parser_init(json, argv[0], argc == 2 ? argv[1] : Qnil);
return self;
}
-#line 2742 "parser.c"
enum {JSON_start = 1};
enum {JSON_first_final = 10};
enum {JSON_error = 0};
@@ -2746,45 +2733,28 @@ enum {JSON_error = 0};
enum {JSON_en_main = 1};
-#line 1257 "parser.rl"
-/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- * It raises JSON::ParserError if fail to parse.
- */
-static VALUE cParser_parse(VALUE self)
{
char *p, *pe;
int cs = EVIL;
- VALUE result = Qnil;
- GET_PARSER;
-
- char stack_buffer[FBUFFER_STACK_SIZE];
- fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
-
- VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
- rvalue_stack stack = {
- .type = RVALUE_STACK_STACK_ALLOCATED,
- .ptr = rvalue_stack_buffer,
- .capa = RVALUE_STACK_INITIAL_CAPA,
- };
- json->stack = &stack;
-#line 2779 "parser.c"
{
cs = JSON_start;
}
-#line 1285 "parser.rl"
- p = json->source;
- pe = p + json->len;
-#line 2788 "parser.c"
{
if ( p == pe )
goto _test_eof;
@@ -2818,9 +2788,9 @@ st0:
cs = 0;
goto _out;
tr2:
-#line 1249 "parser.rl"
{
- char *np = JSON_parse_value(json, p, pe, &result, 0);
if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
}
goto st10;
@@ -2828,7 +2798,7 @@ st10:
if ( ++p == pe )
goto _test_eof10;
case 10:
-#line 2832 "parser.c"
switch( (*p) ) {
case 13: goto st10;
case 32: goto st10;
@@ -2917,10 +2887,10 @@ case 9:
_out: {}
}
-#line 1288 "parser.rl"
- if (json->stack_handle) {
- rvalue_stack_eagerly_release(json->stack_handle);
}
if (cs >= JSON_first_final && p == pe) {
@@ -2931,18 +2901,10 @@ case 9:
}
}
-static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts)
{
- char *p, *pe;
- int cs = EVIL;
- VALUE result = Qnil;
-
- JSON_Parser _parser = {0};
- JSON_Parser *json = &_parser;
- parser_init(json, source, opts);
-
- char stack_buffer[FBUFFER_STACK_SIZE];
- fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
rvalue_stack stack = {
@@ -2950,193 +2912,74 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts)
.ptr = rvalue_stack_buffer,
.capa = RVALUE_STACK_INITIAL_CAPA,
};
- json->stack = &stack;
-#line 2957 "parser.c"
- {
- cs = JSON_start;
- }
-#line 1323 "parser.rl"
- p = json->source;
- pe = p + json->len;
-#line 2966 "parser.c"
- {
- if ( p == pe )
- goto _test_eof;
- switch ( cs )
- {
-st1:
- if ( ++p == pe )
- goto _test_eof1;
-case 1:
- switch( (*p) ) {
- case 13: goto st1;
- case 32: goto st1;
- case 34: goto tr2;
- case 45: goto tr2;
- case 47: goto st6;
- case 73: goto tr2;
- case 78: goto tr2;
- case 91: goto tr2;
- case 102: goto tr2;
- case 110: goto tr2;
- case 116: goto tr2;
- case 123: goto tr2;
- }
- if ( (*p) > 10 ) {
- if ( 48 <= (*p) && (*p) <= 57 )
- goto tr2;
- } else if ( (*p) >= 9 )
- goto st1;
- goto st0;
-st0:
-cs = 0;
- goto _out;
-tr2:
-#line 1249 "parser.rl"
- {
- char *np = JSON_parse_value(json, p, pe, &result, 0);
- if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
}
- goto st10;
-st10:
- if ( ++p == pe )
- goto _test_eof10;
-case 10:
-#line 3010 "parser.c"
- switch( (*p) ) {
- case 13: goto st10;
- case 32: goto st10;
- case 47: goto st2;
- }
- if ( 9 <= (*p) && (*p) <= 10 )
- goto st10;
- goto st0;
-st2:
- if ( ++p == pe )
- goto _test_eof2;
-case 2:
- switch( (*p) ) {
- case 42: goto st3;
- case 47: goto st5;
- }
- goto st0;
-st3:
- if ( ++p == pe )
- goto _test_eof3;
-case 3:
- if ( (*p) == 42 )
- goto st4;
- goto st3;
-st4:
- if ( ++p == pe )
- goto _test_eof4;
-case 4:
- switch( (*p) ) {
- case 42: goto st4;
- case 47: goto st10;
- }
- goto st3;
-st5:
- if ( ++p == pe )
- goto _test_eof5;
-case 5:
- if ( (*p) == 10 )
- goto st10;
- goto st5;
-st6:
- if ( ++p == pe )
- goto _test_eof6;
-case 6:
- switch( (*p) ) {
- case 42: goto st7;
- case 47: goto st9;
- }
- goto st0;
-st7:
- if ( ++p == pe )
- goto _test_eof7;
-case 7:
- if ( (*p) == 42 )
- goto st8;
- goto st7;
-st8:
- if ( ++p == pe )
- goto _test_eof8;
-case 8:
- switch( (*p) ) {
- case 42: goto st8;
- case 47: goto st1;
- }
- goto st7;
-st9:
- if ( ++p == pe )
- goto _test_eof9;
-case 9:
- if ( (*p) == 10 )
- goto st1;
- goto st9;
- }
- _test_eof1: cs = 1; goto _test_eof;
- _test_eof10: cs = 10; goto _test_eof;
- _test_eof2: cs = 2; goto _test_eof;
- _test_eof3: cs = 3; goto _test_eof;
- _test_eof4: cs = 4; goto _test_eof;
- _test_eof5: cs = 5; goto _test_eof;
- _test_eof6: cs = 6; goto _test_eof;
- _test_eof7: cs = 7; goto _test_eof;
- _test_eof8: cs = 8; goto _test_eof;
- _test_eof9: cs = 9; goto _test_eof;
- _test_eof: {}
- _out: {}
- }
-#line 1326 "parser.rl"
- if (json->stack_handle) {
- rvalue_stack_eagerly_release(json->stack_handle);
- }
- if (cs >= JSON_first_final && p == pe) {
- return result;
- } else {
- raise_parse_error("unexpected token at '%s'", p);
- return Qnil;
- }
}
static void JSON_mark(void *ptr)
{
JSON_Parser *json = ptr;
- rb_gc_mark(json->Vsource);
rb_gc_mark(json->create_id);
rb_gc_mark(json->object_class);
rb_gc_mark(json->array_class);
rb_gc_mark(json->decimal_class);
rb_gc_mark(json->match_string);
- rb_gc_mark(json->stack_handle);
-
- long index;
- for (index = 0; index < json->name_cache.length; index++) {
- rb_gc_mark(json->name_cache.entries[index]);
- }
}
static void JSON_free(void *ptr)
{
JSON_Parser *json = ptr;
- fbuffer_free(&json->fbuffer);
ruby_xfree(json);
}
static size_t JSON_memsize(const void *ptr)
{
- const JSON_Parser *json = ptr;
- return sizeof(*json) + FBUFFER_CAPA(&json->fbuffer);
}
static const rb_data_type_t JSON_Parser_type = {
@@ -3149,21 +2992,7 @@ static const rb_data_type_t JSON_Parser_type = {
static VALUE cJSON_parser_s_allocate(VALUE klass)
{
JSON_Parser *json;
- VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
- fbuffer_stack_init(&json->fbuffer, 0, NULL, 0);
- return obj;
-}
-
-/*
- * call-seq: source()
- *
- * Returns a copy of the current _source_ string, that was used to construct
- * this Parser.
- */
-static VALUE cParser_source(VALUE self)
-{
- GET_PARSER;
- return rb_str_dup(json->Vsource);
}
void Init_parser(void)
@@ -3175,15 +3004,15 @@ void Init_parser(void)
#undef rb_intern
rb_require("json/common");
mJSON = rb_define_module("JSON");
- mExt = rb_define_module_under(mJSON, "Ext");
- cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
eNestingError = rb_path2class("JSON::NestingError");
rb_gc_register_mark_object(eNestingError);
- rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
- rb_define_method(cParser, "initialize", cParser_initialize, -1);
- rb_define_method(cParser, "parse", cParser_parse, 0);
- rb_define_method(cParser, "source", cParser_source, 0);
rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2);
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
@@ -1,7 +1,7 @@
#include "ruby.h"
#include "../fbuffer/fbuffer.h"
-static VALUE mJSON, mExt, cParser, eNestingError, Encoding_UTF_8;
static VALUE CNaN, CInfinity, CMinusInfinity;
static ID i_json_creatable_p, i_json_create, i_create_id,
@@ -372,17 +372,11 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
}
typedef struct JSON_ParserStruct {
- VALUE Vsource;
- char *source;
- long len;
- char *memo;
VALUE create_id;
VALUE object_class;
VALUE array_class;
VALUE decimal_class;
VALUE match_string;
- FBuffer fbuffer;
- int in_array;
int max_nesting;
bool allow_nan;
bool allow_trailing_comma;
@@ -391,16 +385,22 @@ typedef struct JSON_ParserStruct {
bool freeze;
bool create_additions;
bool deprecated_create_additions;
- rvalue_cache name_cache;
- rvalue_stack *stack;
- VALUE stack_handle;
} JSON_Parser;
-#define GET_PARSER \
- GET_PARSER_INIT; \
- if (!json->Vsource) rb_raise(rb_eTypeError, "uninitialized instance")
-#define GET_PARSER_INIT \
JSON_Parser *json; \
TypedData_Get_Struct(self, JSON_Parser, &JSON_Parser_type, json)
@@ -408,12 +408,11 @@ typedef struct JSON_ParserStruct {
#define EVIL 0x666
static const rb_data_type_t JSON_Parser_type;
-static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
-static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result);
-static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
-
#ifndef HAVE_STRNLEN
static size_t strnlen(const char *s, size_t maxlen)
@@ -479,7 +478,7 @@ static void raise_parse_error(const char *format, const char *start)
write data;
action parse_value {
- char *np = JSON_parse_value(json, fpc, pe, result, current_nesting);
if (np == NULL) {
fhold; fbreak;
} else {
@@ -492,7 +491,7 @@ static void raise_parse_error(const char *format, const char *start)
action parse_name {
char *np;
json->parsing_name = true;
- np = JSON_parse_string(json, fpc, pe, result);
json->parsing_name = false;
if (np == NULL) { fhold; fbreak; } else {
PUSH(*result);
@@ -512,9 +511,9 @@ static void raise_parse_error(const char *format, const char *start)
) @exit;
}%%
-#define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack)
-static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
@@ -522,18 +521,18 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
}
- long stack_head = json->stack->head;
%% write init;
%% write exec;
if (cs >= JSON_object_first_final) {
- long count = json->stack->head - stack_head;
if (RB_UNLIKELY(json->object_class)) {
VALUE object = rb_class_new_instance(0, 0, json->object_class);
long index = 0;
- VALUE *items = rvalue_stack_peek(json->stack, count);
while (index < count) {
VALUE name = items[index++];
VALUE value = items[index++];
@@ -547,10 +546,10 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
#else
hash = rb_hash_new();
#endif
- rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash);
*result = hash;
}
- rvalue_stack_pop(json->stack, count);
if (RB_UNLIKELY(json->create_additions)) {
VALUE klassname;
@@ -605,7 +604,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
}
}
action parse_string {
- char *np = JSON_parse_string(json, fpc, pe, result);
if (np == NULL) {
fhold;
fbreak;
@@ -625,7 +624,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
raise_parse_error("unexpected token at '%s'", p);
}
}
- np = JSON_parse_number(json, fpc, pe, result);
if (np != NULL) {
fexec np;
}
@@ -634,15 +633,15 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
action parse_array {
char *np;
- json->in_array++;
- np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
- json->in_array--;
if (np == NULL) { fhold; fbreak; } else fexec np;
}
action parse_object {
char *np;
- np = JSON_parse_object(json, fpc, pe, result, current_nesting + 1);
if (np == NULL) { fhold; fbreak; } else fexec np;
}
@@ -661,7 +660,7 @@ main := ignore* (
) ignore* %*exit;
}%%
-static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
@@ -712,16 +711,16 @@ static inline VALUE fast_parse_integer(char *p, char *pe)
return LL2NUM(memo);
}
-static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
{
- long len = p - json->memo;
if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
- *result = fast_parse_integer(json->memo, p);
} else {
- fbuffer_clear(&json->fbuffer);
- fbuffer_append(&json->fbuffer, json->memo, len);
- fbuffer_append_char(&json->fbuffer, '\0');
- *result = rb_cstr2inum(FBUFFER_PTR(&json->fbuffer), 10);
}
return p + 1;
}
@@ -742,18 +741,18 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
) (^[0-9Ee.\-]? @exit ));
}%%
-static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
int cs = EVIL;
bool is_float = false;
%% write init;
- json->memo = p;
%% write exec;
if (cs >= JSON_float_first_final) {
if (!is_float) {
- return JSON_decode_integer(json, p, result);
}
VALUE mod = Qnil;
ID method_id = 0;
@@ -785,16 +784,16 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu
}
}
- long len = p - json->memo;
- fbuffer_clear(&json->fbuffer);
- fbuffer_append(&json->fbuffer, json->memo, len);
- fbuffer_append_char(&json->fbuffer, '\0');
if (method_id) {
- VALUE text = rb_str_new2(FBUFFER_PTR(&json->fbuffer));
*result = rb_funcallv(mod, method_id, 1, &text);
} else {
- *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&json->fbuffer), 1));
}
return p + 1;
@@ -812,7 +811,7 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu
action parse_value {
VALUE v = Qnil;
- char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
if (np == NULL) {
fhold; fbreak;
} else {
@@ -832,34 +831,34 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu
end_array @exit;
}%%
-static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
{
int cs = EVIL;
if (json->max_nesting && current_nesting > json->max_nesting) {
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
}
- long stack_head = json->stack->head;
%% write init;
%% write exec;
if(cs >= JSON_array_first_final) {
- long count = json->stack->head - stack_head;
if (RB_UNLIKELY(json->array_class)) {
VALUE array = rb_class_new_instance(0, 0, json->array_class);
- VALUE *items = rvalue_stack_peek(json->stack, count);
long index;
for (index = 0; index < count; index++) {
rb_funcall(array, i_leftshift, 1, items[index]);
}
*result = array;
} else {
- VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(json->stack, count));
*result = array;
}
- rvalue_stack_pop(json->stack, count);
return p + 1;
} else {
@@ -894,16 +893,16 @@ static inline VALUE build_string(const char *start, const char *end, bool intern
return result;
}
-static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
{
size_t bufferSize = stringEnd - string;
- if (is_name && json->in_array) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
} else {
- cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
}
if (RB_LIKELY(cached_key)) {
@@ -914,19 +913,19 @@ static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringE
return build_string(string, stringEnd, intern, symbolize);
}
-static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
{
size_t bufferSize = stringEnd - string;
char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
int unescape_len;
char buf[4];
- if (is_name && json->in_array) {
VALUE cached_key;
if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
} else {
- cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
}
if (RB_LIKELY(cached_key)) {
@@ -1042,14 +1041,14 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE
write data;
action parse_complex_string {
- *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
fexec p + 1;
fhold;
fbreak;
}
action parse_simple_string {
- *result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
fexec p + 1;
fhold;
fbreak;
@@ -1080,13 +1079,13 @@ match_i(VALUE regexp, VALUE klass, VALUE memo)
return ST_CONTINUE;
}
-static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
{
int cs = EVIL;
VALUE match_string;
%% write init;
- json->memo = p;
%% write exec;
if (json->create_additions && RTEST(match_string = json->match_string)) {
@@ -1162,13 +1161,8 @@ static int configure_parser_i(VALUE key, VALUE val, VALUE data)
return ST_CONTINUE;
}
-static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
{
- if (json->Vsource) {
- rb_raise(rb_eTypeError, "already initialized instance");
- }
-
- json->fbuffer.initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
json->max_nesting = 100;
if (!NIL_P(opts)) {
@@ -1190,17 +1184,12 @@ static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
}
}
- source = convert_encoding(StringValue(source));
- StringValue(source);
- json->len = RSTRING_LEN(source);
- json->source = RSTRING_PTR(source);
- json->Vsource = source;
}
/*
- * call-seq: new(source, opts => {})
*
- * Creates a new JSON::Ext::Parser instance for the string _source_.
*
* It will be configured by the _opts_ hash. _opts_ can have the following
* keys:
@@ -1229,13 +1218,11 @@ static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
* (Float) when parsing decimal numbers. This class must accept a single
* string argument in its constructor.
*/
-static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
{
- GET_PARSER_INIT;
-
- rb_check_arity(argc, 1, 2);
- parser_init(json, argv[0], argc == 2 ? argv[1] : Qnil);
return self;
}
@@ -1247,7 +1234,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
include JSON_common;
action parse_value {
- char *np = JSON_parse_value(json, fpc, pe, &result, 0);
if (np == NULL) { fhold; fbreak; } else fexec np;
}
@@ -1256,38 +1243,21 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
) ignore*;
}%%
-/*
- * call-seq: parse()
- *
- * Parses the current JSON text _source_ and returns the complete data
- * structure as a result.
- * It raises JSON::ParserError if fail to parse.
- */
-static VALUE cParser_parse(VALUE self)
{
char *p, *pe;
int cs = EVIL;
- VALUE result = Qnil;
- GET_PARSER;
-
- char stack_buffer[FBUFFER_STACK_SIZE];
- fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
-
- VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
- rvalue_stack stack = {
- .type = RVALUE_STACK_STACK_ALLOCATED,
- .ptr = rvalue_stack_buffer,
- .capa = RVALUE_STACK_INITIAL_CAPA,
- };
- json->stack = &stack;
%% write init;
- p = json->source;
- pe = p + json->len;
%% write exec;
- if (json->stack_handle) {
- rvalue_stack_eagerly_release(json->stack_handle);
}
if (cs >= JSON_first_final && p == pe) {
@@ -1298,18 +1268,10 @@ static VALUE cParser_parse(VALUE self)
}
}
-static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts)
{
- char *p, *pe;
- int cs = EVIL;
- VALUE result = Qnil;
-
- JSON_Parser _parser = {0};
- JSON_Parser *json = &_parser;
- parser_init(json, source, opts);
-
- char stack_buffer[FBUFFER_STACK_SIZE];
- fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
rvalue_stack stack = {
@@ -1317,53 +1279,74 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts)
.ptr = rvalue_stack_buffer,
.capa = RVALUE_STACK_INITIAL_CAPA,
};
- json->stack = &stack;
- %% write init;
- p = json->source;
- pe = p + json->len;
- %% write exec;
- if (json->stack_handle) {
- rvalue_stack_eagerly_release(json->stack_handle);
- }
- if (cs >= JSON_first_final && p == pe) {
- return result;
- } else {
- raise_parse_error("unexpected token at '%s'", p);
- return Qnil;
}
}
static void JSON_mark(void *ptr)
{
JSON_Parser *json = ptr;
- rb_gc_mark(json->Vsource);
rb_gc_mark(json->create_id);
rb_gc_mark(json->object_class);
rb_gc_mark(json->array_class);
rb_gc_mark(json->decimal_class);
rb_gc_mark(json->match_string);
- rb_gc_mark(json->stack_handle);
-
- long index;
- for (index = 0; index < json->name_cache.length; index++) {
- rb_gc_mark(json->name_cache.entries[index]);
- }
}
static void JSON_free(void *ptr)
{
JSON_Parser *json = ptr;
- fbuffer_free(&json->fbuffer);
ruby_xfree(json);
}
static size_t JSON_memsize(const void *ptr)
{
- const JSON_Parser *json = ptr;
- return sizeof(*json) + FBUFFER_CAPA(&json->fbuffer);
}
static const rb_data_type_t JSON_Parser_type = {
@@ -1376,21 +1359,7 @@ static const rb_data_type_t JSON_Parser_type = {
static VALUE cJSON_parser_s_allocate(VALUE klass)
{
JSON_Parser *json;
- VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
- fbuffer_stack_init(&json->fbuffer, 0, NULL, 0);
- return obj;
-}
-
-/*
- * call-seq: source()
- *
- * Returns a copy of the current _source_ string, that was used to construct
- * this Parser.
- */
-static VALUE cParser_source(VALUE self)
-{
- GET_PARSER;
- return rb_str_dup(json->Vsource);
}
void Init_parser(void)
@@ -1402,15 +1371,15 @@ void Init_parser(void)
#undef rb_intern
rb_require("json/common");
mJSON = rb_define_module("JSON");
- mExt = rb_define_module_under(mJSON, "Ext");
- cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
eNestingError = rb_path2class("JSON::NestingError");
rb_gc_register_mark_object(eNestingError);
- rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
- rb_define_method(cParser, "initialize", cParser_initialize, -1);
- rb_define_method(cParser, "parse", cParser_parse, 0);
- rb_define_method(cParser, "source", cParser_source, 0);
rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2);
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
@@ -6,11 +6,11 @@ class JSONExtParserTest < Test::Unit::TestCase
def test_allocate
parser = JSON::Ext::Parser.new("{}")
- assert_raise(TypeError, '[ruby-core:35079]') do
- parser.__send__(:initialize, "{}")
- end
parser = JSON::Ext::Parser.allocate
- assert_raise(TypeError, '[ruby-core:35079]') { parser.source }
end
def test_error_messages