Teach parse_util_detect_errors about unterminated pipelines

Allow it to return PARSER_TEST_INCOMPLETE for code like
`echo | `
This commit is contained in:
ridiculousfish 2018-02-18 13:13:58 -08:00
parent 26ea8dc362
commit ddd1afc57c
2 changed files with 21 additions and 1 deletions

View file

@ -727,6 +727,18 @@ static void test_parser() {
err(L"redirection after 'end' wrongly reported as error");
}
if (parse_util_detect_errors(L"true | ") != PARSER_TEST_INCOMPLETE) {
err(L"unterminated pipe not reported properly");
}
if (parse_util_detect_errors(L"begin ; true ; end | ") != PARSER_TEST_INCOMPLETE) {
err(L"unterminated pipe not reported properly");
}
if (parse_util_detect_errors(L" | true ") != PARSER_TEST_ERROR) {
err(L"leading pipe not reported properly");
}
if (detect_argument_errors(L"foo")) {
err(L"simple argument reported as error");
}

View file

@ -1198,6 +1198,10 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
// source.
bool has_unclosed_block = false;
// Whether we encounter a missing statement, i.e. a newline after a pipe. This is found by
// detecting job_continuations that have source for pipes but not the statement.
bool has_unclosed_pipe = false;
// Whether there's an unclosed quote, and therefore unfinished. This is only set if
// allow_incomplete is set.
bool has_unclosed_quote = false;
@ -1243,6 +1247,9 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
if (node.type == symbol_end_command && !node.has_source()) {
// An 'end' without source is an unclosed block.
has_unclosed_block = true;
} else if (node.type == symbol_statement && !node.has_source()) {
// Check for a statement without source in a pipeline, i.e. unterminated pipeline.
has_unclosed_pipe |= statement_is_in_pipeline({&node_tree, &node}, false);
} else if (node.type == symbol_boolean_statement) {
// 'or' and 'and' can be in a pipeline, as long as they're first.
tnode_t<g::boolean_statement> gbs{&node_tree, &node};
@ -1290,7 +1297,8 @@ parser_test_error_bits_t parse_util_detect_errors(const wcstring &buff_src,
if (errored) res |= PARSER_TEST_ERROR;
if (has_unclosed_block || has_unclosed_quote) res |= PARSER_TEST_INCOMPLETE;
if (has_unclosed_block || has_unclosed_quote || has_unclosed_pipe)
res |= PARSER_TEST_INCOMPLETE;
if (out_errors != NULL) {
*out_errors = std::move(parse_errors);