json 2.10.2 → 2.12.0
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 +47 -0
- data/ext/json/ext/fbuffer/fbuffer.h +45 -14
- data/ext/json/ext/generator/extconf.rb +29 -0
- data/ext/json/ext/generator/generator.c +467 -100
- data/ext/json/ext/generator/simd.h +112 -0
- data/ext/json/ext/parser/extconf.rb +0 -1
- data/ext/json/ext/parser/parser.c +160 -242
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/lib/json/common.rb +277 -160
- data/lib/json/truffle_ruby/generator.rb +1 -1
- data/lib/json/version.rb +1 -1
- metadata +5 -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
|
@@ -350,19 +337,86 @@ static size_t strnlen(const char *s, size_t maxlen)
|
|
350
337
|
}
|
351
338
|
#endif
|
352
339
|
|
340
|
+
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
341
|
+
{
|
342
|
+
int len = 1;
|
343
|
+
if (ch <= 0x7F) {
|
344
|
+
buf[0] = (char) ch;
|
345
|
+
} else if (ch <= 0x07FF) {
|
346
|
+
buf[0] = (char) ((ch >> 6) | 0xC0);
|
347
|
+
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
348
|
+
len++;
|
349
|
+
} else if (ch <= 0xFFFF) {
|
350
|
+
buf[0] = (char) ((ch >> 12) | 0xE0);
|
351
|
+
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
352
|
+
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
353
|
+
len += 2;
|
354
|
+
} else if (ch <= 0x1fffff) {
|
355
|
+
buf[0] =(char) ((ch >> 18) | 0xF0);
|
356
|
+
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
357
|
+
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
358
|
+
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
359
|
+
len += 3;
|
360
|
+
} else {
|
361
|
+
buf[0] = '?';
|
362
|
+
}
|
363
|
+
return len;
|
364
|
+
}
|
365
|
+
|
366
|
+
typedef struct JSON_ParserStruct {
|
367
|
+
VALUE on_load_proc;
|
368
|
+
VALUE decimal_class;
|
369
|
+
ID decimal_method_id;
|
370
|
+
int max_nesting;
|
371
|
+
bool allow_nan;
|
372
|
+
bool allow_trailing_comma;
|
373
|
+
bool parsing_name;
|
374
|
+
bool symbolize_names;
|
375
|
+
bool freeze;
|
376
|
+
} JSON_ParserConfig;
|
377
|
+
|
378
|
+
typedef struct JSON_ParserStateStruct {
|
379
|
+
VALUE stack_handle;
|
380
|
+
const char *start;
|
381
|
+
const char *cursor;
|
382
|
+
const char *end;
|
383
|
+
rvalue_stack *stack;
|
384
|
+
rvalue_cache name_cache;
|
385
|
+
int in_array;
|
386
|
+
int current_nesting;
|
387
|
+
} JSON_ParserState;
|
388
|
+
|
389
|
+
|
353
390
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
354
391
|
#ifdef RBIMPL_ATTR_NORETURN
|
355
392
|
RBIMPL_ATTR_NORETURN()
|
356
393
|
#endif
|
357
|
-
static void raise_parse_error(const char *format,
|
394
|
+
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
358
395
|
{
|
359
396
|
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
|
360
397
|
|
361
|
-
|
362
|
-
|
398
|
+
const char *cursor = state->cursor;
|
399
|
+
long column = 0;
|
400
|
+
long line = 1;
|
401
|
+
|
402
|
+
while (cursor >= state->start) {
|
403
|
+
if (*cursor-- == '\n') {
|
404
|
+
break;
|
405
|
+
}
|
406
|
+
column++;
|
407
|
+
}
|
408
|
+
|
409
|
+
while (cursor >= state->start) {
|
410
|
+
if (*cursor-- == '\n') {
|
411
|
+
line++;
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
const char *ptr = state->cursor;
|
416
|
+
size_t len = ptr ? strnlen(ptr, PARSE_ERROR_FRAGMENT_LEN) : 0;
|
363
417
|
|
364
418
|
if (len == PARSE_ERROR_FRAGMENT_LEN) {
|
365
|
-
MEMCPY(buffer,
|
419
|
+
MEMCPY(buffer, ptr, char, PARSE_ERROR_FRAGMENT_LEN);
|
366
420
|
|
367
421
|
while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
|
368
422
|
len--;
|
@@ -376,7 +430,23 @@ static void raise_parse_error(const char *format, const char *start)
|
|
376
430
|
ptr = (const char *)buffer;
|
377
431
|
}
|
378
432
|
|
379
|
-
|
433
|
+
VALUE msg = rb_sprintf(format, ptr);
|
434
|
+
VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
|
435
|
+
RB_GC_GUARD(msg);
|
436
|
+
|
437
|
+
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
438
|
+
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
439
|
+
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
440
|
+
rb_exc_raise(exc);
|
441
|
+
}
|
442
|
+
|
443
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
444
|
+
RBIMPL_ATTR_NORETURN()
|
445
|
+
#endif
|
446
|
+
static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
447
|
+
{
|
448
|
+
state->cursor = at;
|
449
|
+
raise_parse_error(format, state);
|
380
450
|
}
|
381
451
|
|
382
452
|
/* unicode */
|
@@ -398,78 +468,25 @@ static const signed char digit_values[256] = {
|
|
398
468
|
-1, -1, -1, -1, -1, -1, -1
|
399
469
|
};
|
400
470
|
|
401
|
-
static uint32_t unescape_unicode(const unsigned char *p)
|
471
|
+
static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
|
402
472
|
{
|
403
473
|
signed char b;
|
404
474
|
uint32_t result = 0;
|
405
475
|
b = digit_values[p[0]];
|
406
|
-
if (b < 0)
|
476
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
407
477
|
result = (result << 4) | (unsigned char)b;
|
408
478
|
b = digit_values[p[1]];
|
409
|
-
if (b < 0)
|
479
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
410
480
|
result = (result << 4) | (unsigned char)b;
|
411
481
|
b = digit_values[p[2]];
|
412
|
-
if (b < 0)
|
482
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
413
483
|
result = (result << 4) | (unsigned char)b;
|
414
484
|
b = digit_values[p[3]];
|
415
|
-
if (b < 0)
|
485
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
416
486
|
result = (result << 4) | (unsigned char)b;
|
417
487
|
return result;
|
418
488
|
}
|
419
489
|
|
420
|
-
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
421
|
-
{
|
422
|
-
int len = 1;
|
423
|
-
if (ch <= 0x7F) {
|
424
|
-
buf[0] = (char) ch;
|
425
|
-
} else if (ch <= 0x07FF) {
|
426
|
-
buf[0] = (char) ((ch >> 6) | 0xC0);
|
427
|
-
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
428
|
-
len++;
|
429
|
-
} else if (ch <= 0xFFFF) {
|
430
|
-
buf[0] = (char) ((ch >> 12) | 0xE0);
|
431
|
-
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
432
|
-
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
433
|
-
len += 2;
|
434
|
-
} else if (ch <= 0x1fffff) {
|
435
|
-
buf[0] =(char) ((ch >> 18) | 0xF0);
|
436
|
-
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
437
|
-
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
438
|
-
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
439
|
-
len += 3;
|
440
|
-
} else {
|
441
|
-
buf[0] = '?';
|
442
|
-
}
|
443
|
-
return len;
|
444
|
-
}
|
445
|
-
|
446
|
-
typedef struct JSON_ParserStruct {
|
447
|
-
VALUE create_id;
|
448
|
-
VALUE object_class;
|
449
|
-
VALUE array_class;
|
450
|
-
VALUE decimal_class;
|
451
|
-
ID decimal_method_id;
|
452
|
-
VALUE match_string;
|
453
|
-
int max_nesting;
|
454
|
-
bool allow_nan;
|
455
|
-
bool allow_trailing_comma;
|
456
|
-
bool parsing_name;
|
457
|
-
bool symbolize_names;
|
458
|
-
bool freeze;
|
459
|
-
bool create_additions;
|
460
|
-
bool deprecated_create_additions;
|
461
|
-
} JSON_ParserConfig;
|
462
|
-
|
463
|
-
typedef struct JSON_ParserStateStruct {
|
464
|
-
VALUE stack_handle;
|
465
|
-
const char *cursor;
|
466
|
-
const char *end;
|
467
|
-
rvalue_stack *stack;
|
468
|
-
rvalue_cache name_cache;
|
469
|
-
int in_array;
|
470
|
-
int current_nesting;
|
471
|
-
} JSON_ParserState;
|
472
|
-
|
473
490
|
#define GET_PARSER_CONFIG \
|
474
491
|
JSON_ParserConfig *config; \
|
475
492
|
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
|
@@ -503,8 +520,7 @@ json_eat_comments(JSON_ParserState *state)
|
|
503
520
|
while (true) {
|
504
521
|
state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
|
505
522
|
if (!state->cursor) {
|
506
|
-
|
507
|
-
raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
|
523
|
+
raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
|
508
524
|
} else {
|
509
525
|
state->cursor++;
|
510
526
|
if (state->cursor < state->end && *state->cursor == '/') {
|
@@ -516,11 +532,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
516
532
|
break;
|
517
533
|
}
|
518
534
|
default:
|
519
|
-
raise_parse_error("unexpected token
|
535
|
+
raise_parse_error("unexpected token '%s'", state);
|
520
536
|
break;
|
521
537
|
}
|
522
538
|
} else {
|
523
|
-
raise_parse_error("unexpected token
|
539
|
+
raise_parse_error("unexpected token '%s'", state);
|
524
540
|
}
|
525
541
|
}
|
526
542
|
|
@@ -639,9 +655,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
639
655
|
break;
|
640
656
|
case 'u':
|
641
657
|
if (pe > stringEnd - 5) {
|
642
|
-
|
658
|
+
raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, p);
|
643
659
|
} else {
|
644
|
-
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
660
|
+
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
645
661
|
pe += 3;
|
646
662
|
/* To handle values above U+FFFF, we take a sequence of
|
647
663
|
* \uXXXX escapes in the U+D800..U+DBFF then
|
@@ -656,10 +672,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
656
672
|
if ((ch & 0xFC00) == 0xD800) {
|
657
673
|
pe++;
|
658
674
|
if (pe > stringEnd - 6) {
|
659
|
-
|
675
|
+
raise_parse_error_at("incomplete surrogate pair at '%s'", state, p);
|
660
676
|
}
|
661
677
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
662
|
-
uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
|
678
|
+
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
663
679
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
664
680
|
| (sur & 0x3FF));
|
665
681
|
pe += 5;
|
@@ -769,18 +785,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
|
|
769
785
|
|
770
786
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
771
787
|
{
|
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
|
-
|
788
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
784
789
|
rvalue_stack_pop(state->stack, count);
|
785
790
|
|
786
791
|
if (config->freeze) {
|
@@ -792,41 +797,11 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
792
797
|
|
793
798
|
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
794
799
|
{
|
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
|
-
}
|
800
|
+
VALUE object = rb_hash_new_capa(count);
|
801
|
+
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
809
802
|
|
810
803
|
rvalue_stack_pop(state->stack, count);
|
811
804
|
|
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
805
|
if (config->freeze) {
|
831
806
|
RB_OBJ_FREEZE(object);
|
832
807
|
}
|
@@ -834,17 +809,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
834
809
|
return object;
|
835
810
|
}
|
836
811
|
|
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
812
|
static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
|
849
813
|
{
|
850
814
|
VALUE string;
|
@@ -856,21 +820,17 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
|
|
856
820
|
string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
|
857
821
|
}
|
858
822
|
|
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
823
|
return string;
|
871
824
|
}
|
872
825
|
|
873
|
-
|
826
|
+
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
|
827
|
+
{
|
828
|
+
if (RB_UNLIKELY(config->on_load_proc)) {
|
829
|
+
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
830
|
+
}
|
831
|
+
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
|
832
|
+
return value;
|
833
|
+
}
|
874
834
|
|
875
835
|
static const bool string_scan[256] = {
|
876
836
|
// ASCII Control Characters
|
@@ -897,18 +857,18 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
897
857
|
case '"': {
|
898
858
|
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
899
859
|
state->cursor++;
|
900
|
-
return
|
860
|
+
return json_push_value(state, config, string);
|
901
861
|
}
|
902
862
|
case '\\': {
|
903
863
|
state->cursor++;
|
904
864
|
escaped = true;
|
905
865
|
if ((unsigned char)*state->cursor < 0x20) {
|
906
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
866
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
907
867
|
}
|
908
868
|
break;
|
909
869
|
}
|
910
870
|
default:
|
911
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
871
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
912
872
|
break;
|
913
873
|
}
|
914
874
|
}
|
@@ -916,7 +876,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
916
876
|
state->cursor++;
|
917
877
|
}
|
918
878
|
|
919
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
879
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
920
880
|
return Qfalse;
|
921
881
|
}
|
922
882
|
|
@@ -924,60 +884,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
924
884
|
{
|
925
885
|
json_eat_whitespace(state);
|
926
886
|
if (state->cursor >= state->end) {
|
927
|
-
raise_parse_error("unexpected end of input", state
|
887
|
+
raise_parse_error("unexpected end of input", state);
|
928
888
|
}
|
929
889
|
|
930
890
|
switch (*state->cursor) {
|
931
891
|
case 'n':
|
932
892
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
|
933
893
|
state->cursor += 4;
|
934
|
-
return
|
894
|
+
return json_push_value(state, config, Qnil);
|
935
895
|
}
|
936
896
|
|
937
|
-
raise_parse_error("unexpected token
|
897
|
+
raise_parse_error("unexpected token '%s'", state);
|
938
898
|
break;
|
939
899
|
case 't':
|
940
900
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
941
901
|
state->cursor += 4;
|
942
|
-
return
|
902
|
+
return json_push_value(state, config, Qtrue);
|
943
903
|
}
|
944
904
|
|
945
|
-
raise_parse_error("unexpected token
|
905
|
+
raise_parse_error("unexpected token '%s'", state);
|
946
906
|
break;
|
947
907
|
case 'f':
|
948
908
|
// Note: memcmp with a small power of two compile to an integer comparison
|
949
909
|
if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
|
950
910
|
state->cursor += 5;
|
951
|
-
return
|
911
|
+
return json_push_value(state, config, Qfalse);
|
952
912
|
}
|
953
913
|
|
954
|
-
raise_parse_error("unexpected token
|
914
|
+
raise_parse_error("unexpected token '%s'", state);
|
955
915
|
break;
|
956
916
|
case 'N':
|
957
917
|
// Note: memcmp with a small power of two compile to an integer comparison
|
958
918
|
if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
|
959
919
|
state->cursor += 3;
|
960
|
-
return
|
920
|
+
return json_push_value(state, config, CNaN);
|
961
921
|
}
|
962
922
|
|
963
|
-
raise_parse_error("unexpected token
|
923
|
+
raise_parse_error("unexpected token '%s'", state);
|
964
924
|
break;
|
965
925
|
case 'I':
|
966
926
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
967
927
|
state->cursor += 8;
|
968
|
-
return
|
928
|
+
return json_push_value(state, config, CInfinity);
|
969
929
|
}
|
970
930
|
|
971
|
-
raise_parse_error("unexpected token
|
931
|
+
raise_parse_error("unexpected token '%s'", state);
|
972
932
|
break;
|
973
933
|
case '-':
|
974
934
|
// Note: memcmp with a small power of two compile to an integer comparison
|
975
935
|
if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
|
976
936
|
if (config->allow_nan) {
|
977
937
|
state->cursor += 9;
|
978
|
-
return
|
938
|
+
return json_push_value(state, config, CMinusInfinity);
|
979
939
|
} else {
|
980
|
-
raise_parse_error("unexpected token
|
940
|
+
raise_parse_error("unexpected token '%s'", state);
|
981
941
|
}
|
982
942
|
}
|
983
943
|
// Fallthrough
|
@@ -995,11 +955,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
995
955
|
long integer_length = state->cursor - start;
|
996
956
|
|
997
957
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
998
|
-
|
958
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
999
959
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
1000
|
-
|
960
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1001
961
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
1002
|
-
|
962
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1003
963
|
}
|
1004
964
|
|
1005
965
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
@@ -1007,7 +967,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1007
967
|
state->cursor++;
|
1008
968
|
|
1009
969
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1010
|
-
raise_parse_error("invalid number: %s", state
|
970
|
+
raise_parse_error("invalid number: %s", state);
|
1011
971
|
}
|
1012
972
|
|
1013
973
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1023,7 +983,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1023
983
|
}
|
1024
984
|
|
1025
985
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1026
|
-
raise_parse_error("invalid number: %s", state
|
986
|
+
raise_parse_error("invalid number: %s", state);
|
1027
987
|
}
|
1028
988
|
|
1029
989
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1032,9 +992,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1032
992
|
}
|
1033
993
|
|
1034
994
|
if (integer) {
|
1035
|
-
return
|
995
|
+
return json_push_value(state, config, json_decode_integer(start, state->cursor));
|
1036
996
|
}
|
1037
|
-
return
|
997
|
+
return json_push_value(state, config, json_decode_float(config, start, state->cursor));
|
1038
998
|
}
|
1039
999
|
case '"': {
|
1040
1000
|
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
|
@@ -1048,7 +1008,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1048
1008
|
|
1049
1009
|
if ((state->cursor < state->end) && (*state->cursor == ']')) {
|
1050
1010
|
state->cursor++;
|
1051
|
-
return
|
1011
|
+
return json_push_value(state, config, json_decode_array(state, config, 0));
|
1052
1012
|
} else {
|
1053
1013
|
state->current_nesting++;
|
1054
1014
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1067,7 +1027,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1067
1027
|
long count = state->stack->head - stack_head;
|
1068
1028
|
state->current_nesting--;
|
1069
1029
|
state->in_array--;
|
1070
|
-
return
|
1030
|
+
return json_push_value(state, config, json_decode_array(state, config, count));
|
1071
1031
|
}
|
1072
1032
|
|
1073
1033
|
if (*state->cursor == ',') {
|
@@ -1083,7 +1043,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1083
1043
|
}
|
1084
1044
|
}
|
1085
1045
|
|
1086
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
1046
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
1087
1047
|
}
|
1088
1048
|
break;
|
1089
1049
|
}
|
@@ -1094,7 +1054,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1094
1054
|
|
1095
1055
|
if ((state->cursor < state->end) && (*state->cursor == '}')) {
|
1096
1056
|
state->cursor++;
|
1097
|
-
return
|
1057
|
+
return json_push_value(state, config, json_decode_object(state, config, 0));
|
1098
1058
|
} else {
|
1099
1059
|
state->current_nesting++;
|
1100
1060
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1102,13 +1062,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1102
1062
|
}
|
1103
1063
|
|
1104
1064
|
if (*state->cursor != '"') {
|
1105
|
-
raise_parse_error("expected object key, got '%s", state
|
1065
|
+
raise_parse_error("expected object key, got '%s", state);
|
1106
1066
|
}
|
1107
1067
|
json_parse_string(state, config, true);
|
1108
1068
|
|
1109
1069
|
json_eat_whitespace(state);
|
1110
1070
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1111
|
-
raise_parse_error("expected ':' after object key", state
|
1071
|
+
raise_parse_error("expected ':' after object key", state);
|
1112
1072
|
}
|
1113
1073
|
state->cursor++;
|
1114
1074
|
|
@@ -1123,7 +1083,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1123
1083
|
state->cursor++;
|
1124
1084
|
state->current_nesting--;
|
1125
1085
|
long count = state->stack->head - stack_head;
|
1126
|
-
return
|
1086
|
+
return json_push_value(state, config, json_decode_object(state, config, count));
|
1127
1087
|
}
|
1128
1088
|
|
1129
1089
|
if (*state->cursor == ',') {
|
@@ -1137,13 +1097,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1137
1097
|
}
|
1138
1098
|
|
1139
1099
|
if (*state->cursor != '"') {
|
1140
|
-
raise_parse_error("expected object key, got: '%s'", state
|
1100
|
+
raise_parse_error("expected object key, got: '%s'", state);
|
1141
1101
|
}
|
1142
1102
|
json_parse_string(state, config, true);
|
1143
1103
|
|
1144
1104
|
json_eat_whitespace(state);
|
1145
1105
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1146
|
-
raise_parse_error("expected ':' after object key, got: '%s", state
|
1106
|
+
raise_parse_error("expected ':' after object key, got: '%s", state);
|
1147
1107
|
}
|
1148
1108
|
state->cursor++;
|
1149
1109
|
|
@@ -1153,24 +1113,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1153
1113
|
}
|
1154
1114
|
}
|
1155
1115
|
|
1156
|
-
raise_parse_error("expected ',' or '}' after object value, got: '%s'", state
|
1116
|
+
raise_parse_error("expected ',' or '}' after object value, got: '%s'", state);
|
1157
1117
|
}
|
1158
1118
|
break;
|
1159
1119
|
}
|
1160
1120
|
|
1161
1121
|
default:
|
1162
|
-
raise_parse_error("unexpected character: '%s'", state
|
1122
|
+
raise_parse_error("unexpected character: '%s'", state);
|
1163
1123
|
break;
|
1164
1124
|
}
|
1165
1125
|
|
1166
|
-
raise_parse_error("unreacheable: '%s'", state
|
1126
|
+
raise_parse_error("unreacheable: '%s'", state);
|
1167
1127
|
}
|
1168
1128
|
|
1169
1129
|
static void json_ensure_eof(JSON_ParserState *state)
|
1170
1130
|
{
|
1171
1131
|
json_eat_whitespace(state);
|
1172
1132
|
if (state->cursor != state->end) {
|
1173
|
-
raise_parse_error("unexpected token at end of stream '%s'", state
|
1133
|
+
raise_parse_error("unexpected token at end of stream '%s'", state);
|
1174
1134
|
}
|
1175
1135
|
}
|
1176
1136
|
|
@@ -1211,10 +1171,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1211
1171
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
1212
1172
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
1213
1173
|
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; }
|
1174
|
+
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
1218
1175
|
else if (key == sym_decimal_class) {
|
1219
1176
|
if (RTEST(val)) {
|
1220
1177
|
if (rb_respond_to(val, i_try_convert)) {
|
@@ -1244,15 +1201,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1244
1201
|
}
|
1245
1202
|
}
|
1246
1203
|
}
|
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
1204
|
|
1257
1205
|
return ST_CONTINUE;
|
1258
1206
|
}
|
@@ -1267,16 +1215,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1267
1215
|
// We assume in most cases few keys are set so it's faster to go over
|
1268
1216
|
// the provided keys than to check all possible keys.
|
1269
1217
|
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
1218
|
}
|
1281
1219
|
|
1282
1220
|
}
|
@@ -1301,15 +1239,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1301
1239
|
* (keys) in a JSON object. Otherwise strings are returned, which is
|
1302
1240
|
* also the default. It's not possible to use this option in
|
1303
1241
|
* 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
1242
|
* * *decimal_class*: Specifies which class to use instead of the default
|
1314
1243
|
* (Float) when parsing decimal numbers. This class must accept a single
|
1315
1244
|
* string argument in its constructor.
|
@@ -1320,11 +1249,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
1320
1249
|
|
1321
1250
|
parser_config_init(config, opts);
|
1322
1251
|
|
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
1252
|
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
1327
|
-
RB_OBJ_WRITTEN(self, Qundef, config->match_string);
|
1328
1253
|
|
1329
1254
|
return self;
|
1330
1255
|
}
|
@@ -1341,9 +1266,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
1341
1266
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1342
1267
|
};
|
1343
1268
|
|
1269
|
+
long len;
|
1270
|
+
const char *start;
|
1271
|
+
RSTRING_GETMEM(Vsource, start, len);
|
1272
|
+
|
1344
1273
|
JSON_ParserState _state = {
|
1345
|
-
.
|
1346
|
-
.
|
1274
|
+
.start = start,
|
1275
|
+
.cursor = start,
|
1276
|
+
.end = start + len,
|
1347
1277
|
.stack = &stack,
|
1348
1278
|
};
|
1349
1279
|
JSON_ParserState *state = &_state;
|
@@ -1387,11 +1317,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
1387
1317
|
static void JSON_ParserConfig_mark(void *ptr)
|
1388
1318
|
{
|
1389
1319
|
JSON_ParserConfig *config = ptr;
|
1390
|
-
rb_gc_mark(config->
|
1391
|
-
rb_gc_mark(config->object_class);
|
1392
|
-
rb_gc_mark(config->array_class);
|
1320
|
+
rb_gc_mark(config->on_load_proc);
|
1393
1321
|
rb_gc_mark(config->decimal_class);
|
1394
|
-
rb_gc_mark(config->match_string);
|
1395
1322
|
}
|
1396
1323
|
|
1397
1324
|
static void JSON_ParserConfig_free(void *ptr)
|
@@ -1459,19 +1386,10 @@ void Init_parser(void)
|
|
1459
1386
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
1460
1387
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
1461
1388
|
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"));
|
1389
|
+
sym_on_load = ID2SYM(rb_intern("on_load"));
|
1466
1390
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1467
|
-
sym_match_string = ID2SYM(rb_intern("match_string"));
|
1468
1391
|
|
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
1392
|
i_chr = rb_intern("chr");
|
1473
|
-
i_match = rb_intern("match");
|
1474
|
-
i_deep_const_get = rb_intern("deep_const_get");
|
1475
1393
|
i_aset = rb_intern("[]=");
|
1476
1394
|
i_aref = rb_intern("[]");
|
1477
1395
|
i_leftshift = rb_intern("<<");
|