Add halt, halt_error builtins (fix #386)
This commit is contained in:
1 parent
6bac4ed059
commit
8ea21a54ad
9 files changed
+163
-7
No files matched your search
@@ -1031,6 +1031,19 @@ static jv f_env(jq_state *jq, jv input) {
|
||||
return env;
|
||||
}
|
||||
|
||||
static jv f_halt(jq_state *jq, jv input) {
|
||||
jv_free(input);
|
||||
jq_halt(jq, jv_invalid(), jv_invalid());
|
||||
return jv_true();
|
||||
}
|
||||
|
||||
static jv f_halt_error(jq_state *jq, jv input, jv a) {
|
||||
if (jv_get_kind(a) != JV_KIND_NUMBER)
|
||||
return type_error(input, "halt_error/1: number required"); \
|
||||
jq_halt(jq, a, input);
|
||||
return jv_true();
|
||||
}
|
||||
|
||||
static jv f_get_search_list(jq_state *jq, jv input) {
|
||||
jv_free(input);
|
||||
return jq_get_lib_dirs(jq);
|
||||
@@ -1467,6 +1480,8 @@ static const struct cfunction function_list[] = {
|
||||
{(cfunction_ptr)f_error, "error", 2},
|
||||
{(cfunction_ptr)f_format, "format", 2},
|
||||
{(cfunction_ptr)f_env, "env", 1},
|
||||
{(cfunction_ptr)f_halt, "halt", 1},
|
||||
{(cfunction_ptr)f_halt_error, "halt_error", 2},
|
||||
{(cfunction_ptr)f_get_search_list, "get_search_list", 1},
|
||||
{(cfunction_ptr)f_get_prog_origin, "get_prog_origin", 1},
|
||||
{(cfunction_ptr)f_get_jq_origin, "get_jq_origin", 1},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
def halt_error: halt_error(5);
|
||||
def error: error(.);
|
||||
def map(f): [.[] | f];
|
||||
def select(f): if f then . else empty end;
|
||||
|
||||
@@ -40,6 +40,10 @@ struct jq_state {
|
||||
int initial_execution;
|
||||
unsigned next_label;
|
||||
|
||||
int halted;
|
||||
jv exit_code;
|
||||
jv error_message;
|
||||
|
||||
jv attrs;
|
||||
jq_input_cb input_cb;
|
||||
void *input_cb_data;
|
||||
@@ -285,6 +289,9 @@ static void jq_reset(jq_state *jq) {
|
||||
jv_free(jq->error);
|
||||
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)
|
||||
jv_free(jq->path);
|
||||
jq->path = jv_null();
|
||||
@@ -320,6 +327,11 @@ jv jq_next(jq_state *jq) {
|
||||
jq->initial_execution = 0;
|
||||
assert(jv_get_kind(jq->error) == JV_KIND_NULL);
|
||||
while (1) {
|
||||
if (jq->halted) {
|
||||
if (jq->debug_trace_enabled)
|
||||
printf("\t<halted>\n");
|
||||
return jv_invalid();
|
||||
}
|
||||
uint16_t opcode = *pc;
|
||||
raising = 0;
|
||||
|
||||
@@ -932,6 +944,10 @@ jq_state *jq_init(void) {
|
||||
jq->curr_frame = 0;
|
||||
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_data = stderr;
|
||||
|
||||
@@ -1163,3 +1179,28 @@ void jq_get_debug_cb(jq_state *jq, jq_msg_cb *cb, void **data) {
|
||||
*cb = jq->debug_cb;
|
||||
*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);
|
||||
}
|
||||
@@ -22,6 +22,11 @@ void jq_start(jq_state *, jv value, int);
|
||||
jv jq_next(jq_state *);
|
||||
void jq_teardown(jq_state **);
|
||||
|
||||
void jq_halt(jq_state *, jv, jv);
|
||||
int jq_halted(jq_state *);
|
||||
jv jq_get_exit_code(jq_state *);
|
||||
jv jq_get_error_message(jq_state *);
|
||||
|
||||
typedef jv (*jq_input_cb)(jq_state *, void *);
|
||||
void jq_set_input_cb(jq_state *, jq_input_cb, void *);
|
||||
void jq_get_input_cb(jq_state *, jq_input_cb *, void **);
|
||||
|
||||
+28
-5
@@ -137,10 +137,11 @@ enum {
|
||||
RAW_NO_LF = 1024,
|
||||
UNBUFFERED_OUTPUT = 2048,
|
||||
EXIT_STATUS = 4096,
|
||||
SEQ = 8192,
|
||||
RUN_TESTS = 16384,
|
||||
EXIT_STATUS_EXACT = 8192,
|
||||
SEQ = 16384,
|
||||
RUN_TESTS = 32768,
|
||||
/* debugging only */
|
||||
DUMP_DISASM = 32768,
|
||||
DUMP_DISASM = 65536,
|
||||
};
|
||||
static int options = 0;
|
||||
|
||||
@@ -182,7 +183,29 @@ static int process(jq_state *jq, jv value, int flags, int dumpopts) {
|
||||
if (options & UNBUFFERED_OUTPUT)
|
||||
fflush(stdout);
|
||||
}
|
||||
if (jv_invalid_has_msg(jv_copy(result))) {
|
||||
if (jq_halted(jq)) {
|
||||
// jq program invoked `halt` or `halt_error`
|
||||
options |= EXIT_STATUS_EXACT;
|
||||
jv exit_code = jq_get_exit_code(jq);
|
||||
if (!jv_is_valid(exit_code))
|
||||
ret = 0;
|
||||
else if (jv_get_kind(exit_code) == JV_KIND_NUMBER)
|
||||
ret = jv_number_value(exit_code);
|
||||
else
|
||||
ret = 5;
|
||||
jv_free(exit_code);
|
||||
jv error_message = jq_get_error_message(jq);
|
||||
if (jv_get_kind(error_message) == JV_KIND_STRING) {
|
||||
fprintf(stderr, "%s", jv_string_value(error_message));
|
||||
} else if (jv_get_kind(error_message) == JV_KIND_NULL) {
|
||||
// Halt with no output
|
||||
} else if (jv_is_valid(error_message)) {
|
||||
error_message = jv_dump_string(jv_copy(error_message), 0);
|
||||
fprintf(stderr, "%s\n", jv_string_value(error_message));
|
||||
} // else no message on stderr; use --debug-trace to see a message
|
||||
fflush(stderr);
|
||||
jv_free(error_message);
|
||||
} else if (jv_invalid_has_msg(jv_copy(result))) {
|
||||
// Uncaught jq exception
|
||||
jv msg = jv_invalid_get_msg(jv_copy(result));
|
||||
jv input_pos = jq_util_input_get_position(jq);
|
||||
@@ -623,7 +646,7 @@ out:
|
||||
jq_teardown(&jq);
|
||||
if (ret >= 10 && (options & EXIT_STATUS))
|
||||
return ret - 10;
|
||||
if (ret >= 10)
|
||||
if (ret >= 10 && !(options & EXIT_STATUS_EXACT))
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
Reference in new issue
Block a user