diff --git a/Rakefile b/Rakefile index 09b69a2e..1e68d2ae 100644 --- a/Rakefile +++ b/Rakefile @@ -40,8 +40,8 @@ EXT_GENERATOR_DL = "#{EXT_GENERATOR_DIR}/generator.#{CONFIG['DLEXT']}" EXT_GENERATOR_SRC = "#{EXT_GENERATOR_DIR}/generator.c" JAVA_DIR = "java/src/json/ext" -JAVA_RAGEL_PATH = "#{JAVA_DIR}/Parser.rl" -JAVA_PARSER_SRC = "#{JAVA_DIR}/Parser.java" +JAVA_RAGEL_PATH = "#{JAVA_DIR}/ParserConfig.rl" +JAVA_PARSER_SRC = "#{JAVA_DIR}/ParserConfig.java" JAVA_SOURCES = FileList["#{JAVA_DIR}/*.java"] JAVA_CLASSES = [] JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar") @@ -95,9 +95,9 @@ end file JAVA_PARSER_SRC => JAVA_RAGEL_PATH do cd JAVA_DIR do if RAGEL_CODEGEN == 'ragel' - sh "ragel Parser.rl -J -o Parser.java" + sh "ragel ParserConfig.rl -J -o ParserConfig.java" else - sh "ragel -x Parser.rl | #{RAGEL_CODEGEN} -J" + sh "ragel -x ParserConfig.rl | #{RAGEL_CODEGEN} -J" end end end diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 83ed9f25..2906cfd1 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -3,7 +3,7 @@ #include "ruby.h" #include "../fbuffer/fbuffer.h" -static VALUE mJSON, mExt, cParser, eNestingError, Encoding_UTF_8; +static VALUE mJSON, 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") +typedef struct JSON_ParserStateStruct { + JSON_Parser *json; + VALUE Vsource; + VALUE stack_handle; + char *source; + long len; + char *memo; + FBuffer fbuffer; + rvalue_stack *stack; + rvalue_cache name_cache; + int in_array; +} JSON_ParserState; -#define GET_PARSER_INIT \ +#define GET_PARSER \ 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); - +static char *JSON_parse_string(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result); +static char *JSON_parse_object(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_value(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_number(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result); +static char *JSON_parse_array(JSON_ParserState *state, 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 472 "parser.rl" -#line 455 "parser.c" +#line 454 "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" +#line 512 "parser.rl" -#define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack) +#define PUSH(result) rvalue_stack_push(state->stack, result, &state->stack_handle, &state->stack) -static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_object(JSON_ParserState *state, 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; + long stack_head = state->stack->head; -#line 479 "parser.c" +#line 478 "parser.c" { cs = JSON_object_start; } -#line 528 "parser.rl" +#line 527 "parser.rl" -#line 486 "parser.c" +#line 485 "parser.c" { short _widec; if ( p == pe ) @@ -511,11 +510,11 @@ case 2: goto st2; goto st0; tr2: -#line 492 "parser.rl" +#line 491 "parser.rl" { char *np; json->parsing_name = true; - np = JSON_parse_string(json, p, pe, result); + np = JSON_parse_string(state, json, p, pe, result); json->parsing_name = false; if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { PUSH(*result); @@ -527,7 +526,7 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 531 "parser.c" +#line 530 "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" +#line 480 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, result, current_nesting); + char *np = JSON_parse_value(state, json, p, pe, result, current_nesting); if (np == NULL) { p--; {p++; cs = 9; goto _out;} } else { @@ -608,20 +607,20 @@ case 8: if ( ++p == pe ) goto _test_eof9; case 9: -#line 612 "parser.c" +#line 611 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 489 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 502 "parser.rl" { p--; {p++; cs = 32; goto _out;} } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 680 "parser.c" +#line 679 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 489 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "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" +#line 489 "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" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 490 "parser.rl" +#line 489 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1016,15 +1015,15 @@ case 31: _out: {} } -#line 529 "parser.rl" +#line 528 "parser.rl" if (cs >= JSON_object_first_final) { - long count = json->stack->head - stack_head; + long count = state->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); + VALUE *items = rvalue_stack_peek(state->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); + rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), hash); *result = hash; } - rvalue_stack_pop(json->stack, count); + rvalue_stack_pop(state->stack, count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -1067,7 +1066,7 @@ case 31: } -#line 1071 "parser.c" +#line 1070 "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" +#line 661 "parser.rl" -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_value(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) { int cs = EVIL; -#line 1087 "parser.c" +#line 1086 "parser.c" { cs = JSON_value_start; } -#line 669 "parser.rl" +#line 668 "parser.rl" -#line 1094 "parser.c" +#line 1093 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1124,9 +1123,9 @@ case 1: cs = 0; goto _out; tr2: -#line 607 "parser.rl" +#line 606 "parser.rl" { - char *np = JSON_parse_string(json, p, pe, result); + char *np = JSON_parse_string(state, json, p, pe, result); if (np == NULL) { p--; {p++; cs = 29; goto _out;} @@ -1136,7 +1135,7 @@ cs = 0; } goto st29; tr3: -#line 617 "parser.rl" +#line 616 "parser.rl" { char *np; if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) { @@ -1148,7 +1147,7 @@ cs = 0; raise_parse_error("unexpected token at '%s'", p); } } - np = JSON_parse_number(json, p, pe, result); + np = JSON_parse_number(state, json, p, pe, result); if (np != NULL) { {p = (( np))-1;} } @@ -1156,25 +1155,25 @@ cs = 0; } goto st29; tr7: -#line 635 "parser.rl" +#line 634 "parser.rl" { char *np; - json->in_array++; - np = JSON_parse_array(json, p, pe, result, current_nesting + 1); - json->in_array--; + state->in_array++; + np = JSON_parse_array(state, json, p, pe, result, current_nesting + 1); + state->in_array--; if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;} } goto st29; tr11: -#line 643 "parser.rl" +#line 642 "parser.rl" { char *np; - np = JSON_parse_object(json, p, pe, result, current_nesting + 1); + np = JSON_parse_object(state, 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" +#line 599 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -1184,7 +1183,7 @@ cs = 0; } goto st29; tr27: -#line 593 "parser.rl" +#line 592 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -1194,19 +1193,19 @@ cs = 0; } goto st29; tr31: -#line 587 "parser.rl" +#line 586 "parser.rl" { *result = Qfalse; } goto st29; tr34: -#line 584 "parser.rl" +#line 583 "parser.rl" { *result = Qnil; } goto st29; tr37: -#line 590 "parser.rl" +#line 589 "parser.rl" { *result = Qtrue; } @@ -1215,9 +1214,9 @@ cs = 0; if ( ++p == pe ) goto _test_eof29; case 29: -#line 649 "parser.rl" +#line 648 "parser.rl" { p--; {p++; cs = 29; goto _out;} } -#line 1221 "parser.c" +#line 1220 "parser.c" switch( (*p) ) { case 13: goto st29; case 32: goto st29; @@ -1458,7 +1457,7 @@ case 28: _out: {} } -#line 670 "parser.rl" +#line 669 "parser.rl" if (json->freeze) { OBJ_FREEZE(*result); @@ -1473,7 +1472,7 @@ case 28: } -#line 1477 "parser.c" +#line 1476 "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" +#line 690 "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) +static char *JSON_decode_integer(JSON_ParserState *state, JSON_Parser *json, char *p, VALUE *result) { - long len = p - json->memo; + long len = p - state->memo; if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) { - *result = fast_parse_integer(json->memo, p); + *result = fast_parse_integer(state->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); + fbuffer_clear(&state->fbuffer); + fbuffer_append(&state->fbuffer, state->memo, len); + fbuffer_append_char(&state->fbuffer, '\0'); + *result = rb_cstr2inum(FBUFFER_PTR(&state->fbuffer), 10); } return p + 1; } -#line 1525 "parser.c" +#line 1524 "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" +#line 742 "parser.rl" -static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) +static char *JSON_parse_number(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result) { int cs = EVIL; bool is_float = false; -#line 1542 "parser.c" +#line 1541 "parser.c" { cs = JSON_float_start; } -#line 751 "parser.rl" - json->memo = p; +#line 750 "parser.rl" + state->memo = p; -#line 1550 "parser.c" +#line 1549 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1586,24 +1585,24 @@ case 6: goto st0; goto tr7; tr7: -#line 735 "parser.rl" +#line 734 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1597 "parser.c" +#line 1596 "parser.c" goto st0; tr8: -#line 736 "parser.rl" +#line 735 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1607 "parser.c" +#line 1606 "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" +#line 735 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1633 "parser.c" +#line 1632 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1686,11 +1685,11 @@ case 10: _out: {} } -#line 753 "parser.rl" +#line 752 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { - return JSON_decode_integer(json, p, result); + return JSON_decode_integer(state, 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'); + long len = p - state->memo; + fbuffer_clear(&state->fbuffer); + fbuffer_append(&state->fbuffer, state->memo, len); + fbuffer_append_char(&state->fbuffer, '\0'); if (method_id) { - VALUE text = rb_str_new2(FBUFFER_PTR(&json->fbuffer)); + VALUE text = rb_str_new2(FBUFFER_PTR(&state->fbuffer)); *result = rb_funcallv(mod, method_id, 1, &text); } else { - *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&json->fbuffer), 1)); + *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&state->fbuffer), 1)); } return p + 1; @@ -1742,7 +1741,7 @@ case 10: -#line 1746 "parser.c" +#line 1745 "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" +#line 832 "parser.rl" -static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_array(JSON_ParserState *state, 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; + long stack_head = state->stack->head; -#line 1767 "parser.c" +#line 1766 "parser.c" { cs = JSON_array_start; } -#line 845 "parser.rl" +#line 844 "parser.rl" -#line 1774 "parser.c" +#line 1773 "parser.c" { short _widec; if ( p == pe ) @@ -1810,10 +1809,10 @@ case 2: goto st2; goto st0; tr2: -#line 813 "parser.rl" +#line 812 "parser.rl" { VALUE v = Qnil; - char *np = JSON_parse_value(json, p, pe, &v, current_nesting); + char *np = JSON_parse_value(state, json, p, pe, &v, current_nesting); if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { @@ -1825,12 +1824,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1829 "parser.c" +#line 1828 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 824 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1888 "parser.c" +#line 1887 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "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" +#line 822 "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" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 823 "parser.rl" +#line 822 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2213,24 +2212,24 @@ case 21: _out: {} } -#line 846 "parser.rl" +#line 845 "parser.rl" if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; + long count = state->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); + VALUE *items = rvalue_stack_peek(state->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)); + VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count)); *result = array; } - rvalue_stack_pop(json->stack, count); + rvalue_stack_pop(state->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) +static VALUE json_string_fastpath(JSON_ParserState *state, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize) { size_t bufferSize = stringEnd - string; - if (is_name && json->in_array) { + if (is_name && state->in_array) { VALUE cached_key; if (RB_UNLIKELY(symbolize)) { - cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); } else { - cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rstring_cache_fetch(&state->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) +static VALUE json_string_unescape(JSON_ParserState *state, 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) { + if (is_name && state->in_array) { VALUE cached_key; if (RB_UNLIKELY(symbolize)) { - cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); } else { - cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rstring_cache_fetch(&state->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" +#line 2410 "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" +#line 1068 "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) +static char *JSON_parse_string(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result) { int cs = EVIL; VALUE match_string; -#line 2440 "parser.c" +#line 2439 "parser.c" { cs = JSON_string_start; } -#line 1089 "parser.rl" - json->memo = p; +#line 1088 "parser.rl" + state->memo = p; -#line 2448 "parser.c" +#line 2447 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2469,25 +2468,25 @@ case 2: goto st0; goto st2; tr2: -#line 1051 "parser.rl" +#line 1050 "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); + *result = json_string_fastpath(state, state->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" +#line 1043 "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); + *result = json_string_unescape(state, state->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" +#line 1043 "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); + *result = json_string_unescape(state, state->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 @@ case 2: if ( ++p == pe ) goto _test_eof9; case 9: -#line 2501 "parser.c" +#line 2500 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -2585,7 +2584,7 @@ case 8: _out: {} } -#line 1091 "parser.rl" +#line 1090 "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) +static void parser_init(JSON_Parser *json, 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 => {}) + * call-seq: new(opts => {}) * - * Creates a new JSON::Ext::Parser instance for the string _source_. + * Creates a new JSON::Ext::ParserConfig instance. * * 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) +static VALUE cParserConfig_initialize(VALUE self, VALUE opts) { - GET_PARSER_INIT; - - rb_check_arity(argc, 1, 2); + GET_PARSER; - parser_init(json, argv[0], argc == 2 ? argv[1] : Qnil); + parser_init(json, opts); return self; } -#line 2742 "parser.c" +#line 2729 "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" +#line 1244 "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) +static VALUE cParser_parse_safe(VALUE vstate) { + JSON_ParserState *state = (JSON_ParserState *)vstate; + VALUE result = Qnil; 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; + JSON_Parser *json = state->json; -#line 2779 "parser.c" +#line 2749 "parser.c" { cs = JSON_start; } -#line 1285 "parser.rl" - p = json->source; - pe = p + json->len; +#line 1255 "parser.rl" + p = state->source; + pe = p + state->len; -#line 2788 "parser.c" +#line 2758 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2818,9 +2788,9 @@ case 1: cs = 0; goto _out; tr2: -#line 1249 "parser.rl" +#line 1236 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, &result, 0); + char *np = JSON_parse_value(state, json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; @@ -2828,7 +2798,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 2832 "parser.c" +#line 2802 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2917,10 +2887,10 @@ case 9: _out: {} } -#line 1288 "parser.rl" +#line 1258 "parser.rl" - if (json->stack_handle) { - rvalue_stack_eagerly_release(json->stack_handle); + if (state->stack_handle) { + rvalue_stack_eagerly_release(state->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) +static VALUE cParser_parse(JSON_Parser *json, VALUE Vsource) { - 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); + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); 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; + JSON_ParserState _state = { + .json = json, + .len = RSTRING_LEN(Vsource), + .source = RSTRING_PTR(Vsource), + .Vsource = Vsource, + .stack = &stack, + }; + JSON_ParserState *state = &_state; -#line 2957 "parser.c" - { - cs = JSON_start; - } + char stack_buffer[FBUFFER_STACK_SIZE]; + fbuffer_stack_init(&state->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); -#line 1323 "parser.rl" - p = json->source; - pe = p + json->len; + int interupted; + VALUE result = rb_protect(cParser_parse_safe, (VALUE)state, &interupted); -#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;} + fbuffer_free(&state->fbuffer); + if (interupted) { + rb_jump_tag(interupted); } - 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: {} - } + return result; +} + +/* + * call-seq: parse(source) + * + * 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 cParserConfig_parse(VALUE self, VALUE Vsource) +{ + GET_PARSER; + return cParser_parse(json, Vsource); +} -#line 1326 "parser.rl" +static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts) +{ + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); - if (json->stack_handle) { - rvalue_stack_eagerly_release(json->stack_handle); - } + JSON_Parser _parser = {0}; + JSON_Parser *json = &_parser; + parser_init(json, opts); - if (cs >= JSON_first_final && p == pe) { - return result; - } else { - raise_parse_error("unexpected token at '%s'", p); - return Qnil; - } + return cParser_parse(json, Vsource); } 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); + return sizeof(JSON_Parser); } 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); + return TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json); } 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); + VALUE mExt = rb_define_module_under(mJSON, "Ext"); + VALUE cParserConfig = rb_define_class_under(mExt, "ParserConfig", 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_alloc_func(cParserConfig, cJSON_parser_s_allocate); + rb_define_method(cParserConfig, "initialize", cParserConfig_initialize, 1); + rb_define_method(cParserConfig, "parse", cParserConfig_parse, 1); + VALUE cParser = rb_define_class_under(mExt, "Parser", rb_cObject); rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2); CNaN = rb_const_get(mJSON, rb_intern("NaN")); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 9856a738..50226a72 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -1,7 +1,7 @@ #include "ruby.h" #include "../fbuffer/fbuffer.h" -static VALUE mJSON, mExt, cParser, eNestingError, Encoding_UTF_8; +static VALUE mJSON, 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") +typedef struct JSON_ParserStateStruct { + JSON_Parser *json; + VALUE Vsource; + VALUE stack_handle; + char *source; + long len; + char *memo; + FBuffer fbuffer; + rvalue_stack *stack; + rvalue_cache name_cache; + int in_array; +} JSON_ParserState; -#define GET_PARSER_INIT \ +#define GET_PARSER \ 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); - +static char *JSON_parse_string(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result); +static char *JSON_parse_object(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_value(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_number(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result); +static char *JSON_parse_array(JSON_ParserState *state, 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); + char *np = JSON_parse_value(state, 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); + np = JSON_parse_string(state, 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) +#define PUSH(result) rvalue_stack_push(state->stack, result, &state->stack_handle, &state->stack) -static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_object(JSON_ParserState *state, 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; + long stack_head = state->stack->head; %% write init; %% write exec; if (cs >= JSON_object_first_final) { - long count = json->stack->head - stack_head; + long count = state->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); + VALUE *items = rvalue_stack_peek(state->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); + rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), hash); *result = hash; } - rvalue_stack_pop(json->stack, count); + rvalue_stack_pop(state->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); + char *np = JSON_parse_string(state, 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); + np = JSON_parse_number(state, 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--; + state->in_array++; + np = JSON_parse_array(state, json, fpc, pe, result, current_nesting + 1); + state->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); + np = JSON_parse_object(state, 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) +static char *JSON_parse_value(JSON_ParserState *state, 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) +static char *JSON_decode_integer(JSON_ParserState *state, JSON_Parser *json, char *p, VALUE *result) { - long len = p - json->memo; + long len = p - state->memo; if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) { - *result = fast_parse_integer(json->memo, p); + *result = fast_parse_integer(state->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); + fbuffer_clear(&state->fbuffer); + fbuffer_append(&state->fbuffer, state->memo, len); + fbuffer_append_char(&state->fbuffer, '\0'); + *result = rb_cstr2inum(FBUFFER_PTR(&state->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) +static char *JSON_parse_number(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result) { int cs = EVIL; bool is_float = false; %% write init; - json->memo = p; + state->memo = p; %% write exec; if (cs >= JSON_float_first_final) { if (!is_float) { - return JSON_decode_integer(json, p, result); + return JSON_decode_integer(state, 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'); + long len = p - state->memo; + fbuffer_clear(&state->fbuffer); + fbuffer_append(&state->fbuffer, state->memo, len); + fbuffer_append_char(&state->fbuffer, '\0'); if (method_id) { - VALUE text = rb_str_new2(FBUFFER_PTR(&json->fbuffer)); + VALUE text = rb_str_new2(FBUFFER_PTR(&state->fbuffer)); *result = rb_funcallv(mod, method_id, 1, &text); } else { - *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&json->fbuffer), 1)); + *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&state->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); + char *np = JSON_parse_value(state, 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) +static char *JSON_parse_array(JSON_ParserState *state, 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; + long stack_head = state->stack->head; %% write init; %% write exec; if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; + long count = state->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); + VALUE *items = rvalue_stack_peek(state->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)); + VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count)); *result = array; } - rvalue_stack_pop(json->stack, count); + rvalue_stack_pop(state->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) +static VALUE json_string_fastpath(JSON_ParserState *state, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize) { size_t bufferSize = stringEnd - string; - if (is_name && json->in_array) { + if (is_name && state->in_array) { VALUE cached_key; if (RB_UNLIKELY(symbolize)) { - cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); } else { - cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rstring_cache_fetch(&state->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) +static VALUE json_string_unescape(JSON_ParserState *state, 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) { + if (is_name && state->in_array) { VALUE cached_key; if (RB_UNLIKELY(symbolize)) { - cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize); } else { - cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize); + cached_key = rstring_cache_fetch(&state->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); + *result = json_string_unescape(state, state->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); + *result = json_string_fastpath(state, state->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) +static char *JSON_parse_string(JSON_ParserState *state, JSON_Parser *json, char *p, char *pe, VALUE *result) { int cs = EVIL; VALUE match_string; %% write init; - json->memo = p; + state->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) +static void parser_init(JSON_Parser *json, 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 => {}) + * call-seq: new(opts => {}) * - * Creates a new JSON::Ext::Parser instance for the string _source_. + * Creates a new JSON::Ext::ParserConfig instance. * * 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) +static VALUE cParserConfig_initialize(VALUE self, VALUE opts) { - GET_PARSER_INIT; - - rb_check_arity(argc, 1, 2); + GET_PARSER; - parser_init(json, argv[0], argc == 2 ? argv[1] : Qnil); + parser_init(json, opts); 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); + char *np = JSON_parse_value(state, 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) +static VALUE cParser_parse_safe(VALUE vstate) { + JSON_ParserState *state = (JSON_ParserState *)vstate; + VALUE result = Qnil; 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; + JSON_Parser *json = state->json; %% write init; - p = json->source; - pe = p + json->len; + p = state->source; + pe = p + state->len; %% write exec; - if (json->stack_handle) { - rvalue_stack_eagerly_release(json->stack_handle); + if (state->stack_handle) { + rvalue_stack_eagerly_release(state->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) +static VALUE cParser_parse(JSON_Parser *json, VALUE Vsource) { - 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); + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); 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; + JSON_ParserState _state = { + .json = json, + .len = RSTRING_LEN(Vsource), + .source = RSTRING_PTR(Vsource), + .Vsource = Vsource, + .stack = &stack, + }; + JSON_ParserState *state = &_state; - if (json->stack_handle) { - rvalue_stack_eagerly_release(json->stack_handle); - } + char stack_buffer[FBUFFER_STACK_SIZE]; + fbuffer_stack_init(&state->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); - if (cs >= JSON_first_final && p == pe) { - return result; - } else { - raise_parse_error("unexpected token at '%s'", p); - return Qnil; + int interupted; + VALUE result = rb_protect(cParser_parse_safe, (VALUE)state, &interupted); + + fbuffer_free(&state->fbuffer); + if (interupted) { + rb_jump_tag(interupted); } + + return result; +} + +/* + * call-seq: parse(source) + * + * 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 cParserConfig_parse(VALUE self, VALUE Vsource) +{ + GET_PARSER; + return cParser_parse(json, Vsource); +} + +static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts) +{ + Vsource = convert_encoding(StringValue(Vsource)); + StringValue(Vsource); + + JSON_Parser _parser = {0}; + JSON_Parser *json = &_parser; + parser_init(json, opts); + + return cParser_parse(json, Vsource); } 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); + return sizeof(JSON_Parser); } 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); + return TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json); } 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); + VALUE mExt = rb_define_module_under(mJSON, "Ext"); + VALUE cParserConfig = rb_define_class_under(mExt, "ParserConfig", 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_alloc_func(cParserConfig, cJSON_parser_s_allocate); + rb_define_method(cParserConfig, "initialize", cParserConfig_initialize, 1); + rb_define_method(cParserConfig, "parse", cParserConfig_parse, 1); + VALUE cParser = rb_define_class_under(mExt, "Parser", rb_cObject); rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2); CNaN = rb_const_get(mJSON, rb_intern("NaN")); diff --git a/java/src/json/ext/Parser.java b/java/src/json/ext/ParserConfig.java similarity index 92% rename from java/src/json/ext/Parser.java rename to java/src/json/ext/ParserConfig.java index 47e66795..6596f97f 100644 --- a/java/src/json/ext/Parser.java +++ b/java/src/json/ext/ParserConfig.java @@ -1,5 +1,5 @@ -// line 1 "Parser.rl" +// line 1 "ParserConfig.rl" /* * This code is copyrighted work by Daniel Luz . * @@ -44,13 +44,12 @@ * *

This class does not perform the actual parsing, just acts as an interface * to Ruby code. When the {@link #parse(ThreadContext)} method is invoked, a - * Parser.ParserSession object is instantiated, which handles the process. + * ParserConfig.ParserSession object is instantiated, which handles the process. * * @author mernen */ -public class Parser extends RubyObject { +public class ParserConfig extends RubyObject { private final RuntimeInfo info; - private RubyString vSource; private RubyString createId; private boolean createAdditions; private boolean deprecatedCreateAdditions; @@ -73,7 +72,7 @@ public class Parser extends RubyObject { private static final String CONST_INFINITY = "Infinity"; private static final String CONST_MINUS_INFINITY = "MinusInfinity"; - static final ObjectAllocator ALLOCATOR = Parser::new; + static final ObjectAllocator ALLOCATOR = ParserConfig::new; /** * Multiple-value return for internal parser methods. @@ -99,13 +98,13 @@ void update(IRubyObject result, int p) { } } - public Parser(Ruby runtime, RubyClass metaClass) { + public ParserConfig(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); info = RuntimeInfo.forRuntime(runtime); } /** - * Parser.new(source, opts = {}) + * ParserConfig.new(source, opts = {}) * *

Creates a new JSON::Ext::Parser instance for the string * source. @@ -156,42 +155,27 @@ public Parser(Ruby runtime, RubyClass metaClass) { @JRubyMethod(name = "new", meta = true) public static IRubyObject newInstance(IRubyObject clazz, IRubyObject arg0, Block block) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); + ParserConfig config = (ParserConfig)((RubyClass)clazz).allocate(); - parser.callInit(arg0, block); + config.callInit(arg0, block); - return parser; + return config; } @JRubyMethod(name = "new", meta = true) public static IRubyObject newInstance(IRubyObject clazz, IRubyObject arg0, IRubyObject arg1, Block block) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); + ParserConfig config = (ParserConfig)((RubyClass)clazz).allocate(); - parser.callInit(arg0, arg1, block); + config.callInit(arg0, arg1, block); - return parser; - } - - @JRubyMethod(meta=true) - public static IRubyObject parse(ThreadContext context, IRubyObject clazz, IRubyObject source, IRubyObject opts) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); - parser.callInit(source, opts, null); - return parser.parse(context); + return config; } @JRubyMethod(visibility = Visibility.PRIVATE) - public IRubyObject initialize(ThreadContext context, IRubyObject arg0) { - return initialize(context, arg0, null); - } - - @JRubyMethod(visibility = Visibility.PRIVATE) - public IRubyObject initialize(ThreadContext context, IRubyObject arg0, IRubyObject arg1) { + public IRubyObject initialize(ThreadContext context, IRubyObject options) { Ruby runtime = context.runtime; - if (this.vSource != null) { - throw runtime.newTypeError("already initialized instance"); - } - OptionsReader opts = new OptionsReader(context, arg1); + OptionsReader opts = new OptionsReader(context, options); this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING); this.allowNaN = opts.getBool("allow_nan", false); this.allowTrailingComma = opts.getBool("allow_trailing_comma", false); @@ -228,8 +212,6 @@ public IRubyObject initialize(ThreadContext context, IRubyObject arg0, IRubyObje if(symbolizeNames && createAdditions) { throw runtime.newArgumentError("options :symbolize_names and :create_additions cannot be used in conjunction"); } - this.vSource = arg0.convertToString(); - this.vSource = convertEncoding(context, vSource); return this; } @@ -258,27 +240,8 @@ private RubyString convertEncoding(ThreadContext context, RubyString source) { * complete data structure as a result. */ @JRubyMethod - public IRubyObject parse(ThreadContext context) { - return new ParserSession(this, context, info).parse(context); - } - - /** - * Parser#source() - * - *

Returns a copy of the current source string, that was - * used to construct this Parser. - */ - @JRubyMethod(name = "source") - public IRubyObject source_get(ThreadContext context) { - return checkAndGetSource(context).dup(); - } - - public RubyString checkAndGetSource(ThreadContext context) { - if (vSource != null) { - return vSource; - } else { - throw context.runtime.newTypeError("uninitialized instance"); - } + public IRubyObject parse(ThreadContext context, IRubyObject source) { + return new ParserSession(this, convertEncoding(context, source.convertToString()), context, info).parse(context); } /** @@ -315,7 +278,7 @@ private IRubyObject createCustomDecimal(final ThreadContext context, final ByteL // Ragel uses lots of fall-through @SuppressWarnings("fallthrough") private static class ParserSession { - private final Parser parser; + private final ParserConfig config; private final RuntimeInfo info; private final ByteList byteList; private final ByteList view; @@ -323,10 +286,10 @@ private static class ParserSession { private final StringDecoder decoder; private int currentNesting = 0; - private ParserSession(Parser parser, ThreadContext context, RuntimeInfo info) { - this.parser = parser; + private ParserSession(ParserConfig config, RubyString source, ThreadContext context, RuntimeInfo info) { + this.config = config; this.info = info; - this.byteList = parser.checkAndGetSource(context).getByteList(); + this.byteList = source.getByteList(); this.data = byteList.unsafeBytes(); this.view = new ByteList(data, false); this.decoder = new StringDecoder(); @@ -340,11 +303,11 @@ private RaiseException unexpectedToken(ThreadContext context, int absStart, int } -// line 366 "Parser.rl" +// line 329 "ParserConfig.rl" -// line 348 "Parser.java" +// line 311 "ParserConfig.java" private static byte[] init__JSON_value_actions_0() { return new byte [] { @@ -458,7 +421,7 @@ private static byte[] init__JSON_value_from_state_actions_0() static final int JSON_value_en_main = 1; -// line 472 "Parser.rl" +// line 435 "ParserConfig.rl" void parseValue(ThreadContext context, ParserResult res, int p, int pe) { @@ -466,14 +429,14 @@ void parseValue(ThreadContext context, ParserResult res, int p, int pe) { IRubyObject result = null; -// line 470 "Parser.java" +// line 433 "ParserConfig.java" { cs = JSON_value_start; } -// line 479 "Parser.rl" +// line 442 "ParserConfig.rl" -// line 477 "Parser.java" +// line 440 "ParserConfig.java" { int _klen; int _trans = 0; @@ -499,13 +462,13 @@ void parseValue(ThreadContext context, ParserResult res, int p, int pe) { while ( _nacts-- > 0 ) { switch ( _JSON_value_actions[_acts++] ) { case 9: -// line 457 "Parser.rl" +// line 420 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 509 "Parser.java" +// line 472 "ParserConfig.java" } } @@ -568,27 +531,27 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) switch ( _JSON_value_actions[_acts++] ) { case 0: -// line 374 "Parser.rl" +// line 337 "ParserConfig.rl" { result = context.nil; } break; case 1: -// line 377 "Parser.rl" +// line 340 "ParserConfig.rl" { result = context.fals; } break; case 2: -// line 380 "Parser.rl" +// line 343 "ParserConfig.rl" { result = context.tru; } break; case 3: -// line 383 "Parser.rl" +// line 346 "ParserConfig.rl" { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_NAN); } else { throw unexpectedToken(context, p - 2, pe); @@ -596,9 +559,9 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } break; case 4: -// line 390 "Parser.rl" +// line 353 "ParserConfig.rl" { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_INFINITY); } else { throw unexpectedToken(context, p - 7, pe); @@ -606,12 +569,12 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } break; case 5: -// line 397 "Parser.rl" +// line 360 "ParserConfig.rl" { if (pe > p + 8 && absSubSequence(p, p + 9).equals(JSON_MINUS_INFINITY)) { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_MINUS_INFINITY); {p = (( p + 10))-1;} p--; @@ -635,7 +598,7 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } break; case 6: -// line 423 "Parser.rl" +// line 386 "ParserConfig.rl" { parseString(context, res, p, pe); if (res.result == null) { @@ -648,7 +611,7 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } break; case 7: -// line 433 "Parser.rl" +// line 396 "ParserConfig.rl" { currentNesting++; parseArray(context, res, p, pe); @@ -663,7 +626,7 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } break; case 8: -// line 445 "Parser.rl" +// line 408 "ParserConfig.rl" { currentNesting++; parseObject(context, res, p, pe); @@ -677,7 +640,7 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } } break; -// line 681 "Parser.java" +// line 644 "ParserConfig.java" } } } @@ -697,10 +660,10 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) break; } } -// line 480 "Parser.rl" +// line 443 "ParserConfig.rl" if (cs >= JSON_value_first_final && result != null) { - if (parser.freeze) { + if (config.freeze) { result.setFrozen(true); } res.update(result, p); @@ -710,7 +673,7 @@ else if ( data[p] > _JSON_value_trans_keys[_mid+1] ) } -// line 714 "Parser.java" +// line 677 "ParserConfig.java" private static byte[] init__JSON_integer_actions_0() { return new byte [] { @@ -809,7 +772,7 @@ private static byte[] init__JSON_integer_trans_actions_0() static final int JSON_integer_en_main = 1; -// line 502 "Parser.rl" +// line 465 "ParserConfig.rl" void parseInteger(ThreadContext context, ParserResult res, int p, int pe) { @@ -826,15 +789,15 @@ int parseIntegerInternal(int p, int pe) { int cs; -// line 830 "Parser.java" +// line 793 "ParserConfig.java" { cs = JSON_integer_start; } -// line 518 "Parser.rl" +// line 481 "ParserConfig.rl" int memo = p; -// line 838 "Parser.java" +// line 801 "ParserConfig.java" { int _klen; int _trans = 0; @@ -915,13 +878,13 @@ else if ( data[p] > _JSON_integer_trans_keys[_mid+1] ) switch ( _JSON_integer_actions[_acts++] ) { case 0: -// line 496 "Parser.rl" +// line 459 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 925 "Parser.java" +// line 888 "ParserConfig.java" } } } @@ -941,7 +904,7 @@ else if ( data[p] > _JSON_integer_trans_keys[_mid+1] ) break; } } -// line 520 "Parser.rl" +// line 483 "ParserConfig.rl" if (cs < JSON_integer_first_final) { return -1; @@ -961,7 +924,7 @@ RubyInteger bytesToInum(Ruby runtime, ByteList num) { } -// line 965 "Parser.java" +// line 928 "ParserConfig.java" private static byte[] init__JSON_float_actions_0() { return new byte [] { @@ -1063,7 +1026,7 @@ private static byte[] init__JSON_float_trans_actions_0() static final int JSON_float_en_main = 1; -// line 553 "Parser.rl" +// line 516 "ParserConfig.rl" void parseFloat(ThreadContext context, ParserResult res, int p, int pe) { @@ -1073,7 +1036,7 @@ void parseFloat(ThreadContext context, ParserResult res, int p, int pe) { return; } final ByteList num = absSubSequence(p, new_p); - IRubyObject number = parser.decimalFactory.apply(context, num); + IRubyObject number = config.decimalFactory.apply(context, num); res.update(number, new_p + 1); } @@ -1082,15 +1045,15 @@ int parseFloatInternal(int p, int pe) { int cs; -// line 1086 "Parser.java" +// line 1049 "ParserConfig.java" { cs = JSON_float_start; } -// line 571 "Parser.rl" +// line 534 "ParserConfig.rl" int memo = p; -// line 1094 "Parser.java" +// line 1057 "ParserConfig.java" { int _klen; int _trans = 0; @@ -1171,13 +1134,13 @@ else if ( data[p] > _JSON_float_trans_keys[_mid+1] ) switch ( _JSON_float_actions[_acts++] ) { case 0: -// line 544 "Parser.rl" +// line 507 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1181 "Parser.java" +// line 1144 "ParserConfig.java" } } } @@ -1197,7 +1160,7 @@ else if ( data[p] > _JSON_float_trans_keys[_mid+1] ) break; } } -// line 573 "Parser.rl" +// line 536 "ParserConfig.rl" if (cs < JSON_float_first_final) { return -1; @@ -1207,7 +1170,7 @@ else if ( data[p] > _JSON_float_trans_keys[_mid+1] ) } -// line 1211 "Parser.java" +// line 1174 "ParserConfig.java" private static byte[] init__JSON_string_actions_0() { return new byte [] { @@ -1309,7 +1272,7 @@ private static byte[] init__JSON_string_trans_actions_0() static final int JSON_string_en_main = 1; -// line 612 "Parser.rl" +// line 575 "ParserConfig.rl" void parseString(ThreadContext context, ParserResult res, int p, int pe) { @@ -1317,15 +1280,15 @@ void parseString(ThreadContext context, ParserResult res, int p, int pe) { IRubyObject result = null; -// line 1321 "Parser.java" +// line 1284 "ParserConfig.java" { cs = JSON_string_start; } -// line 619 "Parser.rl" +// line 582 "ParserConfig.rl" int memo = p; -// line 1329 "Parser.java" +// line 1292 "ParserConfig.java" { int _klen; int _trans = 0; @@ -1406,7 +1369,7 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) switch ( _JSON_string_actions[_acts++] ) { case 0: -// line 587 "Parser.rl" +// line 550 "ParserConfig.rl" { int offset = byteList.begin(); ByteList decoded = decoder.decode(context, byteList, memo + 1 - offset, @@ -1421,13 +1384,13 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) } break; case 1: -// line 600 "Parser.rl" +// line 563 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1431 "Parser.java" +// line 1394 "ParserConfig.java" } } } @@ -1447,10 +1410,10 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) break; } } -// line 621 "Parser.rl" +// line 584 "ParserConfig.rl" - if (parser.createAdditions) { - RubyHash matchString = parser.match_string; + if (config.createAdditions) { + RubyHash matchString = config.match_string; if (matchString != null) { final IRubyObject[] memoArray = { result, null }; try { @@ -1460,7 +1423,7 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) RubyClass klass = (RubyClass) memoArray[1]; if (klass.respondsTo("json_creatable?") && klass.callMethod(context, "json_creatable?").isTrue()) { - if (parser.deprecatedCreateAdditions) { + if (config.deprecatedCreateAdditions) { context.runtime.getWarnings().warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`"); } result = klass.callMethod(context, "json_create", result); @@ -1474,7 +1437,7 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) RubyString string = (RubyString)result; string.setEncoding(UTF8Encoding.INSTANCE); string.clearCodeRange(); - if (parser.freeze) { + if (config.freeze) { string.setFrozen(true); string = context.runtime.freezeAndDedupString(string); } @@ -1488,7 +1451,7 @@ else if ( data[p] > _JSON_string_trans_keys[_mid+1] ) } -// line 1492 "Parser.java" +// line 1455 "ParserConfig.java" private static byte[] init__JSON_array_actions_0() { return new byte [] { @@ -1655,34 +1618,34 @@ private static byte[] init__JSON_array_trans_actions_0() static final int JSON_array_en_main = 1; -// line 699 "Parser.rl" +// line 662 "ParserConfig.rl" void parseArray(ThreadContext context, ParserResult res, int p, int pe) { int cs; - if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) { + if (config.maxNesting > 0 && currentNesting > config.maxNesting) { throw newException(context, Utils.M_NESTING_ERROR, "nesting of " + currentNesting + " is too deep"); } IRubyObject result; - if (parser.arrayClass == context.runtime.getArray()) { + if (config.arrayClass == context.runtime.getArray()) { result = RubyArray.newArray(context.runtime); } else { - result = parser.arrayClass.newInstance(context, + result = config.arrayClass.newInstance(context, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); } -// line 1679 "Parser.java" +// line 1642 "ParserConfig.java" { cs = JSON_array_start; } -// line 718 "Parser.rl" +// line 681 "ParserConfig.rl" -// line 1686 "Parser.java" +// line 1649 "ParserConfig.java" { int _klen; int _trans = 0; @@ -1725,8 +1688,8 @@ else if ( _widec > _JSON_array_cond_keys[_mid+1] ) case 0: { _widec = 65536 + (data[p] - 0); if ( -// line 666 "Parser.rl" - parser.allowTrailingComma ) _widec += 65536; +// line 629 "ParserConfig.rl" + config.allowTrailingComma ) _widec += 65536; break; } } @@ -1795,14 +1758,14 @@ else if ( _widec > _JSON_array_trans_keys[_mid+1] ) switch ( _JSON_array_actions[_acts++] ) { case 0: -// line 668 "Parser.rl" +// line 631 "ParserConfig.rl" { parseValue(context, res, p, pe); if (res.result == null) { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } else { - if (parser.arrayClass == context.runtime.getArray()) { + if (config.arrayClass == context.runtime.getArray()) { ((RubyArray)result).append(res.result); } else { result.callMethod(context, "<<", res.result); @@ -1812,13 +1775,13 @@ else if ( _widec > _JSON_array_trans_keys[_mid+1] ) } break; case 1: -// line 683 "Parser.rl" +// line 646 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 1822 "Parser.java" +// line 1785 "ParserConfig.java" } } } @@ -1838,7 +1801,7 @@ else if ( _widec > _JSON_array_trans_keys[_mid+1] ) break; } } -// line 719 "Parser.rl" +// line 682 "ParserConfig.rl" if (cs >= JSON_array_first_final) { res.update(result, p + 1); @@ -1848,7 +1811,7 @@ else if ( _widec > _JSON_array_trans_keys[_mid+1] ) } -// line 1852 "Parser.java" +// line 1815 "ParserConfig.java" private static byte[] init__JSON_object_actions_0() { return new byte [] { @@ -2025,7 +1988,7 @@ private static byte[] init__JSON_object_trans_actions_0() static final int JSON_object_en_main = 1; -// line 780 "Parser.rl" +// line 743 "ParserConfig.rl" void parseObject(ThreadContext context, ParserResult res, int p, int pe) { @@ -2033,7 +1996,7 @@ void parseObject(ThreadContext context, ParserResult res, int p, int pe) { IRubyObject lastName = null; boolean objectDefault = true; - if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) { + if (config.maxNesting > 0 && currentNesting > config.maxNesting) { throw newException(context, Utils.M_NESTING_ERROR, "nesting of " + currentNesting + " is too deep"); } @@ -2041,23 +2004,23 @@ void parseObject(ThreadContext context, ParserResult res, int p, int pe) { // this is guaranteed to be a RubyHash due to the earlier // allocator test at OptionsReader#getClass IRubyObject result; - if (parser.objectClass == context.runtime.getHash()) { + if (config.objectClass == context.runtime.getHash()) { result = RubyHash.newHash(context.runtime); } else { objectDefault = false; - result = parser.objectClass.newInstance(context, + result = config.objectClass.newInstance(context, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); } -// line 2054 "Parser.java" +// line 2017 "ParserConfig.java" { cs = JSON_object_start; } -// line 804 "Parser.rl" +// line 767 "ParserConfig.rl" -// line 2061 "Parser.java" +// line 2024 "ParserConfig.java" { int _klen; int _trans = 0; @@ -2100,8 +2063,8 @@ else if ( _widec > _JSON_object_cond_keys[_mid+1] ) case 0: { _widec = 65536 + (data[p] - 0); if ( -// line 733 "Parser.rl" - parser.allowTrailingComma ) _widec += 65536; +// line 696 "ParserConfig.rl" + config.allowTrailingComma ) _widec += 65536; break; } } @@ -2170,14 +2133,14 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) switch ( _JSON_object_actions[_acts++] ) { case 0: -// line 735 "Parser.rl" +// line 698 "ParserConfig.rl" { parseValue(context, res, p, pe); if (res.result == null) { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } else { - if (parser.objectClass == context.runtime.getHash()) { + if (config.objectClass == context.runtime.getHash()) { ((RubyHash)result).op_aset(context, lastName, res.result); } else { Helpers.invoke(context, result, "[]=", lastName, res.result); @@ -2187,7 +2150,7 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) } break; case 1: -// line 750 "Parser.rl" +// line 713 "ParserConfig.rl" { parseString(context, res, p, pe); if (res.result == null) { @@ -2195,7 +2158,7 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) { p += 1; _goto_targ = 5; if (true) continue _goto;} } else { RubyString name = (RubyString)res.result; - if (parser.symbolizeNames) { + if (config.symbolizeNames) { lastName = name.intern(); } else { lastName = name; @@ -2205,13 +2168,13 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) } break; case 2: -// line 766 "Parser.rl" +// line 729 "ParserConfig.rl" { p--; { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 2215 "Parser.java" +// line 2178 "ParserConfig.java" } } } @@ -2231,7 +2194,7 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) break; } } -// line 805 "Parser.rl" +// line 768 "ParserConfig.rl" if (cs < JSON_object_first_final) { res.update(null, p + 1); @@ -2241,21 +2204,21 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) IRubyObject returnedResult = result; // attempt to de-serialize object - if (parser.createAdditions) { + if (config.createAdditions) { IRubyObject vKlassName; if (objectDefault) { - vKlassName = ((RubyHash)result).op_aref(context, parser.createId); + vKlassName = ((RubyHash)result).op_aref(context, config.createId); } else { - vKlassName = result.callMethod(context, "[]", parser.createId); + vKlassName = result.callMethod(context, "[]", config.createId); } if (!vKlassName.isNil()) { // might throw ArgumentError, we let it propagate - IRubyObject klass = parser.info.jsonModule.get(). + IRubyObject klass = config.info.jsonModule.get(). callMethod(context, "deep_const_get", vKlassName); if (klass.respondsTo("json_creatable?") && klass.callMethod(context, "json_creatable?").isTrue()) { - if (parser.deprecatedCreateAdditions) { + if (config.deprecatedCreateAdditions) { context.runtime.getWarnings().warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`"); } @@ -2267,7 +2230,7 @@ else if ( _widec > _JSON_object_trans_keys[_mid+1] ) } -// line 2271 "Parser.java" +// line 2234 "ParserConfig.java" private static byte[] init__JSON_actions_0() { return new byte [] { @@ -2370,7 +2333,7 @@ private static byte[] init__JSON_trans_actions_0() static final int JSON_en_main = 1; -// line 859 "Parser.rl" +// line 822 "ParserConfig.rl" public IRubyObject parseImplementation(ThreadContext context) { @@ -2380,16 +2343,16 @@ public IRubyObject parseImplementation(ThreadContext context) { ParserResult res = new ParserResult(); -// line 2384 "Parser.java" +// line 2347 "ParserConfig.java" { cs = JSON_start; } -// line 868 "Parser.rl" +// line 831 "ParserConfig.rl" p = byteList.begin(); pe = p + byteList.length(); -// line 2393 "Parser.java" +// line 2356 "ParserConfig.java" { int _klen; int _trans = 0; @@ -2470,7 +2433,7 @@ else if ( data[p] > _JSON_trans_keys[_mid+1] ) switch ( _JSON_actions[_acts++] ) { case 0: -// line 845 "Parser.rl" +// line 808 "ParserConfig.rl" { parseValue(context, res, p, pe); if (res.result == null) { @@ -2482,7 +2445,7 @@ else if ( data[p] > _JSON_trans_keys[_mid+1] ) } } break; -// line 2486 "Parser.java" +// line 2449 "ParserConfig.java" } } } @@ -2502,7 +2465,7 @@ else if ( data[p] > _JSON_trans_keys[_mid+1] ) break; } } -// line 871 "Parser.rl" +// line 834 "ParserConfig.rl" if (cs >= JSON_first_final && p == pe) { return result; @@ -2531,7 +2494,7 @@ private ByteList absSubSequence(int absStart, int absEnd) { * @param name The constant name */ private IRubyObject getConstant(String name) { - return parser.info.jsonModule.get().getConstant(name); + return config.info.jsonModule.get().getConstant(name); } private RaiseException newException(ThreadContext context, String className, String message) { diff --git a/java/src/json/ext/Parser.rl b/java/src/json/ext/ParserConfig.rl similarity index 88% rename from java/src/json/ext/Parser.rl rename to java/src/json/ext/ParserConfig.rl index bf42b445..0382a7c5 100644 --- a/java/src/json/ext/Parser.rl +++ b/java/src/json/ext/ParserConfig.rl @@ -42,13 +42,12 @@ import static org.jruby.util.ConvertDouble.DoubleConverter; * *

This class does not perform the actual parsing, just acts as an interface * to Ruby code. When the {@link #parse(ThreadContext)} method is invoked, a - * Parser.ParserSession object is instantiated, which handles the process. + * ParserConfig.ParserSession object is instantiated, which handles the process. * * @author mernen */ -public class Parser extends RubyObject { +public class ParserConfig extends RubyObject { private final RuntimeInfo info; - private RubyString vSource; private RubyString createId; private boolean createAdditions; private boolean deprecatedCreateAdditions; @@ -71,7 +70,7 @@ public class Parser extends RubyObject { private static final String CONST_INFINITY = "Infinity"; private static final String CONST_MINUS_INFINITY = "MinusInfinity"; - static final ObjectAllocator ALLOCATOR = Parser::new; + static final ObjectAllocator ALLOCATOR = ParserConfig::new; /** * Multiple-value return for internal parser methods. @@ -97,13 +96,13 @@ public class Parser extends RubyObject { } } - public Parser(Ruby runtime, RubyClass metaClass) { + public ParserConfig(Ruby runtime, RubyClass metaClass) { super(runtime, metaClass); info = RuntimeInfo.forRuntime(runtime); } /** - * Parser.new(source, opts = {}) + * ParserConfig.new(source, opts = {}) * *

Creates a new JSON::Ext::Parser instance for the string * source. @@ -154,42 +153,27 @@ public class Parser extends RubyObject { @JRubyMethod(name = "new", meta = true) public static IRubyObject newInstance(IRubyObject clazz, IRubyObject arg0, Block block) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); + ParserConfig config = (ParserConfig)((RubyClass)clazz).allocate(); - parser.callInit(arg0, block); + config.callInit(arg0, block); - return parser; + return config; } @JRubyMethod(name = "new", meta = true) public static IRubyObject newInstance(IRubyObject clazz, IRubyObject arg0, IRubyObject arg1, Block block) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); + ParserConfig config = (ParserConfig)((RubyClass)clazz).allocate(); - parser.callInit(arg0, arg1, block); + config.callInit(arg0, arg1, block); - return parser; - } - - @JRubyMethod(meta=true) - public static IRubyObject parse(ThreadContext context, IRubyObject clazz, IRubyObject source, IRubyObject opts) { - Parser parser = (Parser)((RubyClass)clazz).allocate(); - parser.callInit(source, opts, null); - return parser.parse(context); + return config; } @JRubyMethod(visibility = Visibility.PRIVATE) - public IRubyObject initialize(ThreadContext context, IRubyObject arg0) { - return initialize(context, arg0, null); - } - - @JRubyMethod(visibility = Visibility.PRIVATE) - public IRubyObject initialize(ThreadContext context, IRubyObject arg0, IRubyObject arg1) { + public IRubyObject initialize(ThreadContext context, IRubyObject options) { Ruby runtime = context.runtime; - if (this.vSource != null) { - throw runtime.newTypeError("already initialized instance"); - } - OptionsReader opts = new OptionsReader(context, arg1); + OptionsReader opts = new OptionsReader(context, options); this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING); this.allowNaN = opts.getBool("allow_nan", false); this.allowTrailingComma = opts.getBool("allow_trailing_comma", false); @@ -226,8 +210,6 @@ public class Parser extends RubyObject { if(symbolizeNames && createAdditions) { throw runtime.newArgumentError("options :symbolize_names and :create_additions cannot be used in conjunction"); } - this.vSource = arg0.convertToString(); - this.vSource = convertEncoding(context, vSource); return this; } @@ -256,27 +238,8 @@ public class Parser extends RubyObject { * complete data structure as a result. */ @JRubyMethod - public IRubyObject parse(ThreadContext context) { - return new ParserSession(this, context, info).parse(context); - } - - /** - * Parser#source() - * - *

Returns a copy of the current source string, that was - * used to construct this Parser. - */ - @JRubyMethod(name = "source") - public IRubyObject source_get(ThreadContext context) { - return checkAndGetSource(context).dup(); - } - - public RubyString checkAndGetSource(ThreadContext context) { - if (vSource != null) { - return vSource; - } else { - throw context.runtime.newTypeError("uninitialized instance"); - } + public IRubyObject parse(ThreadContext context, IRubyObject source) { + return new ParserSession(this, convertEncoding(context, source.convertToString()), context, info).parse(context); } /** @@ -313,7 +276,7 @@ public class Parser extends RubyObject { // Ragel uses lots of fall-through @SuppressWarnings("fallthrough") private static class ParserSession { - private final Parser parser; + private final ParserConfig config; private final RuntimeInfo info; private final ByteList byteList; private final ByteList view; @@ -321,10 +284,10 @@ public class Parser extends RubyObject { private final StringDecoder decoder; private int currentNesting = 0; - private ParserSession(Parser parser, ThreadContext context, RuntimeInfo info) { - this.parser = parser; + private ParserSession(ParserConfig config, RubyString source, ThreadContext context, RuntimeInfo info) { + this.config = config; this.info = info; - this.byteList = parser.checkAndGetSource(context).getByteList(); + this.byteList = source.getByteList(); this.data = byteList.unsafeBytes(); this.view = new ByteList(data, false); this.decoder = new StringDecoder(); @@ -381,14 +344,14 @@ public class Parser extends RubyObject { result = context.tru; } action parse_nan { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_NAN); } else { throw unexpectedToken(context, p - 2, pe); } } action parse_infinity { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_INFINITY); } else { throw unexpectedToken(context, p - 7, pe); @@ -398,7 +361,7 @@ public class Parser extends RubyObject { if (pe > fpc + 8 && absSubSequence(fpc, fpc + 9).equals(JSON_MINUS_INFINITY)) { - if (parser.allowNaN) { + if (config.allowNaN) { result = getConstant(CONST_MINUS_INFINITY); fexec p + 10; fhold; @@ -479,7 +442,7 @@ public class Parser extends RubyObject { %% write exec; if (cs >= JSON_value_first_final && result != null) { - if (parser.freeze) { + if (config.freeze) { result.setFrozen(true); } res.update(result, p); @@ -559,7 +522,7 @@ public class Parser extends RubyObject { return; } final ByteList num = absSubSequence(p, new_p); - IRubyObject number = parser.decimalFactory.apply(context, num); + IRubyObject number = config.decimalFactory.apply(context, num); res.update(number, new_p + 1); } @@ -619,8 +582,8 @@ public class Parser extends RubyObject { int memo = p; %% write exec; - if (parser.createAdditions) { - RubyHash matchString = parser.match_string; + if (config.createAdditions) { + RubyHash matchString = config.match_string; if (matchString != null) { final IRubyObject[] memoArray = { result, null }; try { @@ -630,7 +593,7 @@ public class Parser extends RubyObject { RubyClass klass = (RubyClass) memoArray[1]; if (klass.respondsTo("json_creatable?") && klass.callMethod(context, "json_creatable?").isTrue()) { - if (parser.deprecatedCreateAdditions) { + if (config.deprecatedCreateAdditions) { context.runtime.getWarnings().warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`"); } result = klass.callMethod(context, "json_create", result); @@ -644,7 +607,7 @@ public class Parser extends RubyObject { RubyString string = (RubyString)result; string.setEncoding(UTF8Encoding.INSTANCE); string.clearCodeRange(); - if (parser.freeze) { + if (config.freeze) { string.setFrozen(true); string = context.runtime.freezeAndDedupString(string); } @@ -663,7 +626,7 @@ public class Parser extends RubyObject { write data; - action allow_trailing_comma { parser.allowTrailingComma } + action allow_trailing_comma { config.allowTrailingComma } action parse_value { parseValue(context, res, fpc, pe); @@ -671,7 +634,7 @@ public class Parser extends RubyObject { fhold; fbreak; } else { - if (parser.arrayClass == context.runtime.getArray()) { + if (config.arrayClass == context.runtime.getArray()) { ((RubyArray)result).append(res.result); } else { result.callMethod(context, "<<", res.result); @@ -701,16 +664,16 @@ public class Parser extends RubyObject { void parseArray(ThreadContext context, ParserResult res, int p, int pe) { int cs; - if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) { + if (config.maxNesting > 0 && currentNesting > config.maxNesting) { throw newException(context, Utils.M_NESTING_ERROR, "nesting of " + currentNesting + " is too deep"); } IRubyObject result; - if (parser.arrayClass == context.runtime.getArray()) { + if (config.arrayClass == context.runtime.getArray()) { result = RubyArray.newArray(context.runtime); } else { - result = parser.arrayClass.newInstance(context, + result = config.arrayClass.newInstance(context, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); } @@ -730,7 +693,7 @@ public class Parser extends RubyObject { write data; - action allow_trailing_comma { parser.allowTrailingComma } + action allow_trailing_comma { config.allowTrailingComma } action parse_value { parseValue(context, res, fpc, pe); @@ -738,7 +701,7 @@ public class Parser extends RubyObject { fhold; fbreak; } else { - if (parser.objectClass == context.runtime.getHash()) { + if (config.objectClass == context.runtime.getHash()) { ((RubyHash)result).op_aset(context, lastName, res.result); } else { Helpers.invoke(context, result, "[]=", lastName, res.result); @@ -754,7 +717,7 @@ public class Parser extends RubyObject { fbreak; } else { RubyString name = (RubyString)res.result; - if (parser.symbolizeNames) { + if (config.symbolizeNames) { lastName = name.intern(); } else { lastName = name; @@ -784,7 +747,7 @@ public class Parser extends RubyObject { IRubyObject lastName = null; boolean objectDefault = true; - if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) { + if (config.maxNesting > 0 && currentNesting > config.maxNesting) { throw newException(context, Utils.M_NESTING_ERROR, "nesting of " + currentNesting + " is too deep"); } @@ -792,11 +755,11 @@ public class Parser extends RubyObject { // this is guaranteed to be a RubyHash due to the earlier // allocator test at OptionsReader#getClass IRubyObject result; - if (parser.objectClass == context.runtime.getHash()) { + if (config.objectClass == context.runtime.getHash()) { result = RubyHash.newHash(context.runtime); } else { objectDefault = false; - result = parser.objectClass.newInstance(context, + result = config.objectClass.newInstance(context, IRubyObject.NULL_ARRAY, Block.NULL_BLOCK); } @@ -811,21 +774,21 @@ public class Parser extends RubyObject { IRubyObject returnedResult = result; // attempt to de-serialize object - if (parser.createAdditions) { + if (config.createAdditions) { IRubyObject vKlassName; if (objectDefault) { - vKlassName = ((RubyHash)result).op_aref(context, parser.createId); + vKlassName = ((RubyHash)result).op_aref(context, config.createId); } else { - vKlassName = result.callMethod(context, "[]", parser.createId); + vKlassName = result.callMethod(context, "[]", config.createId); } if (!vKlassName.isNil()) { // might throw ArgumentError, we let it propagate - IRubyObject klass = parser.info.jsonModule.get(). + IRubyObject klass = config.info.jsonModule.get(). callMethod(context, "deep_const_get", vKlassName); if (klass.respondsTo("json_creatable?") && klass.callMethod(context, "json_creatable?").isTrue()) { - if (parser.deprecatedCreateAdditions) { + if (config.deprecatedCreateAdditions) { context.runtime.getWarnings().warn("JSON.load implicit support for `create_additions: true` is deprecated and will be removed in 3.0, use JSON.unsafe_load or explicitly pass `create_additions: true`"); } @@ -896,7 +859,7 @@ public class Parser extends RubyObject { * @param name The constant name */ private IRubyObject getConstant(String name) { - return parser.info.jsonModule.get().getConstant(name); + return config.info.jsonModule.get().getConstant(name); } private RaiseException newException(ThreadContext context, String className, String message) { diff --git a/java/src/json/ext/ParserService.java b/java/src/json/ext/ParserService.java index b6015f96..88aa9674 100644 --- a/java/src/json/ext/ParserService.java +++ b/java/src/json/ext/ParserService.java @@ -25,10 +25,10 @@ public boolean basicLoad(Ruby runtime) throws IOException { info.jsonModule = new WeakReference(runtime.defineModule("JSON")); RubyModule jsonExtModule = info.jsonModule.get().defineModuleUnder("Ext"); - RubyClass parserClass = - jsonExtModule.defineClassUnder("Parser", runtime.getObject(), - Parser.ALLOCATOR); - parserClass.defineAnnotatedMethods(Parser.class); + RubyClass parserConfigClass = + jsonExtModule.defineClassUnder("ParserConfig", runtime.getObject(), + ParserConfig.ALLOCATOR); + parserConfigClass.defineAnnotatedMethods(ParserConfig.class); return true; } } diff --git a/lib/json/common.rb b/lib/json/common.rb index 89f11a0c..3c85ef06 100644 --- a/lib/json/common.rb +++ b/lib/json/common.rb @@ -232,12 +232,13 @@ def parse(source, opts = nil) # - 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 = { + def parse!(source, opts = nil) + options = { :max_nesting => false, :allow_nan => true - }.merge(opts) - Parser.new(source, **(opts||{})).parse + } + options.merge!(opts) if opts + Parser.new(source, options).parse end # :call-seq: @@ -258,7 +259,7 @@ def load_file(filespec, opts = nil) # JSON.parse!(File.read(path, opts)) # # See method #parse! - def load_file!(filespec, opts = {}) + def load_file!(filespec, opts = nil) parse!(File.read(filespec, encoding: Encoding::UTF_8), opts) end diff --git a/lib/json/ext.rb b/lib/json/ext.rb index 2082cae6..f9fca0a1 100644 --- a/lib/json/ext.rb +++ b/lib/json/ext.rb @@ -6,15 +6,36 @@ module JSON # This module holds all the modules/classes that implement JSON's # functionality as C extensions. module Ext + class Parser + class << self + def parse(...) + new(...).parse + end + end + + def initialize(source, opts = nil) + @source = source + @config = Config.new(opts) + end + + def source + @source.dup + end + + def parse + @config.parse(@source) + end + end + + require 'json/ext/parser' + Ext::Parser::Config = Ext::ParserConfig + JSON.parser = Ext::Parser + 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 diff --git a/test/json/json_ext_parser_test.rb b/test/json/json_ext_parser_test.rb index da615049..8aa62625 100644 --- a/test/json/json_ext_parser_test.rb +++ b/test/json/json_ext_parser_test.rb @@ -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.__send__(:initialize, "{}") + assert_equal "{}", parser.source + parser = JSON::Ext::Parser.allocate - assert_raise(TypeError, '[ruby-core:35079]') { parser.source } + assert_nil parser.source end def test_error_messages