execute.c (jq-1.5) | : | execute.c (jq-1.6) | ||
---|---|---|---|---|
skipping to change at line 43 | skipping to change at line 43 | |||
stack_ptr stk_top; | stack_ptr stk_top; | |||
stack_ptr fork_top; | stack_ptr fork_top; | |||
jv path; | jv path; | |||
jv value_at_path; | jv value_at_path; | |||
int subexp_nest; | int subexp_nest; | |||
int debug_trace_enabled; | int debug_trace_enabled; | |||
int initial_execution; | int initial_execution; | |||
unsigned next_label; | unsigned next_label; | |||
int halted; | ||||
jv exit_code; | ||||
jv error_message; | ||||
jv attrs; | jv attrs; | |||
jq_input_cb input_cb; | jq_input_cb input_cb; | |||
void *input_cb_data; | void *input_cb_data; | |||
jq_msg_cb debug_cb; | jq_msg_cb debug_cb; | |||
void *debug_cb_data; | void *debug_cb_data; | |||
}; | }; | |||
struct closure { | struct closure { | |||
struct bytecode* bc; // jq bytecode | struct bytecode* bc; // jq bytecode | |||
stack_ptr env; // jq stack address of closed frame | stack_ptr env; // jq stack address of closed frame | |||
skipping to change at line 67 | skipping to change at line 71 | |||
struct closure closure; | struct closure closure; | |||
jv localvar; | jv localvar; | |||
}; | }; | |||
// jq function call frame | // jq function call frame | |||
struct frame { | struct frame { | |||
struct bytecode* bc; // jq bytecode for callee | struct bytecode* bc; // jq bytecode for callee | |||
stack_ptr env; // jq stack address of frame to return to | stack_ptr env; // jq stack address of frame to return to | |||
stack_ptr retdata; // jq stack address to unwind to on RET | stack_ptr retdata; // jq stack address to unwind to on RET | |||
uint16_t* retaddr; // jq bytecode return address | uint16_t* retaddr; // jq bytecode return address | |||
union frame_entry entries[0]; // nclosures + nlocals | union frame_entry entries[]; // nclosures + nlocals | |||
}; | }; | |||
static int frame_size(struct bytecode* bc) { | static int frame_size(struct bytecode* bc) { | |||
return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc- >nlocals); | return sizeof(struct frame) + sizeof(union frame_entry) * (bc->nclosures + bc- >nlocals); | |||
} | } | |||
static struct frame* frame_current(struct jq_state* jq) { | static struct frame* frame_current(struct jq_state* jq) { | |||
struct frame* fp = stack_block(&jq->stk, jq->curr_frame); | struct frame* fp = stack_block(&jq->stk, jq->curr_frame); | |||
stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame); | stack_ptr next = *stack_block_next(&jq->stk, jq->curr_frame); | |||
skipping to change at line 244 | skipping to change at line 248 | |||
int n2 = jv_array_length(jv_copy(jq->path)); | int n2 = jv_array_length(jv_copy(jq->path)); | |||
assert(n2 == n1 + 1); | assert(n2 == n1 + 1); | |||
jv_free(jq->value_at_path); | jv_free(jq->value_at_path); | |||
jq->value_at_path = value_at_path; | jq->value_at_path = value_at_path; | |||
} else { | } else { | |||
jv_free(component); | jv_free(component); | |||
jv_free(value_at_path); | jv_free(value_at_path); | |||
} | } | |||
} | } | |||
/* For f_getpath() */ | ||||
jv | ||||
_jq_path_append(jq_state *jq, jv v, jv p, jv value_at_path) { | ||||
if (jq->subexp_nest != 0 || | ||||
jv_get_kind(jq->path) != JV_KIND_ARRAY || | ||||
!jv_is_valid(value_at_path)) { | ||||
jv_free(v); | ||||
jv_free(p); | ||||
return value_at_path; | ||||
} | ||||
if (!jv_identical(v, jv_copy(jq->value_at_path))) { | ||||
jv_free(p); | ||||
return value_at_path; | ||||
} | ||||
if (jv_get_kind(p) == JV_KIND_ARRAY) | ||||
jq->path = jv_array_concat(jq->path, p); | ||||
else | ||||
jq->path = jv_array_append(jq->path, p); | ||||
jv_free(jq->value_at_path); | ||||
return jv_copy(jq->value_at_path = value_at_path); | ||||
} | ||||
uint16_t* stack_restore(jq_state *jq){ | uint16_t* stack_restore(jq_state *jq){ | |||
while (!stack_pop_will_free(&jq->stk, jq->fork_top)) { | while (!stack_pop_will_free(&jq->stk, jq->fork_top)) { | |||
if (stack_pop_will_free(&jq->stk, jq->stk_top)) { | if (stack_pop_will_free(&jq->stk, jq->stk_top)) { | |||
jv_free(stack_pop(jq)); | jv_free(stack_pop(jq)); | |||
} else if (stack_pop_will_free(&jq->stk, jq->curr_frame)) { | } else if (stack_pop_will_free(&jq->stk, jq->curr_frame)) { | |||
frame_pop(jq); | frame_pop(jq); | |||
} else { | } else { | |||
assert(0); | assert(0); | |||
} | } | |||
} | } | |||
skipping to change at line 287 | skipping to change at line 313 | |||
static void jq_reset(jq_state *jq) { | static void jq_reset(jq_state *jq) { | |||
while (stack_restore(jq)) {} | while (stack_restore(jq)) {} | |||
assert(jq->stk_top == 0); | assert(jq->stk_top == 0); | |||
assert(jq->fork_top == 0); | assert(jq->fork_top == 0); | |||
assert(jq->curr_frame == 0); | assert(jq->curr_frame == 0); | |||
stack_reset(&jq->stk); | stack_reset(&jq->stk); | |||
jv_free(jq->error); | jv_free(jq->error); | |||
jq->error = jv_null(); | jq->error = jv_null(); | |||
jq->halted = 0; | ||||
jv_free(jq->exit_code); | ||||
jv_free(jq->error_message); | ||||
if (jv_get_kind(jq->path) != JV_KIND_INVALID) | if (jv_get_kind(jq->path) != JV_KIND_INVALID) | |||
jv_free(jq->path); | jv_free(jq->path); | |||
jq->path = jv_null(); | jq->path = jv_null(); | |||
jv_free(jq->value_at_path); | jv_free(jq->value_at_path); | |||
jq->value_at_path = jv_null(); | jq->value_at_path = jv_null(); | |||
jq->subexp_nest = 0; | jq->subexp_nest = 0; | |||
} | } | |||
void jq_report_error(jq_state *jq, jv value) { | void jq_report_error(jq_state *jq, jv value) { | |||
assert(jq->err_cb); | assert(jq->err_cb); | |||
skipping to change at line 322 | skipping to change at line 351 | |||
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | |||
uint16_t* pc = stack_restore(jq); | uint16_t* pc = stack_restore(jq); | |||
assert(pc); | assert(pc); | |||
int raising; | int raising; | |||
int backtracking = !jq->initial_execution; | int backtracking = !jq->initial_execution; | |||
jq->initial_execution = 0; | jq->initial_execution = 0; | |||
assert(jv_get_kind(jq->error) == JV_KIND_NULL); | assert(jv_get_kind(jq->error) == JV_KIND_NULL); | |||
while (1) { | while (1) { | |||
if (jq->halted) { | ||||
if (jq->debug_trace_enabled) | ||||
printf("\t<halted>\n"); | ||||
return jv_invalid(); | ||||
} | ||||
uint16_t opcode = *pc; | uint16_t opcode = *pc; | |||
raising = 0; | raising = 0; | |||
if (jq->debug_trace_enabled) { | if (jq->debug_trace_enabled) { | |||
dump_operation(frame_current(jq)->bc, pc); | dump_operation(frame_current(jq)->bc, pc); | |||
printf("\t"); | printf("\t"); | |||
const struct opcode_description* opdesc = opcode_describe(opcode); | const struct opcode_description* opdesc = opcode_describe(opcode); | |||
stack_ptr param = 0; | stack_ptr param = 0; | |||
if (!backtracking) { | if (!backtracking) { | |||
int stack_in = opdesc->stack_in; | int stack_in = opdesc->stack_in; | |||
if (stack_in == -1) stack_in = pc[1]; | if (stack_in == -1) stack_in = pc[1]; | |||
param = jq->stk_top; | ||||
for (int i=0; i<stack_in; i++) { | for (int i=0; i<stack_in; i++) { | |||
if (i == 0) { | if (i != 0) { | |||
param = jq->stk_top; | ||||
} else { | ||||
printf(" | "); | printf(" | "); | |||
param = *stack_block_next(&jq->stk, param); | param = *stack_block_next(&jq->stk, param); | |||
} | } | |||
if (!param) break; | if (!param) break; | |||
jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT ); | jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOUNT ); | |||
//printf("<%d>", jv_get_refcnt(param->val)); | //printf("<%d>", jv_get_refcnt(param->val)); | |||
//printf(" -- "); | //printf(" -- "); | |||
//jv_dump(jv_copy(jq->path), 0); | //jv_dump(jv_copy(jq->path), 0); | |||
} | } | |||
if (jq->debug_trace_enabled & JQ_DEBUG_TRACE_DETAIL) { | ||||
while ((param = *stack_block_next(&jq->stk, param))) { | ||||
printf(" || "); | ||||
jv_dump(jv_copy(*(jv*)stack_block(&jq->stk, param)), JV_PRINT_REFCOU | ||||
NT); | ||||
} | ||||
} | ||||
} else { | } else { | |||
printf("\t<backtracking>"); | printf("\t<backtracking>"); | |||
} | } | |||
printf("\n"); | printf("\n"); | |||
} | } | |||
if (backtracking) { | if (backtracking) { | |||
opcode = ON_BACKTRACK(opcode); | opcode = ON_BACKTRACK(opcode); | |||
backtracking = 0; | backtracking = 0; | |||
skipping to change at line 419 | skipping to change at line 458 | |||
case SUBEXP_END: { | case SUBEXP_END: { | |||
assert(jq->subexp_nest > 0); | assert(jq->subexp_nest > 0); | |||
jq->subexp_nest--; | jq->subexp_nest--; | |||
jv a = stack_pop(jq); | jv a = stack_pop(jq); | |||
jv b = stack_pop(jq); | jv b = stack_pop(jq); | |||
stack_push(jq, a); | stack_push(jq, a); | |||
stack_push(jq, b); | stack_push(jq, b); | |||
break; | break; | |||
} | } | |||
case PUSHK_UNDER: { | ||||
jv v = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); | ||||
assert(jv_is_valid(v)); | ||||
jv v2 = stack_pop(jq); | ||||
stack_push(jq, v); | ||||
stack_push(jq, v2); | ||||
break; | ||||
} | ||||
case POP: { | case POP: { | |||
jv_free(stack_pop(jq)); | jv_free(stack_pop(jq)); | |||
break; | break; | |||
} | } | |||
case APPEND: { | case APPEND: { | |||
jv v = stack_pop(jq); | jv v = stack_pop(jq); | |||
uint16_t level = *pc++; | uint16_t level = *pc++; | |||
uint16_t vidx = *pc++; | uint16_t vidx = *pc++; | |||
jv* var = frame_local_var(jq, vidx, level); | jv* var = frame_local_var(jq, vidx, level); | |||
skipping to change at line 516 | skipping to change at line 564 | |||
printf("V%d = ", v); | printf("V%d = ", v); | |||
jv_dump(jv_copy(*var), 0); | jv_dump(jv_copy(*var), 0); | |||
printf(" (%d)\n", jv_get_refcnt(*var)); | printf(" (%d)\n", jv_get_refcnt(*var)); | |||
} | } | |||
jv_free(stack_popn(jq)); | jv_free(stack_popn(jq)); | |||
stack_push(jq, *var); | stack_push(jq, *var); | |||
*var = jv_null(); | *var = jv_null(); | |||
break; | break; | |||
} | } | |||
case STOREVN: | ||||
stack_save(jq, pc - 1, stack_get_pos(jq)); | ||||
case STOREV: { | case STOREV: { | |||
uint16_t level = *pc++; | uint16_t level = *pc++; | |||
uint16_t v = *pc++; | uint16_t v = *pc++; | |||
jv* var = frame_local_var(jq, v, level); | jv* var = frame_local_var(jq, v, level); | |||
jv val = stack_pop(jq); | jv val = stack_pop(jq); | |||
if (jq->debug_trace_enabled) { | if (jq->debug_trace_enabled) { | |||
printf("V%d = ", v); | printf("V%d = ", v); | |||
jv_dump(jv_copy(val), 0); | jv_dump(jv_copy(val), 0); | |||
printf(" (%d)\n", jv_get_refcnt(val)); | printf(" (%d)\n", jv_get_refcnt(val)); | |||
} | } | |||
jv_free(*var); | jv_free(*var); | |||
*var = val; | *var = val; | |||
break; | break; | |||
} | } | |||
case ON_BACKTRACK(STOREVN): { | ||||
uint16_t level = *pc++; | ||||
uint16_t v = *pc++; | ||||
jv* var = frame_local_var(jq, v, level); | ||||
jv_free(*var); | ||||
*var = jv_null(); | ||||
goto do_backtrack; | ||||
break; | ||||
} | ||||
case STORE_GLOBAL: { | case STORE_GLOBAL: { | |||
// Get the constant | // Get the constant | |||
jv val = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); | jv val = jv_array_get(jv_copy(frame_current(jq)->bc->constants), *pc++); | |||
assert(jv_is_valid(val)); | assert(jv_is_valid(val)); | |||
// Store the var | // Store the var | |||
uint16_t level = *pc++; | uint16_t level = *pc++; | |||
uint16_t v = *pc++; | uint16_t v = *pc++; | |||
jv* var = frame_local_var(jq, v, level); | jv* var = frame_local_var(jq, v, level); | |||
if (jq->debug_trace_enabled) { | if (jq->debug_trace_enabled) { | |||
skipping to change at line 740 | skipping to change at line 800 | |||
jq->error = jv_null(); | jq->error = jv_null(); | |||
return error; | return error; | |||
} | } | |||
return jv_invalid(); | return jv_invalid(); | |||
} | } | |||
backtracking = 1; | backtracking = 1; | |||
break; | break; | |||
} | } | |||
case FORK_OPT: | case FORK_OPT: | |||
case DESTRUCTURE_ALT: | ||||
case FORK: { | case FORK: { | |||
stack_save(jq, pc - 1, stack_get_pos(jq)); | stack_save(jq, pc - 1, stack_get_pos(jq)); | |||
pc++; // skip offset this time | pc++; // skip offset this time | |||
break; | break; | |||
} | } | |||
case ON_BACKTRACK(FORK_OPT): { | case ON_BACKTRACK(FORK_OPT): | |||
case ON_BACKTRACK(DESTRUCTURE_ALT): { | ||||
if (jv_is_valid(jq->error)) { | if (jv_is_valid(jq->error)) { | |||
// `try EXP ...` backtracked here (no value, `empty`), so we backtrack m ore | // `try EXP ...` backtracked here (no value, `empty`), so we backtrack m ore | |||
jv_free(stack_pop(jq)); | jv_free(stack_pop(jq)); | |||
goto do_backtrack; | goto do_backtrack; | |||
} | } | |||
// `try EXP ...` exception caught in EXP | // `try EXP ...` exception caught in EXP | |||
jv_free(stack_pop(jq)); // free the input | // DESTRUCTURE_ALT doesn't want the error message on the stack, | |||
stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's messag | // as we would just want to throw it away anyway. | |||
e | if (opcode != ON_BACKTRACK(DESTRUCTURE_ALT)) { | |||
jv_free(stack_pop(jq)); // free the input | ||||
stack_push(jq, jv_invalid_get_msg(jq->error)); // push the error's mess | ||||
age | ||||
} else { | ||||
jv_free(jq->error); | ||||
} | ||||
jq->error = jv_null(); | jq->error = jv_null(); | |||
uint16_t offset = *pc++; | uint16_t offset = *pc++; | |||
pc += offset; | pc += offset; | |||
break; | break; | |||
} | } | |||
case ON_BACKTRACK(FORK): { | case ON_BACKTRACK(FORK): { | |||
if (raising) goto do_backtrack; | if (raising) goto do_backtrack; | |||
uint16_t offset = *pc++; | uint16_t offset = *pc++; | |||
pc += offset; | pc += offset; | |||
break; | break; | |||
skipping to change at line 933 | skipping to change at line 1001 | |||
jq->bc = 0; | jq->bc = 0; | |||
jq->next_label = 0; | jq->next_label = 0; | |||
stack_init(&jq->stk); | stack_init(&jq->stk); | |||
jq->stk_top = 0; | jq->stk_top = 0; | |||
jq->fork_top = 0; | jq->fork_top = 0; | |||
jq->curr_frame = 0; | jq->curr_frame = 0; | |||
jq->error = jv_null(); | jq->error = jv_null(); | |||
jq->halted = 0; | ||||
jq->exit_code = jv_invalid(); | ||||
jq->error_message = jv_invalid(); | ||||
jq->err_cb = default_err_cb; | jq->err_cb = default_err_cb; | |||
jq->err_cb_data = stderr; | jq->err_cb_data = stderr; | |||
jq->attrs = jv_object(); | jq->attrs = jv_object(); | |||
jq->path = jv_null(); | jq->path = jv_null(); | |||
jq->value_at_path = jv_null(); | jq->value_at_path = jv_null(); | |||
return jq; | return jq; | |||
} | } | |||
void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) { | void jq_set_error_cb(jq_state *jq, jq_msg_cb cb, void *data) { | |||
skipping to change at line 974 | skipping to change at line 1046 | |||
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | |||
jq_reset(jq); | jq_reset(jq); | |||
struct closure top = {jq->bc, -1}; | struct closure top = {jq->bc, -1}; | |||
struct frame* top_frame = frame_push(jq, top, 0, 0); | struct frame* top_frame = frame_push(jq, top, 0, 0); | |||
top_frame->retdata = 0; | top_frame->retdata = 0; | |||
top_frame->retaddr = 0; | top_frame->retaddr = 0; | |||
stack_push(jq, input); | stack_push(jq, input); | |||
stack_save(jq, jq->bc->code, stack_get_pos(jq)); | stack_save(jq, jq->bc->code, stack_get_pos(jq)); | |||
if (flags & JQ_DEBUG_TRACE) { | jq->debug_trace_enabled = flags & JQ_DEBUG_TRACE_ALL; | |||
jq->debug_trace_enabled = 1; | ||||
} else { | ||||
jq->debug_trace_enabled = 0; | ||||
} | ||||
jq->initial_execution = 1; | jq->initial_execution = 1; | |||
} | } | |||
void jq_teardown(jq_state **jq) { | void jq_teardown(jq_state **jq) { | |||
jq_state *old_jq = *jq; | jq_state *old_jq = *jq; | |||
if (old_jq == NULL) | if (old_jq == NULL) | |||
return; | return; | |||
*jq = NULL; | *jq = NULL; | |||
jq_reset(old_jq); | jq_reset(old_jq); | |||
skipping to change at line 1066 | skipping to change at line 1134 | |||
return bc; | return bc; | |||
} | } | |||
static struct bytecode *optimize(struct bytecode *bc) { | static struct bytecode *optimize(struct bytecode *bc) { | |||
for (int i=0; i<bc->nsubfunctions; i++) { | for (int i=0; i<bc->nsubfunctions; i++) { | |||
bc->subfunctions[i] = optimize(bc->subfunctions[i]); | bc->subfunctions[i] = optimize(bc->subfunctions[i]); | |||
} | } | |||
return optimize_code(bc); | return optimize_code(bc); | |||
} | } | |||
static jv | ||||
args2obj(jv args) | ||||
{ | ||||
if (jv_get_kind(args) == JV_KIND_OBJECT) | ||||
return args; | ||||
assert(jv_get_kind(args) == JV_KIND_ARRAY); | ||||
jv r = jv_object(); | ||||
jv kk = jv_string("name"); | ||||
jv vk = jv_string("value"); | ||||
jv_array_foreach(args, i, v) | ||||
r = jv_object_set(r, jv_object_get(jv_copy(v), kk), jv_object_get(v, vk)); | ||||
jv_free(args); | ||||
jv_free(kk); | ||||
jv_free(vk); | ||||
return r; | ||||
} | ||||
int jq_compile_args(jq_state *jq, const char* str, jv args) { | int jq_compile_args(jq_state *jq, const char* str, jv args) { | |||
jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | jv_nomem_handler(jq->nomem_handler, jq->nomem_handler_data); | |||
assert(jv_get_kind(args) == JV_KIND_ARRAY); | assert(jv_get_kind(args) == JV_KIND_ARRAY || jv_get_kind(args) == JV_KIND_OBJE CT); | |||
struct locfile* locations; | struct locfile* locations; | |||
locations = locfile_init(jq, "<top-level>", str, strlen(str)); | locations = locfile_init(jq, "<top-level>", str, strlen(str)); | |||
block program; | block program; | |||
jq_reset(jq); | jq_reset(jq); | |||
if (jq->bc) { | if (jq->bc) { | |||
bytecode_free(jq->bc); | bytecode_free(jq->bc); | |||
jq->bc = 0; | jq->bc = 0; | |||
} | } | |||
int nerrors = load_program(jq, locations, &program); | int nerrors = load_program(jq, locations, &program); | |||
if (nerrors == 0) { | if (nerrors == 0) { | |||
jv_array_foreach(args, i, arg) { | ||||
jv name = jv_object_get(jv_copy(arg), jv_string("name")); | ||||
jv value = jv_object_get(arg, jv_string("value")); | ||||
program = gen_var_binding(gen_const(value), jv_string_value(name), program | ||||
); | ||||
jv_free(name); | ||||
} | ||||
nerrors = builtins_bind(jq, &program); | nerrors = builtins_bind(jq, &program); | |||
if (nerrors == 0) { | if (nerrors == 0) { | |||
nerrors = block_compile(program, &jq->bc, locations); | nerrors = block_compile(program, &jq->bc, locations, args = args2obj(args) ); | |||
} | } | |||
} | } else | |||
jv_free(args); | ||||
if (nerrors) | if (nerrors) | |||
jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error")); | jq_report_error(jq, jv_string_fmt("jq: %d compile %s", nerrors, nerrors > 1 ? "errors" : "error")); | |||
if (jq->bc) | if (jq->bc) | |||
jq->bc = optimize(jq->bc); | jq->bc = optimize(jq->bc); | |||
jv_free(args); | ||||
locfile_free(locations); | locfile_free(locations); | |||
return jq->bc != NULL; | return jq->bc != NULL; | |||
} | } | |||
int jq_compile(jq_state *jq, const char* str) { | int jq_compile(jq_state *jq, const char* str) { | |||
return jq_compile_args(jq, str, jv_array()); | return jq_compile_args(jq, str, jv_object()); | |||
} | } | |||
jv jq_get_jq_origin(jq_state *jq) { | jv jq_get_jq_origin(jq_state *jq) { | |||
return jq_get_attr(jq, jv_string("JQ_ORIGIN")); | return jq_get_attr(jq, jv_string("JQ_ORIGIN")); | |||
} | } | |||
jv jq_get_prog_origin(jq_state *jq) { | jv jq_get_prog_origin(jq_state *jq) { | |||
return jq_get_attr(jq, jv_string("PROGRAM_ORIGIN")); | return jq_get_attr(jq, jv_string("PROGRAM_ORIGIN")); | |||
} | } | |||
skipping to change at line 1153 | skipping to change at line 1231 | |||
void jq_set_debug_cb(jq_state *jq, jq_msg_cb cb, void *data) { | void jq_set_debug_cb(jq_state *jq, jq_msg_cb cb, void *data) { | |||
jq->debug_cb = cb; | jq->debug_cb = cb; | |||
jq->debug_cb_data = data; | jq->debug_cb_data = data; | |||
} | } | |||
void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) { | void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) { | |||
*cb = jq->debug_cb; | *cb = jq->debug_cb; | |||
*data = jq->debug_cb_data; | *data = jq->debug_cb_data; | |||
} | } | |||
void | ||||
jq_halt(jq_state *jq, jv exit_code, jv error_message) | ||||
{ | ||||
assert(!jq->halted); | ||||
jq->halted = 1; | ||||
jq->exit_code = exit_code; | ||||
jq->error_message = error_message; | ||||
} | ||||
int | ||||
jq_halted(jq_state *jq) | ||||
{ | ||||
return jq->halted; | ||||
} | ||||
jv jq_get_exit_code(jq_state *jq) | ||||
{ | ||||
return jv_copy(jq->exit_code); | ||||
} | ||||
jv jq_get_error_message(jq_state *jq) | ||||
{ | ||||
return jv_copy(jq->error_message); | ||||
} | ||||
End of changes. 24 change blocks. | ||||
26 lines changed or deleted | 104 lines changed or added |