json 1.8.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +251 -87
  3. data/{COPYING-json-jruby → LICENSE} +5 -6
  4. data/README.md +425 -0
  5. data/VERSION +1 -1
  6. data/ext/json/ext/fbuffer/fbuffer.h +10 -4
  7. data/ext/json/ext/generator/extconf.rb +0 -10
  8. data/ext/json/ext/generator/generator.c +308 -135
  9. data/ext/json/ext/generator/generator.h +35 -9
  10. data/ext/json/ext/parser/extconf.rb +25 -6
  11. data/ext/json/ext/parser/parser.c +3035 -1901
  12. data/ext/json/ext/parser/parser.h +29 -10
  13. data/ext/json/ext/parser/parser.rl +261 -211
  14. data/ext/json/extconf.rb +3 -0
  15. data/json.gemspec +57 -27
  16. data/lib/json/add/bigdecimal.rb +3 -2
  17. data/lib/json/add/complex.rb +9 -3
  18. data/lib/json/add/core.rb +1 -0
  19. data/lib/json/add/date.rb +1 -1
  20. data/lib/json/add/date_time.rb +1 -1
  21. data/lib/json/add/exception.rb +1 -1
  22. data/lib/json/add/ostruct.rb +3 -3
  23. data/lib/json/add/range.rb +1 -1
  24. data/lib/json/add/rational.rb +8 -3
  25. data/lib/json/add/regexp.rb +3 -3
  26. data/lib/json/add/set.rb +29 -0
  27. data/lib/json/add/struct.rb +1 -1
  28. data/lib/json/add/symbol.rb +1 -1
  29. data/lib/json/add/time.rb +2 -2
  30. data/lib/json/common.rb +383 -167
  31. data/lib/json/ext.rb +0 -6
  32. data/lib/json/generic_object.rb +5 -4
  33. data/lib/json/pure/generator.rb +83 -126
  34. data/lib/json/pure/parser.rb +63 -85
  35. data/lib/json/pure.rb +2 -8
  36. data/lib/json/version.rb +2 -1
  37. data/lib/json.rb +550 -29
  38. metadata +29 -136
  39. data/.gitignore +0 -12
  40. data/.travis.yml +0 -20
  41. data/COPYING +0 -58
  42. data/GPL +0 -340
  43. data/Gemfile +0 -11
  44. data/README-json-jruby.markdown +0 -33
  45. data/README.rdoc +0 -358
  46. data/Rakefile +0 -412
  47. data/TODO +0 -1
  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 -167
  54. data/java/src/json/ext/Generator.java +0 -444
  55. data/java/src/json/ext/GeneratorMethods.java +0 -232
  56. data/java/src/json/ext/GeneratorService.java +0 -43
  57. data/java/src/json/ext/GeneratorState.java +0 -543
  58. data/java/src/json/ext/OptionsReader.java +0 -114
  59. data/java/src/json/ext/Parser.java +0 -2644
  60. data/java/src/json/ext/Parser.rl +0 -968
  61. data/java/src/json/ext/ParserService.java +0 -35
  62. data/java/src/json/ext/RuntimeInfo.java +0 -121
  63. data/java/src/json/ext/StringDecoder.java +0 -167
  64. data/java/src/json/ext/StringEncoder.java +0 -106
  65. data/java/src/json/ext/Utils.java +0 -89
  66. data/json-java.gemspec +0 -23
  67. data/json_pure.gemspec +0 -39
  68. data/lib/json/ext/.keep +0 -0
  69. data/tests/fixtures/fail1.json +0 -1
  70. data/tests/fixtures/fail10.json +0 -1
  71. data/tests/fixtures/fail11.json +0 -1
  72. data/tests/fixtures/fail12.json +0 -1
  73. data/tests/fixtures/fail13.json +0 -1
  74. data/tests/fixtures/fail14.json +0 -1
  75. data/tests/fixtures/fail18.json +0 -1
  76. data/tests/fixtures/fail19.json +0 -1
  77. data/tests/fixtures/fail2.json +0 -1
  78. data/tests/fixtures/fail20.json +0 -1
  79. data/tests/fixtures/fail21.json +0 -1
  80. data/tests/fixtures/fail22.json +0 -1
  81. data/tests/fixtures/fail23.json +0 -1
  82. data/tests/fixtures/fail24.json +0 -1
  83. data/tests/fixtures/fail25.json +0 -1
  84. data/tests/fixtures/fail27.json +0 -2
  85. data/tests/fixtures/fail28.json +0 -2
  86. data/tests/fixtures/fail3.json +0 -1
  87. data/tests/fixtures/fail4.json +0 -1
  88. data/tests/fixtures/fail5.json +0 -1
  89. data/tests/fixtures/fail6.json +0 -1
  90. data/tests/fixtures/fail7.json +0 -1
  91. data/tests/fixtures/fail8.json +0 -1
  92. data/tests/fixtures/fail9.json +0 -1
  93. data/tests/fixtures/pass1.json +0 -56
  94. data/tests/fixtures/pass15.json +0 -1
  95. data/tests/fixtures/pass16.json +0 -1
  96. data/tests/fixtures/pass17.json +0 -1
  97. data/tests/fixtures/pass2.json +0 -1
  98. data/tests/fixtures/pass26.json +0 -1
  99. data/tests/fixtures/pass3.json +0 -6
  100. data/tests/setup_variant.rb +0 -11
  101. data/tests/test_json.rb +0 -545
  102. data/tests/test_json_addition.rb +0 -196
  103. data/tests/test_json_encoding.rb +0 -65
  104. data/tests/test_json_fixtures.rb +0 -35
  105. data/tests/test_json_generate.rb +0 -322
  106. data/tests/test_json_generic_object.rb +0 -75
  107. data/tests/test_json_string_matching.rb +0 -39
  108. data/tests/test_json_unicode.rb +0 -72
  109. data/tools/fuzz.rb +0 -139
  110. 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 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 matchin 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).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 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) {
317
- this.parser = parser;
318
- this.context = context;
319
- this.byteList = parser.checkAndGetSource().getByteList();
320
- this.data = byteList.unsafeBytes();
321
- this.view = new ByteList(data, false);
322
- this.decoder = new StringDecoder(context);
323
- this.dc = new DoubleConverter();
324
- }
325
-
326
- private RaiseException unexpectedToken(int absStart, int absEnd) {
327
- RubyString msg = getRuntime().newString("unexpected token at '")
328
- .cat(data, absStart, absEnd - absStart)
329
- .cat((byte)'\'');
330
- return newException(Utils.M_PARSER_ERROR, msg);
331
- }
332
-
333
- private Ruby getRuntime() {
334
- return context.getRuntime();
335
- }
336
-
337
- %%{
338
- machine JSON_common;
339
-
340
- cr = '\n';
341
- cr_neg = [^\n];
342
- ws = [ \t\r\n];
343
- c_comment = '/*' ( any* - (any* '*/' any* ) ) '*/';
344
- cpp_comment = '//' cr_neg* cr;
345
- comment = c_comment | cpp_comment;
346
- ignore = ws | comment;
347
- name_separator = ':';
348
- value_separator = ',';
349
- Vnull = 'null';
350
- Vfalse = 'false';
351
- Vtrue = 'true';
352
- VNaN = 'NaN';
353
- VInfinity = 'Infinity';
354
- VMinusInfinity = '-Infinity';
355
- begin_value = [nft"\-[{NI] | digit;
356
- begin_object = '{';
357
- end_object = '}';
358
- begin_array = '[';
359
- end_array = ']';
360
- begin_string = '"';
361
- begin_name = begin_string;
362
- begin_number = digit | '-';
363
- }%%
364
-
365
- %%{
366
- machine JSON_value;
367
- include JSON_common;
368
-
369
- write data;
370
-
371
- action parse_null {
372
- result = getRuntime().getNil();
373
- }
374
- action parse_false {
375
- result = getRuntime().getFalse();
376
- }
377
- action parse_true {
378
- result = getRuntime().getTrue();
379
- }
380
- action parse_nan {
381
- if (parser.allowNaN) {
382
- result = getConstant(CONST_NAN);
383
- } else {
384
- throw unexpectedToken(p - 2, pe);
385
- }
386
- }
387
- action parse_infinity {
388
- if (parser.allowNaN) {
389
- result = getConstant(CONST_INFINITY);
390
- } else {
391
- throw unexpectedToken(p - 7, pe);
392
- }
393
- }
394
- action parse_number {
395
- if (pe > fpc + 9 - (parser.quirksMode ? 1 : 0) &&
396
- absSubSequence(fpc, fpc + 9).equals(JSON_MINUS_INFINITY)) {
397
-
398
- if (parser.allowNaN) {
399
- result = getConstant(CONST_MINUS_INFINITY);
400
- fexec p + 10;
401
- fhold;
402
- fbreak;
403
- } else {
404
- throw unexpectedToken(p, pe);
405
- }
406
- }
407
- parseFloat(res, fpc, pe);
408
- if (res.result != null) {
409
- result = res.result;
410
- fexec res.p;
411
- }
412
- parseInteger(res, fpc, pe);
413
- if (res.result != null) {
414
- result = res.result;
415
- fexec res.p;
416
- }
417
- fhold;
418
- fbreak;
419
- }
420
- action parse_string {
421
- parseString(res, fpc, pe);
422
- if (res.result == null) {
423
- fhold;
424
- fbreak;
425
- } else {
426
- result = res.result;
427
- fexec res.p;
428
- }
429
- }
430
- action parse_array {
431
- currentNesting++;
432
- parseArray(res, fpc, pe);
433
- currentNesting--;
434
- if (res.result == null) {
435
- fhold;
436
- fbreak;
437
- } else {
438
- result = res.result;
439
- fexec res.p;
440
- }
441
- }
442
- action parse_object {
443
- currentNesting++;
444
- parseObject(res, fpc, pe);
445
- currentNesting--;
446
- if (res.result == null) {
447
- fhold;
448
- fbreak;
449
- } else {
450
- result = res.result;
451
- fexec res.p;
452
- }
453
- }
454
- action exit {
455
- fhold;
456
- fbreak;
457
- }
458
-
459
- main := ( Vnull @parse_null |
460
- Vfalse @parse_false |
461
- Vtrue @parse_true |
462
- VNaN @parse_nan |
463
- VInfinity @parse_infinity |
464
- begin_number >parse_number |
465
- begin_string >parse_string |
466
- begin_array >parse_array |
467
- begin_object >parse_object
468
- ) %*exit;
469
- }%%
470
-
471
- void parseValue(ParserResult res, int p, int pe) {
472
- int cs = EVIL;
473
- IRubyObject result = null;
474
-
475
- %% write init;
476
- %% write exec;
477
-
478
- if (cs >= JSON_value_first_final && result != null) {
479
- res.update(result, p);
480
- } else {
481
- res.update(null, p);
482
- }
483
- }
484
-
485
- %%{
486
- machine JSON_integer;
487
-
488
- write data;
489
-
490
- action exit {
491
- fhold;
492
- fbreak;
493
- }
494
-
495
- main := '-'? ( '0' | [1-9][0-9]* ) ( ^[0-9]? @exit );
496
- }%%
497
-
498
- void parseInteger(ParserResult res, int p, int pe) {
499
- int new_p = parseIntegerInternal(p, pe);
500
- if (new_p == -1) {
501
- res.update(null, p);
502
- return;
503
- }
504
- RubyInteger number = createInteger(p, new_p);
505
- res.update(number, new_p + 1);
506
- return;
507
- }
508
-
509
- int parseIntegerInternal(int p, int pe) {
510
- int cs = EVIL;
511
-
512
- %% write init;
513
- int memo = p;
514
- %% write exec;
515
-
516
- if (cs < JSON_integer_first_final) {
517
- return -1;
518
- }
519
-
520
- return p;
521
- }
522
-
523
- RubyInteger createInteger(int p, int new_p) {
524
- Ruby runtime = getRuntime();
525
- ByteList num = absSubSequence(p, new_p);
526
- return bytesToInum(runtime, num);
527
- }
528
-
529
- RubyInteger bytesToInum(Ruby runtime, ByteList num) {
530
- return runtime.is1_9() ?
531
- ConvertBytes.byteListToInum19(runtime, num, 10, true) :
532
- ConvertBytes.byteListToInum(runtime, num, 10, true);
533
- }
534
-
535
- %%{
536
- machine JSON_float;
537
- include JSON_common;
538
-
539
- write data;
540
-
541
- action exit {
542
- fhold;
543
- fbreak;
544
- }
545
-
546
- main := '-'?
547
- ( ( ( '0' | [1-9][0-9]* ) '.' [0-9]+ ( [Ee] [+\-]?[0-9]+ )? )
548
- | ( ( '0' | [1-9][0-9]* ) ( [Ee] [+\-]? [0-9]+ ) ) )
549
- ( ^[0-9Ee.\-]? @exit );
550
- }%%
551
-
552
- void parseFloat(ParserResult res, int p, int pe) {
553
- int new_p = parseFloatInternal(p, pe);
554
- if (new_p == -1) {
555
- res.update(null, p);
556
- return;
557
- }
558
- RubyFloat number = createFloat(p, new_p);
559
- res.update(number, new_p + 1);
560
- return;
561
- }
562
-
563
- int parseFloatInternal(int p, int pe) {
564
- int cs = EVIL;
565
-
566
- %% write init;
567
- int memo = p;
568
- %% write exec;
569
-
570
- if (cs < JSON_float_first_final) {
571
- return -1;
572
- }
573
-
574
- return p;
575
- }
576
-
577
- RubyFloat createFloat(int p, int new_p) {
578
- Ruby runtime = getRuntime();
579
- ByteList num = absSubSequence(p, new_p);
580
- return RubyFloat.newFloat(runtime, dc.parse(num, true, runtime.is1_9()));
581
- }
582
-
583
- %%{
584
- machine JSON_string;
585
- include JSON_common;
586
-
587
- write data;
588
-
589
- action parse_string {
590
- int offset = byteList.begin();
591
- ByteList decoded = decoder.decode(byteList, memo + 1 - offset,
592
- p - offset);
593
- result = getRuntime().newString(decoded);
594
- if (result == null) {
595
- fhold;
596
- fbreak;
597
- } else {
598
- fexec p + 1;
599
- }
600
- }
601
-
602
- action exit {
603
- fhold;
604
- fbreak;
605
- }
606
-
607
- main := '"'
608
- ( ( ^(["\\]|0..0x1f)
609
- | '\\'["\\/bfnrt]
610
- | '\\u'[0-9a-fA-F]{4}
611
- | '\\'^(["\\/bfnrtu]|0..0x1f)
612
- )* %parse_string
613
- ) '"' @exit;
614
- }%%
615
-
616
- void parseString(ParserResult res, int p, int pe) {
617
- int cs = EVIL;
618
- IRubyObject result = null;
619
-
620
- %% write init;
621
- int memo = p;
622
- %% write exec;
623
-
624
- if (parser.createAdditions) {
625
- RubyHash match_string = parser.match_string;
626
- if (match_string != null) {
627
- final IRubyObject[] memoArray = { result, null };
628
- try {
629
- match_string.visitAll(new RubyHash.Visitor() {
630
- @Override
631
- public void visit(IRubyObject pattern, IRubyObject klass) {
632
- if (pattern.callMethod(context, "===", memoArray[0]).isTrue()) {
633
- memoArray[1] = klass;
634
- throw JumpException.SPECIAL_JUMP;
635
- }
636
- }
637
- });
638
- } catch (JumpException e) { }
639
- if (memoArray[1] != null) {
640
- RubyClass klass = (RubyClass) memoArray[1];
641
- if (klass.respondsTo("json_creatable?") &&
642
- klass.callMethod(context, "json_creatable?").isTrue()) {
643
- result = klass.callMethod(context, "json_create", result);
644
- }
645
- }
646
- }
647
- }
648
-
649
- if (cs >= JSON_string_first_final && result != null) {
650
- RuntimeInfo info = RuntimeInfo.forRuntime(context.getRuntime());
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
- }