diff options
Diffstat (limited to 'ext/json/ext/parser/parser.rl')
-rw-r--r-- | ext/json/ext/parser/parser.rl | 177 |
1 files changed, 124 insertions, 53 deletions
diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 21b445e..e7d47e1 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -76,8 +76,9 @@ static VALUE mJSON, mExt, cParser, eParserError, eNestingError; static VALUE CNaN, CInfinity, CMinusInfinity; static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions, - i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class, - i_array_class, i_key_p, i_deep_const_get, i_match, i_match_string, i_aset, i_leftshift; + i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_quirks_mode, + i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match, + i_match_string, i_aset, i_leftshift; %%{ machine JSON_common; @@ -138,13 +139,14 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions, action exit { fhold; fbreak; } - a_pair = ignore* begin_name >parse_name - ignore* name_separator ignore* - begin_value >parse_value; + pair = ignore* begin_name >parse_name ignore* name_separator ignore* begin_value >parse_value; + next_pair = ignore* value_separator pair; - main := begin_object - (a_pair (ignore* value_separator a_pair)*)? - ignore* end_object @exit; + main := ( + begin_object + (pair (next_pair)*)? ignore* + end_object + ) @exit; }%% static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -178,6 +180,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu } } + %%{ machine JSON_value; include JSON_common; @@ -214,7 +217,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu action parse_number { char *np; - if(pe > fpc + 9 && !strncmp(MinusInfinity, fpc, 9)) { + if(pe > fpc + 9 - json->quirks_mode && !strncmp(MinusInfinity, fpc, 9)) { if (json->allow_nan) { *result = CMinusInfinity; fexec p + 10; @@ -282,7 +285,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul action exit { fhold; fbreak; } - main := '-'? ('0' | [1-9][0-9]*) (^[0-9] @exit); + main := '-'? ('0' | [1-9][0-9]*) (^[0-9]? @exit); }%% static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -313,7 +316,7 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res main := '-'? ( (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?) | (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+)) - ) (^[0-9Ee.\-] @exit ); + ) (^[0-9Ee.\-]? @exit ); }%% static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -521,34 +524,6 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu } } - -%%{ - machine JSON; - - write data; - - include JSON_common; - - action parse_object { - char *np; - json->current_nesting = 1; - np = JSON_parse_object(json, fpc, pe, &result); - if (np == NULL) { fhold; fbreak; } else fexec np; - } - - action parse_array { - char *np; - json->current_nesting = 1; - np = JSON_parse_array(json, fpc, pe, &result); - if (np == NULL) { fhold; fbreak; } else fexec np; - } - - main := ignore* ( - begin_object >parse_object | - begin_array >parse_array - ) ignore*; -}%% - /* * Document-class: JSON::Ext::Parser * @@ -630,8 +605,6 @@ static VALUE convert_encoding(VALUE source) */ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) { - char *ptr; - long len; VALUE source, opts; GET_PARSER_INIT; @@ -639,9 +612,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) rb_raise(rb_eTypeError, "already initialized instance"); } rb_scan_args(argc, argv, "11", &source, &opts); - source = convert_encoding(StringValue(source)); - ptr = RSTRING_PTR(source); - len = RSTRING_LEN(source); if (!NIL_P(opts)) { opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash"); if (NIL_P(opts)) { @@ -671,6 +641,13 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } else { json->symbolize_names = 0; } + tmp = ID2SYM(i_quirks_mode); + if (option_given_p(opts, tmp)) { + VALUE quirks_mode = rb_hash_aref(opts, tmp); + json->quirks_mode = RTEST(quirks_mode) ? 1 : 0; + } else { + json->quirks_mode = 0; + } tmp = ID2SYM(i_create_additions); if (option_given_p(opts, tmp)) { json->create_additions = RTEST(rb_hash_aref(opts, tmp)); @@ -711,20 +688,44 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) json->object_class = Qnil; json->array_class = Qnil; } + if (!json->quirks_mode) { + source = convert_encoding(StringValue(source)); + } json->current_nesting = 0; - json->len = len; - json->source = ptr; + json->len = RSTRING_LEN(source); + json->source = RSTRING_PTR(source);; json->Vsource = source; return self; } -/* - * call-seq: parse() - * - * Parses the current JSON text _source_ and returns the complete data - * structure as a result. - */ -static VALUE cParser_parse(VALUE self) +%%{ + machine JSON; + + write data; + + include JSON_common; + + action parse_object { + char *np; + json->current_nesting = 1; + np = JSON_parse_object(json, fpc, pe, &result); + if (np == NULL) { fhold; fbreak; } else fexec np; + } + + action parse_array { + char *np; + json->current_nesting = 1; + np = JSON_parse_array(json, fpc, pe, &result); + if (np == NULL) { fhold; fbreak; } else fexec np; + } + + main := ignore* ( + begin_object >parse_object | + begin_array >parse_array + ) ignore*; +}%% + +static VALUE cParser_parse_strict(VALUE self) { char *p, *pe; int cs = EVIL; @@ -744,6 +745,62 @@ static VALUE cParser_parse(VALUE self) } } + +%%{ + machine JSON_quirks_mode; + + write data; + + include JSON_common; + + action parse_value { + char *np = JSON_parse_value(json, fpc, pe, &result); + if (np == NULL) { fhold; fbreak; } else fexec np; + } + + main := ignore* ( + begin_value >parse_value + ) ignore*; +}%% + +static VALUE cParser_parse_quirks_mode(VALUE self) +{ + char *p, *pe; + int cs = EVIL; + VALUE result = Qnil; + GET_PARSER; + + %% write init; + p = json->source; + pe = p + json->len; + %% write exec; + + if (cs >= JSON_quirks_mode_first_final && p == pe) { + return result; + } else { + rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p); + return Qnil; + } +} + +/* + * call-seq: parse() + * + * Parses the current JSON text _source_ and returns the complete data + * structure as a result. + */ +static VALUE cParser_parse(VALUE self) +{ + GET_PARSER; + + if (json->quirks_mode) { + return cParser_parse_quirks_mode(self); + } else { + return cParser_parse_strict(self); + } +} + + static JSON_Parser *JSON_allocate() { JSON_Parser *json = ALLOC(JSON_Parser); @@ -783,6 +840,18 @@ static VALUE cParser_source(VALUE self) return rb_str_dup(json->Vsource); } +/* + * call-seq: quirks_mode?() + * + * Returns a true, if this parser is in quirks_mode, false otherwise. + */ +static VALUE cParser_quirks_mode_p(VALUE self) +{ + GET_PARSER; + return json->quirks_mode ? Qtrue : Qfalse; +} + + void Init_parser() { rb_require("json/common"); @@ -795,6 +864,7 @@ void Init_parser() rb_define_method(cParser, "initialize", cParser_initialize, -1); rb_define_method(cParser, "parse", cParser_parse, 0); rb_define_method(cParser, "source", cParser_source, 0); + rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0); CNaN = rb_const_get(mJSON, rb_intern("NaN")); CInfinity = rb_const_get(mJSON, rb_intern("Infinity")); @@ -808,6 +878,7 @@ void Init_parser() i_max_nesting = rb_intern("max_nesting"); i_allow_nan = rb_intern("allow_nan"); i_symbolize_names = rb_intern("symbolize_names"); + i_quirks_mode = rb_intern("quirks_mode"); i_object_class = rb_intern("object_class"); i_array_class = rb_intern("array_class"); i_match = rb_intern("match"); |