From: Nicolas Williams Date: Fri, 26 Dec 2014 09:31:01 +0000 (-0600) Subject: Fix `foreach` non-progation of errors X-Git-Tag: jq-1.5rc1~29 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e51e916e3191176f2d2f64ada60f6f4304ed0f54;p=jq Fix `foreach` non-progation of errors Errors were being re-propagated as "break". Also add `error/0` builtin, which made this fix easier. --- diff --git a/builtin.c b/builtin.c index 5ef1b71..4ffdc3b 100644 --- a/builtin.c +++ b/builtin.c @@ -959,6 +959,7 @@ static block bind_bytecoded_builtins(block b) { #define LIBM_DD(name) "def " #name ": _" #name ";", static const char* const jq_builtins[] = { + "def error: error(.);", "def break: error(\"break\");", "def map(f): [.[] | f];", "def map_values(f): .[] |= f;", diff --git a/compile.c b/compile.c index 50a3d49..042161d 100644 --- a/compile.c +++ b/compile.c @@ -685,7 +685,16 @@ block gen_foreach(const char* varname, block source, block init, block update, b gen_op_bound(STOREV, state_var), // extract an output... extract, - // ...and output it + // ...and output it by jumping + // past the BACKTRACK that comes + // right after the loop body, + // which in turn is there + // because... + // + // (Incidentally, extract can also + // backtrack, e.g., if it calls + // empty, in which case we don't + // get here.) output), OP_HAS_VARIABLE)); block foreach = BLOCK(gen_op_simple(DUP), @@ -693,14 +702,14 @@ block gen_foreach(const char* varname, block source, block init, block update, b state_var, gen_op_target(FORK, loop), loop, - // At this point `foreach`'s input will be on - // top of the stack, and we don't want to output - // it, so we backtrack. + // ...at this point `foreach`'s original input + // will be on top of the stack, and we don't + // want to output it, so we backtrack. gen_op_simple(BACKTRACK)); - inst_set_target(output, foreach); + inst_set_target(output, foreach); // make that JUMP go bast the BACKTRACK at the end of the loop block handler = gen_cond(gen_call("_equal", BLOCK(gen_lambda(gen_const(jv_string("break"))), gen_lambda(gen_noop()))), gen_op_simple(BACKTRACK), - gen_call("break", gen_noop())); + gen_call("error", gen_noop())); return gen_try(foreach, handler); }