Correct certain tokenizer error reporting for unclosed subshells

There was some confusion about the different pointers and offsets
in tokenizer_t::call_error.

Fixes #6281
This commit is contained in:
ridiculousfish 2019-11-08 16:53:13 -08:00
parent eb2386f3e3
commit ef8b5e4fa0
2 changed files with 24 additions and 19 deletions

View File

@ -645,7 +645,8 @@ static void test_tokenizer() {
do_test(token.has_value()); do_test(token.has_value());
do_test(token->type == token_type_t::error); do_test(token->type == token_type_t::error);
do_test(token->error == tokenizer_error_t::closing_unopened_subshell); do_test(token->error == tokenizer_error_t::closing_unopened_subshell);
do_test(token->error_offset == 4); do_test(token->offset == 4);
do_test(token->error_offset == 0);
} }
{ {
@ -4631,6 +4632,11 @@ static void test_highlighting() {
{L"stuff", highlight_role_t::param}, {L"stuff", highlight_role_t::param},
}); });
highlight_tests.push_back({
{L"echo", highlight_role_t::command},
{L")", highlight_role_t::error},
});
auto &vars = parser_t::principal_parser().vars(); auto &vars = parser_t::principal_parser().vars();
// Verify variables and wildcards in commands using /bin/cat. // Verify variables and wildcards in commands using /bin/cat.
vars.set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"}); vars.set(L"VARIABLE_IN_COMMAND", ENV_LOCAL, {L"a"});

View File

@ -184,31 +184,30 @@ tok_t tokenizer_t::read_string() {
} else if (c == L')') { } else if (c == L')') {
if (expecting.size() > 0 && expecting.back() == L'}') { if (expecting.size() > 0 && expecting.back() == L'}') {
return this->call_error(tokenizer_error_t::expected_bclose_found_pclose, return this->call_error(tokenizer_error_t::expected_bclose_found_pclose,
this->start, this->token_cursor, 1); this->token_cursor, this->token_cursor, 1);
} }
switch (paran_offsets.size()) { if (paran_offsets.empty()) {
case 0:
return this->call_error(tokenizer_error_t::closing_unopened_subshell, return this->call_error(tokenizer_error_t::closing_unopened_subshell,
this->start, this->token_cursor, 1); this->token_cursor, this->token_cursor, 1);
case 1: }
mode &= ~(tok_modes::subshell);
default:
paran_offsets.pop_back(); paran_offsets.pop_back();
if (paran_offsets.empty()) {
mode &= ~(tok_modes::subshell);
} }
expecting.pop_back(); expecting.pop_back();
} else if (c == L'}') { } else if (c == L'}') {
if (expecting.size() > 0 && expecting.back() == L')') { if (expecting.size() > 0 && expecting.back() == L')') {
return this->call_error(tokenizer_error_t::expected_pclose_found_bclose, return this->call_error(tokenizer_error_t::expected_pclose_found_bclose,
this->start, this->token_cursor, 1); this->token_cursor, this->token_cursor, 1);
} }
switch (brace_offsets.size()) { if (brace_offsets.empty()) {
case 0:
return this->call_error(tokenizer_error_t::closing_unopened_brace, return this->call_error(tokenizer_error_t::closing_unopened_brace,
this->token_cursor, this->start + wcslen(this->start)); this->token_cursor,
case 1: this->token_cursor + wcslen(this->token_cursor));
mode &= ~(tok_modes::curly_braces); }
default:
brace_offsets.pop_back(); brace_offsets.pop_back();
if (brace_offsets.empty()) {
mode &= ~(tok_modes::curly_braces);
} }
expecting.pop_back(); expecting.pop_back();
} else if (c == L'[') { } else if (c == L'[') {