json 1.8.3 → 2.5.1

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