Fix error messages for "and" and "or" after pipe

Fixes #6347
This commit is contained in:
Johannes Altmanninger 2019-11-25 12:47:33 +01:00
parent 97969a9363
commit f36705bb66
5 changed files with 41 additions and 11 deletions

View File

@ -178,6 +178,7 @@ enum parse_error_code_t {
parse_error_unbalancing_else, // else outside of if
parse_error_unbalancing_case, // case outside of switch
parse_error_bare_variable_assignment, // a=b without command
parse_error_andor_in_pipeline, // "and" or "or" after a pipe
};
enum { PARSER_TEST_ERROR = 1, PARSER_TEST_INCOMPLETE = 2 };

View File

@ -53,14 +53,23 @@ wcstring parse_error_t::describe_with_prefix(const wcstring &src, const wcstring
if (skip_caret && this->text.empty()) return L"";
wcstring result = prefix;
if (code == parse_error_bare_variable_assignment) {
wcstring assignment_src = src.substr(this->source_start, this->source_length);
maybe_t<size_t> equals_pos = variable_assignment_equals_pos(assignment_src);
assert(equals_pos);
wcstring variable = assignment_src.substr(0, *equals_pos);
wcstring value = assignment_src.substr(*equals_pos + 1);
append_format(result, ERROR_BAD_COMMAND_ASSIGN_ERR_MSG, variable.c_str(), value.c_str());
return result;
switch (code) {
default:
break;
case parse_error_andor_in_pipeline:
append_format(result, EXEC_ERR_MSG,
src.substr(this->source_start, this->source_length).c_str());
return result;
case parse_error_bare_variable_assignment: {
wcstring assignment_src = src.substr(this->source_start, this->source_length);
maybe_t<size_t> equals_pos = variable_assignment_equals_pos(assignment_src);
assert(equals_pos);
wcstring variable = assignment_src.substr(0, *equals_pos);
wcstring value = assignment_src.substr(*equals_pos + 1);
append_format(result, ERROR_BAD_COMMAND_ASSIGN_ERR_MSG, variable.c_str(),
value.c_str());
return result;
}
}
result.append(this->text);
if (skip_caret || source_start >= src.size() || source_start + source_length > src.size()) {
@ -929,6 +938,17 @@ void parse_ll_t::accept_tokens(parse_token_t token1, parse_token_t token2) {
if (production == nullptr) {
tnode_t<grammar::variable_assignments> variable_assignments;
if (const parse_node_t *parent = nodes.get_parent(node)) {
if (parent->type == symbol_statement &&
(token1.keyword == parse_keyword_and || token1.keyword == parse_keyword_or)) {
if (const parse_node_t *grandparent = nodes.get_parent(*parent)) {
if (grandparent->type == symbol_job_continuation) {
parse_error(token1, parse_error_andor_in_pipeline, L" "
/* won't be printed but must be non-empty, see
describe_with_prefix TODO clean that up */);
continue;
}
}
}
switch (parent->type) {
default:
break;

View File

@ -238,4 +238,7 @@ parsed_source_ref_t parse_source(wcstring src, parse_tree_flags_t flags, parse_e
/// The position of the equal sign in a variable assignment like foo=bar.
maybe_t<size_t> variable_assignment_equals_pos(const wcstring &txt);
/// Error message for improper use of the exec builtin.
#define EXEC_ERR_MSG _(L"The '%ls' command can not be used in a pipeline")
#endif

View File

@ -28,9 +28,6 @@
#include "wildcard.h"
#include "wutil.h" // IWYU pragma: keep
/// Error message for improper use of the exec builtin.
#define EXEC_ERR_MSG _(L"The '%ls' command can not be used in a pipeline")
/// Error message for use of backgrounded commands before and/or.
#define BOOL_AFTER_BACKGROUND_ERROR_MSG \
_(L"The '%ls' command can not be used immediately after a backgrounded job")

9
tests/checks/andor.fish Normal file
View File

@ -0,0 +1,9 @@
#RUN: %fish %s
set -xl LANG C # uniform quotes
eval 'true | and'
# CHECKERR: {{.*}}: The 'and' command can not be used in a pipeline
eval 'true | or'
# CHECKERR: {{.*}}: The 'or' command can not be used in a pipeline