json 2.0.3 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +66 -0
  3. data/Gemfile +1 -3
  4. data/LICENSE +56 -0
  5. data/README.md +54 -21
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +229 -54
  9. data/ext/json/ext/generator/generator.h +5 -3
  10. data/ext/json/ext/parser/extconf.rb +25 -0
  11. data/ext/json/ext/parser/parser.c +180 -85
  12. data/ext/json/ext/parser/parser.h +2 -0
  13. data/ext/json/ext/parser/parser.rl +104 -9
  14. data/ext/json/extconf.rb +1 -0
  15. data/json.gemspec +0 -0
  16. data/lib/json/add/bigdecimal.rb +2 -2
  17. data/lib/json/add/complex.rb +2 -3
  18. data/lib/json/add/ostruct.rb +1 -1
  19. data/lib/json/add/rational.rb +2 -3
  20. data/lib/json/add/regexp.rb +2 -2
  21. data/lib/json/add/set.rb +29 -0
  22. data/lib/json/common.rb +372 -125
  23. data/lib/json/pure/generator.rb +31 -10
  24. data/lib/json/pure/parser.rb +35 -5
  25. data/lib/json/version.rb +1 -1
  26. data/lib/json.rb +549 -29
  27. data/tests/fixtures/fail29.json +1 -0
  28. data/tests/fixtures/fail30.json +1 -0
  29. data/tests/fixtures/fail31.json +1 -0
  30. data/tests/fixtures/fail32.json +1 -0
  31. data/tests/json_addition_test.rb +6 -0
  32. data/tests/json_common_interface_test.rb +47 -4
  33. data/tests/json_encoding_test.rb +2 -0
  34. data/tests/json_fixtures_test.rb +9 -1
  35. data/tests/json_generator_test.rb +30 -8
  36. data/tests/json_parser_test.rb +43 -12
  37. data/tests/lib/core_assertions.rb +763 -0
  38. data/tests/lib/envutil.rb +365 -0
  39. data/tests/lib/find_executable.rb +22 -0
  40. data/tests/lib/helper.rb +4 -0
  41. data/tests/ractor_test.rb +30 -0
  42. data/tests/test_helper.rb +3 -7
  43. metadata +31 -44
  44. data/.gitignore +0 -17
  45. data/.travis.yml +0 -19
  46. data/README-json-jruby.md +0 -33
  47. data/Rakefile +0 -408
  48. data/data/example.json +0 -1
  49. data/data/index.html +0 -38
  50. data/data/prototype.js +0 -4184
  51. data/diagrams/.keep +0 -0
  52. data/install.rb +0 -23
  53. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  54. data/java/src/json/ext/Generator.java +0 -443
  55. data/java/src/json/ext/GeneratorMethods.java +0 -231
  56. data/java/src/json/ext/GeneratorService.java +0 -42
  57. data/java/src/json/ext/GeneratorState.java +0 -490
  58. data/java/src/json/ext/OptionsReader.java +0 -113
  59. data/java/src/json/ext/Parser.java +0 -2347
  60. data/java/src/json/ext/Parser.rl +0 -878
  61. data/java/src/json/ext/ParserService.java +0 -34
  62. data/java/src/json/ext/RuntimeInfo.java +0 -116
  63. data/java/src/json/ext/StringDecoder.java +0 -166
  64. data/java/src/json/ext/StringEncoder.java +0 -111
  65. data/java/src/json/ext/Utils.java +0 -88
  66. data/json-java.gemspec +0 -38
  67. data/json_pure.gemspec +0 -38
  68. data/references/rfc7159.txt +0 -899
  69. data/tools/diff.sh +0 -18
  70. data/tools/fuzz.rb +0 -131
  71. data/tools/server.rb +0 -62
@@ -1,878 +0,0 @@
1
- /*
2
- * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
- *
4
- * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
5
- */
6
- package json.ext;
7
-
8
- import org.jruby.Ruby;
9
- import org.jruby.RubyArray;
10
- import org.jruby.RubyClass;
11
- import org.jruby.RubyEncoding;
12
- import org.jruby.RubyFloat;
13
- import org.jruby.RubyHash;
14
- import org.jruby.RubyInteger;
15
- import org.jruby.RubyModule;
16
- import org.jruby.RubyNumeric;
17
- import org.jruby.RubyObject;
18
- import org.jruby.RubyString;
19
- import org.jruby.anno.JRubyMethod;
20
- import org.jruby.exceptions.JumpException;
21
- import org.jruby.exceptions.RaiseException;
22
- import org.jruby.runtime.Block;
23
- import org.jruby.runtime.ObjectAllocator;
24
- import org.jruby.runtime.ThreadContext;
25
- import org.jruby.runtime.Visibility;
26
- import org.jruby.runtime.builtin.IRubyObject;
27
- import org.jruby.util.ByteList;
28
- import org.jruby.util.ConvertBytes;
29
- import static org.jruby.util.ConvertDouble.DoubleConverter;
30
-
31
- /**
32
- * The <code>JSON::Ext::Parser</code> class.
33
- *
34
- * <p>This is the JSON parser implemented as a Java class. To use it as the
35
- * standard parser, set
36
- * <pre>JSON.parser = JSON::Ext::Parser</pre>
37
- * This is performed for you when you <code>include "json/ext"</code>.
38
- *
39
- * <p>This class does not perform the actual parsing, just acts as an interface
40
- * to Ruby code. When the {@link #parse()} method is invoked, a
41
- * Parser.ParserSession object is instantiated, which handles the process.
42
- *
43
- * @author mernen
44
- */
45
- public class Parser extends RubyObject {
46
- private final RuntimeInfo info;
47
- private RubyString vSource;
48
- private RubyString createId;
49
- private boolean createAdditions;
50
- private int maxNesting;
51
- private boolean allowNaN;
52
- private boolean symbolizeNames;
53
- private RubyClass objectClass;
54
- private RubyClass arrayClass;
55
- private RubyHash matchString;
56
-
57
- private static final int DEFAULT_MAX_NESTING = 100;
58
-
59
- private static final ByteList JSON_MINUS_INFINITY = new ByteList(ByteList.plain("-Infinity"));
60
- // constant names in the JSON module containing those values
61
- private static final String CONST_NAN = "NaN";
62
- private static final String CONST_INFINITY = "Infinity";
63
- private static final String CONST_MINUS_INFINITY = "MinusInfinity";
64
-
65
- static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
66
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
67
- return new Parser(runtime, klazz);
68
- }
69
- };
70
-
71
- /**
72
- * Multiple-value return for internal parser methods.
73
- *
74
- * <p>All the <code>parse<var>Stuff</var></code> methods return instances of
75
- * <code>ParserResult</code> when successful, or <code>null</code> when
76
- * there's a problem with the input data.
77
- */
78
- static final class ParserResult {
79
- /**
80
- * The result of the successful parsing. Should never be
81
- * <code>null</code>.
82
- */
83
- IRubyObject result;
84
- /**
85
- * The point where the parser returned.
86
- */
87
- int p;
88
-
89
- void update(IRubyObject result, int p) {
90
- this.result = result;
91
- this.p = p;
92
- }
93
- }
94
-
95
- public Parser(Ruby runtime, RubyClass metaClass) {
96
- super(runtime, metaClass);
97
- info = RuntimeInfo.forRuntime(runtime);
98
- }
99
-
100
- /**
101
- * <code>Parser.new(source, opts = {})</code>
102
- *
103
- * <p>Creates a new <code>JSON::Ext::Parser</code> instance for the string
104
- * <code>source</code>.
105
- * It will be configured by the <code>opts</code> Hash.
106
- * <code>opts</code> can have the following keys:
107
- *
108
- * <dl>
109
- * <dt><code>:max_nesting</code>
110
- * <dd>The maximum depth of nesting allowed in the parsed data
111
- * structures. Disable depth checking with <code>:max_nesting => false|nil|0</code>,
112
- * it defaults to 100.
113
- *
114
- * <dt><code>:allow_nan</code>
115
- * <dd>If set to <code>true</code>, allow <code>NaN</code>,
116
- * <code>Infinity</code> and <code>-Infinity</code> in defiance of RFC 4627
117
- * to be parsed by the Parser. This option defaults to <code>false</code>.
118
- *
119
- * <dt><code>:symbolize_names</code>
120
- * <dd>If set to <code>true</code>, returns symbols for the names (keys) in
121
- * a JSON object. Otherwise strings are returned, which is also the default.
122
- *
123
- * <dt><code>:create_additions</code>
124
- * <dd>If set to <code>false</code>, the Parser doesn't create additions
125
- * even if a matching class and <code>create_id</code> was found. This option
126
- * defaults to <code>true</code>.
127
- *
128
- * <dt><code>:object_class</code>
129
- * <dd>Defaults to Hash.
130
- *
131
- * <dt><code>:array_class</code>
132
- * <dd>Defaults to Array.
133
- *
134
- * </dl>
135
- */
136
- @JRubyMethod(name = "new", required = 1, optional = 1, meta = true)
137
- public static IRubyObject newInstance(IRubyObject clazz, IRubyObject[] args, Block block) {
138
- Parser parser = (Parser)((RubyClass)clazz).allocate();
139
-
140
- parser.callInit(args, block);
141
-
142
- return parser;
143
- }
144
-
145
- @JRubyMethod(required = 1, optional = 1, visibility = Visibility.PRIVATE)
146
- public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
147
- Ruby runtime = context.getRuntime();
148
- if (this.vSource != null) {
149
- throw runtime.newTypeError("already initialized instance");
150
- }
151
-
152
- OptionsReader opts = new OptionsReader(context, args.length > 1 ? args[1] : null);
153
- this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
154
- this.allowNaN = opts.getBool("allow_nan", false);
155
- this.symbolizeNames = opts.getBool("symbolize_names", false);
156
- this.createId = opts.getString("create_id", getCreateId(context));
157
- this.createAdditions = opts.getBool("create_additions", false);
158
- this.objectClass = opts.getClass("object_class", runtime.getHash());
159
- this.arrayClass = opts.getClass("array_class", runtime.getArray());
160
- this.matchString = opts.getHash("match_string");
161
-
162
- if(symbolizeNames && createAdditions) {
163
- throw runtime.newArgumentError(
164
- "options :symbolize_names and :create_additions cannot be " +
165
- " used in conjunction"
166
- );
167
- }
168
- this.vSource = args[0].convertToString();
169
- this.vSource = convertEncoding(context, vSource);
170
-
171
- return this;
172
- }
173
-
174
- /**
175
- * Checks the given string's encoding. If a non-UTF-8 encoding is detected,
176
- * a converted copy is returned.
177
- * Returns the source string if no conversion is needed.
178
- */
179
- private RubyString convertEncoding(ThreadContext context, RubyString source) {
180
- RubyEncoding encoding = (RubyEncoding)source.encoding(context);
181
- if (encoding == info.ascii8bit.get()) {
182
- if (source.isFrozen()) {
183
- source = (RubyString) source.dup();
184
- }
185
- source.force_encoding(context, info.utf8.get());
186
- } else {
187
- source = (RubyString) source.encode(context, info.utf8.get());
188
- }
189
- return source;
190
- }
191
-
192
- /**
193
- * Checks the first four bytes of the given ByteList to infer its encoding,
194
- * using the principle demonstrated on section 3 of RFC 4627 (JSON).
195
- */
196
- private static String sniffByteList(ByteList bl) {
197
- if (bl.length() < 4) return null;
198
- if (bl.get(0) == 0 && bl.get(2) == 0) {
199
- return bl.get(1) == 0 ? "utf-32be" : "utf-16be";
200
- }
201
- if (bl.get(1) == 0 && bl.get(3) == 0) {
202
- return bl.get(2) == 0 ? "utf-32le" : "utf-16le";
203
- }
204
- return null;
205
- }
206
-
207
- /**
208
- * Assumes the given (binary) RubyString to be in the given encoding, then
209
- * converts it to UTF-8.
210
- */
211
- private RubyString reinterpretEncoding(ThreadContext context,
212
- RubyString str, String sniffedEncoding) {
213
- RubyEncoding actualEncoding = info.getEncoding(context, sniffedEncoding);
214
- RubyEncoding targetEncoding = info.utf8.get();
215
- RubyString dup = (RubyString)str.dup();
216
- dup.force_encoding(context, actualEncoding);
217
- return (RubyString)dup.encode_bang(context, targetEncoding);
218
- }
219
-
220
- /**
221
- * <code>Parser#parse()</code>
222
- *
223
- * <p>Parses the current JSON text <code>source</code> and returns the
224
- * complete data structure as a result.
225
- */
226
- @JRubyMethod
227
- public IRubyObject parse(ThreadContext context) {
228
- return new ParserSession(this, context, info).parse();
229
- }
230
-
231
- /**
232
- * <code>Parser#source()</code>
233
- *
234
- * <p>Returns a copy of the current <code>source</code> string, that was
235
- * used to construct this Parser.
236
- */
237
- @JRubyMethod(name = "source")
238
- public IRubyObject source_get() {
239
- return checkAndGetSource().dup();
240
- }
241
-
242
- public RubyString checkAndGetSource() {
243
- if (vSource != null) {
244
- return vSource;
245
- } else {
246
- throw getRuntime().newTypeError("uninitialized instance");
247
- }
248
- }
249
-
250
- /**
251
- * Queries <code>JSON.create_id</code>. Returns <code>null</code> if it is
252
- * set to <code>nil</code> or <code>false</code>, and a String if not.
253
- */
254
- private RubyString getCreateId(ThreadContext context) {
255
- IRubyObject v = info.jsonModule.get().callMethod(context, "create_id");
256
- return v.isTrue() ? v.convertToString() : null;
257
- }
258
-
259
- /**
260
- * A string parsing session.
261
- *
262
- * <p>Once a ParserSession is instantiated, the source string should not
263
- * change until the parsing is complete. The ParserSession object assumes
264
- * the source {@link RubyString} is still associated to its original
265
- * {@link ByteList}, which in turn must still be bound to the same
266
- * <code>byte[]</code> value (and on the same offset).
267
- */
268
- // Ragel uses lots of fall-through
269
- @SuppressWarnings("fallthrough")
270
- private static class ParserSession {
271
- private final Parser parser;
272
- private final ThreadContext context;
273
- private final RuntimeInfo info;
274
- private final ByteList byteList;
275
- private final ByteList view;
276
- private final byte[] data;
277
- private final StringDecoder decoder;
278
- private int currentNesting = 0;
279
- private final DoubleConverter dc;
280
-
281
- // initialization value for all state variables.
282
- // no idea about the origins of this value, ask Flori ;)
283
- private static final int EVIL = 0x666;
284
-
285
- private ParserSession(Parser parser, ThreadContext context, RuntimeInfo info) {
286
- this.parser = parser;
287
- this.context = context;
288
- this.info = info;
289
- this.byteList = parser.checkAndGetSource().getByteList();
290
- this.data = byteList.unsafeBytes();
291
- this.view = new ByteList(data, false);
292
- this.decoder = new StringDecoder(context);
293
- this.dc = new DoubleConverter();
294
- }
295
-
296
- private RaiseException unexpectedToken(int absStart, int absEnd) {
297
- RubyString msg = getRuntime().newString("unexpected token at '")
298
- .cat(data, absStart, absEnd - absStart)
299
- .cat((byte)'\'');
300
- return newException(Utils.M_PARSER_ERROR, msg);
301
- }
302
-
303
- private Ruby getRuntime() {
304
- return context.getRuntime();
305
- }
306
-
307
- %%{
308
- machine JSON_common;
309
-
310
- cr = '\n';
311
- cr_neg = [^\n];
312
- ws = [ \t\r\n];
313
- c_comment = '/*' ( any* - (any* '*/' any* ) ) '*/';
314
- cpp_comment = '//' cr_neg* cr;
315
- comment = c_comment | cpp_comment;
316
- ignore = ws | comment;
317
- name_separator = ':';
318
- value_separator = ',';
319
- Vnull = 'null';
320
- Vfalse = 'false';
321
- Vtrue = 'true';
322
- VNaN = 'NaN';
323
- VInfinity = 'Infinity';
324
- VMinusInfinity = '-Infinity';
325
- begin_value = [nft"\-[{NI] | digit;
326
- begin_object = '{';
327
- end_object = '}';
328
- begin_array = '[';
329
- end_array = ']';
330
- begin_string = '"';
331
- begin_name = begin_string;
332
- begin_number = digit | '-';
333
- }%%
334
-
335
- %%{
336
- machine JSON_value;
337
- include JSON_common;
338
-
339
- write data;
340
-
341
- action parse_null {
342
- result = getRuntime().getNil();
343
- }
344
- action parse_false {
345
- result = getRuntime().getFalse();
346
- }
347
- action parse_true {
348
- result = getRuntime().getTrue();
349
- }
350
- action parse_nan {
351
- if (parser.allowNaN) {
352
- result = getConstant(CONST_NAN);
353
- } else {
354
- throw unexpectedToken(p - 2, pe);
355
- }
356
- }
357
- action parse_infinity {
358
- if (parser.allowNaN) {
359
- result = getConstant(CONST_INFINITY);
360
- } else {
361
- throw unexpectedToken(p - 7, pe);
362
- }
363
- }
364
- action parse_number {
365
- if (pe > fpc + 8 &&
366
- absSubSequence(fpc, fpc + 9).equals(JSON_MINUS_INFINITY)) {
367
-
368
- if (parser.allowNaN) {
369
- result = getConstant(CONST_MINUS_INFINITY);
370
- fexec p + 10;
371
- fhold;
372
- fbreak;
373
- } else {
374
- throw unexpectedToken(p, pe);
375
- }
376
- }
377
- parseFloat(res, fpc, pe);
378
- if (res.result != null) {
379
- result = res.result;
380
- fexec res.p;
381
- }
382
- parseInteger(res, fpc, pe);
383
- if (res.result != null) {
384
- result = res.result;
385
- fexec res.p;
386
- }
387
- fhold;
388
- fbreak;
389
- }
390
- action parse_string {
391
- parseString(res, fpc, pe);
392
- if (res.result == null) {
393
- fhold;
394
- fbreak;
395
- } else {
396
- result = res.result;
397
- fexec res.p;
398
- }
399
- }
400
- action parse_array {
401
- currentNesting++;
402
- parseArray(res, fpc, pe);
403
- currentNesting--;
404
- if (res.result == null) {
405
- fhold;
406
- fbreak;
407
- } else {
408
- result = res.result;
409
- fexec res.p;
410
- }
411
- }
412
- action parse_object {
413
- currentNesting++;
414
- parseObject(res, fpc, pe);
415
- currentNesting--;
416
- if (res.result == null) {
417
- fhold;
418
- fbreak;
419
- } else {
420
- result = res.result;
421
- fexec res.p;
422
- }
423
- }
424
- action exit {
425
- fhold;
426
- fbreak;
427
- }
428
-
429
- main := ( Vnull @parse_null |
430
- Vfalse @parse_false |
431
- Vtrue @parse_true |
432
- VNaN @parse_nan |
433
- VInfinity @parse_infinity |
434
- begin_number >parse_number |
435
- begin_string >parse_string |
436
- begin_array >parse_array |
437
- begin_object >parse_object
438
- ) %*exit;
439
- }%%
440
-
441
- void parseValue(ParserResult res, int p, int pe) {
442
- int cs = EVIL;
443
- IRubyObject result = null;
444
-
445
- %% write init;
446
- %% write exec;
447
-
448
- if (cs >= JSON_value_first_final && result != null) {
449
- res.update(result, p);
450
- } else {
451
- res.update(null, p);
452
- }
453
- }
454
-
455
- %%{
456
- machine JSON_integer;
457
-
458
- write data;
459
-
460
- action exit {
461
- fhold;
462
- fbreak;
463
- }
464
-
465
- main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9]? @exit );
466
- }%%
467
-
468
- void parseInteger(ParserResult res, int p, int pe) {
469
- int new_p = parseIntegerInternal(p, pe);
470
- if (new_p == -1) {
471
- res.update(null, p);
472
- return;
473
- }
474
- RubyInteger number = createInteger(p, new_p);
475
- res.update(number, new_p + 1);
476
- return;
477
- }
478
-
479
- int parseIntegerInternal(int p, int pe) {
480
- int cs = EVIL;
481
-
482
- %% write init;
483
- int memo = p;
484
- %% write exec;
485
-
486
- if (cs < JSON_integer_first_final) {
487
- return -1;
488
- }
489
-
490
- return p;
491
- }
492
-
493
- RubyInteger createInteger(int p, int new_p) {
494
- Ruby runtime = getRuntime();
495
- ByteList num = absSubSequence(p, new_p);
496
- return bytesToInum(runtime, num);
497
- }
498
-
499
- RubyInteger bytesToInum(Ruby runtime, ByteList num) {
500
- return runtime.is1_9() ?
501
- ConvertBytes.byteListToInum19(runtime, num, 10, true) :
502
- ConvertBytes.byteListToInum(runtime, num, 10, true);
503
- }
504
-
505
- %%{
506
- machine JSON_float;
507
- include JSON_common;
508
-
509
- write data;
510
-
511
- action exit {
512
- fhold;
513
- fbreak;
514
- }
515
-
516
- main := '-'?
517
- ( ( ( '0' | [1-9][0-9]* ) '.' [0-9]+ ( [Ee] [+\-]?[0-9]+ )? )
518
- | ( ( '0' | [1-9][0-9]* ) ( [Ee] [+\-]? [0-9]+ ) ) )
519
- ( ^[0-9Ee.\-]? @exit );
520
- }%%
521
-
522
- void parseFloat(ParserResult res, int p, int pe) {
523
- int new_p = parseFloatInternal(p, pe);
524
- if (new_p == -1) {
525
- res.update(null, p);
526
- return;
527
- }
528
- RubyFloat number = createFloat(p, new_p);
529
- res.update(number, new_p + 1);
530
- return;
531
- }
532
-
533
- int parseFloatInternal(int p, int pe) {
534
- int cs = EVIL;
535
-
536
- %% write init;
537
- int memo = p;
538
- %% write exec;
539
-
540
- if (cs < JSON_float_first_final) {
541
- return -1;
542
- }
543
-
544
- return p;
545
- }
546
-
547
- RubyFloat createFloat(int p, int new_p) {
548
- Ruby runtime = getRuntime();
549
- ByteList num = absSubSequence(p, new_p);
550
- return RubyFloat.newFloat(runtime, dc.parse(num, true, runtime.is1_9()));
551
- }
552
-
553
- %%{
554
- machine JSON_string;
555
- include JSON_common;
556
-
557
- write data;
558
-
559
- action parse_string {
560
- int offset = byteList.begin();
561
- ByteList decoded = decoder.decode(byteList, memo + 1 - offset,
562
- p - offset);
563
- result = getRuntime().newString(decoded);
564
- if (result == null) {
565
- fhold;
566
- fbreak;
567
- } else {
568
- fexec p + 1;
569
- }
570
- }
571
-
572
- action exit {
573
- fhold;
574
- fbreak;
575
- }
576
-
577
- main := '"'
578
- ( ( ^(["\\]|0..0x1f)
579
- | '\\'["\\/bfnrt]
580
- | '\\u'[0-9a-fA-F]{4}
581
- | '\\'^(["\\/bfnrtu]|0..0x1f)
582
- )* %parse_string
583
- ) '"' @exit;
584
- }%%
585
-
586
- void parseString(ParserResult res, int p, int pe) {
587
- int cs = EVIL;
588
- IRubyObject result = null;
589
-
590
- %% write init;
591
- int memo = p;
592
- %% write exec;
593
-
594
- if (parser.createAdditions) {
595
- RubyHash matchString = parser.matchString;
596
- if (matchString != null) {
597
- final IRubyObject[] memoArray = { result, null };
598
- try {
599
- matchString.visitAll(new RubyHash.Visitor() {
600
- @Override
601
- public void visit(IRubyObject pattern, IRubyObject klass) {
602
- if (pattern.callMethod(context, "===", memoArray[0]).isTrue()) {
603
- memoArray[1] = klass;
604
- throw JumpException.SPECIAL_JUMP;
605
- }
606
- }
607
- });
608
- } catch (JumpException e) { }
609
- if (memoArray[1] != null) {
610
- RubyClass klass = (RubyClass) memoArray[1];
611
- if (klass.respondsTo("json_creatable?") &&
612
- klass.callMethod(context, "json_creatable?").isTrue()) {
613
- result = klass.callMethod(context, "json_create", result);
614
- }
615
- }
616
- }
617
- }
618
-
619
- if (cs >= JSON_string_first_final && result != null) {
620
- if (result instanceof RubyString) {
621
- ((RubyString)result).force_encoding(context, info.utf8.get());
622
- }
623
- res.update(result, p + 1);
624
- } else {
625
- res.update(null, p + 1);
626
- }
627
- }
628
-
629
- %%{
630
- machine JSON_array;
631
- include JSON_common;
632
-
633
- write data;
634
-
635
- action parse_value {
636
- parseValue(res, fpc, pe);
637
- if (res.result == null) {
638
- fhold;
639
- fbreak;
640
- } else {
641
- if (parser.arrayClass == getRuntime().getArray()) {
642
- ((RubyArray)result).append(res.result);
643
- } else {
644
- result.callMethod(context, "<<", res.result);
645
- }
646
- fexec res.p;
647
- }
648
- }
649
-
650
- action exit {
651
- fhold;
652
- fbreak;
653
- }
654
-
655
- next_element = value_separator ignore* begin_value >parse_value;
656
-
657
- main := begin_array
658
- ignore*
659
- ( ( begin_value >parse_value
660
- ignore* )
661
- ( ignore*
662
- next_element
663
- ignore* )* )?
664
- ignore*
665
- end_array @exit;
666
- }%%
667
-
668
- void parseArray(ParserResult res, int p, int pe) {
669
- int cs = EVIL;
670
-
671
- if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) {
672
- throw newException(Utils.M_NESTING_ERROR,
673
- "nesting of " + currentNesting + " is too deep");
674
- }
675
-
676
- IRubyObject result;
677
- if (parser.arrayClass == getRuntime().getArray()) {
678
- result = RubyArray.newArray(getRuntime());
679
- } else {
680
- result = parser.arrayClass.newInstance(context,
681
- IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
682
- }
683
-
684
- %% write init;
685
- %% write exec;
686
-
687
- if (cs >= JSON_array_first_final) {
688
- res.update(result, p + 1);
689
- } else {
690
- throw unexpectedToken(p, pe);
691
- }
692
- }
693
-
694
- %%{
695
- machine JSON_object;
696
- include JSON_common;
697
-
698
- write data;
699
-
700
- action parse_value {
701
- parseValue(res, fpc, pe);
702
- if (res.result == null) {
703
- fhold;
704
- fbreak;
705
- } else {
706
- if (parser.objectClass == getRuntime().getHash()) {
707
- ((RubyHash)result).op_aset(context, lastName, res.result);
708
- } else {
709
- result.callMethod(context, "[]=", new IRubyObject[] { lastName, res.result });
710
- }
711
- fexec res.p;
712
- }
713
- }
714
-
715
- action parse_name {
716
- parseString(res, fpc, pe);
717
- if (res.result == null) {
718
- fhold;
719
- fbreak;
720
- } else {
721
- RubyString name = (RubyString)res.result;
722
- if (parser.symbolizeNames) {
723
- lastName = context.getRuntime().is1_9()
724
- ? name.intern19()
725
- : name.intern();
726
- } else {
727
- lastName = name;
728
- }
729
- fexec res.p;
730
- }
731
- }
732
-
733
- action exit {
734
- fhold;
735
- fbreak;
736
- }
737
-
738
- pair = ignore* begin_name >parse_name ignore* name_separator
739
- ignore* begin_value >parse_value;
740
- next_pair = ignore* value_separator pair;
741
-
742
- main := (
743
- begin_object (pair (next_pair)*)? ignore* end_object
744
- ) @exit;
745
- }%%
746
-
747
- void parseObject(ParserResult res, int p, int pe) {
748
- int cs = EVIL;
749
- IRubyObject lastName = null;
750
- boolean objectDefault = true;
751
-
752
- if (parser.maxNesting > 0 && currentNesting > parser.maxNesting) {
753
- throw newException(Utils.M_NESTING_ERROR,
754
- "nesting of " + currentNesting + " is too deep");
755
- }
756
-
757
- // this is guaranteed to be a RubyHash due to the earlier
758
- // allocator test at OptionsReader#getClass
759
- IRubyObject result;
760
- if (parser.objectClass == getRuntime().getHash()) {
761
- result = RubyHash.newHash(getRuntime());
762
- } else {
763
- objectDefault = false;
764
- result = parser.objectClass.newInstance(context,
765
- IRubyObject.NULL_ARRAY, Block.NULL_BLOCK);
766
- }
767
-
768
- %% write init;
769
- %% write exec;
770
-
771
- if (cs < JSON_object_first_final) {
772
- res.update(null, p + 1);
773
- return;
774
- }
775
-
776
- IRubyObject returnedResult = result;
777
-
778
- // attempt to de-serialize object
779
- if (parser.createAdditions) {
780
- IRubyObject vKlassName;
781
- if (objectDefault) {
782
- vKlassName = ((RubyHash)result).op_aref(context, parser.createId);
783
- } else {
784
- vKlassName = result.callMethod(context, "[]", parser.createId);
785
- }
786
-
787
- if (!vKlassName.isNil()) {
788
- // might throw ArgumentError, we let it propagate
789
- IRubyObject klass = parser.info.jsonModule.get().
790
- callMethod(context, "deep_const_get", vKlassName);
791
- if (klass.respondsTo("json_creatable?") &&
792
- klass.callMethod(context, "json_creatable?").isTrue()) {
793
-
794
- returnedResult = klass.callMethod(context, "json_create", result);
795
- }
796
- }
797
- }
798
- res.update(returnedResult, p + 1);
799
- }
800
-
801
- %%{
802
- machine JSON;
803
- include JSON_common;
804
-
805
- write data;
806
-
807
- action parse_value {
808
- parseValue(res, fpc, pe);
809
- if (res.result == null) {
810
- fhold;
811
- fbreak;
812
- } else {
813
- result = res.result;
814
- fexec res.p;
815
- }
816
- }
817
-
818
- main := ignore*
819
- ( begin_value >parse_value)
820
- ignore*;
821
- }%%
822
-
823
- public IRubyObject parseImplemetation() {
824
- int cs = EVIL;
825
- int p, pe;
826
- IRubyObject result = null;
827
- ParserResult res = new ParserResult();
828
-
829
- %% write init;
830
- p = byteList.begin();
831
- pe = p + byteList.length();
832
- %% write exec;
833
-
834
- if (cs >= JSON_first_final && p == pe) {
835
- return result;
836
- } else {
837
- throw unexpectedToken(p, pe);
838
- }
839
- }
840
-
841
- public IRubyObject parse() {
842
- return parseImplemetation();
843
- }
844
-
845
- /**
846
- * Updates the "view" bytelist with the new offsets and returns it.
847
- * @param start
848
- * @param end
849
- */
850
- private ByteList absSubSequence(int absStart, int absEnd) {
851
- view.setBegin(absStart);
852
- view.setRealSize(absEnd - absStart);
853
- return view;
854
- }
855
-
856
- /**
857
- * Retrieves a constant directly descended from the <code>JSON</code> module.
858
- * @param name The constant name
859
- */
860
- private IRubyObject getConstant(String name) {
861
- return parser.info.jsonModule.get().getConstant(name);
862
- }
863
-
864
- private RaiseException newException(String className, String message) {
865
- return Utils.newException(context, className, message);
866
- }
867
-
868
- private RaiseException newException(String className, RubyString message) {
869
- return Utils.newException(context, className, message);
870
- }
871
-
872
- private RaiseException newException(String className,
873
- String messageBegin, ByteList messageEnd) {
874
- return newException(className,
875
- getRuntime().newString(messageBegin).cat(messageEnd));
876
- }
877
- }
878
- }