@port-labs/jq-node-bindings 0.0.1

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.
Files changed (131) hide show
  1. package/.editorconfig +5 -0
  2. package/.jshintignore +1 -0
  3. package/.jshintrc +23 -0
  4. package/binding.gyp +56 -0
  5. package/configure +26 -0
  6. package/deps/jq/.gitattributes +2 -0
  7. package/deps/jq/.travis.yml +53 -0
  8. package/deps/jq/AUTHORS +73 -0
  9. package/deps/jq/COPYING +70 -0
  10. package/deps/jq/ChangeLog +1349 -0
  11. package/deps/jq/Makefile.am +198 -0
  12. package/deps/jq/NEWS +88 -0
  13. package/deps/jq/README.md +64 -0
  14. package/deps/jq/builtin.c +1684 -0
  15. package/deps/jq/builtin.h +10 -0
  16. package/deps/jq/bytecode.c +161 -0
  17. package/deps/jq/bytecode.h +92 -0
  18. package/deps/jq/compile-ios.sh +102 -0
  19. package/deps/jq/compile.c +1210 -0
  20. package/deps/jq/compile.h +101 -0
  21. package/deps/jq/config/m4/check-math-func.m4 +4 -0
  22. package/deps/jq/config/m4/find-func-no-libs.m4 +8 -0
  23. package/deps/jq/config/m4/find-func-no-libs2.m4 +62 -0
  24. package/deps/jq/config/m4/find-func.m4 +9 -0
  25. package/deps/jq/config/m4/misc.m4 +3 -0
  26. package/deps/jq/configure.ac +221 -0
  27. package/deps/jq/docs/Gemfile +7 -0
  28. package/deps/jq/docs/Gemfile.lock +63 -0
  29. package/deps/jq/docs/README.md +25 -0
  30. package/deps/jq/docs/Rakefile +145 -0
  31. package/deps/jq/docs/content/1.tutorial/default.yml +327 -0
  32. package/deps/jq/docs/content/2.download/default.yml +117 -0
  33. package/deps/jq/docs/content/3.manual/manual.yml +2878 -0
  34. package/deps/jq/docs/content/3.manual/v1.3/manual.yml +1270 -0
  35. package/deps/jq/docs/content/3.manual/v1.4/manual.yml +1672 -0
  36. package/deps/jq/docs/content/index/index.yml +51 -0
  37. package/deps/jq/docs/default_manpage.md +22 -0
  38. package/deps/jq/docs/public/.htaccess +28 -0
  39. package/deps/jq/docs/public/bootstrap/css/bootstrap-responsive.css +1058 -0
  40. package/deps/jq/docs/public/bootstrap/css/bootstrap-responsive.min.css +9 -0
  41. package/deps/jq/docs/public/bootstrap/css/bootstrap.css +5224 -0
  42. package/deps/jq/docs/public/bootstrap/css/bootstrap.min.css +9 -0
  43. package/deps/jq/docs/public/bootstrap/img/glyphicons-halflings-white.png +0 -0
  44. package/deps/jq/docs/public/bootstrap/img/glyphicons-halflings.png +0 -0
  45. package/deps/jq/docs/public/bootstrap/js/bootstrap.js +2027 -0
  46. package/deps/jq/docs/public/bootstrap/js/bootstrap.min.js +6 -0
  47. package/deps/jq/docs/public/css/base.scss +99 -0
  48. package/deps/jq/docs/public/jq.png +0 -0
  49. package/deps/jq/docs/public/robots.txt +2 -0
  50. package/deps/jq/docs/site.yml +18 -0
  51. package/deps/jq/docs/templates/default.liquid +34 -0
  52. package/deps/jq/docs/templates/index.liquid +60 -0
  53. package/deps/jq/docs/templates/manual.liquid +122 -0
  54. package/deps/jq/docs/templates/shared/_footer.liquid +5 -0
  55. package/deps/jq/docs/templates/shared/_head.liquid +12 -0
  56. package/deps/jq/docs/templates/shared/_header.liquid +26 -0
  57. package/deps/jq/exec_stack.h +112 -0
  58. package/deps/jq/execute.c +1155 -0
  59. package/deps/jq/inject_errors.c +112 -0
  60. package/deps/jq/jq.1.default +39 -0
  61. package/deps/jq/jq.1.prebuilt +3075 -0
  62. package/deps/jq/jq.h +60 -0
  63. package/deps/jq/jq.spec +70 -0
  64. package/deps/jq/jq_parser.h +9 -0
  65. package/deps/jq/jq_test.c +346 -0
  66. package/deps/jq/jv.c +1333 -0
  67. package/deps/jq/jv.h +240 -0
  68. package/deps/jq/jv_alloc.c +179 -0
  69. package/deps/jq/jv_alloc.h +27 -0
  70. package/deps/jq/jv_aux.c +619 -0
  71. package/deps/jq/jv_dtoa.c +4275 -0
  72. package/deps/jq/jv_dtoa.h +22 -0
  73. package/deps/jq/jv_file.c +49 -0
  74. package/deps/jq/jv_parse.c +852 -0
  75. package/deps/jq/jv_print.c +348 -0
  76. package/deps/jq/jv_unicode.c +96 -0
  77. package/deps/jq/jv_unicode.h +11 -0
  78. package/deps/jq/jv_utf8_tables.h +37 -0
  79. package/deps/jq/lexer.c +2442 -0
  80. package/deps/jq/lexer.h +362 -0
  81. package/deps/jq/lexer.l +184 -0
  82. package/deps/jq/libm.h +160 -0
  83. package/deps/jq/linker.c +393 -0
  84. package/deps/jq/linker.h +7 -0
  85. package/deps/jq/locfile.c +91 -0
  86. package/deps/jq/locfile.h +29 -0
  87. package/deps/jq/m4/ax_compare_version.m4 +177 -0
  88. package/deps/jq/m4/ax_prog_bison_version.m4 +68 -0
  89. package/deps/jq/main.c +566 -0
  90. package/deps/jq/opcode_list.h +44 -0
  91. package/deps/jq/parser.c +3914 -0
  92. package/deps/jq/parser.h +193 -0
  93. package/deps/jq/parser.y +923 -0
  94. package/deps/jq/scripts/crosscompile +42 -0
  95. package/deps/jq/scripts/gen_utf8_tables.py +32 -0
  96. package/deps/jq/scripts/version +5 -0
  97. package/deps/jq/setup.sh +33 -0
  98. package/deps/jq/tests/jq.test +1235 -0
  99. package/deps/jq/tests/jqtest +5 -0
  100. package/deps/jq/tests/mantest +7 -0
  101. package/deps/jq/tests/modules/.jq +5 -0
  102. package/deps/jq/tests/modules/a.jq +2 -0
  103. package/deps/jq/tests/modules/b/b.jq +2 -0
  104. package/deps/jq/tests/modules/c/c.jq +16 -0
  105. package/deps/jq/tests/modules/c/d.jq +1 -0
  106. package/deps/jq/tests/modules/data.json +4 -0
  107. package/deps/jq/tests/modules/lib/jq/e/e.jq +1 -0
  108. package/deps/jq/tests/modules/lib/jq/f.jq +1 -0
  109. package/deps/jq/tests/modules/syntaxerror/syntaxerror.jq +1 -0
  110. package/deps/jq/tests/modules/test_bind_order.jq +4 -0
  111. package/deps/jq/tests/modules/test_bind_order0.jq +1 -0
  112. package/deps/jq/tests/modules/test_bind_order1.jq +2 -0
  113. package/deps/jq/tests/modules/test_bind_order2.jq +2 -0
  114. package/deps/jq/tests/onig.supp +21 -0
  115. package/deps/jq/tests/onig.test +85 -0
  116. package/deps/jq/tests/onigtest +5 -0
  117. package/deps/jq/tests/setup +36 -0
  118. package/deps/jq/tests/shtest +205 -0
  119. package/deps/jq/tests/torture/input0.json +7 -0
  120. package/deps/jq/util.c +462 -0
  121. package/deps/jq/util.h +64 -0
  122. package/deps/jq.gyp +35 -0
  123. package/index.d.ts +3 -0
  124. package/jest.config.js +10 -0
  125. package/lib/index.js +14 -0
  126. package/package.json +48 -0
  127. package/reports/jest-port-api.xml +35 -0
  128. package/src/binding.cc +177 -0
  129. package/src/binding.h +13 -0
  130. package/test/santiy.test.js +122 -0
  131. package/util/configure.js +27 -0
@@ -0,0 +1,852 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include <assert.h>
5
+ #include "jv.h"
6
+ #include "jv_dtoa.h"
7
+ #include "jv_unicode.h"
8
+ #include "jv_alloc.h"
9
+ #include "jv_dtoa.h"
10
+
11
+ typedef const char* presult;
12
+
13
+ #define TRY(x) do {presult msg__ = (x); if (msg__) return msg__; } while(0)
14
+ #ifdef __GNUC__
15
+ #define pfunc __attribute__((warn_unused_result)) presult
16
+ #else
17
+ #define pfunc presult
18
+ #endif
19
+
20
+ enum last_seen {
21
+ JV_LAST_NONE = 0,
22
+ JV_LAST_OPEN_ARRAY = '[',
23
+ JV_LAST_OPEN_OBJECT = '{',
24
+ JV_LAST_COLON = ':',
25
+ JV_LAST_COMMA = ',',
26
+ JV_LAST_VALUE = 'V',
27
+ };
28
+
29
+ struct jv_parser {
30
+ const char* curr_buf;
31
+ int curr_buf_length;
32
+ int curr_buf_pos;
33
+ int curr_buf_is_partial;
34
+ int eof;
35
+ unsigned bom_strip_position;
36
+
37
+ int flags;
38
+
39
+ jv* stack; // parser
40
+ int stackpos; // parser
41
+ int stacklen; // both (optimization; it's really pathlen for streaming)
42
+ jv path; // streamer
43
+ enum last_seen last_seen; // streamer
44
+ jv output; // streamer
45
+ jv next; // both
46
+
47
+ char* tokenbuf;
48
+ int tokenpos;
49
+ int tokenlen;
50
+
51
+ int line, column;
52
+
53
+ struct dtoa_context dtoa;
54
+
55
+ enum {
56
+ JV_PARSER_NORMAL,
57
+ JV_PARSER_STRING,
58
+ JV_PARSER_STRING_ESCAPE,
59
+ JV_PARSER_WAITING_FOR_RS // parse error, waiting for RS
60
+ } st;
61
+ unsigned int last_ch_was_ws:1;
62
+ };
63
+
64
+
65
+ static void parser_init(struct jv_parser* p, int flags) {
66
+ p->flags = flags;
67
+ if ((p->flags & JV_PARSE_STREAMING)) {
68
+ p->path = jv_array();
69
+ } else {
70
+ p->path = jv_invalid();
71
+ p->flags &= ~(JV_PARSE_STREAM_ERRORS);
72
+ }
73
+ p->stack = 0;
74
+ p->stacklen = p->stackpos = 0;
75
+ p->last_seen = JV_LAST_NONE;
76
+ p->output = jv_invalid();
77
+ p->next = jv_invalid();
78
+ p->tokenbuf = 0;
79
+ p->tokenlen = p->tokenpos = 0;
80
+ if ((p->flags & JV_PARSE_SEQ))
81
+ p->st = JV_PARSER_WAITING_FOR_RS;
82
+ else
83
+ p->st = JV_PARSER_NORMAL;
84
+ p->eof = 0;
85
+ p->curr_buf = 0;
86
+ p->curr_buf_length = p->curr_buf_pos = p->curr_buf_is_partial = 0;
87
+ p->bom_strip_position = 0;
88
+ p->last_ch_was_ws = 0;
89
+ p->line = 1;
90
+ p->column = 0;
91
+ jvp_dtoa_context_init(&p->dtoa);
92
+ }
93
+
94
+ static void parser_reset(struct jv_parser* p) {
95
+ if ((p->flags & JV_PARSE_STREAMING)) {
96
+ jv_free(p->path);
97
+ p->path = jv_array();
98
+ p->stacklen = 0;
99
+ }
100
+ p->last_seen = JV_LAST_NONE;
101
+ jv_free(p->output);
102
+ p->output = jv_invalid();
103
+ jv_free(p->next);
104
+ p->next = jv_invalid();
105
+ for (int i=0; i<p->stackpos; i++)
106
+ jv_free(p->stack[i]);
107
+ p->stackpos = 0;
108
+ p->tokenpos = 0;
109
+ p->st = JV_PARSER_NORMAL;
110
+ }
111
+
112
+ static void parser_free(struct jv_parser* p) {
113
+ parser_reset(p);
114
+ jv_free(p->path);
115
+ jv_free(p->output);
116
+ jv_mem_free(p->stack);
117
+ jv_mem_free(p->tokenbuf);
118
+ jvp_dtoa_context_free(&p->dtoa);
119
+ }
120
+
121
+ static pfunc value(struct jv_parser* p, jv val) {
122
+ if ((p->flags & JV_PARSE_STREAMING)) {
123
+ if (jv_is_valid(p->next) || p->last_seen == JV_LAST_VALUE)
124
+ return "Expected separator between values";
125
+ if (p->stacklen > 0)
126
+ p->last_seen = JV_LAST_VALUE;
127
+ else
128
+ p->last_seen = JV_LAST_NONE;
129
+ } else {
130
+ if (jv_is_valid(p->next)) return "Expected separator between values";
131
+ }
132
+ jv_free(p->next);
133
+ p->next = val;
134
+ return 0;
135
+ }
136
+
137
+ static void push(struct jv_parser* p, jv v) {
138
+ assert(p->stackpos <= p->stacklen);
139
+ if (p->stackpos == p->stacklen) {
140
+ p->stacklen = p->stacklen * 2 + 10;
141
+ p->stack = jv_mem_realloc(p->stack, p->stacklen * sizeof(jv));
142
+ }
143
+ assert(p->stackpos < p->stacklen);
144
+ p->stack[p->stackpos++] = v;
145
+ }
146
+
147
+ static pfunc parse_token(struct jv_parser* p, char ch) {
148
+ switch (ch) {
149
+ case '[':
150
+ if (jv_is_valid(p->next)) return "Expected separator between values";
151
+ push(p, jv_array());
152
+ break;
153
+
154
+ case '{':
155
+ if (jv_is_valid(p->next)) return "Expected separator between values";
156
+ push(p, jv_object());
157
+ break;
158
+
159
+ case ':':
160
+ if (!jv_is_valid(p->next))
161
+ return "Expected string key before ':'";
162
+ if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT)
163
+ return "':' not as part of an object";
164
+ if (jv_get_kind(p->next) != JV_KIND_STRING)
165
+ return "Object keys must be strings";
166
+ push(p, p->next);
167
+ p->next = jv_invalid();
168
+ break;
169
+
170
+ case ',':
171
+ if (!jv_is_valid(p->next))
172
+ return "Expected value before ','";
173
+ if (p->stackpos == 0)
174
+ return "',' not as part of an object or array";
175
+ if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_ARRAY) {
176
+ p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next);
177
+ p->next = jv_invalid();
178
+ } else if (jv_get_kind(p->stack[p->stackpos-1]) == JV_KIND_STRING) {
179
+ assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT);
180
+ p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2],
181
+ p->stack[p->stackpos-1], p->next);
182
+ p->stackpos--;
183
+ p->next = jv_invalid();
184
+ } else {
185
+ // this case hits on input like {"a", "b"}
186
+ return "Objects must consist of key:value pairs";
187
+ }
188
+ break;
189
+
190
+ case ']':
191
+ if (p->stackpos == 0 || jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_ARRAY)
192
+ return "Unmatched ']'";
193
+ if (jv_is_valid(p->next)) {
194
+ p->stack[p->stackpos-1] = jv_array_append(p->stack[p->stackpos-1], p->next);
195
+ p->next = jv_invalid();
196
+ } else {
197
+ if (jv_array_length(jv_copy(p->stack[p->stackpos-1])) != 0) {
198
+ // this case hits on input like [1,2,3,]
199
+ return "Expected another array element";
200
+ }
201
+ }
202
+ jv_free(p->next);
203
+ p->next = p->stack[--p->stackpos];
204
+ break;
205
+
206
+ case '}':
207
+ if (p->stackpos == 0)
208
+ return "Unmatched '}'";
209
+ if (jv_is_valid(p->next)) {
210
+ if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_STRING)
211
+ return "Objects must consist of key:value pairs";
212
+ assert(p->stackpos > 1 && jv_get_kind(p->stack[p->stackpos-2]) == JV_KIND_OBJECT);
213
+ p->stack[p->stackpos-2] = jv_object_set(p->stack[p->stackpos-2],
214
+ p->stack[p->stackpos-1], p->next);
215
+ p->stackpos--;
216
+ p->next = jv_invalid();
217
+ } else {
218
+ if (jv_get_kind(p->stack[p->stackpos-1]) != JV_KIND_OBJECT)
219
+ return "Unmatched '}'";
220
+ if (jv_object_length(jv_copy(p->stack[p->stackpos-1])) != 0)
221
+ return "Expected another key-value pair";
222
+ }
223
+ jv_free(p->next);
224
+ p->next = p->stack[--p->stackpos];
225
+ break;
226
+ }
227
+ return 0;
228
+ }
229
+
230
+ static pfunc stream_token(struct jv_parser* p, char ch) {
231
+ jv_kind k;
232
+ jv last;
233
+
234
+ switch (ch) {
235
+ case '[':
236
+ if (jv_is_valid(p->next))
237
+ return "Expected a separator between values";
238
+ p->path = jv_array_append(p->path, jv_number(0)); // push
239
+ p->last_seen = JV_LAST_OPEN_ARRAY;
240
+ p->stacklen++;
241
+ break;
242
+
243
+ case '{':
244
+ if (p->last_seen == JV_LAST_VALUE)
245
+ return "Expected a separator between values";
246
+ // Push object key: null, since we don't know it yet
247
+ p->path = jv_array_append(p->path, jv_null()); // push
248
+ p->last_seen = JV_LAST_OPEN_OBJECT;
249
+ p->stacklen++;
250
+ break;
251
+
252
+ case ':':
253
+ if (p->stacklen == 0 || jv_get_kind(jv_array_get(jv_copy(p->path), p->stacklen - 1)) == JV_KIND_NUMBER)
254
+ return "':' not as part of an object";
255
+ if (!jv_is_valid(p->next) || p->last_seen == JV_LAST_NONE)
256
+ return "Expected string key before ':'";
257
+ if (jv_get_kind(p->next) != JV_KIND_STRING)
258
+ return "Object keys must be strings";
259
+ if (p->last_seen != JV_LAST_VALUE)
260
+ return "':' should follow a key";
261
+ p->last_seen = JV_LAST_COLON;
262
+ p->path = jv_array_set(p->path, p->stacklen - 1, p->next);
263
+ p->next = jv_invalid();
264
+ break;
265
+
266
+ case ',':
267
+ if (p->last_seen != JV_LAST_VALUE)
268
+ return "Expected value before ','";
269
+ if (p->stacklen == 0)
270
+ return "',' not as part of an object or array";
271
+ last = jv_array_get(jv_copy(p->path), p->stacklen - 1);
272
+ k = jv_get_kind(last);
273
+ if (k == JV_KIND_NUMBER) {
274
+ int idx = jv_number_value(last);
275
+
276
+ if (jv_is_valid(p->next)) {
277
+ p->output = JV_ARRAY(jv_copy(p->path), p->next);
278
+ p->next = jv_invalid();
279
+ }
280
+ p->path = jv_array_set(p->path, p->stacklen - 1, jv_number(idx + 1));
281
+ p->last_seen = JV_LAST_COMMA;
282
+ } else if (k == JV_KIND_STRING) {
283
+ if (jv_is_valid(p->next)) {
284
+ p->output = JV_ARRAY(jv_copy(p->path), p->next);
285
+ p->next = jv_invalid();
286
+ }
287
+ p->path = jv_array_set(p->path, p->stacklen - 1, jv_true()); // ready for another name:value pair
288
+ p->last_seen = JV_LAST_COMMA;
289
+ } else {
290
+ assert(k == JV_KIND_NULL);
291
+ // this case hits on input like {,}
292
+ // make sure to handle input like {"a", "b"} and {"a":, ...}
293
+ jv_free(last);
294
+ return "Objects must consist of key:value pairs";
295
+ }
296
+ jv_free(last);
297
+ break;
298
+
299
+ case ']':
300
+ if (p->stacklen == 0)
301
+ return "Unmatched ']' at the top-level";
302
+ if (p->last_seen == JV_LAST_COMMA)
303
+ return "Expected another array element";
304
+ if (p->last_seen == JV_LAST_OPEN_ARRAY)
305
+ assert(!jv_is_valid(p->next));
306
+
307
+ last = jv_array_get(jv_copy(p->path), p->stacklen - 1);
308
+ k = jv_get_kind(last);
309
+ jv_free(last);
310
+
311
+ if (k != JV_KIND_NUMBER)
312
+ return "Unmatched ']' in the middle of an object";
313
+ if (jv_is_valid(p->next)) {
314
+ p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true());
315
+ p->next = jv_invalid();
316
+ } else if (p->last_seen != JV_LAST_OPEN_ARRAY) {
317
+ p->output = JV_ARRAY(jv_copy(p->path));
318
+ }
319
+
320
+ p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop
321
+ //assert(!jv_is_valid(p->next));
322
+ jv_free(p->next);
323
+ p->next = jv_invalid();
324
+
325
+ if (p->last_seen == JV_LAST_OPEN_ARRAY)
326
+ p->output = JV_ARRAY(jv_copy(p->path), jv_array()); // Empty arrays are leaves
327
+
328
+ if (p->stacklen == 0)
329
+ p->last_seen = JV_LAST_NONE;
330
+ else
331
+ p->last_seen = JV_LAST_VALUE;
332
+ break;
333
+
334
+ case '}':
335
+ if (p->stacklen == 0)
336
+ return "Unmatched '}' at the top-level";
337
+ if (p->last_seen == JV_LAST_COMMA)
338
+ return "Expected another key:value pair";
339
+ if (p->last_seen == JV_LAST_OPEN_OBJECT)
340
+ assert(!jv_is_valid(p->next));
341
+
342
+ last = jv_array_get(jv_copy(p->path), p->stacklen - 1);
343
+ k = jv_get_kind(last);
344
+ jv_free(last);
345
+ if (k == JV_KIND_NUMBER)
346
+ return "Unmatched '}' in the middle of an array";
347
+
348
+ if (jv_is_valid(p->next)) {
349
+ if (k != JV_KIND_STRING)
350
+ return "Objects must consist of key:value pairs";
351
+ p->output = JV_ARRAY(jv_copy(p->path), p->next, jv_true());
352
+ p->next = jv_invalid();
353
+ } else {
354
+ // Perhaps {"a":[]}
355
+ if (p->last_seen == JV_LAST_COLON)
356
+ // Looks like {"a":}
357
+ return "Missing value in key:value pair";
358
+ if (p->last_seen == JV_LAST_COMMA)
359
+ // Looks like {"a":0,}
360
+ return "Expected another key-value pair";
361
+ if (p->last_seen == JV_LAST_OPEN_ARRAY)
362
+ return "Unmatched '}' in the middle of an array";
363
+ if (p->last_seen != JV_LAST_VALUE && p->last_seen != JV_LAST_OPEN_OBJECT)
364
+ return "Unmatched '}'";
365
+ if (p->last_seen != JV_LAST_OPEN_OBJECT)
366
+ p->output = JV_ARRAY(jv_copy(p->path));
367
+ }
368
+ p->path = jv_array_slice(p->path, 0, --(p->stacklen)); // pop
369
+ jv_free(p->next);
370
+ p->next = jv_invalid();
371
+
372
+ if (p->last_seen == JV_LAST_OPEN_OBJECT)
373
+ p->output = JV_ARRAY(jv_copy(p->path), jv_object()); // Empty arrays are leaves
374
+
375
+ if (p->stacklen == 0)
376
+ p->last_seen = JV_LAST_NONE;
377
+ else
378
+ p->last_seen = JV_LAST_VALUE;
379
+ break;
380
+ }
381
+ return 0;
382
+ }
383
+
384
+ static void tokenadd(struct jv_parser* p, char c) {
385
+ assert(p->tokenpos <= p->tokenlen);
386
+ if (p->tokenpos == p->tokenlen) {
387
+ p->tokenlen = p->tokenlen*2 + 256;
388
+ p->tokenbuf = jv_mem_realloc(p->tokenbuf, p->tokenlen);
389
+ }
390
+ assert(p->tokenpos < p->tokenlen);
391
+ p->tokenbuf[p->tokenpos++] = c;
392
+ }
393
+
394
+ static int unhex4(char* hex) {
395
+ int r = 0;
396
+ for (int i=0; i<4; i++) {
397
+ char c = *hex++;
398
+ int n;
399
+ if ('0' <= c && c <= '9') n = c - '0';
400
+ else if ('a' <= c && c <= 'f') n = c - 'a' + 10;
401
+ else if ('A' <= c && c <= 'F') n = c - 'A' + 10;
402
+ else return -1;
403
+ r <<= 4;
404
+ r |= n;
405
+ }
406
+ return r;
407
+ }
408
+
409
+ static pfunc found_string(struct jv_parser* p) {
410
+ char* in = p->tokenbuf;
411
+ char* out = p->tokenbuf;
412
+ char* end = p->tokenbuf + p->tokenpos;
413
+
414
+ while (in < end) {
415
+ char c = *in++;
416
+ if (c == '\\') {
417
+ if (in >= end)
418
+ return "Expected escape character at end of string";
419
+ c = *in++;
420
+ switch (c) {
421
+ case '\\':
422
+ case '"':
423
+ case '/': *out++ = c; break;
424
+ case 'b': *out++ = '\b'; break;
425
+ case 'f': *out++ = '\f'; break;
426
+ case 't': *out++ = '\t'; break;
427
+ case 'n': *out++ = '\n'; break;
428
+ case 'r': *out++ = '\r'; break;
429
+
430
+ case 'u':
431
+ /* ahh, the complicated case */
432
+ if (in + 4 > end)
433
+ return "Invalid \\uXXXX escape";
434
+ int hexvalue = unhex4(in);
435
+ if (hexvalue < 0)
436
+ return "Invalid characters in \\uXXXX escape";
437
+ unsigned long codepoint = (unsigned long)hexvalue;
438
+ in += 4;
439
+ if (0xD800 <= codepoint && codepoint <= 0xDBFF) {
440
+ /* who thought UTF-16 surrogate pairs were a good idea? */
441
+ if (in + 6 > end || in[0] != '\\' || in[1] != 'u')
442
+ return "Invalid \\uXXXX\\uXXXX surrogate pair escape";
443
+ unsigned long surrogate = unhex4(in+2);
444
+ if (!(0xDC00 <= surrogate && surrogate <= 0xDFFF))
445
+ return "Invalid \\uXXXX\\uXXXX surrogate pair escape";
446
+ in += 6;
447
+ codepoint = 0x10000 + (((codepoint - 0xD800) << 10)
448
+ |(surrogate - 0xDC00));
449
+ }
450
+ if (codepoint > 0x10FFFF)
451
+ codepoint = 0xFFFD; // U+FFFD REPLACEMENT CHARACTER
452
+ out += jvp_utf8_encode(codepoint, out);
453
+ break;
454
+
455
+ default:
456
+ return "Invalid escape";
457
+ }
458
+ } else {
459
+ if (c > 0 && c < 0x001f)
460
+ return "Invalid string: control characters from U+0000 through U+001F must be escaped";
461
+ *out++ = c;
462
+ }
463
+ }
464
+ TRY(value(p, jv_string_sized(p->tokenbuf, out - p->tokenbuf)));
465
+ p->tokenpos = 0;
466
+ return 0;
467
+ }
468
+
469
+ static pfunc check_literal(struct jv_parser* p) {
470
+ if (p->tokenpos == 0) return 0;
471
+
472
+ const char* pattern = 0;
473
+ int plen;
474
+ jv v;
475
+ switch (p->tokenbuf[0]) {
476
+ case 't': pattern = "true"; plen = 4; v = jv_true(); break;
477
+ case 'f': pattern = "false"; plen = 5; v = jv_false(); break;
478
+ case 'n': pattern = "null"; plen = 4; v = jv_null(); break;
479
+ }
480
+ if (pattern) {
481
+ if (p->tokenpos != plen) return "Invalid literal";
482
+ for (int i=0; i<plen; i++)
483
+ if (p->tokenbuf[i] != pattern[i])
484
+ return "Invalid literal";
485
+ TRY(value(p, v));
486
+ } else {
487
+ // FIXME: better parser
488
+ p->tokenbuf[p->tokenpos] = 0; // FIXME: invalid
489
+ char* end = 0;
490
+ double d = jvp_strtod(&p->dtoa, p->tokenbuf, &end);
491
+ if (end == 0 || *end != 0)
492
+ return "Invalid numeric literal";
493
+ TRY(value(p, jv_number(d)));
494
+ }
495
+ p->tokenpos = 0;
496
+ return 0;
497
+ }
498
+
499
+ typedef enum {
500
+ LITERAL,
501
+ WHITESPACE,
502
+ STRUCTURE,
503
+ QUOTE,
504
+ INVALID
505
+ } chclass;
506
+
507
+ static chclass classify(char c) {
508
+ switch (c) {
509
+ case ' ':
510
+ case '\t':
511
+ case '\r':
512
+ case '\n':
513
+ return WHITESPACE;
514
+ case '"':
515
+ return QUOTE;
516
+ case '[':
517
+ case ',':
518
+ case ']':
519
+ case '{':
520
+ case ':':
521
+ case '}':
522
+ return STRUCTURE;
523
+ default:
524
+ return LITERAL;
525
+ }
526
+ }
527
+
528
+
529
+ static const presult OK = "output produced";
530
+
531
+ static int parse_check_done(struct jv_parser* p, jv* out) {
532
+ if (p->stackpos == 0 && jv_is_valid(p->next)) {
533
+ *out = p->next;
534
+ p->next = jv_invalid();
535
+ return 1;
536
+ } else {
537
+ return 0;
538
+ }
539
+ }
540
+
541
+ static int stream_check_done(struct jv_parser* p, jv* out) {
542
+ if (p->stacklen == 0 && jv_is_valid(p->next)) {
543
+ *out = JV_ARRAY(jv_copy(p->path),p->next);
544
+ p->next = jv_invalid();
545
+ return 1;
546
+ } else if (jv_is_valid(p->output)) {
547
+ if (jv_array_length(jv_copy(p->output)) > 2) {
548
+ // At end of an array or object, necessitating one more output by
549
+ // which to indicate this
550
+ *out = jv_array_slice(jv_copy(p->output), 0, 2);
551
+ p->output = jv_array_slice(p->output, 0, 1); // arrange one more output
552
+ } else {
553
+ // No further processing needed
554
+ *out = p->output;
555
+ p->output = jv_invalid();
556
+ }
557
+ return 1;
558
+ } else {
559
+ return 0;
560
+ }
561
+ }
562
+
563
+ static int parse_check_truncation(struct jv_parser* p) {
564
+ return ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && (p->stackpos > 0 || p->tokenpos > 0 || jv_get_kind(p->next) == JV_KIND_NUMBER));
565
+ }
566
+
567
+ static int stream_check_truncation(struct jv_parser* p) {
568
+ jv_kind k = jv_get_kind(p->next);
569
+ return (p->stacklen > 0 || k == JV_KIND_NUMBER || k == JV_KIND_TRUE || k == JV_KIND_FALSE || k == JV_KIND_NULL);
570
+ }
571
+
572
+ static int parse_is_top_num(struct jv_parser* p) {
573
+ return (p->stackpos == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER);
574
+ }
575
+
576
+ static int stream_is_top_num(struct jv_parser* p) {
577
+ return (p->stacklen == 0 && jv_get_kind(p->next) == JV_KIND_NUMBER);
578
+ }
579
+
580
+ #define check_done(p, o) \
581
+ (((p)->flags & JV_PARSE_STREAMING) ? stream_check_done((p), (o)) : parse_check_done((p), (o)))
582
+
583
+ #define token(p, ch) \
584
+ (((p)->flags & JV_PARSE_STREAMING) ? stream_token((p), (ch)) : parse_token((p), (ch)))
585
+
586
+ #define check_truncation(p) \
587
+ (((p)->flags & JV_PARSE_STREAMING) ? stream_check_truncation((p)) : parse_check_truncation((p)))
588
+
589
+ #define is_top_num(p) \
590
+ (((p)->flags & JV_PARSE_STREAMING) ? stream_is_top_num((p)) : parse_is_top_num((p)))
591
+
592
+ static pfunc scan(struct jv_parser* p, char ch, jv* out) {
593
+ p->column++;
594
+ if (ch == '\n') {
595
+ p->line++;
596
+ p->column = 0;
597
+ }
598
+ if (ch == '\036' /* ASCII RS; see draft-ietf-json-sequence-07 */) {
599
+ if (check_truncation(p)) {
600
+ if (check_literal(p) == 0 && is_top_num(p))
601
+ return "Potentially truncated top-level numeric value";
602
+ return "Truncated value";
603
+ }
604
+ TRY(check_literal(p));
605
+ if (p->st == JV_PARSER_NORMAL && check_done(p, out))
606
+ return OK;
607
+ // shouldn't happen?
608
+ assert(!jv_is_valid(*out));
609
+ parser_reset(p);
610
+ jv_free(*out);
611
+ *out = jv_invalid();
612
+ return OK;
613
+ }
614
+ presult answer = 0;
615
+ p->last_ch_was_ws = 0;
616
+ if (p->st == JV_PARSER_NORMAL) {
617
+ chclass cls = classify(ch);
618
+ if (cls == WHITESPACE)
619
+ p->last_ch_was_ws = 1;
620
+ if (cls != LITERAL) {
621
+ TRY(check_literal(p));
622
+ if (check_done(p, out)) answer = OK;
623
+ }
624
+ switch (cls) {
625
+ case LITERAL:
626
+ tokenadd(p, ch);
627
+ break;
628
+ case WHITESPACE:
629
+ break;
630
+ case QUOTE:
631
+ p->st = JV_PARSER_STRING;
632
+ break;
633
+ case STRUCTURE:
634
+ TRY(token(p, ch));
635
+ break;
636
+ case INVALID:
637
+ return "Invalid character";
638
+ }
639
+ if (check_done(p, out)) answer = OK;
640
+ } else {
641
+ if (ch == '"' && p->st == JV_PARSER_STRING) {
642
+ TRY(found_string(p));
643
+ p->st = JV_PARSER_NORMAL;
644
+ if (check_done(p, out)) answer = OK;
645
+ } else {
646
+ tokenadd(p, ch);
647
+ if (ch == '\\' && p->st == JV_PARSER_STRING) {
648
+ p->st = JV_PARSER_STRING_ESCAPE;
649
+ } else {
650
+ p->st = JV_PARSER_STRING;
651
+ }
652
+ }
653
+ }
654
+ return answer;
655
+ }
656
+
657
+ struct jv_parser* jv_parser_new(int flags) {
658
+ struct jv_parser* p = jv_mem_alloc(sizeof(struct jv_parser));
659
+ parser_init(p, flags);
660
+ p->flags = flags;
661
+ return p;
662
+ }
663
+
664
+ void jv_parser_free(struct jv_parser* p) {
665
+ parser_free(p);
666
+ jv_mem_free(p);
667
+ }
668
+
669
+ static const unsigned char UTF8_BOM[] = {0xEF,0xBB,0xBF};
670
+
671
+ int jv_parser_remaining(struct jv_parser* p) {
672
+ if (p->curr_buf == 0)
673
+ return 0;
674
+ return (p->curr_buf_length - p->curr_buf_pos);
675
+ }
676
+
677
+ void jv_parser_set_buf(struct jv_parser* p, const char* buf, int length, int is_partial) {
678
+ assert((p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length)
679
+ && "previous buffer not exhausted");
680
+ while (length > 0 && p->bom_strip_position < sizeof(UTF8_BOM)) {
681
+ if ((unsigned char)*buf == UTF8_BOM[p->bom_strip_position]) {
682
+ // matched a BOM character
683
+ buf++;
684
+ length--;
685
+ p->bom_strip_position++;
686
+ } else {
687
+ if (p->bom_strip_position == 0) {
688
+ // no BOM in this document
689
+ p->bom_strip_position = sizeof(UTF8_BOM);
690
+ } else {
691
+ // malformed BOM (prefix present, rest missing)
692
+ p->bom_strip_position = 0xff;
693
+ }
694
+ }
695
+ }
696
+ p->curr_buf = buf;
697
+ p->curr_buf_length = length;
698
+ p->curr_buf_pos = 0;
699
+ p->curr_buf_is_partial = is_partial;
700
+ }
701
+
702
+ static jv make_error(struct jv_parser*, const char *, ...) JV_PRINTF_LIKE(2, 3);
703
+
704
+ static jv make_error(struct jv_parser* p, const char *fmt, ...) {
705
+ va_list ap;
706
+ va_start(ap, fmt);
707
+ jv e = jv_string_vfmt(fmt, ap);
708
+ va_end(ap);
709
+ if ((p->flags & JV_PARSE_STREAM_ERRORS))
710
+ return JV_ARRAY(e, jv_copy(p->path));
711
+ return jv_invalid_with_msg(e);
712
+ }
713
+
714
+ jv jv_parser_next(struct jv_parser* p) {
715
+ if (p->eof)
716
+ return jv_invalid();
717
+ if (!p->curr_buf)
718
+ return jv_invalid(); // Need a buffer
719
+ if (p->bom_strip_position == 0xff) {
720
+ if (!(p->flags & JV_PARSE_SEQ))
721
+ return jv_invalid_with_msg(jv_string("Malformed BOM"));
722
+ p->st =JV_PARSER_WAITING_FOR_RS;
723
+ parser_reset(p);
724
+ }
725
+ jv value = jv_invalid();
726
+ if ((p->flags & JV_PARSE_STREAMING) && stream_check_done(p, &value))
727
+ return value;
728
+ char ch;
729
+ presult msg = 0;
730
+ while (!msg && p->curr_buf_pos < p->curr_buf_length) {
731
+ ch = p->curr_buf[p->curr_buf_pos++];
732
+ if (p->st == JV_PARSER_WAITING_FOR_RS) {
733
+ if (ch == '\n') {
734
+ p->line++;
735
+ p->column = 0;
736
+ } else {
737
+ p->column++;
738
+ }
739
+ if (ch == '\036')
740
+ p->st = JV_PARSER_NORMAL;
741
+ continue; // need to resync, wait for RS
742
+ }
743
+ msg = scan(p, ch, &value);
744
+ }
745
+ if (msg == OK) {
746
+ return value;
747
+ } else if (msg) {
748
+ jv_free(value);
749
+ if (ch != '\036' && (p->flags & JV_PARSE_SEQ)) {
750
+ // Skip to the next RS
751
+ p->st = JV_PARSER_WAITING_FOR_RS;
752
+ value = make_error(p, "%s at line %d, column %d (need RS to resync)", msg, p->line, p->column);
753
+ parser_reset(p);
754
+ return value;
755
+ }
756
+ value = make_error(p, "%s at line %d, column %d", msg, p->line, p->column);
757
+ parser_reset(p);
758
+ if (!(p->flags & JV_PARSE_SEQ)) {
759
+ // We're not parsing a JSON text sequence; throw this buffer away.
760
+ // XXX We should fail permanently here.
761
+ p->curr_buf = 0;
762
+ p->curr_buf_pos = 0;
763
+ } // Else ch must be RS; don't clear buf so we can start parsing again after this ch
764
+ return value;
765
+ } else if (p->curr_buf_is_partial) {
766
+ assert(p->curr_buf_pos == p->curr_buf_length);
767
+ // need another buffer
768
+ return jv_invalid();
769
+ } else {
770
+ // at EOF
771
+ p->eof = 1;
772
+ assert(p->curr_buf_pos == p->curr_buf_length);
773
+ jv_free(value);
774
+ if (p->st == JV_PARSER_WAITING_FOR_RS)
775
+ return make_error(p, "Unfinished abandoned text at EOF at line %d, column %d", p->line, p->column);
776
+ if (p->st != JV_PARSER_NORMAL) {
777
+ value = make_error(p, "Unfinished string at EOF at line %d, column %d", p->line, p->column);
778
+ parser_reset(p);
779
+ p->st = JV_PARSER_WAITING_FOR_RS;
780
+ return value;
781
+ }
782
+ if ((msg = check_literal(p))) {
783
+ value = make_error(p, "%s at EOF at line %d, column %d", msg, p->line, p->column);
784
+ parser_reset(p);
785
+ p->st = JV_PARSER_WAITING_FOR_RS;
786
+ return value;
787
+ }
788
+ if (((p->flags & JV_PARSE_STREAMING) && p->stacklen != 0) ||
789
+ (!(p->flags & JV_PARSE_STREAMING) && p->stackpos != 0)) {
790
+ value = make_error(p, "Unfinished JSON term at EOF at line %d, column %d", p->line, p->column);
791
+ parser_reset(p);
792
+ p->st = JV_PARSER_WAITING_FOR_RS;
793
+ return value;
794
+ }
795
+ // p->next is either invalid (nothing here, but no syntax error)
796
+ // or valid (this is the value). either way it's the thing to return
797
+ if ((p->flags & JV_PARSE_STREAMING) && jv_is_valid(p->next)) {
798
+ value = JV_ARRAY(jv_copy(p->path), p->next); // except in streaming mode we've got to make it [path,value]
799
+ } else {
800
+ value = p->next;
801
+ }
802
+ p->next = jv_invalid();
803
+ if ((p->flags & JV_PARSE_SEQ) && !p->last_ch_was_ws && jv_get_kind(value) == JV_KIND_NUMBER) {
804
+ jv_free(value);
805
+ return make_error(p, "Potentially truncated top-level numeric value at EOF at line %d, column %d", p->line, p->column);
806
+ }
807
+ return value;
808
+ }
809
+ }
810
+
811
+ jv jv_parse_sized(const char* string, int length) {
812
+ struct jv_parser parser;
813
+ parser_init(&parser, 0);
814
+ jv_parser_set_buf(&parser, string, length, 0);
815
+ jv value = jv_parser_next(&parser);
816
+ if (jv_is_valid(value)) {
817
+ jv next = jv_parser_next(&parser);
818
+ if (jv_is_valid(next)) {
819
+ // multiple JSON values, we only wanted one
820
+ jv_free(value);
821
+ jv_free(next);
822
+ value = jv_invalid_with_msg(jv_string("Unexpected extra JSON values"));
823
+ } else if (jv_invalid_has_msg(jv_copy(next))) {
824
+ // parser error after the first JSON value
825
+ jv_free(value);
826
+ value = next;
827
+ } else {
828
+ // a single valid JSON value
829
+ jv_free(next);
830
+ }
831
+ } else if (jv_invalid_has_msg(jv_copy(value))) {
832
+ // parse error, we'll return it
833
+ } else {
834
+ // no value at all
835
+ jv_free(value);
836
+ value = jv_invalid_with_msg(jv_string("Expected JSON value"));
837
+ }
838
+ parser_free(&parser);
839
+
840
+ if (!jv_is_valid(value) && jv_invalid_has_msg(jv_copy(value))) {
841
+ jv msg = jv_invalid_get_msg(value);
842
+ value = jv_invalid_with_msg(jv_string_fmt("%s (while parsing '%s')",
843
+ jv_string_value(msg),
844
+ string));
845
+ jv_free(msg);
846
+ }
847
+ return value;
848
+ }
849
+
850
+ jv jv_parse(const char* string) {
851
+ return jv_parse_sized(string, strlen(string));
852
+ }