Previously, interactive execution and --exec used two models for how a failed
command would impact other commands in the execution.
As an example, consider:
fdb> set foo bar ; set bar f\00 ; set baz foo
In interactive mode, this had the effect of {foo=bar, baz=foo}.
In --exec mode, this had the effect of {foo=bar}.
With this change, both now have the effect of {foo=bar}. This is achieved by
prefixing the last parsed command, which is the one that had the error, with a
fake "parse_error" token.
The execution of this would now look like:
ERROR: malformed escape sequence
>>> set foo bar
ERROR: Command failed to completely parse.
ERROR: Not running partial or malformed command: set bar
Which indicates how much execution occurred and where it halted, identically in
both modes of execution.
Previously, running a command like `set \xffx\02abcded/` would cause a crash.
The `x\02` is a malformed typo of `\x02`, and the previously existing code to
handle this case looks like
loop {
err = parse_command
if (err) continue;
// do things
}
Thus, if we hit an error, we'd go back to the top of the loop, and try again.
This should be an infinite loop. However, the actor compiler implementation of
loops involves function calls, so this actually turns into a series of the loop
head calling the loop body calling the loop head calling ... and we eventually
crash due to running out of stack.
This is now fixed by simply letting the code continue on to the check later
that does
if (there was an error) {
print nasty message
return error
}
With output that looks like
ERROR: malformed escape sequence
WARNING: the previous command failed, the remaining commands will not be executed.
And therefore the world becomes a happy place.