oj 3.4.0 → 3.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9badf52195a57cbb014c118468e251a6410492be
4
- data.tar.gz: 8cf51afa4ee58bbb314625d6b4e4c91c69c1f816
2
+ SHA256:
3
+ metadata.gz: 30b24a6a60285c820a9e10671a976043a9163c2e98a3c07ba16af43ad88b8e6f
4
+ data.tar.gz: 90fc1a46d76296f2e226434a26b6acc0cbe16fa378173ea98700b2250ecf45ca
5
5
  SHA512:
6
- metadata.gz: 3366cc54755af4f3d8abbded2afac3b1235a4fe25315964d6d1225c69e849611eecedb2e7d893e14b72514bcc0115b1a2cce94bc007f0e8460230798d1531276
7
- data.tar.gz: 02d082acfd67708b44582a8fe69e10a5f639cc56ec57484c56c283be96ffc4d64b0a41b4c31bac2f707225388b2f5cd2551c9e6aba048c4c973e6c6461a462a8
6
+ metadata.gz: 71d7f8f0c32e3183a9f228764ffacdbd94cac6497e4af07e3ede247a676b2abd3815b3c51228992429a400a0ef879b8f54a8767cfa8b3a573a9931b46ec785e0
7
+ data.tar.gz: ce7fb5fa634fd8122173712faed5435bee5ec3477445d969f3a16f62ac6703dae9fee0f0476cbbfdc8852ba4a7243753d543e44f61eb286489b7a700e0e0dde5
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # [![{}j](http://www.ohler.com/dev/images/oj_comet_64.svg)](http://www.ohler.com/oj) gem
2
2
 
3
- [![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg)](http://travis-ci.org/ohler55/oj?branch=master) [![AppVeyor](https://img.shields.io/appveyor/ci/ohler55/oj/master.svg)](https://ci.appveyor.com/project/ohler55/oj) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg) [![Gratipay](https://img.shields.io/gratipay/project/oj.svg)](https://gratipay.com/oj/)
3
+ [![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg)](http://travis-ci.org/ohler55/oj?branch=master) [![AppVeyor](https://img.shields.io/appveyor/ci/ohler55/oj/master.svg)](https://ci.appveyor.com/project/ohler55/oj) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg)
4
4
 
5
5
  A *fast* JSON parser and Object marshaller as a Ruby gem.
6
6
 
@@ -11,6 +11,7 @@
11
11
  #include "resolve.h"
12
12
  #include "hash.h"
13
13
  #include "encode.h"
14
+ #include "trace.h"
14
15
 
15
16
  static void
16
17
  hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
@@ -55,6 +56,9 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
55
56
  } else {
56
57
  rb_hash_aset(parent->val, rkey, rstr);
57
58
  }
59
+ if (Yes == pi->options.trace) {
60
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
61
+ }
58
62
  }
59
63
  }
60
64
 
@@ -67,6 +71,9 @@ start_hash(ParseInfo pi) {
67
71
  } else {
68
72
  h = rb_hash_new();
69
73
  }
74
+ if (Yes == pi->options.trace) {
75
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
76
+ }
70
77
  return h;
71
78
  }
72
79
 
@@ -90,6 +97,9 @@ end_hash(struct _ParseInfo *pi) {
90
97
  parent->classname = 0;
91
98
  }
92
99
  }
100
+ if (Yes == pi->options.trace) {
101
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
102
+ }
93
103
  }
94
104
 
95
105
  static VALUE
@@ -120,23 +130,34 @@ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
120
130
  }
121
131
  }
122
132
  pi->stack.head->val = rstr;
133
+ if (Yes == pi->options.trace) {
134
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
135
+ }
123
136
  }
124
137
 
125
138
  static void
126
139
  add_num(ParseInfo pi, NumInfo ni) {
127
140
  pi->stack.head->val = oj_num_as_value(ni);
141
+ if (Yes == pi->options.trace) {
142
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
143
+ }
128
144
  }
129
145
 
130
146
  static void
131
147
  hash_set_num(struct _ParseInfo *pi, Val parent, NumInfo ni) {
148
+ volatile VALUE rval = oj_num_as_value(ni);
149
+
132
150
  if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
133
151
  // The rb_hash_set would still work but the unit tests for the
134
152
  // json gem require the less efficient []= method be called to set
135
153
  // values. Even using the store method to set the values will fail
136
154
  // the unit tests.
137
- rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), oj_num_as_value(ni));
155
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval);
138
156
  } else {
139
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), oj_num_as_value(ni));
157
+ rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
158
+ }
159
+ if (Yes == pi->options.trace) {
160
+ oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
140
161
  }
141
162
  }
142
163
 
@@ -151,6 +172,9 @@ hash_set_value(ParseInfo pi, Val parent, VALUE value) {
151
172
  } else {
152
173
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
153
174
  }
175
+ if (Yes == pi->options.trace) {
176
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
177
+ }
154
178
  }
155
179
 
156
180
  static VALUE
@@ -158,20 +182,27 @@ start_array(ParseInfo pi) {
158
182
  if (Qnil != pi->options.array_class) {
159
183
  return rb_class_new_instance(0, NULL, pi->options.array_class);
160
184
  }
185
+ if (Yes == pi->options.trace) {
186
+ oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
187
+ }
161
188
  return rb_ary_new();
162
189
  }
163
190
 
164
191
  static void
165
192
  array_append_num(ParseInfo pi, NumInfo ni) {
166
- Val parent = stack_peek(&pi->stack);
193
+ Val parent = stack_peek(&pi->stack);
194
+ volatile VALUE rval = oj_num_as_value(ni);
167
195
 
168
196
  if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
169
197
  // The rb_ary_push would still work but the unit tests for the json
170
198
  // gem require the less efficient << method be called to push the
171
199
  // values.
172
- rb_funcall(parent->val, rb_intern("<<"), 1, oj_num_as_value(ni));
200
+ rb_funcall(parent->val, rb_intern("<<"), 1, rval);
173
201
  } else {
174
- rb_ary_push(parent->val, oj_num_as_value(ni));
202
+ rb_ary_push(parent->val, rval);
203
+ }
204
+ if (Yes == pi->options.trace) {
205
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
175
206
  }
176
207
  }
177
208
 
@@ -189,6 +220,9 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
189
220
  }
190
221
  }
191
222
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
223
+ if (Yes == pi->options.trace) {
224
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
225
+ }
192
226
  }
193
227
 
194
228
  void
@@ -14,6 +14,7 @@
14
14
  #include "oj.h"
15
15
  #include "parse.h"
16
16
  #include "resolve.h"
17
+ #include "trace.h"
17
18
 
18
19
  extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
19
20
  extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
@@ -874,6 +875,9 @@ void
874
875
  oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
875
876
  int type = rb_type(obj);
876
877
 
878
+ if (Yes == out->opts->trace) {
879
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
880
+ }
877
881
  if (MAX_DEPTH < depth) {
878
882
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
879
883
  }
@@ -882,10 +886,16 @@ oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
882
886
 
883
887
  if (NULL != f) {
884
888
  f(obj, depth, out, true);
889
+ if (Yes == out->opts->trace) {
890
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
891
+ }
885
892
  return;
886
893
  }
887
894
  }
888
895
  oj_dump_nil(Qnil, depth, out, false);
896
+ if (Yes == out->opts->trace) {
897
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
898
+ }
889
899
  }
890
900
 
891
901
  ///// load functions /////
@@ -946,6 +956,9 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
946
956
  default:
947
957
  break;
948
958
  }
959
+ if (Yes == pi->options.trace) {
960
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
961
+ }
949
962
  }
950
963
  }
951
964
 
@@ -963,6 +976,9 @@ end_hash(struct _ParseInfo *pi) {
963
976
  }
964
977
  parent->clas = Qundef;
965
978
  }
979
+ if (Yes == pi->options.trace) {
980
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
981
+ }
966
982
  }
967
983
 
968
984
  static VALUE
@@ -981,11 +997,12 @@ calc_hash_key(ParseInfo pi, Val parent) {
981
997
 
982
998
  static void
983
999
  hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
984
- Val parent = stack_peek(&pi->stack);
1000
+ Val parent = stack_peek(&pi->stack);
1001
+ volatile VALUE rval = oj_num_as_value(ni);
985
1002
 
986
1003
  switch (rb_type(parent->val)) {
987
1004
  case T_OBJECT:
988
- oj_set_obj_ivar(parent, kval, oj_num_as_value(ni));
1005
+ oj_set_obj_ivar(parent, kval, rval);
989
1006
  break;
990
1007
  case T_HASH:
991
1008
  if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) {
@@ -1001,7 +1018,7 @@ hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
1001
1018
  if (86400 == ni->exp) { // UTC time
1002
1019
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1003
1020
  // Since the ruby C routines alway create local time, the
1004
- // offset and then a convertion to UTC keeps makes the time
1021
+ // offset and then a conversion to UTC keeps makes the time
1005
1022
  // match the expected value.
1006
1023
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1007
1024
  } else if (ni->hasExp) {
@@ -1020,13 +1037,17 @@ hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
1020
1037
  } else {
1021
1038
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1022
1039
  }
1040
+ rval = parent->val;
1023
1041
  } else {
1024
- rb_hash_aset(parent->val, calc_hash_key(pi, kval), oj_num_as_value(ni));
1042
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
1025
1043
  }
1026
1044
  break;
1027
1045
  default:
1028
1046
  break;
1029
1047
  }
1048
+ if (Yes == pi->options.trace) {
1049
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
1050
+ }
1030
1051
  }
1031
1052
 
1032
1053
  static void
@@ -1043,13 +1064,20 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1043
1064
  default:
1044
1065
  break;
1045
1066
  }
1067
+ if (Yes == pi->options.trace) {
1068
+ oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
1069
+ }
1046
1070
  }
1047
1071
 
1048
1072
  static void
1049
1073
  array_append_num(ParseInfo pi, NumInfo ni) {
1050
- Val parent = stack_peek(&pi->stack);
1074
+ Val parent = stack_peek(&pi->stack);
1075
+ volatile VALUE rval = oj_num_as_value(ni);
1051
1076
 
1052
- rb_ary_push(parent->val, oj_num_as_value(ni));
1077
+ rb_ary_push(parent->val, rval);
1078
+ if (Yes == pi->options.trace) {
1079
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1080
+ }
1053
1081
  }
1054
1082
 
1055
1083
  static void
@@ -1066,6 +1094,9 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
1066
1094
  }
1067
1095
  }
1068
1096
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1097
+ if (Yes == pi->options.trace) {
1098
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1099
+ }
1069
1100
  }
1070
1101
 
1071
1102
  void
@@ -6,6 +6,7 @@
6
6
  #include "code.h"
7
7
  #include "dump.h"
8
8
  #include "rails.h"
9
+ #include "trace.h"
9
10
 
10
11
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
11
12
  #define OJ_INFINITY (1.0/0.0)
@@ -901,7 +902,10 @@ set_state_depth(VALUE state, int depth) {
901
902
  void
902
903
  oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
903
904
  int type = rb_type(obj);
904
-
905
+
906
+ if (Yes == out->opts->trace) {
907
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
908
+ }
905
909
  if (out->opts->dump_opts.max_depth <= depth) {
906
910
  // When JSON.dump is called then an ArgumentError is expected and the
907
911
  // limit is the depth inclusive. If JSON.generate is called then a
@@ -924,8 +928,14 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
924
928
 
925
929
  if (NULL != f) {
926
930
  f(obj, depth, out, as_ok);
931
+ if (Yes == out->opts->trace) {
932
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
933
+ }
927
934
  return;
928
935
  }
929
936
  }
930
937
  oj_dump_nil(Qnil, depth, out, false);
938
+ if (Yes == out->opts->trace) {
939
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
940
+ }
931
941
  }
@@ -5,6 +5,7 @@
5
5
 
6
6
  #include "dump.h"
7
7
  #include "odd.h"
8
+ #include "trace.h"
8
9
 
9
10
  static const char hex_chars[17] = "0123456789abcdef";
10
11
 
@@ -816,6 +817,9 @@ void
816
817
  oj_dump_obj_val(VALUE obj, int depth, Out out) {
817
818
  int type = rb_type(obj);
818
819
 
820
+ if (Yes == out->opts->trace) {
821
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
822
+ }
819
823
  if (MAX_DEPTH < depth) {
820
824
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
821
825
  }
@@ -824,8 +828,14 @@ oj_dump_obj_val(VALUE obj, int depth, Out out) {
824
828
 
825
829
  if (NULL != f) {
826
830
  f(obj, depth, out, false);
831
+ if (Yes == out->opts->trace) {
832
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
833
+ }
827
834
  return;
828
835
  }
829
836
  }
830
837
  oj_dump_nil(Qnil, depth, out, false);
838
+ if (Yes == out->opts->trace) {
839
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
840
+ }
831
841
  }
@@ -12,6 +12,7 @@
12
12
  #include <errno.h>
13
13
 
14
14
  #include "dump.h"
15
+ #include "trace.h"
15
16
 
16
17
  #if !HAS_ENCODING_SUPPORT || defined(RUBINIUS_RUBY)
17
18
  #define rb_eEncodingError rb_eException
@@ -366,6 +367,9 @@ void
366
367
  oj_dump_strict_val(VALUE obj, int depth, Out out) {
367
368
  int type = rb_type(obj);
368
369
 
370
+ if (Yes == out->opts->trace) {
371
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
372
+ }
369
373
  if (MAX_DEPTH < depth) {
370
374
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
371
375
  }
@@ -374,6 +378,9 @@ oj_dump_strict_val(VALUE obj, int depth, Out out) {
374
378
 
375
379
  if (NULL != f) {
376
380
  f(obj, depth, out, false);
381
+ if (Yes == out->opts->trace) {
382
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
383
+ }
377
384
  return;
378
385
  }
379
386
  }
@@ -409,6 +416,9 @@ void
409
416
  oj_dump_null_val(VALUE obj, int depth, Out out) {
410
417
  int type = rb_type(obj);
411
418
 
419
+ if (Yes == out->opts->trace) {
420
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
421
+ }
412
422
  if (MAX_DEPTH < depth) {
413
423
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
414
424
  }
@@ -417,8 +427,14 @@ oj_dump_null_val(VALUE obj, int depth, Out out) {
417
427
 
418
428
  if (NULL != f) {
419
429
  f(obj, depth, out, false);
430
+ if (Yes == out->opts->trace) {
431
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
432
+ }
420
433
  return;
421
434
  }
422
435
  }
423
436
  oj_dump_nil(Qnil, depth, out, false);
437
+ if (Yes == out->opts->trace) {
438
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
439
+ }
424
440
  }
@@ -44,13 +44,13 @@ static VALUE state_class;
44
44
  /* Document-method: parser=
45
45
  * call-seq: parser=(parser)
46
46
  *
47
- * Does nothing other than provide compatibiltiy.
47
+ * Does nothing other than provide compatibility.
48
48
  * - *parser* [_Object_] ignored
49
49
  */
50
50
  /* Document-method: generator=
51
51
  * call-seq: generator=(generator)
52
52
  *
53
- * Does nothing other than provide compatibiltiy.
53
+ * Does nothing other than provide compatibility.
54
54
  * - *generator* [_Object_] ignored
55
55
  */
56
56
 
@@ -606,7 +606,7 @@ mimic_parse_bang(int argc, VALUE *argv, VALUE self) {
606
606
  /* Document-method: recurse_proc
607
607
  * call-seq: recurse_proc(obj, &proc)
608
608
  *
609
- * Yields to the proc for every element in the obj recursivly.
609
+ * Yields to the proc for every element in the obj recursively.
610
610
  *
611
611
  * - *obj* [_Hash_|Array] object to walk
612
612
  * - *proc* [_Proc_] to yield to on each element
@@ -684,6 +684,7 @@ static struct _Options mimic_object_to_json_options = {
684
684
  No, // allow_invalid
685
685
  No, // create_ok
686
686
  No, // allow_nan
687
+ No, // trace
687
688
  oj_json_class,// create_id
688
689
  10, // create_id_len
689
690
  3, // sec_prec
@@ -13,6 +13,7 @@
13
13
  #include "hash.h"
14
14
  #include "odd.h"
15
15
  #include "encode.h"
16
+ #include "trace.h"
16
17
 
17
18
  inline static long
18
19
  read_long(const char *str, size_t len) {
@@ -286,7 +287,7 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
286
287
  if (86400 == ni->exp) { // UTC time
287
288
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
288
289
  // Since the ruby C routines alway create local time, the
289
- // offset and then a convertion to UTC keeps makes the time
290
+ // offset and then a conversion to UTC keeps makes the time
290
291
  // match the expected value.
291
292
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
292
293
  } else if (ni->hasExp) {
@@ -482,9 +483,10 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
482
483
 
483
484
  static void
484
485
  hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
485
- const char *key = kval->key;
486
- int klen = kval->klen;
487
- Val parent = stack_peek(&pi->stack);
486
+ const char *key = kval->key;
487
+ int klen = kval->klen;
488
+ Val parent = stack_peek(&pi->stack);
489
+ volatile VALUE rval = Qnil;
488
490
 
489
491
  WHICH_TYPE:
490
492
  switch (rb_type(parent->val)) {
@@ -499,41 +501,50 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
499
501
  rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
500
502
  break;
501
503
  case T_STRING:
504
+ rval = str_to_value(pi, str, len, orig);
502
505
  if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
503
- rb_funcall(parent->val, oj_replace_id, 1, str_to_value(pi, str, len, orig));
506
+ rb_funcall(parent->val, oj_replace_id, 1, rval);
504
507
  } else {
505
- oj_set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
508
+ oj_set_obj_ivar(parent, kval, rval);
506
509
  }
507
510
  break;
508
511
  case T_OBJECT:
509
- oj_set_obj_ivar(parent, kval, str_to_value(pi, str, len, orig));
512
+ rval = str_to_value(pi, str, len, orig);
513
+ oj_set_obj_ivar(parent, kval, rval);
510
514
  break;
511
515
  case T_CLASS:
512
516
  if (0 == parent->odd_args) {
513
517
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
514
518
  return;
515
- } else if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, str_to_value(pi, str, len, orig))) {
516
- char buf[256];
519
+ } else {
520
+ rval = str_to_value(pi, str, len, orig);
521
+ if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
522
+ char buf[256];
517
523
 
518
- if ((int)sizeof(buf) - 1 <= klen) {
519
- klen = sizeof(buf) - 2;
524
+ if ((int)sizeof(buf) - 1 <= klen) {
525
+ klen = sizeof(buf) - 2;
526
+ }
527
+ memcpy(buf, key, klen);
528
+ buf[klen] = '\0';
529
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
520
530
  }
521
- memcpy(buf, key, klen);
522
- buf[klen] = '\0';
523
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
524
531
  }
525
532
  break;
526
533
  default:
527
534
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
528
535
  return;
529
536
  }
537
+ if (Yes == pi->options.trace) {
538
+ oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
539
+ }
530
540
  }
531
541
 
532
542
  static void
533
543
  hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
534
- const char *key = kval->key;
535
- int klen = kval->klen;
536
- Val parent = stack_peek(&pi->stack);
544
+ const char *key = kval->key;
545
+ int klen = kval->klen;
546
+ Val parent = stack_peek(&pi->stack);
547
+ volatile VALUE rval = Qnil;
537
548
 
538
549
  WHICH_TYPE:
539
550
  switch (rb_type(parent->val)) {
@@ -545,35 +556,43 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
545
556
  }
546
557
  break;
547
558
  case T_HASH:
548
- rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), oj_num_as_value(ni));
559
+ rval = oj_num_as_value(ni);
560
+ rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
549
561
  break;
550
562
  case T_OBJECT:
551
563
  if (2 == klen && '^' == *key && 'i' == key[1] &&
552
564
  !ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
553
565
  oj_circ_array_set(pi->circ_array, parent->val, ni->i);
554
566
  } else {
555
- oj_set_obj_ivar(parent, kval, oj_num_as_value(ni));
567
+ rval = oj_num_as_value(ni);
568
+ oj_set_obj_ivar(parent, kval, rval);
556
569
  }
557
570
  break;
558
571
  case T_CLASS:
559
572
  if (0 == parent->odd_args) {
560
573
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
561
574
  return;
562
- } else if (0 != oj_odd_set_arg(parent->odd_args, key, klen, oj_num_as_value(ni))) {
563
- char buf[256];
575
+ } else {
576
+ rval = oj_num_as_value(ni);
577
+ if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
578
+ char buf[256];
564
579
 
565
- if ((int)sizeof(buf) - 1 <= klen) {
566
- klen = sizeof(buf) - 2;
580
+ if ((int)sizeof(buf) - 1 <= klen) {
581
+ klen = sizeof(buf) - 2;
582
+ }
583
+ memcpy(buf, key, klen);
584
+ buf[klen] = '\0';
585
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
567
586
  }
568
- memcpy(buf, key, klen);
569
- buf[klen] = '\0';
570
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
571
587
  }
572
588
  break;
573
589
  default:
574
590
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
575
591
  return;
576
592
  }
593
+ if (Yes == pi->options.trace) {
594
+ oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
595
+ }
577
596
  }
578
597
 
579
598
  static void
@@ -644,10 +663,16 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
644
663
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
645
664
  return;
646
665
  }
666
+ if (Yes == pi->options.trace) {
667
+ oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
668
+ }
647
669
  }
648
670
 
649
671
  static VALUE
650
672
  start_hash(ParseInfo pi) {
673
+ if (Yes == pi->options.trace) {
674
+ oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
675
+ }
651
676
  return Qnil;
652
677
  }
653
678
 
@@ -664,10 +689,15 @@ end_hash(struct _ParseInfo *pi) {
664
689
  oj_odd_free(oa);
665
690
  parent->odd_args = 0;
666
691
  }
692
+ if (Yes == pi->options.trace) {
693
+ oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
694
+ }
667
695
  }
668
696
 
669
697
  static void
670
698
  array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
699
+ volatile VALUE rval = Qnil;
700
+
671
701
  if (3 <= len && 0 != pi->circ_array) {
672
702
  if ('i' == str[1]) {
673
703
  long i = read_long(str + 2, len - 2);
@@ -686,22 +716,37 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
686
716
 
687
717
  }
688
718
  }
689
- rb_ary_push(stack_peek(&pi->stack)->val, str_to_value(pi, str, len, orig));
719
+ rval = str_to_value(pi, str, len, orig);
720
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
721
+ if (Yes == pi->options.trace) {
722
+ oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
723
+ }
690
724
  }
691
725
 
692
726
  static void
693
727
  array_append_num(ParseInfo pi, NumInfo ni) {
694
- rb_ary_push(stack_peek(&pi->stack)->val, oj_num_as_value(ni));
728
+ volatile VALUE rval = oj_num_as_value(ni);
729
+
730
+ rb_ary_push(stack_peek(&pi->stack)->val, rval);
731
+ if (Yes == pi->options.trace) {
732
+ oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
733
+ }
695
734
  }
696
735
 
697
736
  static void
698
737
  add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
699
738
  pi->stack.head->val = str_to_value(pi, str, len, orig);
739
+ if (Yes == pi->options.trace) {
740
+ oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
741
+ }
700
742
  }
701
743
 
702
744
  static void
703
745
  add_num(ParseInfo pi, NumInfo ni) {
704
746
  pi->stack.head->val = oj_num_as_value(ni);
747
+ if (Yes == pi->options.trace) {
748
+ oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
749
+ }
705
750
  }
706
751
 
707
752
  void