oj 3.12.2 → 3.13.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/ext/oj/buf.h +9 -0
  4. data/ext/oj/cache.c +193 -0
  5. data/ext/oj/cache.h +20 -0
  6. data/ext/oj/compat.c +8 -22
  7. data/ext/oj/custom.c +15 -14
  8. data/ext/oj/debug.c +132 -0
  9. data/ext/oj/dump.c +12 -15
  10. data/ext/oj/dump_compat.c +3 -3
  11. data/ext/oj/dump_object.c +9 -9
  12. data/ext/oj/dump_strict.c +3 -3
  13. data/ext/oj/err.h +19 -0
  14. data/ext/oj/extconf.rb +4 -0
  15. data/ext/oj/fast.c +7 -18
  16. data/ext/oj/intern.c +398 -0
  17. data/ext/oj/intern.h +27 -0
  18. data/ext/oj/mimic_json.c +9 -9
  19. data/ext/oj/object.c +11 -59
  20. data/ext/oj/odd.c +1 -1
  21. data/ext/oj/oj.c +167 -109
  22. data/ext/oj/oj.h +2 -2
  23. data/ext/oj/parse.c +5 -5
  24. data/ext/oj/parser.c +1512 -0
  25. data/ext/oj/parser.h +90 -0
  26. data/ext/oj/rails.c +5 -5
  27. data/ext/oj/resolve.c +2 -20
  28. data/ext/oj/rxclass.c +1 -1
  29. data/ext/oj/saj.c +1 -1
  30. data/ext/oj/saj2.c +348 -0
  31. data/ext/oj/scp.c +1 -1
  32. data/ext/oj/sparse.c +2 -2
  33. data/ext/oj/stream_writer.c +4 -4
  34. data/ext/oj/strict.c +10 -27
  35. data/ext/oj/string_writer.c +2 -2
  36. data/ext/oj/usual.c +1228 -0
  37. data/ext/oj/validate.c +51 -0
  38. data/ext/oj/wab.c +9 -17
  39. data/lib/oj/error.rb +1 -1
  40. data/lib/oj/mimic.rb +1 -1
  41. data/lib/oj/version.rb +1 -1
  42. data/pages/Modes.md +2 -0
  43. data/pages/Options.md +17 -5
  44. data/pages/Parser.md +309 -0
  45. data/pages/Rails.md +2 -2
  46. data/test/json_gem/json_generator_test.rb +1 -1
  47. data/test/perf_parser.rb +184 -0
  48. data/test/test_hash.rb +1 -1
  49. data/test/test_parser.rb +27 -0
  50. data/test/test_parser_saj.rb +245 -0
  51. data/test/test_parser_usual.rb +213 -0
  52. metadata +22 -5
  53. data/ext/oj/hash.c +0 -168
  54. data/ext/oj/hash.h +0 -21
  55. data/ext/oj/hash_test.c +0 -491
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89a87064f6668864cec4ab0c43892b4950c8ef7a9f7ea3da22f459af5bcd0083
4
- data.tar.gz: bc078e8b28d710a2194e2943343db687ec15d35d2556efff2f9e46936f3bb0b0
3
+ metadata.gz: 6371eea98925c8d16b816b991404d643051c566f3d36e2c4cf2c69cd29ffd816
4
+ data.tar.gz: 9373b88d98493ddf677e5f72fd1a16f155f5a9c773f007452b1e5810c586e057
5
5
  SHA512:
6
- metadata.gz: 95cb66c13e871bf85a351348b0c458c53fe2cd4057886396a62b763386fafe5d99c97143151808eb70dd526b8f13740cd43e266805c6b3454eac1be6940897db
7
- data.tar.gz: '09e24c7ec1daf2c10850b071eb4060aed265db662a92a78439eee1746b22437396f3358f82d982e040874c0916af3c38def244e03416e4971c2c5649823ff7c2'
6
+ metadata.gz: bb0fb2e41354e3f96804aa2d74f546e87f2df9076b1e3ec3815b271b0cf4b84ac4dc3ed6d49f59a11cb845c3675de84b4ac8a3b27dc3f80fd310f196437a34b4
7
+ data.tar.gz: ca2efef1c0e3f1e3fb36c7bf0ba5fdffcc596680f2d28923efd8a8cd7cf472178a364a3a93370f5bbefb404e9d0b338754905ed9eb4183eaa9fe0061af41bc93
data/README.md CHANGED
@@ -8,8 +8,7 @@
8
8
 
9
9
  A *fast* JSON parser and Object marshaller as a Ruby gem.
10
10
 
11
- Version 3.0 is out! 3.0 provides better json gem and Rails compatibility. It
12
- also provides additional optimization options.
11
+ Version 3.13 is out with a much faster parser (`Oj::Parser`) and option isolation.
13
12
 
14
13
  ## Using
15
14
 
@@ -54,7 +53,7 @@ For more details on options, modes, advanced features, and more follow these
54
53
  links.
55
54
 
56
55
  - [{file:Options.md}](pages/Options.md) for parse and dump options.
57
- - [{file:Modes.md}](pages/Modes.md) for details on modes for strict JSON compliance, mimicing the JSON gem, and mimicing Rails and ActiveSupport behavior.
56
+ - [{file:Modes.md}](pages/Modes.md) for details on modes for strict JSON compliance, mimicking the JSON gem, and mimicking Rails and ActiveSupport behavior.
58
57
  - [{file:JsonGem.md}](pages/JsonGem.md) includes more details on json gem compatibility and use.
59
58
  - [{file:Rails.md}](pages/Rails.md) includes more details on Rails and ActiveSupport compatibility and use.
60
59
  - [{file:Custom.md}](pages/Custom.md) includes more details on Custom mode.
data/ext/oj/buf.h CHANGED
@@ -19,6 +19,10 @@ inline static void buf_init(Buf buf) {
19
19
  buf->tail = buf->head;
20
20
  }
21
21
 
22
+ inline static void buf_reset(Buf buf) {
23
+ buf->tail = buf->head;
24
+ }
25
+
22
26
  inline static void buf_cleanup(Buf buf) {
23
27
  if (buf->base != buf->head) {
24
28
  xfree(buf->head);
@@ -29,6 +33,11 @@ inline static size_t buf_len(Buf buf) {
29
33
  return buf->tail - buf->head;
30
34
  }
31
35
 
36
+ inline static const char *buf_str(Buf buf) {
37
+ *buf->tail = '\0';
38
+ return buf->head;
39
+ }
40
+
32
41
  inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
33
42
  if (buf->end <= buf->tail + slen) {
34
43
  size_t len = buf->end - buf->head;
data/ext/oj/cache.c ADDED
@@ -0,0 +1,193 @@
1
+ // Copyright (c) 2011, 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #include "cache.h"
5
+
6
+ #define REHASH_LIMIT 64
7
+ #define MIN_SHIFT 8
8
+
9
+ typedef struct _slot {
10
+ struct _slot *next;
11
+ VALUE val;
12
+ uint32_t hash;
13
+ uint8_t klen;
14
+ char key[CACHE_MAX_KEY];
15
+ } * Slot;
16
+
17
+ typedef struct _cache {
18
+ Slot * slots;
19
+ size_t cnt;
20
+ VALUE (*form)(const char *str, size_t len);
21
+ uint32_t size;
22
+ uint32_t mask;
23
+ bool mark;
24
+ } * Cache;
25
+
26
+ // almost the Murmur hash algorithm
27
+ #define M 0x5bd1e995
28
+ #define C1 0xCC9E2D51
29
+ #define C2 0x1B873593
30
+ #define N 0xE6546B64
31
+
32
+ void cache_set_form(Cache c, VALUE (*form)(const char *str, size_t len)) {
33
+ c->form = form;
34
+ }
35
+
36
+ #if 0
37
+ // For debugging only.
38
+ static void cache_print(Cache c) {
39
+ for (uint32_t i = 0; i < c->size; i++) {
40
+ printf("%4d:", i);
41
+ for (Slot s = c->slots[i]; NULL != s; s = s->next) {
42
+ char buf[40];
43
+ strncpy(buf, s->key, s->klen);
44
+ buf[s->klen] = '\0';
45
+ printf(" %s", buf);
46
+ }
47
+ printf("\n");
48
+ }
49
+ }
50
+ #endif
51
+
52
+ static uint32_t hash_calc(const uint8_t *key, size_t len) {
53
+ const uint8_t *end = key + len;
54
+ const uint8_t *endless = key + (len & 0xFFFFFFFC);
55
+ uint32_t h = (uint32_t)len;
56
+ uint32_t k;
57
+
58
+ while (key < endless) {
59
+ k = (uint32_t)*key++;
60
+ k |= (uint32_t)*key++ << 8;
61
+ k |= (uint32_t)*key++ << 16;
62
+ k |= (uint32_t)*key++ << 24;
63
+
64
+ k *= M;
65
+ k ^= k >> 24;
66
+ h *= M;
67
+ h ^= k * M;
68
+ }
69
+ if (1 < end - key) {
70
+ uint16_t k16 = (uint16_t)*key++;
71
+
72
+ k16 |= (uint16_t)*key++ << 8;
73
+ h ^= k16 << 8;
74
+ }
75
+ if (key < end) {
76
+ h ^= *key;
77
+ }
78
+ h *= M;
79
+ h ^= h >> 13;
80
+ h *= M;
81
+ h ^= h >> 15;
82
+
83
+ return h;
84
+ }
85
+
86
+ Cache cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark) {
87
+ Cache c = ALLOC(struct _cache);
88
+ int shift = 0;
89
+
90
+ for (; REHASH_LIMIT < size; size /= 2, shift++) {
91
+ }
92
+ if (shift < MIN_SHIFT) {
93
+ shift = MIN_SHIFT;
94
+ }
95
+ c->size = 1 << shift;
96
+ c->mask = c->size - 1;
97
+ c->slots = ALLOC_N(Slot, c->size);
98
+ memset(c->slots, 0, sizeof(Slot) * c->size);
99
+ c->form = form;
100
+ c->cnt = 0;
101
+ c->mark = mark;
102
+
103
+ return c;
104
+ }
105
+
106
+ static void rehash(Cache c) {
107
+ uint32_t osize = c->size;
108
+ Slot * end = c->slots + osize;
109
+ Slot * sp;
110
+
111
+ c->size = osize * 4;
112
+ c->mask = c->size - 1;
113
+ REALLOC_N(c->slots, Slot, c->size);
114
+ memset(c->slots + osize, 0, sizeof(Slot) * osize * 3);
115
+ for (sp = c->slots; sp < end; sp++) {
116
+ Slot s = *sp;
117
+ Slot next = NULL;
118
+
119
+ *sp = NULL;
120
+ for (; NULL != s; s = next) {
121
+ uint32_t h = s->hash & c->mask;
122
+ Slot * bucket = c->slots + h;
123
+
124
+ next = s->next;
125
+ s->next = *bucket;
126
+ *bucket = s;
127
+ }
128
+ }
129
+ }
130
+
131
+ void cache_free(Cache c) {
132
+ uint32_t i;
133
+
134
+ for (i = 0; i < c->size; i++) {
135
+ Slot next;
136
+ Slot s;
137
+
138
+ for (s = c->slots[i]; NULL != s; s = next) {
139
+ next = s->next;
140
+ xfree(s);
141
+ }
142
+ }
143
+ xfree(c->slots);
144
+ xfree(c);
145
+ }
146
+
147
+ void cache_mark(Cache c) {
148
+ if (c->mark) {
149
+ uint32_t i;
150
+
151
+ for (i = 0; i < c->size; i++) {
152
+ Slot s;
153
+ for (s = c->slots[i]; NULL != s; s = s->next) {
154
+ rb_gc_mark(s->val);
155
+ }
156
+ }
157
+ }
158
+ }
159
+
160
+ VALUE
161
+ cache_intern(Cache c, const char *key, size_t len) {
162
+ if (CACHE_MAX_KEY < len) {
163
+ return c->form(key, len);
164
+ }
165
+ uint32_t h = hash_calc((const uint8_t *)key, len);
166
+ Slot * bucket = c->slots + (h & c->mask);
167
+ Slot b;
168
+ Slot tail = NULL;
169
+
170
+ for (b = *bucket; NULL != b; b = b->next) {
171
+ if ((uint8_t)len == b->klen && 0 == strncmp(b->key, key, len)) {
172
+ return b->val;
173
+ }
174
+ tail = b;
175
+ }
176
+ b = ALLOC(struct _slot);
177
+ b->hash = h;
178
+ b->next = NULL;
179
+ memcpy(b->key, key, len);
180
+ b->klen = (uint8_t)len;
181
+ b->key[len] = '\0';
182
+ b->val = c->form(key, len);
183
+ if (NULL == tail) {
184
+ *bucket = b;
185
+ } else {
186
+ tail->next = b;
187
+ }
188
+ c->cnt++;
189
+ if (REHASH_LIMIT < c->cnt / c->size) {
190
+ rehash(c);
191
+ }
192
+ return b->val;
193
+ }
data/ext/oj/cache.h ADDED
@@ -0,0 +1,20 @@
1
+ // Copyright (c) 2021 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
3
+
4
+ #ifndef CACHE_H
5
+ #define CACHE_H
6
+
7
+ #include <ruby.h>
8
+ #include <stdbool.h>
9
+
10
+ #define CACHE_MAX_KEY 35
11
+
12
+ struct _cache;
13
+
14
+ extern struct _cache *cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark);
15
+ extern void cache_free(struct _cache *c);
16
+ extern void cache_mark(struct _cache *c);
17
+ extern void cache_set_form(struct _cache *c, VALUE (*form)(const char *str, size_t len));
18
+ extern VALUE cache_intern(struct _cache *c, const char *key, size_t len);
19
+
20
+ #endif /* CACHE_H */
data/ext/oj/compat.c CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  #include "encode.h"
7
7
  #include "err.h"
8
- #include "hash.h"
8
+ #include "intern.h"
9
9
  #include "oj.h"
10
10
  #include "parse.h"
11
11
  #include "resolve.h"
@@ -27,30 +27,16 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
27
27
 
28
28
  if (Qundef == rkey) {
29
29
  if (Yes != pi->options.cache_keys) {
30
- rkey = rb_str_new(key, klen);
31
- rkey = oj_encode(rkey);
32
30
  if (Yes == pi->options.sym_key) {
33
- rkey = rb_str_intern(rkey);
34
- }
35
- } else {
36
- VALUE *slot;
37
-
38
- if (Yes == pi->options.sym_key) {
39
- if (Qnil == (rkey = oj_sym_hash_get(key, klen, &slot))) {
40
- rkey = rb_str_new(key, klen);
41
- rkey = oj_encode(rkey);
42
- rkey = rb_str_intern(rkey);
43
- *slot = rkey;
44
- rb_gc_register_address(slot);
45
- }
31
+ rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
46
32
  } else {
47
- if (Qnil == (rkey = oj_str_hash_get(key, klen, &slot))) {
48
- rkey = rb_str_new(key, klen);
49
- rkey = oj_encode(rkey);
50
- *slot = rkey;
51
- rb_gc_register_address(slot);
52
- }
33
+ rkey = rb_str_new(key, klen);
34
+ rkey = oj_encode(rkey);
53
35
  }
36
+ } else if (Yes == pi->options.sym_key) {
37
+ rkey = oj_sym_intern(key, klen);
38
+ } else {
39
+ rkey = oj_str_intern(key, klen);
54
40
  }
55
41
  }
56
42
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
data/ext/oj/custom.c CHANGED
@@ -8,7 +8,7 @@
8
8
  #include "dump.h"
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
- #include "hash.h"
11
+ #include "intern.h"
12
12
  #include "odd.h"
13
13
  #include "oj.h"
14
14
  #include "parse.h"
@@ -31,14 +31,14 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
31
31
 
32
32
  static void dump_obj_as_str(VALUE obj, int depth, Out out) {
33
33
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
34
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
34
+ const char * str = RSTRING_PTR(rstr);
35
35
 
36
36
  oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
37
37
  }
38
38
 
39
39
  static void bigdecimal_dump(VALUE obj, int depth, Out out) {
40
40
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
41
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
41
+ const char * str = RSTRING_PTR(rstr);
42
42
  int len = (int)RSTRING_LEN(rstr);
43
43
 
44
44
  if (0 == strcasecmp("Infinity", str)) {
@@ -123,7 +123,7 @@ static void date_dump(VALUE obj, int depth, Out out) {
123
123
  case RubyTime:
124
124
  case XmlTime:
125
125
  v = rb_funcall(obj, rb_intern("iso8601"), 0);
126
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&v), (int)RSTRING_LEN(v), 0, 0, out);
126
+ oj_dump_cstr(RSTRING_PTR(v), (int)RSTRING_LEN(v), 0, 0, out);
127
127
  break;
128
128
  case UnixZTime:
129
129
  v = rb_funcall(obj, rb_intern("to_time"), 0);
@@ -420,7 +420,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
420
420
  if (Qundef == v || T_STRING != rb_type(v)) {
421
421
  rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
422
422
  } else {
423
- const char *s = rb_string_value_ptr((VALUE *)&v);
423
+ const char *s = RSTRING_PTR(v);
424
424
  int len = (int)RSTRING_LEN(v);
425
425
  const char *name = rb_id2name(*odd->attrs);
426
426
  size_t nlen = strlen(name);
@@ -510,7 +510,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
510
510
  if (Yes == out->opts->trace) {
511
511
  oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
512
512
  }
513
- s = rb_string_value_ptr((VALUE *)&rs);
513
+ s = RSTRING_PTR(rs);
514
514
  len = (int)RSTRING_LEN(rs);
515
515
 
516
516
  assure_size(out, len + 1);
@@ -537,7 +537,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
537
537
  if (aj == obj) {
538
538
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
539
539
 
540
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr),
540
+ oj_dump_cstr(RSTRING_PTR(rstr),
541
541
  (int)RSTRING_LEN(rstr),
542
542
  false,
543
543
  false,
@@ -833,9 +833,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
833
833
  v = rb_struct_aref(obj, INT2FIX(i));
834
834
  #endif
835
835
  if (ma != Qnil) {
836
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
836
+ volatile VALUE s = rb_sym2str(rb_ary_entry(ma, i));
837
837
 
838
- name = rb_string_value_ptr((VALUE *)&s);
838
+ name = RSTRING_PTR(s);
839
839
  len = (int)RSTRING_LEN(s);
840
840
  } else {
841
841
  len = snprintf(num_id, sizeof(num_id), "%d", i);
@@ -959,12 +959,13 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
959
959
  volatile VALUE rstr = rb_str_new(str, len);
960
960
 
961
961
  if (Qundef == rkey) {
962
- rkey = rb_str_new(key, klen);
963
- rstr = oj_encode(rstr);
964
- rkey = oj_encode(rkey);
965
962
  if (Yes == pi->options.sym_key) {
966
- rkey = rb_str_intern(rkey);
963
+ rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
964
+ } else {
965
+ rkey = rb_str_new(key, klen);
966
+ rkey = oj_encode(rkey);
967
967
  }
968
+ rstr = oj_encode(rstr);
968
969
  }
969
970
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
970
971
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
@@ -1031,7 +1032,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1031
1032
  }
1032
1033
  if (86400 == ni->exp) { // UTC time
1033
1034
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1034
- // Since the ruby C routines alway create local time, the
1035
+ // Since the ruby C routines always create local time, the
1035
1036
  // offset and then a conversion to UTC keeps makes the time
1036
1037
  // match the expected value.
1037
1038
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
data/ext/oj/debug.c ADDED
@@ -0,0 +1,132 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "parser.h"
4
+
5
+ static void add_null(struct _ojParser *p) {
6
+ switch (p->stack[p->depth]) {
7
+ case TOP_FUN: printf("*** add_null at top\n"); break;
8
+ case ARRAY_FUN: printf("*** add_null to array\n"); break;
9
+ case OBJECT_FUN: printf("*** add_null with '%s'\n", buf_str(&p->key)); break;
10
+ }
11
+ }
12
+
13
+ static void add_true(struct _ojParser *p) {
14
+ switch (p->stack[p->depth]) {
15
+ case TOP_FUN: printf("*** add_true at top\n"); break;
16
+ case ARRAY_FUN: printf("*** add_true to array\n"); break;
17
+ case OBJECT_FUN: printf("*** add_true with '%s'\n", buf_str(&p->key)); break;
18
+ }
19
+ }
20
+
21
+ static void add_false(struct _ojParser *p) {
22
+ switch (p->stack[p->depth]) {
23
+ case TOP_FUN: printf("*** add_false at top\n"); break;
24
+ case ARRAY_FUN: printf("*** add_false to array\n"); break;
25
+ case OBJECT_FUN: printf("*** add_false with '%s'\n", buf_str(&p->key)); break;
26
+ }
27
+ }
28
+
29
+ static void add_int(struct _ojParser *p) {
30
+ switch (p->stack[p->depth]) {
31
+ case TOP_FUN: printf("*** add_int %lld at top\n", (long long)p->num.fixnum); break;
32
+ case ARRAY_FUN: printf("*** add_int %lld to array\n", (long long)p->num.fixnum); break;
33
+ case OBJECT_FUN:
34
+ printf("*** add_int %lld with '%s'\n", (long long)p->num.fixnum, buf_str(&p->key));
35
+ break;
36
+ }
37
+ }
38
+
39
+ static void add_float(struct _ojParser *p) {
40
+ switch (p->stack[p->depth]) {
41
+ case TOP_FUN: printf("*** add_float %Lf at top\n", p->num.dub); break;
42
+ case ARRAY_FUN: printf("*** add_float %Lf to array\n", p->num.dub); break;
43
+ case OBJECT_FUN: printf("*** add_float %Lf with '%s'\n", p->num.dub, buf_str(&p->key)); break;
44
+ }
45
+ }
46
+
47
+ static void add_big(struct _ojParser *p) {
48
+ switch (p->stack[p->depth]) {
49
+ case TOP_FUN: printf("*** add_big %s at top\n", buf_str(&p->buf)); break;
50
+ case ARRAY_FUN: printf("*** add_big %s to array\n", buf_str(&p->buf)); break;
51
+ case OBJECT_FUN:
52
+ printf("*** add_big %s with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
53
+ break;
54
+ }
55
+ }
56
+
57
+ static void add_str(struct _ojParser *p) {
58
+ switch (p->stack[p->depth]) {
59
+ case TOP_FUN: printf("*** add_str '%s' at top\n", buf_str(&p->buf)); break;
60
+ case ARRAY_FUN: printf("*** add_str '%s' to array\n", buf_str(&p->buf)); break;
61
+ case OBJECT_FUN:
62
+ printf("*** add_str '%s' with '%s'\n", buf_str(&p->buf), buf_str(&p->key));
63
+ break;
64
+ }
65
+ }
66
+
67
+ static void open_array(struct _ojParser *p) {
68
+ switch (p->stack[p->depth]) {
69
+ case TOP_FUN: printf("*** open_array at top\n"); break;
70
+ case ARRAY_FUN: printf("*** open_array to array\n"); break;
71
+ case OBJECT_FUN: printf("*** open_array with '%s'\n", buf_str(&p->key)); break;
72
+ }
73
+ }
74
+
75
+ static void close_array(struct _ojParser *p) {
76
+ printf("*** close_array\n");
77
+ }
78
+
79
+ static void open_object(struct _ojParser *p) {
80
+ switch (p->stack[p->depth]) {
81
+ case TOP_FUN: printf("*** open_object at top\n"); break;
82
+ case ARRAY_FUN: printf("*** open_object to array\n"); break;
83
+ case OBJECT_FUN: printf("*** open_object with '%s'\n", buf_str(&p->key)); break;
84
+ }
85
+ }
86
+
87
+ static void close_object(struct _ojParser *p) {
88
+ printf("*** close_object\n");
89
+ }
90
+
91
+ static VALUE option(ojParser p, const char *key, VALUE value) {
92
+ rb_raise(rb_eArgError, "%s is not an option for the debug delegate", key);
93
+ return Qnil;
94
+ }
95
+
96
+ static VALUE result(struct _ojParser *p) {
97
+ return Qnil;
98
+ }
99
+
100
+ static void start(struct _ojParser *p) {
101
+ printf("*** start\n");
102
+ }
103
+
104
+ static void dfree(struct _ojParser *p) {
105
+ }
106
+
107
+ static void mark(struct _ojParser *p) {
108
+ }
109
+
110
+ void oj_set_parser_debug(ojParser p) {
111
+ Funcs end = p->funcs + 3;
112
+ Funcs f;
113
+
114
+ for (f = p->funcs; f < end; f++) {
115
+ f->add_null = add_null;
116
+ f->add_true = add_true;
117
+ f->add_false = add_false;
118
+ f->add_int = add_int;
119
+ f->add_float = add_float;
120
+ f->add_big = add_big;
121
+ f->add_str = add_str;
122
+ f->open_array = open_array;
123
+ f->close_array = close_array;
124
+ f->open_object = open_object;
125
+ f->close_object = close_object;
126
+ }
127
+ p->option = option;
128
+ p->result = result;
129
+ p->free = dfree;
130
+ p->mark = mark;
131
+ p->start = start;
132
+ }