json 2.10.2 → 2.12.2
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 +56 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +80 -15
- data/ext/json/ext/generator/extconf.rb +30 -0
- data/ext/json/ext/generator/generator.c +466 -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 +180 -250
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/lib/json/common.rb +280 -163
- data/lib/json/ext.rb +2 -2
- 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,33 +337,128 @@ 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
|
-
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN +
|
396
|
+
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
360
397
|
|
361
|
-
|
362
|
-
|
398
|
+
const char *cursor = state->cursor;
|
399
|
+
long column = 0;
|
400
|
+
long line = 1;
|
363
401
|
|
364
|
-
|
365
|
-
|
402
|
+
while (cursor >= state->start) {
|
403
|
+
if (*cursor-- == '\n') {
|
404
|
+
break;
|
405
|
+
}
|
406
|
+
column++;
|
407
|
+
}
|
366
408
|
|
367
|
-
|
368
|
-
|
409
|
+
while (cursor >= state->start) {
|
410
|
+
if (*cursor-- == '\n') {
|
411
|
+
line++;
|
369
412
|
}
|
413
|
+
}
|
370
414
|
|
371
|
-
|
372
|
-
|
415
|
+
const char *ptr = "EOF";
|
416
|
+
if (state->cursor && state->cursor < state->end) {
|
417
|
+
ptr = state->cursor;
|
418
|
+
size_t len = 0;
|
419
|
+
while (len < PARSE_ERROR_FRAGMENT_LEN) {
|
420
|
+
char ch = ptr[len];
|
421
|
+
if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
|
422
|
+
break;
|
423
|
+
}
|
424
|
+
len++;
|
373
425
|
}
|
374
426
|
|
375
|
-
|
376
|
-
|
427
|
+
if (len) {
|
428
|
+
buffer[0] = '\'';
|
429
|
+
MEMCPY(buffer + 1, ptr, char, len);
|
430
|
+
|
431
|
+
while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
|
432
|
+
len--;
|
433
|
+
}
|
434
|
+
|
435
|
+
if (buffer[len] >= 0xC0) { // multibyte character start
|
436
|
+
len--;
|
437
|
+
}
|
438
|
+
|
439
|
+
buffer[len + 1] = '\'';
|
440
|
+
buffer[len + 2] = '\0';
|
441
|
+
ptr = (const char *)buffer;
|
442
|
+
}
|
377
443
|
}
|
378
444
|
|
379
|
-
|
445
|
+
VALUE msg = rb_sprintf(format, ptr);
|
446
|
+
VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
|
447
|
+
RB_GC_GUARD(msg);
|
448
|
+
|
449
|
+
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
450
|
+
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
451
|
+
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
452
|
+
rb_exc_raise(exc);
|
453
|
+
}
|
454
|
+
|
455
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
456
|
+
RBIMPL_ATTR_NORETURN()
|
457
|
+
#endif
|
458
|
+
static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
459
|
+
{
|
460
|
+
state->cursor = at;
|
461
|
+
raise_parse_error(format, state);
|
380
462
|
}
|
381
463
|
|
382
464
|
/* unicode */
|
@@ -398,78 +480,25 @@ static const signed char digit_values[256] = {
|
|
398
480
|
-1, -1, -1, -1, -1, -1, -1
|
399
481
|
};
|
400
482
|
|
401
|
-
static uint32_t unescape_unicode(const unsigned char *p)
|
483
|
+
static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
|
402
484
|
{
|
403
485
|
signed char b;
|
404
486
|
uint32_t result = 0;
|
405
487
|
b = digit_values[p[0]];
|
406
|
-
if (b < 0)
|
488
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
407
489
|
result = (result << 4) | (unsigned char)b;
|
408
490
|
b = digit_values[p[1]];
|
409
|
-
if (b < 0)
|
491
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
410
492
|
result = (result << 4) | (unsigned char)b;
|
411
493
|
b = digit_values[p[2]];
|
412
|
-
if (b < 0)
|
494
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
413
495
|
result = (result << 4) | (unsigned char)b;
|
414
496
|
b = digit_values[p[3]];
|
415
|
-
if (b < 0)
|
497
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
416
498
|
result = (result << 4) | (unsigned char)b;
|
417
499
|
return result;
|
418
500
|
}
|
419
501
|
|
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
502
|
#define GET_PARSER_CONFIG \
|
474
503
|
JSON_ParserConfig *config; \
|
475
504
|
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
|
@@ -503,8 +532,7 @@ json_eat_comments(JSON_ParserState *state)
|
|
503
532
|
while (true) {
|
504
533
|
state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
|
505
534
|
if (!state->cursor) {
|
506
|
-
|
507
|
-
raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
|
535
|
+
raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
|
508
536
|
} else {
|
509
537
|
state->cursor++;
|
510
538
|
if (state->cursor < state->end && *state->cursor == '/') {
|
@@ -516,11 +544,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
516
544
|
break;
|
517
545
|
}
|
518
546
|
default:
|
519
|
-
raise_parse_error("unexpected token
|
547
|
+
raise_parse_error("unexpected token %s", state);
|
520
548
|
break;
|
521
549
|
}
|
522
550
|
} else {
|
523
|
-
raise_parse_error("unexpected token
|
551
|
+
raise_parse_error("unexpected token %s", state);
|
524
552
|
}
|
525
553
|
}
|
526
554
|
|
@@ -639,9 +667,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
639
667
|
break;
|
640
668
|
case 'u':
|
641
669
|
if (pe > stringEnd - 5) {
|
642
|
-
|
670
|
+
raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
|
643
671
|
} else {
|
644
|
-
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
672
|
+
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
645
673
|
pe += 3;
|
646
674
|
/* To handle values above U+FFFF, we take a sequence of
|
647
675
|
* \uXXXX escapes in the U+D800..U+DBFF then
|
@@ -656,10 +684,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
656
684
|
if ((ch & 0xFC00) == 0xD800) {
|
657
685
|
pe++;
|
658
686
|
if (pe > stringEnd - 6) {
|
659
|
-
|
687
|
+
raise_parse_error_at("incomplete surrogate pair at %s", state, p);
|
660
688
|
}
|
661
689
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
662
|
-
uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
|
690
|
+
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
663
691
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
664
692
|
| (sur & 0x3FF));
|
665
693
|
pe += 5;
|
@@ -769,18 +797,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
|
|
769
797
|
|
770
798
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
771
799
|
{
|
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
|
-
|
800
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
784
801
|
rvalue_stack_pop(state->stack, count);
|
785
802
|
|
786
803
|
if (config->freeze) {
|
@@ -792,41 +809,11 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
792
809
|
|
793
810
|
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
794
811
|
{
|
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
|
-
}
|
812
|
+
VALUE object = rb_hash_new_capa(count);
|
813
|
+
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
809
814
|
|
810
815
|
rvalue_stack_pop(state->stack, count);
|
811
816
|
|
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
817
|
if (config->freeze) {
|
831
818
|
RB_OBJ_FREEZE(object);
|
832
819
|
}
|
@@ -834,17 +821,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
834
821
|
return object;
|
835
822
|
}
|
836
823
|
|
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
824
|
static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
|
849
825
|
{
|
850
826
|
VALUE string;
|
@@ -856,21 +832,17 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
|
|
856
832
|
string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
|
857
833
|
}
|
858
834
|
|
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
835
|
return string;
|
871
836
|
}
|
872
837
|
|
873
|
-
|
838
|
+
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
|
839
|
+
{
|
840
|
+
if (RB_UNLIKELY(config->on_load_proc)) {
|
841
|
+
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
842
|
+
}
|
843
|
+
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
|
844
|
+
return value;
|
845
|
+
}
|
874
846
|
|
875
847
|
static const bool string_scan[256] = {
|
876
848
|
// ASCII Control Characters
|
@@ -897,18 +869,18 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
897
869
|
case '"': {
|
898
870
|
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
899
871
|
state->cursor++;
|
900
|
-
return
|
872
|
+
return json_push_value(state, config, string);
|
901
873
|
}
|
902
874
|
case '\\': {
|
903
875
|
state->cursor++;
|
904
876
|
escaped = true;
|
905
877
|
if ((unsigned char)*state->cursor < 0x20) {
|
906
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
878
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
907
879
|
}
|
908
880
|
break;
|
909
881
|
}
|
910
882
|
default:
|
911
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
883
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
912
884
|
break;
|
913
885
|
}
|
914
886
|
}
|
@@ -916,7 +888,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
916
888
|
state->cursor++;
|
917
889
|
}
|
918
890
|
|
919
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
891
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
920
892
|
return Qfalse;
|
921
893
|
}
|
922
894
|
|
@@ -924,60 +896,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
924
896
|
{
|
925
897
|
json_eat_whitespace(state);
|
926
898
|
if (state->cursor >= state->end) {
|
927
|
-
raise_parse_error("unexpected end of input", state
|
899
|
+
raise_parse_error("unexpected end of input", state);
|
928
900
|
}
|
929
901
|
|
930
902
|
switch (*state->cursor) {
|
931
903
|
case 'n':
|
932
904
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
|
933
905
|
state->cursor += 4;
|
934
|
-
return
|
906
|
+
return json_push_value(state, config, Qnil);
|
935
907
|
}
|
936
908
|
|
937
|
-
raise_parse_error("unexpected token
|
909
|
+
raise_parse_error("unexpected token %s", state);
|
938
910
|
break;
|
939
911
|
case 't':
|
940
912
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
941
913
|
state->cursor += 4;
|
942
|
-
return
|
914
|
+
return json_push_value(state, config, Qtrue);
|
943
915
|
}
|
944
916
|
|
945
|
-
raise_parse_error("unexpected token
|
917
|
+
raise_parse_error("unexpected token %s", state);
|
946
918
|
break;
|
947
919
|
case 'f':
|
948
920
|
// Note: memcmp with a small power of two compile to an integer comparison
|
949
921
|
if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
|
950
922
|
state->cursor += 5;
|
951
|
-
return
|
923
|
+
return json_push_value(state, config, Qfalse);
|
952
924
|
}
|
953
925
|
|
954
|
-
raise_parse_error("unexpected token
|
926
|
+
raise_parse_error("unexpected token %s", state);
|
955
927
|
break;
|
956
928
|
case 'N':
|
957
929
|
// Note: memcmp with a small power of two compile to an integer comparison
|
958
930
|
if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
|
959
931
|
state->cursor += 3;
|
960
|
-
return
|
932
|
+
return json_push_value(state, config, CNaN);
|
961
933
|
}
|
962
934
|
|
963
|
-
raise_parse_error("unexpected token
|
935
|
+
raise_parse_error("unexpected token %s", state);
|
964
936
|
break;
|
965
937
|
case 'I':
|
966
938
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
967
939
|
state->cursor += 8;
|
968
|
-
return
|
940
|
+
return json_push_value(state, config, CInfinity);
|
969
941
|
}
|
970
942
|
|
971
|
-
raise_parse_error("unexpected token
|
943
|
+
raise_parse_error("unexpected token %s", state);
|
972
944
|
break;
|
973
945
|
case '-':
|
974
946
|
// Note: memcmp with a small power of two compile to an integer comparison
|
975
947
|
if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
|
976
948
|
if (config->allow_nan) {
|
977
949
|
state->cursor += 9;
|
978
|
-
return
|
950
|
+
return json_push_value(state, config, CMinusInfinity);
|
979
951
|
} else {
|
980
|
-
raise_parse_error("unexpected token
|
952
|
+
raise_parse_error("unexpected token %s", state);
|
981
953
|
}
|
982
954
|
}
|
983
955
|
// Fallthrough
|
@@ -995,11 +967,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
995
967
|
long integer_length = state->cursor - start;
|
996
968
|
|
997
969
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
998
|
-
|
970
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
999
971
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
1000
|
-
|
972
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1001
973
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
1002
|
-
|
974
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1003
975
|
}
|
1004
976
|
|
1005
977
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
@@ -1007,7 +979,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1007
979
|
state->cursor++;
|
1008
980
|
|
1009
981
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1010
|
-
raise_parse_error("invalid number: %s", state
|
982
|
+
raise_parse_error("invalid number: %s", state);
|
1011
983
|
}
|
1012
984
|
|
1013
985
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1023,7 +995,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1023
995
|
}
|
1024
996
|
|
1025
997
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1026
|
-
raise_parse_error("invalid number: %s", state
|
998
|
+
raise_parse_error("invalid number: %s", state);
|
1027
999
|
}
|
1028
1000
|
|
1029
1001
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1032,9 +1004,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1032
1004
|
}
|
1033
1005
|
|
1034
1006
|
if (integer) {
|
1035
|
-
return
|
1007
|
+
return json_push_value(state, config, json_decode_integer(start, state->cursor));
|
1036
1008
|
}
|
1037
|
-
return
|
1009
|
+
return json_push_value(state, config, json_decode_float(config, start, state->cursor));
|
1038
1010
|
}
|
1039
1011
|
case '"': {
|
1040
1012
|
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
|
@@ -1048,7 +1020,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1048
1020
|
|
1049
1021
|
if ((state->cursor < state->end) && (*state->cursor == ']')) {
|
1050
1022
|
state->cursor++;
|
1051
|
-
return
|
1023
|
+
return json_push_value(state, config, json_decode_array(state, config, 0));
|
1052
1024
|
} else {
|
1053
1025
|
state->current_nesting++;
|
1054
1026
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1067,7 +1039,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1067
1039
|
long count = state->stack->head - stack_head;
|
1068
1040
|
state->current_nesting--;
|
1069
1041
|
state->in_array--;
|
1070
|
-
return
|
1042
|
+
return json_push_value(state, config, json_decode_array(state, config, count));
|
1071
1043
|
}
|
1072
1044
|
|
1073
1045
|
if (*state->cursor == ',') {
|
@@ -1083,7 +1055,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1083
1055
|
}
|
1084
1056
|
}
|
1085
1057
|
|
1086
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
1058
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
1087
1059
|
}
|
1088
1060
|
break;
|
1089
1061
|
}
|
@@ -1094,7 +1066,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1094
1066
|
|
1095
1067
|
if ((state->cursor < state->end) && (*state->cursor == '}')) {
|
1096
1068
|
state->cursor++;
|
1097
|
-
return
|
1069
|
+
return json_push_value(state, config, json_decode_object(state, config, 0));
|
1098
1070
|
} else {
|
1099
1071
|
state->current_nesting++;
|
1100
1072
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1102,13 +1074,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1102
1074
|
}
|
1103
1075
|
|
1104
1076
|
if (*state->cursor != '"') {
|
1105
|
-
raise_parse_error("expected object key, got
|
1077
|
+
raise_parse_error("expected object key, got %s", state);
|
1106
1078
|
}
|
1107
1079
|
json_parse_string(state, config, true);
|
1108
1080
|
|
1109
1081
|
json_eat_whitespace(state);
|
1110
1082
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1111
|
-
raise_parse_error("expected ':' after object key", state
|
1083
|
+
raise_parse_error("expected ':' after object key", state);
|
1112
1084
|
}
|
1113
1085
|
state->cursor++;
|
1114
1086
|
|
@@ -1123,7 +1095,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1123
1095
|
state->cursor++;
|
1124
1096
|
state->current_nesting--;
|
1125
1097
|
long count = state->stack->head - stack_head;
|
1126
|
-
return
|
1098
|
+
return json_push_value(state, config, json_decode_object(state, config, count));
|
1127
1099
|
}
|
1128
1100
|
|
1129
1101
|
if (*state->cursor == ',') {
|
@@ -1137,13 +1109,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1137
1109
|
}
|
1138
1110
|
|
1139
1111
|
if (*state->cursor != '"') {
|
1140
|
-
raise_parse_error("expected object key, got:
|
1112
|
+
raise_parse_error("expected object key, got: %s", state);
|
1141
1113
|
}
|
1142
1114
|
json_parse_string(state, config, true);
|
1143
1115
|
|
1144
1116
|
json_eat_whitespace(state);
|
1145
1117
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1146
|
-
raise_parse_error("expected ':' after object key, got:
|
1118
|
+
raise_parse_error("expected ':' after object key, got: %s", state);
|
1147
1119
|
}
|
1148
1120
|
state->cursor++;
|
1149
1121
|
|
@@ -1153,24 +1125,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1153
1125
|
}
|
1154
1126
|
}
|
1155
1127
|
|
1156
|
-
raise_parse_error("expected ',' or '}' after object value, got:
|
1128
|
+
raise_parse_error("expected ',' or '}' after object value, got: %s", state);
|
1157
1129
|
}
|
1158
1130
|
break;
|
1159
1131
|
}
|
1160
1132
|
|
1161
1133
|
default:
|
1162
|
-
raise_parse_error("unexpected character:
|
1134
|
+
raise_parse_error("unexpected character: %s", state);
|
1163
1135
|
break;
|
1164
1136
|
}
|
1165
1137
|
|
1166
|
-
raise_parse_error("unreacheable:
|
1138
|
+
raise_parse_error("unreacheable: %s", state);
|
1167
1139
|
}
|
1168
1140
|
|
1169
1141
|
static void json_ensure_eof(JSON_ParserState *state)
|
1170
1142
|
{
|
1171
1143
|
json_eat_whitespace(state);
|
1172
1144
|
if (state->cursor != state->end) {
|
1173
|
-
raise_parse_error("unexpected token at end of stream
|
1145
|
+
raise_parse_error("unexpected token at end of stream %s", state);
|
1174
1146
|
}
|
1175
1147
|
}
|
1176
1148
|
|
@@ -1211,10 +1183,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1211
1183
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
1212
1184
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
1213
1185
|
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; }
|
1186
|
+
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
1218
1187
|
else if (key == sym_decimal_class) {
|
1219
1188
|
if (RTEST(val)) {
|
1220
1189
|
if (rb_respond_to(val, i_try_convert)) {
|
@@ -1244,15 +1213,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1244
1213
|
}
|
1245
1214
|
}
|
1246
1215
|
}
|
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
1216
|
|
1257
1217
|
return ST_CONTINUE;
|
1258
1218
|
}
|
@@ -1267,16 +1227,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1267
1227
|
// We assume in most cases few keys are set so it's faster to go over
|
1268
1228
|
// the provided keys than to check all possible keys.
|
1269
1229
|
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
1230
|
}
|
1281
1231
|
|
1282
1232
|
}
|
@@ -1301,15 +1251,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1301
1251
|
* (keys) in a JSON object. Otherwise strings are returned, which is
|
1302
1252
|
* also the default. It's not possible to use this option in
|
1303
1253
|
* 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
1254
|
* * *decimal_class*: Specifies which class to use instead of the default
|
1314
1255
|
* (Float) when parsing decimal numbers. This class must accept a single
|
1315
1256
|
* string argument in its constructor.
|
@@ -1320,11 +1261,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
1320
1261
|
|
1321
1262
|
parser_config_init(config, opts);
|
1322
1263
|
|
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
1264
|
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
1327
|
-
RB_OBJ_WRITTEN(self, Qundef, config->match_string);
|
1328
1265
|
|
1329
1266
|
return self;
|
1330
1267
|
}
|
@@ -1341,9 +1278,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
1341
1278
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1342
1279
|
};
|
1343
1280
|
|
1281
|
+
long len;
|
1282
|
+
const char *start;
|
1283
|
+
RSTRING_GETMEM(Vsource, start, len);
|
1284
|
+
|
1344
1285
|
JSON_ParserState _state = {
|
1345
|
-
.
|
1346
|
-
.
|
1286
|
+
.start = start,
|
1287
|
+
.cursor = start,
|
1288
|
+
.end = start + len,
|
1347
1289
|
.stack = &stack,
|
1348
1290
|
};
|
1349
1291
|
JSON_ParserState *state = &_state;
|
@@ -1387,11 +1329,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
1387
1329
|
static void JSON_ParserConfig_mark(void *ptr)
|
1388
1330
|
{
|
1389
1331
|
JSON_ParserConfig *config = ptr;
|
1390
|
-
rb_gc_mark(config->
|
1391
|
-
rb_gc_mark(config->object_class);
|
1392
|
-
rb_gc_mark(config->array_class);
|
1332
|
+
rb_gc_mark(config->on_load_proc);
|
1393
1333
|
rb_gc_mark(config->decimal_class);
|
1394
|
-
rb_gc_mark(config->match_string);
|
1395
1334
|
}
|
1396
1335
|
|
1397
1336
|
static void JSON_ParserConfig_free(void *ptr)
|
@@ -1459,19 +1398,10 @@ void Init_parser(void)
|
|
1459
1398
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
1460
1399
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
1461
1400
|
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"));
|
1401
|
+
sym_on_load = ID2SYM(rb_intern("on_load"));
|
1466
1402
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1467
|
-
sym_match_string = ID2SYM(rb_intern("match_string"));
|
1468
1403
|
|
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
1404
|
i_chr = rb_intern("chr");
|
1473
|
-
i_match = rb_intern("match");
|
1474
|
-
i_deep_const_get = rb_intern("deep_const_get");
|
1475
1405
|
i_aset = rb_intern("[]=");
|
1476
1406
|
i_aref = rb_intern("[]");
|
1477
1407
|
i_leftshift = rb_intern("<<");
|