json 2.10.2 → 2.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +38 -0
- data/ext/json/ext/fbuffer/fbuffer.h +45 -14
- data/ext/json/ext/generator/generator.c +111 -92
- data/ext/json/ext/parser/extconf.rb +0 -1
- data/ext/json/ext/parser/parser.c +30 -151
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/lib/json/common.rb +274 -159
- data/lib/json/truffle_ruby/generator.rb +1 -1
- data/lib/json/version.rb +1 -1
- metadata +4 -2
@@ -31,28 +31,15 @@ typedef unsigned char _Bool;
|
|
31
31
|
static VALUE mJSON, eNestingError, Encoding_UTF_8;
|
32
32
|
static VALUE CNaN, CInfinity, CMinusInfinity;
|
33
33
|
|
34
|
-
static ID
|
35
|
-
i_chr, i_deep_const_get, i_match, i_aset, i_aref,
|
34
|
+
static ID i_chr, i_aset, i_aref,
|
36
35
|
i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
|
37
36
|
|
38
37
|
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
|
39
|
-
|
40
|
-
sym_decimal_class, sym_match_string;
|
38
|
+
sym_decimal_class, sym_on_load;
|
41
39
|
|
42
40
|
static int binary_encindex;
|
43
41
|
static int utf8_encindex;
|
44
42
|
|
45
|
-
#ifdef HAVE_RB_CATEGORY_WARN
|
46
|
-
# define json_deprecated(message) rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, message)
|
47
|
-
#else
|
48
|
-
# define json_deprecated(message) rb_warn(message)
|
49
|
-
#endif
|
50
|
-
|
51
|
-
static const char deprecated_create_additions_warning[] =
|
52
|
-
"JSON.load implicit support for `create_additions: true` is deprecated "
|
53
|
-
"and will be removed in 3.0, use JSON.unsafe_load or explicitly "
|
54
|
-
"pass `create_additions: true`";
|
55
|
-
|
56
43
|
#ifndef HAVE_RB_HASH_BULK_INSERT
|
57
44
|
// For TruffleRuby
|
58
45
|
void
|
@@ -444,20 +431,15 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
|
444
431
|
}
|
445
432
|
|
446
433
|
typedef struct JSON_ParserStruct {
|
447
|
-
VALUE
|
448
|
-
VALUE object_class;
|
449
|
-
VALUE array_class;
|
434
|
+
VALUE on_load_proc;
|
450
435
|
VALUE decimal_class;
|
451
436
|
ID decimal_method_id;
|
452
|
-
VALUE match_string;
|
453
437
|
int max_nesting;
|
454
438
|
bool allow_nan;
|
455
439
|
bool allow_trailing_comma;
|
456
440
|
bool parsing_name;
|
457
441
|
bool symbolize_names;
|
458
442
|
bool freeze;
|
459
|
-
bool create_additions;
|
460
|
-
bool deprecated_create_additions;
|
461
443
|
} JSON_ParserConfig;
|
462
444
|
|
463
445
|
typedef struct JSON_ParserStateStruct {
|
@@ -769,18 +751,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
|
|
769
751
|
|
770
752
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
771
753
|
{
|
772
|
-
VALUE array;
|
773
|
-
if (RB_UNLIKELY(config->array_class)) {
|
774
|
-
array = rb_class_new_instance(0, 0, config->array_class);
|
775
|
-
VALUE *items = rvalue_stack_peek(state->stack, count);
|
776
|
-
long index;
|
777
|
-
for (index = 0; index < count; index++) {
|
778
|
-
rb_funcall(array, i_leftshift, 1, items[index]);
|
779
|
-
}
|
780
|
-
} else {
|
781
|
-
array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
782
|
-
}
|
783
|
-
|
754
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
784
755
|
rvalue_stack_pop(state->stack, count);
|
785
756
|
|
786
757
|
if (config->freeze) {
|
@@ -792,41 +763,11 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
792
763
|
|
793
764
|
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
794
765
|
{
|
795
|
-
VALUE object;
|
796
|
-
|
797
|
-
object = rb_class_new_instance(0, 0, config->object_class);
|
798
|
-
long index = 0;
|
799
|
-
VALUE *items = rvalue_stack_peek(state->stack, count);
|
800
|
-
while (index < count) {
|
801
|
-
VALUE name = items[index++];
|
802
|
-
VALUE value = items[index++];
|
803
|
-
rb_funcall(object, i_aset, 2, name, value);
|
804
|
-
}
|
805
|
-
} else {
|
806
|
-
object = rb_hash_new_capa(count);
|
807
|
-
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
808
|
-
}
|
766
|
+
VALUE object = rb_hash_new_capa(count);
|
767
|
+
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
809
768
|
|
810
769
|
rvalue_stack_pop(state->stack, count);
|
811
770
|
|
812
|
-
if (RB_UNLIKELY(config->create_additions)) {
|
813
|
-
VALUE klassname;
|
814
|
-
if (config->object_class) {
|
815
|
-
klassname = rb_funcall(object, i_aref, 1, config->create_id);
|
816
|
-
} else {
|
817
|
-
klassname = rb_hash_aref(object, config->create_id);
|
818
|
-
}
|
819
|
-
if (!NIL_P(klassname)) {
|
820
|
-
VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
|
821
|
-
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
|
822
|
-
if (config->deprecated_create_additions) {
|
823
|
-
json_deprecated(deprecated_create_additions_warning);
|
824
|
-
}
|
825
|
-
object = rb_funcall(klass, i_json_create, 1, object);
|
826
|
-
}
|
827
|
-
}
|
828
|
-
}
|
829
|
-
|
830
771
|
if (config->freeze) {
|
831
772
|
RB_OBJ_FREEZE(object);
|
832
773
|
}
|
@@ -834,17 +775,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
834
775
|
return object;
|
835
776
|
}
|
836
777
|
|
837
|
-
static int match_i(VALUE regexp, VALUE klass, VALUE memo)
|
838
|
-
{
|
839
|
-
if (regexp == Qundef) return ST_STOP;
|
840
|
-
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
|
841
|
-
RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
|
842
|
-
rb_ary_push(memo, klass);
|
843
|
-
return ST_STOP;
|
844
|
-
}
|
845
|
-
return ST_CONTINUE;
|
846
|
-
}
|
847
|
-
|
848
778
|
static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
|
849
779
|
{
|
850
780
|
VALUE string;
|
@@ -856,21 +786,17 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
|
|
856
786
|
string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
|
857
787
|
}
|
858
788
|
|
859
|
-
if (RB_UNLIKELY(config->create_additions && RTEST(config->match_string))) {
|
860
|
-
VALUE klass;
|
861
|
-
VALUE memo = rb_ary_new2(2);
|
862
|
-
rb_ary_push(memo, string);
|
863
|
-
rb_hash_foreach(config->match_string, match_i, memo);
|
864
|
-
klass = rb_ary_entry(memo, 1);
|
865
|
-
if (RTEST(klass)) {
|
866
|
-
string = rb_funcall(klass, i_json_create, 1, string);
|
867
|
-
}
|
868
|
-
}
|
869
|
-
|
870
789
|
return string;
|
871
790
|
}
|
872
791
|
|
873
|
-
|
792
|
+
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
|
793
|
+
{
|
794
|
+
if (RB_UNLIKELY(config->on_load_proc)) {
|
795
|
+
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
796
|
+
}
|
797
|
+
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
|
798
|
+
return value;
|
799
|
+
}
|
874
800
|
|
875
801
|
static const bool string_scan[256] = {
|
876
802
|
// ASCII Control Characters
|
@@ -897,7 +823,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
897
823
|
case '"': {
|
898
824
|
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
899
825
|
state->cursor++;
|
900
|
-
return
|
826
|
+
return json_push_value(state, config, string);
|
901
827
|
}
|
902
828
|
case '\\': {
|
903
829
|
state->cursor++;
|
@@ -931,7 +857,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
931
857
|
case 'n':
|
932
858
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
|
933
859
|
state->cursor += 4;
|
934
|
-
return
|
860
|
+
return json_push_value(state, config, Qnil);
|
935
861
|
}
|
936
862
|
|
937
863
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
@@ -939,7 +865,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
939
865
|
case 't':
|
940
866
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
941
867
|
state->cursor += 4;
|
942
|
-
return
|
868
|
+
return json_push_value(state, config, Qtrue);
|
943
869
|
}
|
944
870
|
|
945
871
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
@@ -948,7 +874,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
948
874
|
// Note: memcmp with a small power of two compile to an integer comparison
|
949
875
|
if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
|
950
876
|
state->cursor += 5;
|
951
|
-
return
|
877
|
+
return json_push_value(state, config, Qfalse);
|
952
878
|
}
|
953
879
|
|
954
880
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
@@ -957,7 +883,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
957
883
|
// Note: memcmp with a small power of two compile to an integer comparison
|
958
884
|
if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
|
959
885
|
state->cursor += 3;
|
960
|
-
return
|
886
|
+
return json_push_value(state, config, CNaN);
|
961
887
|
}
|
962
888
|
|
963
889
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
@@ -965,7 +891,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
965
891
|
case 'I':
|
966
892
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
967
893
|
state->cursor += 8;
|
968
|
-
return
|
894
|
+
return json_push_value(state, config, CInfinity);
|
969
895
|
}
|
970
896
|
|
971
897
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
@@ -975,7 +901,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
975
901
|
if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
|
976
902
|
if (config->allow_nan) {
|
977
903
|
state->cursor += 9;
|
978
|
-
return
|
904
|
+
return json_push_value(state, config, CMinusInfinity);
|
979
905
|
} else {
|
980
906
|
raise_parse_error("unexpected token at '%s'", state->cursor);
|
981
907
|
}
|
@@ -1032,9 +958,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1032
958
|
}
|
1033
959
|
|
1034
960
|
if (integer) {
|
1035
|
-
return
|
961
|
+
return json_push_value(state, config, json_decode_integer(start, state->cursor));
|
1036
962
|
}
|
1037
|
-
return
|
963
|
+
return json_push_value(state, config, json_decode_float(config, start, state->cursor));
|
1038
964
|
}
|
1039
965
|
case '"': {
|
1040
966
|
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
|
@@ -1048,7 +974,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1048
974
|
|
1049
975
|
if ((state->cursor < state->end) && (*state->cursor == ']')) {
|
1050
976
|
state->cursor++;
|
1051
|
-
return
|
977
|
+
return json_push_value(state, config, json_decode_array(state, config, 0));
|
1052
978
|
} else {
|
1053
979
|
state->current_nesting++;
|
1054
980
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1067,7 +993,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1067
993
|
long count = state->stack->head - stack_head;
|
1068
994
|
state->current_nesting--;
|
1069
995
|
state->in_array--;
|
1070
|
-
return
|
996
|
+
return json_push_value(state, config, json_decode_array(state, config, count));
|
1071
997
|
}
|
1072
998
|
|
1073
999
|
if (*state->cursor == ',') {
|
@@ -1094,7 +1020,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1094
1020
|
|
1095
1021
|
if ((state->cursor < state->end) && (*state->cursor == '}')) {
|
1096
1022
|
state->cursor++;
|
1097
|
-
return
|
1023
|
+
return json_push_value(state, config, json_decode_object(state, config, 0));
|
1098
1024
|
} else {
|
1099
1025
|
state->current_nesting++;
|
1100
1026
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1123,7 +1049,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1123
1049
|
state->cursor++;
|
1124
1050
|
state->current_nesting--;
|
1125
1051
|
long count = state->stack->head - stack_head;
|
1126
|
-
return
|
1052
|
+
return json_push_value(state, config, json_decode_object(state, config, count));
|
1127
1053
|
}
|
1128
1054
|
|
1129
1055
|
if (*state->cursor == ',') {
|
@@ -1211,10 +1137,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1211
1137
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
1212
1138
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
1213
1139
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
1214
|
-
else if (key ==
|
1215
|
-
else if (key == sym_object_class) { config->object_class = RTEST(val) ? val : Qfalse; }
|
1216
|
-
else if (key == sym_array_class) { config->array_class = RTEST(val) ? val : Qfalse; }
|
1217
|
-
else if (key == sym_match_string) { config->match_string = RTEST(val) ? val : Qfalse; }
|
1140
|
+
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
1218
1141
|
else if (key == sym_decimal_class) {
|
1219
1142
|
if (RTEST(val)) {
|
1220
1143
|
if (rb_respond_to(val, i_try_convert)) {
|
@@ -1244,15 +1167,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1244
1167
|
}
|
1245
1168
|
}
|
1246
1169
|
}
|
1247
|
-
else if (key == sym_create_additions) {
|
1248
|
-
if (NIL_P(val)) {
|
1249
|
-
config->create_additions = true;
|
1250
|
-
config->deprecated_create_additions = true;
|
1251
|
-
} else {
|
1252
|
-
config->create_additions = RTEST(val);
|
1253
|
-
config->deprecated_create_additions = false;
|
1254
|
-
}
|
1255
|
-
}
|
1256
1170
|
|
1257
1171
|
return ST_CONTINUE;
|
1258
1172
|
}
|
@@ -1267,16 +1181,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1267
1181
|
// We assume in most cases few keys are set so it's faster to go over
|
1268
1182
|
// the provided keys than to check all possible keys.
|
1269
1183
|
rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
|
1270
|
-
|
1271
|
-
if (config->symbolize_names && config->create_additions) {
|
1272
|
-
rb_raise(rb_eArgError,
|
1273
|
-
"options :symbolize_names and :create_additions cannot be "
|
1274
|
-
" used in conjunction");
|
1275
|
-
}
|
1276
|
-
|
1277
|
-
if (config->create_additions && !config->create_id) {
|
1278
|
-
config->create_id = rb_funcall(mJSON, i_create_id, 0);
|
1279
|
-
}
|
1280
1184
|
}
|
1281
1185
|
|
1282
1186
|
}
|
@@ -1301,15 +1205,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1301
1205
|
* (keys) in a JSON object. Otherwise strings are returned, which is
|
1302
1206
|
* also the default. It's not possible to use this option in
|
1303
1207
|
* conjunction with the *create_additions* option.
|
1304
|
-
* * *create_additions*: If set to false, the Parser doesn't create
|
1305
|
-
* additions even if a matching class and create_id was found. This option
|
1306
|
-
* defaults to false.
|
1307
|
-
* * *object_class*: Defaults to Hash. If another type is provided, it will be used
|
1308
|
-
* instead of Hash to represent JSON objects. The type must respond to
|
1309
|
-
* +new+ without arguments, and return an object that respond to +[]=+.
|
1310
|
-
* * *array_class*: Defaults to Array If another type is provided, it will be used
|
1311
|
-
* instead of Hash to represent JSON arrays. The type must respond to
|
1312
|
-
* +new+ without arguments, and return an object that respond to +<<+.
|
1313
1208
|
* * *decimal_class*: Specifies which class to use instead of the default
|
1314
1209
|
* (Float) when parsing decimal numbers. This class must accept a single
|
1315
1210
|
* string argument in its constructor.
|
@@ -1320,11 +1215,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
1320
1215
|
|
1321
1216
|
parser_config_init(config, opts);
|
1322
1217
|
|
1323
|
-
RB_OBJ_WRITTEN(self, Qundef, config->create_id);
|
1324
|
-
RB_OBJ_WRITTEN(self, Qundef, config->object_class);
|
1325
|
-
RB_OBJ_WRITTEN(self, Qundef, config->array_class);
|
1326
1218
|
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
1327
|
-
RB_OBJ_WRITTEN(self, Qundef, config->match_string);
|
1328
1219
|
|
1329
1220
|
return self;
|
1330
1221
|
}
|
@@ -1387,11 +1278,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
1387
1278
|
static void JSON_ParserConfig_mark(void *ptr)
|
1388
1279
|
{
|
1389
1280
|
JSON_ParserConfig *config = ptr;
|
1390
|
-
rb_gc_mark(config->
|
1391
|
-
rb_gc_mark(config->object_class);
|
1392
|
-
rb_gc_mark(config->array_class);
|
1281
|
+
rb_gc_mark(config->on_load_proc);
|
1393
1282
|
rb_gc_mark(config->decimal_class);
|
1394
|
-
rb_gc_mark(config->match_string);
|
1395
1283
|
}
|
1396
1284
|
|
1397
1285
|
static void JSON_ParserConfig_free(void *ptr)
|
@@ -1459,19 +1347,10 @@ void Init_parser(void)
|
|
1459
1347
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
1460
1348
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
1461
1349
|
sym_freeze = ID2SYM(rb_intern("freeze"));
|
1462
|
-
|
1463
|
-
sym_create_id = ID2SYM(rb_intern("create_id"));
|
1464
|
-
sym_object_class = ID2SYM(rb_intern("object_class"));
|
1465
|
-
sym_array_class = ID2SYM(rb_intern("array_class"));
|
1350
|
+
sym_on_load = ID2SYM(rb_intern("on_load"));
|
1466
1351
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1467
|
-
sym_match_string = ID2SYM(rb_intern("match_string"));
|
1468
1352
|
|
1469
|
-
i_create_id = rb_intern("create_id");
|
1470
|
-
i_json_creatable_p = rb_intern("json_creatable?");
|
1471
|
-
i_json_create = rb_intern("json_create");
|
1472
1353
|
i_chr = rb_intern("chr");
|
1473
|
-
i_match = rb_intern("match");
|
1474
|
-
i_deep_const_get = rb_intern("deep_const_get");
|
1475
1354
|
i_aset = rb_intern("[]=");
|
1476
1355
|
i_aref = rb_intern("[]");
|
1477
1356
|
i_leftshift = rb_intern("<<");
|