ffde2ee86d432b39ee0607beb0ba3a131b6c8b53
[packages/precise/mcollective.git] / lib / mcollective / vendor / json / ext / json / ext / parser / parser.rl
1 #include "parser.h"
2
3 /* unicode */
4
5 static const char digit_values[256] = {
6     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
7     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
9     -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
10     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
11     10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
12     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
13     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
14     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
15     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
16     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
17     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
18     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
19     -1, -1, -1, -1, -1, -1, -1
20 };
21
22 static UTF32 unescape_unicode(const unsigned char *p)
23 {
24     char b;
25     UTF32 result = 0;
26     b = digit_values[p[0]];
27     if (b < 0) return UNI_REPLACEMENT_CHAR;
28     result = (result << 4) | b;
29     b = digit_values[p[1]];
30     result = (result << 4) | b;
31     if (b < 0) return UNI_REPLACEMENT_CHAR;
32     b = digit_values[p[2]];
33     result = (result << 4) | b;
34     if (b < 0) return UNI_REPLACEMENT_CHAR;
35     b = digit_values[p[3]];
36     result = (result << 4) | b;
37     if (b < 0) return UNI_REPLACEMENT_CHAR;
38     return result;
39 }
40
41 static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
42 {
43     int len = 1;
44     if (ch <= 0x7F) {
45         buf[0] = (char) ch;
46     } else if (ch <= 0x07FF) {
47         buf[0] = (char) ((ch >> 6) | 0xC0);
48         buf[1] = (char) ((ch & 0x3F) | 0x80);
49         len++;
50     } else if (ch <= 0xFFFF) {
51         buf[0] = (char) ((ch >> 12) | 0xE0);
52         buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
53         buf[2] = (char) ((ch & 0x3F) | 0x80);
54         len += 2;
55     } else if (ch <= 0x1fffff) {
56         buf[0] =(char) ((ch >> 18) | 0xF0);
57         buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
58         buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
59         buf[3] =(char) ((ch & 0x3F) | 0x80);
60         len += 3;
61     } else {
62         buf[0] = '?';
63     }
64     return len;
65 }
66
67 #ifdef HAVE_RUBY_ENCODING_H
68 static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,
69     CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;
70 static ID i_encoding, i_encode;
71 #else
72 static ID i_iconv;
73 #endif
74
75 static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
76 static VALUE CNaN, CInfinity, CMinusInfinity;
77
78 static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
79           i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_quirks_mode,
80           i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match,
81           i_match_string, i_aset, i_leftshift;
82
83 %%{
84     machine JSON_common;
85
86     cr                  = '\n';
87     cr_neg              = [^\n];
88     ws                  = [ \t\r\n];
89     c_comment           = '/*' ( any* - (any* '*/' any* ) ) '*/';
90     cpp_comment         = '//' cr_neg* cr;
91     comment             = c_comment | cpp_comment;
92     ignore              = ws | comment;
93     name_separator      = ':';
94     value_separator     = ',';
95     Vnull               = 'null';
96     Vfalse              = 'false';
97     Vtrue               = 'true';
98     VNaN                = 'NaN';
99     VInfinity           = 'Infinity';
100     VMinusInfinity      = '-Infinity';
101     begin_value         = [nft\"\-\[\{NI] | digit;
102     begin_object        = '{';
103     end_object          = '}';
104     begin_array         = '[';
105     end_array           = ']';
106     begin_string        = '"';
107     begin_name          = begin_string;
108     begin_number        = digit | '-';
109 }%%
110
111 %%{
112     machine JSON_object;
113     include JSON_common;
114
115     write data;
116
117     action parse_value {
118         VALUE v = Qnil;
119         char *np = JSON_parse_value(json, fpc, pe, &v);
120         if (np == NULL) {
121             fhold; fbreak;
122         } else {
123             if (NIL_P(json->object_class)) {
124                 rb_hash_aset(*result, last_name, v);
125             } else {
126                 rb_funcall(*result, i_aset, 2, last_name, v);
127             }
128             fexec np;
129         }
130     }
131
132     action parse_name {
133         char *np;
134         json->parsing_name = 1;
135         np = JSON_parse_string(json, fpc, pe, &last_name);
136         json->parsing_name = 0;
137         if (np == NULL) { fhold; fbreak; } else fexec np;
138     }
139
140     action exit { fhold; fbreak; }
141
142     pair  = ignore* begin_name >parse_name ignore* name_separator ignore* begin_value >parse_value;
143     next_pair   = ignore* value_separator pair;
144
145     main := (
146       begin_object
147       (pair (next_pair)*)? ignore*
148       end_object
149     ) @exit;
150 }%%
151
152 static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)
153 {
154     int cs = EVIL;
155     VALUE last_name = Qnil;
156     VALUE object_class = json->object_class;
157
158     if (json->max_nesting && json->current_nesting > json->max_nesting) {
159         rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
160     }
161
162     *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
163
164     %% write init;
165     %% write exec;
166
167     if (cs >= JSON_object_first_final) {
168         if (json->create_additions) {
169             VALUE klassname = rb_hash_aref(*result, json->create_id);
170             if (!NIL_P(klassname)) {
171                 VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
172                 if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
173                     *result = rb_funcall(klass, i_json_create, 1, *result);
174                 }
175             }
176         }
177         return p + 1;
178     } else {
179         return NULL;
180     }
181 }
182
183
184 %%{
185     machine JSON_value;
186     include JSON_common;
187
188     write data;
189
190     action parse_null {
191         *result = Qnil;
192     }
193     action parse_false {
194         *result = Qfalse;
195     }
196     action parse_true {
197         *result = Qtrue;
198     }
199     action parse_nan {
200         if (json->allow_nan) {
201             *result = CNaN;
202         } else {
203             rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2);
204         }
205     }
206     action parse_infinity {
207         if (json->allow_nan) {
208             *result = CInfinity;
209         } else {
210             rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8);
211         }
212     }
213     action parse_string {
214         char *np = JSON_parse_string(json, fpc, pe, result);
215         if (np == NULL) { fhold; fbreak; } else fexec np;
216     }
217
218     action parse_number {
219         char *np;
220         if(pe > fpc + 9 - json->quirks_mode && !strncmp(MinusInfinity, fpc, 9)) {
221             if (json->allow_nan) {
222                 *result = CMinusInfinity;
223                 fexec p + 10;
224                 fhold; fbreak;
225             } else {
226                 rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
227             }
228         }
229         np = JSON_parse_float(json, fpc, pe, result);
230         if (np != NULL) fexec np;
231         np = JSON_parse_integer(json, fpc, pe, result);
232         if (np != NULL) fexec np;
233         fhold; fbreak;
234     }
235
236     action parse_array {
237         char *np;
238         json->current_nesting++;
239         np = JSON_parse_array(json, fpc, pe, result);
240         json->current_nesting--;
241         if (np == NULL) { fhold; fbreak; } else fexec np;
242     }
243
244     action parse_object {
245         char *np;
246         json->current_nesting++;
247         np =  JSON_parse_object(json, fpc, pe, result);
248         json->current_nesting--;
249         if (np == NULL) { fhold; fbreak; } else fexec np;
250     }
251
252     action exit { fhold; fbreak; }
253
254 main := (
255               Vnull @parse_null |
256               Vfalse @parse_false |
257               Vtrue @parse_true |
258               VNaN @parse_nan |
259               VInfinity @parse_infinity |
260               begin_number >parse_number |
261               begin_string >parse_string |
262               begin_array >parse_array |
263               begin_object >parse_object
264         ) %*exit;
265 }%%
266
267 static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)
268 {
269     int cs = EVIL;
270
271     %% write init;
272     %% write exec;
273
274     if (cs >= JSON_value_first_final) {
275         return p;
276     } else {
277         return NULL;
278     }
279 }
280
281 %%{
282     machine JSON_integer;
283
284     write data;
285
286     action exit { fhold; fbreak; }
287
288     main := '-'? ('0' | [1-9][0-9]*) (^[0-9]? @exit);
289 }%%
290
291 static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
292 {
293     int cs = EVIL;
294
295     %% write init;
296     json->memo = p;
297     %% write exec;
298
299     if (cs >= JSON_integer_first_final) {
300         long len = p - json->memo;
301         *result = rb_Integer(rb_str_new(json->memo, len));
302         return p + 1;
303     } else {
304         return NULL;
305     }
306 }
307
308 %%{
309     machine JSON_float;
310     include JSON_common;
311
312     write data;
313
314     action exit { fhold; fbreak; }
315
316     main := '-'? (
317               (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
318               | (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
319              )  (^[0-9Ee.\-]? @exit );
320 }%%
321
322 static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
323 {
324     int cs = EVIL;
325
326     %% write init;
327     json->memo = p;
328     %% write exec;
329
330     if (cs >= JSON_float_first_final) {
331         long len = p - json->memo;
332         *result = rb_Float(rb_str_new(json->memo, len));
333         return p + 1;
334     } else {
335         return NULL;
336     }
337 }
338
339
340 %%{
341     machine JSON_array;
342     include JSON_common;
343
344     write data;
345
346     action parse_value {
347         VALUE v = Qnil;
348         char *np = JSON_parse_value(json, fpc, pe, &v);
349         if (np == NULL) {
350             fhold; fbreak;
351         } else {
352             if (NIL_P(json->array_class)) {
353                 rb_ary_push(*result, v);
354             } else {
355                 rb_funcall(*result, i_leftshift, 1, v);
356             }
357             fexec np;
358         }
359     }
360
361     action exit { fhold; fbreak; }
362
363     next_element  = value_separator ignore* begin_value >parse_value;
364
365     main := begin_array ignore*
366           ((begin_value >parse_value ignore*)
367            (ignore* next_element ignore*)*)?
368           end_array @exit;
369 }%%
370
371 static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)
372 {
373     int cs = EVIL;
374     VALUE array_class = json->array_class;
375
376     if (json->max_nesting && json->current_nesting > json->max_nesting) {
377         rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
378     }
379     *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
380
381     %% write init;
382     %% write exec;
383
384     if(cs >= JSON_array_first_final) {
385         return p + 1;
386     } else {
387         rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
388         return NULL;
389     }
390 }
391
392 static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
393 {
394     char *p = string, *pe = string, *unescape;
395     int unescape_len;
396
397     while (pe < stringEnd) {
398         if (*pe == '\\') {
399             unescape = (char *) "?";
400             unescape_len = 1;
401             if (pe > p) rb_str_buf_cat(result, p, pe - p);
402             switch (*++pe) {
403                 case 'n':
404                     unescape = (char *) "\n";
405                     break;
406                 case 'r':
407                     unescape = (char *) "\r";
408                     break;
409                 case 't':
410                     unescape = (char *) "\t";
411                     break;
412                 case '"':
413                     unescape = (char *) "\"";
414                     break;
415                 case '\\':
416                     unescape = (char *) "\\";
417                     break;
418                 case 'b':
419                     unescape = (char *) "\b";
420                     break;
421                 case 'f':
422                     unescape = (char *) "\f";
423                     break;
424                 case 'u':
425                     if (pe > stringEnd - 4) {
426                         return Qnil;
427                     } else {
428                         char buf[4];
429                         UTF32 ch = unescape_unicode((unsigned char *) ++pe);
430                         pe += 3;
431                         if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
432                             pe++;
433                             if (pe > stringEnd - 6) return Qnil;
434                             if (pe[0] == '\\' && pe[1] == 'u') {
435                                 UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
436                                 ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
437                                         | (sur & 0x3FF));
438                                 pe += 5;
439                             } else {
440                                 unescape = (char *) "?";
441                                 break;
442                             }
443                         }
444                         unescape_len = convert_UTF32_to_UTF8(buf, ch);
445                         unescape = buf;
446                     }
447                     break;
448                 default:
449                     p = pe;
450                     continue;
451             }
452             rb_str_buf_cat(result, unescape, unescape_len);
453             p = ++pe;
454         } else {
455             pe++;
456         }
457     }
458     rb_str_buf_cat(result, p, pe - p);
459     return result;
460 }
461
462 %%{
463     machine JSON_string;
464     include JSON_common;
465
466     write data;
467
468     action parse_string {
469         *result = json_string_unescape(*result, json->memo + 1, p);
470         if (NIL_P(*result)) {
471             fhold;
472             fbreak;
473         } else {
474             FORCE_UTF8(*result);
475             fexec p + 1;
476         }
477     }
478
479     action exit { fhold; fbreak; }
480
481     main := '"' ((^([\"\\] | 0..0x1f) | '\\'[\"\\/bfnrt] | '\\u'[0-9a-fA-F]{4} | '\\'^([\"\\/bfnrtu]|0..0x1f))* %parse_string) '"' @exit;
482 }%%
483
484 static int
485 match_i(VALUE regexp, VALUE klass, VALUE memo)
486 {
487     if (regexp == Qundef) return ST_STOP;
488     if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
489       RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
490         rb_ary_push(memo, klass);
491         return ST_STOP;
492     }
493     return ST_CONTINUE;
494 }
495
496 static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
497 {
498     int cs = EVIL;
499     VALUE match_string;
500
501     *result = rb_str_buf_new(0);
502     %% write init;
503     json->memo = p;
504     %% write exec;
505
506     if (json->create_additions && RTEST(match_string = json->match_string)) {
507           VALUE klass;
508           VALUE memo = rb_ary_new2(2);
509           rb_ary_push(memo, *result);
510           rb_hash_foreach(match_string, match_i, memo);
511           klass = rb_ary_entry(memo, 1);
512           if (RTEST(klass)) {
513               *result = rb_funcall(klass, i_json_create, 1, *result);
514           }
515     }
516
517     if (json->symbolize_names && json->parsing_name) {
518       *result = rb_str_intern(*result);
519     }
520     if (cs >= JSON_string_first_final) {
521         return p + 1;
522     } else {
523         return NULL;
524     }
525 }
526
527 /*
528  * Document-class: JSON::Ext::Parser
529  *
530  * This is the JSON parser implemented as a C extension. It can be configured
531  * to be used by setting
532  *
533  *  JSON.parser = JSON::Ext::Parser
534  *
535  * with the method parser= in JSON.
536  *
537  */
538
539 static VALUE convert_encoding(VALUE source)
540 {
541     char *ptr = RSTRING_PTR(source);
542     long len = RSTRING_LEN(source);
543     if (len < 2) {
544         rb_raise(eParserError, "A JSON text must at least contain two octets!");
545     }
546 #ifdef HAVE_RUBY_ENCODING_H
547     {
548         VALUE encoding = rb_funcall(source, i_encoding, 0);
549         if (encoding == CEncoding_ASCII_8BIT) {
550             if (len >= 4 &&  ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
551                 source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_32BE);
552             } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
553                 source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_16BE);
554             } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
555                 source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_32LE);
556             } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
557                 source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_16LE);
558             } else {
559                 source = rb_str_dup(source);
560                 FORCE_UTF8(source);
561             }
562         } else {
563             source = rb_funcall(source, i_encode, 1, CEncoding_UTF_8);
564         }
565     }
566 #else
567     if (len >= 4 &&  ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
568       source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-32be"), source);
569     } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
570       source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-16be"), source);
571     } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
572       source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-32le"), source);
573     } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
574       source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-16le"), source);
575     }
576 #endif
577     return source;
578 }
579
580 /*
581  * call-seq: new(source, opts => {})
582  *
583  * Creates a new JSON::Ext::Parser instance for the string _source_.
584  *
585  * Creates a new JSON::Ext::Parser instance for the string _source_.
586  *
587  * It will be configured by the _opts_ hash. _opts_ can have the following
588  * keys:
589  *
590  * _opts_ can have the following keys:
591  * * *max_nesting*: The maximum depth of nesting allowed in the parsed data
592  *   structures. Disable depth checking with :max_nesting => false|nil|0, it
593  *   defaults to 19.
594  * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
595  *   defiance of RFC 4627 to be parsed by the Parser. This option defaults to
596  *   false.
597  * * *symbolize_names*: If set to true, returns symbols for the names
598  *   (keys) in a JSON object. Otherwise strings are returned, which is also
599  *   the default.
600  * * *create_additions*: If set to false, the Parser doesn't create
601  *   additions even if a matchin class and create_id was found. This option
602  *   defaults to true.
603  * * *object_class*: Defaults to Hash
604  * * *array_class*: Defaults to Array
605  * * *quirks_mode*: Enables quirks_mode for parser, that is for example
606  *   parsing single JSON values instead of documents is possible.
607  *
608  */
609 static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
610 {
611     VALUE source, opts;
612     GET_PARSER_INIT;
613
614     if (json->Vsource) {
615         rb_raise(rb_eTypeError, "already initialized instance");
616     }
617     rb_scan_args(argc, argv, "11", &source, &opts);
618     if (!NIL_P(opts)) {
619         opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
620         if (NIL_P(opts)) {
621             rb_raise(rb_eArgError, "opts needs to be like a hash");
622         } else {
623             VALUE tmp = ID2SYM(i_max_nesting);
624             if (option_given_p(opts, tmp)) {
625                 VALUE max_nesting = rb_hash_aref(opts, tmp);
626                 if (RTEST(max_nesting)) {
627                     Check_Type(max_nesting, T_FIXNUM);
628                     json->max_nesting = FIX2INT(max_nesting);
629                 } else {
630                     json->max_nesting = 0;
631                 }
632             } else {
633                 json->max_nesting = 19;
634             }
635             tmp = ID2SYM(i_allow_nan);
636             if (option_given_p(opts, tmp)) {
637                 json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
638             } else {
639                 json->allow_nan = 0;
640             }
641             tmp = ID2SYM(i_symbolize_names);
642             if (option_given_p(opts, tmp)) {
643                 json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
644             } else {
645                 json->symbolize_names = 0;
646             }
647             tmp = ID2SYM(i_quirks_mode);
648             if (option_given_p(opts, tmp)) {
649                 VALUE quirks_mode = rb_hash_aref(opts, tmp);
650                 json->quirks_mode = RTEST(quirks_mode) ? 1 : 0;
651             } else {
652                 json->quirks_mode = 0;
653             }
654             tmp = ID2SYM(i_create_additions);
655             if (option_given_p(opts, tmp)) {
656                 json->create_additions = RTEST(rb_hash_aref(opts, tmp));
657             } else {
658                 json->create_additions = 0;
659             }
660             tmp = ID2SYM(i_create_id);
661             if (option_given_p(opts, tmp)) {
662                 json->create_id = rb_hash_aref(opts, tmp);
663             } else {
664                 json->create_id = rb_funcall(mJSON, i_create_id, 0);
665             }
666             tmp = ID2SYM(i_object_class);
667             if (option_given_p(opts, tmp)) {
668                 json->object_class = rb_hash_aref(opts, tmp);
669             } else {
670                 json->object_class = Qnil;
671             }
672             tmp = ID2SYM(i_array_class);
673             if (option_given_p(opts, tmp)) {
674                 json->array_class = rb_hash_aref(opts, tmp);
675             } else {
676                 json->array_class = Qnil;
677             }
678             tmp = ID2SYM(i_match_string);
679             if (option_given_p(opts, tmp)) {
680                 VALUE match_string = rb_hash_aref(opts, tmp);
681                 json->match_string = RTEST(match_string) ? match_string : Qnil;
682             } else {
683                 json->match_string = Qnil;
684             }
685         }
686     } else {
687         json->max_nesting = 19;
688         json->allow_nan = 0;
689         json->create_additions = 1;
690         json->create_id = rb_funcall(mJSON, i_create_id, 0);
691         json->object_class = Qnil;
692         json->array_class = Qnil;
693     }
694     if (!json->quirks_mode) {
695       source = convert_encoding(StringValue(source));
696     }
697     json->current_nesting = 0;
698     json->len = RSTRING_LEN(source);
699     json->source = RSTRING_PTR(source);;
700     json->Vsource = source;
701     return self;
702 }
703
704 %%{
705     machine JSON;
706
707     write data;
708
709     include JSON_common;
710
711     action parse_object {
712         char *np;
713         json->current_nesting = 1;
714         np = JSON_parse_object(json, fpc, pe, &result);
715         if (np == NULL) { fhold; fbreak; } else fexec np;
716     }
717
718     action parse_array {
719         char *np;
720         json->current_nesting = 1;
721         np = JSON_parse_array(json, fpc, pe, &result);
722         if (np == NULL) { fhold; fbreak; } else fexec np;
723     }
724
725     main := ignore* (
726             begin_object >parse_object |
727             begin_array >parse_array
728             ) ignore*;
729 }%%
730
731 static VALUE cParser_parse_strict(VALUE self)
732 {
733     char *p, *pe;
734     int cs = EVIL;
735     VALUE result = Qnil;
736     GET_PARSER;
737
738     %% write init;
739     p = json->source;
740     pe = p + json->len;
741     %% write exec;
742
743     if (cs >= JSON_first_final && p == pe) {
744         return result;
745     } else {
746         rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
747         return Qnil;
748     }
749 }
750
751
752 %%{
753     machine JSON_quirks_mode;
754
755     write data;
756
757     include JSON_common;
758
759     action parse_value {
760         char *np = JSON_parse_value(json, fpc, pe, &result);
761         if (np == NULL) { fhold; fbreak; } else fexec np;
762     }
763
764     main := ignore* (
765             begin_value >parse_value
766             ) ignore*;
767 }%%
768
769 static VALUE cParser_parse_quirks_mode(VALUE self)
770 {
771     char *p, *pe;
772     int cs = EVIL;
773     VALUE result = Qnil;
774     GET_PARSER;
775
776     %% write init;
777     p = json->source;
778     pe = p + json->len;
779     %% write exec;
780
781     if (cs >= JSON_quirks_mode_first_final && p == pe) {
782         return result;
783     } else {
784         rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
785         return Qnil;
786     }
787 }
788
789 /*
790  * call-seq: parse()
791  *
792  *  Parses the current JSON text _source_ and returns the complete data
793  *  structure as a result.
794  */
795 static VALUE cParser_parse(VALUE self)
796 {
797   GET_PARSER;
798
799   if (json->quirks_mode) {
800     return cParser_parse_quirks_mode(self);
801   } else {
802     return cParser_parse_strict(self);
803   }
804 }
805
806
807 static JSON_Parser *JSON_allocate()
808 {
809     JSON_Parser *json = ALLOC(JSON_Parser);
810     MEMZERO(json, JSON_Parser, 1);
811     return json;
812 }
813
814 static void JSON_mark(JSON_Parser *json)
815 {
816     rb_gc_mark_maybe(json->Vsource);
817     rb_gc_mark_maybe(json->create_id);
818     rb_gc_mark_maybe(json->object_class);
819     rb_gc_mark_maybe(json->array_class);
820     rb_gc_mark_maybe(json->match_string);
821 }
822
823 static void JSON_free(JSON_Parser *json)
824 {
825     ruby_xfree(json);
826 }
827
828 static VALUE cJSON_parser_s_allocate(VALUE klass)
829 {
830     JSON_Parser *json = JSON_allocate();
831     return Data_Wrap_Struct(klass, JSON_mark, JSON_free, json);
832 }
833
834 /*
835  * call-seq: source()
836  *
837  * Returns a copy of the current _source_ string, that was used to construct
838  * this Parser.
839  */
840 static VALUE cParser_source(VALUE self)
841 {
842     GET_PARSER;
843     return rb_str_dup(json->Vsource);
844 }
845
846 /*
847  * call-seq: quirks_mode?()
848  *
849  * Returns a true, if this parser is in quirks_mode, false otherwise.
850  */
851 static VALUE cParser_quirks_mode_p(VALUE self)
852 {
853     GET_PARSER;
854     return json->quirks_mode ? Qtrue : Qfalse;
855 }
856
857
858 void Init_parser()
859 {
860     rb_require("json/common");
861     mJSON = rb_define_module("JSON");
862     mExt = rb_define_module_under(mJSON, "Ext");
863     cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
864     eParserError = rb_path2class("JSON::ParserError");
865     eNestingError = rb_path2class("JSON::NestingError");
866     rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
867     rb_define_method(cParser, "initialize", cParser_initialize, -1);
868     rb_define_method(cParser, "parse", cParser_parse, 0);
869     rb_define_method(cParser, "source", cParser_source, 0);
870     rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0);
871
872     CNaN = rb_const_get(mJSON, rb_intern("NaN"));
873     CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
874     CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
875
876     i_json_creatable_p = rb_intern("json_creatable?");
877     i_json_create = rb_intern("json_create");
878     i_create_id = rb_intern("create_id");
879     i_create_additions = rb_intern("create_additions");
880     i_chr = rb_intern("chr");
881     i_max_nesting = rb_intern("max_nesting");
882     i_allow_nan = rb_intern("allow_nan");
883     i_symbolize_names = rb_intern("symbolize_names");
884     i_quirks_mode = rb_intern("quirks_mode");
885     i_object_class = rb_intern("object_class");
886     i_array_class = rb_intern("array_class");
887     i_match = rb_intern("match");
888     i_match_string = rb_intern("match_string");
889     i_key_p = rb_intern("key?");
890     i_deep_const_get = rb_intern("deep_const_get");
891     i_aset = rb_intern("[]=");
892     i_leftshift = rb_intern("<<");
893 #ifdef HAVE_RUBY_ENCODING_H
894     CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
895     CEncoding_UTF_16BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16be"));
896     CEncoding_UTF_16LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16le"));
897     CEncoding_UTF_32BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32be"));
898     CEncoding_UTF_32LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32le"));
899     CEncoding_ASCII_8BIT = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("ascii-8bit"));
900     i_encoding = rb_intern("encoding");
901     i_encode = rb_intern("encode");
902 #else
903     i_iconv = rb_intern("iconv");
904 #endif
905 }
906
907 /*
908  * Local variables:
909  * mode: c
910  * c-file-style: ruby
911  * indent-tabs-mode: nil
912  * End:
913  */