fix: foreach should not break init backtracking with DUPN (#3266)
Simplifies the compilation of `foreach` to avoid the problem in #3227 by removing unnecessary `FORK ... BACKTRACK`. Does not address `reduce`, which is less trivial.
This commit is contained in:
1 parent
f65d088b75
commit
c70ae1ada4
2 files changed
+27
-39
No files matched your search
+19
-39
@@ -843,46 +843,26 @@ block gen_reduce(block source, block matcher, block init, block body) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
block gen_foreach(block source, block matcher, block init, block update, block extract) {
|
block gen_foreach(block source, block matcher, block init, block update, block extract) {
|
||||||
block output = gen_op_targetlater(JUMP);
|
|
||||||
block state_var = gen_op_var_fresh(STOREV, "foreach");
|
block state_var = gen_op_var_fresh(STOREV, "foreach");
|
||||||
block loop = BLOCK(gen_op_simple(DUPN),
|
return BLOCK(gen_op_simple(DUP),
|
||||||
// get a value from the source expression:
|
init,
|
||||||
source,
|
state_var,
|
||||||
// destructure the value into variable(s) for all the code
|
gen_op_simple(DUP),
|
||||||
// in the body to see
|
// get a value from the source expression:
|
||||||
bind_alternation_matchers(matcher,
|
source,
|
||||||
// load the loop state variable
|
// destructure the value into variable(s) for all the code
|
||||||
BLOCK(gen_op_bound(LOADV, state_var),
|
// in the body to see
|
||||||
// generate updated state
|
bind_alternation_matchers(matcher,
|
||||||
update,
|
// load the loop state variable
|
||||||
// save the updated state for value extraction
|
BLOCK(gen_op_bound(LOADV, state_var),
|
||||||
gen_op_simple(DUP),
|
// generate updated state
|
||||||
// save new state
|
update,
|
||||||
gen_op_bound(STOREV, state_var),
|
// save the updated state for value extraction
|
||||||
// extract an output...
|
gen_op_simple(DUP),
|
||||||
extract,
|
// save new state
|
||||||
// ...and output it by jumping
|
gen_op_bound(STOREV, state_var),
|
||||||
// past the BACKTRACK that comes
|
// extract an output...
|
||||||
// right after the loop body,
|
extract)));
|
||||||
// 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)));
|
|
||||||
block foreach = BLOCK(gen_op_simple(DUP),
|
|
||||||
init,
|
|
||||||
state_var,
|
|
||||||
gen_op_target(FORK, loop),
|
|
||||||
loop,
|
|
||||||
// ...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); // make that JUMP go bast the BACKTRACK at the end of the loop
|
|
||||||
return foreach;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
block gen_definedor(block a, block b) {
|
block gen_definedor(block a, block b) {
|
||||||
|
|||||||
@@ -2319,3 +2319,11 @@ try ltrimstr("x") catch "x", try rtrimstr("x") catch "x" | "ok"
|
|||||||
try ["OK", setpath([[1]]; 1)] catch ["KO", .]
|
try ["OK", setpath([[1]]; 1)] catch ["KO", .]
|
||||||
[]
|
[]
|
||||||
["KO","Cannot update field at array index of array"]
|
["KO","Cannot update field at array index of array"]
|
||||||
|
|
||||||
|
# regression test for #3227
|
||||||
|
foreach .[] as $x (0, 1; . + $x)
|
||||||
|
[1, 2]
|
||||||
|
1
|
||||||
|
3
|
||||||
|
2
|
||||||
|
4
|
||||||
Reference in new issue
Block a user