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