123456789_123456789_123456789_123456789_123456789_

Class: JSON::Ext::Parser

Relationships & Source Files
Inherits: Object
Defined in: ext/json/parser/parser.c,
ext/json/parser/parser.c

Overview

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.

Class Method Summary

Instance Method Summary

  • #parse

    Parses the current ::JSON text source and returns the complete data structure as a result.

  • #source

    Returns a copy of the current source string, that was used to construct this Parser.

Constructor Details

.new(source, opts) ⇒ {}

Creates a new Parser instance for the string source.

Creates a new 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

[ GitHub ]

  
# File 'ext/json/parser/parser.c', line 2808

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;
}

Instance Method Details

#parse

Parses the current ::JSON text source and returns the complete data structure as a result.

[ GitHub ]

  
# File 'ext/json/parser/parser.c', line 2954

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, "%u: unexpected token at '%s'", __LINE__, p);
		return Qnil;
	}
}

#source

Returns a copy of the current source string, that was used to construct this Parser.

[ GitHub ]

  
# File 'ext/json/parser/parser.c', line 3273

static VALUE cParser_source(VALUE self)
{
	GET_PARSER;
	return rb_str_dup(json->Vsource);
}