mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-23 09:03:37 +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());
|
const wcstring src = str2wcstring(&txt.at(0), txt.size());
|
||||||
parse_node_tree_t parse_tree;
|
parse_node_tree_t parse_tree;
|
||||||
parse_error_list_t errors;
|
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)
|
if (! success)
|
||||||
{
|
{
|
||||||
stdout_buffer.append(L"Parsing failed:\n");
|
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");
|
stdout_buffer.append(L"(Reparsed with continue after error)\n");
|
||||||
parse_tree.clear();
|
parse_tree.clear();
|
||||||
errors.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);
|
const wcstring dump = parse_dump_tree(parse_tree, src);
|
||||||
stdout_buffer.append(dump);
|
stdout_buffer.append(dump);
|
||||||
|
|
|
@ -2452,7 +2452,8 @@ static void test_new_parser_errors(void)
|
||||||
}
|
}
|
||||||
tests[] =
|
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"end", parse_error_unbalancing_end},
|
||||||
{L"echo hi ; 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_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_end, //end outside of block
|
||||||
parse_error_unbalancing_else, //else outside of if
|
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);
|
void accept_tokens(parse_token_t token1, parse_token_t token2);
|
||||||
|
|
||||||
/* Report tokenizer errors */
|
/* 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 */
|
/* Indicate if we hit a fatal error */
|
||||||
bool has_fatal_error(void) const
|
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);
|
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)
|
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;
|
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;
|
parse_ll_t parser;
|
||||||
parser.set_should_generate_error_messages(errors != NULL);
|
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 */
|
/* 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)
|
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 */
|
/* Handle errors */
|
||||||
|
|
|
@ -197,7 +197,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The big entry point. Parse a string! */
|
/* 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:
|
/* 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
|
// We detect this via an 'end_command' block without source
|
||||||
bool has_unclosed_block = false;
|
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
|
// Parse the input string into a parse tree
|
||||||
// Some errors are detected here
|
// Some errors are detected here
|
||||||
bool parsed = parse_tree_from_string(buff_src, parse_flag_leave_unterminated, &node_tree, &parse_errors);
|
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)
|
if (! parsed)
|
||||||
{
|
{
|
||||||
errored = true;
|
errored = true;
|
||||||
|
@ -1120,7 +1138,7 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src, pars
|
||||||
if (errored)
|
if (errored)
|
||||||
res |= PARSER_TEST_ERROR;
|
res |= PARSER_TEST_ERROR;
|
||||||
|
|
||||||
if (has_unclosed_block)
|
if (has_unclosed_block || has_unclosed_quote)
|
||||||
res |= PARSER_TEST_INCOMPLETE;
|
res |= PARSER_TEST_INCOMPLETE;
|
||||||
|
|
||||||
if (out_errors)
|
if (out_errors)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user