json 2.10.2 → 2.13.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 +70 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +80 -15
- data/ext/json/ext/generator/extconf.rb +6 -0
- data/ext/json/ext/generator/generator.c +458 -118
- data/ext/json/ext/parser/extconf.rb +5 -2
- data/ext/json/ext/parser/parser.c +333 -267
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +188 -0
- data/ext/json/ext/vendor/fpconv.c +479 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +2 -3
- data/lib/json/common.rb +282 -164
- data/lib/json/ext.rb +2 -2
- data/lib/json/truffle_ruby/generator.rb +1 -1
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +33 -0
- metadata +6 -2
@@ -20,6 +20,8 @@ typedef unsigned char _Bool;
|
|
20
20
|
#endif
|
21
21
|
#endif
|
22
22
|
|
23
|
+
#include "../simd/simd.h"
|
24
|
+
|
23
25
|
#ifndef RB_UNLIKELY
|
24
26
|
#define RB_UNLIKELY(expr) expr
|
25
27
|
#endif
|
@@ -31,28 +33,15 @@ typedef unsigned char _Bool;
|
|
31
33
|
static VALUE mJSON, eNestingError, Encoding_UTF_8;
|
32
34
|
static VALUE CNaN, CInfinity, CMinusInfinity;
|
33
35
|
|
34
|
-
static ID
|
35
|
-
i_chr, i_deep_const_get, i_match, i_aset, i_aref,
|
36
|
+
static ID i_chr, i_aset, i_aref,
|
36
37
|
i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
|
37
38
|
|
38
39
|
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;
|
40
|
+
sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
|
41
41
|
|
42
42
|
static int binary_encindex;
|
43
43
|
static int utf8_encindex;
|
44
44
|
|
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
45
|
#ifndef HAVE_RB_HASH_BULK_INSERT
|
57
46
|
// For TruffleRuby
|
58
47
|
void
|
@@ -350,73 +339,6 @@ static size_t strnlen(const char *s, size_t maxlen)
|
|
350
339
|
}
|
351
340
|
#endif
|
352
341
|
|
353
|
-
#define PARSE_ERROR_FRAGMENT_LEN 32
|
354
|
-
#ifdef RBIMPL_ATTR_NORETURN
|
355
|
-
RBIMPL_ATTR_NORETURN()
|
356
|
-
#endif
|
357
|
-
static void raise_parse_error(const char *format, const char *start)
|
358
|
-
{
|
359
|
-
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
|
360
|
-
|
361
|
-
size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
|
362
|
-
const char *ptr = start;
|
363
|
-
|
364
|
-
if (len == PARSE_ERROR_FRAGMENT_LEN) {
|
365
|
-
MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
|
366
|
-
|
367
|
-
while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
|
368
|
-
len--;
|
369
|
-
}
|
370
|
-
|
371
|
-
if (buffer[len - 1] >= 0xC0) { // multibyte character start
|
372
|
-
len--;
|
373
|
-
}
|
374
|
-
|
375
|
-
buffer[len] = '\0';
|
376
|
-
ptr = (const char *)buffer;
|
377
|
-
}
|
378
|
-
|
379
|
-
rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
|
380
|
-
}
|
381
|
-
|
382
|
-
/* unicode */
|
383
|
-
|
384
|
-
static const signed char digit_values[256] = {
|
385
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
386
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
387
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
|
388
|
-
-1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
|
389
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
390
|
-
10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
391
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
392
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
393
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
394
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
395
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
396
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
397
|
-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
398
|
-
-1, -1, -1, -1, -1, -1, -1
|
399
|
-
};
|
400
|
-
|
401
|
-
static uint32_t unescape_unicode(const unsigned char *p)
|
402
|
-
{
|
403
|
-
signed char b;
|
404
|
-
uint32_t result = 0;
|
405
|
-
b = digit_values[p[0]];
|
406
|
-
if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
|
407
|
-
result = (result << 4) | (unsigned char)b;
|
408
|
-
b = digit_values[p[1]];
|
409
|
-
if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
|
410
|
-
result = (result << 4) | (unsigned char)b;
|
411
|
-
b = digit_values[p[2]];
|
412
|
-
if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
|
413
|
-
result = (result << 4) | (unsigned char)b;
|
414
|
-
b = digit_values[p[3]];
|
415
|
-
if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
|
416
|
-
result = (result << 4) | (unsigned char)b;
|
417
|
-
return result;
|
418
|
-
}
|
419
|
-
|
420
342
|
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
421
343
|
{
|
422
344
|
int len = 1;
|
@@ -443,25 +365,28 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
|
443
365
|
return len;
|
444
366
|
}
|
445
367
|
|
368
|
+
enum duplicate_key_action {
|
369
|
+
JSON_DEPRECATED = 0,
|
370
|
+
JSON_IGNORE,
|
371
|
+
JSON_RAISE,
|
372
|
+
};
|
373
|
+
|
446
374
|
typedef struct JSON_ParserStruct {
|
447
|
-
VALUE
|
448
|
-
VALUE object_class;
|
449
|
-
VALUE array_class;
|
375
|
+
VALUE on_load_proc;
|
450
376
|
VALUE decimal_class;
|
451
377
|
ID decimal_method_id;
|
452
|
-
|
378
|
+
enum duplicate_key_action on_duplicate_key;
|
453
379
|
int max_nesting;
|
454
380
|
bool allow_nan;
|
455
381
|
bool allow_trailing_comma;
|
456
382
|
bool parsing_name;
|
457
383
|
bool symbolize_names;
|
458
384
|
bool freeze;
|
459
|
-
bool create_additions;
|
460
|
-
bool deprecated_create_additions;
|
461
385
|
} JSON_ParserConfig;
|
462
386
|
|
463
387
|
typedef struct JSON_ParserStateStruct {
|
464
388
|
VALUE stack_handle;
|
389
|
+
const char *start;
|
465
390
|
const char *cursor;
|
466
391
|
const char *end;
|
467
392
|
rvalue_stack *stack;
|
@@ -470,6 +395,135 @@ typedef struct JSON_ParserStateStruct {
|
|
470
395
|
int current_nesting;
|
471
396
|
} JSON_ParserState;
|
472
397
|
|
398
|
+
static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
|
399
|
+
{
|
400
|
+
const char *cursor = state->cursor;
|
401
|
+
long column = 0;
|
402
|
+
long line = 1;
|
403
|
+
|
404
|
+
while (cursor >= state->start) {
|
405
|
+
if (*cursor-- == '\n') {
|
406
|
+
break;
|
407
|
+
}
|
408
|
+
column++;
|
409
|
+
}
|
410
|
+
|
411
|
+
while (cursor >= state->start) {
|
412
|
+
if (*cursor-- == '\n') {
|
413
|
+
line++;
|
414
|
+
}
|
415
|
+
}
|
416
|
+
*line_out = line;
|
417
|
+
*column_out = column;
|
418
|
+
}
|
419
|
+
|
420
|
+
static void emit_parse_warning(const char *message, JSON_ParserState *state)
|
421
|
+
{
|
422
|
+
long line, column;
|
423
|
+
cursor_position(state, &line, &column);
|
424
|
+
|
425
|
+
VALUE warning = rb_sprintf("%s at line %ld column %ld", message, line, column);
|
426
|
+
rb_funcall(mJSON, rb_intern("deprecation_warning"), 1, warning);
|
427
|
+
}
|
428
|
+
|
429
|
+
#define PARSE_ERROR_FRAGMENT_LEN 32
|
430
|
+
|
431
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
432
|
+
RBIMPL_ATTR_NORETURN()
|
433
|
+
#endif
|
434
|
+
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
435
|
+
{
|
436
|
+
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
437
|
+
long line, column;
|
438
|
+
cursor_position(state, &line, &column);
|
439
|
+
|
440
|
+
const char *ptr = "EOF";
|
441
|
+
if (state->cursor && state->cursor < state->end) {
|
442
|
+
ptr = state->cursor;
|
443
|
+
size_t len = 0;
|
444
|
+
while (len < PARSE_ERROR_FRAGMENT_LEN) {
|
445
|
+
char ch = ptr[len];
|
446
|
+
if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
|
447
|
+
break;
|
448
|
+
}
|
449
|
+
len++;
|
450
|
+
}
|
451
|
+
|
452
|
+
if (len) {
|
453
|
+
buffer[0] = '\'';
|
454
|
+
MEMCPY(buffer + 1, ptr, char, len);
|
455
|
+
|
456
|
+
while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
|
457
|
+
len--;
|
458
|
+
}
|
459
|
+
|
460
|
+
if (buffer[len] >= 0xC0) { // multibyte character start
|
461
|
+
len--;
|
462
|
+
}
|
463
|
+
|
464
|
+
buffer[len + 1] = '\'';
|
465
|
+
buffer[len + 2] = '\0';
|
466
|
+
ptr = (const char *)buffer;
|
467
|
+
}
|
468
|
+
}
|
469
|
+
|
470
|
+
VALUE msg = rb_sprintf(format, ptr);
|
471
|
+
VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
|
472
|
+
RB_GC_GUARD(msg);
|
473
|
+
|
474
|
+
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
475
|
+
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
476
|
+
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
477
|
+
rb_exc_raise(exc);
|
478
|
+
}
|
479
|
+
|
480
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
481
|
+
RBIMPL_ATTR_NORETURN()
|
482
|
+
#endif
|
483
|
+
static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
484
|
+
{
|
485
|
+
state->cursor = at;
|
486
|
+
raise_parse_error(format, state);
|
487
|
+
}
|
488
|
+
|
489
|
+
/* unicode */
|
490
|
+
|
491
|
+
static const signed char digit_values[256] = {
|
492
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
493
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
494
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
|
495
|
+
-1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
|
496
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
497
|
+
10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
498
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
499
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
500
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
501
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
502
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
503
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
504
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
505
|
+
-1, -1, -1, -1, -1, -1, -1
|
506
|
+
};
|
507
|
+
|
508
|
+
static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
|
509
|
+
{
|
510
|
+
signed char b;
|
511
|
+
uint32_t result = 0;
|
512
|
+
b = digit_values[p[0]];
|
513
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
514
|
+
result = (result << 4) | (unsigned char)b;
|
515
|
+
b = digit_values[p[1]];
|
516
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
517
|
+
result = (result << 4) | (unsigned char)b;
|
518
|
+
b = digit_values[p[2]];
|
519
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
520
|
+
result = (result << 4) | (unsigned char)b;
|
521
|
+
b = digit_values[p[3]];
|
522
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
523
|
+
result = (result << 4) | (unsigned char)b;
|
524
|
+
return result;
|
525
|
+
}
|
526
|
+
|
473
527
|
#define GET_PARSER_CONFIG \
|
474
528
|
JSON_ParserConfig *config; \
|
475
529
|
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
|
@@ -488,7 +542,7 @@ static void
|
|
488
542
|
json_eat_comments(JSON_ParserState *state)
|
489
543
|
{
|
490
544
|
if (state->cursor + 1 < state->end) {
|
491
|
-
switch(state->cursor[1]) {
|
545
|
+
switch (state->cursor[1]) {
|
492
546
|
case '/': {
|
493
547
|
state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
|
494
548
|
if (!state->cursor) {
|
@@ -503,8 +557,7 @@ json_eat_comments(JSON_ParserState *state)
|
|
503
557
|
while (true) {
|
504
558
|
state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
|
505
559
|
if (!state->cursor) {
|
506
|
-
|
507
|
-
raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
|
560
|
+
raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
|
508
561
|
} else {
|
509
562
|
state->cursor++;
|
510
563
|
if (state->cursor < state->end && *state->cursor == '/') {
|
@@ -516,11 +569,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
516
569
|
break;
|
517
570
|
}
|
518
571
|
default:
|
519
|
-
raise_parse_error("unexpected token
|
572
|
+
raise_parse_error("unexpected token %s", state);
|
520
573
|
break;
|
521
574
|
}
|
522
575
|
} else {
|
523
|
-
raise_parse_error("unexpected token
|
576
|
+
raise_parse_error("unexpected token %s", state);
|
524
577
|
}
|
525
578
|
}
|
526
579
|
|
@@ -639,9 +692,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
639
692
|
break;
|
640
693
|
case 'u':
|
641
694
|
if (pe > stringEnd - 5) {
|
642
|
-
|
695
|
+
raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
|
643
696
|
} else {
|
644
|
-
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
697
|
+
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
645
698
|
pe += 3;
|
646
699
|
/* To handle values above U+FFFF, we take a sequence of
|
647
700
|
* \uXXXX escapes in the U+D800..U+DBFF then
|
@@ -656,10 +709,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
656
709
|
if ((ch & 0xFC00) == 0xD800) {
|
657
710
|
pe++;
|
658
711
|
if (pe > stringEnd - 6) {
|
659
|
-
|
712
|
+
raise_parse_error_at("incomplete surrogate pair at %s", state, p);
|
660
713
|
}
|
661
714
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
662
|
-
uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
|
715
|
+
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
663
716
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
664
717
|
| (sur & 0x3FF));
|
665
718
|
pe += 5;
|
@@ -769,18 +822,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
|
|
769
822
|
|
770
823
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
771
824
|
{
|
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
|
-
|
825
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
784
826
|
rvalue_stack_pop(state->stack, count);
|
785
827
|
|
786
828
|
if (config->freeze) {
|
@@ -790,43 +832,70 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
790
832
|
return array;
|
791
833
|
}
|
792
834
|
|
793
|
-
static
|
835
|
+
static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
|
794
836
|
{
|
795
|
-
VALUE
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
837
|
+
VALUE set = rb_hash_new_capa(count / 2);
|
838
|
+
for (size_t index = 0; index < count; index += 2) {
|
839
|
+
size_t before = RHASH_SIZE(set);
|
840
|
+
VALUE key = pairs[index];
|
841
|
+
rb_hash_aset(set, key, Qtrue);
|
842
|
+
if (RHASH_SIZE(set) == before) {
|
843
|
+
if (RB_SYMBOL_P(key)) {
|
844
|
+
return rb_sym2str(key);
|
845
|
+
}
|
846
|
+
return key;
|
804
847
|
}
|
805
|
-
} else {
|
806
|
-
object = rb_hash_new_capa(count);
|
807
|
-
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
808
848
|
}
|
849
|
+
return Qfalse;
|
850
|
+
}
|
809
851
|
|
810
|
-
|
852
|
+
static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
853
|
+
{
|
854
|
+
VALUE message = rb_sprintf(
|
855
|
+
"detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
|
856
|
+
rb_inspect(duplicate_key)
|
857
|
+
);
|
811
858
|
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
859
|
+
emit_parse_warning(RSTRING_PTR(message), state);
|
860
|
+
RB_GC_GUARD(message);
|
861
|
+
}
|
862
|
+
|
863
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
864
|
+
RBIMPL_ATTR_NORETURN()
|
865
|
+
#endif
|
866
|
+
static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
867
|
+
{
|
868
|
+
VALUE message = rb_sprintf(
|
869
|
+
"duplicate key %"PRIsVALUE,
|
870
|
+
rb_inspect(duplicate_key)
|
871
|
+
);
|
872
|
+
|
873
|
+
raise_parse_error(RSTRING_PTR(message), state);
|
874
|
+
RB_GC_GUARD(message);
|
875
|
+
}
|
876
|
+
|
877
|
+
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
|
878
|
+
{
|
879
|
+
size_t entries_count = count / 2;
|
880
|
+
VALUE object = rb_hash_new_capa(entries_count);
|
881
|
+
const VALUE *pairs = rvalue_stack_peek(state->stack, count);
|
882
|
+
rb_hash_bulk_insert(count, pairs, object);
|
883
|
+
|
884
|
+
if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
|
885
|
+
switch (config->on_duplicate_key) {
|
886
|
+
case JSON_IGNORE:
|
887
|
+
break;
|
888
|
+
case JSON_DEPRECATED:
|
889
|
+
emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
|
890
|
+
break;
|
891
|
+
case JSON_RAISE:
|
892
|
+
raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
|
893
|
+
break;
|
827
894
|
}
|
828
895
|
}
|
829
896
|
|
897
|
+
rvalue_stack_pop(state->stack, count);
|
898
|
+
|
830
899
|
if (config->freeze) {
|
831
900
|
RB_OBJ_FREEZE(object);
|
832
901
|
}
|
@@ -834,17 +903,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
834
903
|
return object;
|
835
904
|
}
|
836
905
|
|
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
906
|
static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
|
849
907
|
{
|
850
908
|
VALUE string;
|
@@ -856,23 +914,19 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
|
|
856
914
|
string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
|
857
915
|
}
|
858
916
|
|
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
917
|
return string;
|
871
918
|
}
|
872
919
|
|
873
|
-
|
920
|
+
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
|
921
|
+
{
|
922
|
+
if (RB_UNLIKELY(config->on_load_proc)) {
|
923
|
+
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
924
|
+
}
|
925
|
+
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
|
926
|
+
return value;
|
927
|
+
}
|
874
928
|
|
875
|
-
static const bool
|
929
|
+
static const bool string_scan_table[256] = {
|
876
930
|
// ASCII Control Characters
|
877
931
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
878
932
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
@@ -885,38 +939,77 @@ static const bool string_scan[256] = {
|
|
885
939
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
886
940
|
};
|
887
941
|
|
942
|
+
#if (defined(__GNUC__ ) || defined(__clang__))
|
943
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
944
|
+
#else
|
945
|
+
#define FORCE_INLINE
|
946
|
+
#endif
|
947
|
+
|
948
|
+
#ifdef HAVE_SIMD
|
949
|
+
static SIMD_Implementation simd_impl = SIMD_NONE;
|
950
|
+
#endif /* HAVE_SIMD */
|
951
|
+
|
952
|
+
static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
|
953
|
+
{
|
954
|
+
#ifdef HAVE_SIMD
|
955
|
+
#if defined(HAVE_SIMD_NEON)
|
956
|
+
|
957
|
+
uint64_t mask = 0;
|
958
|
+
if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
|
959
|
+
state->cursor += trailing_zeros64(mask) >> 2;
|
960
|
+
return 1;
|
961
|
+
}
|
962
|
+
|
963
|
+
#elif defined(HAVE_SIMD_SSE2)
|
964
|
+
if (simd_impl == SIMD_SSE2) {
|
965
|
+
int mask = 0;
|
966
|
+
if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
|
967
|
+
state->cursor += trailing_zeros(mask);
|
968
|
+
return 1;
|
969
|
+
}
|
970
|
+
}
|
971
|
+
#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
|
972
|
+
#endif /* HAVE_SIMD */
|
973
|
+
|
974
|
+
while (state->cursor < state->end) {
|
975
|
+
if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
|
976
|
+
return 1;
|
977
|
+
}
|
978
|
+
*state->cursor++;
|
979
|
+
}
|
980
|
+
return 0;
|
981
|
+
}
|
982
|
+
|
888
983
|
static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
|
889
984
|
{
|
890
985
|
state->cursor++;
|
891
986
|
const char *start = state->cursor;
|
892
987
|
bool escaped = false;
|
893
988
|
|
894
|
-
while (state
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
|
907
|
-
}
|
908
|
-
break;
|
989
|
+
while (RB_UNLIKELY(string_scan(state))) {
|
990
|
+
switch (*state->cursor) {
|
991
|
+
case '"': {
|
992
|
+
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
993
|
+
state->cursor++;
|
994
|
+
return json_push_value(state, config, string);
|
995
|
+
}
|
996
|
+
case '\\': {
|
997
|
+
state->cursor++;
|
998
|
+
escaped = true;
|
999
|
+
if ((unsigned char)*state->cursor < 0x20) {
|
1000
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
909
1001
|
}
|
910
|
-
|
911
|
-
raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
|
912
|
-
break;
|
1002
|
+
break;
|
913
1003
|
}
|
1004
|
+
default:
|
1005
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
1006
|
+
break;
|
914
1007
|
}
|
915
1008
|
|
916
1009
|
state->cursor++;
|
917
1010
|
}
|
918
1011
|
|
919
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
1012
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
920
1013
|
return Qfalse;
|
921
1014
|
}
|
922
1015
|
|
@@ -924,60 +1017,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
924
1017
|
{
|
925
1018
|
json_eat_whitespace(state);
|
926
1019
|
if (state->cursor >= state->end) {
|
927
|
-
raise_parse_error("unexpected end of input", state
|
1020
|
+
raise_parse_error("unexpected end of input", state);
|
928
1021
|
}
|
929
1022
|
|
930
1023
|
switch (*state->cursor) {
|
931
1024
|
case 'n':
|
932
1025
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
|
933
1026
|
state->cursor += 4;
|
934
|
-
return
|
1027
|
+
return json_push_value(state, config, Qnil);
|
935
1028
|
}
|
936
1029
|
|
937
|
-
raise_parse_error("unexpected token
|
1030
|
+
raise_parse_error("unexpected token %s", state);
|
938
1031
|
break;
|
939
1032
|
case 't':
|
940
1033
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
941
1034
|
state->cursor += 4;
|
942
|
-
return
|
1035
|
+
return json_push_value(state, config, Qtrue);
|
943
1036
|
}
|
944
1037
|
|
945
|
-
raise_parse_error("unexpected token
|
1038
|
+
raise_parse_error("unexpected token %s", state);
|
946
1039
|
break;
|
947
1040
|
case 'f':
|
948
1041
|
// Note: memcmp with a small power of two compile to an integer comparison
|
949
1042
|
if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
|
950
1043
|
state->cursor += 5;
|
951
|
-
return
|
1044
|
+
return json_push_value(state, config, Qfalse);
|
952
1045
|
}
|
953
1046
|
|
954
|
-
raise_parse_error("unexpected token
|
1047
|
+
raise_parse_error("unexpected token %s", state);
|
955
1048
|
break;
|
956
1049
|
case 'N':
|
957
1050
|
// Note: memcmp with a small power of two compile to an integer comparison
|
958
1051
|
if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
|
959
1052
|
state->cursor += 3;
|
960
|
-
return
|
1053
|
+
return json_push_value(state, config, CNaN);
|
961
1054
|
}
|
962
1055
|
|
963
|
-
raise_parse_error("unexpected token
|
1056
|
+
raise_parse_error("unexpected token %s", state);
|
964
1057
|
break;
|
965
1058
|
case 'I':
|
966
1059
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
967
1060
|
state->cursor += 8;
|
968
|
-
return
|
1061
|
+
return json_push_value(state, config, CInfinity);
|
969
1062
|
}
|
970
1063
|
|
971
|
-
raise_parse_error("unexpected token
|
1064
|
+
raise_parse_error("unexpected token %s", state);
|
972
1065
|
break;
|
973
1066
|
case '-':
|
974
1067
|
// Note: memcmp with a small power of two compile to an integer comparison
|
975
1068
|
if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
|
976
1069
|
if (config->allow_nan) {
|
977
1070
|
state->cursor += 9;
|
978
|
-
return
|
1071
|
+
return json_push_value(state, config, CMinusInfinity);
|
979
1072
|
} else {
|
980
|
-
raise_parse_error("unexpected token
|
1073
|
+
raise_parse_error("unexpected token %s", state);
|
981
1074
|
}
|
982
1075
|
}
|
983
1076
|
// Fallthrough
|
@@ -995,11 +1088,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
995
1088
|
long integer_length = state->cursor - start;
|
996
1089
|
|
997
1090
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
998
|
-
|
1091
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
999
1092
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
1000
|
-
|
1093
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1001
1094
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
1002
|
-
|
1095
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
1003
1096
|
}
|
1004
1097
|
|
1005
1098
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
@@ -1007,7 +1100,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1007
1100
|
state->cursor++;
|
1008
1101
|
|
1009
1102
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1010
|
-
raise_parse_error("invalid number: %s", state
|
1103
|
+
raise_parse_error("invalid number: %s", state);
|
1011
1104
|
}
|
1012
1105
|
|
1013
1106
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1023,7 +1116,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1023
1116
|
}
|
1024
1117
|
|
1025
1118
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
1026
|
-
raise_parse_error("invalid number: %s", state
|
1119
|
+
raise_parse_error("invalid number: %s", state);
|
1027
1120
|
}
|
1028
1121
|
|
1029
1122
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1032,9 +1125,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1032
1125
|
}
|
1033
1126
|
|
1034
1127
|
if (integer) {
|
1035
|
-
return
|
1128
|
+
return json_push_value(state, config, json_decode_integer(start, state->cursor));
|
1036
1129
|
}
|
1037
|
-
return
|
1130
|
+
return json_push_value(state, config, json_decode_float(config, start, state->cursor));
|
1038
1131
|
}
|
1039
1132
|
case '"': {
|
1040
1133
|
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
|
@@ -1048,7 +1141,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1048
1141
|
|
1049
1142
|
if ((state->cursor < state->end) && (*state->cursor == ']')) {
|
1050
1143
|
state->cursor++;
|
1051
|
-
return
|
1144
|
+
return json_push_value(state, config, json_decode_array(state, config, 0));
|
1052
1145
|
} else {
|
1053
1146
|
state->current_nesting++;
|
1054
1147
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1067,7 +1160,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1067
1160
|
long count = state->stack->head - stack_head;
|
1068
1161
|
state->current_nesting--;
|
1069
1162
|
state->in_array--;
|
1070
|
-
return
|
1163
|
+
return json_push_value(state, config, json_decode_array(state, config, count));
|
1071
1164
|
}
|
1072
1165
|
|
1073
1166
|
if (*state->cursor == ',') {
|
@@ -1083,18 +1176,20 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1083
1176
|
}
|
1084
1177
|
}
|
1085
1178
|
|
1086
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
1179
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
1087
1180
|
}
|
1088
1181
|
break;
|
1089
1182
|
}
|
1090
1183
|
case '{': {
|
1184
|
+
const char *object_start_cursor = state->cursor;
|
1185
|
+
|
1091
1186
|
state->cursor++;
|
1092
1187
|
json_eat_whitespace(state);
|
1093
1188
|
long stack_head = state->stack->head;
|
1094
1189
|
|
1095
1190
|
if ((state->cursor < state->end) && (*state->cursor == '}')) {
|
1096
1191
|
state->cursor++;
|
1097
|
-
return
|
1192
|
+
return json_push_value(state, config, json_decode_object(state, config, 0));
|
1098
1193
|
} else {
|
1099
1194
|
state->current_nesting++;
|
1100
1195
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
@@ -1102,13 +1197,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1102
1197
|
}
|
1103
1198
|
|
1104
1199
|
if (*state->cursor != '"') {
|
1105
|
-
raise_parse_error("expected object key, got
|
1200
|
+
raise_parse_error("expected object key, got %s", state);
|
1106
1201
|
}
|
1107
1202
|
json_parse_string(state, config, true);
|
1108
1203
|
|
1109
1204
|
json_eat_whitespace(state);
|
1110
1205
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1111
|
-
raise_parse_error("expected ':' after object key", state
|
1206
|
+
raise_parse_error("expected ':' after object key", state);
|
1112
1207
|
}
|
1113
1208
|
state->cursor++;
|
1114
1209
|
|
@@ -1122,8 +1217,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1122
1217
|
if (*state->cursor == '}') {
|
1123
1218
|
state->cursor++;
|
1124
1219
|
state->current_nesting--;
|
1125
|
-
|
1126
|
-
|
1220
|
+
size_t count = state->stack->head - stack_head;
|
1221
|
+
|
1222
|
+
// Temporary rewind cursor in case an error is raised
|
1223
|
+
const char *final_cursor = state->cursor;
|
1224
|
+
state->cursor = object_start_cursor;
|
1225
|
+
VALUE object = json_decode_object(state, config, count);
|
1226
|
+
state->cursor = final_cursor;
|
1227
|
+
|
1228
|
+
return json_push_value(state, config, object);
|
1127
1229
|
}
|
1128
1230
|
|
1129
1231
|
if (*state->cursor == ',') {
|
@@ -1137,13 +1239,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1137
1239
|
}
|
1138
1240
|
|
1139
1241
|
if (*state->cursor != '"') {
|
1140
|
-
raise_parse_error("expected object key, got:
|
1242
|
+
raise_parse_error("expected object key, got: %s", state);
|
1141
1243
|
}
|
1142
1244
|
json_parse_string(state, config, true);
|
1143
1245
|
|
1144
1246
|
json_eat_whitespace(state);
|
1145
1247
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1146
|
-
raise_parse_error("expected ':' after object key, got:
|
1248
|
+
raise_parse_error("expected ':' after object key, got: %s", state);
|
1147
1249
|
}
|
1148
1250
|
state->cursor++;
|
1149
1251
|
|
@@ -1153,24 +1255,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1153
1255
|
}
|
1154
1256
|
}
|
1155
1257
|
|
1156
|
-
raise_parse_error("expected ',' or '}' after object value, got:
|
1258
|
+
raise_parse_error("expected ',' or '}' after object value, got: %s", state);
|
1157
1259
|
}
|
1158
1260
|
break;
|
1159
1261
|
}
|
1160
1262
|
|
1161
1263
|
default:
|
1162
|
-
raise_parse_error("unexpected character:
|
1264
|
+
raise_parse_error("unexpected character: %s", state);
|
1163
1265
|
break;
|
1164
1266
|
}
|
1165
1267
|
|
1166
|
-
raise_parse_error("unreacheable:
|
1268
|
+
raise_parse_error("unreacheable: %s", state);
|
1167
1269
|
}
|
1168
1270
|
|
1169
1271
|
static void json_ensure_eof(JSON_ParserState *state)
|
1170
1272
|
{
|
1171
1273
|
json_eat_whitespace(state);
|
1172
1274
|
if (state->cursor != state->end) {
|
1173
|
-
raise_parse_error("unexpected token at end of stream
|
1275
|
+
raise_parse_error("unexpected token at end of stream %s", state);
|
1174
1276
|
}
|
1175
1277
|
}
|
1176
1278
|
|
@@ -1211,10 +1313,8 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1211
1313
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
1212
1314
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
1213
1315
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
1214
|
-
else if (key ==
|
1215
|
-
else if (key ==
|
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; }
|
1316
|
+
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
1317
|
+
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
1218
1318
|
else if (key == sym_decimal_class) {
|
1219
1319
|
if (RTEST(val)) {
|
1220
1320
|
if (rb_respond_to(val, i_try_convert)) {
|
@@ -1244,15 +1344,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1244
1344
|
}
|
1245
1345
|
}
|
1246
1346
|
}
|
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
1347
|
|
1257
1348
|
return ST_CONTINUE;
|
1258
1349
|
}
|
@@ -1267,16 +1358,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1267
1358
|
// We assume in most cases few keys are set so it's faster to go over
|
1268
1359
|
// the provided keys than to check all possible keys.
|
1269
1360
|
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
1361
|
}
|
1281
1362
|
|
1282
1363
|
}
|
@@ -1301,15 +1382,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1301
1382
|
* (keys) in a JSON object. Otherwise strings are returned, which is
|
1302
1383
|
* also the default. It's not possible to use this option in
|
1303
1384
|
* 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
1385
|
* * *decimal_class*: Specifies which class to use instead of the default
|
1314
1386
|
* (Float) when parsing decimal numbers. This class must accept a single
|
1315
1387
|
* string argument in its constructor.
|
@@ -1320,11 +1392,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
1320
1392
|
|
1321
1393
|
parser_config_init(config, opts);
|
1322
1394
|
|
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
1395
|
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
1327
|
-
RB_OBJ_WRITTEN(self, Qundef, config->match_string);
|
1328
1396
|
|
1329
1397
|
return self;
|
1330
1398
|
}
|
@@ -1341,9 +1409,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
1341
1409
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1342
1410
|
};
|
1343
1411
|
|
1412
|
+
long len;
|
1413
|
+
const char *start;
|
1414
|
+
RSTRING_GETMEM(Vsource, start, len);
|
1415
|
+
|
1344
1416
|
JSON_ParserState _state = {
|
1345
|
-
.
|
1346
|
-
.
|
1417
|
+
.start = start,
|
1418
|
+
.cursor = start,
|
1419
|
+
.end = start + len,
|
1347
1420
|
.stack = &stack,
|
1348
1421
|
};
|
1349
1422
|
JSON_ParserState *state = &_state;
|
@@ -1387,11 +1460,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
1387
1460
|
static void JSON_ParserConfig_mark(void *ptr)
|
1388
1461
|
{
|
1389
1462
|
JSON_ParserConfig *config = ptr;
|
1390
|
-
rb_gc_mark(config->
|
1391
|
-
rb_gc_mark(config->object_class);
|
1392
|
-
rb_gc_mark(config->array_class);
|
1463
|
+
rb_gc_mark(config->on_load_proc);
|
1393
1464
|
rb_gc_mark(config->decimal_class);
|
1394
|
-
rb_gc_mark(config->match_string);
|
1395
1465
|
}
|
1396
1466
|
|
1397
1467
|
static void JSON_ParserConfig_free(void *ptr)
|
@@ -1459,19 +1529,11 @@ void Init_parser(void)
|
|
1459
1529
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
1460
1530
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
1461
1531
|
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"));
|
1532
|
+
sym_on_load = ID2SYM(rb_intern("on_load"));
|
1466
1533
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1467
|
-
|
1534
|
+
sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
|
1468
1535
|
|
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
1536
|
i_chr = rb_intern("chr");
|
1473
|
-
i_match = rb_intern("match");
|
1474
|
-
i_deep_const_get = rb_intern("deep_const_get");
|
1475
1537
|
i_aset = rb_intern("[]=");
|
1476
1538
|
i_aref = rb_intern("[]");
|
1477
1539
|
i_leftshift = rb_intern("<<");
|
@@ -1483,4 +1545,8 @@ void Init_parser(void)
|
|
1483
1545
|
binary_encindex = rb_ascii8bit_encindex();
|
1484
1546
|
utf8_encindex = rb_utf8_encindex();
|
1485
1547
|
enc_utf8 = rb_utf8_encoding();
|
1548
|
+
|
1549
|
+
#ifdef HAVE_SIMD
|
1550
|
+
simd_impl = find_simd_implementation();
|
1551
|
+
#endif
|
1486
1552
|
}
|