From 38b95defbd3a777d77b6c1b23f47a435af3f55f9 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 9 Feb 2021 22:06:59 +0100 Subject: [PATCH] Inside an unclosed subshell, do not report other parse errors In an interactive shell, typing "for x in (" would print an error: fish: Expected end of the statement, but found a parse_token_type_t::tokenizer_error Our tokenizer converts "(" into a special error token, hence this message. Fix two cases by not reporting errors, but only if we allow parsing incomplete input. I'm not really sure if this is necessary, but it's sufficient. Fixes #7693 --- src/ast.cpp | 10 ++++++++++ src/fish_tests.cpp | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/ast.cpp b/src/ast.cpp index 5b1c3fbd8..9609c1d85 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -1111,6 +1111,11 @@ class ast_t::populator_t { if (!token.allows_token(peek_token().type)) { const auto &peek = peek_token(); + if ((flags_ & parse_flag_leave_unterminated) && + peek.tok_error == tokenizer_error_t::unterminated_subshell) { + return; + } + parse_error(peek, parse_error_generic, L"Expected %ls, but found %ls", token_types_user_presentable_description({TokTypes...}).c_str(), peek.user_presentable_description().c_str()); @@ -1134,6 +1139,11 @@ class ast_t::populator_t { keyword.unsourced = true; const auto &peek = peek_token(); + if ((flags_ & parse_flag_leave_unterminated) && + peek.tok_error == tokenizer_error_t::unterminated_subshell) { + return; + } + // Special error reporting for keyword_t. std::array allowed = {{KWs...}}; if (allowed.size() == 1 && allowed[0] == parse_keyword_t::kw_end) { diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index a35aa1d9e..8acb995d1 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -4790,6 +4790,14 @@ static void test_new_parser_ad_hoc() { // because we don't want to color it as an error. ast = ast_t::parse(L"a=", parse_flag_leave_unterminated); do_test(!ast.errored()); + + parse_error_list_t errors; + ast = ast_t::parse(L"begin; echo (", parse_flag_leave_unterminated, &errors); + do_test(errors.size() == 1 && errors.at(0).code == parse_error_tokenizer_unterminated_subshell); + + errors.clear(); + ast = ast_t::parse(L"for x in (", parse_flag_leave_unterminated, &errors); + do_test(errors.size() == 1 && errors.at(0).code == parse_error_tokenizer_unterminated_subshell); } static void test_new_parser_errors() {