json_pure 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. data/CHANGES +25 -0
  2. data/GPL +340 -0
  3. data/README +77 -0
  4. data/Rakefile +250 -0
  5. data/TODO +1 -0
  6. data/VERSION +1 -0
  7. data/benchmarks/benchmark.txt +133 -0
  8. data/benchmarks/benchmark_generator.rb +44 -0
  9. data/benchmarks/benchmark_parser.rb +22 -0
  10. data/benchmarks/benchmark_rails.rb +26 -0
  11. data/bin/edit_json.rb +11 -0
  12. data/data/example.json +1 -0
  13. data/data/index.html +37 -0
  14. data/data/prototype.js +2515 -0
  15. data/ext/json/ext/generator/Makefile +149 -0
  16. data/ext/json/ext/generator/extconf.rb +9 -0
  17. data/ext/json/ext/generator/generator.c +729 -0
  18. data/ext/json/ext/generator/unicode.c +184 -0
  19. data/ext/json/ext/generator/unicode.h +40 -0
  20. data/ext/json/ext/parser/Makefile +149 -0
  21. data/ext/json/ext/parser/extconf.rb +9 -0
  22. data/ext/json/ext/parser/parser.c +1551 -0
  23. data/ext/json/ext/parser/parser.rl +515 -0
  24. data/ext/json/ext/parser/unicode.c +156 -0
  25. data/ext/json/ext/parser/unicode.h +44 -0
  26. data/install.rb +26 -0
  27. data/lib/json.rb +205 -0
  28. data/lib/json/Array.xpm +21 -0
  29. data/lib/json/FalseClass.xpm +21 -0
  30. data/lib/json/Hash.xpm +21 -0
  31. data/lib/json/Key.xpm +73 -0
  32. data/lib/json/NilClass.xpm +21 -0
  33. data/lib/json/Numeric.xpm +28 -0
  34. data/lib/json/String.xpm +96 -0
  35. data/lib/json/TrueClass.xpm +21 -0
  36. data/lib/json/common.rb +184 -0
  37. data/lib/json/editor.rb +1207 -0
  38. data/lib/json/ext.rb +13 -0
  39. data/lib/json/json.xpm +1499 -0
  40. data/lib/json/pure.rb +75 -0
  41. data/lib/json/pure/generator.rb +321 -0
  42. data/lib/json/pure/parser.rb +210 -0
  43. data/lib/json/version.rb +8 -0
  44. data/tests/fixtures/fail1.json +1 -0
  45. data/tests/fixtures/fail10.json +1 -0
  46. data/tests/fixtures/fail11.json +1 -0
  47. data/tests/fixtures/fail12.json +1 -0
  48. data/tests/fixtures/fail13.json +1 -0
  49. data/tests/fixtures/fail14.json +1 -0
  50. data/tests/fixtures/fail15.json +1 -0
  51. data/tests/fixtures/fail16.json +1 -0
  52. data/tests/fixtures/fail17.json +1 -0
  53. data/tests/fixtures/fail19.json +1 -0
  54. data/tests/fixtures/fail2.json +1 -0
  55. data/tests/fixtures/fail20.json +1 -0
  56. data/tests/fixtures/fail21.json +1 -0
  57. data/tests/fixtures/fail22.json +1 -0
  58. data/tests/fixtures/fail23.json +1 -0
  59. data/tests/fixtures/fail24.json +1 -0
  60. data/tests/fixtures/fail25.json +1 -0
  61. data/tests/fixtures/fail26.json +1 -0
  62. data/tests/fixtures/fail27.json +2 -0
  63. data/tests/fixtures/fail28.json +2 -0
  64. data/tests/fixtures/fail3.json +1 -0
  65. data/tests/fixtures/fail4.json +1 -0
  66. data/tests/fixtures/fail5.json +1 -0
  67. data/tests/fixtures/fail6.json +1 -0
  68. data/tests/fixtures/fail7.json +1 -0
  69. data/tests/fixtures/fail8.json +1 -0
  70. data/tests/fixtures/fail9.json +1 -0
  71. data/tests/fixtures/pass1.json +56 -0
  72. data/tests/fixtures/pass18.json +1 -0
  73. data/tests/fixtures/pass2.json +1 -0
  74. data/tests/fixtures/pass3.json +6 -0
  75. data/tests/runner.rb +24 -0
  76. data/tests/test_json.rb +235 -0
  77. data/tests/test_json_addition.rb +94 -0
  78. data/tests/test_json_fixtures.rb +30 -0
  79. data/tests/test_json_generate.rb +81 -0
  80. data/tests/test_json_unicode.rb +55 -0
  81. data/tools/fuzz.rb +133 -0
  82. data/tools/server.rb +62 -0
  83. metadata +146 -0
@@ -0,0 +1,515 @@
1
+ /* vim: set cin et sw=4 ts=4: */
2
+
3
+ #include "ruby.h"
4
+ #include "re.h"
5
+ #include "unicode.h"
6
+
7
+ #ifndef swap16
8
+ #define swap16(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
9
+ #endif
10
+
11
+ #define EVIL 0x666
12
+
13
+ static VALUE mJSON, mExt, cParser, eParserError;
14
+
15
+ static ID i_json_creatable_p, i_json_create, i_create_id, i_chr;
16
+
17
+ typedef struct JSON_ParserStruct {
18
+ VALUE Vsource;
19
+ char *source;
20
+ long len;
21
+ char *memo;
22
+ VALUE create_id;
23
+ } JSON_Parser;
24
+
25
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
26
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result);
27
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result);
28
+ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
29
+ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
30
+ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
31
+
32
+ #define GET_STRUCT \
33
+ JSON_Parser *json; \
34
+ Data_Get_Struct(self, JSON_Parser, json);
35
+
36
+ %%{
37
+ machine JSON_common;
38
+
39
+ cr = '\n';
40
+ cr_neg = [^\n];
41
+ ws = [ \t\r\n];
42
+ c_comment = '/*' ( any* - (any* '*/' any* ) ) '*/';
43
+ cpp_comment = '//' cr_neg* cr;
44
+ comment = c_comment | cpp_comment;
45
+ ignore = ws | comment;
46
+ name_separator = ':';
47
+ value_separator = ',';
48
+ Vnull = 'null';
49
+ Vfalse = 'false';
50
+ Vtrue = 'true';
51
+ begin_value = [nft"\-[{] | digit;
52
+ begin_object = '{';
53
+ end_object = '}';
54
+ begin_array = '[';
55
+ end_array = ']';
56
+ begin_string = '"';
57
+ begin_name = begin_string;
58
+ begin_number = digit | '-';
59
+ }%%
60
+
61
+ %%{
62
+ machine JSON_object;
63
+ include JSON_common;
64
+
65
+ write data;
66
+
67
+ action parse_value {
68
+ VALUE v = Qnil;
69
+ char *np = JSON_parse_value(json, fpc, pe, &v);
70
+ if (np == NULL) {
71
+ fbreak;
72
+ } else {
73
+ rb_hash_aset(*result, last_name, v);
74
+ fexec np;
75
+ }
76
+ }
77
+
78
+ action parse_name {
79
+ char *np = JSON_parse_string(json, fpc, pe, &last_name);
80
+ if (np == NULL) fbreak; else fexec np;
81
+ }
82
+
83
+ action exit { fbreak; }
84
+
85
+ a_pair = ignore* begin_name >parse_name
86
+ ignore* name_separator ignore*
87
+ begin_value >parse_value;
88
+
89
+ main := begin_object
90
+ (a_pair (ignore* value_separator a_pair)*)?
91
+ ignore* end_object @exit;
92
+ }%%
93
+
94
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)
95
+ {
96
+ int cs = EVIL;
97
+ VALUE last_name = Qnil;
98
+ *result = rb_hash_new();
99
+
100
+ %% write init;
101
+ %% write exec;
102
+
103
+ if (cs >= JSON_object_first_final) {
104
+ VALUE klassname = rb_hash_aref(*result, json->create_id);
105
+ if (!NIL_P(klassname)) {
106
+ VALUE klass = rb_path2class(StringValueCStr(klassname));
107
+ if RTEST(rb_funcall(klass, i_json_creatable_p, 0)) {
108
+ *result = rb_funcall(klass, i_json_create, 1, *result);
109
+ }
110
+ }
111
+ return p + 1;
112
+ } else {
113
+ return NULL;
114
+ }
115
+ }
116
+
117
+ %%{
118
+ machine JSON_value;
119
+ include JSON_common;
120
+
121
+ write data;
122
+
123
+ action parse_null {
124
+ *result = Qnil;
125
+ }
126
+ action parse_false {
127
+ *result = Qfalse;
128
+ }
129
+ action parse_true {
130
+ *result = Qtrue;
131
+ }
132
+ action parse_string {
133
+ char *np = JSON_parse_string(json, fpc, pe, result);
134
+ if (np == NULL) fbreak; else fexec np;
135
+ }
136
+
137
+ action parse_number {
138
+ char *np;
139
+ np = JSON_parse_float(json, fpc, pe, result);
140
+ if (np != NULL) fexec np;
141
+ np = JSON_parse_integer(json, fpc, pe, result);
142
+ if (np != NULL) fexec np;
143
+ fbreak;
144
+ }
145
+
146
+ action parse_array {
147
+ char *np = JSON_parse_array(json, fpc, pe, result);
148
+ if (np == NULL) fbreak; else fexec np;
149
+ }
150
+
151
+ action parse_object {
152
+ char *np = JSON_parse_object(json, fpc, pe, result);
153
+ if (np == NULL) fbreak; else fexec np;
154
+ }
155
+
156
+ action exit { fbreak; }
157
+
158
+ main := (
159
+ Vnull @parse_null |
160
+ Vfalse @parse_false |
161
+ Vtrue @parse_true |
162
+ begin_number >parse_number |
163
+ begin_string >parse_string |
164
+ begin_array >parse_array |
165
+ begin_object >parse_object
166
+ ) %*exit;
167
+ }%%
168
+
169
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)
170
+ {
171
+ int cs = EVIL;
172
+
173
+ %% write init;
174
+ %% write exec;
175
+
176
+ if (cs >= JSON_value_first_final) {
177
+ return p;
178
+ } else {
179
+ return NULL;
180
+ }
181
+ }
182
+
183
+ %%{
184
+ machine JSON_integer;
185
+
186
+ write data;
187
+
188
+ action exit { fbreak; }
189
+
190
+ main := '-'? ('0' | [1-9][0-9]*) (^[0-9] @exit);
191
+ }%%
192
+
193
+ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
194
+ {
195
+ int cs = EVIL;
196
+
197
+ %% write init;
198
+ json->memo = p;
199
+ %% write exec;
200
+
201
+ if (cs >= JSON_integer_first_final) {
202
+ long len = p - json->memo;
203
+ *result = rb_Integer(rb_str_new(json->memo, len));
204
+ return p + 1;
205
+ } else {
206
+ return NULL;
207
+ }
208
+ }
209
+
210
+ %%{
211
+ machine JSON_float;
212
+ include JSON_common;
213
+
214
+ write data;
215
+
216
+ action exit { fbreak; }
217
+
218
+ main := '-'? (
219
+ (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
220
+ | ([1-9][0-9]* ([Ee] [+\-]?[0-9]+))
221
+ ) (^[0-9Ee.\-] @exit );
222
+ }%%
223
+
224
+ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
225
+ {
226
+ int cs = EVIL;
227
+
228
+ %% write init;
229
+ json->memo = p;
230
+ %% write exec;
231
+
232
+ if (cs >= JSON_float_first_final) {
233
+ long len = p - json->memo;
234
+ *result = rb_Float(rb_str_new(json->memo, len));
235
+ return p + 1;
236
+ } else {
237
+ return NULL;
238
+ }
239
+ }
240
+
241
+
242
+ %%{
243
+ machine JSON_array;
244
+ include JSON_common;
245
+
246
+ write data;
247
+
248
+ action parse_value {
249
+ VALUE v = Qnil;
250
+ char *np = JSON_parse_value(json, fpc, pe, &v);
251
+ if (np == NULL) {
252
+ fbreak;
253
+ } else {
254
+ rb_ary_push(*result, v);
255
+ fexec np;
256
+ }
257
+ }
258
+
259
+ action exit { fbreak; }
260
+
261
+ next_element = value_separator ignore* begin_value >parse_value;
262
+
263
+ main := begin_array ignore*
264
+ ((begin_value >parse_value ignore*)
265
+ (ignore* next_element ignore*)*)?
266
+ end_array @exit;
267
+ }%%
268
+
269
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)
270
+ {
271
+ int cs = EVIL;
272
+ *result = rb_ary_new();
273
+
274
+ %% write init;
275
+ %% write exec;
276
+
277
+ if(cs >= JSON_array_first_final) {
278
+ return p + 1;
279
+ } else {
280
+ rb_raise(eParserError, "unexpected token at '%s'", p);
281
+ }
282
+ }
283
+
284
+ static VALUE json_string_escape(char *p, char *pe)
285
+ {
286
+ VALUE result = rb_str_buf_new(pe - p + 1);
287
+
288
+ while (p < pe) {
289
+ if (*p == '\\') {
290
+ p++;
291
+ if (p >= pe) return Qnil; /* raise an exception later, \ at end */
292
+ switch (*p) {
293
+ case '"':
294
+ case '\\':
295
+ rb_str_buf_cat(result, p, 1);
296
+ p++;
297
+ break;
298
+ case 'b':
299
+ rb_str_buf_cat2(result, "\b");
300
+ p++;
301
+ break;
302
+ case 'f':
303
+ rb_str_buf_cat2(result, "\f");
304
+ p++;
305
+ break;
306
+ case 'n':
307
+ rb_str_buf_cat2(result, "\n");
308
+ p++;
309
+ break;
310
+ case 'r':
311
+ rb_str_buf_cat2(result, "\r");
312
+ p++;
313
+ break;
314
+ case 't':
315
+ rb_str_buf_cat2(result, "\t");
316
+ p++;
317
+ break;
318
+ case 'u':
319
+ if (p > pe - 4) {
320
+ return Qnil;
321
+ } else {
322
+ p = JSON_convert_UTF16_to_UTF8(result, p, pe, strictConversion);
323
+ }
324
+ break;
325
+ }
326
+ } else {
327
+ char *q = p;
328
+ while (*q != '\\' && q < pe) q++;
329
+ rb_str_buf_cat(result, p, q - p);
330
+ p = q;
331
+ }
332
+ }
333
+ return result;
334
+ }
335
+
336
+ %%{
337
+ machine JSON_string;
338
+ include JSON_common;
339
+
340
+ write data;
341
+
342
+ action parse_string {
343
+ *result = json_string_escape(json->memo + 1, p);
344
+ if (NIL_P(*result)) fbreak; else fexec p + 1;
345
+ }
346
+
347
+ action exit { fbreak; }
348
+
349
+ main := '"' ((^(["\\] | 0..0x1f) | '\\'["\\/bfnrt] | '\\u'[0-9a-fA-F]{4})* %parse_string) '"' @exit;
350
+ }%%
351
+
352
+ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result)
353
+ {
354
+ int cs = EVIL;
355
+
356
+ *result = rb_str_new("", 0);
357
+ %% write init;
358
+ json->memo = p;
359
+ %% write exec;
360
+
361
+ if (cs >= JSON_string_first_final) {
362
+ return p + 1;
363
+ } else {
364
+ return NULL;
365
+ }
366
+ }
367
+
368
+
369
+ %%{
370
+ machine JSON;
371
+
372
+ write data;
373
+
374
+ include JSON_common;
375
+
376
+ action parse_object {
377
+ char *np = JSON_parse_object(json, fpc, pe, &result);
378
+ if (np == NULL) fbreak; else fexec np;
379
+ }
380
+
381
+ action parse_array {
382
+ char *np = JSON_parse_array(json, fpc, pe, &result);
383
+ if (np == NULL) fbreak; else fexec np;
384
+ }
385
+
386
+ main := ignore* (
387
+ begin_object >parse_object |
388
+ begin_array >parse_array
389
+ ) ignore*;
390
+ }%%
391
+
392
+ /*
393
+ * Document-class: JSON::Ext::Parser
394
+ *
395
+ * This is the JSON parser implemented as a C extension. It can be configured
396
+ * to be used by setting
397
+ *
398
+ * JSON.parser = JSON::Ext::Parser
399
+ *
400
+ * with the method parser= in JSON.
401
+ *
402
+ */
403
+
404
+ /*
405
+ * call-seq: new(source)
406
+ *
407
+ * Creates a new JSON::Ext::Parser instance for the string _source_.
408
+ */
409
+ static VALUE cParser_initialize(VALUE self, VALUE source)
410
+ {
411
+ char *ptr;
412
+ long len;
413
+ GET_STRUCT;
414
+ source = StringValue(source);
415
+ ptr = RSTRING(source)->ptr;
416
+ len = RSTRING(source)->len;
417
+ if (len < 2) {
418
+ rb_raise(eParserError, "A JSON text must at least contain two octets!");
419
+ }
420
+ /*
421
+ Convert these?
422
+ if (len >= 4 && ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
423
+ rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
424
+ } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
425
+ rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
426
+ } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
427
+ rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
428
+ } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
429
+ rb_raise(eParserError, "Only UTF8 octet streams are supported atm!");
430
+ }
431
+ */
432
+ json->len = len;
433
+ json->source = ptr;
434
+ json->Vsource = source;
435
+ json->create_id = rb_funcall(mJSON, i_create_id, 0);
436
+ return self;
437
+ }
438
+
439
+ /*
440
+ * call-seq: parse()
441
+ *
442
+ * Parses the current JSON text _source_ and returns the complete data
443
+ * structure as a result.
444
+ */
445
+ static VALUE cParser_parse(VALUE self)
446
+ {
447
+ GET_STRUCT;
448
+ char *p, *pe;
449
+ int cs = EVIL;
450
+ VALUE result = Qnil;
451
+
452
+ %% write init;
453
+ p = json->source;
454
+ pe = p + json->len;
455
+ %% write exec;
456
+
457
+ if (cs >= JSON_first_final && p == pe) {
458
+ return result;
459
+ } else {
460
+ rb_raise(eParserError, "unexpected token at '%s'", p);
461
+ }
462
+ }
463
+
464
+ static JSON_Parser *JSON_allocate()
465
+ {
466
+ JSON_Parser *json = ALLOC(JSON_Parser);
467
+ MEMZERO(json, JSON_Parser, 1);
468
+ return json;
469
+ }
470
+
471
+ static void JSON_mark(JSON_Parser *json)
472
+ {
473
+ rb_gc_mark_maybe(json->Vsource);
474
+ rb_gc_mark_maybe(json->create_id);
475
+ }
476
+
477
+ static void JSON_free(JSON_Parser *json)
478
+ {
479
+ free(json);
480
+ }
481
+
482
+ static VALUE cJSON_parser_s_allocate(VALUE klass)
483
+ {
484
+ JSON_Parser *json = JSON_allocate();
485
+ return Data_Wrap_Struct(klass, JSON_mark, JSON_free, json);
486
+ }
487
+
488
+ /*
489
+ * call-seq: source()
490
+ *
491
+ * Returns a copy of the current _source_ string, that was used to construct
492
+ * this Parser.
493
+ */
494
+ static VALUE cParser_source(VALUE self)
495
+ {
496
+ GET_STRUCT;
497
+ return rb_str_dup(json->Vsource);
498
+ }
499
+
500
+ void Init_parser()
501
+ {
502
+ mJSON = rb_define_module("JSON");
503
+ mExt = rb_define_module_under(mJSON, "Ext");
504
+ cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
505
+ eParserError = rb_path2class("JSON::ParserError");
506
+ rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
507
+ rb_define_method(cParser, "initialize", cParser_initialize, 1);
508
+ rb_define_method(cParser, "parse", cParser_parse, 0);
509
+ rb_define_method(cParser, "source", cParser_source, 0);
510
+
511
+ i_json_creatable_p = rb_intern("json_creatable?");
512
+ i_json_create = rb_intern("json_create");
513
+ i_create_id = rb_intern("create_id");
514
+ i_chr = rb_intern("chr");
515
+ }