json 1.8.6 → 2.5.1

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