json 2.7.5 → 2.9.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 +36 -0
- data/README.md +8 -77
- data/ext/json/ext/fbuffer/fbuffer.h +122 -54
- data/ext/json/ext/generator/generator.c +391 -232
- data/ext/json/ext/parser/extconf.rb +5 -27
- data/ext/json/ext/parser/parser.c +1597 -596
- data/ext/json/ext/parser/parser.rl +726 -258
- data/json.gemspec +4 -1
- data/lib/json/add/bigdecimal.rb +1 -1
- data/lib/json/common.rb +239 -77
- data/lib/json/ext/generator/state.rb +12 -31
- data/lib/json/ext.rb +2 -4
- data/lib/json/{pure → truffle_ruby}/generator.rb +173 -124
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +15 -20
- metadata +4 -8
- data/ext/json/ext/generator/generator.h +0 -118
- data/ext/json/ext/parser/parser.h +0 -60
- data/lib/json/pure/parser.rb +0 -331
- data/lib/json/pure.rb +0 -16
@@ -1,5 +1,309 @@
|
|
1
|
+
#include "ruby.h"
|
1
2
|
#include "../fbuffer/fbuffer.h"
|
2
|
-
|
3
|
+
|
4
|
+
static VALUE mJSON, mExt, cParser, eNestingError, Encoding_UTF_8;
|
5
|
+
static VALUE CNaN, CInfinity, CMinusInfinity;
|
6
|
+
|
7
|
+
static ID i_json_creatable_p, i_json_create, i_create_id,
|
8
|
+
i_chr, i_deep_const_get, i_match, i_aset, i_aref,
|
9
|
+
i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
|
10
|
+
|
11
|
+
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
|
12
|
+
sym_create_additions, sym_create_id, sym_object_class, sym_array_class,
|
13
|
+
sym_decimal_class, sym_match_string;
|
14
|
+
|
15
|
+
static int binary_encindex;
|
16
|
+
static int utf8_encindex;
|
17
|
+
|
18
|
+
#ifdef HAVE_RB_CATEGORY_WARN
|
19
|
+
# define json_deprecated(message) rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, message)
|
20
|
+
#else
|
21
|
+
# define json_deprecated(message) rb_warn(message)
|
22
|
+
#endif
|
23
|
+
|
24
|
+
static const char deprecated_create_additions_warning[] =
|
25
|
+
"JSON.load implicit support for `create_additions: true` is deprecated "
|
26
|
+
"and will be removed in 3.0, use JSON.unsafe_load or explicitly "
|
27
|
+
"pass `create_additions: true`";
|
28
|
+
|
29
|
+
#ifndef HAVE_RB_HASH_BULK_INSERT
|
30
|
+
// For TruffleRuby
|
31
|
+
void rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
|
32
|
+
{
|
33
|
+
long index = 0;
|
34
|
+
while (index < count) {
|
35
|
+
VALUE name = pairs[index++];
|
36
|
+
VALUE value = pairs[index++];
|
37
|
+
rb_hash_aset(hash, name, value);
|
38
|
+
}
|
39
|
+
RB_GC_GUARD(hash);
|
40
|
+
}
|
41
|
+
#endif
|
42
|
+
|
43
|
+
/* name cache */
|
44
|
+
|
45
|
+
#include <string.h>
|
46
|
+
#include <ctype.h>
|
47
|
+
|
48
|
+
// Object names are likely to be repeated, and are frozen.
|
49
|
+
// As such we can re-use them if we keep a cache of the ones we've seen so far,
|
50
|
+
// and save much more expensive lookups into the global fstring table.
|
51
|
+
// This cache implementation is deliberately simple, as we're optimizing for compactness,
|
52
|
+
// to be able to fit safely on the stack.
|
53
|
+
// As such, binary search into a sorted array gives a good tradeoff between compactness and
|
54
|
+
// performance.
|
55
|
+
#define JSON_RVALUE_CACHE_CAPA 63
|
56
|
+
typedef struct rvalue_cache_struct {
|
57
|
+
int length;
|
58
|
+
VALUE entries[JSON_RVALUE_CACHE_CAPA];
|
59
|
+
} rvalue_cache;
|
60
|
+
|
61
|
+
static rb_encoding *enc_utf8;
|
62
|
+
|
63
|
+
#define JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH 55
|
64
|
+
|
65
|
+
static inline VALUE build_interned_string(const char *str, const long length)
|
66
|
+
{
|
67
|
+
# ifdef HAVE_RB_ENC_INTERNED_STR
|
68
|
+
return rb_enc_interned_str(str, length, enc_utf8);
|
69
|
+
# else
|
70
|
+
VALUE rstring = rb_utf8_str_new(str, length);
|
71
|
+
return rb_funcall(rb_str_freeze(rstring), i_uminus, 0);
|
72
|
+
# endif
|
73
|
+
}
|
74
|
+
|
75
|
+
static inline VALUE build_symbol(const char *str, const long length)
|
76
|
+
{
|
77
|
+
return rb_str_intern(build_interned_string(str, length));
|
78
|
+
}
|
79
|
+
|
80
|
+
static void rvalue_cache_insert_at(rvalue_cache *cache, int index, VALUE rstring)
|
81
|
+
{
|
82
|
+
MEMMOVE(&cache->entries[index + 1], &cache->entries[index], VALUE, cache->length - index);
|
83
|
+
cache->length++;
|
84
|
+
cache->entries[index] = rstring;
|
85
|
+
}
|
86
|
+
|
87
|
+
static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
|
88
|
+
{
|
89
|
+
long rstring_length = RSTRING_LEN(rstring);
|
90
|
+
if (length == rstring_length) {
|
91
|
+
return memcmp(str, RSTRING_PTR(rstring), length);
|
92
|
+
} else {
|
93
|
+
return (int)(length - rstring_length);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const long length)
|
98
|
+
{
|
99
|
+
if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
|
100
|
+
// Common names aren't likely to be very long. So we just don't
|
101
|
+
// cache names above an arbitrary threshold.
|
102
|
+
return Qfalse;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (RB_UNLIKELY(!isalpha(str[0]))) {
|
106
|
+
// Simple heuristic, if the first character isn't a letter,
|
107
|
+
// we're much less likely to see this string again.
|
108
|
+
// We mostly want to cache strings that are likely to be repeated.
|
109
|
+
return Qfalse;
|
110
|
+
}
|
111
|
+
|
112
|
+
int low = 0;
|
113
|
+
int high = cache->length - 1;
|
114
|
+
int mid = 0;
|
115
|
+
int last_cmp = 0;
|
116
|
+
|
117
|
+
while (low <= high) {
|
118
|
+
mid = (high + low) >> 1;
|
119
|
+
VALUE entry = cache->entries[mid];
|
120
|
+
last_cmp = rstring_cache_cmp(str, length, entry);
|
121
|
+
|
122
|
+
if (last_cmp == 0) {
|
123
|
+
return entry;
|
124
|
+
} else if (last_cmp > 0) {
|
125
|
+
low = mid + 1;
|
126
|
+
} else {
|
127
|
+
high = mid - 1;
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
if (RB_UNLIKELY(memchr(str, '\\', length))) {
|
132
|
+
// We assume the overwhelming majority of names don't need to be escaped.
|
133
|
+
// But if they do, we have to fallback to the slow path.
|
134
|
+
return Qfalse;
|
135
|
+
}
|
136
|
+
|
137
|
+
VALUE rstring = build_interned_string(str, length);
|
138
|
+
|
139
|
+
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
|
140
|
+
if (last_cmp > 0) {
|
141
|
+
mid += 1;
|
142
|
+
}
|
143
|
+
|
144
|
+
rvalue_cache_insert_at(cache, mid, rstring);
|
145
|
+
}
|
146
|
+
return rstring;
|
147
|
+
}
|
148
|
+
|
149
|
+
static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const long length)
|
150
|
+
{
|
151
|
+
if (RB_UNLIKELY(length > JSON_RVALUE_CACHE_MAX_ENTRY_LENGTH)) {
|
152
|
+
// Common names aren't likely to be very long. So we just don't
|
153
|
+
// cache names above an arbitrary threshold.
|
154
|
+
return Qfalse;
|
155
|
+
}
|
156
|
+
|
157
|
+
if (RB_UNLIKELY(!isalpha(str[0]))) {
|
158
|
+
// Simple heuristic, if the first character isn't a letter,
|
159
|
+
// we're much less likely to see this string again.
|
160
|
+
// We mostly want to cache strings that are likely to be repeated.
|
161
|
+
return Qfalse;
|
162
|
+
}
|
163
|
+
|
164
|
+
int low = 0;
|
165
|
+
int high = cache->length - 1;
|
166
|
+
int mid = 0;
|
167
|
+
int last_cmp = 0;
|
168
|
+
|
169
|
+
while (low <= high) {
|
170
|
+
mid = (high + low) >> 1;
|
171
|
+
VALUE entry = cache->entries[mid];
|
172
|
+
last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
|
173
|
+
|
174
|
+
if (last_cmp == 0) {
|
175
|
+
return entry;
|
176
|
+
} else if (last_cmp > 0) {
|
177
|
+
low = mid + 1;
|
178
|
+
} else {
|
179
|
+
high = mid - 1;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
if (RB_UNLIKELY(memchr(str, '\\', length))) {
|
184
|
+
// We assume the overwhelming majority of names don't need to be escaped.
|
185
|
+
// But if they do, we have to fallback to the slow path.
|
186
|
+
return Qfalse;
|
187
|
+
}
|
188
|
+
|
189
|
+
VALUE rsymbol = build_symbol(str, length);
|
190
|
+
|
191
|
+
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
|
192
|
+
if (last_cmp > 0) {
|
193
|
+
mid += 1;
|
194
|
+
}
|
195
|
+
|
196
|
+
rvalue_cache_insert_at(cache, mid, rsymbol);
|
197
|
+
}
|
198
|
+
return rsymbol;
|
199
|
+
}
|
200
|
+
|
201
|
+
/* rvalue stack */
|
202
|
+
|
203
|
+
#define RVALUE_STACK_INITIAL_CAPA 128
|
204
|
+
|
205
|
+
enum rvalue_stack_type {
|
206
|
+
RVALUE_STACK_HEAP_ALLOCATED = 0,
|
207
|
+
RVALUE_STACK_STACK_ALLOCATED = 1,
|
208
|
+
};
|
209
|
+
|
210
|
+
typedef struct rvalue_stack_struct {
|
211
|
+
enum rvalue_stack_type type;
|
212
|
+
long capa;
|
213
|
+
long head;
|
214
|
+
VALUE *ptr;
|
215
|
+
} rvalue_stack;
|
216
|
+
|
217
|
+
static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref);
|
218
|
+
|
219
|
+
static rvalue_stack *rvalue_stack_grow(rvalue_stack *stack, VALUE *handle, rvalue_stack **stack_ref)
|
220
|
+
{
|
221
|
+
long required = stack->capa * 2;
|
222
|
+
|
223
|
+
if (stack->type == RVALUE_STACK_STACK_ALLOCATED) {
|
224
|
+
stack = rvalue_stack_spill(stack, handle, stack_ref);
|
225
|
+
} else {
|
226
|
+
REALLOC_N(stack->ptr, VALUE, required);
|
227
|
+
stack->capa = required;
|
228
|
+
}
|
229
|
+
return stack;
|
230
|
+
}
|
231
|
+
|
232
|
+
static void rvalue_stack_push(rvalue_stack *stack, VALUE value, VALUE *handle, rvalue_stack **stack_ref)
|
233
|
+
{
|
234
|
+
if (RB_UNLIKELY(stack->head >= stack->capa)) {
|
235
|
+
stack = rvalue_stack_grow(stack, handle, stack_ref);
|
236
|
+
}
|
237
|
+
stack->ptr[stack->head] = value;
|
238
|
+
stack->head++;
|
239
|
+
}
|
240
|
+
|
241
|
+
static inline VALUE *rvalue_stack_peek(rvalue_stack *stack, long count)
|
242
|
+
{
|
243
|
+
return stack->ptr + (stack->head - count);
|
244
|
+
}
|
245
|
+
|
246
|
+
static inline void rvalue_stack_pop(rvalue_stack *stack, long count)
|
247
|
+
{
|
248
|
+
stack->head -= count;
|
249
|
+
}
|
250
|
+
|
251
|
+
static void rvalue_stack_mark(void *ptr)
|
252
|
+
{
|
253
|
+
rvalue_stack *stack = (rvalue_stack *)ptr;
|
254
|
+
long index;
|
255
|
+
for (index = 0; index < stack->head; index++) {
|
256
|
+
rb_gc_mark(stack->ptr[index]);
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
static void rvalue_stack_free(void *ptr)
|
261
|
+
{
|
262
|
+
rvalue_stack *stack = (rvalue_stack *)ptr;
|
263
|
+
if (stack) {
|
264
|
+
ruby_xfree(stack->ptr);
|
265
|
+
ruby_xfree(stack);
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
static size_t rvalue_stack_memsize(const void *ptr)
|
270
|
+
{
|
271
|
+
const rvalue_stack *stack = (const rvalue_stack *)ptr;
|
272
|
+
return sizeof(rvalue_stack) + sizeof(VALUE) * stack->capa;
|
273
|
+
}
|
274
|
+
|
275
|
+
static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
|
276
|
+
"JSON::Ext::Parser/rvalue_stack",
|
277
|
+
{
|
278
|
+
.dmark = rvalue_stack_mark,
|
279
|
+
.dfree = rvalue_stack_free,
|
280
|
+
.dsize = rvalue_stack_memsize,
|
281
|
+
},
|
282
|
+
0, 0,
|
283
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
284
|
+
};
|
285
|
+
|
286
|
+
static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref)
|
287
|
+
{
|
288
|
+
rvalue_stack *stack;
|
289
|
+
*handle = TypedData_Make_Struct(0, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
|
290
|
+
*stack_ref = stack;
|
291
|
+
MEMCPY(stack, old_stack, rvalue_stack, 1);
|
292
|
+
|
293
|
+
stack->capa = old_stack->capa << 1;
|
294
|
+
stack->ptr = ALLOC_N(VALUE, stack->capa);
|
295
|
+
stack->type = RVALUE_STACK_HEAP_ALLOCATED;
|
296
|
+
MEMCPY(stack->ptr, old_stack->ptr, VALUE, old_stack->head);
|
297
|
+
return stack;
|
298
|
+
}
|
299
|
+
|
300
|
+
static void rvalue_stack_eagerly_release(VALUE handle)
|
301
|
+
{
|
302
|
+
rvalue_stack *stack;
|
303
|
+
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
|
304
|
+
RTYPEDDATA_DATA(handle) = NULL;
|
305
|
+
rvalue_stack_free(stack);
|
306
|
+
}
|
3
307
|
|
4
308
|
/* unicode */
|
5
309
|
|
@@ -67,6 +371,58 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
|
67
371
|
return len;
|
68
372
|
}
|
69
373
|
|
374
|
+
typedef struct JSON_ParserStruct {
|
375
|
+
VALUE Vsource;
|
376
|
+
char *source;
|
377
|
+
long len;
|
378
|
+
char *memo;
|
379
|
+
VALUE create_id;
|
380
|
+
VALUE object_class;
|
381
|
+
VALUE array_class;
|
382
|
+
VALUE decimal_class;
|
383
|
+
VALUE match_string;
|
384
|
+
FBuffer fbuffer;
|
385
|
+
int in_array;
|
386
|
+
int max_nesting;
|
387
|
+
bool allow_nan;
|
388
|
+
bool allow_trailing_comma;
|
389
|
+
bool parsing_name;
|
390
|
+
bool symbolize_names;
|
391
|
+
bool freeze;
|
392
|
+
bool create_additions;
|
393
|
+
bool deprecated_create_additions;
|
394
|
+
rvalue_cache name_cache;
|
395
|
+
rvalue_stack *stack;
|
396
|
+
VALUE stack_handle;
|
397
|
+
} JSON_Parser;
|
398
|
+
|
399
|
+
#define GET_PARSER \
|
400
|
+
GET_PARSER_INIT; \
|
401
|
+
if (!json->Vsource) rb_raise(rb_eTypeError, "uninitialized instance")
|
402
|
+
|
403
|
+
#define GET_PARSER_INIT \
|
404
|
+
JSON_Parser *json; \
|
405
|
+
TypedData_Get_Struct(self, JSON_Parser, &JSON_Parser_type, json)
|
406
|
+
|
407
|
+
#define MinusInfinity "-Infinity"
|
408
|
+
#define EVIL 0x666
|
409
|
+
|
410
|
+
static const rb_data_type_t JSON_Parser_type;
|
411
|
+
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
412
|
+
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
|
413
|
+
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
|
414
|
+
static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
415
|
+
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
|
416
|
+
|
417
|
+
|
418
|
+
#ifndef HAVE_STRNLEN
|
419
|
+
static size_t strnlen(const char *s, size_t maxlen)
|
420
|
+
{
|
421
|
+
char *p;
|
422
|
+
return ((p = memchr(s, '\0', maxlen)) ? p - s : maxlen);
|
423
|
+
}
|
424
|
+
#endif
|
425
|
+
|
70
426
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
71
427
|
#ifdef RBIMPL_ATTR_NORETURN
|
72
428
|
RBIMPL_ATTR_NORETURN()
|
@@ -84,21 +440,9 @@ static void raise_parse_error(const char *format, const char *start)
|
|
84
440
|
ptr = buffer;
|
85
441
|
}
|
86
442
|
|
87
|
-
rb_enc_raise(
|
443
|
+
rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
|
88
444
|
}
|
89
445
|
|
90
|
-
static VALUE mJSON, mExt, cParser, eNestingError;
|
91
|
-
static VALUE CNaN, CInfinity, CMinusInfinity;
|
92
|
-
|
93
|
-
static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
|
94
|
-
i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
|
95
|
-
i_object_class, i_array_class, i_decimal_class,
|
96
|
-
i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
|
97
|
-
i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
|
98
|
-
|
99
|
-
static int binary_encindex;
|
100
|
-
static int utf8_encindex;
|
101
|
-
|
102
446
|
|
103
447
|
%%{
|
104
448
|
machine JSON_common;
|
@@ -135,27 +479,25 @@ static int utf8_encindex;
|
|
135
479
|
write data;
|
136
480
|
|
137
481
|
action parse_value {
|
138
|
-
|
139
|
-
char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
|
482
|
+
char *np = JSON_parse_value(json, fpc, pe, result, current_nesting);
|
140
483
|
if (np == NULL) {
|
141
484
|
fhold; fbreak;
|
142
485
|
} else {
|
143
|
-
if (NIL_P(json->object_class)) {
|
144
|
-
OBJ_FREEZE(last_name);
|
145
|
-
rb_hash_aset(*result, last_name, v);
|
146
|
-
} else {
|
147
|
-
rb_funcall(*result, i_aset, 2, last_name, v);
|
148
|
-
}
|
149
486
|
fexec np;
|
150
487
|
}
|
151
488
|
}
|
152
489
|
|
490
|
+
action allow_trailing_comma { json->allow_trailing_comma }
|
491
|
+
|
153
492
|
action parse_name {
|
154
493
|
char *np;
|
155
|
-
json->parsing_name =
|
156
|
-
np = JSON_parse_string(json, fpc, pe,
|
157
|
-
json->parsing_name =
|
158
|
-
if (np == NULL) { fhold; fbreak; } else
|
494
|
+
json->parsing_name = true;
|
495
|
+
np = JSON_parse_string(json, fpc, pe, result);
|
496
|
+
json->parsing_name = false;
|
497
|
+
if (np == NULL) { fhold; fbreak; } else {
|
498
|
+
PUSH(*result);
|
499
|
+
fexec np;
|
500
|
+
}
|
159
501
|
}
|
160
502
|
|
161
503
|
action exit { fhold; fbreak; }
|
@@ -165,37 +507,64 @@ static int utf8_encindex;
|
|
165
507
|
|
166
508
|
main := (
|
167
509
|
begin_object
|
168
|
-
(pair (next_pair)*)? ignore*
|
510
|
+
(pair (next_pair)*((ignore* value_separator) when allow_trailing_comma)?)? ignore*
|
169
511
|
end_object
|
170
512
|
) @exit;
|
171
513
|
}%%
|
172
514
|
|
515
|
+
#define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack)
|
516
|
+
|
173
517
|
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
|
174
518
|
{
|
175
519
|
int cs = EVIL;
|
176
|
-
VALUE last_name = Qnil;
|
177
|
-
VALUE object_class = json->object_class;
|
178
520
|
|
179
521
|
if (json->max_nesting && current_nesting > json->max_nesting) {
|
180
522
|
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
|
181
523
|
}
|
182
524
|
|
183
|
-
|
525
|
+
long stack_head = json->stack->head;
|
184
526
|
|
185
527
|
%% write init;
|
186
528
|
%% write exec;
|
187
529
|
|
188
530
|
if (cs >= JSON_object_first_final) {
|
189
|
-
|
531
|
+
long count = json->stack->head - stack_head;
|
532
|
+
|
533
|
+
if (RB_UNLIKELY(json->object_class)) {
|
534
|
+
VALUE object = rb_class_new_instance(0, 0, json->object_class);
|
535
|
+
long index = 0;
|
536
|
+
VALUE *items = rvalue_stack_peek(json->stack, count);
|
537
|
+
while (index < count) {
|
538
|
+
VALUE name = items[index++];
|
539
|
+
VALUE value = items[index++];
|
540
|
+
rb_funcall(object, i_aset, 2, name, value);
|
541
|
+
}
|
542
|
+
*result = object;
|
543
|
+
} else {
|
544
|
+
VALUE hash;
|
545
|
+
#ifdef HAVE_RB_HASH_NEW_CAPA
|
546
|
+
hash = rb_hash_new_capa(count >> 1);
|
547
|
+
#else
|
548
|
+
hash = rb_hash_new();
|
549
|
+
#endif
|
550
|
+
rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash);
|
551
|
+
*result = hash;
|
552
|
+
}
|
553
|
+
rvalue_stack_pop(json->stack, count);
|
554
|
+
|
555
|
+
if (RB_UNLIKELY(json->create_additions)) {
|
190
556
|
VALUE klassname;
|
191
|
-
if (
|
192
|
-
|
557
|
+
if (json->object_class) {
|
558
|
+
klassname = rb_funcall(*result, i_aref, 1, json->create_id);
|
193
559
|
} else {
|
194
|
-
|
560
|
+
klassname = rb_hash_aref(*result, json->create_id);
|
195
561
|
}
|
196
562
|
if (!NIL_P(klassname)) {
|
197
563
|
VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
|
198
564
|
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
|
565
|
+
if (json->deprecated_create_additions) {
|
566
|
+
json_deprecated(deprecated_create_additions_warning);
|
567
|
+
}
|
199
568
|
*result = rb_funcall(klass, i_json_create, 1, *result);
|
200
569
|
}
|
201
570
|
}
|
@@ -206,7 +575,6 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
206
575
|
}
|
207
576
|
}
|
208
577
|
|
209
|
-
|
210
578
|
%%{
|
211
579
|
machine JSON_value;
|
212
580
|
include JSON_common;
|
@@ -238,7 +606,12 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
238
606
|
}
|
239
607
|
action parse_string {
|
240
608
|
char *np = JSON_parse_string(json, fpc, pe, result);
|
241
|
-
if (np == NULL) {
|
609
|
+
if (np == NULL) {
|
610
|
+
fhold;
|
611
|
+
fbreak;
|
612
|
+
} else {
|
613
|
+
fexec np;
|
614
|
+
}
|
242
615
|
}
|
243
616
|
|
244
617
|
action parse_number {
|
@@ -252,16 +625,18 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
252
625
|
raise_parse_error("unexpected token at '%s'", p);
|
253
626
|
}
|
254
627
|
}
|
255
|
-
np =
|
256
|
-
if (np != NULL)
|
257
|
-
|
258
|
-
|
628
|
+
np = JSON_parse_number(json, fpc, pe, result);
|
629
|
+
if (np != NULL) {
|
630
|
+
fexec np;
|
631
|
+
}
|
259
632
|
fhold; fbreak;
|
260
633
|
}
|
261
634
|
|
262
635
|
action parse_array {
|
263
636
|
char *np;
|
637
|
+
json->in_array++;
|
264
638
|
np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
|
639
|
+
json->in_array--;
|
265
640
|
if (np == NULL) { fhold; fbreak; } else fexec np;
|
266
641
|
}
|
267
642
|
|
@@ -279,10 +654,10 @@ main := ignore* (
|
|
279
654
|
Vtrue @parse_true |
|
280
655
|
VNaN @parse_nan |
|
281
656
|
VInfinity @parse_infinity |
|
282
|
-
begin_number
|
283
|
-
begin_string
|
284
|
-
begin_array
|
285
|
-
begin_object
|
657
|
+
begin_number @parse_number |
|
658
|
+
begin_string @parse_string |
|
659
|
+
begin_array @parse_array |
|
660
|
+
begin_object @parse_object
|
286
661
|
) ignore* %*exit;
|
287
662
|
}%%
|
288
663
|
|
@@ -298,6 +673,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
298
673
|
}
|
299
674
|
|
300
675
|
if (cs >= JSON_value_first_final) {
|
676
|
+
PUSH(*result);
|
301
677
|
return p;
|
302
678
|
} else {
|
303
679
|
return NULL;
|
@@ -314,24 +690,40 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
314
690
|
main := '-'? ('0' | [1-9][0-9]*) (^[0-9]? @exit);
|
315
691
|
}%%
|
316
692
|
|
317
|
-
|
693
|
+
#define MAX_FAST_INTEGER_SIZE 18
|
694
|
+
static inline VALUE fast_parse_integer(char *p, char *pe)
|
318
695
|
{
|
319
|
-
|
696
|
+
bool negative = false;
|
697
|
+
if (*p == '-') {
|
698
|
+
negative = true;
|
699
|
+
p++;
|
700
|
+
}
|
320
701
|
|
321
|
-
|
322
|
-
|
323
|
-
|
702
|
+
long long memo = 0;
|
703
|
+
while (p < pe) {
|
704
|
+
memo *= 10;
|
705
|
+
memo += *p - '0';
|
706
|
+
p++;
|
707
|
+
}
|
708
|
+
|
709
|
+
if (negative) {
|
710
|
+
memo = -memo;
|
711
|
+
}
|
712
|
+
return LL2NUM(memo);
|
713
|
+
}
|
324
714
|
|
325
|
-
|
715
|
+
static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
|
716
|
+
{
|
326
717
|
long len = p - json->memo;
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
718
|
+
if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
|
719
|
+
*result = fast_parse_integer(json->memo, p);
|
720
|
+
} else {
|
721
|
+
fbuffer_clear(&json->fbuffer);
|
722
|
+
fbuffer_append(&json->fbuffer, json->memo, len);
|
723
|
+
fbuffer_append_char(&json->fbuffer, '\0');
|
724
|
+
*result = rb_cstr2inum(FBUFFER_PTR(&json->fbuffer), 10);
|
725
|
+
}
|
331
726
|
return p + 1;
|
332
|
-
} else {
|
333
|
-
return NULL;
|
334
|
-
}
|
335
727
|
}
|
336
728
|
|
337
729
|
%%{
|
@@ -341,25 +733,31 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
|
|
341
733
|
write data;
|
342
734
|
|
343
735
|
action exit { fhold; fbreak; }
|
736
|
+
action isFloat { is_float = true; }
|
344
737
|
|
345
738
|
main := '-'? (
|
346
|
-
(('0' | [1-9][0-9]*)
|
347
|
-
|
348
|
-
|
739
|
+
(('0' | [1-9][0-9]*)
|
740
|
+
((('.' [0-9]+ ([Ee] [+\-]?[0-9]+)?) |
|
741
|
+
([Ee] [+\-]?[0-9]+)) > isFloat)?
|
742
|
+
) (^[0-9Ee.\-]? @exit ));
|
349
743
|
}%%
|
350
744
|
|
351
|
-
static char *
|
745
|
+
static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
352
746
|
{
|
353
747
|
int cs = EVIL;
|
748
|
+
bool is_float = false;
|
354
749
|
|
355
750
|
%% write init;
|
356
751
|
json->memo = p;
|
357
752
|
%% write exec;
|
358
753
|
|
359
754
|
if (cs >= JSON_float_first_final) {
|
755
|
+
if (!is_float) {
|
756
|
+
return JSON_decode_integer(json, p, result);
|
757
|
+
}
|
360
758
|
VALUE mod = Qnil;
|
361
759
|
ID method_id = 0;
|
362
|
-
if (
|
760
|
+
if (json->decimal_class) {
|
363
761
|
if (rb_respond_to(json->decimal_class, i_try_convert)) {
|
364
762
|
mod = json->decimal_class;
|
365
763
|
method_id = i_try_convert;
|
@@ -388,15 +786,15 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
388
786
|
}
|
389
787
|
|
390
788
|
long len = p - json->memo;
|
391
|
-
fbuffer_clear(json->fbuffer);
|
392
|
-
fbuffer_append(json->fbuffer, json->memo, len);
|
393
|
-
fbuffer_append_char(json->fbuffer, '\0');
|
789
|
+
fbuffer_clear(&json->fbuffer);
|
790
|
+
fbuffer_append(&json->fbuffer, json->memo, len);
|
791
|
+
fbuffer_append_char(&json->fbuffer, '\0');
|
394
792
|
|
395
793
|
if (method_id) {
|
396
|
-
VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
|
794
|
+
VALUE text = rb_str_new2(FBUFFER_PTR(&json->fbuffer));
|
397
795
|
*result = rb_funcallv(mod, method_id, 1, &text);
|
398
796
|
} else {
|
399
|
-
*result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
|
797
|
+
*result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(&json->fbuffer), 1));
|
400
798
|
}
|
401
799
|
|
402
800
|
return p + 1;
|
@@ -418,39 +816,51 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
418
816
|
if (np == NULL) {
|
419
817
|
fhold; fbreak;
|
420
818
|
} else {
|
421
|
-
if (NIL_P(json->array_class)) {
|
422
|
-
rb_ary_push(*result, v);
|
423
|
-
} else {
|
424
|
-
rb_funcall(*result, i_leftshift, 1, v);
|
425
|
-
}
|
426
819
|
fexec np;
|
427
820
|
}
|
428
821
|
}
|
429
822
|
|
823
|
+
action allow_trailing_comma { json->allow_trailing_comma }
|
824
|
+
|
430
825
|
action exit { fhold; fbreak; }
|
431
826
|
|
432
827
|
next_element = value_separator ignore* begin_value >parse_value;
|
433
828
|
|
434
829
|
main := begin_array ignore*
|
435
830
|
((begin_value >parse_value ignore*)
|
436
|
-
|
831
|
+
(ignore* next_element ignore*)*((value_separator ignore*) when allow_trailing_comma)?)?
|
437
832
|
end_array @exit;
|
438
833
|
}%%
|
439
834
|
|
440
835
|
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
|
441
836
|
{
|
442
837
|
int cs = EVIL;
|
443
|
-
VALUE array_class = json->array_class;
|
444
838
|
|
445
839
|
if (json->max_nesting && current_nesting > json->max_nesting) {
|
446
840
|
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
|
447
841
|
}
|
448
|
-
|
842
|
+
long stack_head = json->stack->head;
|
449
843
|
|
450
844
|
%% write init;
|
451
845
|
%% write exec;
|
452
846
|
|
453
847
|
if(cs >= JSON_array_first_final) {
|
848
|
+
long count = json->stack->head - stack_head;
|
849
|
+
|
850
|
+
if (RB_UNLIKELY(json->array_class)) {
|
851
|
+
VALUE array = rb_class_new_instance(0, 0, json->array_class);
|
852
|
+
VALUE *items = rvalue_stack_peek(json->stack, count);
|
853
|
+
long index;
|
854
|
+
for (index = 0; index < count; index++) {
|
855
|
+
rb_funcall(array, i_leftshift, 1, items[index]);
|
856
|
+
}
|
857
|
+
*result = array;
|
858
|
+
} else {
|
859
|
+
VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(json->stack, count));
|
860
|
+
*result = array;
|
861
|
+
}
|
862
|
+
rvalue_stack_pop(json->stack, count);
|
863
|
+
|
454
864
|
return p + 1;
|
455
865
|
} else {
|
456
866
|
raise_parse_error("unexpected token at '%s'", p);
|
@@ -458,29 +868,81 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
458
868
|
}
|
459
869
|
}
|
460
870
|
|
461
|
-
static const
|
462
|
-
|
871
|
+
static inline VALUE build_string(const char *start, const char *end, bool intern, bool symbolize)
|
872
|
+
{
|
873
|
+
if (symbolize) {
|
874
|
+
intern = true;
|
875
|
+
}
|
876
|
+
VALUE result;
|
877
|
+
# ifdef HAVE_RB_ENC_INTERNED_STR
|
878
|
+
if (intern) {
|
879
|
+
result = rb_enc_interned_str(start, (long)(end - start), enc_utf8);
|
880
|
+
} else {
|
881
|
+
result = rb_utf8_str_new(start, (long)(end - start));
|
882
|
+
}
|
883
|
+
# else
|
884
|
+
result = rb_utf8_str_new(start, (long)(end - start));
|
885
|
+
if (intern) {
|
886
|
+
result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
|
887
|
+
}
|
888
|
+
# endif
|
889
|
+
|
890
|
+
if (symbolize) {
|
891
|
+
result = rb_str_intern(result);
|
892
|
+
}
|
893
|
+
|
894
|
+
return result;
|
895
|
+
}
|
896
|
+
|
897
|
+
static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
|
898
|
+
{
|
899
|
+
size_t bufferSize = stringEnd - string;
|
900
|
+
|
901
|
+
if (is_name && json->in_array) {
|
902
|
+
VALUE cached_key;
|
903
|
+
if (RB_UNLIKELY(symbolize)) {
|
904
|
+
cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
|
905
|
+
} else {
|
906
|
+
cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
|
907
|
+
}
|
908
|
+
|
909
|
+
if (RB_LIKELY(cached_key)) {
|
910
|
+
return cached_key;
|
911
|
+
}
|
912
|
+
}
|
913
|
+
|
914
|
+
return build_string(string, stringEnd, intern, symbolize);
|
915
|
+
}
|
916
|
+
|
917
|
+
static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringEnd, bool is_name, bool intern, bool symbolize)
|
463
918
|
{
|
464
|
-
VALUE result = Qnil;
|
465
919
|
size_t bufferSize = stringEnd - string;
|
466
920
|
char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
|
467
921
|
int unescape_len;
|
468
922
|
char buf[4];
|
469
923
|
|
470
|
-
if (
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
924
|
+
if (is_name && json->in_array) {
|
925
|
+
VALUE cached_key;
|
926
|
+
if (RB_UNLIKELY(symbolize)) {
|
927
|
+
cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
|
928
|
+
} else {
|
929
|
+
cached_key = rstring_cache_fetch(&json->name_cache, string, bufferSize);
|
930
|
+
}
|
931
|
+
|
932
|
+
if (RB_LIKELY(cached_key)) {
|
933
|
+
return cached_key;
|
934
|
+
}
|
935
|
+
}
|
936
|
+
|
937
|
+
pe = memchr(p, '\\', bufferSize);
|
938
|
+
if (RB_UNLIKELY(pe == NULL)) {
|
939
|
+
return build_string(string, stringEnd, intern, symbolize);
|
482
940
|
}
|
483
941
|
|
942
|
+
VALUE result = rb_str_buf_new(bufferSize);
|
943
|
+
rb_enc_associate_index(result, utf8_encindex);
|
944
|
+
buffer = bufferStart = RSTRING_PTR(result);
|
945
|
+
|
484
946
|
while (pe < stringEnd) {
|
485
947
|
if (*pe == '\\') {
|
486
948
|
unescape = (char *) "?";
|
@@ -513,9 +975,6 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
513
975
|
break;
|
514
976
|
case 'u':
|
515
977
|
if (pe > stringEnd - 4) {
|
516
|
-
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
517
|
-
ruby_xfree(bufferStart);
|
518
|
-
}
|
519
978
|
raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
|
520
979
|
} else {
|
521
980
|
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
@@ -533,9 +992,6 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
533
992
|
if ((ch & 0xFC00) == 0xD800) {
|
534
993
|
pe++;
|
535
994
|
if (pe > stringEnd - 6) {
|
536
|
-
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
537
|
-
ruby_xfree(bufferStart);
|
538
|
-
}
|
539
995
|
raise_parse_error("incomplete surrogate pair at '%s'", p);
|
540
996
|
}
|
541
997
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
@@ -568,41 +1024,12 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
568
1024
|
MEMCPY(buffer, p, char, pe - p);
|
569
1025
|
buffer += pe - p;
|
570
1026
|
}
|
571
|
-
|
572
|
-
# ifdef HAVE_RB_ENC_INTERNED_STR
|
573
|
-
if (intern) {
|
574
|
-
result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
|
575
|
-
} else {
|
576
|
-
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
577
|
-
}
|
578
|
-
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
579
|
-
ruby_xfree(bufferStart);
|
580
|
-
}
|
581
|
-
# else
|
582
|
-
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
583
|
-
|
584
|
-
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
585
|
-
ruby_xfree(bufferStart);
|
586
|
-
}
|
587
|
-
|
588
|
-
if (intern) {
|
589
|
-
# if STR_UMINUS_DEDUPE_FROZEN
|
590
|
-
// Starting from MRI 2.8 it is preferable to freeze the string
|
591
|
-
// before deduplication so that it can be interned directly
|
592
|
-
// otherwise it would be duplicated first which is wasteful.
|
593
|
-
result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
|
594
|
-
# elif STR_UMINUS_DEDUPE
|
595
|
-
// MRI 2.5 and older do not deduplicate strings that are already
|
596
|
-
// frozen.
|
597
|
-
result = rb_funcall(result, i_uminus, 0);
|
598
|
-
# else
|
599
|
-
result = rb_str_freeze(result);
|
600
|
-
# endif
|
601
|
-
}
|
602
|
-
# endif
|
1027
|
+
rb_str_set_len(result, buffer - bufferStart);
|
603
1028
|
|
604
1029
|
if (symbolize) {
|
605
|
-
|
1030
|
+
result = rb_str_intern(result);
|
1031
|
+
} else if (intern) {
|
1032
|
+
result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
|
606
1033
|
}
|
607
1034
|
|
608
1035
|
return result;
|
@@ -614,19 +1041,31 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
614
1041
|
|
615
1042
|
write data;
|
616
1043
|
|
617
|
-
action
|
618
|
-
*result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
} else {
|
623
|
-
fexec p + 1;
|
624
|
-
}
|
1044
|
+
action parse_complex_string {
|
1045
|
+
*result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
|
1046
|
+
fexec p + 1;
|
1047
|
+
fhold;
|
1048
|
+
fbreak;
|
625
1049
|
}
|
626
1050
|
|
627
|
-
action
|
1051
|
+
action parse_simple_string {
|
1052
|
+
*result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
|
1053
|
+
fexec p + 1;
|
1054
|
+
fhold;
|
1055
|
+
fbreak;
|
1056
|
+
}
|
628
1057
|
|
629
|
-
|
1058
|
+
double_quote = '"';
|
1059
|
+
escape = '\\';
|
1060
|
+
control = 0..0x1f;
|
1061
|
+
simple = any - escape - double_quote - control;
|
1062
|
+
|
1063
|
+
main := double_quote (
|
1064
|
+
(simple*)(
|
1065
|
+
(double_quote) @parse_simple_string |
|
1066
|
+
((^([\"\\] | control) | escape[\"\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | escape^([\"\\/bfnrtu]|0..0x1f))* double_quote) @parse_complex_string
|
1067
|
+
)
|
1068
|
+
);
|
630
1069
|
}%%
|
631
1070
|
|
632
1071
|
static int
|
@@ -684,18 +1123,78 @@ static VALUE convert_encoding(VALUE source)
|
|
684
1123
|
{
|
685
1124
|
int encindex = RB_ENCODING_GET(source);
|
686
1125
|
|
687
|
-
if (encindex == utf8_encindex) {
|
1126
|
+
if (RB_LIKELY(encindex == utf8_encindex)) {
|
688
1127
|
return source;
|
689
1128
|
}
|
690
1129
|
|
691
1130
|
if (encindex == binary_encindex) {
|
692
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8
|
693
|
-
// TODO: Deprecate in 2.8.0
|
694
|
-
// TODO: Remove in 3.0.0
|
1131
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8
|
695
1132
|
return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
|
696
1133
|
}
|
697
1134
|
|
698
|
-
return
|
1135
|
+
return rb_funcall(source, i_encode, 1, Encoding_UTF_8);
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
static int configure_parser_i(VALUE key, VALUE val, VALUE data)
|
1139
|
+
{
|
1140
|
+
JSON_Parser *json = (JSON_Parser *)data;
|
1141
|
+
|
1142
|
+
if (key == sym_max_nesting) { json->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
|
1143
|
+
else if (key == sym_allow_nan) { json->allow_nan = RTEST(val); }
|
1144
|
+
else if (key == sym_allow_trailing_comma) { json->allow_trailing_comma = RTEST(val); }
|
1145
|
+
else if (key == sym_symbolize_names) { json->symbolize_names = RTEST(val); }
|
1146
|
+
else if (key == sym_freeze) { json->freeze = RTEST(val); }
|
1147
|
+
else if (key == sym_create_id) { json->create_id = RTEST(val) ? val : Qfalse; }
|
1148
|
+
else if (key == sym_object_class) { json->object_class = RTEST(val) ? val : Qfalse; }
|
1149
|
+
else if (key == sym_array_class) { json->array_class = RTEST(val) ? val : Qfalse; }
|
1150
|
+
else if (key == sym_decimal_class) { json->decimal_class = RTEST(val) ? val : Qfalse; }
|
1151
|
+
else if (key == sym_match_string) { json->match_string = RTEST(val) ? val : Qfalse; }
|
1152
|
+
else if (key == sym_create_additions) {
|
1153
|
+
if (NIL_P(val)) {
|
1154
|
+
json->create_additions = true;
|
1155
|
+
json->deprecated_create_additions = true;
|
1156
|
+
} else {
|
1157
|
+
json->create_additions = RTEST(val);
|
1158
|
+
json->deprecated_create_additions = false;
|
1159
|
+
}
|
1160
|
+
}
|
1161
|
+
|
1162
|
+
return ST_CONTINUE;
|
1163
|
+
}
|
1164
|
+
|
1165
|
+
static void parser_init(JSON_Parser *json, VALUE source, VALUE opts)
|
1166
|
+
{
|
1167
|
+
if (json->Vsource) {
|
1168
|
+
rb_raise(rb_eTypeError, "already initialized instance");
|
1169
|
+
}
|
1170
|
+
|
1171
|
+
json->fbuffer.initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
1172
|
+
json->max_nesting = 100;
|
1173
|
+
|
1174
|
+
if (!NIL_P(opts)) {
|
1175
|
+
Check_Type(opts, T_HASH);
|
1176
|
+
if (RHASH_SIZE(opts) > 0) {
|
1177
|
+
// We assume in most cases few keys are set so it's faster to go over
|
1178
|
+
// the provided keys than to check all possible keys.
|
1179
|
+
rb_hash_foreach(opts, configure_parser_i, (VALUE)json);
|
1180
|
+
|
1181
|
+
if (json->symbolize_names && json->create_additions) {
|
1182
|
+
rb_raise(rb_eArgError,
|
1183
|
+
"options :symbolize_names and :create_additions cannot be "
|
1184
|
+
" used in conjunction");
|
1185
|
+
}
|
1186
|
+
|
1187
|
+
if (json->create_additions && !json->create_id) {
|
1188
|
+
json->create_id = rb_funcall(mJSON, i_create_id, 0);
|
1189
|
+
}
|
1190
|
+
}
|
1191
|
+
|
1192
|
+
}
|
1193
|
+
source = convert_encoding(StringValue(source));
|
1194
|
+
StringValue(source);
|
1195
|
+
json->len = RSTRING_LEN(source);
|
1196
|
+
json->source = RSTRING_PTR(source);
|
1197
|
+
json->Vsource = source;
|
699
1198
|
}
|
700
1199
|
|
701
1200
|
/*
|
@@ -732,111 +1231,11 @@ static VALUE convert_encoding(VALUE source)
|
|
732
1231
|
*/
|
733
1232
|
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
734
1233
|
{
|
735
|
-
VALUE source, opts;
|
736
1234
|
GET_PARSER_INIT;
|
737
1235
|
|
738
|
-
if (json->Vsource) {
|
739
|
-
rb_raise(rb_eTypeError, "already initialized instance");
|
740
|
-
}
|
741
|
-
|
742
1236
|
rb_check_arity(argc, 1, 2);
|
743
|
-
source = argv[0];
|
744
|
-
opts = Qnil;
|
745
|
-
if (argc == 2) {
|
746
|
-
opts = argv[1];
|
747
|
-
Check_Type(argv[1], T_HASH);
|
748
|
-
if (RHASH_SIZE(argv[1]) > 0) {
|
749
|
-
opts = argv[1];
|
750
|
-
}
|
751
|
-
}
|
752
1237
|
|
753
|
-
|
754
|
-
VALUE tmp = ID2SYM(i_max_nesting);
|
755
|
-
if (option_given_p(opts, tmp)) {
|
756
|
-
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
757
|
-
if (RTEST(max_nesting)) {
|
758
|
-
Check_Type(max_nesting, T_FIXNUM);
|
759
|
-
json->max_nesting = FIX2INT(max_nesting);
|
760
|
-
} else {
|
761
|
-
json->max_nesting = 0;
|
762
|
-
}
|
763
|
-
} else {
|
764
|
-
json->max_nesting = 100;
|
765
|
-
}
|
766
|
-
tmp = ID2SYM(i_allow_nan);
|
767
|
-
if (option_given_p(opts, tmp)) {
|
768
|
-
json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
769
|
-
} else {
|
770
|
-
json->allow_nan = 0;
|
771
|
-
}
|
772
|
-
tmp = ID2SYM(i_symbolize_names);
|
773
|
-
if (option_given_p(opts, tmp)) {
|
774
|
-
json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
775
|
-
} else {
|
776
|
-
json->symbolize_names = 0;
|
777
|
-
}
|
778
|
-
tmp = ID2SYM(i_freeze);
|
779
|
-
if (option_given_p(opts, tmp)) {
|
780
|
-
json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
781
|
-
} else {
|
782
|
-
json->freeze = 0;
|
783
|
-
}
|
784
|
-
tmp = ID2SYM(i_create_additions);
|
785
|
-
if (option_given_p(opts, tmp)) {
|
786
|
-
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
|
787
|
-
} else {
|
788
|
-
json->create_additions = 0;
|
789
|
-
}
|
790
|
-
if (json->symbolize_names && json->create_additions) {
|
791
|
-
rb_raise(rb_eArgError,
|
792
|
-
"options :symbolize_names and :create_additions cannot be "
|
793
|
-
" used in conjunction");
|
794
|
-
}
|
795
|
-
tmp = ID2SYM(i_create_id);
|
796
|
-
if (option_given_p(opts, tmp)) {
|
797
|
-
json->create_id = rb_hash_aref(opts, tmp);
|
798
|
-
} else {
|
799
|
-
json->create_id = rb_funcall(mJSON, i_create_id, 0);
|
800
|
-
}
|
801
|
-
tmp = ID2SYM(i_object_class);
|
802
|
-
if (option_given_p(opts, tmp)) {
|
803
|
-
json->object_class = rb_hash_aref(opts, tmp);
|
804
|
-
} else {
|
805
|
-
json->object_class = Qnil;
|
806
|
-
}
|
807
|
-
tmp = ID2SYM(i_array_class);
|
808
|
-
if (option_given_p(opts, tmp)) {
|
809
|
-
json->array_class = rb_hash_aref(opts, tmp);
|
810
|
-
} else {
|
811
|
-
json->array_class = Qnil;
|
812
|
-
}
|
813
|
-
tmp = ID2SYM(i_decimal_class);
|
814
|
-
if (option_given_p(opts, tmp)) {
|
815
|
-
json->decimal_class = rb_hash_aref(opts, tmp);
|
816
|
-
} else {
|
817
|
-
json->decimal_class = Qnil;
|
818
|
-
}
|
819
|
-
tmp = ID2SYM(i_match_string);
|
820
|
-
if (option_given_p(opts, tmp)) {
|
821
|
-
VALUE match_string = rb_hash_aref(opts, tmp);
|
822
|
-
json->match_string = RTEST(match_string) ? match_string : Qnil;
|
823
|
-
} else {
|
824
|
-
json->match_string = Qnil;
|
825
|
-
}
|
826
|
-
} else {
|
827
|
-
json->max_nesting = 100;
|
828
|
-
json->allow_nan = 0;
|
829
|
-
json->create_additions = 0;
|
830
|
-
json->create_id = Qnil;
|
831
|
-
json->object_class = Qnil;
|
832
|
-
json->array_class = Qnil;
|
833
|
-
json->decimal_class = Qnil;
|
834
|
-
}
|
835
|
-
source = convert_encoding(StringValue(source));
|
836
|
-
StringValue(source);
|
837
|
-
json->len = RSTRING_LEN(source);
|
838
|
-
json->source = RSTRING_PTR(source);;
|
839
|
-
json->Vsource = source;
|
1238
|
+
parser_init(json, argv[0], argc == 2 ? argv[1] : Qnil);
|
840
1239
|
return self;
|
841
1240
|
}
|
842
1241
|
|
@@ -871,11 +1270,64 @@ static VALUE cParser_parse(VALUE self)
|
|
871
1270
|
VALUE result = Qnil;
|
872
1271
|
GET_PARSER;
|
873
1272
|
|
1273
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1274
|
+
fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
|
1275
|
+
|
1276
|
+
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
|
1277
|
+
rvalue_stack stack = {
|
1278
|
+
.type = RVALUE_STACK_STACK_ALLOCATED,
|
1279
|
+
.ptr = rvalue_stack_buffer,
|
1280
|
+
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1281
|
+
};
|
1282
|
+
json->stack = &stack;
|
1283
|
+
|
874
1284
|
%% write init;
|
875
1285
|
p = json->source;
|
876
1286
|
pe = p + json->len;
|
877
1287
|
%% write exec;
|
878
1288
|
|
1289
|
+
if (json->stack_handle) {
|
1290
|
+
rvalue_stack_eagerly_release(json->stack_handle);
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
if (cs >= JSON_first_final && p == pe) {
|
1294
|
+
return result;
|
1295
|
+
} else {
|
1296
|
+
raise_parse_error("unexpected token at '%s'", p);
|
1297
|
+
return Qnil;
|
1298
|
+
}
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts)
|
1302
|
+
{
|
1303
|
+
char *p, *pe;
|
1304
|
+
int cs = EVIL;
|
1305
|
+
VALUE result = Qnil;
|
1306
|
+
|
1307
|
+
JSON_Parser _parser = {0};
|
1308
|
+
JSON_Parser *json = &_parser;
|
1309
|
+
parser_init(json, source, opts);
|
1310
|
+
|
1311
|
+
char stack_buffer[FBUFFER_STACK_SIZE];
|
1312
|
+
fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE);
|
1313
|
+
|
1314
|
+
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
|
1315
|
+
rvalue_stack stack = {
|
1316
|
+
.type = RVALUE_STACK_STACK_ALLOCATED,
|
1317
|
+
.ptr = rvalue_stack_buffer,
|
1318
|
+
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1319
|
+
};
|
1320
|
+
json->stack = &stack;
|
1321
|
+
|
1322
|
+
%% write init;
|
1323
|
+
p = json->source;
|
1324
|
+
pe = p + json->len;
|
1325
|
+
%% write exec;
|
1326
|
+
|
1327
|
+
if (json->stack_handle) {
|
1328
|
+
rvalue_stack_eagerly_release(json->stack_handle);
|
1329
|
+
}
|
1330
|
+
|
879
1331
|
if (cs >= JSON_first_final && p == pe) {
|
880
1332
|
return result;
|
881
1333
|
} else {
|
@@ -893,19 +1345,25 @@ static void JSON_mark(void *ptr)
|
|
893
1345
|
rb_gc_mark(json->array_class);
|
894
1346
|
rb_gc_mark(json->decimal_class);
|
895
1347
|
rb_gc_mark(json->match_string);
|
1348
|
+
rb_gc_mark(json->stack_handle);
|
1349
|
+
|
1350
|
+
long index;
|
1351
|
+
for (index = 0; index < json->name_cache.length; index++) {
|
1352
|
+
rb_gc_mark(json->name_cache.entries[index]);
|
1353
|
+
}
|
896
1354
|
}
|
897
1355
|
|
898
1356
|
static void JSON_free(void *ptr)
|
899
1357
|
{
|
900
1358
|
JSON_Parser *json = ptr;
|
901
|
-
fbuffer_free(json->fbuffer);
|
1359
|
+
fbuffer_free(&json->fbuffer);
|
902
1360
|
ruby_xfree(json);
|
903
1361
|
}
|
904
1362
|
|
905
1363
|
static size_t JSON_memsize(const void *ptr)
|
906
1364
|
{
|
907
1365
|
const JSON_Parser *json = ptr;
|
908
|
-
return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
|
1366
|
+
return sizeof(*json) + FBUFFER_CAPA(&json->fbuffer);
|
909
1367
|
}
|
910
1368
|
|
911
1369
|
static const rb_data_type_t JSON_Parser_type = {
|
@@ -919,7 +1377,7 @@ static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
919
1377
|
{
|
920
1378
|
JSON_Parser *json;
|
921
1379
|
VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
|
922
|
-
json->fbuffer
|
1380
|
+
fbuffer_stack_init(&json->fbuffer, 0, NULL, 0);
|
923
1381
|
return obj;
|
924
1382
|
}
|
925
1383
|
|
@@ -953,6 +1411,8 @@ void Init_parser(void)
|
|
953
1411
|
rb_define_method(cParser, "parse", cParser_parse, 0);
|
954
1412
|
rb_define_method(cParser, "source", cParser_source, 0);
|
955
1413
|
|
1414
|
+
rb_define_singleton_method(cParser, "parse", cParser_m_parse, 2);
|
1415
|
+
|
956
1416
|
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
|
957
1417
|
rb_gc_register_mark_object(CNaN);
|
958
1418
|
|
@@ -962,30 +1422,38 @@ void Init_parser(void)
|
|
962
1422
|
CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
|
963
1423
|
rb_gc_register_mark_object(CMinusInfinity);
|
964
1424
|
|
1425
|
+
rb_global_variable(&Encoding_UTF_8);
|
1426
|
+
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
|
1427
|
+
|
1428
|
+
sym_max_nesting = ID2SYM(rb_intern("max_nesting"));
|
1429
|
+
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
1430
|
+
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
1431
|
+
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
1432
|
+
sym_freeze = ID2SYM(rb_intern("freeze"));
|
1433
|
+
sym_create_additions = ID2SYM(rb_intern("create_additions"));
|
1434
|
+
sym_create_id = ID2SYM(rb_intern("create_id"));
|
1435
|
+
sym_object_class = ID2SYM(rb_intern("object_class"));
|
1436
|
+
sym_array_class = ID2SYM(rb_intern("array_class"));
|
1437
|
+
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1438
|
+
sym_match_string = ID2SYM(rb_intern("match_string"));
|
1439
|
+
|
1440
|
+
i_create_id = rb_intern("create_id");
|
965
1441
|
i_json_creatable_p = rb_intern("json_creatable?");
|
966
1442
|
i_json_create = rb_intern("json_create");
|
967
|
-
i_create_id = rb_intern("create_id");
|
968
|
-
i_create_additions = rb_intern("create_additions");
|
969
1443
|
i_chr = rb_intern("chr");
|
970
|
-
i_max_nesting = rb_intern("max_nesting");
|
971
|
-
i_allow_nan = rb_intern("allow_nan");
|
972
|
-
i_symbolize_names = rb_intern("symbolize_names");
|
973
|
-
i_object_class = rb_intern("object_class");
|
974
|
-
i_array_class = rb_intern("array_class");
|
975
|
-
i_decimal_class = rb_intern("decimal_class");
|
976
1444
|
i_match = rb_intern("match");
|
977
|
-
i_match_string = rb_intern("match_string");
|
978
1445
|
i_deep_const_get = rb_intern("deep_const_get");
|
979
1446
|
i_aset = rb_intern("[]=");
|
980
1447
|
i_aref = rb_intern("[]");
|
981
1448
|
i_leftshift = rb_intern("<<");
|
982
1449
|
i_new = rb_intern("new");
|
983
1450
|
i_try_convert = rb_intern("try_convert");
|
984
|
-
i_freeze = rb_intern("freeze");
|
985
1451
|
i_uminus = rb_intern("-@");
|
1452
|
+
i_encode = rb_intern("encode");
|
986
1453
|
|
987
1454
|
binary_encindex = rb_ascii8bit_encindex();
|
988
1455
|
utf8_encindex = rb_utf8_encindex();
|
1456
|
+
enc_utf8 = rb_utf8_encoding();
|
989
1457
|
}
|
990
1458
|
|
991
1459
|
/*
|