class JSON::Ext::Parser
This is the JSON
parser implemented as a C extension. It can be configured to be used by setting
JSON.parser = JSON::Ext::Parser
with the method parser= in JSON
.
Public Class Methods
Creates a new JSON::Ext::Parser
instance for the string source.
Creates a new JSON::Ext::Parser
instance for the string source.
It will be configured by the opts hash. opts can have the following keys:
opts can have the following keys:
-
max_nesting: The maximum depth of nesting allowed in the parsed data structures. Disable depth checking with :max_nesting => false|nil|0, it defaults to 100.
-
allow_nan: If set to true, allow NaN, Infinity and -Infinity in defiance of RFC 4627 to be parsed by the
Parser
. This option defaults to false. -
symbolize_names: If set to true, returns symbols for the names (keys) in a
JSON
object. Otherwise strings are returned, which is also the default. It’s not possible to use this option in conjunction with the create_additions option. -
create_additions: If set to false, the
Parser
doesn’t create additions even if a matching class and create_id was found. This option defaults to false. -
object_class: Defaults to Hash
-
array_class: Defaults to Array
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) { VALUE source, opts; GET_PARSER_INIT; if (json->Vsource) { rb_raise(rb_eTypeError, "already initialized instance"); } #ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH rb_scan_args(argc, argv, "1:", &source, &opts); #else rb_scan_args(argc, argv, "11", &source, &opts); #endif if (!NIL_P(opts)) { #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash"); if (NIL_P(opts)) { rb_raise(rb_eArgError, "opts needs to be like a hash"); } else { #endif VALUE tmp = ID2SYM(i_max_nesting); if (option_given_p(opts, tmp)) { VALUE max_nesting = rb_hash_aref(opts, tmp); if (RTEST(max_nesting)) { Check_Type(max_nesting, T_FIXNUM); json->max_nesting = FIX2INT(max_nesting); } else { json->max_nesting = 0; } } else { json->max_nesting = 100; } tmp = ID2SYM(i_allow_nan); if (option_given_p(opts, tmp)) { json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0; } else { json->allow_nan = 0; } tmp = ID2SYM(i_symbolize_names); if (option_given_p(opts, tmp)) { json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0; } else { json->symbolize_names = 0; } tmp = ID2SYM(i_freeze); if (option_given_p(opts, tmp)) { json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0; } else { json->freeze = 0; } tmp = ID2SYM(i_create_additions); if (option_given_p(opts, tmp)) { json->create_additions = RTEST(rb_hash_aref(opts, tmp)); } else { json->create_additions = 0; } if (json->symbolize_names && json->create_additions) { rb_raise(rb_eArgError, "options :symbolize_names and :create_additions cannot be " " used in conjunction"); } tmp = ID2SYM(i_create_id); if (option_given_p(opts, tmp)) { json->create_id = rb_hash_aref(opts, tmp); } else { json->create_id = rb_funcall(mJSON, i_create_id, 0); } tmp = ID2SYM(i_object_class); if (option_given_p(opts, tmp)) { json->object_class = rb_hash_aref(opts, tmp); } else { json->object_class = Qnil; } tmp = ID2SYM(i_array_class); if (option_given_p(opts, tmp)) { json->array_class = rb_hash_aref(opts, tmp); } else { json->array_class = Qnil; } tmp = ID2SYM(i_decimal_class); if (option_given_p(opts, tmp)) { json->decimal_class = rb_hash_aref(opts, tmp); } else { json->decimal_class = Qnil; } tmp = ID2SYM(i_match_string); if (option_given_p(opts, tmp)) { VALUE match_string = rb_hash_aref(opts, tmp); json->match_string = RTEST(match_string) ? match_string : Qnil; } else { json->match_string = Qnil; } #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH } #endif } else { json->max_nesting = 100; json->allow_nan = 0; json->create_additions = 0; json->create_id = rb_funcall(mJSON, i_create_id, 0); json->object_class = Qnil; json->array_class = Qnil; json->decimal_class = Qnil; } source = convert_encoding(StringValue(source)); StringValue(source); json->len = RSTRING_LEN(source); json->source = RSTRING_PTR(source);; json->Vsource = source; return self; }
Public Instance Methods
Parses the current JSON
text source and returns the complete data structure as a result. It raises JSON::ParseError if fail to parse.
static VALUE cParser_parse(VALUE self) { char *p, *pe; int cs = EVIL; VALUE result = Qnil; GET_PARSER; { cs = (int)JSON_start; } #line 851 "parser.rl" p = json->source; pe = p + json->len; { if ( p == pe ) goto _test_eof; switch ( cs ) { case 1: goto st_case_1; case 0: goto st_case_0; case 10: goto st_case_10; case 2: goto st_case_2; case 3: goto st_case_3; case 4: goto st_case_4; case 5: goto st_case_5; case 6: goto st_case_6; case 7: goto st_case_7; case 8: goto st_case_8; case 9: goto st_case_9; } goto st_out; st1: p+= 1; if ( p == pe ) goto _test_eof1; st_case_1: switch( ( (*( p))) ) { case 13: { goto st1; } case 32: { goto st1; } case 34: { goto ctr2; } case 45: { goto ctr2; } case 47: { goto st6; } case 73: { goto ctr2; } case 78: { goto ctr2; } case 91: { goto ctr2; } case 102: { goto ctr2; } case 110: { goto ctr2; } case 116: { goto ctr2; } case 123: { goto ctr2; } } if ( ( (*( p))) > 10 ) { if ( 48 <= ( (*( p))) && ( (*( p))) <= 57 ) { goto ctr2; } } else if ( ( (*( p))) >= 9 ) { goto st1; } { goto st0; } st_case_0: st0: cs = 0; goto _out; ctr2: { #line 827 "parser.rl" char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { {p = p - 1; } {p+= 1; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; st10: p+= 1; if ( p == pe ) goto _test_eof10; st_case_10: switch( ( (*( p))) ) { case 13: { goto st10; } case 32: { goto st10; } case 47: { goto st2; } } if ( 9 <= ( (*( p))) && ( (*( p))) <= 10 ) { goto st10; } { goto st0; } st2: p+= 1; if ( p == pe ) goto _test_eof2; st_case_2: switch( ( (*( p))) ) { case 42: { goto st3; } case 47: { goto st5; } } { goto st0; } st3: p+= 1; if ( p == pe ) goto _test_eof3; st_case_3: if ( ( (*( p))) == 42 ) { goto st4; } { goto st3; } st4: p+= 1; if ( p == pe ) goto _test_eof4; st_case_4: switch( ( (*( p))) ) { case 42: { goto st4; } case 47: { goto st10; } } { goto st3; } st5: p+= 1; if ( p == pe ) goto _test_eof5; st_case_5: if ( ( (*( p))) == 10 ) { goto st10; } { goto st5; } st6: p+= 1; if ( p == pe ) goto _test_eof6; st_case_6: switch( ( (*( p))) ) { case 42: { goto st7; } case 47: { goto st9; } } { goto st0; } st7: p+= 1; if ( p == pe ) goto _test_eof7; st_case_7: if ( ( (*( p))) == 42 ) { goto st8; } { goto st7; } st8: p+= 1; if ( p == pe ) goto _test_eof8; st_case_8: switch( ( (*( p))) ) { case 42: { goto st8; } case 47: { goto st1; } } { goto st7; } st9: p+= 1; if ( p == pe ) goto _test_eof9; st_case_9: if ( ( (*( p))) == 10 ) { goto st1; } { goto st9; } st_out: _test_eof1: cs = 1; goto _test_eof; _test_eof10: cs = 10; goto _test_eof; _test_eof2: cs = 2; goto _test_eof; _test_eof3: cs = 3; goto _test_eof; _test_eof4: cs = 4; goto _test_eof; _test_eof5: cs = 5; goto _test_eof; _test_eof6: cs = 6; goto _test_eof; _test_eof7: cs = 7; goto _test_eof; _test_eof8: cs = 8; goto _test_eof; _test_eof9: cs = 9; goto _test_eof; _test_eof: {} _out: {} } #line 854 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; } else { rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return Qnil; } }
Returns a copy of the current source string, that was used to construct this Parser
.
static VALUE cParser_source(VALUE self) { GET_PARSER; return rb_str_dup(json->Vsource); }