json 2.10.2 → 2.15.1
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 +110 -7
- data/README.md +16 -1
- data/ext/json/ext/fbuffer/fbuffer.h +110 -19
- data/ext/json/ext/generator/extconf.rb +6 -0
- data/ext/json/ext/generator/generator.c +543 -196
- data/ext/json/ext/parser/extconf.rb +5 -2
- data/ext/json/ext/parser/parser.c +339 -268
- 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 +480 -0
- data/ext/json/ext/vendor/jeaiii-ltoa.h +267 -0
- data/json.gemspec +2 -3
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/string.rb +35 -0
- data/lib/json/common.rb +312 -169
- data/lib/json/ext/generator/state.rb +7 -14
- data/lib/json/ext.rb +2 -2
- data/lib/json/generic_object.rb +0 -8
- data/lib/json/truffle_ruby/generator.rb +64 -46
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +55 -0
- metadata +8 -3
|
@@ -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,15 +709,20 @@ 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);
|
|
716
|
+
|
|
717
|
+
if ((sur & 0xFC00) != 0xDC00) {
|
|
718
|
+
raise_parse_error_at("invalid surrogate pair at %s", state, p);
|
|
719
|
+
}
|
|
720
|
+
|
|
663
721
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
|
664
722
|
| (sur & 0x3FF));
|
|
665
723
|
pe += 5;
|
|
666
724
|
} else {
|
|
667
|
-
|
|
725
|
+
raise_parse_error_at("incomplete surrogate pair at %s", state, p);
|
|
668
726
|
break;
|
|
669
727
|
}
|
|
670
728
|
}
|
|
@@ -769,18 +827,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
|
|
|
769
827
|
|
|
770
828
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
|
771
829
|
{
|
|
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
|
-
|
|
830
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
|
|
784
831
|
rvalue_stack_pop(state->stack, count);
|
|
785
832
|
|
|
786
833
|
if (config->freeze) {
|
|
@@ -790,43 +837,70 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
|
790
837
|
return array;
|
|
791
838
|
}
|
|
792
839
|
|
|
793
|
-
static
|
|
840
|
+
static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
|
|
794
841
|
{
|
|
795
|
-
VALUE
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
842
|
+
VALUE set = rb_hash_new_capa(count / 2);
|
|
843
|
+
for (size_t index = 0; index < count; index += 2) {
|
|
844
|
+
size_t before = RHASH_SIZE(set);
|
|
845
|
+
VALUE key = pairs[index];
|
|
846
|
+
rb_hash_aset(set, key, Qtrue);
|
|
847
|
+
if (RHASH_SIZE(set) == before) {
|
|
848
|
+
if (RB_SYMBOL_P(key)) {
|
|
849
|
+
return rb_sym2str(key);
|
|
850
|
+
}
|
|
851
|
+
return key;
|
|
804
852
|
}
|
|
805
|
-
} else {
|
|
806
|
-
object = rb_hash_new_capa(count);
|
|
807
|
-
rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
|
|
808
853
|
}
|
|
854
|
+
return Qfalse;
|
|
855
|
+
}
|
|
809
856
|
|
|
810
|
-
|
|
857
|
+
static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
|
858
|
+
{
|
|
859
|
+
VALUE message = rb_sprintf(
|
|
860
|
+
"detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
|
|
861
|
+
rb_inspect(duplicate_key)
|
|
862
|
+
);
|
|
811
863
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
864
|
+
emit_parse_warning(RSTRING_PTR(message), state);
|
|
865
|
+
RB_GC_GUARD(message);
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
|
869
|
+
RBIMPL_ATTR_NORETURN()
|
|
870
|
+
#endif
|
|
871
|
+
static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
|
872
|
+
{
|
|
873
|
+
VALUE message = rb_sprintf(
|
|
874
|
+
"duplicate key %"PRIsVALUE,
|
|
875
|
+
rb_inspect(duplicate_key)
|
|
876
|
+
);
|
|
877
|
+
|
|
878
|
+
raise_parse_error(RSTRING_PTR(message), state);
|
|
879
|
+
RB_GC_GUARD(message);
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
|
|
883
|
+
{
|
|
884
|
+
size_t entries_count = count / 2;
|
|
885
|
+
VALUE object = rb_hash_new_capa(entries_count);
|
|
886
|
+
const VALUE *pairs = rvalue_stack_peek(state->stack, count);
|
|
887
|
+
rb_hash_bulk_insert(count, pairs, object);
|
|
888
|
+
|
|
889
|
+
if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
|
|
890
|
+
switch (config->on_duplicate_key) {
|
|
891
|
+
case JSON_IGNORE:
|
|
892
|
+
break;
|
|
893
|
+
case JSON_DEPRECATED:
|
|
894
|
+
emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
|
|
895
|
+
break;
|
|
896
|
+
case JSON_RAISE:
|
|
897
|
+
raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
|
|
898
|
+
break;
|
|
827
899
|
}
|
|
828
900
|
}
|
|
829
901
|
|
|
902
|
+
rvalue_stack_pop(state->stack, count);
|
|
903
|
+
|
|
830
904
|
if (config->freeze) {
|
|
831
905
|
RB_OBJ_FREEZE(object);
|
|
832
906
|
}
|
|
@@ -834,17 +908,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
|
834
908
|
return object;
|
|
835
909
|
}
|
|
836
910
|
|
|
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
911
|
static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
|
|
849
912
|
{
|
|
850
913
|
VALUE string;
|
|
@@ -856,23 +919,19 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
|
|
|
856
919
|
string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
|
|
857
920
|
}
|
|
858
921
|
|
|
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
922
|
return string;
|
|
871
923
|
}
|
|
872
924
|
|
|
873
|
-
|
|
925
|
+
static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
|
|
926
|
+
{
|
|
927
|
+
if (RB_UNLIKELY(config->on_load_proc)) {
|
|
928
|
+
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
|
929
|
+
}
|
|
930
|
+
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
|
|
931
|
+
return value;
|
|
932
|
+
}
|
|
874
933
|
|
|
875
|
-
static const bool
|
|
934
|
+
static const bool string_scan_table[256] = {
|
|
876
935
|
// ASCII Control Characters
|
|
877
936
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
878
937
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
@@ -885,38 +944,77 @@ static const bool string_scan[256] = {
|
|
|
885
944
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
886
945
|
};
|
|
887
946
|
|
|
947
|
+
#if (defined(__GNUC__ ) || defined(__clang__))
|
|
948
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
|
949
|
+
#else
|
|
950
|
+
#define FORCE_INLINE
|
|
951
|
+
#endif
|
|
952
|
+
|
|
953
|
+
#ifdef HAVE_SIMD
|
|
954
|
+
static SIMD_Implementation simd_impl = SIMD_NONE;
|
|
955
|
+
#endif /* HAVE_SIMD */
|
|
956
|
+
|
|
957
|
+
static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
|
|
958
|
+
{
|
|
959
|
+
#ifdef HAVE_SIMD
|
|
960
|
+
#if defined(HAVE_SIMD_NEON)
|
|
961
|
+
|
|
962
|
+
uint64_t mask = 0;
|
|
963
|
+
if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
|
|
964
|
+
state->cursor += trailing_zeros64(mask) >> 2;
|
|
965
|
+
return 1;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
#elif defined(HAVE_SIMD_SSE2)
|
|
969
|
+
if (simd_impl == SIMD_SSE2) {
|
|
970
|
+
int mask = 0;
|
|
971
|
+
if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
|
|
972
|
+
state->cursor += trailing_zeros(mask);
|
|
973
|
+
return 1;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
|
|
977
|
+
#endif /* HAVE_SIMD */
|
|
978
|
+
|
|
979
|
+
while (state->cursor < state->end) {
|
|
980
|
+
if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
|
|
981
|
+
return 1;
|
|
982
|
+
}
|
|
983
|
+
state->cursor++;
|
|
984
|
+
}
|
|
985
|
+
return 0;
|
|
986
|
+
}
|
|
987
|
+
|
|
888
988
|
static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
|
|
889
989
|
{
|
|
890
990
|
state->cursor++;
|
|
891
991
|
const char *start = state->cursor;
|
|
892
992
|
bool escaped = false;
|
|
893
993
|
|
|
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;
|
|
994
|
+
while (RB_UNLIKELY(string_scan(state))) {
|
|
995
|
+
switch (*state->cursor) {
|
|
996
|
+
case '"': {
|
|
997
|
+
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
|
998
|
+
state->cursor++;
|
|
999
|
+
return json_push_value(state, config, string);
|
|
1000
|
+
}
|
|
1001
|
+
case '\\': {
|
|
1002
|
+
state->cursor++;
|
|
1003
|
+
escaped = true;
|
|
1004
|
+
if ((unsigned char)*state->cursor < 0x20) {
|
|
1005
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
|
909
1006
|
}
|
|
910
|
-
|
|
911
|
-
raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
|
|
912
|
-
break;
|
|
1007
|
+
break;
|
|
913
1008
|
}
|
|
1009
|
+
default:
|
|
1010
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
|
1011
|
+
break;
|
|
914
1012
|
}
|
|
915
1013
|
|
|
916
1014
|
state->cursor++;
|
|
917
1015
|
}
|
|
918
1016
|
|
|
919
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
|
1017
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
|
920
1018
|
return Qfalse;
|
|
921
1019
|
}
|
|
922
1020
|
|
|
@@ -924,60 +1022,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
924
1022
|
{
|
|
925
1023
|
json_eat_whitespace(state);
|
|
926
1024
|
if (state->cursor >= state->end) {
|
|
927
|
-
raise_parse_error("unexpected end of input", state
|
|
1025
|
+
raise_parse_error("unexpected end of input", state);
|
|
928
1026
|
}
|
|
929
1027
|
|
|
930
1028
|
switch (*state->cursor) {
|
|
931
1029
|
case 'n':
|
|
932
1030
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
|
|
933
1031
|
state->cursor += 4;
|
|
934
|
-
return
|
|
1032
|
+
return json_push_value(state, config, Qnil);
|
|
935
1033
|
}
|
|
936
1034
|
|
|
937
|
-
raise_parse_error("unexpected token
|
|
1035
|
+
raise_parse_error("unexpected token %s", state);
|
|
938
1036
|
break;
|
|
939
1037
|
case 't':
|
|
940
1038
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
|
941
1039
|
state->cursor += 4;
|
|
942
|
-
return
|
|
1040
|
+
return json_push_value(state, config, Qtrue);
|
|
943
1041
|
}
|
|
944
1042
|
|
|
945
|
-
raise_parse_error("unexpected token
|
|
1043
|
+
raise_parse_error("unexpected token %s", state);
|
|
946
1044
|
break;
|
|
947
1045
|
case 'f':
|
|
948
1046
|
// Note: memcmp with a small power of two compile to an integer comparison
|
|
949
1047
|
if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
|
|
950
1048
|
state->cursor += 5;
|
|
951
|
-
return
|
|
1049
|
+
return json_push_value(state, config, Qfalse);
|
|
952
1050
|
}
|
|
953
1051
|
|
|
954
|
-
raise_parse_error("unexpected token
|
|
1052
|
+
raise_parse_error("unexpected token %s", state);
|
|
955
1053
|
break;
|
|
956
1054
|
case 'N':
|
|
957
1055
|
// Note: memcmp with a small power of two compile to an integer comparison
|
|
958
1056
|
if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
|
|
959
1057
|
state->cursor += 3;
|
|
960
|
-
return
|
|
1058
|
+
return json_push_value(state, config, CNaN);
|
|
961
1059
|
}
|
|
962
1060
|
|
|
963
|
-
raise_parse_error("unexpected token
|
|
1061
|
+
raise_parse_error("unexpected token %s", state);
|
|
964
1062
|
break;
|
|
965
1063
|
case 'I':
|
|
966
1064
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
|
967
1065
|
state->cursor += 8;
|
|
968
|
-
return
|
|
1066
|
+
return json_push_value(state, config, CInfinity);
|
|
969
1067
|
}
|
|
970
1068
|
|
|
971
|
-
raise_parse_error("unexpected token
|
|
1069
|
+
raise_parse_error("unexpected token %s", state);
|
|
972
1070
|
break;
|
|
973
1071
|
case '-':
|
|
974
1072
|
// Note: memcmp with a small power of two compile to an integer comparison
|
|
975
1073
|
if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
|
|
976
1074
|
if (config->allow_nan) {
|
|
977
1075
|
state->cursor += 9;
|
|
978
|
-
return
|
|
1076
|
+
return json_push_value(state, config, CMinusInfinity);
|
|
979
1077
|
} else {
|
|
980
|
-
raise_parse_error("unexpected token
|
|
1078
|
+
raise_parse_error("unexpected token %s", state);
|
|
981
1079
|
}
|
|
982
1080
|
}
|
|
983
1081
|
// Fallthrough
|
|
@@ -995,11 +1093,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
995
1093
|
long integer_length = state->cursor - start;
|
|
996
1094
|
|
|
997
1095
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
|
998
|
-
|
|
1096
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
|
999
1097
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
|
1000
|
-
|
|
1098
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
|
1001
1099
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
|
1002
|
-
|
|
1100
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
|
1003
1101
|
}
|
|
1004
1102
|
|
|
1005
1103
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
|
@@ -1007,7 +1105,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1007
1105
|
state->cursor++;
|
|
1008
1106
|
|
|
1009
1107
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
|
1010
|
-
raise_parse_error("invalid number: %s", state
|
|
1108
|
+
raise_parse_error("invalid number: %s", state);
|
|
1011
1109
|
}
|
|
1012
1110
|
|
|
1013
1111
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
|
@@ -1023,7 +1121,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1023
1121
|
}
|
|
1024
1122
|
|
|
1025
1123
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
|
1026
|
-
raise_parse_error("invalid number: %s", state
|
|
1124
|
+
raise_parse_error("invalid number: %s", state);
|
|
1027
1125
|
}
|
|
1028
1126
|
|
|
1029
1127
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
|
@@ -1032,9 +1130,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1032
1130
|
}
|
|
1033
1131
|
|
|
1034
1132
|
if (integer) {
|
|
1035
|
-
return
|
|
1133
|
+
return json_push_value(state, config, json_decode_integer(start, state->cursor));
|
|
1036
1134
|
}
|
|
1037
|
-
return
|
|
1135
|
+
return json_push_value(state, config, json_decode_float(config, start, state->cursor));
|
|
1038
1136
|
}
|
|
1039
1137
|
case '"': {
|
|
1040
1138
|
// %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
|
|
@@ -1048,7 +1146,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1048
1146
|
|
|
1049
1147
|
if ((state->cursor < state->end) && (*state->cursor == ']')) {
|
|
1050
1148
|
state->cursor++;
|
|
1051
|
-
return
|
|
1149
|
+
return json_push_value(state, config, json_decode_array(state, config, 0));
|
|
1052
1150
|
} else {
|
|
1053
1151
|
state->current_nesting++;
|
|
1054
1152
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
|
@@ -1067,7 +1165,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1067
1165
|
long count = state->stack->head - stack_head;
|
|
1068
1166
|
state->current_nesting--;
|
|
1069
1167
|
state->in_array--;
|
|
1070
|
-
return
|
|
1168
|
+
return json_push_value(state, config, json_decode_array(state, config, count));
|
|
1071
1169
|
}
|
|
1072
1170
|
|
|
1073
1171
|
if (*state->cursor == ',') {
|
|
@@ -1083,18 +1181,20 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1083
1181
|
}
|
|
1084
1182
|
}
|
|
1085
1183
|
|
|
1086
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
|
1184
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
|
1087
1185
|
}
|
|
1088
1186
|
break;
|
|
1089
1187
|
}
|
|
1090
1188
|
case '{': {
|
|
1189
|
+
const char *object_start_cursor = state->cursor;
|
|
1190
|
+
|
|
1091
1191
|
state->cursor++;
|
|
1092
1192
|
json_eat_whitespace(state);
|
|
1093
1193
|
long stack_head = state->stack->head;
|
|
1094
1194
|
|
|
1095
1195
|
if ((state->cursor < state->end) && (*state->cursor == '}')) {
|
|
1096
1196
|
state->cursor++;
|
|
1097
|
-
return
|
|
1197
|
+
return json_push_value(state, config, json_decode_object(state, config, 0));
|
|
1098
1198
|
} else {
|
|
1099
1199
|
state->current_nesting++;
|
|
1100
1200
|
if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
|
|
@@ -1102,13 +1202,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1102
1202
|
}
|
|
1103
1203
|
|
|
1104
1204
|
if (*state->cursor != '"') {
|
|
1105
|
-
raise_parse_error("expected object key, got
|
|
1205
|
+
raise_parse_error("expected object key, got %s", state);
|
|
1106
1206
|
}
|
|
1107
1207
|
json_parse_string(state, config, true);
|
|
1108
1208
|
|
|
1109
1209
|
json_eat_whitespace(state);
|
|
1110
1210
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
|
1111
|
-
raise_parse_error("expected ':' after object key", state
|
|
1211
|
+
raise_parse_error("expected ':' after object key", state);
|
|
1112
1212
|
}
|
|
1113
1213
|
state->cursor++;
|
|
1114
1214
|
|
|
@@ -1122,8 +1222,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1122
1222
|
if (*state->cursor == '}') {
|
|
1123
1223
|
state->cursor++;
|
|
1124
1224
|
state->current_nesting--;
|
|
1125
|
-
|
|
1126
|
-
|
|
1225
|
+
size_t count = state->stack->head - stack_head;
|
|
1226
|
+
|
|
1227
|
+
// Temporary rewind cursor in case an error is raised
|
|
1228
|
+
const char *final_cursor = state->cursor;
|
|
1229
|
+
state->cursor = object_start_cursor;
|
|
1230
|
+
VALUE object = json_decode_object(state, config, count);
|
|
1231
|
+
state->cursor = final_cursor;
|
|
1232
|
+
|
|
1233
|
+
return json_push_value(state, config, object);
|
|
1127
1234
|
}
|
|
1128
1235
|
|
|
1129
1236
|
if (*state->cursor == ',') {
|
|
@@ -1137,13 +1244,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1137
1244
|
}
|
|
1138
1245
|
|
|
1139
1246
|
if (*state->cursor != '"') {
|
|
1140
|
-
raise_parse_error("expected object key, got:
|
|
1247
|
+
raise_parse_error("expected object key, got: %s", state);
|
|
1141
1248
|
}
|
|
1142
1249
|
json_parse_string(state, config, true);
|
|
1143
1250
|
|
|
1144
1251
|
json_eat_whitespace(state);
|
|
1145
1252
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
|
1146
|
-
raise_parse_error("expected ':' after object key, got:
|
|
1253
|
+
raise_parse_error("expected ':' after object key, got: %s", state);
|
|
1147
1254
|
}
|
|
1148
1255
|
state->cursor++;
|
|
1149
1256
|
|
|
@@ -1153,24 +1260,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
|
1153
1260
|
}
|
|
1154
1261
|
}
|
|
1155
1262
|
|
|
1156
|
-
raise_parse_error("expected ',' or '}' after object value, got:
|
|
1263
|
+
raise_parse_error("expected ',' or '}' after object value, got: %s", state);
|
|
1157
1264
|
}
|
|
1158
1265
|
break;
|
|
1159
1266
|
}
|
|
1160
1267
|
|
|
1161
1268
|
default:
|
|
1162
|
-
raise_parse_error("unexpected character:
|
|
1269
|
+
raise_parse_error("unexpected character: %s", state);
|
|
1163
1270
|
break;
|
|
1164
1271
|
}
|
|
1165
1272
|
|
|
1166
|
-
raise_parse_error("
|
|
1273
|
+
raise_parse_error("unreachable: %s", state);
|
|
1167
1274
|
}
|
|
1168
1275
|
|
|
1169
1276
|
static void json_ensure_eof(JSON_ParserState *state)
|
|
1170
1277
|
{
|
|
1171
1278
|
json_eat_whitespace(state);
|
|
1172
1279
|
if (state->cursor != state->end) {
|
|
1173
|
-
raise_parse_error("unexpected token at end of stream
|
|
1280
|
+
raise_parse_error("unexpected token at end of stream %s", state);
|
|
1174
1281
|
}
|
|
1175
1282
|
}
|
|
1176
1283
|
|
|
@@ -1211,10 +1318,8 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1211
1318
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
|
1212
1319
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
|
1213
1320
|
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; }
|
|
1321
|
+
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
|
1322
|
+
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
|
1218
1323
|
else if (key == sym_decimal_class) {
|
|
1219
1324
|
if (RTEST(val)) {
|
|
1220
1325
|
if (rb_respond_to(val, i_try_convert)) {
|
|
@@ -1244,15 +1349,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1244
1349
|
}
|
|
1245
1350
|
}
|
|
1246
1351
|
}
|
|
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
1352
|
|
|
1257
1353
|
return ST_CONTINUE;
|
|
1258
1354
|
}
|
|
@@ -1267,16 +1363,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
|
1267
1363
|
// We assume in most cases few keys are set so it's faster to go over
|
|
1268
1364
|
// the provided keys than to check all possible keys.
|
|
1269
1365
|
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
1366
|
}
|
|
1281
1367
|
|
|
1282
1368
|
}
|
|
@@ -1301,15 +1387,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
|
1301
1387
|
* (keys) in a JSON object. Otherwise strings are returned, which is
|
|
1302
1388
|
* also the default. It's not possible to use this option in
|
|
1303
1389
|
* 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
1390
|
* * *decimal_class*: Specifies which class to use instead of the default
|
|
1314
1391
|
* (Float) when parsing decimal numbers. This class must accept a single
|
|
1315
1392
|
* string argument in its constructor.
|
|
@@ -1320,11 +1397,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
|
1320
1397
|
|
|
1321
1398
|
parser_config_init(config, opts);
|
|
1322
1399
|
|
|
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
1400
|
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
|
1327
|
-
RB_OBJ_WRITTEN(self, Qundef, config->match_string);
|
|
1328
1401
|
|
|
1329
1402
|
return self;
|
|
1330
1403
|
}
|
|
@@ -1341,9 +1414,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1341
1414
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
|
1342
1415
|
};
|
|
1343
1416
|
|
|
1417
|
+
long len;
|
|
1418
|
+
const char *start;
|
|
1419
|
+
RSTRING_GETMEM(Vsource, start, len);
|
|
1420
|
+
|
|
1344
1421
|
JSON_ParserState _state = {
|
|
1345
|
-
.
|
|
1346
|
-
.
|
|
1422
|
+
.start = start,
|
|
1423
|
+
.cursor = start,
|
|
1424
|
+
.end = start + len,
|
|
1347
1425
|
.stack = &stack,
|
|
1348
1426
|
};
|
|
1349
1427
|
JSON_ParserState *state = &_state;
|
|
@@ -1387,11 +1465,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
|
1387
1465
|
static void JSON_ParserConfig_mark(void *ptr)
|
|
1388
1466
|
{
|
|
1389
1467
|
JSON_ParserConfig *config = ptr;
|
|
1390
|
-
rb_gc_mark(config->
|
|
1391
|
-
rb_gc_mark(config->object_class);
|
|
1392
|
-
rb_gc_mark(config->array_class);
|
|
1468
|
+
rb_gc_mark(config->on_load_proc);
|
|
1393
1469
|
rb_gc_mark(config->decimal_class);
|
|
1394
|
-
rb_gc_mark(config->match_string);
|
|
1395
1470
|
}
|
|
1396
1471
|
|
|
1397
1472
|
static void JSON_ParserConfig_free(void *ptr)
|
|
@@ -1459,19 +1534,11 @@ void Init_parser(void)
|
|
|
1459
1534
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
|
1460
1535
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
|
1461
1536
|
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"));
|
|
1537
|
+
sym_on_load = ID2SYM(rb_intern("on_load"));
|
|
1466
1538
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
|
1467
|
-
|
|
1539
|
+
sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
|
|
1468
1540
|
|
|
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
1541
|
i_chr = rb_intern("chr");
|
|
1473
|
-
i_match = rb_intern("match");
|
|
1474
|
-
i_deep_const_get = rb_intern("deep_const_get");
|
|
1475
1542
|
i_aset = rb_intern("[]=");
|
|
1476
1543
|
i_aref = rb_intern("[]");
|
|
1477
1544
|
i_leftshift = rb_intern("<<");
|
|
@@ -1483,4 +1550,8 @@ void Init_parser(void)
|
|
|
1483
1550
|
binary_encindex = rb_ascii8bit_encindex();
|
|
1484
1551
|
utf8_encindex = rb_utf8_encindex();
|
|
1485
1552
|
enc_utf8 = rb_utf8_encoding();
|
|
1553
|
+
|
|
1554
|
+
#ifdef HAVE_SIMD
|
|
1555
|
+
simd_impl = find_simd_implementation();
|
|
1556
|
+
#endif
|
|
1486
1557
|
}
|