Restore error messages for bare variable assignment

Since #6287, bare variable assignments do not parse, which broke
the "Unsupported use of '='" error message.

This commit catches parse errors that occur on bare variable assignments.
When a statement node fails to parse, then we check if there is at least one
prefixing variable assignment. If so, we emit the old error message.

See also #6347
This commit is contained in:
Johannes Altmanninger 2019-11-25 09:19:53 +01:00
parent 563bdf3cc7
commit 97969a9363
3 changed files with 60 additions and 5 deletions

View file

@ -174,9 +174,10 @@ enum parse_error_code_t {
parse_error_tokenizer_unterminated_escape,
parse_error_tokenizer_other,
parse_error_unbalancing_end, // end outside of block
parse_error_unbalancing_else, // else outside of if
parse_error_unbalancing_case // case outside of switch
parse_error_unbalancing_end, // end outside of block
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
};
enum { PARSER_TEST_ERROR = 1, PARSER_TEST_INCOMPLETE = 2 };

View file

@ -53,6 +53,15 @@ 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;
}
result.append(this->text);
if (skip_caret || source_start >= src.size() || source_start + source_length > src.size()) {
return result;
@ -918,8 +927,45 @@ void parse_ll_t::accept_tokens(parse_token_t token1, parse_token_t token2) {
production_for_token(stack_elem.type, token1, token2, &tag);
node.tag = tag;
if (production == nullptr) {
parse_error_failed_production(stack_elem, token1);
// The above sets fatal_errored, which ends the loop.
tnode_t<grammar::variable_assignments> variable_assignments;
if (const parse_node_t *parent = nodes.get_parent(node)) {
switch (parent->type) {
default:
break;
case symbol_job:
variable_assignments =
tnode_t<grammar::job>(&nodes, parent)
.try_get_child<grammar::variable_assignments, 0>();
break;
case symbol_job_continuation:
variable_assignments =
tnode_t<grammar::job_continuation>(&nodes, parent)
.try_get_child<grammar::variable_assignments, 2>();
break;
case symbol_not_statement:
variable_assignments =
tnode_t<grammar::not_statement>(&nodes, parent)
.try_get_child<grammar::variable_assignments, 1>();
break;
}
}
tnode_t<grammar::variable_assignment> variable_assignment;
tnode_t<grammar::tok_string> assignment_tok;
if (variable_assignments &&
(variable_assignment =
variable_assignments.try_get_child<grammar::variable_assignment, 0>()) &&
(assignment_tok = variable_assignment.try_get_child<grammar::tok_string, 0>())) {
parse_token_t token(parse_token_type_string);
token.source_start = assignment_tok.source_range()->start;
token.source_length = assignment_tok.source_range()->length;
parse_error(token, parse_error_bare_variable_assignment,
L" " /* won't be printed but must be non-empty, see
describe_with_prefix */
);
} else {
parse_error_failed_production(stack_elem, token1);
}
// The above set fatal_errored, which ends the loop.
} else {
bool is_terminate = (token1.type == parse_token_type_terminate);

View file

@ -76,3 +76,11 @@ complete -C'a=b xalias '
alias envxalias='a=b x'
complete -C'a=b envxalias '
# CHECK: arg
# Eval invalid grammar to allow fish to parse this file
eval 'a=(echo b)'
# CHECKERR: {{.*}}: Unsupported use of '='. In fish, please use 'set a (echo b)'.
eval ': | a=b'
# CHECKERR: {{.*}}: Unsupported use of '='. In fish, please use 'set a b'.
eval 'not a=b'
# CHECKERR: {{.*}}: Unsupported use of '='. In fish, please use 'set a b'.