From 792799e815f38f26cf8262e4d8c291ad955e651a Mon Sep 17 00:00:00 2001 From: yugui Date: Fri, 17 Jul 2009 10:06:58 +0000 Subject: merges r23346 from trunk into ruby_1_9_1. -- Update to JSON 1.1.4. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_1@24168 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 4 + ext/json/ext/generator/generator.c | 71 +++++-- ext/json/ext/parser/parser.c | 205 +++++++++++-------- ext/json/ext/parser/parser.rl | 30 ++- ext/json/lib/json.rb | 162 ++++++++++----- ext/json/lib/json/add/core.rb | 2 +- ext/json/lib/json/common.rb | 0 ext/json/lib/json/editor.rb | 13 +- ext/json/lib/json/ext.rb | 2 + ext/json/lib/json/pure.rb | 22 -- ext/json/lib/json/pure/generator.rb | 394 ------------------------------------ ext/json/lib/json/pure/parser.rb | 269 ------------------------ ext/json/lib/json/version.rb | 2 +- version.h | 2 +- 14 files changed, 344 insertions(+), 834 deletions(-) mode change 100644 => 100755 ext/json/lib/json.rb mode change 100644 => 100755 ext/json/lib/json/common.rb mode change 100644 => 100755 ext/json/lib/json/editor.rb delete mode 100644 ext/json/lib/json/pure.rb delete mode 100644 ext/json/lib/json/pure/generator.rb delete mode 100644 ext/json/lib/json/pure/parser.rb diff --git a/ChangeLog b/ChangeLog index a51bc45c36..4ddd3f4774 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Tue May 5 10:42:28 2009 NARUSE, Yui + + * ext/json: Update to JSON 1.1.4. + Wed Jul 15 16:29:35 2009 NAKAMURA Usaku * win32/Makefile.sub (LIBPATHFLAG): path is already quoted in mkmf.rb. diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index 1f48d3c780..108e80fd65 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1,8 +1,33 @@ #include #include "ruby.h" +#if HAVE_RUBY_ST_H +#include "ruby/st.h" +#endif +#if HAVE_ST_H +#include "st.h" +#endif #include "unicode.h" #include +#ifndef RHASH_TBL +#define RHASH_TBL(hsh) (RHASH(hsh)->tbl) +#endif + +#ifndef RHASH_SIZE +#define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries) +#endif + +#ifndef RFLOAT_VALUE +#define RFLOAT_VALUE(val) (RFLOAT(val)->value) +#endif + +#ifdef HAVE_RUBY_ENCODING_H +#include "ruby/encoding.h" +#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding()) +#else +#define FORCE_UTF8(obj) +#endif + #define check_max_nesting(state, depth) do { \ long current_nesting = 1 + depth; \ if (state->max_nesting != 0 && current_nesting > state->max_nesting) \ @@ -163,6 +188,7 @@ static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self) } } OBJ_INFECT(result, self); + FORCE_UTF8(result); return result; } @@ -260,6 +286,7 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) { result = mArray_json_transfrom(self, Vstate, Vdepth); } OBJ_INFECT(result, self); + FORCE_UTF8(result); return result; } @@ -270,7 +297,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) { */ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self) { - return rb_funcall(self, i_to_s, 0); + VALUE result = rb_funcall(self, i_to_s, 0); + FORCE_UTF8(result); + return result; } /* @@ -281,27 +310,29 @@ static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self) static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) { JSON_Generator_State *state = NULL; - VALUE Vstate, rest, tmp; + VALUE Vstate, rest, tmp, result; double value = RFLOAT_VALUE(self); rb_scan_args(argc, argv, "01*", &Vstate, &rest); if (!NIL_P(Vstate)) Data_Get_Struct(Vstate, JSON_Generator_State, state); if (isinf(value)) { if (!state || state->allow_nan) { - return rb_funcall(self, i_to_s, 0); + result = rb_funcall(self, i_to_s, 0); } else { tmp = rb_funcall(self, i_to_s, 0); rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp)); } } else if (isnan(value)) { if (!state || state->allow_nan) { - return rb_funcall(self, i_to_s, 0); + result = rb_funcall(self, i_to_s, 0); } else { tmp = rb_funcall(self, i_to_s, 0); rb_raise(eGeneratorError, "%u: %s not allowed in JSON", __LINE__, StringValueCStr(tmp)); } } else { - return rb_funcall(self, i_to_s, 0); + result = rb_funcall(self, i_to_s, 0); } + FORCE_UTF8(result); + return result; } /* @@ -310,7 +341,9 @@ static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self) * Extends _modul_ with the String::Extend module. */ static VALUE mString_included_s(VALUE self, VALUE modul) { - return rb_funcall(modul, i_extend, 1, mString_Extend); + VALUE result = rb_funcall(modul, i_extend, 1, mString_Extend); + FORCE_UTF8(result); + return result; } /* @@ -326,6 +359,7 @@ static VALUE mString_to_json(int argc, VALUE *argv, VALUE self) rb_str_buf_cat2(result, "\""); JSON_convert_UTF8_to_JSON(result, self, strictConversion); rb_str_buf_cat2(result, "\""); + FORCE_UTF8(result); return result; } @@ -343,6 +377,7 @@ static VALUE mString_to_json_raw_object(VALUE self) { rb_hash_aset(result, rb_funcall(mJSON, i_create_id, 0), rb_class_name(rb_obj_class(self))); ary = rb_funcall(self, i_unpack, 1, rb_str_new2("C*")); rb_hash_aset(result, rb_str_new2("raw"), ary); + FORCE_UTF8(result); return result; } @@ -353,9 +388,11 @@ static VALUE mString_to_json_raw_object(VALUE self) { * to_json_raw_object of this String. */ static VALUE mString_to_json_raw(int argc, VALUE *argv, VALUE self) { - VALUE obj = mString_to_json_raw_object(self); + VALUE result, obj = mString_to_json_raw_object(self); Check_Type(obj, T_HASH); - return mHash_to_json(argc, argv, obj); + result = mHash_to_json(argc, argv, obj); + FORCE_UTF8(result); + return result; } /* @@ -378,7 +415,9 @@ static VALUE mString_Extend_json_create(VALUE self, VALUE o) { */ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self) { - return rb_str_new2("true"); + VALUE result = rb_str_new2("true"); + FORCE_UTF8(result); + return result; } /* @@ -388,7 +427,9 @@ static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self) */ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self) { - return rb_str_new2("false"); + VALUE result = rb_str_new2("false"); + FORCE_UTF8(result); + return result; } /* @@ -397,7 +438,9 @@ static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self) */ static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self) { - return rb_str_new2("null"); + VALUE result = rb_str_new2("null"); + FORCE_UTF8(result); + return result; } /* @@ -409,9 +452,11 @@ static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self) */ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self) { - VALUE string = rb_funcall(self, i_to_s, 0); + VALUE result, string = rb_funcall(self, i_to_s, 0); Check_Type(string, T_STRING); - return mString_to_json(argc, argv, string); + result = mString_to_json(argc, argv, string); + FORCE_UTF8(result); + return result; } /* diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 9de618d0e6..6928eda9e5 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -1,10 +1,30 @@ + #line 1 "parser.rl" #include "ruby.h" -#include "ruby/encoding.h" #include "unicode.h" +#if HAVE_RE_H +#include "re.h" +#endif +#if HAVE_RUBY_ST_H +#include "ruby/st.h" +#endif +#if HAVE_ST_H +#include "st.h" +#endif #define EVIL 0x666 +#ifndef RHASH_TBL +#define RHASH_TBL(hsh) (RHASH(hsh)->tbl) +#endif + +#ifdef HAVE_RUBY_ENCODING_H +#include "ruby/encoding.h" +#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding()) +#else +#define FORCE_UTF8(obj) +#endif + static VALUE mJSON, mExt, cParser, eParserError, eNestingError; static VALUE CNaN, CInfinity, CMinusInfinity; @@ -35,18 +55,20 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul JSON_Parser *json; \ Data_Get_Struct(self, JSON_Parser, json); -#line 64 "parser.rl" +#line 82 "parser.rl" -#line 44 "parser.c" + +#line 64 "parser.c" static const int JSON_object_start = 1; static const int JSON_object_first_final = 27; static const int JSON_object_error = 0; static const int JSON_object_en_main = 1; -#line 97 "parser.rl" + +#line 115 "parser.rl" static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -61,13 +83,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu *result = rb_hash_new(); -#line 66 "parser.c" +#line 87 "parser.c" { cs = JSON_object_start; } -#line 111 "parser.rl" + +#line 129 "parser.rl" -#line 72 "parser.c" +#line 94 "parser.c" { if ( p == pe ) goto _test_eof; @@ -95,7 +118,7 @@ case 2: goto st2; goto st0; tr2: -#line 83 "parser.rl" +#line 101 "parser.rl" { char *np = JSON_parse_string(json, p, pe, &last_name); if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else {p = (( np))-1;} @@ -105,7 +128,7 @@ st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 110 "parser.c" +#line 132 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -172,7 +195,7 @@ case 8: goto st8; goto st0; tr11: -#line 72 "parser.rl" +#line 90 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v); @@ -188,7 +211,7 @@ st9: if ( ++p == pe ) goto _test_eof9; case 9: -#line 193 "parser.c" +#line 215 "parser.c" switch( (*p) ) { case 13: goto st9; case 32: goto st9; @@ -277,14 +300,14 @@ case 18: goto st9; goto st18; tr4: -#line 88 "parser.rl" +#line 106 "parser.rl" { p--; {p++; cs = 27; goto _out;} } goto st27; st27: if ( ++p == pe ) goto _test_eof27; case 27: -#line 289 "parser.c" +#line 311 "parser.c" goto st0; st19: if ( ++p == pe ) @@ -381,7 +404,8 @@ case 26: _test_eof: {} _out: {} } -#line 112 "parser.rl" + +#line 130 "parser.rl" if (cs >= JSON_object_first_final) { if (RTEST(json->create_id)) { @@ -400,14 +424,15 @@ case 26: } -#line 405 "parser.c" +#line 428 "parser.c" static const int JSON_value_start = 1; static const int JSON_value_first_final = 21; static const int JSON_value_error = 0; static const int JSON_value_en_main = 1; -#line 210 "parser.rl" + +#line 228 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -415,13 +440,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 420 "parser.c" +#line 444 "parser.c" { cs = JSON_value_start; } -#line 217 "parser.rl" + +#line 235 "parser.rl" -#line 426 "parser.c" +#line 451 "parser.c" { if ( p == pe ) goto _test_eof; @@ -446,14 +472,14 @@ st0: cs = 0; goto _out; tr0: -#line 158 "parser.rl" +#line 176 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) { p--; {p++; cs = 21; goto _out;} } else {p = (( np))-1;} } goto st21; tr2: -#line 163 "parser.rl" +#line 181 "parser.rl" { char *np; if(pe > p + 9 && !strncmp(MinusInfinity, p, 9)) { @@ -473,7 +499,7 @@ tr2: } goto st21; tr5: -#line 181 "parser.rl" +#line 199 "parser.rl" { char *np; json->current_nesting++; @@ -483,7 +509,7 @@ tr5: } goto st21; tr9: -#line 189 "parser.rl" +#line 207 "parser.rl" { char *np; json->current_nesting++; @@ -493,7 +519,7 @@ tr9: } goto st21; tr16: -#line 151 "parser.rl" +#line 169 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -503,7 +529,7 @@ tr16: } goto st21; tr18: -#line 144 "parser.rl" +#line 162 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -513,19 +539,19 @@ tr18: } goto st21; tr22: -#line 138 "parser.rl" +#line 156 "parser.rl" { *result = Qfalse; } goto st21; tr25: -#line 135 "parser.rl" +#line 153 "parser.rl" { *result = Qnil; } goto st21; tr28: -#line 141 "parser.rl" +#line 159 "parser.rl" { *result = Qtrue; } @@ -534,9 +560,9 @@ st21: if ( ++p == pe ) goto _test_eof21; case 21: -#line 197 "parser.rl" +#line 215 "parser.rl" { p--; {p++; cs = 21; goto _out;} } -#line 541 "parser.c" +#line 566 "parser.c" goto st0; st2: if ( ++p == pe ) @@ -696,7 +722,8 @@ case 20: _test_eof: {} _out: {} } -#line 218 "parser.rl" + +#line 236 "parser.rl" if (cs >= JSON_value_first_final) { return p; @@ -706,14 +733,15 @@ case 20: } -#line 711 "parser.c" +#line 737 "parser.c" static const int JSON_integer_start = 1; static const int JSON_integer_first_final = 5; static const int JSON_integer_error = 0; static const int JSON_integer_en_main = 1; -#line 234 "parser.rl" + +#line 252 "parser.rl" static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -721,14 +749,15 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res int cs = EVIL; -#line 726 "parser.c" +#line 753 "parser.c" { cs = JSON_integer_start; } -#line 241 "parser.rl" + +#line 259 "parser.rl" json->memo = p; -#line 733 "parser.c" +#line 761 "parser.c" { if ( p == pe ) goto _test_eof; @@ -762,14 +791,14 @@ case 3: goto st0; goto tr4; tr4: -#line 231 "parser.rl" +#line 249 "parser.rl" { p--; {p++; cs = 5; goto _out;} } goto st5; st5: if ( ++p == pe ) goto _test_eof5; case 5: -#line 774 "parser.c" +#line 802 "parser.c" goto st0; st4: if ( ++p == pe ) @@ -787,7 +816,8 @@ case 4: _test_eof: {} _out: {} } -#line 243 "parser.rl" + +#line 261 "parser.rl" if (cs >= JSON_integer_first_final) { long len = p - json->memo; @@ -799,14 +829,15 @@ case 4: } -#line 804 "parser.c" +#line 833 "parser.c" static const int JSON_float_start = 1; static const int JSON_float_first_final = 10; static const int JSON_float_error = 0; static const int JSON_float_en_main = 1; -#line 265 "parser.rl" + +#line 283 "parser.rl" static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -814,14 +845,15 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 819 "parser.c" +#line 849 "parser.c" { cs = JSON_float_start; } -#line 272 "parser.rl" + +#line 290 "parser.rl" json->memo = p; -#line 826 "parser.c" +#line 857 "parser.c" { if ( p == pe ) goto _test_eof; @@ -879,14 +911,14 @@ case 5: goto st0; goto tr7; tr7: -#line 259 "parser.rl" +#line 277 "parser.rl" { p--; {p++; cs = 10; goto _out;} } goto st10; st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 891 "parser.c" +#line 922 "parser.c" goto st0; st6: if ( ++p == pe ) @@ -946,7 +978,8 @@ case 9: _test_eof: {} _out: {} } -#line 274 "parser.rl" + +#line 292 "parser.rl" if (cs >= JSON_float_first_final) { long len = p - json->memo; @@ -959,14 +992,15 @@ case 9: -#line 964 "parser.c" +#line 996 "parser.c" static const int JSON_array_start = 1; static const int JSON_array_first_final = 17; static const int JSON_array_error = 0; static const int JSON_array_en_main = 1; -#line 310 "parser.rl" + +#line 328 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -979,13 +1013,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul *result = rb_ary_new(); -#line 984 "parser.c" +#line 1017 "parser.c" { cs = JSON_array_start; } -#line 322 "parser.rl" + +#line 340 "parser.rl" -#line 990 "parser.c" +#line 1024 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1024,7 +1059,7 @@ case 2: goto st2; goto st0; tr2: -#line 291 "parser.rl" +#line 309 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v); @@ -1040,7 +1075,7 @@ st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1045 "parser.c" +#line 1079 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -1140,14 +1175,14 @@ case 12: goto st3; goto st12; tr4: -#line 302 "parser.rl" +#line 320 "parser.rl" { p--; {p++; cs = 17; goto _out;} } goto st17; st17: if ( ++p == pe ) goto _test_eof17; case 17: -#line 1152 "parser.c" +#line 1186 "parser.c" goto st0; st13: if ( ++p == pe ) @@ -1202,7 +1237,8 @@ case 16: _test_eof: {} _out: {} } -#line 323 "parser.rl" + +#line 341 "parser.rl" if(cs >= JSON_array_first_final) { return p + 1; @@ -1268,14 +1304,15 @@ static VALUE json_string_unescape(char *p, char *pe) } -#line 1273 "parser.c" +#line 1308 "parser.c" static const int JSON_string_start = 1; static const int JSON_string_first_final = 8; static const int JSON_string_error = 0; static const int JSON_string_en_main = 1; -#line 401 "parser.rl" + +#line 425 "parser.rl" static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1284,14 +1321,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu *result = rb_str_new("", 0); -#line 1289 "parser.c" +#line 1325 "parser.c" { cs = JSON_string_start; } -#line 409 "parser.rl" + +#line 433 "parser.rl" json->memo = p; -#line 1296 "parser.c" +#line 1333 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1316,19 +1354,25 @@ case 2: goto st0; goto st2; tr2: -#line 393 "parser.rl" +#line 411 "parser.rl" { *result = json_string_unescape(json->memo + 1, p); - if (NIL_P(*result)) { p--; {p++; cs = 8; goto _out;} } else {p = (( p + 1))-1;} - } -#line 398 "parser.rl" + if (NIL_P(*result)) { + p--; + {p++; cs = 8; goto _out;} + } else { + FORCE_UTF8(*result); + {p = (( p + 1))-1;} + } + } +#line 422 "parser.rl" { p--; {p++; cs = 8; goto _out;} } goto st8; st8: if ( ++p == pe ) goto _test_eof8; case 8: -#line 1333 "parser.c" +#line 1376 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -1403,11 +1447,11 @@ case 7: _test_eof: {} _out: {} } -#line 411 "parser.rl" + +#line 435 "parser.rl" if (cs >= JSON_string_first_final) { - rb_enc_associate(*result, rb_utf8_encoding()); - return p + 1; + return p + 1; } else { return NULL; } @@ -1415,14 +1459,15 @@ case 7: -#line 1419 "parser.c" +#line 1463 "parser.c" static const int JSON_start = 1; static const int JSON_first_final = 10; static const int JSON_error = 0; static const int JSON_en_main = 1; -#line 445 "parser.rl" + +#line 469 "parser.rl" /* @@ -1545,15 +1590,16 @@ static VALUE cParser_parse(VALUE self) GET_STRUCT; -#line 1549 "parser.c" +#line 1594 "parser.c" { cs = JSON_start; } -#line 567 "parser.rl" + +#line 591 "parser.rl" p = json->source; pe = p + json->len; -#line 1557 "parser.c" +#line 1603 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1609,7 +1655,7 @@ case 5: goto st1; goto st5; tr3: -#line 434 "parser.rl" +#line 458 "parser.rl" { char *np; json->current_nesting = 1; @@ -1618,7 +1664,7 @@ tr3: } goto st10; tr4: -#line 427 "parser.rl" +#line 451 "parser.rl" { char *np; json->current_nesting = 1; @@ -1630,7 +1676,7 @@ st10: if ( ++p == pe ) goto _test_eof10; case 10: -#line 1634 "parser.c" +#line 1680 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -1686,7 +1732,8 @@ case 9: _test_eof: {} _out: {} } -#line 570 "parser.rl" + +#line 594 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 8325a93795..ca1876a7fc 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -1,8 +1,28 @@ #include "ruby.h" #include "unicode.h" +#if HAVE_RE_H +#include "re.h" +#endif +#if HAVE_RUBY_ST_H +#include "ruby/st.h" +#endif +#if HAVE_ST_H +#include "st.h" +#endif #define EVIL 0x666 +#ifndef RHASH_TBL +#define RHASH_TBL(hsh) (RHASH(hsh)->tbl) +#endif + +#ifdef HAVE_RUBY_ENCODING_H +#include "ruby/encoding.h" +#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding()) +#else +#define FORCE_UTF8(obj) +#endif + static VALUE mJSON, mExt, cParser, eParserError, eNestingError; static VALUE CNaN, CInfinity, CMinusInfinity; @@ -390,8 +410,14 @@ static VALUE json_string_unescape(char *p, char *pe) action parse_string { *result = json_string_unescape(json->memo + 1, p); - if (NIL_P(*result)) { fhold; fbreak; } else fexec p + 1; - } + if (NIL_P(*result)) { + fhold; + fbreak; + } else { + FORCE_UTF8(*result); + fexec p + 1; + } + } action exit { fhold; fbreak; } diff --git a/ext/json/lib/json.rb b/ext/json/lib/json.rb old mode 100644 new mode 100755 index 3b0b711550..9e5c3f7950 --- a/ext/json/lib/json.rb +++ b/ext/json/lib/json.rb @@ -77,57 +77,121 @@ require 'json/common' # # == Speed Comparisons # -# I have created some benchmark results (see the benchmarks subdir of the -# package) for the JSON-Parser to estimate the speed up in the C extension: -# -# JSON::Pure::Parser:: 28.90 calls/second -# JSON::Ext::Parser:: 505.50 calls/second -# -# This is ca. 17.5 times the speed of the pure Ruby implementation. -# -# I have benchmarked the JSON-Generator as well. This generates a few more -# values, because there are different modes, that also influence the achieved +# I have created some benchmark results (see the benchmarks/data-p4-3Ghz +# subdir of the package) for the JSON-parser to estimate the speed up in the C +# extension: +# +# Comparing times (call_time_mean): +# 1 ParserBenchmarkExt#parser 900 repeats: +# 553.922304770 ( real) -> 21.500x +# 0.001805307 +# 2 ParserBenchmarkYAML#parser 1000 repeats: +# 224.513358139 ( real) -> 8.714x +# 0.004454078 +# 3 ParserBenchmarkPure#parser 1000 repeats: +# 26.755020642 ( real) -> 1.038x +# 0.037376163 +# 4 ParserBenchmarkRails#parser 1000 repeats: +# 25.763381731 ( real) -> 1.000x +# 0.038814780 +# calls/sec ( time) -> speed covers +# secs/call +# +# In the table above 1 is JSON::Ext::Parser, 2 is YAML.load with YAML +# compatbile JSON document, 3 is is JSON::Pure::Parser, and 4 is +# ActiveSupport::JSON.decode. The ActiveSupport JSON-decoder converts the +# input first to YAML and then uses the YAML-parser, the conversion seems to +# slow it down so much that it is only as fast as the JSON::Pure::Parser! +# +# If you look at the benchmark data you can see that this is mostly caused by +# the frequent high outliers - the median of the Rails-parser runs is still +# overall smaller than the median of the JSON::Pure::Parser runs: +# +# Comparing times (call_time_median): +# 1 ParserBenchmarkExt#parser 900 repeats: +# 800.592479481 ( real) -> 26.936x +# 0.001249075 +# 2 ParserBenchmarkYAML#parser 1000 repeats: +# 271.002390644 ( real) -> 9.118x +# 0.003690004 +# 3 ParserBenchmarkRails#parser 1000 repeats: +# 30.227910865 ( real) -> 1.017x +# 0.033082008 +# 4 ParserBenchmarkPure#parser 1000 repeats: +# 29.722384421 ( real) -> 1.000x +# 0.033644676 +# calls/sec ( time) -> speed covers +# secs/call +# +# I have benchmarked the JSON-Generator as well. This generated a few more +# values, because there are different modes that also influence the achieved # speed: # -# * JSON::Pure::Generator: -# generate:: 35.06 calls/second -# pretty_generate:: 34.00 calls/second -# fast_generate:: 41.06 calls/second -# -# * JSON::Ext::Generator: -# generate:: 492.11 calls/second -# pretty_generate:: 348.85 calls/second -# fast_generate:: 541.60 calls/second -# -# * Speedup Ext/Pure: -# generate safe:: 14.0 times -# generate pretty:: 10.3 times -# generate fast:: 13.2 times -# -# The rails framework includes a generator as well, also it seems to be rather -# slow: I measured only 23.87 calls/second which is slower than any of my pure -# generator results. Here a comparison of the different speedups with the Rails -# measurement as the divisor: -# -# * Speedup Pure/Rails: -# generate safe:: 1.5 times -# generate pretty:: 1.4 times -# generate fast:: 1.7 times -# -# * Speedup Ext/Rails: -# generate safe:: 20.6 times -# generate pretty:: 14.6 times -# generate fast:: 22.7 times -# -# To achieve the fastest JSON text output, you can use the -# fast_generate/fast_unparse methods. Beware, that this will disable the -# checking for circular Ruby data structures, which may cause JSON to go into -# an infinite loop. +# Comparing times (call_time_mean): +# 1 GeneratorBenchmarkExt#generator_fast 1000 repeats: +# 547.354332608 ( real) -> 15.090x +# 0.001826970 +# 2 GeneratorBenchmarkExt#generator_safe 1000 repeats: +# 443.968212317 ( real) -> 12.240x +# 0.002252414 +# 3 GeneratorBenchmarkExt#generator_pretty 900 repeats: +# 375.104545883 ( real) -> 10.341x +# 0.002665923 +# 4 GeneratorBenchmarkPure#generator_fast 1000 repeats: +# 49.978706968 ( real) -> 1.378x +# 0.020008521 +# 5 GeneratorBenchmarkRails#generator 1000 repeats: +# 38.531868759 ( real) -> 1.062x +# 0.025952543 +# 6 GeneratorBenchmarkPure#generator_safe 1000 repeats: +# 36.927649925 ( real) -> 1.018x 7 (>=3859) +# 0.027079979 +# 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats: +# 36.272134441 ( real) -> 1.000x 6 (>=3859) +# 0.027569373 +# calls/sec ( time) -> speed covers +# secs/call +# +# In the table above 1-3 are JSON::Ext::Generator methods. 4, 6, and 7 are +# JSON::Pure::Generator methods and 5 is the Rails JSON generator. It is now a +# bit faster than the generator_safe and generator_pretty methods of the pure +# variant but slower than the others. +# +# To achieve the fastest JSON text output, you can use the fast_generate +# method. Beware, that this will disable the checking for circular Ruby data +# structures, which may cause JSON to go into an infinite loop. +# +# Here are the median comparisons for completeness' sake: +# +# Comparing times (call_time_median): +# 1 GeneratorBenchmarkExt#generator_fast 1000 repeats: +# 708.258020939 ( real) -> 16.547x +# 0.001411915 +# 2 GeneratorBenchmarkExt#generator_safe 1000 repeats: +# 569.105020353 ( real) -> 13.296x +# 0.001757145 +# 3 GeneratorBenchmarkExt#generator_pretty 900 repeats: +# 482.825371244 ( real) -> 11.280x +# 0.002071142 +# 4 GeneratorBenchmarkPure#generator_fast 1000 repeats: +# 62.717626652 ( real) -> 1.465x +# 0.015944481 +# 5 GeneratorBenchmarkRails#generator 1000 repeats: +# 43.965681162 ( real) -> 1.027x +# 0.022745013 +# 6 GeneratorBenchmarkPure#generator_safe 1000 repeats: +# 43.929073409 ( real) -> 1.026x 7 (>=3859) +# 0.022763968 +# 7 GeneratorBenchmarkPure#generator_pretty 1000 repeats: +# 42.802514491 ( real) -> 1.000x 6 (>=3859) +# 0.023363113 +# calls/sec ( time) -> speed covers +# secs/call # # == Examples # -# To create a JSON text from a ruby data structure, you -# can call JSON.generate (or JSON.unparse) like that: +# To create a JSON text from a ruby data structure, you can call JSON.generate +# like that: # # json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10] # # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]" @@ -210,8 +274,8 @@ require 'json/common' # } # ] # -# There are also the methods Kernel#j for unparse, and Kernel#jj for -# pretty_unparse output to the console, that work analogous to Core Ruby's p +# There are also the methods Kernel#j for generate, and Kernel#jj for +# pretty_generate output to the console, that work analogous to Core Ruby's p # and the pp library's pp methods. # # The script tools/server.rb contains a small example if you want to test, how @@ -230,6 +294,4 @@ module JSON require 'json/pure' end end - - JSON_LOADED = true end diff --git a/ext/json/lib/json/add/core.rb b/ext/json/lib/json/add/core.rb index 7121a77ff1..4423e7ad75 100644 --- a/ext/json/lib/json/add/core.rb +++ b/ext/json/lib/json/add/core.rb @@ -96,7 +96,7 @@ class Struct def to_json(*args) klass = self.class.name - klass.nil? and raise JSON::JSONError, "Only named structs are supported!" + klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { 'json_class' => klass, 'v' => values, diff --git a/ext/json/lib/json/common.rb b/ext/json/lib/json/common.rb old mode 100644 new mode 100755 diff --git a/ext/json/lib/json/editor.rb b/ext/json/lib/json/editor.rb old mode 100644 new mode 100755 index 12a7f94591..1e13f33c8c --- a/ext/json/lib/json/editor.rb +++ b/ext/json/lib/json/editor.rb @@ -769,7 +769,12 @@ module JSON iter.type, iter.content = 'FalseClass', 'false' end when 'Numeric' - iter.content = (Integer(value) rescue Float(value) rescue 0).to_s + iter.content = + if value == 'Infinity' + value + else + (Integer(value) rescue Float(value) rescue 0).to_s + end when 'String' iter.content = value when 'Hash', 'Array' @@ -937,7 +942,11 @@ module JSON type = types[type_input.active] @content = case type when 'Numeric' - Integer(value_input.text) rescue Float(value_input.text) rescue 0 + if (t = value_input.text) == 'Infinity' + 1 / 0.0 + else + Integer(t) rescue Float(t) rescue 0 + end else value_input.text end.to_s diff --git a/ext/json/lib/json/ext.rb b/ext/json/lib/json/ext.rb index ff4fa42329..719e56025c 100644 --- a/ext/json/lib/json/ext.rb +++ b/ext/json/lib/json/ext.rb @@ -10,4 +10,6 @@ module JSON JSON.parser = Parser JSON.generator = Generator end + + JSON_LOADED = true end diff --git a/ext/json/lib/json/pure.rb b/ext/json/lib/json/pure.rb deleted file mode 100644 index 6af8705c5b..0000000000 --- a/ext/json/lib/json/pure.rb +++ /dev/null @@ -1,22 +0,0 @@ -require 'json/common' -require 'json/pure/parser' -require 'json/pure/generator' - -module JSON - # Swap consecutive bytes of _string_ in place. - def self.swap!(string) # :nodoc: - 0.upto(string.size / 2) do |i| - break unless string[2 * i + 1] - string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i] - end - string - end - - # This module holds all the modules/classes that implement JSON's - # functionality in pure ruby. - module Pure - $DEBUG and warn "Using pure library for JSON." - JSON.parser = Parser - JSON.generator = Generator - end -end diff --git a/ext/json/lib/json/pure/generator.rb b/ext/json/lib/json/pure/generator.rb deleted file mode 100644 index 9c7cfac0a2..0000000000 --- a/ext/json/lib/json/pure/generator.rb +++ /dev/null @@ -1,394 +0,0 @@ -module JSON - MAP = { - "\x0" => '\u0000', - "\x1" => '\u0001', - "\x2" => '\u0002', - "\x3" => '\u0003', - "\x4" => '\u0004', - "\x5" => '\u0005', - "\x6" => '\u0006', - "\x7" => '\u0007', - "\b" => '\b', - "\t" => '\t', - "\n" => '\n', - "\xb" => '\u000b', - "\f" => '\f', - "\r" => '\r', - "\xe" => '\u000e', - "\xf" => '\u000f', - "\x10" => '\u0010', - "\x11" => '\u0011', - "\x12" => '\u0012', - "\x13" => '\u0013', - "\x14" => '\u0014', - "\x15" => '\u0015', - "\x16" => '\u0016', - "\x17" => '\u0017', - "\x18" => '\u0018', - "\x19" => '\u0019', - "\x1a" => '\u001a', - "\x1b" => '\u001b', - "\x1c" => '\u001c', - "\x1d" => '\u001d', - "\x1e" => '\u001e', - "\x1f" => '\u001f', - '"' => '\"', - '\\' => '\\\\', - '/' => '\/', - } # :nodoc: - - # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with - # UTF16 big endian characters as \u????, and return it. - def utf8_to_json(string) # :nodoc: - string = string.dup.force_encoding(Encoding::ASCII_8BIT) - string.gsub!(/["\\\/\x0-\x1f]/) { MAP[$&] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - c.unpack("U*").map{|c| - c>0xFFFF ? ('\ud%03x\ud%03x'%[0x7C0+c/1024,0xC00+c%1024]) : ('\u%04x'%c) - }.join("") - } - string - end - module_function :utf8_to_json - - module Pure - module Generator - # This class is used to create State instances, that are use to hold data - # while generating a JSON text from a a Ruby data structure. - class State - # Creates a State object from _opts_, which ought to be Hash to create - # a new State instance configured by _opts_, something else to create - # an unconfigured instance. If _opts_ is a State object, it is just - # returned. - def self.from_state(opts) - case opts - when self - opts - when Hash - new(opts) - else - new - end - end - - # Instantiates a new State object, configured by _opts_. - # - # _opts_ can have the following keys: - # - # * *indent*: a string used to indent levels (default: ''), - # * *space*: a string that is put after, a : or , delimiter (default: ''), - # * *space_before*: a string that is put before a : pair delimiter (default: ''), - # * *object_nl*: a string that is put at the end of a JSON object (default: ''), - # * *array_nl*: a string that is put at the end of a JSON array (default: ''), - # * *check_circular*: true if checking for circular data structures - # should be done (the default), false otherwise. - # * *check_circular*: true if checking for circular data structures - # should be done, false (the default) otherwise. - # * *allow_nan*: true if NaN, Infinity, and -Infinity should be - # generated, otherwise an exception is thrown, if these values are - # encountered. This options defaults to false. - def initialize(opts = {}) - @seen = {} - @indent = '' - @space = '' - @space_before = '' - @object_nl = '' - @array_nl = '' - @check_circular = true - @allow_nan = false - configure opts - end - - # This string is used to indent levels in the JSON text. - attr_accessor :indent - - # This string is used to insert a space between the tokens in a JSON - # string. - attr_accessor :space - - # This string is used to insert a space before the ':' in JSON objects. - attr_accessor :space_before - - # This string is put at the end of a line that holds a JSON object (or - # Hash). - attr_accessor :object_nl - - # This string is put at the end of a line that holds a JSON array. - attr_accessor :array_nl - - # This integer returns the maximum level of data structure nesting in - # the generated JSON, max_nesting = 0 if no maximum is checked. - attr_accessor :max_nesting - - def check_max_nesting(depth) # :nodoc: - return if @max_nesting.zero? - current_nesting = depth + 1 - current_nesting > @max_nesting and - raise NestingError, "nesting of #{current_nesting} is too deep" - end - - # Returns true, if circular data structures should be checked, - # otherwise returns false. - def check_circular? - @check_circular - end - - # Returns true if NaN, Infinity, and -Infinity should be considered as - # valid JSON and output. - def allow_nan? - @allow_nan - end - - # Returns _true_, if _object_ was already seen during this generating - # run. - def seen?(object) - @seen.key?(object.__id__) - end - - # Remember _object_, to find out if it was already encountered (if a - # cyclic data structure is if a cyclic data structure is rendered). - def remember(object) - @seen[object.__id__] = true - end - - # Forget _object_ for this generating run. - def forget(object) - @seen.delete object.__id__ - end - - # Configure this State instance with the Hash _opts_, and return - # itself. - def configure(opts) - @indent = opts[:indent] if opts.key?(:indent) - @space = opts[:space] if opts.key?(:space) - @space_before = opts[:space_before] if opts.key?(:space_before) - @object_nl = opts[:object_nl] if opts.key?(:object_nl) - @array_nl = opts[:array_nl] if opts.key?(:array_nl) - @check_circular = !!opts[:check_circular] if opts.key?(:check_circular) - @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan) - if !opts.key?(:max_nesting) # defaults to 19 - @max_nesting = 19 - elsif opts[:max_nesting] - @max_nesting = opts[:max_nesting] - else - @max_nesting = 0 - end - self - end - - # Returns the configuration instance variables as a hash, that can be - # passed to the configure method. - def to_h - result = {} - for iv in %w[indent space space_before object_nl array_nl check_circular allow_nan max_nesting] - result[iv.intern] = instance_variable_get("@#{iv}") - end - result - end - end - - module GeneratorMethods - module Object - # Converts this object to a string (calling #to_s), converts - # it to a JSON string, and returns the result. This is a fallback, if no - # special method #to_json was defined for some object. - def to_json(*) to_s.to_json end - end - - module Hash - # Returns a JSON string containing a JSON object, that is unparsed from - # this Hash instance. - # _state_ is a JSON::State object, that can also be used to configure the - # produced JSON string output further. - # _depth_ is used to find out nesting depth, to indent accordingly. - def to_json(state = nil, depth = 0, *) - if state - state = JSON.state.from_state(state) - state.check_max_nesting(depth) - json_check_circular(state) { json_transform(state, depth) } - else - json_transform(state, depth) - end - end - - private - - def json_check_circular(state) - if state and state.check_circular? - state.seen?(self) and raise JSON::CircularDatastructure, - "circular data structures not supported!" - state.remember self - end - yield - ensure - state and state.forget self - end - - def json_shift(state, depth) - state and not state.object_nl.empty? or return '' - state.indent * depth - end - - def json_transform(state, depth) - delim = ',' - delim << state.object_nl if state - result = '{' - result << state.object_nl if state - result << map { |key,value| - s = json_shift(state, depth + 1) - s << key.to_s.to_json(state, depth + 1) - s << state.space_before if state - s << ':' - s << state.space if state - s << value.to_json(state, depth + 1) - }.join(delim) - result << state.object_nl if state - result << json_shift(state, depth) - result << '}' - result - end - end - - module Array - # Returns a JSON string containing a JSON array, that is unparsed from - # this Array instance. - # _state_ is a JSON::State object, that can also be used to configure the - # produced JSON string output further. - # _depth_ is used to find out nesting depth, to indent accordingly. - def to_json(state = nil, depth = 0, *) - if state - state = JSON.state.from_state(state) - state.check_max_nesting(depth) - json_check_circular(state) { json_transform(state, depth) } - else - json_transform(state, depth) - end - end - - private - - def json_check_circular(state) - if state and state.check_circular? - state.seen?(self) and raise JSON::CircularDatastructure, - "circular data structures not supported!" - state.remember self - end - yield - ensure - state and state.forget self - end - - def json_shift(state, depth) - state and not state.array_nl.empty? or return '' - state.indent * depth - end - - def json_transform(state, depth) - delim = ',' - delim << state.array_nl if state - result = '[' - result << state.array_nl if state - result << map { |value| - json_shift(state, depth + 1) << value.to_json(state, depth + 1) - }.join(delim) - result << state.array_nl if state - result << json_shift(state, depth) - result << ']' - result - end - end - - module Integer - # Returns a JSON string representation for this Integer number. - def to_json(*) to_s end - end - - module Float - # Returns a JSON string representation for this Float number. - def to_json(state = nil, *) - case - when infinite? - if !state || state.allow_nan? - to_s - else - raise GeneratorError, "#{self} not allowed in JSON" - end - when nan? - if !state || state.allow_nan? - to_s - else - raise GeneratorError, "#{self} not allowed in JSON" - end - else - to_s - end - end - end - - module String - # This string should be encoded with UTF-8 A call to this method - # returns a JSON string encoded with UTF16 big endian characters as - # \u????. - def to_json(*) - '"' << JSON.utf8_to_json(self) << '"' - end - - # Module that holds the extinding methods if, the String module is - # included. - module Extend - # Raw Strings are JSON Objects (the raw bytes are stored in an array for the - # key "raw"). The Ruby String can be created by this module method. - def json_create(o) - o['raw'].pack('C*') - end - end - - # Extends _modul_ with the String::Extend module. - def self.included(modul) - modul.extend Extend - end - - # This method creates a raw object hash, that can be nested into - # other data structures and will be unparsed as a raw string. This - # method should be used, if you want to convert raw strings to JSON - # instead of UTF-8 strings, e. g. binary data. - def to_json_raw_object - { - JSON.create_id => self.class.name, - 'raw' => self.unpack('C*'), - } - end - - # This method creates a JSON text from the result of - # a call to to_json_raw_object of this String. - def to_json_raw(*args) - to_json_raw_object.to_json(*args) - end - end - - module TrueClass - # Returns a JSON string for true: 'true'. - def to_json(*) 'true' end - end - - module FalseClass - # Returns a JSON string for false: 'false'. - def to_json(*) 'false' end - end - - module NilClass - # Returns a JSON string for nil: 'null'. - def to_json(*) 'null' end - end - end - end - end -end diff --git a/ext/json/lib/json/pure/parser.rb b/ext/json/lib/json/pure/parser.rb deleted file mode 100644 index 9c3fea91da..0000000000 --- a/ext/json/lib/json/pure/parser.rb +++ /dev/null @@ -1,269 +0,0 @@ -require 'strscan' - -module JSON - module Pure - # This class implements the JSON parser that is used to parse a JSON string - # into a Ruby data structure. - class Parser < StringScanner - STRING = /" ((?:[^\x0-\x1f"\\] | - \\["\\\/bfnrt] | - \\u[0-9a-fA-F]{4} | - \\[\x20-\xff])*) - "/nx - INTEGER = /(-?0|-?[1-9]\d*)/ - FLOAT = /(-? - (?:0|[1-9]\d*) - (?: - \.\d+(?i:e[+-]?\d+) | - \.\d+ | - (?i:e[+-]?\d+) - ) - )/x - NAN = /NaN/ - INFINITY = /Infinity/ - MINUS_INFINITY = /-Infinity/ - OBJECT_OPEN = /\{/ - OBJECT_CLOSE = /\}/ - ARRAY_OPEN = /\[/ - ARRAY_CLOSE = /\]/ - PAIR_DELIMITER = /:/ - COLLECTION_DELIMITER = /,/ - TRUE = /true/ - FALSE = /false/ - NULL = /null/ - IGNORE = %r( - (?: - //[^\n\r]*[\n\r]| # line comments - /\* # c-style comments - (?: - [^*/]| # normal chars - /[^*]| # slashes that do not start a nested comment - \*[^/]| # asterisks that do not end this comment - /(?=\*/) # single slash before this comment's end - )* - \*/ # the End of this comment - |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr - )+ - )mx - - UNPARSED = Object.new - - # Creates a new JSON::Pure::Parser instance for the string _source_. - # - # It will be configured by the _opts_ hash. _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 19. - # * *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. - # * *create_additions*: If set to false, the Parser doesn't create - # additions even if a matchin class and create_id was found. This option - # defaults to true. - def initialize(source, opts = {}) - super - if !opts.key?(:max_nesting) # defaults to 19 - @max_nesting = 19 - elsif opts[:max_nesting] - @max_nesting = opts[:max_nesting] - else - @max_nesting = 0 - end - @allow_nan = !!opts[:allow_nan] - ca = true - ca = opts[:create_additions] if opts.key?(:create_additions) - @create_id = ca ? JSON.create_id : nil - end - - alias source string - - # Parses the current JSON string _source_ and returns the complete data - # structure as a result. - def parse - reset - obj = nil - until eos? - case - when scan(OBJECT_OPEN) - obj and raise ParserError, "source '#{peek(20)}' not in JSON!" - @current_nesting = 1 - obj = parse_object - when scan(ARRAY_OPEN) - obj and raise ParserError, "source '#{peek(20)}' not in JSON!" - @current_nesting = 1 - obj = parse_array - when skip(IGNORE) - ; - else - raise ParserError, "source '#{peek(20)}' not in JSON!" - end - end - obj or raise ParserError, "source did not contain any JSON!" - obj - end - - private - - # Unescape characters in strings. - UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr } - UNESCAPE_MAP.update({ - ?" => '"', - ?\\ => '\\', - ?/ => '/', - ?b => "\b", - ?f => "\f", - ?n => "\n", - ?r => "\r", - ?t => "\t", - ?u => nil, - }) - - def parse_string - if scan(STRING) - return '' if self[1].empty? - self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c| - if u = UNESCAPE_MAP[$&[1]] - u - else # \uXXXX - res = [] - stack = nil - [c.delete!('\\\\u')].pack("H*").unpack("n*").each do |c| - case c - when 0xD800..0xDBFF - raise JSON::ParserError, "partial character in source" if stack - stack = c - when 0xDC00..0xDFFF - raise JSON::ParserError, - "partial character in source" unless (0xD800..0xDBFF).include?(stack) - res << (stack << 10) - 0x35fdc00 + c - stack = nil - else - raise JSON::ParserError, "partial character in source" if stack - res << c - end - end - raise JSON::ParserError, "partial character in source" if stack - res.pack("U*") - end - end.force_encoding("UTF-8") - else - UNPARSED - end - end - - def parse_value - case - when scan(FLOAT) - Float(self[1]) - when scan(INTEGER) - Integer(self[1]) - when scan(TRUE) - true - when scan(FALSE) - false - when scan(NULL) - nil - when (string = parse_string) != UNPARSED - string - when scan(ARRAY_OPEN) - @current_nesting += 1 - ary = parse_array - @current_nesting -= 1 - ary - when scan(OBJECT_OPEN) - @current_nesting += 1 - obj = parse_object - @current_nesting -= 1 - obj - when @allow_nan && scan(NAN) - NaN - when @allow_nan && scan(INFINITY) - Infinity - when @allow_nan && scan(MINUS_INFINITY) - MinusInfinity - else - UNPARSED - end - end - - def parse_array - raise NestingError, "nesting of #@current_nesting is to deep" if - @max_nesting.nonzero? && @current_nesting > @max_nesting - result = [] - delim = false - until eos? - case - when (value = parse_value) != UNPARSED - delim = false - result << value - skip(IGNORE) - if scan(COLLECTION_DELIMITER) - delim = true - elsif match?(ARRAY_CLOSE) - ; - else - raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!" - end - when scan(ARRAY_CLOSE) - if delim - raise ParserError, "expected next element in array at '#{peek(20)}'!" - end - break - when skip(IGNORE) - ; - else - raise ParserError, "unexpected token in array at '#{peek(20)}'!" - end - end - result - end - - def parse_object - raise NestingError, "nesting of #@current_nesting is to deep" if - @max_nesting.nonzero? && @current_nesting > @max_nesting - result = {} - delim = false - until eos? - case - when (string = parse_string) != UNPARSED - skip(IGNORE) - unless scan(PAIR_DELIMITER) - raise ParserError, "expected ':' in object at '#{peek(20)}'!" - end - skip(IGNORE) - unless (value = parse_value).equal? UNPARSED - result[string] = value - delim = false - skip(IGNORE) - if scan(COLLECTION_DELIMITER) - delim = true - elsif match?(OBJECT_CLOSE) - ; - else - raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!" - end - else - raise ParserError, "expected value in object at '#{peek(20)}'!" - end - when scan(OBJECT_CLOSE) - if delim - raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!" - end - if @create_id and klassname = result[@create_id] - klass = JSON.deep_const_get klassname - break unless klass and klass.json_creatable? - result = klass.json_create(result) - end - break - when skip(IGNORE) - ; - else - raise ParserError, "unexpected token in object at '#{peek(20)}'!" - end - end - result - end - end - end -end diff --git a/ext/json/lib/json/version.rb b/ext/json/lib/json/version.rb index acf8217048..e2764b0c6e 100644 --- a/ext/json/lib/json/version.rb +++ b/ext/json/lib/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.1.3' + VERSION = '1.1.4' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/version.h b/version.h index 752d1f94f2..f58fd85075 100644 --- a/version.h +++ b/version.h @@ -1,6 +1,6 @@ #define RUBY_VERSION "1.9.1" #define RUBY_RELEASE_DATE "2009-07-15" -#define RUBY_PATCHLEVEL 239 +#define RUBY_PATCHLEVEL 240 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 9 #define RUBY_VERSION_TEENY 1 -- cgit v1.2.3