json 2.3.0 → 2.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +55 -0
  3. data/README.md +16 -0
  4. data/VERSION +1 -1
  5. data/ext/json/ext/generator/generator.c +131 -12
  6. data/ext/json/ext/generator/generator.h +5 -2
  7. data/ext/json/ext/parser/extconf.rb +25 -0
  8. data/ext/json/ext/parser/parser.c +138 -95
  9. data/ext/json/ext/parser/parser.h +1 -0
  10. data/ext/json/ext/parser/parser.rl +68 -25
  11. data/ext/json/extconf.rb +1 -0
  12. data/json.gemspec +0 -0
  13. data/lib/json.rb +549 -29
  14. data/lib/json/add/complex.rb +0 -1
  15. data/lib/json/add/rational.rb +0 -1
  16. data/lib/json/common.rb +370 -123
  17. data/lib/json/pure/generator.rb +29 -9
  18. data/lib/json/pure/parser.rb +22 -4
  19. data/lib/json/version.rb +1 -1
  20. data/tests/fixtures/fail29.json +1 -0
  21. data/tests/fixtures/fail30.json +1 -0
  22. data/tests/fixtures/fail31.json +1 -0
  23. data/tests/fixtures/fail32.json +1 -0
  24. data/tests/json_addition_test.rb +0 -4
  25. data/tests/json_common_interface_test.rb +43 -0
  26. data/tests/json_fixtures_test.rb +9 -1
  27. data/tests/json_generator_test.rb +16 -38
  28. data/tests/json_parser_test.rb +25 -0
  29. data/tests/lib/core_assertions.rb +763 -0
  30. data/tests/lib/envutil.rb +365 -0
  31. data/tests/lib/find_executable.rb +22 -0
  32. data/tests/lib/helper.rb +4 -0
  33. data/tests/ractor_test.rb +30 -0
  34. data/tests/test_helper.rb +3 -3
  35. metadata +29 -40
  36. data/.gitignore +0 -18
  37. data/.travis.yml +0 -24
  38. data/README-json-jruby.md +0 -33
  39. data/Rakefile +0 -413
  40. data/diagrams/.keep +0 -0
  41. data/install.rb +0 -23
  42. data/java/src/json/ext/ByteListTranscoder.java +0 -166
  43. data/java/src/json/ext/Generator.java +0 -466
  44. data/java/src/json/ext/GeneratorMethods.java +0 -231
  45. data/java/src/json/ext/GeneratorService.java +0 -42
  46. data/java/src/json/ext/GeneratorState.java +0 -490
  47. data/java/src/json/ext/OptionsReader.java +0 -113
  48. data/java/src/json/ext/Parser.java +0 -2362
  49. data/java/src/json/ext/Parser.rl +0 -893
  50. data/java/src/json/ext/ParserService.java +0 -34
  51. data/java/src/json/ext/RuntimeInfo.java +0 -116
  52. data/java/src/json/ext/StringDecoder.java +0 -166
  53. data/java/src/json/ext/StringEncoder.java +0 -111
  54. data/java/src/json/ext/Utils.java +0 -88
  55. data/json-java.gemspec +0 -37
  56. data/json_pure.gemspec +0 -38
  57. data/references/rfc7159.txt +0 -899
  58. data/tools/diff.sh +0 -18
  59. data/tools/fuzz.rb +0 -131
  60. data/tools/server.rb +0 -62
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca534a7e54763534530fcc4d010c6ff3e45ae08959e64d7a54e2ed6b1c4d6cf4
4
- data.tar.gz: 5ed1902c0706bb321b4f4833203c4b6ae3cd47c4303bca04977442965ef9cbe6
3
+ metadata.gz: 4ba367cf703870f72ec5de7af43e713095df4b9c88cb0ae12a4c10455052383a
4
+ data.tar.gz: 622fc0230b9a26ddde47fb3e81c2cf2f0143c22cbfd2429019db1a0f9eef5aaa
5
5
  SHA512:
6
- metadata.gz: 70cefe1d1604c66bff786a1f530acd9fab15670957b84a0efc91d450e130e0b48da6ff0d8858549413fe6beb956b3d19d313f178cbe8f5123ec32ab701635bf9
7
- data.tar.gz: d0b3f6d760d2100b47e4160f372344d057f60ddd7c58e3bc2dceb35b690cbd14e6af75a3028d121099f1586ed134876c16bdf7ad58e68c7295e5c0cc20f52538
6
+ metadata.gz: 1cab7c9113f03333b720a039fd065d5dd376ab3b4dda1630ccf316ee72121ed4a8abfc06a576be524ce7a86b78e9af917b507fbe95411efef11a563da95295c4
7
+ data.tar.gz: 68b7cec95107a831286fc3ff36971cd9cc0efbc29157bc0df95a16238b5594214ffca0d417f2dd9011f9e26bf4e163e01e179cbf06f8c053df68c4d60f2416cc
data/CHANGES.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # Changes
2
2
 
3
+ ## 2020-12-22 (2.5.1)
4
+
5
+ * Restore the compatibility for constants of JSON class.
6
+
7
+ ## 2020-12-22 (2.5.0)
8
+
9
+ * Ready to Ractor-safe at Ruby 3.0.
10
+
11
+ ## 2020-12-17 (2.4.1)
12
+
13
+ * Restore version.rb with 2.4.1
14
+
15
+ ## 2020-12-15 (2.4.0)
16
+
17
+ * Implement a freeze: parser option #447
18
+ * Fix an issue with generate_pretty and empty objects in the Ruby and Java implementations #449
19
+ * Fix JSON.load_file doc #448
20
+ * Fix pure parser with unclosed arrays / objects #425
21
+ * bundle the LICENSE file in the gem #444
22
+ * Add an option to escape forward slash character #405
23
+ * RDoc for JSON #439 #446 #442 #434 #433 #430
24
+
25
+ ## 2020-06-30 (2.3.1)
26
+
27
+ * Spelling and grammar fixes for comments. Pull request #191 by Josh
28
+ Kline.
29
+ * Enhance generic JSON and #generate docs. Pull request #347 by Victor
30
+ Shepelev.
31
+ * Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev.
32
+ * Baseline changes to help (JRuby) development. Pull request #371 by Karol
33
+ Bucek.
34
+ * Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI.
35
+ * Remove invalid JSON.generate description from JSON module rdoc. Pull
36
+ request #384 by Jeremy Evans.
37
+ * Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze.
38
+ * Rdoc enhancements. Pull request #413 by Burdette Lamar.
39
+ * Fixtures/ are not being tested... Pull request #416 by Marc-André
40
+ Lafortune.
41
+ * Use frozen string for hash key. Pull request #420 by Marc-André
42
+ Lafortune.
43
+ * Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette
44
+ Lamar.
45
+ * Small typo fix. Pull request #423 by Marc-André Lafortune.
46
+
47
+ ## 2019-12-11 (2.3.0)
48
+ * Fix default of `create_additions` to always be `false` for `JSON(user_input)`
49
+ and `JSON.parse(user_input, nil)`.
50
+ Note that `JSON.load` remains with default `true` and is meant for internal
51
+ serialization of trusted data. [CVE-2020-10663]
52
+ * Fix passing args all #to_json in json/add/*.
53
+ * Fix encoding issues
54
+ * Fix issues of keyword vs positional parameter
55
+ * Fix JSON::Parser against bigdecimal updates
56
+ * Bug fixes to JRuby port
57
+
3
58
  ## 2019-02-21 (2.2.0)
4
59
  * Adds support for 2.6 BigDecimal and ruby standard library Set datetype.
5
60
 
data/README.md CHANGED
@@ -390,6 +390,22 @@ Here are the median comparisons for completeness' sake:
390
390
  secs/call
391
391
  ```
392
392
 
393
+ ## Development
394
+
395
+ ### Release
396
+
397
+ Update the json.gemspec and json-java.gemspec.
398
+
399
+ ```
400
+ rbenv shell 2.6.5
401
+ rake build
402
+ gem push pkg/json-2.3.0.gem
403
+
404
+ rbenv shell jruby-9.2.9.0
405
+ rake build
406
+ gem push pkg/json-2.3.0-java.gem
407
+ ```
408
+
393
409
  ## Author
394
410
 
395
411
  Florian Frank <mailto:flori@ping.de>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 2.5.1
@@ -15,14 +15,13 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
15
  #endif
16
16
  mFloat, mString, mString_Extend,
17
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError,
19
- i_SAFE_STATE_PROTOTYPE;
18
+ eNestingError;
20
19
 
21
20
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
21
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
23
22
  i_pack, i_unpack, i_create_id, i_extend, i_key_p,
24
23
  i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
25
- i_buffer_initial_length, i_dup;
24
+ i_buffer_initial_length, i_dup, i_escape_slash;
26
25
 
27
26
  /*
28
27
  * Copyright 2001-2004 Unicode, Inc.
@@ -130,7 +129,7 @@ static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16
130
129
 
131
130
  /* Converts string to a JSON string in FBuffer buffer, where all but the ASCII
132
131
  * and control characters are JSON escaped. */
133
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
132
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash)
134
133
  {
135
134
  const UTF8 *source = (UTF8 *) RSTRING_PTR(string);
136
135
  const UTF8 *sourceEnd = source + RSTRING_LEN(string);
@@ -180,6 +179,11 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
180
179
  case '"':
181
180
  fbuffer_append(buffer, "\\\"", 2);
182
181
  break;
182
+ case '/':
183
+ if(escape_slash) {
184
+ fbuffer_append(buffer, "\\/", 2);
185
+ break;
186
+ }
183
187
  default:
184
188
  fbuffer_append_char(buffer, (char)ch);
185
189
  break;
@@ -229,7 +233,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
229
233
  * characters required by the JSON standard are JSON escaped. The remaining
230
234
  * characters (should be UTF8) are just passed through and appended to the
231
235
  * result. */
232
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
236
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash)
233
237
  {
234
238
  const char *ptr = RSTRING_PTR(string), *p;
235
239
  unsigned long len = RSTRING_LEN(string), start = 0, end = 0;
@@ -280,6 +284,12 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
280
284
  escape = "\\\"";
281
285
  escape_len = 2;
282
286
  break;
287
+ case '/':
288
+ if(escape_slash) {
289
+ escape = "\\/";
290
+ escape_len = 2;
291
+ break;
292
+ }
283
293
  default:
284
294
  {
285
295
  unsigned short clen = 1;
@@ -328,6 +338,76 @@ static char *fstrndup(const char *ptr, unsigned long len) {
328
338
  *
329
339
  */
330
340
 
341
+ /* Explanation of the following: that's the only way to not pollute
342
+ * standard library's docs with GeneratorMethods::<ClassName> which
343
+ * are uninformative and take a large place in a list of classes
344
+ */
345
+
346
+ /*
347
+ * Document-module: JSON::Ext::Generator::GeneratorMethods
348
+ * :nodoc:
349
+ */
350
+
351
+ /*
352
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
353
+ * :nodoc:
354
+ */
355
+
356
+ /*
357
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
358
+ * :nodoc:
359
+ */
360
+
361
+ /*
362
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
363
+ * :nodoc:
364
+ */
365
+
366
+ /*
367
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
368
+ * :nodoc:
369
+ */
370
+
371
+ /*
372
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
373
+ * :nodoc:
374
+ */
375
+
376
+ /*
377
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
378
+ * :nodoc:
379
+ */
380
+
381
+ /*
382
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
383
+ * :nodoc:
384
+ */
385
+
386
+ /*
387
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
388
+ * :nodoc:
389
+ */
390
+
391
+ /*
392
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
393
+ * :nodoc:
394
+ */
395
+
396
+ /*
397
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String
398
+ * :nodoc:
399
+ */
400
+
401
+ /*
402
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
403
+ * :nodoc:
404
+ */
405
+
406
+ /*
407
+ * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
408
+ * :nodoc:
409
+ */
410
+
331
411
  /*
332
412
  * call-seq: to_json(state = nil)
333
413
  *
@@ -539,13 +619,18 @@ static size_t State_memsize(const void *ptr)
539
619
  return size;
540
620
  }
541
621
 
622
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
623
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
624
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
625
+ #endif
626
+
542
627
  #ifdef NEW_TYPEDDATA_WRAPPER
543
628
  static const rb_data_type_t JSON_Generator_State_type = {
544
629
  "JSON/Generator/State",
545
630
  {NULL, State_free, State_memsize,},
546
631
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
547
632
  0, 0,
548
- RUBY_TYPED_FREE_IMMEDIATELY,
633
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
549
634
  #endif
550
635
  };
551
636
  #endif
@@ -646,6 +731,8 @@ static VALUE cState_configure(VALUE self, VALUE opts)
646
731
  state->allow_nan = RTEST(tmp);
647
732
  tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
648
733
  state->ascii_only = RTEST(tmp);
734
+ tmp = rb_hash_aref(opts, ID2SYM(i_escape_slash));
735
+ state->escape_slash = RTEST(tmp);
649
736
  return self;
650
737
  }
651
738
 
@@ -680,6 +767,7 @@ static VALUE cState_to_h(VALUE self)
680
767
  rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
681
768
  rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
682
769
  rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
770
+ rb_hash_aset(result, ID2SYM(i_escape_slash), state->escape_slash ? Qtrue : Qfalse);
683
771
  rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
684
772
  rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
685
773
  return result;
@@ -864,9 +952,9 @@ static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
864
952
  }
865
953
  #endif
866
954
  if (state->ascii_only) {
867
- convert_UTF8_to_JSON_ASCII(buffer, obj);
955
+ convert_UTF8_to_JSON_ASCII(buffer, obj, state->escape_slash);
868
956
  } else {
869
- convert_UTF8_to_JSON(buffer, obj);
957
+ convert_UTF8_to_JSON(buffer, obj, state->escape_slash);
870
958
  }
871
959
  fbuffer_append_char(buffer, '"');
872
960
  }
@@ -1026,7 +1114,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
1026
1114
  * generated, otherwise an exception is thrown, if these values are
1027
1115
  * encountered. This options defaults to false.
1028
1116
  * * *ascii_only*: true if only ASCII characters should be generated. This
1029
- * ontions defaults to false.
1117
+ * option defaults to false.
1030
1118
  * * *buffer_initial_length*: sets the initial length of the generator's
1031
1119
  * internal buffer.
1032
1120
  */
@@ -1082,8 +1170,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1082
1170
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1083
1171
  return rb_funcall(self, i_new, 1, opts);
1084
1172
  } else {
1085
- VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1086
- return rb_funcall(prototype, i_dup, 0);
1173
+ return rb_class_new_instance(0, NULL, cState);
1087
1174
  }
1088
1175
  }
1089
1176
 
@@ -1307,6 +1394,31 @@ static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1307
1394
  return state->max_nesting = FIX2LONG(depth);
1308
1395
  }
1309
1396
 
1397
+ /*
1398
+ * call-seq: escape_slash
1399
+ *
1400
+ * If this boolean is true, the forward slashes will be escaped in
1401
+ * the json output.
1402
+ */
1403
+ static VALUE cState_escape_slash(VALUE self)
1404
+ {
1405
+ GET_STATE(self);
1406
+ return state->escape_slash ? Qtrue : Qfalse;
1407
+ }
1408
+
1409
+ /*
1410
+ * call-seq: escape_slash=(depth)
1411
+ *
1412
+ * This sets whether or not the forward slashes will be escaped in
1413
+ * the json output.
1414
+ */
1415
+ static VALUE cState_escape_slash_set(VALUE self, VALUE enable)
1416
+ {
1417
+ GET_STATE(self);
1418
+ state->escape_slash = RTEST(enable);
1419
+ return Qnil;
1420
+ }
1421
+
1310
1422
  /*
1311
1423
  * call-seq: allow_nan?
1312
1424
  *
@@ -1390,6 +1502,10 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1390
1502
  */
1391
1503
  void Init_generator(void)
1392
1504
  {
1505
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1506
+ rb_ext_ractor_safe(true);
1507
+ #endif
1508
+
1393
1509
  #undef rb_intern
1394
1510
  rb_require("json/common");
1395
1511
 
@@ -1419,6 +1535,9 @@ void Init_generator(void)
1419
1535
  rb_define_method(cState, "array_nl=", cState_array_nl_set, 1);
1420
1536
  rb_define_method(cState, "max_nesting", cState_max_nesting, 0);
1421
1537
  rb_define_method(cState, "max_nesting=", cState_max_nesting_set, 1);
1538
+ rb_define_method(cState, "escape_slash", cState_escape_slash, 0);
1539
+ rb_define_method(cState, "escape_slash?", cState_escape_slash, 0);
1540
+ rb_define_method(cState, "escape_slash=", cState_escape_slash_set, 1);
1422
1541
  rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
1423
1542
  rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
1424
1543
  rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
@@ -1475,6 +1594,7 @@ void Init_generator(void)
1475
1594
  i_object_nl = rb_intern("object_nl");
1476
1595
  i_array_nl = rb_intern("array_nl");
1477
1596
  i_max_nesting = rb_intern("max_nesting");
1597
+ i_escape_slash = rb_intern("escape_slash");
1478
1598
  i_allow_nan = rb_intern("allow_nan");
1479
1599
  i_ascii_only = rb_intern("ascii_only");
1480
1600
  i_depth = rb_intern("depth");
@@ -1495,5 +1615,4 @@ void Init_generator(void)
1495
1615
  i_encoding = rb_intern("encoding");
1496
1616
  i_encode = rb_intern("encode");
1497
1617
  #endif
1498
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1499
1618
  }
@@ -49,8 +49,8 @@ static const UTF32 halfMask = 0x3FFUL;
49
49
  static unsigned char isLegalUTF8(const UTF8 *source, unsigned long length);
50
50
  static void unicode_escape(char *buf, UTF16 character);
51
51
  static void unicode_escape_to_buffer(FBuffer *buffer, char buf[6], UTF16 character);
52
- static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string);
53
- static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string);
52
+ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string, char escape_slash);
53
+ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string, char escape_slash);
54
54
  static char *fstrndup(const char *ptr, unsigned long len);
55
55
 
56
56
  /* ruby api and some helpers */
@@ -72,6 +72,7 @@ typedef struct JSON_Generator_StateStruct {
72
72
  long max_nesting;
73
73
  char allow_nan;
74
74
  char ascii_only;
75
+ char escape_slash;
75
76
  long depth;
76
77
  long buffer_initial_length;
77
78
  } JSON_Generator_State;
@@ -150,6 +151,8 @@ static VALUE cState_allow_nan_p(VALUE self);
150
151
  static VALUE cState_ascii_only_p(VALUE self);
151
152
  static VALUE cState_depth(VALUE self);
152
153
  static VALUE cState_depth_set(VALUE self, VALUE depth);
154
+ static VALUE cState_escape_slash(VALUE self);
155
+ static VALUE cState_escape_slash_set(VALUE self, VALUE depth);
153
156
  static FBuffer *cState_prepare_buffer(VALUE self);
154
157
  #ifndef ZALLOC
155
158
  #define ZALLOC(type) ((type *)ruby_zalloc(sizeof(type)))
@@ -3,4 +3,29 @@ require 'mkmf'
3
3
 
4
4
  have_func("rb_enc_raise", "ruby.h")
5
5
 
6
+ # checking if String#-@ (str_uminus) dedupes... '
7
+ begin
8
+ a = -(%w(t e s t).join)
9
+ b = -(%w(t e s t).join)
10
+ if a.equal?(b)
11
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
12
+ else
13
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
14
+ end
15
+ rescue NoMethodError
16
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
17
+ end
18
+
19
+ # checking if String#-@ (str_uminus) directly interns frozen strings... '
20
+ begin
21
+ s = rand.to_s.freeze
22
+ if (-s).equal?(s) && (-s.dup).equal?(s)
23
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
24
+ else
25
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
26
+ end
27
+ rescue NoMethodError
28
+ $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
29
+ end
30
+
6
31
  create_makefile 'json/ext/parser'
@@ -1,4 +1,4 @@
1
-
1
+ /* This file is automatically generated from parser.rl by using ragel */
2
2
  #line 1 "parser.rl"
3
3
  #include "../fbuffer/fbuffer.h"
4
4
  #include "parser.h"
@@ -91,13 +91,12 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
91
91
 
92
92
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
93
93
  static VALUE CNaN, CInfinity, CMinusInfinity;
94
- static VALUE cBigDecimal = Qundef;
95
94
 
96
95
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
97
96
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
98
97
  i_object_class, i_array_class, i_decimal_class, i_key_p,
99
98
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
100
- i_leftshift, i_new, i_BigDecimal;
99
+ i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
101
100
 
102
101
 
103
102
  #line 126 "parser.rl"
@@ -112,7 +111,7 @@ enum {JSON_object_error = 0};
112
111
  enum {JSON_object_en_main = 1};
113
112
 
114
113
 
115
- #line 167 "parser.rl"
114
+ #line 168 "parser.rl"
116
115
 
117
116
 
118
117
  static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -133,7 +132,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
133
132
  cs = JSON_object_start;
134
133
  }
135
134
 
136
- #line 182 "parser.rl"
135
+ #line 183 "parser.rl"
137
136
 
138
137
  #line 139 "parser.c"
139
138
  {
@@ -163,7 +162,7 @@ case 2:
163
162
  goto st2;
164
163
  goto st0;
165
164
  tr2:
166
- #line 149 "parser.rl"
165
+ #line 150 "parser.rl"
167
166
  {
168
167
  char *np;
169
168
  json->parsing_name = 1;
@@ -251,6 +250,7 @@ tr11:
251
250
  p--; {p++; cs = 9; goto _out;}
252
251
  } else {
253
252
  if (NIL_P(json->object_class)) {
253
+ OBJ_FREEZE(last_name);
254
254
  rb_hash_aset(*result, last_name, v);
255
255
  } else {
256
256
  rb_funcall(*result, i_aset, 2, last_name, v);
@@ -263,7 +263,7 @@ st9:
263
263
  if ( ++p == pe )
264
264
  goto _test_eof9;
265
265
  case 9:
266
- #line 267 "parser.c"
266
+ #line 268 "parser.c"
267
267
  switch( (*p) ) {
268
268
  case 13: goto st9;
269
269
  case 32: goto st9;
@@ -352,14 +352,14 @@ case 18:
352
352
  goto st9;
353
353
  goto st18;
354
354
  tr4:
355
- #line 157 "parser.rl"
355
+ #line 158 "parser.rl"
356
356
  { p--; {p++; cs = 27; goto _out;} }
357
357
  goto st27;
358
358
  st27:
359
359
  if ( ++p == pe )
360
360
  goto _test_eof27;
361
361
  case 27:
362
- #line 363 "parser.c"
362
+ #line 364 "parser.c"
363
363
  goto st0;
364
364
  st19:
365
365
  if ( ++p == pe )
@@ -457,7 +457,7 @@ case 26:
457
457
  _out: {}
458
458
  }
459
459
 
460
- #line 183 "parser.rl"
460
+ #line 184 "parser.rl"
461
461
 
462
462
  if (cs >= JSON_object_first_final) {
463
463
  if (json->create_additions) {
@@ -482,7 +482,7 @@ case 26:
482
482
 
483
483
 
484
484
 
485
- #line 486 "parser.c"
485
+ #line 487 "parser.c"
486
486
  enum {JSON_value_start = 1};
487
487
  enum {JSON_value_first_final = 29};
488
488
  enum {JSON_value_error = 0};
@@ -490,7 +490,7 @@ enum {JSON_value_error = 0};
490
490
  enum {JSON_value_en_main = 1};
491
491
 
492
492
 
493
- #line 283 "parser.rl"
493
+ #line 284 "parser.rl"
494
494
 
495
495
 
496
496
  static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -498,14 +498,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
498
498
  int cs = EVIL;
499
499
 
500
500
 
501
- #line 502 "parser.c"
501
+ #line 503 "parser.c"
502
502
  {
503
503
  cs = JSON_value_start;
504
504
  }
505
505
 
506
- #line 290 "parser.rl"
506
+ #line 291 "parser.rl"
507
507
 
508
- #line 509 "parser.c"
508
+ #line 510 "parser.c"
509
509
  {
510
510
  if ( p == pe )
511
511
  goto _test_eof;
@@ -539,14 +539,14 @@ st0:
539
539
  cs = 0;
540
540
  goto _out;
541
541
  tr2:
542
- #line 235 "parser.rl"
542
+ #line 236 "parser.rl"
543
543
  {
544
544
  char *np = JSON_parse_string(json, p, pe, result);
545
545
  if (np == NULL) { p--; {p++; cs = 29; goto _out;} } else {p = (( np))-1;}
546
546
  }
547
547
  goto st29;
548
548
  tr3:
549
- #line 240 "parser.rl"
549
+ #line 241 "parser.rl"
550
550
  {
551
551
  char *np;
552
552
  if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) {
@@ -566,7 +566,7 @@ tr3:
566
566
  }
567
567
  goto st29;
568
568
  tr7:
569
- #line 258 "parser.rl"
569
+ #line 259 "parser.rl"
570
570
  {
571
571
  char *np;
572
572
  np = JSON_parse_array(json, p, pe, result, current_nesting + 1);
@@ -574,7 +574,7 @@ tr7:
574
574
  }
575
575
  goto st29;
576
576
  tr11:
577
- #line 264 "parser.rl"
577
+ #line 265 "parser.rl"
578
578
  {
579
579
  char *np;
580
580
  np = JSON_parse_object(json, p, pe, result, current_nesting + 1);
@@ -582,7 +582,7 @@ tr11:
582
582
  }
583
583
  goto st29;
584
584
  tr25:
585
- #line 228 "parser.rl"
585
+ #line 229 "parser.rl"
586
586
  {
587
587
  if (json->allow_nan) {
588
588
  *result = CInfinity;
@@ -592,7 +592,7 @@ tr25:
592
592
  }
593
593
  goto st29;
594
594
  tr27:
595
- #line 221 "parser.rl"
595
+ #line 222 "parser.rl"
596
596
  {
597
597
  if (json->allow_nan) {
598
598
  *result = CNaN;
@@ -602,19 +602,19 @@ tr27:
602
602
  }
603
603
  goto st29;
604
604
  tr31:
605
- #line 215 "parser.rl"
605
+ #line 216 "parser.rl"
606
606
  {
607
607
  *result = Qfalse;
608
608
  }
609
609
  goto st29;
610
610
  tr34:
611
- #line 212 "parser.rl"
611
+ #line 213 "parser.rl"
612
612
  {
613
613
  *result = Qnil;
614
614
  }
615
615
  goto st29;
616
616
  tr37:
617
- #line 218 "parser.rl"
617
+ #line 219 "parser.rl"
618
618
  {
619
619
  *result = Qtrue;
620
620
  }
@@ -623,9 +623,9 @@ st29:
623
623
  if ( ++p == pe )
624
624
  goto _test_eof29;
625
625
  case 29:
626
- #line 270 "parser.rl"
626
+ #line 271 "parser.rl"
627
627
  { p--; {p++; cs = 29; goto _out;} }
628
- #line 629 "parser.c"
628
+ #line 630 "parser.c"
629
629
  switch( (*p) ) {
630
630
  case 13: goto st29;
631
631
  case 32: goto st29;
@@ -866,7 +866,11 @@ case 28:
866
866
  _out: {}
867
867
  }
868
868
 
869
- #line 291 "parser.rl"
869
+ #line 292 "parser.rl"
870
+
871
+ if (json->freeze) {
872
+ OBJ_FREEZE(*result);
873
+ }
870
874
 
871
875
  if (cs >= JSON_value_first_final) {
872
876
  return p;
@@ -876,7 +880,7 @@ case 28:
876
880
  }
877
881
 
878
882
 
879
- #line 880 "parser.c"
883
+ #line 885 "parser.c"
880
884
  enum {JSON_integer_start = 1};
881
885
  enum {JSON_integer_first_final = 3};
882
886
  enum {JSON_integer_error = 0};
@@ -884,7 +888,7 @@ enum {JSON_integer_error = 0};
884
888
  enum {JSON_integer_en_main = 1};
885
889
 
886
890
 
887
- #line 307 "parser.rl"
891
+ #line 312 "parser.rl"
888
892
 
889
893
 
890
894
  static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
@@ -892,15 +896,15 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
892
896
  int cs = EVIL;
893
897
 
894
898
 
895
- #line 896 "parser.c"
899
+ #line 901 "parser.c"
896
900
  {
897
901
  cs = JSON_integer_start;
898
902
  }
899
903
 
900
- #line 314 "parser.rl"
904
+ #line 319 "parser.rl"
901
905
  json->memo = p;
902
906
 
903
- #line 904 "parser.c"
907
+ #line 909 "parser.c"
904
908
  {
905
909
  if ( p == pe )
906
910
  goto _test_eof;
@@ -934,14 +938,14 @@ case 3:
934
938
  goto st0;
935
939
  goto tr4;
936
940
  tr4:
937
- #line 304 "parser.rl"
941
+ #line 309 "parser.rl"
938
942
  { p--; {p++; cs = 4; goto _out;} }
939
943
  goto st4;
940
944
  st4:
941
945
  if ( ++p == pe )
942
946
  goto _test_eof4;
943
947
  case 4:
944
- #line 945 "parser.c"
948
+ #line 950 "parser.c"
945
949
  goto st0;
946
950
  st5:
947
951
  if ( ++p == pe )
@@ -960,7 +964,7 @@ case 5:
960
964
  _out: {}
961
965
  }
962
966
 
963
- #line 316 "parser.rl"
967
+ #line 321 "parser.rl"
964
968
 
965
969
  if (cs >= JSON_integer_first_final) {
966
970
  long len = p - json->memo;
@@ -975,7 +979,7 @@ case 5:
975
979
  }
976
980
 
977
981
 
978
- #line 979 "parser.c"
982
+ #line 984 "parser.c"
979
983
  enum {JSON_float_start = 1};
980
984
  enum {JSON_float_first_final = 8};
981
985
  enum {JSON_float_error = 0};
@@ -983,36 +987,23 @@ enum {JSON_float_error = 0};
983
987
  enum {JSON_float_en_main = 1};
984
988
 
985
989
 
986
- #line 341 "parser.rl"
990
+ #line 346 "parser.rl"
987
991
 
988
992
 
989
- static int is_bigdecimal_class(VALUE obj)
990
- {
991
- if (cBigDecimal == Qundef) {
992
- if (rb_const_defined(rb_cObject, i_BigDecimal)) {
993
- cBigDecimal = rb_const_get_at(rb_cObject, i_BigDecimal);
994
- }
995
- else {
996
- return 0;
997
- }
998
- }
999
- return obj == cBigDecimal;
1000
- }
1001
-
1002
993
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
1003
994
  {
1004
995
  int cs = EVIL;
1005
996
 
1006
997
 
1007
- #line 1008 "parser.c"
998
+ #line 1013 "parser.c"
1008
999
  {
1009
1000
  cs = JSON_float_start;
1010
1001
  }
1011
1002
 
1012
- #line 361 "parser.rl"
1003
+ #line 366 "parser.rl"
1013
1004
  json->memo = p;
1014
1005
 
1015
- #line 1016 "parser.c"
1006
+ #line 1021 "parser.c"
1016
1007
  {
1017
1008
  if ( p == pe )
1018
1009
  goto _test_eof;
@@ -1070,14 +1061,14 @@ case 8:
1070
1061
  goto st0;
1071
1062
  goto tr9;
1072
1063
  tr9:
1073
- #line 335 "parser.rl"
1064
+ #line 340 "parser.rl"
1074
1065
  { p--; {p++; cs = 9; goto _out;} }
1075
1066
  goto st9;
1076
1067
  st9:
1077
1068
  if ( ++p == pe )
1078
1069
  goto _test_eof9;
1079
1070
  case 9:
1080
- #line 1081 "parser.c"
1071
+ #line 1086 "parser.c"
1081
1072
  goto st0;
1082
1073
  st5:
1083
1074
  if ( ++p == pe )
@@ -1138,24 +1129,49 @@ case 7:
1138
1129
  _out: {}
1139
1130
  }
1140
1131
 
1141
- #line 363 "parser.rl"
1132
+ #line 368 "parser.rl"
1142
1133
 
1143
1134
  if (cs >= JSON_float_first_final) {
1135
+ VALUE mod = Qnil;
1136
+ ID method_id = 0;
1137
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
1138
+ mod = json->decimal_class;
1139
+ method_id = i_try_convert;
1140
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
1141
+ mod = json->decimal_class;
1142
+ method_id = i_new;
1143
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
1144
+ VALUE name = rb_class_name(json->decimal_class);
1145
+ const char *name_cstr = RSTRING_PTR(name);
1146
+ const char *last_colon = strrchr(name_cstr, ':');
1147
+ if (last_colon) {
1148
+ const char *mod_path_end = last_colon - 1;
1149
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
1150
+ mod = rb_path_to_class(mod_path);
1151
+
1152
+ const char *method_name_beg = last_colon + 1;
1153
+ long before_len = method_name_beg - name_cstr;
1154
+ long len = RSTRING_LEN(name) - before_len;
1155
+ VALUE method_name = rb_str_substr(name, before_len, len);
1156
+ method_id = SYM2ID(rb_str_intern(method_name));
1157
+ } else {
1158
+ mod = rb_mKernel;
1159
+ method_id = SYM2ID(rb_str_intern(name));
1160
+ }
1161
+ }
1162
+
1144
1163
  long len = p - json->memo;
1145
1164
  fbuffer_clear(json->fbuffer);
1146
1165
  fbuffer_append(json->fbuffer, json->memo, len);
1147
1166
  fbuffer_append_char(json->fbuffer, '\0');
1148
- if (NIL_P(json->decimal_class)) {
1149
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1167
+
1168
+ if (method_id) {
1169
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1170
+ *result = rb_funcallv(mod, method_id, 1, &text);
1150
1171
  } else {
1151
- VALUE text;
1152
- text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1153
- if (is_bigdecimal_class(json->decimal_class)) {
1154
- *result = rb_funcall(Qnil, i_BigDecimal, 1, text);
1155
- } else {
1156
- *result = rb_funcall(json->decimal_class, i_new, 1, text);
1157
- }
1172
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1158
1173
  }
1174
+
1159
1175
  return p + 1;
1160
1176
  } else {
1161
1177
  return NULL;
@@ -1164,7 +1180,7 @@ case 7:
1164
1180
 
1165
1181
 
1166
1182
 
1167
- #line 1168 "parser.c"
1183
+ #line 1173 "parser.c"
1168
1184
  enum {JSON_array_start = 1};
1169
1185
  enum {JSON_array_first_final = 17};
1170
1186
  enum {JSON_array_error = 0};
@@ -1172,7 +1188,7 @@ enum {JSON_array_error = 0};
1172
1188
  enum {JSON_array_en_main = 1};
1173
1189
 
1174
1190
 
1175
- #line 416 "parser.rl"
1191
+ #line 421 "parser.rl"
1176
1192
 
1177
1193
 
1178
1194
  static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
@@ -1186,14 +1202,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
1186
1202
  *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
1187
1203
 
1188
1204
 
1189
- #line 1190 "parser.c"
1205
+ #line 1195 "parser.c"
1190
1206
  {
1191
1207
  cs = JSON_array_start;
1192
1208
  }
1193
1209
 
1194
- #line 429 "parser.rl"
1210
+ #line 434 "parser.rl"
1195
1211
 
1196
- #line 1197 "parser.c"
1212
+ #line 1202 "parser.c"
1197
1213
  {
1198
1214
  if ( p == pe )
1199
1215
  goto _test_eof;
@@ -1232,7 +1248,7 @@ case 2:
1232
1248
  goto st2;
1233
1249
  goto st0;
1234
1250
  tr2:
1235
- #line 393 "parser.rl"
1251
+ #line 398 "parser.rl"
1236
1252
  {
1237
1253
  VALUE v = Qnil;
1238
1254
  char *np = JSON_parse_value(json, p, pe, &v, current_nesting);
@@ -1252,7 +1268,7 @@ st3:
1252
1268
  if ( ++p == pe )
1253
1269
  goto _test_eof3;
1254
1270
  case 3:
1255
- #line 1256 "parser.c"
1271
+ #line 1261 "parser.c"
1256
1272
  switch( (*p) ) {
1257
1273
  case 13: goto st3;
1258
1274
  case 32: goto st3;
@@ -1352,14 +1368,14 @@ case 12:
1352
1368
  goto st3;
1353
1369
  goto st12;
1354
1370
  tr4:
1355
- #line 408 "parser.rl"
1371
+ #line 413 "parser.rl"
1356
1372
  { p--; {p++; cs = 17; goto _out;} }
1357
1373
  goto st17;
1358
1374
  st17:
1359
1375
  if ( ++p == pe )
1360
1376
  goto _test_eof17;
1361
1377
  case 17:
1362
- #line 1363 "parser.c"
1378
+ #line 1368 "parser.c"
1363
1379
  goto st0;
1364
1380
  st13:
1365
1381
  if ( ++p == pe )
@@ -1415,7 +1431,7 @@ case 16:
1415
1431
  _out: {}
1416
1432
  }
1417
1433
 
1418
- #line 430 "parser.rl"
1434
+ #line 435 "parser.rl"
1419
1435
 
1420
1436
  if(cs >= JSON_array_first_final) {
1421
1437
  return p + 1;
@@ -1504,7 +1520,7 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
1504
1520
  }
1505
1521
 
1506
1522
 
1507
- #line 1508 "parser.c"
1523
+ #line 1513 "parser.c"
1508
1524
  enum {JSON_string_start = 1};
1509
1525
  enum {JSON_string_first_final = 8};
1510
1526
  enum {JSON_string_error = 0};
@@ -1512,7 +1528,7 @@ enum {JSON_string_error = 0};
1512
1528
  enum {JSON_string_en_main = 1};
1513
1529
 
1514
1530
 
1515
- #line 537 "parser.rl"
1531
+ #line 542 "parser.rl"
1516
1532
 
1517
1533
 
1518
1534
  static int
@@ -1534,15 +1550,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
1534
1550
 
1535
1551
  *result = rb_str_buf_new(0);
1536
1552
 
1537
- #line 1538 "parser.c"
1553
+ #line 1543 "parser.c"
1538
1554
  {
1539
1555
  cs = JSON_string_start;
1540
1556
  }
1541
1557
 
1542
- #line 558 "parser.rl"
1558
+ #line 563 "parser.rl"
1543
1559
  json->memo = p;
1544
1560
 
1545
- #line 1546 "parser.c"
1561
+ #line 1551 "parser.c"
1546
1562
  {
1547
1563
  if ( p == pe )
1548
1564
  goto _test_eof;
@@ -1563,11 +1579,11 @@ case 2:
1563
1579
  case 34: goto tr2;
1564
1580
  case 92: goto st3;
1565
1581
  }
1566
- if ( 0 <= (*p) && (*p) <= 31 )
1582
+ if ( 0 <= (signed char)(*p) && (*p) <= 31 )
1567
1583
  goto st0;
1568
1584
  goto st2;
1569
1585
  tr2:
1570
- #line 523 "parser.rl"
1586
+ #line 528 "parser.rl"
1571
1587
  {
1572
1588
  *result = json_string_unescape(*result, json->memo + 1, p);
1573
1589
  if (NIL_P(*result)) {
@@ -1578,14 +1594,14 @@ tr2:
1578
1594
  {p = (( p + 1))-1;}
1579
1595
  }
1580
1596
  }
1581
- #line 534 "parser.rl"
1597
+ #line 539 "parser.rl"
1582
1598
  { p--; {p++; cs = 8; goto _out;} }
1583
1599
  goto st8;
1584
1600
  st8:
1585
1601
  if ( ++p == pe )
1586
1602
  goto _test_eof8;
1587
1603
  case 8:
1588
- #line 1589 "parser.c"
1604
+ #line 1594 "parser.c"
1589
1605
  goto st0;
1590
1606
  st3:
1591
1607
  if ( ++p == pe )
@@ -1593,7 +1609,7 @@ st3:
1593
1609
  case 3:
1594
1610
  if ( (*p) == 117 )
1595
1611
  goto st4;
1596
- if ( 0 <= (*p) && (*p) <= 31 )
1612
+ if ( 0 <= (signed char)(*p) && (*p) <= 31 )
1597
1613
  goto st0;
1598
1614
  goto st2;
1599
1615
  st4:
@@ -1661,7 +1677,7 @@ case 7:
1661
1677
  _out: {}
1662
1678
  }
1663
1679
 
1664
- #line 560 "parser.rl"
1680
+ #line 565 "parser.rl"
1665
1681
 
1666
1682
  if (json->create_additions && RTEST(match_string = json->match_string)) {
1667
1683
  VALUE klass;
@@ -1677,7 +1693,22 @@ case 7:
1677
1693
  if (json->symbolize_names && json->parsing_name) {
1678
1694
  *result = rb_str_intern(*result);
1679
1695
  } else if (RB_TYPE_P(*result, T_STRING)) {
1696
+ # if STR_UMINUS_DEDUPE_FROZEN
1697
+ if (json->freeze) {
1698
+ // Starting from MRI 2.8 it is preferable to freeze the string
1699
+ // before deduplication so that it can be interned directly
1700
+ // otherwise it would be duplicated first which is wasteful.
1701
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
1702
+ }
1703
+ # elif STR_UMINUS_DEDUPE
1704
+ if (json->freeze) {
1705
+ // MRI 2.5 and older do not deduplicate strings that are already
1706
+ // frozen.
1707
+ *result = rb_funcall(*result, i_uminus, 0);
1708
+ }
1709
+ # else
1680
1710
  rb_str_resize(*result, RSTRING_LEN(*result));
1711
+ # endif
1681
1712
  }
1682
1713
  if (cs >= JSON_string_first_final) {
1683
1714
  return p + 1;
@@ -1785,6 +1816,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1785
1816
  } else {
1786
1817
  json->symbolize_names = 0;
1787
1818
  }
1819
+ tmp = ID2SYM(i_freeze);
1820
+ if (option_given_p(opts, tmp)) {
1821
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
1822
+ } else {
1823
+ json->freeze = 0;
1824
+ }
1788
1825
  tmp = ID2SYM(i_create_additions);
1789
1826
  if (option_given_p(opts, tmp)) {
1790
1827
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -1848,7 +1885,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
1848
1885
  }
1849
1886
 
1850
1887
 
1851
- #line 1852 "parser.c"
1888
+ #line 1878 "parser.c"
1852
1889
  enum {JSON_start = 1};
1853
1890
  enum {JSON_first_final = 10};
1854
1891
  enum {JSON_error = 0};
@@ -1856,7 +1893,7 @@ enum {JSON_error = 0};
1856
1893
  enum {JSON_en_main = 1};
1857
1894
 
1858
1895
 
1859
- #line 760 "parser.rl"
1896
+ #line 786 "parser.rl"
1860
1897
 
1861
1898
 
1862
1899
  /*
@@ -1873,16 +1910,16 @@ static VALUE cParser_parse(VALUE self)
1873
1910
  GET_PARSER;
1874
1911
 
1875
1912
 
1876
- #line 1877 "parser.c"
1913
+ #line 1903 "parser.c"
1877
1914
  {
1878
1915
  cs = JSON_start;
1879
1916
  }
1880
1917
 
1881
- #line 776 "parser.rl"
1918
+ #line 802 "parser.rl"
1882
1919
  p = json->source;
1883
1920
  pe = p + json->len;
1884
1921
 
1885
- #line 1886 "parser.c"
1922
+ #line 1912 "parser.c"
1886
1923
  {
1887
1924
  if ( p == pe )
1888
1925
  goto _test_eof;
@@ -1916,7 +1953,7 @@ st0:
1916
1953
  cs = 0;
1917
1954
  goto _out;
1918
1955
  tr2:
1919
- #line 752 "parser.rl"
1956
+ #line 778 "parser.rl"
1920
1957
  {
1921
1958
  char *np = JSON_parse_value(json, p, pe, &result, 0);
1922
1959
  if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;}
@@ -1926,7 +1963,7 @@ st10:
1926
1963
  if ( ++p == pe )
1927
1964
  goto _test_eof10;
1928
1965
  case 10:
1929
- #line 1930 "parser.c"
1966
+ #line 1956 "parser.c"
1930
1967
  switch( (*p) ) {
1931
1968
  case 13: goto st10;
1932
1969
  case 32: goto st10;
@@ -2015,7 +2052,7 @@ case 9:
2015
2052
  _out: {}
2016
2053
  }
2017
2054
 
2018
- #line 779 "parser.rl"
2055
+ #line 805 "parser.rl"
2019
2056
 
2020
2057
  if (cs >= JSON_first_final && p == pe) {
2021
2058
  return result;
@@ -2082,6 +2119,10 @@ static VALUE cParser_source(VALUE self)
2082
2119
 
2083
2120
  void Init_parser(void)
2084
2121
  {
2122
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
2123
+ rb_ext_ractor_safe(true);
2124
+ #endif
2125
+
2085
2126
  #undef rb_intern
2086
2127
  rb_require("json/common");
2087
2128
  mJSON = rb_define_module("JSON");
@@ -2124,7 +2165,9 @@ void Init_parser(void)
2124
2165
  i_aref = rb_intern("[]");
2125
2166
  i_leftshift = rb_intern("<<");
2126
2167
  i_new = rb_intern("new");
2127
- i_BigDecimal = rb_intern("BigDecimal");
2168
+ i_try_convert = rb_intern("try_convert");
2169
+ i_freeze = rb_intern("freeze");
2170
+ i_uminus = rb_intern("-@");
2128
2171
  }
2129
2172
 
2130
2173
  /*