]> granicus.if.org Git - jq/commitdiff
Fix `foreach` non-progation of errors
authorNicolas Williams <nico@cryptonector.com>
Fri, 26 Dec 2014 09:31:01 +0000 (03:31 -0600)
committerNicolas Williams <nico@cryptonector.com>
Sat, 27 Dec 2014 05:05:20 +0000 (23:05 -0600)
Errors were being re-propagated as "break".

Also add `error/0` builtin, which made this fix easier.

builtin.c
compile.c

index 5ef1b714e6a4c66d0b306559c60bc72b9d8067e0..4ffdc3bf2fd0f062740a1e39539c9a65012caf3d 100644 (file)
--- 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;",
index 50a3d49ac4df8de30059eff7d2df6cb2f7d02d33..042161db8b0b576b87249f29d58d0738938cb304 100644 (file)
--- 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);
 }