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