mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 03:54:04 +08:00
Fix for issue where unterminated quotes would attempt to be executed,
instead of continuing edit onto the next line.
This commit is contained in:
parent
b9394b9599
commit
dc8014562b
|
@ -4298,7 +4298,7 @@ int builtin_parse(parser_t &parser, wchar_t **argv)
|
|||
const wcstring src = str2wcstring(&txt.at(0), txt.size());
|
||||
parse_node_tree_t parse_tree;
|
||||
parse_error_list_t errors;
|
||||
bool success = parse_tree_from_string(src, parse_flag_none, &parse_tree, &errors, true);
|
||||
bool success = parse_tree_from_string(src, parse_flag_none, &parse_tree, &errors);
|
||||
if (! success)
|
||||
{
|
||||
stdout_buffer.append(L"Parsing failed:\n");
|
||||
|
@ -4311,7 +4311,7 @@ int builtin_parse(parser_t &parser, wchar_t **argv)
|
|||
stdout_buffer.append(L"(Reparsed with continue after error)\n");
|
||||
parse_tree.clear();
|
||||
errors.clear();
|
||||
parse_tree_from_string(src, parse_flag_continue_after_error, &parse_tree, &errors, true);
|
||||
parse_tree_from_string(src, parse_flag_continue_after_error, &parse_tree, &errors);
|
||||
}
|
||||
const wcstring dump = parse_dump_tree(parse_tree, src);
|
||||
stdout_buffer.append(dump);
|
||||
|
|
|
@ -2452,7 +2452,8 @@ static void test_new_parser_errors(void)
|
|||
}
|
||||
tests[] =
|
||||
{
|
||||
{L"echo (abc", parse_error_tokenizer},
|
||||
{L"echo 'abc", parse_error_tokenizer_unterminated_quote},
|
||||
{L"echo (abc", parse_error_tokenizer_unterminated_subshell},
|
||||
|
||||
{L"end", parse_error_unbalancing_end},
|
||||
{L"echo hi ; end", parse_error_unbalancing_end},
|
||||
|
|
|
@ -114,7 +114,11 @@ enum parse_error_code_t
|
|||
|
||||
parse_error_generic, // unclassified error types
|
||||
|
||||
parse_error_tokenizer, //tokenizer error
|
||||
//tokenizer errors
|
||||
parse_error_tokenizer_unterminated_quote,
|
||||
parse_error_tokenizer_unterminated_subshell,
|
||||
parse_error_tokenizer_unterminated_escape,
|
||||
parse_error_tokenizer_other,
|
||||
|
||||
parse_error_unbalancing_end, //end outside of block
|
||||
parse_error_unbalancing_else, //else outside of if
|
||||
|
|
|
@ -583,7 +583,7 @@ class parse_ll_t
|
|||
void accept_tokens(parse_token_t token1, parse_token_t token2);
|
||||
|
||||
/* Report tokenizer errors */
|
||||
void report_tokenizer_error(parse_token_t token, const wchar_t *tok_error);
|
||||
void report_tokenizer_error(parse_token_t token, int tok_err, const wchar_t *tok_error);
|
||||
|
||||
/* Indicate if we hit a fatal error */
|
||||
bool has_fatal_error(void) const
|
||||
|
@ -786,10 +786,31 @@ void parse_ll_t::parse_error_failed_production(struct parse_stack_element_t &sta
|
|||
}
|
||||
}
|
||||
|
||||
void parse_ll_t::report_tokenizer_error(parse_token_t token, const wchar_t *tok_error)
|
||||
void parse_ll_t::report_tokenizer_error(parse_token_t token, int tok_err_code, const wchar_t *tok_error)
|
||||
{
|
||||
assert(tok_error != NULL);
|
||||
this->parse_error(token, parse_error_tokenizer, L"%ls", tok_error);
|
||||
parse_error_code_t parse_error_code;
|
||||
switch (tok_err_code)
|
||||
{
|
||||
case TOK_UNTERMINATED_QUOTE:
|
||||
parse_error_code = parse_error_tokenizer_unterminated_quote;
|
||||
break;
|
||||
|
||||
case TOK_UNTERMINATED_SUBSHELL:
|
||||
parse_error_code = parse_error_tokenizer_unterminated_subshell;
|
||||
break;
|
||||
|
||||
case TOK_UNTERMINATED_ESCAPE:
|
||||
parse_error_code = parse_error_tokenizer_unterminated_escape;
|
||||
break;
|
||||
|
||||
case TOK_OTHER:
|
||||
default:
|
||||
parse_error_code = parse_error_tokenizer_other;
|
||||
break;
|
||||
|
||||
}
|
||||
this->parse_error(token, parse_error_code, L"%ls", tok_error);
|
||||
}
|
||||
|
||||
void parse_ll_t::parse_error(const wchar_t *expected, parse_token_t token)
|
||||
|
@ -1076,7 +1097,7 @@ static inline parse_token_t next_parse_token(tokenizer_t *tok)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t parse_flags, parse_node_tree_t *output, parse_error_list_t *errors, bool log_it)
|
||||
bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t parse_flags, parse_node_tree_t *output, parse_error_list_t *errors)
|
||||
{
|
||||
parse_ll_t parser;
|
||||
parser.set_should_generate_error_messages(errors != NULL);
|
||||
|
@ -1116,7 +1137,7 @@ bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t parse_flags,
|
|||
/* Handle tokenizer errors. This is a hack because really the parser should report this for itself; but it has no way of getting the tokenizer message */
|
||||
if (queue[1].type == parse_special_type_tokenizer_error)
|
||||
{
|
||||
parser.report_tokenizer_error(queue[1], tok_last(&tok));
|
||||
parser.report_tokenizer_error(queue[1], tok_get_error(&tok), tok_last(&tok));
|
||||
}
|
||||
|
||||
/* Handle errors */
|
||||
|
|
|
@ -197,7 +197,7 @@ public:
|
|||
};
|
||||
|
||||
/* The big entry point. Parse a string! */
|
||||
bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags, parse_node_tree_t *output, parse_error_list_t *errors, bool log_it = false);
|
||||
bool parse_tree_from_string(const wcstring &str, parse_tree_flags_t flags, parse_node_tree_t *output, parse_error_list_t *errors);
|
||||
|
||||
/* Fish grammar:
|
||||
|
||||
|
|
|
@ -992,9 +992,27 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars
|
|||
// We detect this via an 'end_command' block without source
|
||||
bool has_unclosed_block = false;
|
||||
|
||||
// Whether there's an unclosed quote, and therefore unfinished
|
||||
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 (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;
|
||||
|
@ -1120,7 +1138,7 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars
|
|||
if (errored)
|
||||
res |= PARSER_TEST_ERROR;
|
||||
|
||||
if (has_unclosed_block)
|
||||
if (has_unclosed_block || has_unclosed_quote)
|
||||
res |= PARSER_TEST_INCOMPLETE;
|
||||
|
||||
if (out_errors)
|
||||
|
|
Loading…
Reference in New Issue
Block a user