json 1.0.0 → 2.7.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 +7 -0
- data/CHANGES.md +503 -0
- data/LICENSE +56 -0
- data/README.md +416 -0
- data/ext/json/ext/fbuffer/fbuffer.h +187 -0
- data/ext/json/ext/generator/depend +1 -0
- data/ext/json/ext/generator/extconf.rb +2 -7
- data/ext/json/ext/generator/generator.c +1312 -338
- data/ext/json/ext/generator/generator.h +177 -0
- data/ext/json/ext/parser/depend +1 -0
- data/ext/json/ext/parser/extconf.rb +28 -5
- data/ext/json/ext/parser/parser.c +1349 -689
- data/ext/json/ext/parser/parser.h +96 -0
- data/ext/json/ext/parser/parser.rl +644 -188
- data/ext/json/extconf.rb +3 -0
- data/json.gemspec +68 -0
- data/lib/json/add/bigdecimal.rb +58 -0
- data/lib/json/add/complex.rb +51 -0
- data/lib/json/add/core.rb +12 -0
- data/lib/json/add/date.rb +54 -0
- data/lib/json/add/date_time.rb +67 -0
- data/lib/json/add/exception.rb +49 -0
- data/lib/json/add/ostruct.rb +54 -0
- data/lib/json/add/range.rb +54 -0
- data/lib/json/add/rational.rb +49 -0
- data/lib/json/add/regexp.rb +48 -0
- data/lib/json/add/set.rb +48 -0
- data/lib/json/add/struct.rb +52 -0
- data/lib/json/add/symbol.rb +48 -0
- data/lib/json/add/time.rb +59 -0
- data/lib/json/common.rb +588 -74
- data/lib/json/ext.rb +3 -1
- data/lib/json/generic_object.rb +75 -0
- data/lib/json/pure/generator.rb +311 -119
- data/lib/json/pure/parser.rb +182 -55
- data/lib/json/pure.rb +5 -65
- data/lib/json/version.rb +2 -1
- data/lib/json.rb +583 -196
- metadata +78 -137
- data/CHANGES +0 -25
- data/GPL +0 -340
- data/README +0 -77
- data/Rakefile +0 -250
- data/TODO +0 -1
- data/VERSION +0 -1
- data/benchmarks/benchmark.txt +0 -133
- data/benchmarks/benchmark_generator.rb +0 -44
- data/benchmarks/benchmark_parser.rb +0 -22
- data/benchmarks/benchmark_rails.rb +0 -26
- data/bin/edit_json.rb +0 -11
- data/data/example.json +0 -1
- data/data/index.html +0 -37
- data/data/prototype.js +0 -2515
- data/ext/json/ext/generator/Makefile +0 -149
- data/ext/json/ext/generator/unicode.c +0 -184
- data/ext/json/ext/generator/unicode.h +0 -40
- data/ext/json/ext/parser/Makefile +0 -149
- data/ext/json/ext/parser/unicode.c +0 -156
- data/ext/json/ext/parser/unicode.h +0 -44
- data/install.rb +0 -26
- data/lib/json/Array.xpm +0 -21
- data/lib/json/FalseClass.xpm +0 -21
- data/lib/json/Hash.xpm +0 -21
- data/lib/json/Key.xpm +0 -73
- data/lib/json/NilClass.xpm +0 -21
- data/lib/json/Numeric.xpm +0 -28
- data/lib/json/String.xpm +0 -96
- data/lib/json/TrueClass.xpm +0 -21
- data/lib/json/editor.rb +0 -1207
- data/lib/json/json.xpm +0 -1499
- data/tests/fixtures/fail1.json +0 -1
- data/tests/fixtures/fail10.json +0 -1
- data/tests/fixtures/fail11.json +0 -1
- data/tests/fixtures/fail12.json +0 -1
- data/tests/fixtures/fail13.json +0 -1
- data/tests/fixtures/fail14.json +0 -1
- data/tests/fixtures/fail15.json +0 -1
- data/tests/fixtures/fail16.json +0 -1
- data/tests/fixtures/fail17.json +0 -1
- data/tests/fixtures/fail19.json +0 -1
- data/tests/fixtures/fail2.json +0 -1
- data/tests/fixtures/fail20.json +0 -1
- data/tests/fixtures/fail21.json +0 -1
- data/tests/fixtures/fail22.json +0 -1
- data/tests/fixtures/fail23.json +0 -1
- data/tests/fixtures/fail24.json +0 -1
- data/tests/fixtures/fail25.json +0 -1
- data/tests/fixtures/fail26.json +0 -1
- data/tests/fixtures/fail27.json +0 -2
- data/tests/fixtures/fail28.json +0 -2
- data/tests/fixtures/fail3.json +0 -1
- data/tests/fixtures/fail4.json +0 -1
- data/tests/fixtures/fail5.json +0 -1
- data/tests/fixtures/fail6.json +0 -1
- data/tests/fixtures/fail7.json +0 -1
- data/tests/fixtures/fail8.json +0 -1
- data/tests/fixtures/fail9.json +0 -1
- data/tests/fixtures/pass1.json +0 -56
- data/tests/fixtures/pass18.json +0 -1
- data/tests/fixtures/pass2.json +0 -1
- data/tests/fixtures/pass3.json +0 -6
- data/tests/runner.rb +0 -24
- data/tests/test_json.rb +0 -235
- data/tests/test_json_addition.rb +0 -94
- data/tests/test_json_fixtures.rb +0 -30
- data/tests/test_json_generate.rb +0 -81
- data/tests/test_json_unicode.rb +0 -55
- data/tools/fuzz.rb +0 -133
- data/tools/server.rb +0 -62
@@ -1,37 +1,100 @@
|
|
1
|
-
|
1
|
+
#include "../fbuffer/fbuffer.h"
|
2
|
+
#include "parser.h"
|
3
|
+
|
4
|
+
#if defined HAVE_RUBY_ENCODING_H
|
5
|
+
# define EXC_ENCODING rb_utf8_encoding(),
|
6
|
+
# ifndef HAVE_RB_ENC_RAISE
|
7
|
+
static void
|
8
|
+
enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
|
9
|
+
{
|
10
|
+
va_list args;
|
11
|
+
VALUE mesg;
|
2
12
|
|
3
|
-
|
4
|
-
|
5
|
-
|
13
|
+
va_start(args, fmt);
|
14
|
+
mesg = rb_enc_vsprintf(enc, fmt, args);
|
15
|
+
va_end(args);
|
6
16
|
|
7
|
-
|
8
|
-
|
17
|
+
rb_exc_raise(rb_exc_new3(exc, mesg));
|
18
|
+
}
|
19
|
+
# define rb_enc_raise enc_raise
|
20
|
+
# endif
|
21
|
+
#else
|
22
|
+
# define EXC_ENCODING /* nothing */
|
23
|
+
# define rb_enc_raise rb_raise
|
9
24
|
#endif
|
10
25
|
|
11
|
-
|
12
|
-
|
13
|
-
static
|
14
|
-
|
15
|
-
|
26
|
+
/* unicode */
|
27
|
+
|
28
|
+
static const signed char digit_values[256] = {
|
29
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
30
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
31
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
|
32
|
+
-1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
|
33
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
34
|
+
10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
35
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
36
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
37
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
38
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
39
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
40
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
41
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
42
|
+
-1, -1, -1, -1, -1, -1, -1
|
43
|
+
};
|
44
|
+
|
45
|
+
static UTF32 unescape_unicode(const unsigned char *p)
|
46
|
+
{
|
47
|
+
signed char b;
|
48
|
+
UTF32 result = 0;
|
49
|
+
b = digit_values[p[0]];
|
50
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
51
|
+
result = (result << 4) | (unsigned char)b;
|
52
|
+
b = digit_values[p[1]];
|
53
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
54
|
+
result = (result << 4) | (unsigned char)b;
|
55
|
+
b = digit_values[p[2]];
|
56
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
57
|
+
result = (result << 4) | (unsigned char)b;
|
58
|
+
b = digit_values[p[3]];
|
59
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
60
|
+
result = (result << 4) | (unsigned char)b;
|
61
|
+
return result;
|
62
|
+
}
|
16
63
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
64
|
+
static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
|
65
|
+
{
|
66
|
+
int len = 1;
|
67
|
+
if (ch <= 0x7F) {
|
68
|
+
buf[0] = (char) ch;
|
69
|
+
} else if (ch <= 0x07FF) {
|
70
|
+
buf[0] = (char) ((ch >> 6) | 0xC0);
|
71
|
+
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
72
|
+
len++;
|
73
|
+
} else if (ch <= 0xFFFF) {
|
74
|
+
buf[0] = (char) ((ch >> 12) | 0xE0);
|
75
|
+
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
76
|
+
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
77
|
+
len += 2;
|
78
|
+
} else if (ch <= 0x1fffff) {
|
79
|
+
buf[0] =(char) ((ch >> 18) | 0xF0);
|
80
|
+
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
81
|
+
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
82
|
+
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
83
|
+
len += 3;
|
84
|
+
} else {
|
85
|
+
buf[0] = '?';
|
86
|
+
}
|
87
|
+
return len;
|
88
|
+
}
|
24
89
|
|
25
|
-
static
|
26
|
-
static
|
27
|
-
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
28
|
-
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
29
|
-
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
30
|
-
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
90
|
+
static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
|
91
|
+
static VALUE CNaN, CInfinity, CMinusInfinity;
|
31
92
|
|
32
|
-
|
33
|
-
|
34
|
-
|
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, i_key_p,
|
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;
|
35
98
|
|
36
99
|
%%{
|
37
100
|
machine JSON_common;
|
@@ -48,7 +111,10 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
48
111
|
Vnull = 'null';
|
49
112
|
Vfalse = 'false';
|
50
113
|
Vtrue = 'true';
|
51
|
-
|
114
|
+
VNaN = 'NaN';
|
115
|
+
VInfinity = 'Infinity';
|
116
|
+
VMinusInfinity = '-Infinity';
|
117
|
+
begin_value = [nft\"\-\[\{NI] | digit;
|
52
118
|
begin_object = '{';
|
53
119
|
end_object = '}';
|
54
120
|
begin_array = '[';
|
@@ -66,46 +132,68 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
66
132
|
|
67
133
|
action parse_value {
|
68
134
|
VALUE v = Qnil;
|
69
|
-
char *np = JSON_parse_value(json, fpc, pe, &v);
|
135
|
+
char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
|
70
136
|
if (np == NULL) {
|
71
|
-
fbreak;
|
137
|
+
fhold; fbreak;
|
72
138
|
} else {
|
73
|
-
|
139
|
+
if (NIL_P(json->object_class)) {
|
140
|
+
OBJ_FREEZE(last_name);
|
141
|
+
rb_hash_aset(*result, last_name, v);
|
142
|
+
} else {
|
143
|
+
rb_funcall(*result, i_aset, 2, last_name, v);
|
144
|
+
}
|
74
145
|
fexec np;
|
75
146
|
}
|
76
147
|
}
|
77
148
|
|
78
149
|
action parse_name {
|
79
|
-
char *np
|
80
|
-
|
150
|
+
char *np;
|
151
|
+
json->parsing_name = 1;
|
152
|
+
np = JSON_parse_string(json, fpc, pe, &last_name);
|
153
|
+
json->parsing_name = 0;
|
154
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
81
155
|
}
|
82
156
|
|
83
|
-
action exit { fbreak; }
|
157
|
+
action exit { fhold; fbreak; }
|
84
158
|
|
85
|
-
|
86
|
-
|
87
|
-
begin_value >parse_value;
|
159
|
+
pair = ignore* begin_name >parse_name ignore* name_separator ignore* begin_value >parse_value;
|
160
|
+
next_pair = ignore* value_separator pair;
|
88
161
|
|
89
|
-
main :=
|
90
|
-
|
91
|
-
|
162
|
+
main := (
|
163
|
+
begin_object
|
164
|
+
(pair (next_pair)*)? ignore*
|
165
|
+
end_object
|
166
|
+
) @exit;
|
92
167
|
}%%
|
93
168
|
|
94
|
-
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
169
|
+
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
|
95
170
|
{
|
96
171
|
int cs = EVIL;
|
97
172
|
VALUE last_name = Qnil;
|
98
|
-
|
173
|
+
VALUE object_class = json->object_class;
|
174
|
+
|
175
|
+
if (json->max_nesting && current_nesting > json->max_nesting) {
|
176
|
+
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
|
177
|
+
}
|
178
|
+
|
179
|
+
*result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
|
99
180
|
|
100
181
|
%% write init;
|
101
182
|
%% write exec;
|
102
183
|
|
103
184
|
if (cs >= JSON_object_first_final) {
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
185
|
+
if (json->create_additions) {
|
186
|
+
VALUE klassname;
|
187
|
+
if (NIL_P(json->object_class)) {
|
188
|
+
klassname = rb_hash_aref(*result, json->create_id);
|
189
|
+
} else {
|
190
|
+
klassname = rb_funcall(*result, i_aref, 1, json->create_id);
|
191
|
+
}
|
192
|
+
if (!NIL_P(klassname)) {
|
193
|
+
VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
|
194
|
+
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
|
195
|
+
*result = rb_funcall(klass, i_json_create, 1, *result);
|
196
|
+
}
|
109
197
|
}
|
110
198
|
}
|
111
199
|
return p + 1;
|
@@ -114,6 +202,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
114
202
|
}
|
115
203
|
}
|
116
204
|
|
205
|
+
|
117
206
|
%%{
|
118
207
|
machine JSON_value;
|
119
208
|
include JSON_common;
|
@@ -129,50 +218,81 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
129
218
|
action parse_true {
|
130
219
|
*result = Qtrue;
|
131
220
|
}
|
221
|
+
action parse_nan {
|
222
|
+
if (json->allow_nan) {
|
223
|
+
*result = CNaN;
|
224
|
+
} else {
|
225
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
action parse_infinity {
|
229
|
+
if (json->allow_nan) {
|
230
|
+
*result = CInfinity;
|
231
|
+
} else {
|
232
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 7);
|
233
|
+
}
|
234
|
+
}
|
132
235
|
action parse_string {
|
133
236
|
char *np = JSON_parse_string(json, fpc, pe, result);
|
134
|
-
if (np == NULL) fbreak; else fexec np;
|
237
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
135
238
|
}
|
136
239
|
|
137
240
|
action parse_number {
|
138
241
|
char *np;
|
242
|
+
if(pe > fpc + 8 && !strncmp(MinusInfinity, fpc, 9)) {
|
243
|
+
if (json->allow_nan) {
|
244
|
+
*result = CMinusInfinity;
|
245
|
+
fexec p + 10;
|
246
|
+
fhold; fbreak;
|
247
|
+
} else {
|
248
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
249
|
+
}
|
250
|
+
}
|
139
251
|
np = JSON_parse_float(json, fpc, pe, result);
|
140
252
|
if (np != NULL) fexec np;
|
141
253
|
np = JSON_parse_integer(json, fpc, pe, result);
|
142
254
|
if (np != NULL) fexec np;
|
143
|
-
fbreak;
|
255
|
+
fhold; fbreak;
|
144
256
|
}
|
145
257
|
|
146
|
-
action parse_array {
|
147
|
-
char *np
|
148
|
-
|
258
|
+
action parse_array {
|
259
|
+
char *np;
|
260
|
+
np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
|
261
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
149
262
|
}
|
150
263
|
|
151
|
-
action parse_object {
|
152
|
-
char *np
|
153
|
-
|
264
|
+
action parse_object {
|
265
|
+
char *np;
|
266
|
+
np = JSON_parse_object(json, fpc, pe, result, current_nesting + 1);
|
267
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
154
268
|
}
|
155
269
|
|
156
|
-
action exit { fbreak; }
|
270
|
+
action exit { fhold; fbreak; }
|
157
271
|
|
158
|
-
main := (
|
272
|
+
main := ignore* (
|
159
273
|
Vnull @parse_null |
|
160
274
|
Vfalse @parse_false |
|
161
275
|
Vtrue @parse_true |
|
276
|
+
VNaN @parse_nan |
|
277
|
+
VInfinity @parse_infinity |
|
162
278
|
begin_number >parse_number |
|
163
279
|
begin_string >parse_string |
|
164
280
|
begin_array >parse_array |
|
165
281
|
begin_object >parse_object
|
166
|
-
) %*exit;
|
282
|
+
) ignore* %*exit;
|
167
283
|
}%%
|
168
284
|
|
169
|
-
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
285
|
+
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
|
170
286
|
{
|
171
287
|
int cs = EVIL;
|
172
288
|
|
173
289
|
%% write init;
|
174
290
|
%% write exec;
|
175
291
|
|
292
|
+
if (json->freeze) {
|
293
|
+
OBJ_FREEZE(*result);
|
294
|
+
}
|
295
|
+
|
176
296
|
if (cs >= JSON_value_first_final) {
|
177
297
|
return p;
|
178
298
|
} else {
|
@@ -185,9 +305,9 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
185
305
|
|
186
306
|
write data;
|
187
307
|
|
188
|
-
action exit { fbreak; }
|
308
|
+
action exit { fhold; fbreak; }
|
189
309
|
|
190
|
-
main := '-'? ('0' | [1-9][0-9]*) (^[0-9] @exit);
|
310
|
+
main := '-'? ('0' | [1-9][0-9]*) (^[0-9]? @exit);
|
191
311
|
}%%
|
192
312
|
|
193
313
|
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
@@ -200,7 +320,10 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
|
|
200
320
|
|
201
321
|
if (cs >= JSON_integer_first_final) {
|
202
322
|
long len = p - json->memo;
|
203
|
-
|
323
|
+
fbuffer_clear(json->fbuffer);
|
324
|
+
fbuffer_append(json->fbuffer, json->memo, len);
|
325
|
+
fbuffer_append_char(json->fbuffer, '\0');
|
326
|
+
*result = rb_cstr2inum(FBUFFER_PTR(json->fbuffer), 10);
|
204
327
|
return p + 1;
|
205
328
|
} else {
|
206
329
|
return NULL;
|
@@ -213,12 +336,12 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
|
|
213
336
|
|
214
337
|
write data;
|
215
338
|
|
216
|
-
action exit { fbreak; }
|
339
|
+
action exit { fhold; fbreak; }
|
217
340
|
|
218
341
|
main := '-'? (
|
219
342
|
(('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
|
220
|
-
| ([1-9][0-9]* ([Ee] [+\-]?[0-9]+))
|
221
|
-
) (^[0-9Ee.\-] @exit );
|
343
|
+
| (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
|
344
|
+
) (^[0-9Ee.\-]? @exit );
|
222
345
|
}%%
|
223
346
|
|
224
347
|
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
@@ -230,8 +353,46 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
230
353
|
%% write exec;
|
231
354
|
|
232
355
|
if (cs >= JSON_float_first_final) {
|
356
|
+
VALUE mod = Qnil;
|
357
|
+
ID method_id = 0;
|
358
|
+
if (rb_respond_to(json->decimal_class, i_try_convert)) {
|
359
|
+
mod = json->decimal_class;
|
360
|
+
method_id = i_try_convert;
|
361
|
+
} else if (rb_respond_to(json->decimal_class, i_new)) {
|
362
|
+
mod = json->decimal_class;
|
363
|
+
method_id = i_new;
|
364
|
+
} else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
|
365
|
+
VALUE name = rb_class_name(json->decimal_class);
|
366
|
+
const char *name_cstr = RSTRING_PTR(name);
|
367
|
+
const char *last_colon = strrchr(name_cstr, ':');
|
368
|
+
if (last_colon) {
|
369
|
+
const char *mod_path_end = last_colon - 1;
|
370
|
+
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
|
371
|
+
mod = rb_path_to_class(mod_path);
|
372
|
+
|
373
|
+
const char *method_name_beg = last_colon + 1;
|
374
|
+
long before_len = method_name_beg - name_cstr;
|
375
|
+
long len = RSTRING_LEN(name) - before_len;
|
376
|
+
VALUE method_name = rb_str_substr(name, before_len, len);
|
377
|
+
method_id = SYM2ID(rb_str_intern(method_name));
|
378
|
+
} else {
|
379
|
+
mod = rb_mKernel;
|
380
|
+
method_id = SYM2ID(rb_str_intern(name));
|
381
|
+
}
|
382
|
+
}
|
383
|
+
|
233
384
|
long len = p - json->memo;
|
234
|
-
|
385
|
+
fbuffer_clear(json->fbuffer);
|
386
|
+
fbuffer_append(json->fbuffer, json->memo, len);
|
387
|
+
fbuffer_append_char(json->fbuffer, '\0');
|
388
|
+
|
389
|
+
if (method_id) {
|
390
|
+
VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
|
391
|
+
*result = rb_funcallv(mod, method_id, 1, &text);
|
392
|
+
} else {
|
393
|
+
*result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
|
394
|
+
}
|
395
|
+
|
235
396
|
return p + 1;
|
236
397
|
} else {
|
237
398
|
return NULL;
|
@@ -247,16 +408,20 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
247
408
|
|
248
409
|
action parse_value {
|
249
410
|
VALUE v = Qnil;
|
250
|
-
char *np = JSON_parse_value(json, fpc, pe, &v);
|
411
|
+
char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
|
251
412
|
if (np == NULL) {
|
252
|
-
fbreak;
|
413
|
+
fhold; fbreak;
|
253
414
|
} else {
|
254
|
-
|
415
|
+
if (NIL_P(json->array_class)) {
|
416
|
+
rb_ary_push(*result, v);
|
417
|
+
} else {
|
418
|
+
rb_funcall(*result, i_leftshift, 1, v);
|
419
|
+
}
|
255
420
|
fexec np;
|
256
421
|
}
|
257
422
|
}
|
258
423
|
|
259
|
-
action exit { fbreak; }
|
424
|
+
action exit { fhold; fbreak; }
|
260
425
|
|
261
426
|
next_element = value_separator ignore* begin_value >parse_value;
|
262
427
|
|
@@ -266,10 +431,15 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
266
431
|
end_array @exit;
|
267
432
|
}%%
|
268
433
|
|
269
|
-
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
434
|
+
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
|
270
435
|
{
|
271
436
|
int cs = EVIL;
|
272
|
-
|
437
|
+
VALUE array_class = json->array_class;
|
438
|
+
|
439
|
+
if (json->max_nesting && current_nesting > json->max_nesting) {
|
440
|
+
rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
|
441
|
+
}
|
442
|
+
*result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
|
273
443
|
|
274
444
|
%% write init;
|
275
445
|
%% write exec;
|
@@ -277,59 +447,154 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
277
447
|
if(cs >= JSON_array_first_final) {
|
278
448
|
return p + 1;
|
279
449
|
} else {
|
280
|
-
|
450
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
451
|
+
return NULL;
|
281
452
|
}
|
282
453
|
}
|
283
454
|
|
284
|
-
static
|
455
|
+
static const size_t MAX_STACK_BUFFER_SIZE = 128;
|
456
|
+
static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int symbolize)
|
285
457
|
{
|
286
|
-
VALUE result =
|
458
|
+
VALUE result = Qnil;
|
459
|
+
size_t bufferSize = stringEnd - string;
|
460
|
+
char *p = string, *pe = string, *unescape, *bufferStart, *buffer;
|
461
|
+
int unescape_len;
|
462
|
+
char buf[4];
|
463
|
+
|
464
|
+
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
465
|
+
# ifdef HAVE_RB_ENC_INTERNED_STR
|
466
|
+
bufferStart = buffer = ALLOC_N(char, bufferSize ? bufferSize : 1);
|
467
|
+
# else
|
468
|
+
bufferStart = buffer = ALLOC_N(char, bufferSize);
|
469
|
+
# endif
|
470
|
+
} else {
|
471
|
+
# ifdef HAVE_RB_ENC_INTERNED_STR
|
472
|
+
bufferStart = buffer = ALLOCA_N(char, bufferSize ? bufferSize : 1);
|
473
|
+
# else
|
474
|
+
bufferStart = buffer = ALLOCA_N(char, bufferSize);
|
475
|
+
# endif
|
476
|
+
}
|
287
477
|
|
288
|
-
while (
|
289
|
-
if (*
|
290
|
-
|
291
|
-
|
292
|
-
|
478
|
+
while (pe < stringEnd) {
|
479
|
+
if (*pe == '\\') {
|
480
|
+
unescape = (char *) "?";
|
481
|
+
unescape_len = 1;
|
482
|
+
if (pe > p) {
|
483
|
+
MEMCPY(buffer, p, char, pe - p);
|
484
|
+
buffer += pe - p;
|
485
|
+
}
|
486
|
+
switch (*++pe) {
|
487
|
+
case 'n':
|
488
|
+
unescape = (char *) "\n";
|
489
|
+
break;
|
490
|
+
case 'r':
|
491
|
+
unescape = (char *) "\r";
|
492
|
+
break;
|
493
|
+
case 't':
|
494
|
+
unescape = (char *) "\t";
|
495
|
+
break;
|
293
496
|
case '"':
|
497
|
+
unescape = (char *) "\"";
|
498
|
+
break;
|
294
499
|
case '\\':
|
295
|
-
|
296
|
-
p++;
|
500
|
+
unescape = (char *) "\\";
|
297
501
|
break;
|
298
502
|
case 'b':
|
299
|
-
|
300
|
-
p++;
|
503
|
+
unescape = (char *) "\b";
|
301
504
|
break;
|
302
505
|
case 'f':
|
303
|
-
|
304
|
-
p++;
|
305
|
-
break;
|
306
|
-
case 'n':
|
307
|
-
rb_str_buf_cat2(result, "\n");
|
308
|
-
p++;
|
309
|
-
break;
|
310
|
-
case 'r':
|
311
|
-
rb_str_buf_cat2(result, "\r");
|
312
|
-
p++;
|
313
|
-
break;
|
314
|
-
case 't':
|
315
|
-
rb_str_buf_cat2(result, "\t");
|
316
|
-
p++;
|
506
|
+
unescape = (char *) "\f";
|
317
507
|
break;
|
318
508
|
case 'u':
|
319
|
-
if (
|
320
|
-
|
509
|
+
if (pe > stringEnd - 4) {
|
510
|
+
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
511
|
+
ruby_xfree(bufferStart);
|
512
|
+
}
|
513
|
+
rb_enc_raise(
|
514
|
+
EXC_ENCODING eParserError,
|
515
|
+
"incomplete unicode character escape sequence at '%s'", p
|
516
|
+
);
|
321
517
|
} else {
|
322
|
-
|
518
|
+
UTF32 ch = unescape_unicode((unsigned char *) ++pe);
|
519
|
+
pe += 3;
|
520
|
+
if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
|
521
|
+
pe++;
|
522
|
+
if (pe > stringEnd - 6) {
|
523
|
+
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
524
|
+
ruby_xfree(bufferStart);
|
525
|
+
}
|
526
|
+
rb_enc_raise(
|
527
|
+
EXC_ENCODING eParserError,
|
528
|
+
"incomplete surrogate pair at '%s'", p
|
529
|
+
);
|
530
|
+
}
|
531
|
+
if (pe[0] == '\\' && pe[1] == 'u') {
|
532
|
+
UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
|
533
|
+
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
534
|
+
| (sur & 0x3FF));
|
535
|
+
pe += 5;
|
536
|
+
} else {
|
537
|
+
unescape = (char *) "?";
|
538
|
+
break;
|
539
|
+
}
|
540
|
+
}
|
541
|
+
unescape_len = convert_UTF32_to_UTF8(buf, ch);
|
542
|
+
unescape = buf;
|
323
543
|
}
|
324
544
|
break;
|
545
|
+
default:
|
546
|
+
p = pe;
|
547
|
+
continue;
|
325
548
|
}
|
549
|
+
MEMCPY(buffer, unescape, char, unescape_len);
|
550
|
+
buffer += unescape_len;
|
551
|
+
p = ++pe;
|
326
552
|
} else {
|
327
|
-
|
328
|
-
while (*q != '\\' && q < pe) q++;
|
329
|
-
rb_str_buf_cat(result, p, q - p);
|
330
|
-
p = q;
|
553
|
+
pe++;
|
331
554
|
}
|
332
555
|
}
|
556
|
+
|
557
|
+
if (pe > p) {
|
558
|
+
MEMCPY(buffer, p, char, pe - p);
|
559
|
+
buffer += pe - p;
|
560
|
+
}
|
561
|
+
|
562
|
+
# ifdef HAVE_RB_ENC_INTERNED_STR
|
563
|
+
if (intern) {
|
564
|
+
result = rb_enc_interned_str(bufferStart, (long)(buffer - bufferStart), rb_utf8_encoding());
|
565
|
+
} else {
|
566
|
+
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
567
|
+
}
|
568
|
+
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
569
|
+
ruby_xfree(bufferStart);
|
570
|
+
}
|
571
|
+
# else
|
572
|
+
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
573
|
+
|
574
|
+
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
575
|
+
ruby_xfree(bufferStart);
|
576
|
+
}
|
577
|
+
|
578
|
+
if (intern) {
|
579
|
+
# if STR_UMINUS_DEDUPE_FROZEN
|
580
|
+
// Starting from MRI 2.8 it is preferable to freeze the string
|
581
|
+
// before deduplication so that it can be interned directly
|
582
|
+
// otherwise it would be duplicated first which is wasteful.
|
583
|
+
result = rb_funcall(rb_str_freeze(result), i_uminus, 0);
|
584
|
+
# elif STR_UMINUS_DEDUPE
|
585
|
+
// MRI 2.5 and older do not deduplicate strings that are already
|
586
|
+
// frozen.
|
587
|
+
result = rb_funcall(result, i_uminus, 0);
|
588
|
+
# else
|
589
|
+
result = rb_str_freeze(result);
|
590
|
+
# endif
|
591
|
+
}
|
592
|
+
# endif
|
593
|
+
|
594
|
+
if (symbolize) {
|
595
|
+
result = rb_str_intern(result);
|
596
|
+
}
|
597
|
+
|
333
598
|
return result;
|
334
599
|
}
|
335
600
|
|
@@ -340,24 +605,52 @@ static VALUE json_string_escape(char *p, char *pe)
|
|
340
605
|
write data;
|
341
606
|
|
342
607
|
action parse_string {
|
343
|
-
*result =
|
344
|
-
if (NIL_P(*result))
|
608
|
+
*result = json_string_unescape(json->memo + 1, p, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names);
|
609
|
+
if (NIL_P(*result)) {
|
610
|
+
fhold;
|
611
|
+
fbreak;
|
612
|
+
} else {
|
613
|
+
fexec p + 1;
|
614
|
+
}
|
345
615
|
}
|
346
616
|
|
347
|
-
action exit { fbreak; }
|
617
|
+
action exit { fhold; fbreak; }
|
348
618
|
|
349
|
-
main := '"' ((^(["\\] | 0..0x1f) | '\\'["\\/bfnrt] | '\\u'[0-9a-fA-F]{4})* %parse_string) '"' @exit;
|
619
|
+
main := '"' ((^([\"\\] | 0..0x1f) | '\\'[\"\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | '\\'^([\"\\/bfnrtu]|0..0x1f))* %parse_string) '"' @exit;
|
350
620
|
}%%
|
351
621
|
|
622
|
+
static int
|
623
|
+
match_i(VALUE regexp, VALUE klass, VALUE memo)
|
624
|
+
{
|
625
|
+
if (regexp == Qundef) return ST_STOP;
|
626
|
+
if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
|
627
|
+
RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
|
628
|
+
rb_ary_push(memo, klass);
|
629
|
+
return ST_STOP;
|
630
|
+
}
|
631
|
+
return ST_CONTINUE;
|
632
|
+
}
|
633
|
+
|
352
634
|
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
|
353
635
|
{
|
354
636
|
int cs = EVIL;
|
637
|
+
VALUE match_string;
|
355
638
|
|
356
|
-
*result = rb_str_new("", 0);
|
357
639
|
%% write init;
|
358
640
|
json->memo = p;
|
359
641
|
%% write exec;
|
360
642
|
|
643
|
+
if (json->create_additions && RTEST(match_string = json->match_string)) {
|
644
|
+
VALUE klass;
|
645
|
+
VALUE memo = rb_ary_new2(2);
|
646
|
+
rb_ary_push(memo, *result);
|
647
|
+
rb_hash_foreach(match_string, match_i, memo);
|
648
|
+
klass = rb_ary_entry(memo, 1);
|
649
|
+
if (RTEST(klass)) {
|
650
|
+
*result = rb_funcall(klass, i_json_create, 1, *result);
|
651
|
+
}
|
652
|
+
}
|
653
|
+
|
361
654
|
if (cs >= JSON_string_first_final) {
|
362
655
|
return p + 1;
|
363
656
|
} else {
|
@@ -365,31 +658,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
365
658
|
}
|
366
659
|
}
|
367
660
|
|
368
|
-
|
369
|
-
%%{
|
370
|
-
machine JSON;
|
371
|
-
|
372
|
-
write data;
|
373
|
-
|
374
|
-
include JSON_common;
|
375
|
-
|
376
|
-
action parse_object {
|
377
|
-
char *np = JSON_parse_object(json, fpc, pe, &result);
|
378
|
-
if (np == NULL) fbreak; else fexec np;
|
379
|
-
}
|
380
|
-
|
381
|
-
action parse_array {
|
382
|
-
char *np = JSON_parse_array(json, fpc, pe, &result);
|
383
|
-
if (np == NULL) fbreak; else fexec np;
|
384
|
-
}
|
385
|
-
|
386
|
-
main := ignore* (
|
387
|
-
begin_object >parse_object |
|
388
|
-
begin_array >parse_array
|
389
|
-
) ignore*;
|
390
|
-
}%%
|
391
|
-
|
392
|
-
/*
|
661
|
+
/*
|
393
662
|
* Document-class: JSON::Ext::Parser
|
394
663
|
*
|
395
664
|
* This is the JSON parser implemented as a C extension. It can be configured
|
@@ -401,88 +670,231 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
401
670
|
*
|
402
671
|
*/
|
403
672
|
|
673
|
+
static VALUE convert_encoding(VALUE source)
|
674
|
+
{
|
675
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
676
|
+
rb_encoding *enc = rb_enc_get(source);
|
677
|
+
if (enc == rb_ascii8bit_encoding()) {
|
678
|
+
if (OBJ_FROZEN(source)) {
|
679
|
+
source = rb_str_dup(source);
|
680
|
+
}
|
681
|
+
FORCE_UTF8(source);
|
682
|
+
} else {
|
683
|
+
source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
|
684
|
+
}
|
685
|
+
#endif
|
686
|
+
return source;
|
687
|
+
}
|
688
|
+
|
404
689
|
/*
|
405
|
-
* call-seq: new(source)
|
690
|
+
* call-seq: new(source, opts => {})
|
406
691
|
*
|
407
692
|
* Creates a new JSON::Ext::Parser instance for the string _source_.
|
693
|
+
*
|
694
|
+
* It will be configured by the _opts_ hash. _opts_ can have the following
|
695
|
+
* keys:
|
696
|
+
*
|
697
|
+
* _opts_ can have the following keys:
|
698
|
+
* * *max_nesting*: The maximum depth of nesting allowed in the parsed data
|
699
|
+
* structures. Disable depth checking with :max_nesting => false|nil|0, it
|
700
|
+
* defaults to 100.
|
701
|
+
* * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
|
702
|
+
* defiance of RFC 4627 to be parsed by the Parser. This option defaults to
|
703
|
+
* false.
|
704
|
+
* * *symbolize_names*: If set to true, returns symbols for the names
|
705
|
+
* (keys) in a JSON object. Otherwise strings are returned, which is
|
706
|
+
* also the default. It's not possible to use this option in
|
707
|
+
* conjunction with the *create_additions* option.
|
708
|
+
* * *create_additions*: If set to false, the Parser doesn't create
|
709
|
+
* additions even if a matching class and create_id was found. This option
|
710
|
+
* defaults to false.
|
711
|
+
* * *object_class*: Defaults to Hash
|
712
|
+
* * *array_class*: Defaults to Array
|
408
713
|
*/
|
409
|
-
static VALUE cParser_initialize(VALUE
|
714
|
+
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
410
715
|
{
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
716
|
+
VALUE source, opts;
|
717
|
+
GET_PARSER_INIT;
|
718
|
+
|
719
|
+
if (json->Vsource) {
|
720
|
+
rb_raise(rb_eTypeError, "already initialized instance");
|
721
|
+
}
|
722
|
+
rb_scan_args(argc, argv, "1:", &source, &opts);
|
723
|
+
if (!NIL_P(opts)) {
|
724
|
+
VALUE tmp = ID2SYM(i_max_nesting);
|
725
|
+
if (option_given_p(opts, tmp)) {
|
726
|
+
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
727
|
+
if (RTEST(max_nesting)) {
|
728
|
+
Check_Type(max_nesting, T_FIXNUM);
|
729
|
+
json->max_nesting = FIX2INT(max_nesting);
|
730
|
+
} else {
|
731
|
+
json->max_nesting = 0;
|
732
|
+
}
|
733
|
+
} else {
|
734
|
+
json->max_nesting = 100;
|
735
|
+
}
|
736
|
+
tmp = ID2SYM(i_allow_nan);
|
737
|
+
if (option_given_p(opts, tmp)) {
|
738
|
+
json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
739
|
+
} else {
|
740
|
+
json->allow_nan = 0;
|
741
|
+
}
|
742
|
+
tmp = ID2SYM(i_symbolize_names);
|
743
|
+
if (option_given_p(opts, tmp)) {
|
744
|
+
json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
745
|
+
} else {
|
746
|
+
json->symbolize_names = 0;
|
747
|
+
}
|
748
|
+
tmp = ID2SYM(i_freeze);
|
749
|
+
if (option_given_p(opts, tmp)) {
|
750
|
+
json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
751
|
+
} else {
|
752
|
+
json->freeze = 0;
|
753
|
+
}
|
754
|
+
tmp = ID2SYM(i_create_additions);
|
755
|
+
if (option_given_p(opts, tmp)) {
|
756
|
+
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
|
757
|
+
} else {
|
758
|
+
json->create_additions = 0;
|
759
|
+
}
|
760
|
+
if (json->symbolize_names && json->create_additions) {
|
761
|
+
rb_raise(rb_eArgError,
|
762
|
+
"options :symbolize_names and :create_additions cannot be "
|
763
|
+
" used in conjunction");
|
764
|
+
}
|
765
|
+
tmp = ID2SYM(i_create_id);
|
766
|
+
if (option_given_p(opts, tmp)) {
|
767
|
+
json->create_id = rb_hash_aref(opts, tmp);
|
768
|
+
} else {
|
769
|
+
json->create_id = rb_funcall(mJSON, i_create_id, 0);
|
770
|
+
}
|
771
|
+
tmp = ID2SYM(i_object_class);
|
772
|
+
if (option_given_p(opts, tmp)) {
|
773
|
+
json->object_class = rb_hash_aref(opts, tmp);
|
774
|
+
} else {
|
775
|
+
json->object_class = Qnil;
|
776
|
+
}
|
777
|
+
tmp = ID2SYM(i_array_class);
|
778
|
+
if (option_given_p(opts, tmp)) {
|
779
|
+
json->array_class = rb_hash_aref(opts, tmp);
|
780
|
+
} else {
|
781
|
+
json->array_class = Qnil;
|
782
|
+
}
|
783
|
+
tmp = ID2SYM(i_decimal_class);
|
784
|
+
if (option_given_p(opts, tmp)) {
|
785
|
+
json->decimal_class = rb_hash_aref(opts, tmp);
|
786
|
+
} else {
|
787
|
+
json->decimal_class = Qnil;
|
788
|
+
}
|
789
|
+
tmp = ID2SYM(i_match_string);
|
790
|
+
if (option_given_p(opts, tmp)) {
|
791
|
+
VALUE match_string = rb_hash_aref(opts, tmp);
|
792
|
+
json->match_string = RTEST(match_string) ? match_string : Qnil;
|
793
|
+
} else {
|
794
|
+
json->match_string = Qnil;
|
795
|
+
}
|
796
|
+
} else {
|
797
|
+
json->max_nesting = 100;
|
798
|
+
json->allow_nan = 0;
|
799
|
+
json->create_additions = 0;
|
800
|
+
json->create_id = Qnil;
|
801
|
+
json->object_class = Qnil;
|
802
|
+
json->array_class = Qnil;
|
803
|
+
json->decimal_class = Qnil;
|
804
|
+
}
|
805
|
+
source = convert_encoding(StringValue(source));
|
806
|
+
StringValue(source);
|
807
|
+
json->len = RSTRING_LEN(source);
|
808
|
+
json->source = RSTRING_PTR(source);;
|
434
809
|
json->Vsource = source;
|
435
|
-
json->create_id = rb_funcall(mJSON, i_create_id, 0);
|
436
810
|
return self;
|
437
811
|
}
|
438
812
|
|
813
|
+
%%{
|
814
|
+
machine JSON;
|
815
|
+
|
816
|
+
write data;
|
817
|
+
|
818
|
+
include JSON_common;
|
819
|
+
|
820
|
+
action parse_value {
|
821
|
+
char *np = JSON_parse_value(json, fpc, pe, &result, 0);
|
822
|
+
if (np == NULL) { fhold; fbreak; } else fexec np;
|
823
|
+
}
|
824
|
+
|
825
|
+
main := ignore* (
|
826
|
+
begin_value >parse_value
|
827
|
+
) ignore*;
|
828
|
+
}%%
|
829
|
+
|
439
830
|
/*
|
440
831
|
* call-seq: parse()
|
441
832
|
*
|
442
833
|
* Parses the current JSON text _source_ and returns the complete data
|
443
834
|
* structure as a result.
|
835
|
+
* It raises JSON::ParserError if fail to parse.
|
444
836
|
*/
|
445
837
|
static VALUE cParser_parse(VALUE self)
|
446
838
|
{
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
839
|
+
char *p, *pe;
|
840
|
+
int cs = EVIL;
|
841
|
+
VALUE result = Qnil;
|
842
|
+
GET_PARSER;
|
451
843
|
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
844
|
+
%% write init;
|
845
|
+
p = json->source;
|
846
|
+
pe = p + json->len;
|
847
|
+
%% write exec;
|
456
848
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
849
|
+
if (cs >= JSON_first_final && p == pe) {
|
850
|
+
return result;
|
851
|
+
} else {
|
852
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
853
|
+
return Qnil;
|
854
|
+
}
|
462
855
|
}
|
463
856
|
|
464
|
-
static
|
857
|
+
static void JSON_mark(void *ptr)
|
465
858
|
{
|
466
|
-
JSON_Parser *json =
|
467
|
-
|
468
|
-
|
859
|
+
JSON_Parser *json = ptr;
|
860
|
+
rb_gc_mark_maybe(json->Vsource);
|
861
|
+
rb_gc_mark_maybe(json->create_id);
|
862
|
+
rb_gc_mark_maybe(json->object_class);
|
863
|
+
rb_gc_mark_maybe(json->array_class);
|
864
|
+
rb_gc_mark_maybe(json->decimal_class);
|
865
|
+
rb_gc_mark_maybe(json->match_string);
|
469
866
|
}
|
470
867
|
|
471
|
-
static void
|
868
|
+
static void JSON_free(void *ptr)
|
472
869
|
{
|
473
|
-
|
474
|
-
|
870
|
+
JSON_Parser *json = ptr;
|
871
|
+
fbuffer_free(json->fbuffer);
|
872
|
+
ruby_xfree(json);
|
475
873
|
}
|
476
874
|
|
477
|
-
static
|
875
|
+
static size_t JSON_memsize(const void *ptr)
|
478
876
|
{
|
479
|
-
|
877
|
+
const JSON_Parser *json = ptr;
|
878
|
+
return sizeof(*json) + FBUFFER_CAPA(json->fbuffer);
|
480
879
|
}
|
481
880
|
|
881
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
882
|
+
static const rb_data_type_t JSON_Parser_type = {
|
883
|
+
"JSON/Parser",
|
884
|
+
{JSON_mark, JSON_free, JSON_memsize,},
|
885
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
886
|
+
0, 0,
|
887
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
888
|
+
#endif
|
889
|
+
};
|
890
|
+
#endif
|
891
|
+
|
482
892
|
static VALUE cJSON_parser_s_allocate(VALUE klass)
|
483
893
|
{
|
484
|
-
JSON_Parser *json
|
485
|
-
|
894
|
+
JSON_Parser *json;
|
895
|
+
VALUE obj = TypedData_Make_Struct(klass, JSON_Parser, &JSON_Parser_type, json);
|
896
|
+
json->fbuffer = fbuffer_alloc(0);
|
897
|
+
return obj;
|
486
898
|
}
|
487
899
|
|
488
900
|
/*
|
@@ -493,23 +905,67 @@ static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
493
905
|
*/
|
494
906
|
static VALUE cParser_source(VALUE self)
|
495
907
|
{
|
496
|
-
|
908
|
+
GET_PARSER;
|
497
909
|
return rb_str_dup(json->Vsource);
|
498
910
|
}
|
499
911
|
|
500
|
-
void Init_parser()
|
912
|
+
void Init_parser(void)
|
501
913
|
{
|
914
|
+
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
915
|
+
rb_ext_ractor_safe(true);
|
916
|
+
#endif
|
917
|
+
|
918
|
+
#undef rb_intern
|
919
|
+
rb_require("json/common");
|
502
920
|
mJSON = rb_define_module("JSON");
|
503
921
|
mExt = rb_define_module_under(mJSON, "Ext");
|
504
922
|
cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
|
505
923
|
eParserError = rb_path2class("JSON::ParserError");
|
924
|
+
eNestingError = rb_path2class("JSON::NestingError");
|
925
|
+
rb_gc_register_mark_object(eParserError);
|
926
|
+
rb_gc_register_mark_object(eNestingError);
|
506
927
|
rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
|
507
|
-
rb_define_method(cParser, "initialize", cParser_initialize, 1);
|
928
|
+
rb_define_method(cParser, "initialize", cParser_initialize, -1);
|
508
929
|
rb_define_method(cParser, "parse", cParser_parse, 0);
|
509
930
|
rb_define_method(cParser, "source", cParser_source, 0);
|
510
931
|
|
932
|
+
CNaN = rb_const_get(mJSON, rb_intern("NaN"));
|
933
|
+
rb_gc_register_mark_object(CNaN);
|
934
|
+
|
935
|
+
CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
|
936
|
+
rb_gc_register_mark_object(CInfinity);
|
937
|
+
|
938
|
+
CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
|
939
|
+
rb_gc_register_mark_object(CMinusInfinity);
|
940
|
+
|
511
941
|
i_json_creatable_p = rb_intern("json_creatable?");
|
512
942
|
i_json_create = rb_intern("json_create");
|
513
943
|
i_create_id = rb_intern("create_id");
|
944
|
+
i_create_additions = rb_intern("create_additions");
|
514
945
|
i_chr = rb_intern("chr");
|
946
|
+
i_max_nesting = rb_intern("max_nesting");
|
947
|
+
i_allow_nan = rb_intern("allow_nan");
|
948
|
+
i_symbolize_names = rb_intern("symbolize_names");
|
949
|
+
i_object_class = rb_intern("object_class");
|
950
|
+
i_array_class = rb_intern("array_class");
|
951
|
+
i_decimal_class = rb_intern("decimal_class");
|
952
|
+
i_match = rb_intern("match");
|
953
|
+
i_match_string = rb_intern("match_string");
|
954
|
+
i_key_p = rb_intern("key?");
|
955
|
+
i_deep_const_get = rb_intern("deep_const_get");
|
956
|
+
i_aset = rb_intern("[]=");
|
957
|
+
i_aref = rb_intern("[]");
|
958
|
+
i_leftshift = rb_intern("<<");
|
959
|
+
i_new = rb_intern("new");
|
960
|
+
i_try_convert = rb_intern("try_convert");
|
961
|
+
i_freeze = rb_intern("freeze");
|
962
|
+
i_uminus = rb_intern("-@");
|
515
963
|
}
|
964
|
+
|
965
|
+
/*
|
966
|
+
* Local variables:
|
967
|
+
* mode: c
|
968
|
+
* c-file-style: ruby
|
969
|
+
* indent-tabs-mode: nil
|
970
|
+
* End:
|
971
|
+
*/
|