json_pure 2.4.0 → 2.4.1

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