diff --git a/src/parse_constants.h b/src/parse_constants.h index d9abf4863..f2d2a8006 100644 --- a/src/parse_constants.h +++ b/src/parse_constants.h @@ -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 }; diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index 406872379..fce988a01 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -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 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 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 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; diff --git a/src/parse_tree.h b/src/parse_tree.h index 54b173266..d1f60834d 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -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 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 diff --git a/src/parse_util.cpp b/src/parse_util.cpp index 72edf9457..733590373 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -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") diff --git a/tests/checks/andor.fish b/tests/checks/andor.fish new file mode 100644 index 000000000..3d31dda4c --- /dev/null +++ b/tests/checks/andor.fish @@ -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