json 2.10.2 → 2.12.0

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.
@@ -31,28 +31,15 @@ typedef unsigned char _Bool;
31
31
  static VALUE mJSON, eNestingError, Encoding_UTF_8;
32
32
  static VALUE CNaN, CInfinity, CMinusInfinity;
33
33
 
34
- static ID i_json_creatable_p, i_json_create, i_create_id,
35
- i_chr, i_deep_const_get, i_match, i_aset, i_aref,
34
+ static ID i_chr, i_aset, i_aref,
36
35
  i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
37
36
 
38
37
  static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
39
- sym_create_additions, sym_create_id, sym_object_class, sym_array_class,
40
- sym_decimal_class, sym_match_string;
38
+ sym_decimal_class, sym_on_load;
41
39
 
42
40
  static int binary_encindex;
43
41
  static int utf8_encindex;
44
42
 
45
- #ifdef HAVE_RB_CATEGORY_WARN
46
- # define json_deprecated(message) rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, message)
47
- #else
48
- # define json_deprecated(message) rb_warn(message)
49
- #endif
50
-
51
- static const char deprecated_create_additions_warning[] =
52
- "JSON.load implicit support for `create_additions: true` is deprecated "
53
- "and will be removed in 3.0, use JSON.unsafe_load or explicitly "
54
- "pass `create_additions: true`";
55
-
56
43
  #ifndef HAVE_RB_HASH_BULK_INSERT
57
44
  // For TruffleRuby
58
45
  void
@@ -350,19 +337,86 @@ static size_t strnlen(const char *s, size_t maxlen)
350
337
  }
351
338
  #endif
352
339
 
340
+ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
341
+ {
342
+ int len = 1;
343
+ if (ch <= 0x7F) {
344
+ buf[0] = (char) ch;
345
+ } else if (ch <= 0x07FF) {
346
+ buf[0] = (char) ((ch >> 6) | 0xC0);
347
+ buf[1] = (char) ((ch & 0x3F) | 0x80);
348
+ len++;
349
+ } else if (ch <= 0xFFFF) {
350
+ buf[0] = (char) ((ch >> 12) | 0xE0);
351
+ buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
352
+ buf[2] = (char) ((ch & 0x3F) | 0x80);
353
+ len += 2;
354
+ } else if (ch <= 0x1fffff) {
355
+ buf[0] =(char) ((ch >> 18) | 0xF0);
356
+ buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
357
+ buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
358
+ buf[3] =(char) ((ch & 0x3F) | 0x80);
359
+ len += 3;
360
+ } else {
361
+ buf[0] = '?';
362
+ }
363
+ return len;
364
+ }
365
+
366
+ typedef struct JSON_ParserStruct {
367
+ VALUE on_load_proc;
368
+ VALUE decimal_class;
369
+ ID decimal_method_id;
370
+ int max_nesting;
371
+ bool allow_nan;
372
+ bool allow_trailing_comma;
373
+ bool parsing_name;
374
+ bool symbolize_names;
375
+ bool freeze;
376
+ } JSON_ParserConfig;
377
+
378
+ typedef struct JSON_ParserStateStruct {
379
+ VALUE stack_handle;
380
+ const char *start;
381
+ const char *cursor;
382
+ const char *end;
383
+ rvalue_stack *stack;
384
+ rvalue_cache name_cache;
385
+ int in_array;
386
+ int current_nesting;
387
+ } JSON_ParserState;
388
+
389
+
353
390
  #define PARSE_ERROR_FRAGMENT_LEN 32
354
391
  #ifdef RBIMPL_ATTR_NORETURN
355
392
  RBIMPL_ATTR_NORETURN()
356
393
  #endif
357
- static void raise_parse_error(const char *format, const char *start)
394
+ static void raise_parse_error(const char *format, JSON_ParserState *state)
358
395
  {
359
396
  unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
360
397
 
361
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
362
- const char *ptr = start;
398
+ const char *cursor = state->cursor;
399
+ long column = 0;
400
+ long line = 1;
401
+
402
+ while (cursor >= state->start) {
403
+ if (*cursor-- == '\n') {
404
+ break;
405
+ }
406
+ column++;
407
+ }
408
+
409
+ while (cursor >= state->start) {
410
+ if (*cursor-- == '\n') {
411
+ line++;
412
+ }
413
+ }
414
+
415
+ const char *ptr = state->cursor;
416
+ size_t len = ptr ? strnlen(ptr, PARSE_ERROR_FRAGMENT_LEN) : 0;
363
417
 
364
418
  if (len == PARSE_ERROR_FRAGMENT_LEN) {
365
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
419
+ MEMCPY(buffer, ptr, char, PARSE_ERROR_FRAGMENT_LEN);
366
420
 
367
421
  while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
368
422
  len--;
@@ -376,7 +430,23 @@ static void raise_parse_error(const char *format, const char *start)
376
430
  ptr = (const char *)buffer;
377
431
  }
378
432
 
379
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
433
+ VALUE msg = rb_sprintf(format, ptr);
434
+ VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
435
+ RB_GC_GUARD(msg);
436
+
437
+ VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
438
+ rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
439
+ rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
440
+ rb_exc_raise(exc);
441
+ }
442
+
443
+ #ifdef RBIMPL_ATTR_NORETURN
444
+ RBIMPL_ATTR_NORETURN()
445
+ #endif
446
+ static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
447
+ {
448
+ state->cursor = at;
449
+ raise_parse_error(format, state);
380
450
  }
381
451
 
382
452
  /* unicode */
@@ -398,78 +468,25 @@ static const signed char digit_values[256] = {
398
468
  -1, -1, -1, -1, -1, -1, -1
399
469
  };
400
470
 
401
- static uint32_t unescape_unicode(const unsigned char *p)
471
+ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
402
472
  {
403
473
  signed char b;
404
474
  uint32_t result = 0;
405
475
  b = digit_values[p[0]];
406
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
476
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
407
477
  result = (result << 4) | (unsigned char)b;
408
478
  b = digit_values[p[1]];
409
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
479
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
410
480
  result = (result << 4) | (unsigned char)b;
411
481
  b = digit_values[p[2]];
412
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
482
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
413
483
  result = (result << 4) | (unsigned char)b;
414
484
  b = digit_values[p[3]];
415
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
485
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
416
486
  result = (result << 4) | (unsigned char)b;
417
487
  return result;
418
488
  }
419
489
 
420
- static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
421
- {
422
- int len = 1;
423
- if (ch <= 0x7F) {
424
- buf[0] = (char) ch;
425
- } else if (ch <= 0x07FF) {
426
- buf[0] = (char) ((ch >> 6) | 0xC0);
427
- buf[1] = (char) ((ch & 0x3F) | 0x80);
428
- len++;
429
- } else if (ch <= 0xFFFF) {
430
- buf[0] = (char) ((ch >> 12) | 0xE0);
431
- buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
432
- buf[2] = (char) ((ch & 0x3F) | 0x80);
433
- len += 2;
434
- } else if (ch <= 0x1fffff) {
435
- buf[0] =(char) ((ch >> 18) | 0xF0);
436
- buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
437
- buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
438
- buf[3] =(char) ((ch & 0x3F) | 0x80);
439
- len += 3;
440
- } else {
441
- buf[0] = '?';
442
- }
443
- return len;
444
- }
445
-
446
- typedef struct JSON_ParserStruct {
447
- VALUE create_id;
448
- VALUE object_class;
449
- VALUE array_class;
450
- VALUE decimal_class;
451
- ID decimal_method_id;
452
- VALUE match_string;
453
- int max_nesting;
454
- bool allow_nan;
455
- bool allow_trailing_comma;
456
- bool parsing_name;
457
- bool symbolize_names;
458
- bool freeze;
459
- bool create_additions;
460
- bool deprecated_create_additions;
461
- } JSON_ParserConfig;
462
-
463
- typedef struct JSON_ParserStateStruct {
464
- VALUE stack_handle;
465
- const char *cursor;
466
- const char *end;
467
- rvalue_stack *stack;
468
- rvalue_cache name_cache;
469
- int in_array;
470
- int current_nesting;
471
- } JSON_ParserState;
472
-
473
490
  #define GET_PARSER_CONFIG \
474
491
  JSON_ParserConfig *config; \
475
492
  TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
@@ -503,8 +520,7 @@ json_eat_comments(JSON_ParserState *state)
503
520
  while (true) {
504
521
  state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
505
522
  if (!state->cursor) {
506
- state->cursor = state->end;
507
- raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
523
+ raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
508
524
  } else {
509
525
  state->cursor++;
510
526
  if (state->cursor < state->end && *state->cursor == '/') {
@@ -516,11 +532,11 @@ json_eat_comments(JSON_ParserState *state)
516
532
  break;
517
533
  }
518
534
  default:
519
- raise_parse_error("unexpected token at '%s'", state->cursor);
535
+ raise_parse_error("unexpected token '%s'", state);
520
536
  break;
521
537
  }
522
538
  } else {
523
- raise_parse_error("unexpected token at '%s'", state->cursor);
539
+ raise_parse_error("unexpected token '%s'", state);
524
540
  }
525
541
  }
526
542
 
@@ -639,9 +655,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
639
655
  break;
640
656
  case 'u':
641
657
  if (pe > stringEnd - 5) {
642
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
658
+ raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, p);
643
659
  } else {
644
- uint32_t ch = unescape_unicode((unsigned char *) ++pe);
660
+ uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
645
661
  pe += 3;
646
662
  /* To handle values above U+FFFF, we take a sequence of
647
663
  * \uXXXX escapes in the U+D800..U+DBFF then
@@ -656,10 +672,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
656
672
  if ((ch & 0xFC00) == 0xD800) {
657
673
  pe++;
658
674
  if (pe > stringEnd - 6) {
659
- raise_parse_error("incomplete surrogate pair at '%s'", p);
675
+ raise_parse_error_at("incomplete surrogate pair at '%s'", state, p);
660
676
  }
661
677
  if (pe[0] == '\\' && pe[1] == 'u') {
662
- uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
678
+ uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
663
679
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
664
680
  | (sur & 0x3FF));
665
681
  pe += 5;
@@ -769,18 +785,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
769
785
 
770
786
  static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
771
787
  {
772
- VALUE array;
773
- if (RB_UNLIKELY(config->array_class)) {
774
- array = rb_class_new_instance(0, 0, config->array_class);
775
- VALUE *items = rvalue_stack_peek(state->stack, count);
776
- long index;
777
- for (index = 0; index < count; index++) {
778
- rb_funcall(array, i_leftshift, 1, items[index]);
779
- }
780
- } else {
781
- array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
782
- }
783
-
788
+ VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
784
789
  rvalue_stack_pop(state->stack, count);
785
790
 
786
791
  if (config->freeze) {
@@ -792,41 +797,11 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
792
797
 
793
798
  static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
794
799
  {
795
- VALUE object;
796
- if (RB_UNLIKELY(config->object_class)) {
797
- object = rb_class_new_instance(0, 0, config->object_class);
798
- long index = 0;
799
- VALUE *items = rvalue_stack_peek(state->stack, count);
800
- while (index < count) {
801
- VALUE name = items[index++];
802
- VALUE value = items[index++];
803
- rb_funcall(object, i_aset, 2, name, value);
804
- }
805
- } else {
806
- object = rb_hash_new_capa(count);
807
- rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
808
- }
800
+ VALUE object = rb_hash_new_capa(count);
801
+ rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
809
802
 
810
803
  rvalue_stack_pop(state->stack, count);
811
804
 
812
- if (RB_UNLIKELY(config->create_additions)) {
813
- VALUE klassname;
814
- if (config->object_class) {
815
- klassname = rb_funcall(object, i_aref, 1, config->create_id);
816
- } else {
817
- klassname = rb_hash_aref(object, config->create_id);
818
- }
819
- if (!NIL_P(klassname)) {
820
- VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
821
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
822
- if (config->deprecated_create_additions) {
823
- json_deprecated(deprecated_create_additions_warning);
824
- }
825
- object = rb_funcall(klass, i_json_create, 1, object);
826
- }
827
- }
828
- }
829
-
830
805
  if (config->freeze) {
831
806
  RB_OBJ_FREEZE(object);
832
807
  }
@@ -834,17 +809,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
834
809
  return object;
835
810
  }
836
811
 
837
- static int match_i(VALUE regexp, VALUE klass, VALUE memo)
838
- {
839
- if (regexp == Qundef) return ST_STOP;
840
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
841
- RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
842
- rb_ary_push(memo, klass);
843
- return ST_STOP;
844
- }
845
- return ST_CONTINUE;
846
- }
847
-
848
812
  static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
849
813
  {
850
814
  VALUE string;
@@ -856,21 +820,17 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
856
820
  string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
857
821
  }
858
822
 
859
- if (RB_UNLIKELY(config->create_additions && RTEST(config->match_string))) {
860
- VALUE klass;
861
- VALUE memo = rb_ary_new2(2);
862
- rb_ary_push(memo, string);
863
- rb_hash_foreach(config->match_string, match_i, memo);
864
- klass = rb_ary_entry(memo, 1);
865
- if (RTEST(klass)) {
866
- string = rb_funcall(klass, i_json_create, 1, string);
867
- }
868
- }
869
-
870
823
  return string;
871
824
  }
872
825
 
873
- #define PUSH(result) rvalue_stack_push(state->stack, result, &state->stack_handle, &state->stack)
826
+ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
827
+ {
828
+ if (RB_UNLIKELY(config->on_load_proc)) {
829
+ value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
830
+ }
831
+ rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
832
+ return value;
833
+ }
874
834
 
875
835
  static const bool string_scan[256] = {
876
836
  // ASCII Control Characters
@@ -897,18 +857,18 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
897
857
  case '"': {
898
858
  VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
899
859
  state->cursor++;
900
- return PUSH(string);
860
+ return json_push_value(state, config, string);
901
861
  }
902
862
  case '\\': {
903
863
  state->cursor++;
904
864
  escaped = true;
905
865
  if ((unsigned char)*state->cursor < 0x20) {
906
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
866
+ raise_parse_error("invalid ASCII control character in string: %s", state);
907
867
  }
908
868
  break;
909
869
  }
910
870
  default:
911
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
871
+ raise_parse_error("invalid ASCII control character in string: %s", state);
912
872
  break;
913
873
  }
914
874
  }
@@ -916,7 +876,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
916
876
  state->cursor++;
917
877
  }
918
878
 
919
- raise_parse_error("unexpected end of input, expected closing \"", state->cursor);
879
+ raise_parse_error("unexpected end of input, expected closing \"", state);
920
880
  return Qfalse;
921
881
  }
922
882
 
@@ -924,60 +884,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
924
884
  {
925
885
  json_eat_whitespace(state);
926
886
  if (state->cursor >= state->end) {
927
- raise_parse_error("unexpected end of input", state->cursor);
887
+ raise_parse_error("unexpected end of input", state);
928
888
  }
929
889
 
930
890
  switch (*state->cursor) {
931
891
  case 'n':
932
892
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
933
893
  state->cursor += 4;
934
- return PUSH(Qnil);
894
+ return json_push_value(state, config, Qnil);
935
895
  }
936
896
 
937
- raise_parse_error("unexpected token at '%s'", state->cursor);
897
+ raise_parse_error("unexpected token '%s'", state);
938
898
  break;
939
899
  case 't':
940
900
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
941
901
  state->cursor += 4;
942
- return PUSH(Qtrue);
902
+ return json_push_value(state, config, Qtrue);
943
903
  }
944
904
 
945
- raise_parse_error("unexpected token at '%s'", state->cursor);
905
+ raise_parse_error("unexpected token '%s'", state);
946
906
  break;
947
907
  case 'f':
948
908
  // Note: memcmp with a small power of two compile to an integer comparison
949
909
  if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
950
910
  state->cursor += 5;
951
- return PUSH(Qfalse);
911
+ return json_push_value(state, config, Qfalse);
952
912
  }
953
913
 
954
- raise_parse_error("unexpected token at '%s'", state->cursor);
914
+ raise_parse_error("unexpected token '%s'", state);
955
915
  break;
956
916
  case 'N':
957
917
  // Note: memcmp with a small power of two compile to an integer comparison
958
918
  if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
959
919
  state->cursor += 3;
960
- return PUSH(CNaN);
920
+ return json_push_value(state, config, CNaN);
961
921
  }
962
922
 
963
- raise_parse_error("unexpected token at '%s'", state->cursor);
923
+ raise_parse_error("unexpected token '%s'", state);
964
924
  break;
965
925
  case 'I':
966
926
  if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
967
927
  state->cursor += 8;
968
- return PUSH(CInfinity);
928
+ return json_push_value(state, config, CInfinity);
969
929
  }
970
930
 
971
- raise_parse_error("unexpected token at '%s'", state->cursor);
931
+ raise_parse_error("unexpected token '%s'", state);
972
932
  break;
973
933
  case '-':
974
934
  // Note: memcmp with a small power of two compile to an integer comparison
975
935
  if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
976
936
  if (config->allow_nan) {
977
937
  state->cursor += 9;
978
- return PUSH(CMinusInfinity);
938
+ return json_push_value(state, config, CMinusInfinity);
979
939
  } else {
980
- raise_parse_error("unexpected token at '%s'", state->cursor);
940
+ raise_parse_error("unexpected token '%s'", state);
981
941
  }
982
942
  }
983
943
  // Fallthrough
@@ -995,11 +955,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
995
955
  long integer_length = state->cursor - start;
996
956
 
997
957
  if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
998
- raise_parse_error("invalid number: %s", start);
958
+ raise_parse_error_at("invalid number: %s", state, start);
999
959
  } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
1000
- raise_parse_error("invalid number: %s", start);
960
+ raise_parse_error_at("invalid number: %s", state, start);
1001
961
  } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
1002
- raise_parse_error("invalid number: %s", start);
962
+ raise_parse_error_at("invalid number: %s", state, start);
1003
963
  }
1004
964
 
1005
965
  if ((state->cursor < state->end) && (*state->cursor == '.')) {
@@ -1007,7 +967,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1007
967
  state->cursor++;
1008
968
 
1009
969
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
1010
- raise_parse_error("invalid number: %s", state->cursor);
970
+ raise_parse_error("invalid number: %s", state);
1011
971
  }
1012
972
 
1013
973
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -1023,7 +983,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1023
983
  }
1024
984
 
1025
985
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
1026
- raise_parse_error("invalid number: %s", state->cursor);
986
+ raise_parse_error("invalid number: %s", state);
1027
987
  }
1028
988
 
1029
989
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -1032,9 +992,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1032
992
  }
1033
993
 
1034
994
  if (integer) {
1035
- return PUSH(json_decode_integer(start, state->cursor));
995
+ return json_push_value(state, config, json_decode_integer(start, state->cursor));
1036
996
  }
1037
- return PUSH(json_decode_float(config, start, state->cursor));
997
+ return json_push_value(state, config, json_decode_float(config, start, state->cursor));
1038
998
  }
1039
999
  case '"': {
1040
1000
  // %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
@@ -1048,7 +1008,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1048
1008
 
1049
1009
  if ((state->cursor < state->end) && (*state->cursor == ']')) {
1050
1010
  state->cursor++;
1051
- return PUSH(json_decode_array(state, config, 0));
1011
+ return json_push_value(state, config, json_decode_array(state, config, 0));
1052
1012
  } else {
1053
1013
  state->current_nesting++;
1054
1014
  if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
@@ -1067,7 +1027,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1067
1027
  long count = state->stack->head - stack_head;
1068
1028
  state->current_nesting--;
1069
1029
  state->in_array--;
1070
- return PUSH(json_decode_array(state, config, count));
1030
+ return json_push_value(state, config, json_decode_array(state, config, count));
1071
1031
  }
1072
1032
 
1073
1033
  if (*state->cursor == ',') {
@@ -1083,7 +1043,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1083
1043
  }
1084
1044
  }
1085
1045
 
1086
- raise_parse_error("expected ',' or ']' after array value", state->cursor);
1046
+ raise_parse_error("expected ',' or ']' after array value", state);
1087
1047
  }
1088
1048
  break;
1089
1049
  }
@@ -1094,7 +1054,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1094
1054
 
1095
1055
  if ((state->cursor < state->end) && (*state->cursor == '}')) {
1096
1056
  state->cursor++;
1097
- return PUSH(json_decode_object(state, config, 0));
1057
+ return json_push_value(state, config, json_decode_object(state, config, 0));
1098
1058
  } else {
1099
1059
  state->current_nesting++;
1100
1060
  if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
@@ -1102,13 +1062,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1102
1062
  }
1103
1063
 
1104
1064
  if (*state->cursor != '"') {
1105
- raise_parse_error("expected object key, got '%s", state->cursor);
1065
+ raise_parse_error("expected object key, got '%s", state);
1106
1066
  }
1107
1067
  json_parse_string(state, config, true);
1108
1068
 
1109
1069
  json_eat_whitespace(state);
1110
1070
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1111
- raise_parse_error("expected ':' after object key", state->cursor);
1071
+ raise_parse_error("expected ':' after object key", state);
1112
1072
  }
1113
1073
  state->cursor++;
1114
1074
 
@@ -1123,7 +1083,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1123
1083
  state->cursor++;
1124
1084
  state->current_nesting--;
1125
1085
  long count = state->stack->head - stack_head;
1126
- return PUSH(json_decode_object(state, config, count));
1086
+ return json_push_value(state, config, json_decode_object(state, config, count));
1127
1087
  }
1128
1088
 
1129
1089
  if (*state->cursor == ',') {
@@ -1137,13 +1097,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1137
1097
  }
1138
1098
 
1139
1099
  if (*state->cursor != '"') {
1140
- raise_parse_error("expected object key, got: '%s'", state->cursor);
1100
+ raise_parse_error("expected object key, got: '%s'", state);
1141
1101
  }
1142
1102
  json_parse_string(state, config, true);
1143
1103
 
1144
1104
  json_eat_whitespace(state);
1145
1105
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1146
- raise_parse_error("expected ':' after object key, got: '%s", state->cursor);
1106
+ raise_parse_error("expected ':' after object key, got: '%s", state);
1147
1107
  }
1148
1108
  state->cursor++;
1149
1109
 
@@ -1153,24 +1113,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1153
1113
  }
1154
1114
  }
1155
1115
 
1156
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor);
1116
+ raise_parse_error("expected ',' or '}' after object value, got: '%s'", state);
1157
1117
  }
1158
1118
  break;
1159
1119
  }
1160
1120
 
1161
1121
  default:
1162
- raise_parse_error("unexpected character: '%s'", state->cursor);
1122
+ raise_parse_error("unexpected character: '%s'", state);
1163
1123
  break;
1164
1124
  }
1165
1125
 
1166
- raise_parse_error("unreacheable: '%s'", state->cursor);
1126
+ raise_parse_error("unreacheable: '%s'", state);
1167
1127
  }
1168
1128
 
1169
1129
  static void json_ensure_eof(JSON_ParserState *state)
1170
1130
  {
1171
1131
  json_eat_whitespace(state);
1172
1132
  if (state->cursor != state->end) {
1173
- raise_parse_error("unexpected token at end of stream '%s'", state->cursor);
1133
+ raise_parse_error("unexpected token at end of stream '%s'", state);
1174
1134
  }
1175
1135
  }
1176
1136
 
@@ -1211,10 +1171,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1211
1171
  else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
1212
1172
  else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
1213
1173
  else if (key == sym_freeze) { config->freeze = RTEST(val); }
1214
- else if (key == sym_create_id) { config->create_id = RTEST(val) ? val : Qfalse; }
1215
- else if (key == sym_object_class) { config->object_class = RTEST(val) ? val : Qfalse; }
1216
- else if (key == sym_array_class) { config->array_class = RTEST(val) ? val : Qfalse; }
1217
- else if (key == sym_match_string) { config->match_string = RTEST(val) ? val : Qfalse; }
1174
+ else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
1218
1175
  else if (key == sym_decimal_class) {
1219
1176
  if (RTEST(val)) {
1220
1177
  if (rb_respond_to(val, i_try_convert)) {
@@ -1244,15 +1201,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1244
1201
  }
1245
1202
  }
1246
1203
  }
1247
- else if (key == sym_create_additions) {
1248
- if (NIL_P(val)) {
1249
- config->create_additions = true;
1250
- config->deprecated_create_additions = true;
1251
- } else {
1252
- config->create_additions = RTEST(val);
1253
- config->deprecated_create_additions = false;
1254
- }
1255
- }
1256
1204
 
1257
1205
  return ST_CONTINUE;
1258
1206
  }
@@ -1267,16 +1215,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
1267
1215
  // We assume in most cases few keys are set so it's faster to go over
1268
1216
  // the provided keys than to check all possible keys.
1269
1217
  rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
1270
-
1271
- if (config->symbolize_names && config->create_additions) {
1272
- rb_raise(rb_eArgError,
1273
- "options :symbolize_names and :create_additions cannot be "
1274
- " used in conjunction");
1275
- }
1276
-
1277
- if (config->create_additions && !config->create_id) {
1278
- config->create_id = rb_funcall(mJSON, i_create_id, 0);
1279
- }
1280
1218
  }
1281
1219
 
1282
1220
  }
@@ -1301,15 +1239,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
1301
1239
  * (keys) in a JSON object. Otherwise strings are returned, which is
1302
1240
  * also the default. It's not possible to use this option in
1303
1241
  * conjunction with the *create_additions* option.
1304
- * * *create_additions*: If set to false, the Parser doesn't create
1305
- * additions even if a matching class and create_id was found. This option
1306
- * defaults to false.
1307
- * * *object_class*: Defaults to Hash. If another type is provided, it will be used
1308
- * instead of Hash to represent JSON objects. The type must respond to
1309
- * +new+ without arguments, and return an object that respond to +[]=+.
1310
- * * *array_class*: Defaults to Array If another type is provided, it will be used
1311
- * instead of Hash to represent JSON arrays. The type must respond to
1312
- * +new+ without arguments, and return an object that respond to +<<+.
1313
1242
  * * *decimal_class*: Specifies which class to use instead of the default
1314
1243
  * (Float) when parsing decimal numbers. This class must accept a single
1315
1244
  * string argument in its constructor.
@@ -1320,11 +1249,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
1320
1249
 
1321
1250
  parser_config_init(config, opts);
1322
1251
 
1323
- RB_OBJ_WRITTEN(self, Qundef, config->create_id);
1324
- RB_OBJ_WRITTEN(self, Qundef, config->object_class);
1325
- RB_OBJ_WRITTEN(self, Qundef, config->array_class);
1326
1252
  RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
1327
- RB_OBJ_WRITTEN(self, Qundef, config->match_string);
1328
1253
 
1329
1254
  return self;
1330
1255
  }
@@ -1341,9 +1266,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
1341
1266
  .capa = RVALUE_STACK_INITIAL_CAPA,
1342
1267
  };
1343
1268
 
1269
+ long len;
1270
+ const char *start;
1271
+ RSTRING_GETMEM(Vsource, start, len);
1272
+
1344
1273
  JSON_ParserState _state = {
1345
- .cursor = RSTRING_PTR(Vsource),
1346
- .end = RSTRING_END(Vsource),
1274
+ .start = start,
1275
+ .cursor = start,
1276
+ .end = start + len,
1347
1277
  .stack = &stack,
1348
1278
  };
1349
1279
  JSON_ParserState *state = &_state;
@@ -1387,11 +1317,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
1387
1317
  static void JSON_ParserConfig_mark(void *ptr)
1388
1318
  {
1389
1319
  JSON_ParserConfig *config = ptr;
1390
- rb_gc_mark(config->create_id);
1391
- rb_gc_mark(config->object_class);
1392
- rb_gc_mark(config->array_class);
1320
+ rb_gc_mark(config->on_load_proc);
1393
1321
  rb_gc_mark(config->decimal_class);
1394
- rb_gc_mark(config->match_string);
1395
1322
  }
1396
1323
 
1397
1324
  static void JSON_ParserConfig_free(void *ptr)
@@ -1459,19 +1386,10 @@ void Init_parser(void)
1459
1386
  sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
1460
1387
  sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
1461
1388
  sym_freeze = ID2SYM(rb_intern("freeze"));
1462
- sym_create_additions = ID2SYM(rb_intern("create_additions"));
1463
- sym_create_id = ID2SYM(rb_intern("create_id"));
1464
- sym_object_class = ID2SYM(rb_intern("object_class"));
1465
- sym_array_class = ID2SYM(rb_intern("array_class"));
1389
+ sym_on_load = ID2SYM(rb_intern("on_load"));
1466
1390
  sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
1467
- sym_match_string = ID2SYM(rb_intern("match_string"));
1468
1391
 
1469
- i_create_id = rb_intern("create_id");
1470
- i_json_creatable_p = rb_intern("json_creatable?");
1471
- i_json_create = rb_intern("json_create");
1472
1392
  i_chr = rb_intern("chr");
1473
- i_match = rb_intern("match");
1474
- i_deep_const_get = rb_intern("deep_const_get");
1475
1393
  i_aset = rb_intern("[]=");
1476
1394
  i_aref = rb_intern("[]");
1477
1395
  i_leftshift = rb_intern("<<");