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