mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 04:58:57 +00:00
Allow parse_util_detect_errors to treat incomplete strings as errors
Fixes bug where sourcing a file with an unclosed quote would not have a backtrace
This commit is contained in:
parent
f6a89d13c2
commit
5e60efefbf
4 changed files with 23 additions and 12 deletions
|
@ -447,7 +447,7 @@ static int builtin_complete(parser_t &parser, wchar_t **argv)
|
|||
{
|
||||
const wcstring condition_string = condition;
|
||||
parse_error_list_t errors;
|
||||
if (parse_util_detect_errors(condition_string, &errors))
|
||||
if (parse_util_detect_errors(condition_string, &errors, false /* do not accept incomplete */))
|
||||
{
|
||||
append_format(stderr_buffer,
|
||||
L"%ls: Condition '%ls' contained a syntax error",
|
||||
|
|
|
@ -1149,7 +1149,7 @@ parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t
|
|||
tmp.append(paran_end+1);
|
||||
|
||||
parse_error_list_t subst_errors;
|
||||
err |= parse_util_detect_errors(subst, &subst_errors);
|
||||
err |= parse_util_detect_errors(subst, &subst_errors, false /* do not accept incomplete */);
|
||||
|
||||
/* Our command substitution produced error offsets relative to its source. Tweak the offsets of the errors in the command substitution to account for both its offset within the string, and the offset of the node */
|
||||
size_t error_offset = (paran_begin + 1 - arg_cpy) + node.source_start;
|
||||
|
@ -1212,7 +1212,7 @@ parser_test_error_bits_t parse_util_detect_errors_in_argument(const parse_node_t
|
|||
return err;
|
||||
}
|
||||
|
||||
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors)
|
||||
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors, bool allow_incomplete)
|
||||
{
|
||||
parse_node_tree_t node_tree;
|
||||
parse_error_list_t parse_errors;
|
||||
|
@ -1227,31 +1227,41 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars
|
|||
bool has_unclosed_block = false;
|
||||
|
||||
// Whether there's an unclosed quote, and therefore unfinished
|
||||
// This is only set if allow_incomplete is set
|
||||
bool has_unclosed_quote = false;
|
||||
|
||||
// Parse the input string into a parse tree
|
||||
// Some errors are detected here
|
||||
bool parsed = parse_tree_from_string(buff_src, parse_flag_leave_unterminated, &node_tree, &parse_errors);
|
||||
|
||||
for (size_t i=0; i < parse_errors.size(); i++)
|
||||
if (allow_incomplete)
|
||||
{
|
||||
if (parse_errors.at(i).code == parse_error_tokenizer_unterminated_quote)
|
||||
for (size_t i=0; i < parse_errors.size(); i++)
|
||||
{
|
||||
// Remove this error, since we don't consider it a real error
|
||||
has_unclosed_quote = true;
|
||||
parse_errors.erase(parse_errors.begin() + i);
|
||||
i--;
|
||||
if (parse_errors.at(i).code == parse_error_tokenizer_unterminated_quote)
|
||||
{
|
||||
// Remove this error, since we don't consider it a real error
|
||||
has_unclosed_quote = true;
|
||||
parse_errors.erase(parse_errors.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #1238: If the only error was unterminated quote, then consider this to have parsed successfully. A better fix would be to have parse_tree_from_string return this information directly (but it would be a shame to munge up its nice bool return).
|
||||
if (parse_errors.empty() && has_unclosed_quote)
|
||||
{
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
if (! parsed)
|
||||
{
|
||||
errored = true;
|
||||
}
|
||||
|
||||
// has_unclosed_quote may only be set if allow_incomplete is true
|
||||
assert(! has_unclosed_quote || allow_incomplete);
|
||||
|
||||
// Expand all commands
|
||||
// Verify 'or' and 'and' not used inside pipelines
|
||||
// Verify pipes via parser_is_pipe_forbidden
|
||||
|
|
|
@ -178,7 +178,8 @@ wcstring parse_util_escape_string_with_quote(const wcstring &cmd, wchar_t quote)
|
|||
/** Given a string, parse it as fish code and then return the indents. The return value has the same size as the string */
|
||||
std::vector<int> parse_util_compute_indents(const wcstring &src);
|
||||
|
||||
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = NULL);
|
||||
/** Given a string, detect parse errors in it. If allow_incomplete is set, then if the string is incomplete (e.g. an unclosed quote), an error is not returned and the PARSER_TEST_INCOMPLETE bit is set in the return value. If allow_incomplete is not set, then incomplete strings result in an error. */
|
||||
parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, parse_error_list_t *out_errors = NULL, bool allow_incomplete = true);
|
||||
|
||||
/**
|
||||
Test if this argument contains any errors. Detected errors include syntax errors in command substitutions, improperly escaped characters and improper use of the variable expansion operator.
|
||||
|
|
|
@ -2544,7 +2544,7 @@ int reader_shell_test(const wchar_t *b)
|
|||
bstr.push_back(L'\n');
|
||||
|
||||
parse_error_list_t errors;
|
||||
int res = parse_util_detect_errors(bstr, &errors);
|
||||
int res = parse_util_detect_errors(bstr, &errors, true /* do accept incomplete */);
|
||||
|
||||
if (res & PARSER_TEST_ERROR)
|
||||
{
|
||||
|
@ -4220,7 +4220,7 @@ static int read_ni(int fd, const io_chain_t &io)
|
|||
}
|
||||
|
||||
parse_error_list_t errors;
|
||||
if (! parse_util_detect_errors(str, &errors))
|
||||
if (! parse_util_detect_errors(str, &errors, false /* do not accept incomplete */))
|
||||
{
|
||||
parser.eval(str, io, TOP);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue