json 2.3.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -37,6 +37,7 @@ typedef struct JSON_ParserStruct {
37
37
  int allow_nan;
38
38
  int parsing_name;
39
39
  int symbolize_names;
40
+ int freeze;
40
41
  VALUE object_class;
41
42
  VALUE array_class;
42
43
  VALUE decimal_class;
@@ -95,7 +95,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
95
95
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
96
96
  i_object_class, i_array_class, i_decimal_class, i_key_p,
97
97
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
98
- i_leftshift, i_new, i_BigDecimal;
98
+ i_leftshift, i_new, i_BigDecimal, i_freeze, i_uminus;
99
99
 
100
100
  %%{
101
101
  machine JSON_common;
@@ -290,6 +290,10 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul
290
290
  %% write init;
291
291
  %% write exec;
292
292
 
293
+ if (json->freeze) {
294
+ OBJ_FREEZE(*result);
295
+ }
296
+
293
297
  if (cs >= JSON_value_first_final) {
294
298
  return p;
295
299
  } else {
@@ -573,7 +577,22 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
573
577
  if (json->symbolize_names && json->parsing_name) {
574
578
  *result = rb_str_intern(*result);
575
579
  } else if (RB_TYPE_P(*result, T_STRING)) {
580
+ # if STR_UMINUS_DEDUPE_FROZEN
581
+ if (json->freeze) {
582
+ // Starting from MRI 2.8 it is preferable to freeze the string
583
+ // before deduplication so that it can be interned directly
584
+ // otherwise it would be duplicated first which is wasteful.
585
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
586
+ }
587
+ # elif STR_UMINUS_DEDUPE
588
+ if (json->freeze) {
589
+ // MRI 2.5 and older do not deduplicate strings that are already
590
+ // frozen.
591
+ *result = rb_funcall(*result, i_uminus, 0);
592
+ }
593
+ # else
576
594
  rb_str_resize(*result, RSTRING_LEN(*result));
595
+ # endif
577
596
  }
578
597
  if (cs >= JSON_string_first_final) {
579
598
  return p + 1;
@@ -681,6 +700,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
681
700
  } else {
682
701
  json->symbolize_names = 0;
683
702
  }
703
+ tmp = ID2SYM(i_freeze);
704
+ if (option_given_p(opts, tmp)) {
705
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
706
+ } else {
707
+ json->freeze = 0;
708
+ }
684
709
  tmp = ID2SYM(i_create_additions);
685
710
  if (option_given_p(opts, tmp)) {
686
711
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
@@ -886,6 +911,8 @@ void Init_parser(void)
886
911
  i_leftshift = rb_intern("<<");
887
912
  i_new = rb_intern("new");
888
913
  i_BigDecimal = rb_intern("BigDecimal");
914
+ i_freeze = rb_intern("freeze");
915
+ i_uminus = rb_intern("-@");
889
916
  }
890
917
 
891
918
  /*
@@ -1,2 +1,3 @@
1
1
  require 'mkmf'
2
+
2
3
  create_makefile('json')
@@ -10,13 +10,10 @@ import org.jruby.RubyArray;
10
10
  import org.jruby.RubyBasicObject;
11
11
  import org.jruby.RubyBignum;
12
12
  import org.jruby.RubyBoolean;
13
- import org.jruby.RubyClass;
14
13
  import org.jruby.RubyFixnum;
15
14
  import org.jruby.RubyFloat;
16
15
  import org.jruby.RubyHash;
17
- import org.jruby.RubyNumeric;
18
16
  import org.jruby.RubyString;
19
- import org.jruby.runtime.ClassIndex;
20
17
  import org.jruby.runtime.ThreadContext;
21
18
  import org.jruby.runtime.builtin.IRubyObject;
22
19
  import org.jruby.util.ByteList;
@@ -32,8 +29,7 @@ public final class Generator {
32
29
  static <T extends IRubyObject> RubyString
33
30
  generateJson(ThreadContext context, T object,
34
31
  Handler<? super T> handler, IRubyObject[] args) {
35
- Session session = new Session(context, args.length > 0 ? args[0]
36
- : null);
32
+ Session session = new Session(context, args.length > 0 ? args[0] : null);
37
33
  return session.infect(handler.generateNew(session, object));
38
34
  }
39
35
 
@@ -43,7 +39,7 @@ public final class Generator {
43
39
  */
44
40
  static <T extends IRubyObject> RubyString
45
41
  generateJson(ThreadContext context, T object, IRubyObject[] args) {
46
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
42
+ Handler<? super T> handler = getHandlerFor(context.runtime, object);
47
43
  return generateJson(context, object, handler, args);
48
44
  }
49
45
 
@@ -55,33 +51,18 @@ public final class Generator {
55
51
  generateJson(ThreadContext context, T object,
56
52
  GeneratorState config) {
57
53
  Session session = new Session(context, config);
58
- Handler<? super T> handler = getHandlerFor(context.getRuntime(), object);
54
+ Handler<? super T> handler = getHandlerFor(context.runtime, object);
59
55
  return handler.generateNew(session, object);
60
56
  }
61
57
 
62
- // NOTE: drop this once Ruby 1.9.3 support is gone!
63
- private static final int FIXNUM = 1;
64
- private static final int BIGNUM = 2;
65
- private static final int ARRAY = 3;
66
- private static final int STRING = 4;
67
- private static final int NIL = 5;
68
- private static final int TRUE = 6;
69
- private static final int FALSE = 7;
70
- private static final int HASH = 10;
71
- private static final int FLOAT = 11;
72
- // hard-coded due JRuby 1.7 compatibility
73
- // https://github.com/jruby/jruby/blob/1.7.27/core/src/main/java/org/jruby/runtime/ClassIndex.java
74
-
75
58
  /**
76
59
  * Returns the best serialization handler for the given object.
77
60
  */
78
61
  // Java's generics can't handle this satisfactorily, so I'll just leave
79
62
  // the best I could get and ignore the warnings
80
63
  @SuppressWarnings("unchecked")
81
- private static <T extends IRubyObject>
82
- Handler<? super T> getHandlerFor(Ruby runtime, T object) {
83
- switch (((RubyBasicObject) object).getNativeTypeIndex()) {
84
- // can not use getNativeClassIndex due 1.7 compatibility
64
+ private static <T extends IRubyObject> Handler<? super T> getHandlerFor(Ruby runtime, T object) {
65
+ switch (((RubyBasicObject) object).getNativeClassIndex()) {
85
66
  case NIL : return (Handler) NIL_HANDLER;
86
67
  case TRUE : return (Handler) TRUE_HANDLER;
87
68
  case FALSE : return (Handler) FALSE_HANDLER;
@@ -158,7 +139,7 @@ public final class Generator {
158
139
 
159
140
  public StringEncoder getStringEncoder() {
160
141
  if (stringEncoder == null) {
161
- stringEncoder = new StringEncoder(context, getState().asciiOnly());
142
+ stringEncoder = new StringEncoder(context, getState().asciiOnly(), getState().escapeSlash());
162
143
  }
163
144
  return stringEncoder;
164
145
  }
@@ -353,13 +334,13 @@ public final class Generator {
353
334
 
354
335
  buffer.append((byte)'{');
355
336
  buffer.append(objectNl);
356
- object.visitAll(new RubyHash.Visitor() {
357
- private boolean firstPair = true;
358
337
 
338
+ final boolean[] firstPair = new boolean[]{true};
339
+ object.visitAll(new RubyHash.Visitor() {
359
340
  @Override
360
341
  public void visit(IRubyObject key, IRubyObject value) {
361
- if (firstPair) {
362
- firstPair = false;
342
+ if (firstPair[0]) {
343
+ firstPair[0] = false;
363
344
  } else {
364
345
  buffer.append((byte)',');
365
346
  buffer.append(objectNl);
@@ -379,7 +360,7 @@ public final class Generator {
379
360
  }
380
361
  });
381
362
  state.decreaseDepth();
382
- if (objectNl.length() != 0) {
363
+ if (!firstPair[0] && objectNl.length() != 0) {
383
364
  buffer.append(objectNl);
384
365
  buffer.append(Utils.repeat(state.getIndent(), state.getDepth()));
385
366
  }
@@ -82,6 +82,12 @@ public class GeneratorState extends RubyObject {
82
82
  */
83
83
  private boolean quirksMode = DEFAULT_QUIRKS_MODE;
84
84
  static final boolean DEFAULT_QUIRKS_MODE = false;
85
+ /**
86
+ * If set to <code>true</code> the forward slash will be escaped in
87
+ * json output.
88
+ */
89
+ private boolean escapeSlash = DEFAULT_ESCAPE_SLASH;
90
+ static final boolean DEFAULT_ESCAPE_SLASH = false;
85
91
  /**
86
92
  * The initial buffer length of this state. (This isn't really used on all
87
93
  * non-C implementations.)
@@ -171,6 +177,9 @@ public class GeneratorState extends RubyObject {
171
177
  * <code>-Infinity</code> should be generated, otherwise an exception is
172
178
  * thrown if these values are encountered.
173
179
  * This options defaults to <code>false</code>.
180
+ * <dt><code>:escape_slash</code>
181
+ * <dd>set to <code>true</code> if the forward slashes should be escaped
182
+ * in the json output (default: <code>false</code>)
174
183
  */
175
184
  @JRubyMethod(optional=1, visibility=Visibility.PRIVATE)
176
185
  public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
@@ -194,6 +203,7 @@ public class GeneratorState extends RubyObject {
194
203
  this.allowNaN = orig.allowNaN;
195
204
  this.asciiOnly = orig.asciiOnly;
196
205
  this.quirksMode = orig.quirksMode;
206
+ this.escapeSlash = orig.escapeSlash;
197
207
  this.bufferInitialLength = orig.bufferInitialLength;
198
208
  this.depth = orig.depth;
199
209
  return this;
@@ -346,6 +356,24 @@ public class GeneratorState extends RubyObject {
346
356
  return max_nesting;
347
357
  }
348
358
 
359
+ /**
360
+ * Returns true if forward slashes are escaped in the json output.
361
+ */
362
+ public boolean escapeSlash() {
363
+ return escapeSlash;
364
+ }
365
+
366
+ @JRubyMethod(name="escape_slash")
367
+ public RubyBoolean escape_slash_get(ThreadContext context) {
368
+ return context.getRuntime().newBoolean(escapeSlash);
369
+ }
370
+
371
+ @JRubyMethod(name="escape_slash=")
372
+ public IRubyObject escape_slash_set(IRubyObject escape_slash) {
373
+ escapeSlash = escape_slash.isTrue();
374
+ return escape_slash.getRuntime().newBoolean(escapeSlash);
375
+ }
376
+
349
377
  public boolean allowNaN() {
350
378
  return allowNaN;
351
379
  }
@@ -430,6 +458,7 @@ public class GeneratorState extends RubyObject {
430
458
  maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
431
459
  allowNaN = opts.getBool("allow_nan", DEFAULT_ALLOW_NAN);
432
460
  asciiOnly = opts.getBool("ascii_only", DEFAULT_ASCII_ONLY);
461
+ escapeSlash = opts.getBool("escape_slash", DEFAULT_ESCAPE_SLASH);
433
462
  bufferInitialLength = opts.getInt("buffer_initial_length", DEFAULT_BUFFER_INITIAL_LENGTH);
434
463
 
435
464
  depth = opts.getInt("depth", 0);
@@ -457,6 +486,7 @@ public class GeneratorState extends RubyObject {
457
486
  result.op_aset(context, runtime.newSymbol("allow_nan"), allow_nan_p(context));
458
487
  result.op_aset(context, runtime.newSymbol("ascii_only"), ascii_only_p(context));
459
488
  result.op_aset(context, runtime.newSymbol("max_nesting"), max_nesting_get(context));
489
+ result.op_aset(context, runtime.newSymbol("escape_slash"), escape_slash_get(context));
460
490
  result.op_aset(context, runtime.newSymbol("depth"), depth_get(context));
461
491
  result.op_aset(context, runtime.newSymbol("buffer_initial_length"), buffer_initial_length_get(context));
462
492
  for (String name: getInstanceVariableNameList()) {
@@ -52,6 +52,7 @@ public class Parser extends RubyObject {
52
52
  private int maxNesting;
53
53
  private boolean allowNaN;
54
54
  private boolean symbolizeNames;
55
+ private boolean freeze;
55
56
  private RubyClass objectClass;
56
57
  private RubyClass arrayClass;
57
58
  private RubyClass decimalClass;
@@ -160,6 +161,7 @@ public class Parser extends RubyObject {
160
161
  this.maxNesting = opts.getInt("max_nesting", DEFAULT_MAX_NESTING);
161
162
  this.allowNaN = opts.getBool("allow_nan", false);
162
163
  this.symbolizeNames = opts.getBool("symbolize_names", false);
164
+ this.freeze = opts.getBool("freeze", false);
163
165
  this.createId = opts.getString("create_id", getCreateId(context));
164
166
  this.createAdditions = opts.getBool("create_additions", false);
165
167
  this.objectClass = opts.getClass("object_class", runtime.getHash());
@@ -313,11 +315,11 @@ public class Parser extends RubyObject {
313
315
  }
314
316
 
315
317
 
316
- // line 339 "Parser.rl"
318
+ // line 341 "Parser.rl"
317
319
 
318
320
 
319
321
 
320
- // line 321 "Parser.java"
322
+ // line 323 "Parser.java"
321
323
  private static byte[] init__JSON_value_actions_0()
322
324
  {
323
325
  return new byte [] {
@@ -431,7 +433,7 @@ static final int JSON_value_error = 0;
431
433
  static final int JSON_value_en_main = 1;
432
434
 
433
435
 
434
- // line 445 "Parser.rl"
436
+ // line 447 "Parser.rl"
435
437
 
436
438
 
437
439
  void parseValue(ParserResult res, int p, int pe) {
@@ -439,14 +441,14 @@ static final int JSON_value_en_main = 1;
439
441
  IRubyObject result = null;
440
442
 
441
443
 
442
- // line 443 "Parser.java"
444
+ // line 445 "Parser.java"
443
445
  {
444
446
  cs = JSON_value_start;
445
447
  }
446
448
 
447
- // line 452 "Parser.rl"
449
+ // line 454 "Parser.rl"
448
450
 
449
- // line 450 "Parser.java"
451
+ // line 452 "Parser.java"
450
452
  {
451
453
  int _klen;
452
454
  int _trans = 0;
@@ -472,13 +474,13 @@ case 1:
472
474
  while ( _nacts-- > 0 ) {
473
475
  switch ( _JSON_value_actions[_acts++] ) {
474
476
  case 9:
475
- // line 430 "Parser.rl"
477
+ // line 432 "Parser.rl"
476
478
  {
477
479
  p--;
478
480
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
479
481
  }
480
482
  break;
481
- // line 482 "Parser.java"
483
+ // line 484 "Parser.java"
482
484
  }
483
485
  }
484
486
 
@@ -541,25 +543,25 @@ case 1:
541
543
  switch ( _JSON_value_actions[_acts++] )
542
544
  {
543
545
  case 0:
544
- // line 347 "Parser.rl"
546
+ // line 349 "Parser.rl"
545
547
  {
546
548
  result = getRuntime().getNil();
547
549
  }
548
550
  break;
549
551
  case 1:
550
- // line 350 "Parser.rl"
552
+ // line 352 "Parser.rl"
551
553
  {
552
554
  result = getRuntime().getFalse();
553
555
  }
554
556
  break;
555
557
  case 2:
556
- // line 353 "Parser.rl"
558
+ // line 355 "Parser.rl"
557
559
  {
558
560
  result = getRuntime().getTrue();
559
561
  }
560
562
  break;
561
563
  case 3:
562
- // line 356 "Parser.rl"
564
+ // line 358 "Parser.rl"
563
565
  {
564
566
  if (parser.allowNaN) {
565
567
  result = getConstant(CONST_NAN);
@@ -569,7 +571,7 @@ case 1:
569
571
  }
570
572
  break;
571
573
  case 4:
572
- // line 363 "Parser.rl"
574
+ // line 365 "Parser.rl"
573
575
  {
574
576
  if (parser.allowNaN) {
575
577
  result = getConstant(CONST_INFINITY);
@@ -579,7 +581,7 @@ case 1:
579
581
  }
580
582
  break;
581
583
  case 5:
582
- // line 370 "Parser.rl"
584
+ // line 372 "Parser.rl"
583
585
  {
584
586
  if (pe > p + 8 &&
585
587
  absSubSequence(p, p + 9).equals(JSON_MINUS_INFINITY)) {
@@ -608,7 +610,7 @@ case 1:
608
610
  }
609
611
  break;
610
612
  case 6:
611
- // line 396 "Parser.rl"
613
+ // line 398 "Parser.rl"
612
614
  {
613
615
  parseString(res, p, pe);
614
616
  if (res.result == null) {
@@ -621,7 +623,7 @@ case 1:
621
623
  }
622
624
  break;
623
625
  case 7:
624
- // line 406 "Parser.rl"
626
+ // line 408 "Parser.rl"
625
627
  {
626
628
  currentNesting++;
627
629
  parseArray(res, p, pe);
@@ -636,7 +638,7 @@ case 1:
636
638
  }
637
639
  break;
638
640
  case 8:
639
- // line 418 "Parser.rl"
641
+ // line 420 "Parser.rl"
640
642
  {
641
643
  currentNesting++;
642
644
  parseObject(res, p, pe);
@@ -650,7 +652,7 @@ case 1:
650
652
  }
651
653
  }
652
654
  break;
653
- // line 654 "Parser.java"
655
+ // line 656 "Parser.java"
654
656
  }
655
657
  }
656
658
  }
@@ -670,9 +672,12 @@ case 5:
670
672
  break; }
671
673
  }
672
674
 
673
- // line 453 "Parser.rl"
675
+ // line 455 "Parser.rl"
674
676
 
675
677
  if (cs >= JSON_value_first_final && result != null) {
678
+ if (parser.freeze) {
679
+ result.setFrozen(true);
680
+ }
676
681
  res.update(result, p);
677
682
  } else {
678
683
  res.update(null, p);
@@ -680,7 +685,7 @@ case 5:
680
685
  }
681
686
 
682
687
 
683
- // line 684 "Parser.java"
688
+ // line 689 "Parser.java"
684
689
  private static byte[] init__JSON_integer_actions_0()
685
690
  {
686
691
  return new byte [] {
@@ -779,7 +784,7 @@ static final int JSON_integer_error = 0;
779
784
  static final int JSON_integer_en_main = 1;
780
785
 
781
786
 
782
- // line 472 "Parser.rl"
787
+ // line 477 "Parser.rl"
783
788
 
784
789
 
785
790
  void parseInteger(ParserResult res, int p, int pe) {
@@ -797,15 +802,15 @@ static final int JSON_integer_en_main = 1;
797
802
  int cs = EVIL;
798
803
 
799
804
 
800
- // line 801 "Parser.java"
805
+ // line 806 "Parser.java"
801
806
  {
802
807
  cs = JSON_integer_start;
803
808
  }
804
809
 
805
- // line 489 "Parser.rl"
810
+ // line 494 "Parser.rl"
806
811
  int memo = p;
807
812
 
808
- // line 809 "Parser.java"
813
+ // line 814 "Parser.java"
809
814
  {
810
815
  int _klen;
811
816
  int _trans = 0;
@@ -886,13 +891,13 @@ case 1:
886
891
  switch ( _JSON_integer_actions[_acts++] )
887
892
  {
888
893
  case 0:
889
- // line 466 "Parser.rl"
894
+ // line 471 "Parser.rl"
890
895
  {
891
896
  p--;
892
897
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
893
898
  }
894
899
  break;
895
- // line 896 "Parser.java"
900
+ // line 901 "Parser.java"
896
901
  }
897
902
  }
898
903
  }
@@ -912,7 +917,7 @@ case 5:
912
917
  break; }
913
918
  }
914
919
 
915
- // line 491 "Parser.rl"
920
+ // line 496 "Parser.rl"
916
921
 
917
922
  if (cs < JSON_integer_first_final) {
918
923
  return -1;
@@ -934,7 +939,7 @@ case 5:
934
939
  }
935
940
 
936
941
 
937
- // line 938 "Parser.java"
942
+ // line 943 "Parser.java"
938
943
  private static byte[] init__JSON_float_actions_0()
939
944
  {
940
945
  return new byte [] {
@@ -1036,7 +1041,7 @@ static final int JSON_float_error = 0;
1036
1041
  static final int JSON_float_en_main = 1;
1037
1042
 
1038
1043
 
1039
- // line 526 "Parser.rl"
1044
+ // line 531 "Parser.rl"
1040
1045
 
1041
1046
 
1042
1047
  void parseFloat(ParserResult res, int p, int pe) {
@@ -1056,15 +1061,15 @@ static final int JSON_float_en_main = 1;
1056
1061
  int cs = EVIL;
1057
1062
 
1058
1063
 
1059
- // line 1060 "Parser.java"
1064
+ // line 1065 "Parser.java"
1060
1065
  {
1061
1066
  cs = JSON_float_start;
1062
1067
  }
1063
1068
 
1064
- // line 545 "Parser.rl"
1069
+ // line 550 "Parser.rl"
1065
1070
  int memo = p;
1066
1071
 
1067
- // line 1068 "Parser.java"
1072
+ // line 1073 "Parser.java"
1068
1073
  {
1069
1074
  int _klen;
1070
1075
  int _trans = 0;
@@ -1145,13 +1150,13 @@ case 1:
1145
1150
  switch ( _JSON_float_actions[_acts++] )
1146
1151
  {
1147
1152
  case 0:
1148
- // line 517 "Parser.rl"
1153
+ // line 522 "Parser.rl"
1149
1154
  {
1150
1155
  p--;
1151
1156
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
1152
1157
  }
1153
1158
  break;
1154
- // line 1155 "Parser.java"
1159
+ // line 1160 "Parser.java"
1155
1160
  }
1156
1161
  }
1157
1162
  }
@@ -1171,7 +1176,7 @@ case 5:
1171
1176
  break; }
1172
1177
  }
1173
1178
 
1174
- // line 547 "Parser.rl"
1179
+ // line 552 "Parser.rl"
1175
1180
 
1176
1181
  if (cs < JSON_float_first_final) {
1177
1182
  return -1;
@@ -1194,7 +1199,7 @@ case 5:
1194
1199
  }
1195
1200
 
1196
1201
 
1197
- // line 1198 "Parser.java"
1202
+ // line 1203 "Parser.java"
1198
1203
  private static byte[] init__JSON_string_actions_0()
1199
1204
  {
1200
1205
  return new byte [] {
@@ -1296,7 +1301,7 @@ static final int JSON_string_error = 0;
1296
1301
  static final int JSON_string_en_main = 1;
1297
1302
 
1298
1303
 
1299
- // line 599 "Parser.rl"
1304
+ // line 604 "Parser.rl"
1300
1305
 
1301
1306
 
1302
1307
  void parseString(ParserResult res, int p, int pe) {
@@ -1304,15 +1309,15 @@ static final int JSON_string_en_main = 1;
1304
1309
  IRubyObject result = null;
1305
1310
 
1306
1311
 
1307
- // line 1308 "Parser.java"
1312
+ // line 1313 "Parser.java"
1308
1313
  {
1309
1314
  cs = JSON_string_start;
1310
1315
  }
1311
1316
 
1312
- // line 606 "Parser.rl"
1317
+ // line 611 "Parser.rl"
1313
1318
  int memo = p;
1314
1319
 
1315
- // line 1316 "Parser.java"
1320
+ // line 1321 "Parser.java"
1316
1321
  {
1317
1322
  int _klen;
1318
1323
  int _trans = 0;
@@ -1393,7 +1398,7 @@ case 1:
1393
1398
  switch ( _JSON_string_actions[_acts++] )
1394
1399
  {
1395
1400
  case 0:
1396
- // line 574 "Parser.rl"
1401
+ // line 579 "Parser.rl"
1397
1402
  {
1398
1403
  int offset = byteList.begin();
1399
1404
  ByteList decoded = decoder.decode(byteList, memo + 1 - offset,
@@ -1408,13 +1413,13 @@ case 1:
1408
1413
  }
1409
1414
  break;
1410
1415
  case 1:
1411
- // line 587 "Parser.rl"
1416
+ // line 592 "Parser.rl"
1412
1417
  {
1413
1418
  p--;
1414
1419
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
1415
1420
  }
1416
1421
  break;
1417
- // line 1418 "Parser.java"
1422
+ // line 1423 "Parser.java"
1418
1423
  }
1419
1424
  }
1420
1425
  }
@@ -1434,7 +1439,7 @@ case 5:
1434
1439
  break; }
1435
1440
  }
1436
1441
 
1437
- // line 608 "Parser.rl"
1442
+ // line 613 "Parser.rl"
1438
1443
 
1439
1444
  if (parser.createAdditions) {
1440
1445
  RubyHash matchString = parser.match_string;
@@ -1463,16 +1468,23 @@ case 5:
1463
1468
 
1464
1469
  if (cs >= JSON_string_first_final && result != null) {
1465
1470
  if (result instanceof RubyString) {
1466
- ((RubyString)result).force_encoding(context, info.utf8.get());
1471
+ RubyString string = (RubyString)result;
1472
+ string.force_encoding(context, info.utf8.get());
1473
+ if (parser.freeze) {
1474
+ string.setFrozen(true);
1475
+ string = getRuntime().freezeAndDedupString(string);
1476
+ }
1477
+ res.update(string, p + 1);
1478
+ } else {
1479
+ res.update(result, p + 1);
1467
1480
  }
1468
- res.update(result, p + 1);
1469
1481
  } else {
1470
1482
  res.update(null, p + 1);
1471
1483
  }
1472
1484
  }
1473
1485
 
1474
1486
 
1475
- // line 1476 "Parser.java"
1487
+ // line 1488 "Parser.java"
1476
1488
  private static byte[] init__JSON_array_actions_0()
1477
1489
  {
1478
1490
  return new byte [] {
@@ -1585,7 +1597,7 @@ static final int JSON_array_error = 0;
1585
1597
  static final int JSON_array_en_main = 1;
1586
1598
 
1587
1599
 
1588
- // line 681 "Parser.rl"
1600
+ // line 693 "Parser.rl"
1589
1601
 
1590
1602
 
1591
1603
  void parseArray(ParserResult res, int p, int pe) {
@@ -1605,14 +1617,14 @@ static final int JSON_array_en_main = 1;
1605
1617
  }
1606
1618
 
1607
1619
 
1608
- // line 1609 "Parser.java"
1620
+ // line 1621 "Parser.java"
1609
1621
  {
1610
1622
  cs = JSON_array_start;
1611
1623
  }
1612
1624
 
1613
- // line 700 "Parser.rl"
1625
+ // line 712 "Parser.rl"
1614
1626
 
1615
- // line 1616 "Parser.java"
1627
+ // line 1628 "Parser.java"
1616
1628
  {
1617
1629
  int _klen;
1618
1630
  int _trans = 0;
@@ -1693,7 +1705,7 @@ case 1:
1693
1705
  switch ( _JSON_array_actions[_acts++] )
1694
1706
  {
1695
1707
  case 0:
1696
- // line 650 "Parser.rl"
1708
+ // line 662 "Parser.rl"
1697
1709
  {
1698
1710
  parseValue(res, p, pe);
1699
1711
  if (res.result == null) {
@@ -1710,13 +1722,13 @@ case 1:
1710
1722
  }
1711
1723
  break;
1712
1724
  case 1:
1713
- // line 665 "Parser.rl"
1725
+ // line 677 "Parser.rl"
1714
1726
  {
1715
1727
  p--;
1716
1728
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
1717
1729
  }
1718
1730
  break;
1719
- // line 1720 "Parser.java"
1731
+ // line 1732 "Parser.java"
1720
1732
  }
1721
1733
  }
1722
1734
  }
@@ -1736,7 +1748,7 @@ case 5:
1736
1748
  break; }
1737
1749
  }
1738
1750
 
1739
- // line 701 "Parser.rl"
1751
+ // line 713 "Parser.rl"
1740
1752
 
1741
1753
  if (cs >= JSON_array_first_final) {
1742
1754
  res.update(result, p + 1);
@@ -1746,7 +1758,7 @@ case 5:
1746
1758
  }
1747
1759
 
1748
1760
 
1749
- // line 1750 "Parser.java"
1761
+ // line 1762 "Parser.java"
1750
1762
  private static byte[] init__JSON_object_actions_0()
1751
1763
  {
1752
1764
  return new byte [] {
@@ -1869,7 +1881,7 @@ static final int JSON_object_error = 0;
1869
1881
  static final int JSON_object_en_main = 1;
1870
1882
 
1871
1883
 
1872
- // line 760 "Parser.rl"
1884
+ // line 772 "Parser.rl"
1873
1885
 
1874
1886
 
1875
1887
  void parseObject(ParserResult res, int p, int pe) {
@@ -1894,14 +1906,14 @@ static final int JSON_object_en_main = 1;
1894
1906
  }
1895
1907
 
1896
1908
 
1897
- // line 1898 "Parser.java"
1909
+ // line 1910 "Parser.java"
1898
1910
  {
1899
1911
  cs = JSON_object_start;
1900
1912
  }
1901
1913
 
1902
- // line 784 "Parser.rl"
1914
+ // line 796 "Parser.rl"
1903
1915
 
1904
- // line 1905 "Parser.java"
1916
+ // line 1917 "Parser.java"
1905
1917
  {
1906
1918
  int _klen;
1907
1919
  int _trans = 0;
@@ -1982,7 +1994,7 @@ case 1:
1982
1994
  switch ( _JSON_object_actions[_acts++] )
1983
1995
  {
1984
1996
  case 0:
1985
- // line 715 "Parser.rl"
1997
+ // line 727 "Parser.rl"
1986
1998
  {
1987
1999
  parseValue(res, p, pe);
1988
2000
  if (res.result == null) {
@@ -1999,7 +2011,7 @@ case 1:
1999
2011
  }
2000
2012
  break;
2001
2013
  case 1:
2002
- // line 730 "Parser.rl"
2014
+ // line 742 "Parser.rl"
2003
2015
  {
2004
2016
  parseString(res, p, pe);
2005
2017
  if (res.result == null) {
@@ -2019,13 +2031,13 @@ case 1:
2019
2031
  }
2020
2032
  break;
2021
2033
  case 2:
2022
- // line 748 "Parser.rl"
2034
+ // line 760 "Parser.rl"
2023
2035
  {
2024
2036
  p--;
2025
2037
  { p += 1; _goto_targ = 5; if (true) continue _goto;}
2026
2038
  }
2027
2039
  break;
2028
- // line 2029 "Parser.java"
2040
+ // line 2041 "Parser.java"
2029
2041
  }
2030
2042
  }
2031
2043
  }
@@ -2045,7 +2057,7 @@ case 5:
2045
2057
  break; }
2046
2058
  }
2047
2059
 
2048
- // line 785 "Parser.rl"
2060
+ // line 797 "Parser.rl"
2049
2061
 
2050
2062
  if (cs < JSON_object_first_final) {
2051
2063
  res.update(null, p + 1);
@@ -2078,7 +2090,7 @@ case 5:
2078
2090
  }
2079
2091
 
2080
2092
 
2081
- // line 2082 "Parser.java"
2093
+ // line 2094 "Parser.java"
2082
2094
  private static byte[] init__JSON_actions_0()
2083
2095
  {
2084
2096
  return new byte [] {
@@ -2181,7 +2193,7 @@ static final int JSON_error = 0;
2181
2193
  static final int JSON_en_main = 1;
2182
2194
 
2183
2195
 
2184
- // line 836 "Parser.rl"
2196
+ // line 848 "Parser.rl"
2185
2197
 
2186
2198
 
2187
2199
  public IRubyObject parseImplemetation() {
@@ -2191,16 +2203,16 @@ static final int JSON_en_main = 1;
2191
2203
  ParserResult res = new ParserResult();
2192
2204
 
2193
2205
 
2194
- // line 2195 "Parser.java"
2206
+ // line 2207 "Parser.java"
2195
2207
  {
2196
2208
  cs = JSON_start;
2197
2209
  }
2198
2210
 
2199
- // line 845 "Parser.rl"
2211
+ // line 857 "Parser.rl"
2200
2212
  p = byteList.begin();
2201
2213
  pe = p + byteList.length();
2202
2214
 
2203
- // line 2204 "Parser.java"
2215
+ // line 2216 "Parser.java"
2204
2216
  {
2205
2217
  int _klen;
2206
2218
  int _trans = 0;
@@ -2281,7 +2293,7 @@ case 1:
2281
2293
  switch ( _JSON_actions[_acts++] )
2282
2294
  {
2283
2295
  case 0:
2284
- // line 822 "Parser.rl"
2296
+ // line 834 "Parser.rl"
2285
2297
  {
2286
2298
  parseValue(res, p, pe);
2287
2299
  if (res.result == null) {
@@ -2293,7 +2305,7 @@ case 1:
2293
2305
  }
2294
2306
  }
2295
2307
  break;
2296
- // line 2297 "Parser.java"
2308
+ // line 2309 "Parser.java"
2297
2309
  }
2298
2310
  }
2299
2311
  }
@@ -2313,7 +2325,7 @@ case 5:
2313
2325
  break; }
2314
2326
  }
2315
2327
 
2316
- // line 848 "Parser.rl"
2328
+ // line 860 "Parser.rl"
2317
2329
 
2318
2330
  if (cs >= JSON_first_final && p == pe) {
2319
2331
  return result;