json 2.0.3 → 2.5.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.
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
- }