json 2.11.3 → 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 +18 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +38 -4
- data/ext/json/ext/generator/extconf.rb +30 -0
- data/ext/json/ext/generator/generator.c +359 -12
- data/ext/json/ext/generator/simd.h +112 -0
- data/ext/json/ext/parser/parser.c +151 -100
- data/ext/json/ext/vendor/fpconv.c +10 -10
- data/lib/json/common.rb +7 -5
- data/lib/json/ext.rb +2 -2
- data/lib/json/version.rb +1 -1
- metadata +3 -2
@@ -0,0 +1,112 @@
|
|
1
|
+
typedef enum {
|
2
|
+
SIMD_NONE,
|
3
|
+
SIMD_NEON,
|
4
|
+
SIMD_SSE2
|
5
|
+
} SIMD_Implementation;
|
6
|
+
|
7
|
+
#ifdef JSON_ENABLE_SIMD
|
8
|
+
|
9
|
+
#ifdef __clang__
|
10
|
+
#if __has_builtin(__builtin_ctzll)
|
11
|
+
#define HAVE_BUILTIN_CTZLL 1
|
12
|
+
#else
|
13
|
+
#define HAVE_BUILTIN_CTZLL 0
|
14
|
+
#endif
|
15
|
+
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
16
|
+
#define HAVE_BUILTIN_CTZLL 1
|
17
|
+
#else
|
18
|
+
#define HAVE_BUILTIN_CTZLL 0
|
19
|
+
#endif
|
20
|
+
|
21
|
+
static inline uint32_t trailing_zeros64(uint64_t input) {
|
22
|
+
#if HAVE_BUILTIN_CTZLL
|
23
|
+
return __builtin_ctzll(input);
|
24
|
+
#else
|
25
|
+
uint32_t trailing_zeros = 0;
|
26
|
+
uint64_t temp = input;
|
27
|
+
while ((temp & 1) == 0 && temp > 0) {
|
28
|
+
trailing_zeros++;
|
29
|
+
temp >>= 1;
|
30
|
+
}
|
31
|
+
return trailing_zeros;
|
32
|
+
#endif
|
33
|
+
}
|
34
|
+
|
35
|
+
static inline int trailing_zeros(int input) {
|
36
|
+
#if HAVE_BUILTIN_CTZLL
|
37
|
+
return __builtin_ctz(input);
|
38
|
+
#else
|
39
|
+
int trailing_zeros = 0;
|
40
|
+
int temp = input;
|
41
|
+
while ((temp & 1) == 0 && temp > 0) {
|
42
|
+
trailing_zeros++;
|
43
|
+
temp >>= 1;
|
44
|
+
}
|
45
|
+
return trailing_zeros;
|
46
|
+
#endif
|
47
|
+
}
|
48
|
+
|
49
|
+
#define SIMD_MINIMUM_THRESHOLD 6
|
50
|
+
|
51
|
+
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
|
52
|
+
#include <arm_neon.h>
|
53
|
+
|
54
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
55
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
56
|
+
return SIMD_NEON;
|
57
|
+
}
|
58
|
+
|
59
|
+
#define HAVE_SIMD 1
|
60
|
+
#define HAVE_SIMD_NEON 1
|
61
|
+
|
62
|
+
uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
|
63
|
+
uint8x16x4_t tab;
|
64
|
+
tab.val[0] = vld1q_u8(table);
|
65
|
+
tab.val[1] = vld1q_u8(table+16);
|
66
|
+
tab.val[2] = vld1q_u8(table+32);
|
67
|
+
tab.val[3] = vld1q_u8(table+48);
|
68
|
+
return tab;
|
69
|
+
}
|
70
|
+
|
71
|
+
#endif /* ARM Neon Support.*/
|
72
|
+
|
73
|
+
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
74
|
+
|
75
|
+
#ifdef HAVE_X86INTRIN_H
|
76
|
+
#include <x86intrin.h>
|
77
|
+
|
78
|
+
#define HAVE_SIMD 1
|
79
|
+
#define HAVE_SIMD_SSE2 1
|
80
|
+
|
81
|
+
#ifdef HAVE_CPUID_H
|
82
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
83
|
+
|
84
|
+
#include <cpuid.h>
|
85
|
+
#endif /* HAVE_CPUID_H */
|
86
|
+
|
87
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
88
|
+
|
89
|
+
#if defined(__GNUC__ ) || defined(__clang__)
|
90
|
+
#ifdef __GNUC__
|
91
|
+
__builtin_cpu_init();
|
92
|
+
#endif /* __GNUC__ */
|
93
|
+
|
94
|
+
// TODO Revisit. I think the SSE version now only uses SSE2 instructions.
|
95
|
+
if (__builtin_cpu_supports("sse2")) {
|
96
|
+
return SIMD_SSE2;
|
97
|
+
}
|
98
|
+
#endif /* __GNUC__ || __clang__*/
|
99
|
+
|
100
|
+
return SIMD_NONE;
|
101
|
+
}
|
102
|
+
|
103
|
+
#endif /* HAVE_X86INTRIN_H */
|
104
|
+
#endif /* X86_64 Support */
|
105
|
+
|
106
|
+
#endif /* JSON_ENABLE_SIMD */
|
107
|
+
|
108
|
+
#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
|
109
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
110
|
+
return SIMD_NONE;
|
111
|
+
}
|
112
|
+
#endif
|
@@ -337,33 +337,128 @@ static size_t strnlen(const char *s, size_t maxlen)
|
|
337
337
|
}
|
338
338
|
#endif
|
339
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
|
+
|
340
390
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
341
391
|
#ifdef RBIMPL_ATTR_NORETURN
|
342
392
|
RBIMPL_ATTR_NORETURN()
|
343
393
|
#endif
|
344
|
-
static void raise_parse_error(const char *format,
|
394
|
+
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
345
395
|
{
|
346
|
-
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN +
|
396
|
+
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
347
397
|
|
348
|
-
|
349
|
-
|
398
|
+
const char *cursor = state->cursor;
|
399
|
+
long column = 0;
|
400
|
+
long line = 1;
|
350
401
|
|
351
|
-
|
352
|
-
|
402
|
+
while (cursor >= state->start) {
|
403
|
+
if (*cursor-- == '\n') {
|
404
|
+
break;
|
405
|
+
}
|
406
|
+
column++;
|
407
|
+
}
|
353
408
|
|
354
|
-
|
355
|
-
|
409
|
+
while (cursor >= state->start) {
|
410
|
+
if (*cursor-- == '\n') {
|
411
|
+
line++;
|
356
412
|
}
|
413
|
+
}
|
357
414
|
|
358
|
-
|
359
|
-
|
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++;
|
360
425
|
}
|
361
426
|
|
362
|
-
|
363
|
-
|
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
|
+
}
|
364
443
|
}
|
365
444
|
|
366
|
-
|
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);
|
367
462
|
}
|
368
463
|
|
369
464
|
/* unicode */
|
@@ -385,73 +480,25 @@ static const signed char digit_values[256] = {
|
|
385
480
|
-1, -1, -1, -1, -1, -1, -1
|
386
481
|
};
|
387
482
|
|
388
|
-
static uint32_t unescape_unicode(const unsigned char *p)
|
483
|
+
static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
|
389
484
|
{
|
390
485
|
signed char b;
|
391
486
|
uint32_t result = 0;
|
392
487
|
b = digit_values[p[0]];
|
393
|
-
if (b < 0)
|
488
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
394
489
|
result = (result << 4) | (unsigned char)b;
|
395
490
|
b = digit_values[p[1]];
|
396
|
-
if (b < 0)
|
491
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
397
492
|
result = (result << 4) | (unsigned char)b;
|
398
493
|
b = digit_values[p[2]];
|
399
|
-
if (b < 0)
|
494
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
400
495
|
result = (result << 4) | (unsigned char)b;
|
401
496
|
b = digit_values[p[3]];
|
402
|
-
if (b < 0)
|
497
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
403
498
|
result = (result << 4) | (unsigned char)b;
|
404
499
|
return result;
|
405
500
|
}
|
406
501
|
|
407
|
-
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
408
|
-
{
|
409
|
-
int len = 1;
|
410
|
-
if (ch <= 0x7F) {
|
411
|
-
buf[0] = (char) ch;
|
412
|
-
} else if (ch <= 0x07FF) {
|
413
|
-
buf[0] = (char) ((ch >> 6) | 0xC0);
|
414
|
-
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
415
|
-
len++;
|
416
|
-
} else if (ch <= 0xFFFF) {
|
417
|
-
buf[0] = (char) ((ch >> 12) | 0xE0);
|
418
|
-
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
419
|
-
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
420
|
-
len += 2;
|
421
|
-
} else if (ch <= 0x1fffff) {
|
422
|
-
buf[0] =(char) ((ch >> 18) | 0xF0);
|
423
|
-
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
424
|
-
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
425
|
-
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
426
|
-
len += 3;
|
427
|
-
} else {
|
428
|
-
buf[0] = '?';
|
429
|
-
}
|
430
|
-
return len;
|
431
|
-
}
|
432
|
-
|
433
|
-
typedef struct JSON_ParserStruct {
|
434
|
-
VALUE on_load_proc;
|
435
|
-
VALUE decimal_class;
|
436
|
-
ID decimal_method_id;
|
437
|
-
int max_nesting;
|
438
|
-
bool allow_nan;
|
439
|
-
bool allow_trailing_comma;
|
440
|
-
bool parsing_name;
|
441
|
-
bool symbolize_names;
|
442
|
-
bool freeze;
|
443
|
-
} JSON_ParserConfig;
|
444
|
-
|
445
|
-
typedef struct JSON_ParserStateStruct {
|
446
|
-
VALUE stack_handle;
|
447
|
-
const char *cursor;
|
448
|
-
const char *end;
|
449
|
-
rvalue_stack *stack;
|
450
|
-
rvalue_cache name_cache;
|
451
|
-
int in_array;
|
452
|
-
int current_nesting;
|
453
|
-
} JSON_ParserState;
|
454
|
-
|
455
502
|
#define GET_PARSER_CONFIG \
|
456
503
|
JSON_ParserConfig *config; \
|
457
504
|
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
|
@@ -485,8 +532,7 @@ json_eat_comments(JSON_ParserState *state)
|
|
485
532
|
while (true) {
|
486
533
|
state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
|
487
534
|
if (!state->cursor) {
|
488
|
-
|
489
|
-
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);
|
490
536
|
} else {
|
491
537
|
state->cursor++;
|
492
538
|
if (state->cursor < state->end && *state->cursor == '/') {
|
@@ -498,11 +544,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
498
544
|
break;
|
499
545
|
}
|
500
546
|
default:
|
501
|
-
raise_parse_error("unexpected token
|
547
|
+
raise_parse_error("unexpected token %s", state);
|
502
548
|
break;
|
503
549
|
}
|
504
550
|
} else {
|
505
|
-
raise_parse_error("unexpected token
|
551
|
+
raise_parse_error("unexpected token %s", state);
|
506
552
|
}
|
507
553
|
}
|
508
554
|
|
@@ -621,9 +667,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
621
667
|
break;
|
622
668
|
case 'u':
|
623
669
|
if (pe > stringEnd - 5) {
|
624
|
-
|
670
|
+
raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
|
625
671
|
} else {
|
626
|
-
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
672
|
+
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
627
673
|
pe += 3;
|
628
674
|
/* To handle values above U+FFFF, we take a sequence of
|
629
675
|
* \uXXXX escapes in the U+D800..U+DBFF then
|
@@ -638,10 +684,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
638
684
|
if ((ch & 0xFC00) == 0xD800) {
|
639
685
|
pe++;
|
640
686
|
if (pe > stringEnd - 6) {
|
641
|
-
|
687
|
+
raise_parse_error_at("incomplete surrogate pair at %s", state, p);
|
642
688
|
}
|
643
689
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
644
|
-
uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
|
690
|
+
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
645
691
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
646
692
|
| (sur & 0x3FF));
|
647
693
|
pe += 5;
|
@@ -829,12 +875,12 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
829
875
|
state->cursor++;
|
830
876
|
escaped = true;
|
831
877
|
if ((unsigned char)*state->cursor < 0x20) {
|
832
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
878
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
833
879
|
}
|
834
880
|
break;
|
835
881
|
}
|
836
882
|
default:
|
837
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
883
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
838
884
|
break;
|
839
885
|
}
|
840
886
|
}
|
@@ -842,7 +888,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
842
888
|
state->cursor++;
|
843
889
|
}
|
844
890
|
|
845
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
891
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
846
892
|
return Qfalse;
|
847
893
|
}
|
848
894
|
|
@@ -850,7 +896,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
850
896
|
{
|
851
897
|
json_eat_whitespace(state);
|
852
898
|
if (state->cursor >= state->end) {
|
853
|
-
raise_parse_error("unexpected end of input", state
|
899
|
+
raise_parse_error("unexpected end of input", state);
|
854
900
|
}
|
855
901
|
|
856
902
|
switch (*state->cursor) {
|
@@ -860,7 +906,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
860
906
|
return json_push_value(state, config, Qnil);
|
861
907
|
}
|
862
908
|
|
863
|
-
raise_parse_error("unexpected token
|
909
|
+
raise_parse_error("unexpected token %s", state);
|
864
910
|
break;
|
865
911
|
case 't':
|
866
912
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
@@ -868,7 +914,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
868
914
|
return json_push_value(state, config, Qtrue);
|
869
915
|
}
|
870
916
|
|
871
|
-
raise_parse_error("unexpected token
|
917
|
+
raise_parse_error("unexpected token %s", state);
|
872
918
|
break;
|
873
919
|
case 'f':
|
874
920
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -877,7 +923,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
877
923
|
return json_push_value(state, config, Qfalse);
|
878
924
|
}
|
879
925
|
|
880
|
-
raise_parse_error("unexpected token
|
926
|
+
raise_parse_error("unexpected token %s", state);
|
881
927
|
break;
|
882
928
|
case 'N':
|
883
929
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -886,7 +932,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
886
932
|
return json_push_value(state, config, CNaN);
|
887
933
|
}
|
888
934
|
|
889
|
-
raise_parse_error("unexpected token
|
935
|
+
raise_parse_error("unexpected token %s", state);
|
890
936
|
break;
|
891
937
|
case 'I':
|
892
938
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
@@ -894,7 +940,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
894
940
|
return json_push_value(state, config, CInfinity);
|
895
941
|
}
|
896
942
|
|
897
|
-
raise_parse_error("unexpected token
|
943
|
+
raise_parse_error("unexpected token %s", state);
|
898
944
|
break;
|
899
945
|
case '-':
|
900
946
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -903,7 +949,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
903
949
|
state->cursor += 9;
|
904
950
|
return json_push_value(state, config, CMinusInfinity);
|
905
951
|
} else {
|
906
|
-
raise_parse_error("unexpected token
|
952
|
+
raise_parse_error("unexpected token %s", state);
|
907
953
|
}
|
908
954
|
}
|
909
955
|
// Fallthrough
|
@@ -921,11 +967,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
921
967
|
long integer_length = state->cursor - start;
|
922
968
|
|
923
969
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
924
|
-
|
970
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
925
971
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
926
|
-
|
972
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
927
973
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
928
|
-
|
974
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
929
975
|
}
|
930
976
|
|
931
977
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
@@ -933,7 +979,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
933
979
|
state->cursor++;
|
934
980
|
|
935
981
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
936
|
-
raise_parse_error("invalid number: %s", state
|
982
|
+
raise_parse_error("invalid number: %s", state);
|
937
983
|
}
|
938
984
|
|
939
985
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -949,7 +995,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
949
995
|
}
|
950
996
|
|
951
997
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
952
|
-
raise_parse_error("invalid number: %s", state
|
998
|
+
raise_parse_error("invalid number: %s", state);
|
953
999
|
}
|
954
1000
|
|
955
1001
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1009,7 +1055,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1009
1055
|
}
|
1010
1056
|
}
|
1011
1057
|
|
1012
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
1058
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
1013
1059
|
}
|
1014
1060
|
break;
|
1015
1061
|
}
|
@@ -1028,13 +1074,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1028
1074
|
}
|
1029
1075
|
|
1030
1076
|
if (*state->cursor != '"') {
|
1031
|
-
raise_parse_error("expected object key, got
|
1077
|
+
raise_parse_error("expected object key, got %s", state);
|
1032
1078
|
}
|
1033
1079
|
json_parse_string(state, config, true);
|
1034
1080
|
|
1035
1081
|
json_eat_whitespace(state);
|
1036
1082
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1037
|
-
raise_parse_error("expected ':' after object key", state
|
1083
|
+
raise_parse_error("expected ':' after object key", state);
|
1038
1084
|
}
|
1039
1085
|
state->cursor++;
|
1040
1086
|
|
@@ -1063,13 +1109,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1063
1109
|
}
|
1064
1110
|
|
1065
1111
|
if (*state->cursor != '"') {
|
1066
|
-
raise_parse_error("expected object key, got:
|
1112
|
+
raise_parse_error("expected object key, got: %s", state);
|
1067
1113
|
}
|
1068
1114
|
json_parse_string(state, config, true);
|
1069
1115
|
|
1070
1116
|
json_eat_whitespace(state);
|
1071
1117
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1072
|
-
raise_parse_error("expected ':' after object key, got:
|
1118
|
+
raise_parse_error("expected ':' after object key, got: %s", state);
|
1073
1119
|
}
|
1074
1120
|
state->cursor++;
|
1075
1121
|
|
@@ -1079,24 +1125,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1079
1125
|
}
|
1080
1126
|
}
|
1081
1127
|
|
1082
|
-
raise_parse_error("expected ',' or '}' after object value, got:
|
1128
|
+
raise_parse_error("expected ',' or '}' after object value, got: %s", state);
|
1083
1129
|
}
|
1084
1130
|
break;
|
1085
1131
|
}
|
1086
1132
|
|
1087
1133
|
default:
|
1088
|
-
raise_parse_error("unexpected character:
|
1134
|
+
raise_parse_error("unexpected character: %s", state);
|
1089
1135
|
break;
|
1090
1136
|
}
|
1091
1137
|
|
1092
|
-
raise_parse_error("unreacheable:
|
1138
|
+
raise_parse_error("unreacheable: %s", state);
|
1093
1139
|
}
|
1094
1140
|
|
1095
1141
|
static void json_ensure_eof(JSON_ParserState *state)
|
1096
1142
|
{
|
1097
1143
|
json_eat_whitespace(state);
|
1098
1144
|
if (state->cursor != state->end) {
|
1099
|
-
raise_parse_error("unexpected token at end of stream
|
1145
|
+
raise_parse_error("unexpected token at end of stream %s", state);
|
1100
1146
|
}
|
1101
1147
|
}
|
1102
1148
|
|
@@ -1232,9 +1278,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
1232
1278
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1233
1279
|
};
|
1234
1280
|
|
1281
|
+
long len;
|
1282
|
+
const char *start;
|
1283
|
+
RSTRING_GETMEM(Vsource, start, len);
|
1284
|
+
|
1235
1285
|
JSON_ParserState _state = {
|
1236
|
-
.
|
1237
|
-
.
|
1286
|
+
.start = start,
|
1287
|
+
.cursor = start,
|
1288
|
+
.end = start + len,
|
1238
1289
|
.stack = &stack,
|
1239
1290
|
};
|
1240
1291
|
JSON_ParserState *state = &_state;
|
@@ -41,7 +41,7 @@ typedef struct Fp {
|
|
41
41
|
int exp;
|
42
42
|
} Fp;
|
43
43
|
|
44
|
-
static Fp powers_ten[] = {
|
44
|
+
static const Fp powers_ten[] = {
|
45
45
|
{ 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
|
46
46
|
{ 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
|
47
47
|
{ 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
|
@@ -92,7 +92,7 @@ static Fp find_cachedpow10(int exp, int* k)
|
|
92
92
|
{
|
93
93
|
const double one_log_ten = 0.30102999566398114;
|
94
94
|
|
95
|
-
int approx = -(exp + npowers) * one_log_ten;
|
95
|
+
int approx = (int)(-(exp + npowers) * one_log_ten);
|
96
96
|
int idx = (approx - firstpower) / steppowers;
|
97
97
|
|
98
98
|
while(1) {
|
@@ -123,7 +123,7 @@ static Fp find_cachedpow10(int exp, int* k)
|
|
123
123
|
#define absv(n) ((n) < 0 ? -(n) : (n))
|
124
124
|
#define minv(a, b) ((a) < (b) ? (a) : (b))
|
125
125
|
|
126
|
-
static uint64_t tens[] = {
|
126
|
+
static const uint64_t tens[] = {
|
127
127
|
10000000000000000000U, 1000000000000000000U, 100000000000000000U,
|
128
128
|
10000000000000000U, 1000000000000000U, 100000000000000U,
|
129
129
|
10000000000000U, 1000000000000U, 100000000000U,
|
@@ -244,7 +244,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
|
|
244
244
|
uint64_t part2 = upper->frac & (one.frac - 1);
|
245
245
|
|
246
246
|
int idx = 0, kappa = 10;
|
247
|
-
uint64_t* divp;
|
247
|
+
const uint64_t* divp;
|
248
248
|
/* 1000000000 */
|
249
249
|
for(divp = tens + 10; kappa > 0; divp++) {
|
250
250
|
|
@@ -268,7 +268,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
|
|
268
268
|
}
|
269
269
|
|
270
270
|
/* 10 */
|
271
|
-
uint64_t* unit = tens + 18;
|
271
|
+
const uint64_t* unit = tens + 18;
|
272
272
|
|
273
273
|
while(true) {
|
274
274
|
part2 *= 10;
|
@@ -340,7 +340,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
|
|
340
340
|
}
|
341
341
|
|
342
342
|
/* write decimal w/o scientific notation */
|
343
|
-
if(K < 0 && (K > -7 || exp <
|
343
|
+
if(K < 0 && (K > -7 || exp < 10)) {
|
344
344
|
int offset = ndigits - absv(K);
|
345
345
|
/* fp < 1.0 -> write leading zero */
|
346
346
|
if(offset <= 0) {
|
@@ -432,8 +432,8 @@ static int filter_special(double fp, char* dest)
|
|
432
432
|
*
|
433
433
|
* Input:
|
434
434
|
* fp -> the double to convert, dest -> destination buffer.
|
435
|
-
* The generated string will never be longer than
|
436
|
-
* Make sure to pass a pointer to at least
|
435
|
+
* The generated string will never be longer than 28 characters.
|
436
|
+
* Make sure to pass a pointer to at least 28 bytes of memory.
|
437
437
|
* The emitted string will not be null terminated.
|
438
438
|
*
|
439
439
|
* Output:
|
@@ -443,7 +443,7 @@ static int filter_special(double fp, char* dest)
|
|
443
443
|
*
|
444
444
|
* void print(double d)
|
445
445
|
* {
|
446
|
-
* char buf[
|
446
|
+
* char buf[28 + 1] // plus null terminator
|
447
447
|
* int str_len = fpconv_dtoa(d, buf);
|
448
448
|
*
|
449
449
|
* buf[str_len] = '\0';
|
@@ -451,7 +451,7 @@ static int filter_special(double fp, char* dest)
|
|
451
451
|
* }
|
452
452
|
*
|
453
453
|
*/
|
454
|
-
static int fpconv_dtoa(double d, char dest[
|
454
|
+
static int fpconv_dtoa(double d, char dest[28])
|
455
455
|
{
|
456
456
|
char digits[18];
|
457
457
|
|