@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,1155 @@
1
+ #include <assert.h>
2
+ #include <errno.h>
3
+ #include <stdarg.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <stdint.h>
7
+ #include <sys/stat.h>
8
+
9
+ #include "exec_stack.h"
10
+ #include "bytecode.h"
11
+
12
+ #include "jv_alloc.h"
13
+ #include "jq_parser.h"
14
+ #include "locfile.h"
15
+ #include "jv.h"
16
+ #include "jq.h"
17
+ #include "parser.h"
18
+ #include "builtin.h"
19
+ #include "util.h"
20
+ #include "linker.h"
21
+
22
+ struct jq_state {
23
+ void (*nomem_handler)(void *);
24
+ void *nomem_handler_data;
25
+ struct bytecode* bc;
26
+
27
+ jq_msg_cb err_cb;
28
+ void *err_cb_data;
29
+ jv error;
30
+
31
+ struct stack stk;
32
+ stack_ptr curr_frame;
33
+ stack_ptr stk_top;
34
+ stack_ptr fork_top;
35
+
36
+ jv path;
37
+ jv value_at_path;
38
+ int subexp_nest;
39
+ int debug_trace_enabled;
40
+ int initial_execution;
41
+ unsigned next_label;
42
+
43
+ jv attrs;
44
+ jq_input_cb input_cb;
45
+ void *input_cb_data;
46
+ jq_msg_cb debug_cb;
47
+ void *debug_cb_data;
48
+ };
49
+
50
+ struct closure {
51
+ struct bytecode* bc; // jq bytecode
52
+ stack_ptr env; // jq stack address of closed frame
53
+ };
54
+
55
+ // locals for any function called: either a closure or a local variable
56
+ union frame_entry {
57
+ struct closure closure;
58
+ jv localvar;
59
+ };
60
+
61
+ // jq function call frame
62
+ struct frame {
63
+ struct bytecode* bc; // jq bytecode for callee
64
+ stack_ptr env; // jq stack address of frame to return to
65
+ stack_ptr retdata; // jq stack address to unwind to on RET
66
+ uint16_t* retaddr; // jq bytecode return address
67
+ union frame_entry entries[0]; // nclosures + nlocals
68
+ };
69
+
70
+ static int frame_size(struct bytecode* bc) {
71
+ return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc->nlocals);
72
+ }
73
+
74
+ static struct frame* frame_current(struct jq_state* jq) {
75
+ struct frame* fp = stack_block(&jq->stk, jq->curr_frame);
76
+
77
+ stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame);
78
+ if (next) {
79
+ struct frame* fpnext = stack_block(&jq->stk, next);
80
+ struct bytecode* bc = fpnext->bc;
81
+ assert(fp->retaddr >= bc->code && fp->retaddr < bc->code + bc->codelen);
82
+ } else {
83
+ assert(fp->retaddr == 0);
84
+ }
85
+ return fp;
86
+ }
87
+
88
+ static stack_ptr frame_get_level(struct jq_state* jq, int level) {
89
+ stack_ptr fr = jq->curr_frame;
90
+ for (int i=0; i<level; i++) {
91
+ struct frame* fp = stack_block(&jq->stk, fr);
92
+ fr = fp->env;
93
+ }
94
+ return fr;
95
+ }
96
+
97
+ static jv* frame_local_var(struct jq_state* jq, int var, int level) {
98
+ struct frame* fr = stack_block(&jq->stk, frame_get_level(jq, level));
99
+ assert(var >= 0);
100
+ assert(var < fr->bc->nlocals);
101
+ return &fr->entries[fr->bc->nclosures + var].localvar;
102
+ }
103
+
104
+ static struct closure make_closure(struct jq_state* jq, uint16_t* pc) {
105
+ uint16_t level = *pc++;
106
+ uint16_t idx = *pc++;
107
+ stack_ptr fridx = frame_get_level(jq, level);
108
+ struct frame* fr = stack_block(&jq->stk, fridx);
109
+ if (idx & ARG_NEWCLOSURE) {
110
+ // A new closure closing the frame identified by level, and with
111
+ // the bytecode body of the idx'th subfunction of that frame
112
+ int subfn_idx = idx & ~ARG_NEWCLOSURE;
113
+ assert(subfn_idx < fr->bc->nsubfunctions);
114
+ struct closure cl = {fr->bc->subfunctions[subfn_idx],
115
+ fridx};
116
+ return cl;
117
+ } else {
118
+ // A reference to a closure from the frame identified by level; copy
119
+ // it as-is
120
+ int closure = idx;
121
+ assert(closure >= 0);
122
+ assert(closure < fr->bc->nclosures);
123
+ return fr->entries[closure].closure;
124
+ }
125
+ }
126
+
127
+ static struct frame* frame_push(struct jq_state* jq, struct closure callee,
128
+ uint16_t* argdef, int nargs) {
129
+ stack_ptr new_frame_idx = stack_push_block(&jq->stk, jq->curr_frame, frame_size(callee.bc));
130
+ struct frame* new_frame = stack_block(&jq->stk, new_frame_idx);
131
+ new_frame->bc = callee.bc;
132
+ new_frame->env = callee.env;
133
+ assert(nargs == new_frame->bc->nclosures);
134
+ union frame_entry* entries = new_frame->entries;
135
+ for (int i=0; i<nargs; i++) {
136
+ entries->closure = make_closure(jq, argdef + i * 2);
137
+ entries++;
138
+ }
139
+ for (int i=0; i<callee.bc->nlocals; i++) {
140
+ entries->localvar = jv_invalid();
141
+ entries++;
142
+ }
143
+ jq->curr_frame = new_frame_idx;
144
+ return new_frame;
145
+ }
146
+
147
+ static void frame_pop(struct jq_state* jq) {
148
+ assert(jq->curr_frame);
149
+ struct frame* fp = frame_current(jq);
150
+ if (stack_pop_will_free(&jq->stk, jq->curr_frame)) {
151
+ int nlocals = fp->bc->nlocals;
152
+ for (int i=0; i<nlocals; i++) {
153
+ jv_free(*frame_local_var(jq, i, 0));
154
+ }
155
+ }
156
+ jq->curr_frame = stack_pop_block(&jq->stk, jq->curr_frame, frame_size(fp->bc));
157
+ }
158
+
159
+ void stack_push(jq_state *jq, jv val) {
160
+ assert(jv_is_valid(val));
161
+ jq->stk_top = stack_push_block(&jq->stk, jq->stk_top, sizeof(jv));
162
+ jv* sval = stack_block(&jq->stk, jq->stk_top);
163
+ *sval = val;
164
+ }
165
+
166
+ jv stack_pop(jq_state *jq) {
167
+ jv* sval = stack_block(&jq->stk, jq->stk_top);
168
+ jv val = *sval;
169
+ if (!stack_pop_will_free(&jq->stk, jq->stk_top)) {
170
+ val = jv_copy(val);
171
+ }
172
+ jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv));
173
+ assert(jv_is_valid(val));
174
+ return val;
175
+ }
176
+
177
+ // Like stack_pop(), but assert !stack_pop_will_free() and replace with
178
+ // jv_null() on the stack.
179
+ jv stack_popn(jq_state *jq) {
180
+ jv* sval = stack_block(&jq->stk, jq->stk_top);
181
+ jv val = *sval;
182
+ if (!stack_pop_will_free(&jq->stk, jq->stk_top)) {
183
+ *sval = jv_null();
184
+ }
185
+ jq->stk_top = stack_pop_block(&jq->stk, jq->stk_top, sizeof(jv));
186
+ assert(jv_is_valid(val));
187
+ return val;
188
+ }
189
+
190
+
191
+ struct forkpoint {
192
+ stack_ptr saved_data_stack;
193
+ stack_ptr saved_curr_frame;
194
+ int path_len, subexp_nest;
195
+ jv value_at_path;
196
+ uint16_t* return_address;
197
+ };
198
+
199
+ struct stack_pos {
200
+ stack_ptr saved_data_stack, saved_curr_frame;
201
+ };
202
+
203
+ struct stack_pos stack_get_pos(jq_state* jq) {
204
+ struct stack_pos sp = {jq->stk_top, jq->curr_frame};
205
+ return sp;
206
+ }
207
+
208
+ void stack_save(jq_state *jq, uint16_t* retaddr, struct stack_pos sp){
209
+ jq->fork_top = stack_push_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint));
210
+ struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top);
211
+ fork->saved_data_stack = jq->stk_top;
212
+ fork->saved_curr_frame = jq->curr_frame;
213
+ fork->path_len =
214
+ jv_get_kind(jq->path) == JV_KIND_ARRAY ? jv_array_length(jv_copy(jq->path)) : 0;
215
+ fork->value_at_path = jv_copy(jq->value_at_path);
216
+ fork->subexp_nest = jq->subexp_nest;
217
+ fork->return_address = retaddr;
218
+ jq->stk_top = sp.saved_data_stack;
219
+ jq->curr_frame = sp.saved_curr_frame;
220
+ }
221
+
222
+ static int path_intact(jq_state *jq, jv curr) {
223
+ if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) {
224
+ return jv_identical(curr, jv_copy(jq->value_at_path));
225
+ } else {
226
+ jv_free(curr);
227
+ return 1;
228
+ }
229
+ }
230
+
231
+ static void path_append(jq_state* jq, jv component, jv value_at_path) {
232
+ if (jq->subexp_nest == 0 && jv_get_kind(jq->path) == JV_KIND_ARRAY) {
233
+ int n1 = jv_array_length(jv_copy(jq->path));
234
+ jq->path = jv_array_append(jq->path, component);
235
+ int n2 = jv_array_length(jv_copy(jq->path));
236
+ assert(n2 == n1 + 1);
237
+ jv_free(jq->value_at_path);
238
+ jq->value_at_path = value_at_path;
239
+ } else {
240
+ jv_free(component);
241
+ jv_free(value_at_path);
242
+ }
243
+ }
244
+
245
+ uint16_t* stack_restore(jq_state *jq){
246
+ while (!stack_pop_will_free(&jq->stk, jq->fork_top)) {
247
+ if (stack_pop_will_free(&jq->stk, jq->stk_top)) {
248
+ jv_free(stack_pop(jq));
249
+ } else if (stack_pop_will_free(&jq->stk, jq->curr_frame)) {
250
+ frame_pop(jq);
251
+ } else {
252
+ assert(0);
253
+ }
254
+ }
255
+
256
+ if (jq->fork_top == 0) {
257
+ return 0;
258
+ }
259
+
260
+ struct forkpoint* fork = stack_block(&jq->stk, jq->fork_top);
261
+ uint16_t* retaddr = fork->return_address;
262
+ jq->stk_top = fork->saved_data_stack;
263
+ jq->curr_frame = fork->saved_curr_frame;
264
+ int path_len = fork->path_len;
265
+ if (jv_get_kind(jq->path) == JV_KIND_ARRAY) {
266
+ assert(path_len >= 0);
267
+ jq->path = jv_array_slice(jq->path, 0, path_len);
268
+ } else {
269
+ assert(path_len == 0);
270
+ }
271
+ jv_free(jq->value_at_path);
272
+ jq->value_at_path = fork->value_at_path;
273
+ jq->subexp_nest = fork->subexp_nest;
274
+ jq->fork_top = stack_pop_block(&jq->stk, jq->fork_top, sizeof(struct forkpoint));
275
+ return retaddr;
276
+ }
277
+
278
+ static void jq_reset(jq_state *jq) {
279
+ while (stack_restore(jq)) {}
280
+
281
+ assert(jq->stk_top == 0);
282
+ assert(jq->fork_top == 0);
283
+ assert(jq->curr_frame == 0);
284
+ stack_reset(&jq->stk);
285
+ jv_free(jq->error);
286
+ jq->error = jv_null();
287
+
288
+ if (jv_get_kind(jq->path) != JV_KIND_INVALID)
289
+ jv_free(jq->path);
290
+ jq->path = jv_null();
291
+ jv_free(jq->value_at_path);
292
+ jq->value_at_path = jv_null();
293
+ jq->subexp_nest = 0;
294
+ }
295
+
296
+ void jq_report_error(jq_state *jq, jv value) {
297
+ assert(jq->err_cb);
298
+ // callback must jv_free() its jv argument
299
+ jq->err_cb(jq->err_cb_data, value);
300
+ }
301
+
302
+ static void set_error(jq_state *jq, jv value) {
303
+ // Record so try/catch can find it.
304
+ jv_free(jq->error);
305
+ jq->error = value;
306
+ }
307
+
308
+ #define ON_BACKTRACK(op) ((op)+NUM_OPCODES)
309
+
310
+ jv jq_next(jq_state *jq) {
311
+ jv cfunc_input[MAX_CFUNCTION_ARGS];
312
+
313
+ jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
314
+
315
+ uint16_t* pc = stack_restore(jq);
316
+ assert(pc);
317
+
318
+ int raising;
319
+ int backtracking = !jq->initial_execution;
320
+ jq->initial_execution = 0;
321
+ assert(jv_get_kind(jq->error) == JV_KIND_NULL);
322
+ while (1) {
323
+ uint16_t opcode = *pc;
324
+ raising = 0;
325
+
326
+ if (jq->debug_trace_enabled) {
327
+ dump_operation(frame_current(jq)->bc, pc);
328
+ printf("\t");
329
+ const struct opcode_description* opdesc = opcode_describe(opcode);
330
+ stack_ptr param = 0;
331
+ if (!backtracking) {
332
+ int stack_in = opdesc->stack_in;
333
+ if (stack_in == -1) stack_in = pc[1];
334
+ for (int i=0; i<stack_in; i++) {
335
+ if (i == 0) {
336
+ param = jq->stk_top;
337
+ } else {
338
+ printf(" | ");
339
+ param = *stack_block_next(&jq->stk, param);
340
+ }
341
+ if (!param) break;
342
+ jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT);
343
+ //printf("<%d>", jv_get_refcnt(param->val));
344
+ //printf(" -- ");
345
+ //jv_dump(jv_copy(jq->path), 0);
346
+ }
347
+ } else {
348
+ printf("\t<backtracking>");
349
+ }
350
+
351
+ printf("\n");
352
+ }
353
+
354
+ if (backtracking) {
355
+ opcode = ON_BACKTRACK(opcode);
356
+ backtracking = 0;
357
+ raising = !jv_is_valid(jq->error);
358
+ }
359
+ pc++;
360
+
361
+ switch (opcode) {
362
+ default: assert(0 && "invalid instruction");
363
+
364
+ case TOP: break;
365
+
366
+ case LOADK: {
367
+ jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++);
368
+ assert(jv_is_valid(v));
369
+ jv_free(stack_pop(jq));
370
+ stack_push(jq, v);
371
+ break;
372
+ }
373
+
374
+ case GENLABEL: {
375
+ stack_push(jq, JV_OBJECT(jv_string("__jq"), jv_number(jq->next_label++)));
376
+ break;
377
+ }
378
+
379
+ case DUP: {
380
+ jv v = stack_pop(jq);
381
+ stack_push(jq, jv_copy(v));
382
+ stack_push(jq, v);
383
+ break;
384
+ }
385
+
386
+ case DUPN: {
387
+ jv v = stack_popn(jq);
388
+ stack_push(jq, jv_copy(v));
389
+ stack_push(jq, v);
390
+ break;
391
+ }
392
+
393
+ case DUP2: {
394
+ jv keep = stack_pop(jq);
395
+ jv v = stack_pop(jq);
396
+ stack_push(jq, jv_copy(v));
397
+ stack_push(jq, keep);
398
+ stack_push(jq, v);
399
+ break;
400
+ }
401
+
402
+ case SUBEXP_BEGIN: {
403
+ jv v = stack_pop(jq);
404
+ stack_push(jq, jv_copy(v));
405
+ stack_push(jq, v);
406
+ jq->subexp_nest++;
407
+ break;
408
+ }
409
+
410
+ case SUBEXP_END: {
411
+ assert(jq->subexp_nest > 0);
412
+ jq->subexp_nest--;
413
+ jv a = stack_pop(jq);
414
+ jv b = stack_pop(jq);
415
+ stack_push(jq, a);
416
+ stack_push(jq, b);
417
+ break;
418
+ }
419
+
420
+ case POP: {
421
+ jv_free(stack_pop(jq));
422
+ break;
423
+ }
424
+
425
+ case APPEND: {
426
+ jv v = stack_pop(jq);
427
+ uint16_t level = *pc++;
428
+ uint16_t vidx = *pc++;
429
+ jv* var = frame_local_var(jq, vidx, level);
430
+ assert(jv_get_kind(*var) == JV_KIND_ARRAY);
431
+ *var = jv_array_append(*var, v);
432
+ break;
433
+ }
434
+
435
+ case INSERT: {
436
+ jv stktop = stack_pop(jq);
437
+ jv v = stack_pop(jq);
438
+ jv k = stack_pop(jq);
439
+ jv objv = stack_pop(jq);
440
+ assert(jv_get_kind(objv) == JV_KIND_OBJECT);
441
+ if (jv_get_kind(k) == JV_KIND_STRING) {
442
+ stack_push(jq, jv_object_set(objv, k, v));
443
+ stack_push(jq, stktop);
444
+ } else {
445
+ char errbuf[15];
446
+ set_error(jq, jv_invalid_with_msg(jv_string_fmt("Cannot use %s (%s) as object key",
447
+ jv_kind_name(jv_get_kind(k)),
448
+ jv_dump_string_trunc(jv_copy(k), errbuf, sizeof(errbuf)))));
449
+ jv_free(stktop);
450
+ jv_free(v);
451
+ jv_free(k);
452
+ jv_free(objv);
453
+ goto do_backtrack;
454
+ }
455
+ break;
456
+ }
457
+
458
+ case ON_BACKTRACK(RANGE):
459
+ case RANGE: {
460
+ uint16_t level = *pc++;
461
+ uint16_t v = *pc++;
462
+ jv* var = frame_local_var(jq, v, level);
463
+ jv max = stack_pop(jq);
464
+ if (raising) goto do_backtrack;
465
+ if (jv_get_kind(*var) != JV_KIND_NUMBER ||
466
+ jv_get_kind(max) != JV_KIND_NUMBER) {
467
+ set_error(jq, jv_invalid_with_msg(jv_string_fmt("Range bounds must be numeric")));
468
+ jv_free(max);
469
+ goto do_backtrack;
470
+ } else if (jv_number_value(jv_copy(*var)) >= jv_number_value(jv_copy(max))) {
471
+ /* finished iterating */
472
+ goto do_backtrack;
473
+ } else {
474
+ jv curr = jv_copy(*var);
475
+ *var = jv_number(jv_number_value(*var) + 1);
476
+
477
+ struct stack_pos spos = stack_get_pos(jq);
478
+ stack_push(jq, jv_copy(max));
479
+ stack_save(jq, pc - 3, spos);
480
+
481
+ stack_push(jq, curr);
482
+ }
483
+ break;
484
+ }
485
+
486
+ // FIXME: loadv/storev may do too much copying/freeing
487
+ case LOADV: {
488
+ uint16_t level = *pc++;
489
+ uint16_t v = *pc++;
490
+ jv* var = frame_local_var(jq, v, level);
491
+ if (jq->debug_trace_enabled) {
492
+ printf("V%d = ", v);
493
+ jv_dump(jv_copy(*var), 0);
494
+ printf(" (%d)\n", jv_get_refcnt(*var));
495
+ }
496
+ jv_free(stack_pop(jq));
497
+ stack_push(jq, jv_copy(*var));
498
+ break;
499
+ }
500
+
501
+ // Does a load but replaces the variable with null
502
+ case LOADVN: {
503
+ uint16_t level = *pc++;
504
+ uint16_t v = *pc++;
505
+ jv* var = frame_local_var(jq, v, level);
506
+ if (jq->debug_trace_enabled) {
507
+ printf("V%d = ", v);
508
+ jv_dump(jv_copy(*var), 0);
509
+ printf(" (%d)\n", jv_get_refcnt(*var));
510
+ }
511
+ jv_free(stack_popn(jq));
512
+ stack_push(jq, *var);
513
+ *var = jv_null();
514
+ break;
515
+ }
516
+
517
+ case STOREV: {
518
+ uint16_t level = *pc++;
519
+ uint16_t v = *pc++;
520
+ jv* var = frame_local_var(jq, v, level);
521
+ jv val = stack_pop(jq);
522
+ if (jq->debug_trace_enabled) {
523
+ printf("V%d = ", v);
524
+ jv_dump(jv_copy(val), 0);
525
+ printf(" (%d)\n", jv_get_refcnt(val));
526
+ }
527
+ jv_free(*var);
528
+ *var = val;
529
+ break;
530
+ }
531
+
532
+ case STORE_GLOBAL: {
533
+ // Get the constant
534
+ jv val = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++);
535
+ assert(jv_is_valid(val));
536
+
537
+ // Store the var
538
+ uint16_t level = *pc++;
539
+ uint16_t v = *pc++;
540
+ jv* var = frame_local_var(jq, v, level);
541
+ if (jq->debug_trace_enabled) {
542
+ printf("V%d = ", v);
543
+ jv_dump(jv_copy(val), 0);
544
+ printf(" (%d)\n", jv_get_refcnt(val));
545
+ }
546
+ jv_free(*var);
547
+ *var = val;
548
+ break;
549
+ }
550
+
551
+ case PATH_BEGIN: {
552
+ jv v = stack_pop(jq);
553
+ stack_push(jq, jq->path);
554
+
555
+ stack_save(jq, pc - 1, stack_get_pos(jq));
556
+
557
+ stack_push(jq, jv_number(jq->subexp_nest));
558
+ stack_push(jq, jq->value_at_path);
559
+ stack_push(jq, jv_copy(v));
560
+
561
+ jq->path = jv_array();
562
+ jq->value_at_path = v; // next INDEX operation must index into v
563
+ jq->subexp_nest = 0;
564
+ break;
565
+ }
566
+
567
+ case PATH_END: {
568
+ jv v = stack_pop(jq);
569
+ // detect invalid path expression like path(.a | reverse)
570
+ if (!path_intact(jq, jv_copy(v))) {
571
+ char errbuf[30];
572
+ jv msg = jv_string_fmt(
573
+ "Invalid path expression with result %s",
574
+ jv_dump_string_trunc(v, errbuf, sizeof(errbuf)));
575
+ set_error(jq, jv_invalid_with_msg(msg));
576
+ goto do_backtrack;
577
+ }
578
+ jv_free(v); // discard value, only keep path
579
+
580
+ jv old_value_at_path = stack_pop(jq);
581
+ int old_subexp_nest = (int)jv_number_value(stack_pop(jq));
582
+
583
+ jv path = jq->path;
584
+ jq->path = stack_pop(jq);
585
+
586
+ struct stack_pos spos = stack_get_pos(jq);
587
+ stack_push(jq, jv_copy(path));
588
+ stack_save(jq, pc - 1, spos);
589
+
590
+ stack_push(jq, path);
591
+ jq->subexp_nest = old_subexp_nest;
592
+ jv_free(jq->value_at_path);
593
+ jq->value_at_path = old_value_at_path;
594
+ break;
595
+ }
596
+
597
+ case ON_BACKTRACK(PATH_BEGIN):
598
+ case ON_BACKTRACK(PATH_END): {
599
+ jv_free(jq->path);
600
+ jq->path = stack_pop(jq);
601
+ goto do_backtrack;
602
+ }
603
+
604
+ case INDEX:
605
+ case INDEX_OPT: {
606
+ jv t = stack_pop(jq);
607
+ jv k = stack_pop(jq);
608
+ // detect invalid path expression like path(reverse | .a)
609
+ if (!path_intact(jq, jv_copy(t))) {
610
+ char keybuf[15];
611
+ char objbuf[30];
612
+ jv msg = jv_string_fmt(
613
+ "Invalid path expression near attempt to access element %s of %s",
614
+ jv_dump_string_trunc(k, keybuf, sizeof(keybuf)),
615
+ jv_dump_string_trunc(t, objbuf, sizeof(objbuf)));
616
+ set_error(jq, jv_invalid_with_msg(msg));
617
+ goto do_backtrack;
618
+ }
619
+ jv v = jv_get(t, jv_copy(k));
620
+ if (jv_is_valid(v)) {
621
+ path_append(jq, k, jv_copy(v));
622
+ stack_push(jq, v);
623
+ } else {
624
+ jv_free(k);
625
+ if (opcode == INDEX)
626
+ set_error(jq, v);
627
+ else
628
+ jv_free(v);
629
+ goto do_backtrack;
630
+ }
631
+ break;
632
+ }
633
+
634
+
635
+ case JUMP: {
636
+ uint16_t offset = *pc++;
637
+ pc += offset;
638
+ break;
639
+ }
640
+
641
+ case JUMP_F: {
642
+ uint16_t offset = *pc++;
643
+ jv t = stack_pop(jq);
644
+ jv_kind kind = jv_get_kind(t);
645
+ if (kind == JV_KIND_FALSE || kind == JV_KIND_NULL) {
646
+ pc += offset;
647
+ }
648
+ stack_push(jq, t); // FIXME do this better
649
+ break;
650
+ }
651
+
652
+ case EACH:
653
+ case EACH_OPT: {
654
+ jv container = stack_pop(jq);
655
+ // detect invalid path expression like path(reverse | .[])
656
+ if (!path_intact(jq, jv_copy(container))) {
657
+ char errbuf[30];
658
+ jv msg = jv_string_fmt(
659
+ "Invalid path expression near attempt to iterate through %s",
660
+ jv_dump_string_trunc(container, errbuf, sizeof(errbuf)));
661
+ set_error(jq, jv_invalid_with_msg(msg));
662
+ goto do_backtrack;
663
+ }
664
+ stack_push(jq, container);
665
+ stack_push(jq, jv_number(-1));
666
+ // fallthrough
667
+ }
668
+ case ON_BACKTRACK(EACH):
669
+ case ON_BACKTRACK(EACH_OPT): {
670
+ int idx = jv_number_value(stack_pop(jq));
671
+ jv container = stack_pop(jq);
672
+
673
+ int keep_going, is_last = 0;
674
+ jv key, value;
675
+ if (jv_get_kind(container) == JV_KIND_ARRAY) {
676
+ if (opcode == EACH || opcode == EACH_OPT) idx = 0;
677
+ else idx = idx + 1;
678
+ int len = jv_array_length(jv_copy(container));
679
+ keep_going = idx < len;
680
+ is_last = idx == len - 1;
681
+ if (keep_going) {
682
+ key = jv_number(idx);
683
+ value = jv_array_get(jv_copy(container), idx);
684
+ }
685
+ } else if (jv_get_kind(container) == JV_KIND_OBJECT) {
686
+ if (opcode == EACH || opcode == EACH_OPT) idx = jv_object_iter(container);
687
+ else idx = jv_object_iter_next(container, idx);
688
+ keep_going = jv_object_iter_valid(container, idx);
689
+ if (keep_going) {
690
+ key = jv_object_iter_key(container, idx);
691
+ value = jv_object_iter_value(container, idx);
692
+ }
693
+ } else {
694
+ assert(opcode == EACH || opcode == EACH_OPT);
695
+ if (opcode == EACH) {
696
+ char errbuf[15];
697
+ set_error(jq,
698
+ jv_invalid_with_msg(jv_string_fmt("Cannot iterate over %s (%s)",
699
+ jv_kind_name(jv_get_kind(container)),
700
+ jv_dump_string_trunc(jv_copy(container), errbuf, sizeof(errbuf)))));
701
+ }
702
+ keep_going = 0;
703
+ }
704
+
705
+ if (!keep_going || raising) {
706
+ if (keep_going)
707
+ jv_free(value);
708
+ jv_free(container);
709
+ goto do_backtrack;
710
+ } else if (is_last) {
711
+ // we don't need to make a backtrack point
712
+ jv_free(container);
713
+ path_append(jq, key, jv_copy(value));
714
+ stack_push(jq, value);
715
+ } else {
716
+ struct stack_pos spos = stack_get_pos(jq);
717
+ stack_push(jq, container);
718
+ stack_push(jq, jv_number(idx));
719
+ stack_save(jq, pc - 1, spos);
720
+ path_append(jq, key, jv_copy(value));
721
+ stack_push(jq, value);
722
+ }
723
+ break;
724
+ }
725
+
726
+ do_backtrack:
727
+ case BACKTRACK: {
728
+ pc = stack_restore(jq);
729
+ if (!pc) {
730
+ if (!jv_is_valid(jq->error)) {
731
+ jv error = jq->error;
732
+ jq->error = jv_null();
733
+ return error;
734
+ }
735
+ return jv_invalid();
736
+ }
737
+ backtracking = 1;
738
+ break;
739
+ }
740
+
741
+ case FORK_OPT:
742
+ case FORK: {
743
+ stack_save(jq, pc - 1, stack_get_pos(jq));
744
+ pc++; // skip offset this time
745
+ break;
746
+ }
747
+
748
+ case ON_BACKTRACK(FORK_OPT): {
749
+ if (jv_is_valid(jq->error)) {
750
+ // `try EXP ...` backtracked here (no value, `empty`), so we backtrack more
751
+ jv_free(stack_pop(jq));
752
+ goto do_backtrack;
753
+ }
754
+ // `try EXP ...` exception caught in EXP
755
+ jv_free(stack_pop(jq)); // free the input
756
+ stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's message
757
+ jq->error = jv_null();
758
+ uint16_t offset = *pc++;
759
+ pc += offset;
760
+ break;
761
+ }
762
+ case ON_BACKTRACK(FORK): {
763
+ if (raising) goto do_backtrack;
764
+ uint16_t offset = *pc++;
765
+ pc += offset;
766
+ break;
767
+ }
768
+
769
+ case CALL_BUILTIN: {
770
+ int nargs = *pc++;
771
+ jv top = stack_pop(jq);
772
+ jv* in = cfunc_input;
773
+ in[0] = top;
774
+ for (int i = 1; i < nargs; i++) {
775
+ in[i] = stack_pop(jq);
776
+ }
777
+ struct cfunction* function = &frame_current(jq)->bc->globals->cfunctions[*pc++];
778
+ typedef jv (*func_1)(jq_state*,jv);
779
+ typedef jv (*func_2)(jq_state*,jv,jv);
780
+ typedef jv (*func_3)(jq_state*,jv,jv,jv);
781
+ typedef jv (*func_4)(jq_state*,jv,jv,jv,jv);
782
+ typedef jv (*func_5)(jq_state*,jv,jv,jv,jv,jv);
783
+ switch (function->nargs) {
784
+ case 1: top = ((func_1)function->fptr)(jq, in[0]); break;
785
+ case 2: top = ((func_2)function->fptr)(jq, in[0], in[1]); break;
786
+ case 3: top = ((func_3)function->fptr)(jq, in[0], in[1], in[2]); break;
787
+ case 4: top = ((func_4)function->fptr)(jq, in[0], in[1], in[2], in[3]); break;
788
+ case 5: top = ((func_5)function->fptr)(jq, in[0], in[1], in[2], in[3], in[4]); break;
789
+ // FIXME: a) up to 7 arguments (input + 6), b) should assert
790
+ // because the compiler should not generate this error.
791
+ default: return jv_invalid_with_msg(jv_string("Function takes too many arguments"));
792
+ }
793
+
794
+ if (jv_is_valid(top)) {
795
+ stack_push(jq, top);
796
+ } else if (jv_invalid_has_msg(jv_copy(top))) {
797
+ set_error(jq, top);
798
+ goto do_backtrack;
799
+ } else {
800
+ // C-coded function returns invalid w/o msg? -> backtrack, as if
801
+ // it had returned `empty`
802
+ goto do_backtrack;
803
+ }
804
+ break;
805
+ }
806
+
807
+ case TAIL_CALL_JQ:
808
+ case CALL_JQ: {
809
+ /*
810
+ * Bytecode layout here:
811
+ *
812
+ * CALL_JQ
813
+ * <nclosures> (i.e., number of call arguments)
814
+ * <callee closure> (what we're calling)
815
+ * <nclosures' worth of closures> (frame reference + code pointer)
816
+ *
817
+ * <next instruction (to return to)>
818
+ *
819
+ * Each closure consists of two uint16_t values: a "level"
820
+ * identifying the frame to be closed over, and an index.
821
+ *
822
+ * The level is a relative number of call frames reachable from
823
+ * the currently one; 0 -> current frame, 1 -> previous frame, and
824
+ * so on.
825
+ *
826
+ * The index is either an index of the closed frame's subfunctions
827
+ * or of the closed frame's parameter closures. If the latter,
828
+ * that closure will be passed, else the closed frame's pointer
829
+ * and the subfunction's code will form the closure to be passed.
830
+ *
831
+ * See make_closure() for more information.
832
+ */
833
+ jv input = stack_pop(jq);
834
+ uint16_t nclosures = *pc++;
835
+ uint16_t* retaddr = pc + 2 + nclosures*2;
836
+ stack_ptr retdata = jq->stk_top;
837
+ struct frame* new_frame;
838
+ struct closure cl = make_closure(jq, pc);
839
+ if (opcode == TAIL_CALL_JQ) {
840
+ retaddr = frame_current(jq)->retaddr;
841
+ retdata = frame_current(jq)->retdata;
842
+ frame_pop(jq);
843
+ }
844
+ new_frame = frame_push(jq, cl, pc + 2, nclosures);
845
+ new_frame->retdata = retdata;
846
+ new_frame->retaddr = retaddr;
847
+ pc = new_frame->bc->code;
848
+ stack_push(jq, input);
849
+ break;
850
+ }
851
+
852
+ case RET: {
853
+ jv value = stack_pop(jq);
854
+ assert(jq->stk_top == frame_current(jq)->retdata);
855
+ uint16_t* retaddr = frame_current(jq)->retaddr;
856
+ if (retaddr) {
857
+ // function return
858
+ pc = retaddr;
859
+ frame_pop(jq);
860
+ } else {
861
+ // top-level return, yielding value
862
+ struct stack_pos spos = stack_get_pos(jq);
863
+ stack_push(jq, jv_null());
864
+ stack_save(jq, pc - 1, spos);
865
+ return value;
866
+ }
867
+ stack_push(jq, value);
868
+ break;
869
+ }
870
+ case ON_BACKTRACK(RET): {
871
+ // resumed after top-level return
872
+ goto do_backtrack;
873
+ }
874
+ }
875
+ }
876
+ }
877
+
878
+ jv jq_format_error(jv msg) {
879
+ if (jv_get_kind(msg) == JV_KIND_NULL ||
880
+ (jv_get_kind(msg) == JV_KIND_INVALID && !jv_invalid_has_msg(jv_copy(msg)))) {
881
+ jv_free(msg);
882
+ fprintf(stderr, "jq: error: out of memory\n");
883
+ return jv_null();
884
+ }
885
+
886
+ if (jv_get_kind(msg) == JV_KIND_STRING)
887
+ return msg; // expected to already be formatted
888
+
889
+ if (jv_get_kind(msg) == JV_KIND_INVALID)
890
+ msg = jv_invalid_get_msg(msg);
891
+
892
+ if (jv_get_kind(msg) == JV_KIND_NULL)
893
+ return jq_format_error(msg); // ENOMEM
894
+
895
+ // Invalid with msg; prefix with "jq: error: "
896
+
897
+ if (jv_get_kind(msg) != JV_KIND_INVALID) {
898
+ if (jv_get_kind(msg) == JV_KIND_STRING)
899
+ return jv_string_fmt("jq: error: %s", jv_string_value(msg));
900
+
901
+ msg = jv_dump_string(msg, JV_PRINT_INVALID);
902
+ if (jv_get_kind(msg) == JV_KIND_STRING)
903
+ return jv_string_fmt("jq: error: %s", jv_string_value(msg));
904
+ return jq_format_error(jv_null()); // ENOMEM
905
+ }
906
+
907
+ // An invalid inside an invalid!
908
+ return jq_format_error(jv_invalid_get_msg(msg));
909
+ }
910
+
911
+ // XXX Refactor into a utility function that returns a jv and one that
912
+ // uses it and then prints that jv's string as the complete error
913
+ // message.
914
+ static void default_err_cb(void *data, jv msg) {
915
+ msg = jq_format_error(msg);
916
+ fprintf((FILE *)data, "%s\n", jv_string_value(msg));
917
+ jv_free(msg);
918
+ }
919
+
920
+ jq_state *jq_init(void) {
921
+ jq_state *jq;
922
+ jq = jv_mem_alloc_unguarded(sizeof(*jq));
923
+ if (jq == NULL)
924
+ return NULL;
925
+
926
+ jq->bc = 0;
927
+ jq->next_label = 0;
928
+
929
+ stack_init(&jq->stk);
930
+ jq->stk_top = 0;
931
+ jq->fork_top = 0;
932
+ jq->curr_frame = 0;
933
+ jq->error = jv_null();
934
+
935
+ jq->err_cb = default_err_cb;
936
+ jq->err_cb_data = stderr;
937
+
938
+ jq->attrs = jv_object();
939
+ jq->path = jv_null();
940
+ jq->value_at_path = jv_null();
941
+ return jq;
942
+ }
943
+
944
+ void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) {
945
+ if (cb == NULL) {
946
+ jq->err_cb = default_err_cb;
947
+ jq->err_cb_data = stderr;
948
+ } else {
949
+ jq->err_cb = cb;
950
+ jq->err_cb_data = data;
951
+ }
952
+ }
953
+
954
+ void jq_get_error_cb(jq_state *jq, jq_msg_cb *cb, void **data) {
955
+ *cb = jq->err_cb;
956
+ *data = jq->err_cb_data;
957
+ }
958
+
959
+ void jq_set_nomem_handler(jq_state *jq, void (*nomem_handler)(void *), void *data) {
960
+ jv_nomem_handler(nomem_handler, data);
961
+ jq->nomem_handler = nomem_handler;
962
+ jq->nomem_handler_data = data;
963
+ }
964
+
965
+
966
+ void jq_start(jq_state *jq, jv input, int flags) {
967
+ jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
968
+ jq_reset(jq);
969
+
970
+ struct closure top = {jq->bc, -1};
971
+ struct frame* top_frame = frame_push(jq, top, 0, 0);
972
+ top_frame->retdata = 0;
973
+ top_frame->retaddr = 0;
974
+
975
+ stack_push(jq, input);
976
+ stack_save(jq, jq->bc->code, stack_get_pos(jq));
977
+ if (flags & JQ_DEBUG_TRACE) {
978
+ jq->debug_trace_enabled = 1;
979
+ } else {
980
+ jq->debug_trace_enabled = 0;
981
+ }
982
+ jq->initial_execution = 1;
983
+ }
984
+
985
+ void jq_teardown(jq_state **jq) {
986
+ jq_state *old_jq = *jq;
987
+ if (old_jq == NULL)
988
+ return;
989
+ *jq = NULL;
990
+
991
+ jq_reset(old_jq);
992
+ bytecode_free(old_jq->bc);
993
+ old_jq->bc = 0;
994
+ jv_free(old_jq->attrs);
995
+
996
+ jv_mem_free(old_jq);
997
+ }
998
+
999
+ static int ret_follows(uint16_t *pc) {
1000
+ if (*pc == RET)
1001
+ return 1;
1002
+ if (*pc++ != JUMP)
1003
+ return 0;
1004
+ return ret_follows(pc + *pc + 1); // FIXME, might be ironic
1005
+ }
1006
+
1007
+ /*
1008
+ * Look for tail calls that can be optimized: tail calls with no
1009
+ * references left to the current frame.
1010
+ *
1011
+ * We're staring at this bytecode layout:
1012
+ *
1013
+ * CALL_JQ
1014
+ * <nclosures>
1015
+ * <callee closure> (2 units)
1016
+ * <nclosures closures> (2 units each)
1017
+ * <next instruction>
1018
+ *
1019
+ * A closure is:
1020
+ *
1021
+ * <level> (a relative frame count chased via the current frame's env)
1022
+ * <index> (an index of a subfunction or closure in that frame)
1023
+ *
1024
+ * We're looking for:
1025
+ *
1026
+ * a) the next instruction is a RET or a chain of unconditional JUMPs
1027
+ * that ends in a RET, and
1028
+ *
1029
+ * b) none of the closures -callee included- have level == 0.
1030
+ */
1031
+ static uint16_t tail_call_analyze(uint16_t *pc) {
1032
+ assert(*pc == CALL_JQ);
1033
+ pc++;
1034
+ // + 1 for the callee closure
1035
+ for (uint16_t nclosures = *pc++ + 1; nclosures > 0; pc++, nclosures--) {
1036
+ if (*pc++ == 0)
1037
+ return CALL_JQ;
1038
+ }
1039
+ if (ret_follows(pc))
1040
+ return TAIL_CALL_JQ;
1041
+ return CALL_JQ;
1042
+ }
1043
+
1044
+ static struct bytecode *optimize_code(struct bytecode *bc) {
1045
+ uint16_t *pc = bc->code;
1046
+ // FIXME: Don't mutate bc->code...
1047
+ while (pc < bc->code + bc->codelen) {
1048
+ switch (*pc) {
1049
+ case CALL_JQ:
1050
+ *pc = tail_call_analyze(pc);
1051
+ break;
1052
+
1053
+ // Other bytecode optimizations here. A peephole optimizer would
1054
+ // fit right in.
1055
+ default: break;
1056
+ }
1057
+ pc += bytecode_operation_length(pc);
1058
+ }
1059
+ return bc;
1060
+ }
1061
+
1062
+ static struct bytecode *optimize(struct bytecode *bc) {
1063
+ for (int i=0; i<bc->nsubfunctions; i++) {
1064
+ bc->subfunctions[i] = optimize(bc->subfunctions[i]);
1065
+ }
1066
+ return optimize_code(bc);
1067
+ }
1068
+
1069
+ int jq_compile_args(jq_state *jq, const char* str, jv args) {
1070
+ jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data);
1071
+ assert(jv_get_kind(args) == JV_KIND_ARRAY);
1072
+ struct locfile* locations;
1073
+ locations = locfile_init(jq, "<top-level>", str, strlen(str));
1074
+ block program;
1075
+ jq_reset(jq);
1076
+ if (jq->bc) {
1077
+ bytecode_free(jq->bc);
1078
+ jq->bc = 0;
1079
+ }
1080
+ int nerrors = load_program(jq, locations, &program);
1081
+ if (nerrors == 0) {
1082
+ jv_array_foreach(args, i, arg) {
1083
+ jv name = jv_object_get(jv_copy(arg), jv_string("name"));
1084
+ jv value = jv_object_get(arg, jv_string("value"));
1085
+ program = gen_var_binding(gen_const(value), jv_string_value(name), program);
1086
+ jv_free(name);
1087
+ }
1088
+
1089
+ nerrors = builtins_bind(jq, &program);
1090
+ if (nerrors == 0) {
1091
+ nerrors = block_compile(program, &jq->bc, locations);
1092
+ }
1093
+ }
1094
+ if (nerrors)
1095
+ jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error"));
1096
+ if (jq->bc)
1097
+ jq->bc = optimize(jq->bc);
1098
+ jv_free(args);
1099
+ locfile_free(locations);
1100
+ return jq->bc != NULL;
1101
+ }
1102
+
1103
+ int jq_compile(jq_state *jq, const char* str) {
1104
+ return jq_compile_args(jq, str, jv_array());
1105
+ }
1106
+
1107
+ jv jq_get_jq_origin(jq_state *jq) {
1108
+ return jq_get_attr(jq, jv_string("JQ_ORIGIN"));
1109
+ }
1110
+
1111
+ jv jq_get_prog_origin(jq_state *jq) {
1112
+ return jq_get_attr(jq, jv_string("PROGRAM_ORIGIN"));
1113
+ }
1114
+
1115
+ jv jq_get_lib_dirs(jq_state *jq) {
1116
+ return jq_get_attr(jq, jv_string("JQ_LIBRARY_PATH"));
1117
+ }
1118
+
1119
+ void jq_set_attrs(jq_state *jq, jv attrs) {
1120
+ assert(jv_get_kind(attrs) == JV_KIND_OBJECT);
1121
+ jv_free(jq->attrs);
1122
+ jq->attrs = attrs;
1123
+ }
1124
+
1125
+ void jq_set_attr(jq_state *jq, jv attr, jv val) {
1126
+ jq->attrs = jv_object_set(jq->attrs, attr, val);
1127
+ }
1128
+
1129
+ jv jq_get_attr(jq_state *jq, jv attr) {
1130
+ return jv_object_get(jv_copy(jq->attrs), attr);
1131
+ }
1132
+
1133
+ void jq_dump_disassembly(jq_state *jq, int indent) {
1134
+ dump_disassembly(indent, jq->bc);
1135
+ }
1136
+
1137
+ void jq_set_input_cb(jq_state *jq, jq_input_cb cb, void *data) {
1138
+ jq->input_cb = cb;
1139
+ jq->input_cb_data = data;
1140
+ }
1141
+
1142
+ void jq_get_input_cb(jq_state *jq, jq_input_cb *cb, void **data) {
1143
+ *cb = jq->input_cb;
1144
+ *data = jq->input_cb_data;
1145
+ }
1146
+
1147
+ void jq_set_debug_cb(jq_state *jq, jq_msg_cb cb, void *data) {
1148
+ jq->debug_cb = cb;
1149
+ jq->debug_cb_data = data;
1150
+ }
1151
+
1152
+ void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) {
1153
+ *cb = jq->debug_cb;
1154
+ *data = jq->debug_cb_data;
1155
+ }