diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 17cf062a5..ff01bdbe3 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -3961,6 +3961,11 @@ static void test_highlighting() { {L"||", highlight_spec_operator}, {L"true", highlight_spec_command}, {L";", highlight_spec_statement_terminator}, + {L"and", highlight_spec_operator}, + {L"not", highlight_spec_operator}, + {L"!", highlight_spec_operator}, + {L"true", highlight_spec_command}, + {L";", highlight_spec_statement_terminator}, {L"end", highlight_spec_command}, {NULL, -1}}; diff --git a/src/highlight.cpp b/src/highlight.cpp index 0deff0590..1c91172d7 100644 --- a/src/highlight.cpp +++ b/src/highlight.cpp @@ -1033,7 +1033,6 @@ const highlighter_t::color_array_t &highlighter_t::highlight() { case symbol_if_clause: case symbol_else_clause: case symbol_case_item: - case symbol_not_statement: case symbol_decorated_statement: case symbol_if_statement: { this->color_children(node, parse_token_type_string, highlight_spec_command); @@ -1065,6 +1064,10 @@ const highlighter_t::color_array_t &highlighter_t::highlight() { this->color_node(node, highlight_spec_operator); break; + case symbol_not_statement: + this->color_children(node, parse_token_type_string, highlight_spec_operator); + break; + case symbol_job_decorator: this->color_node(node, highlight_spec_operator); break; diff --git a/src/parse_constants.h b/src/parse_constants.h index b4f679b6a..9deb0efc3 100644 --- a/src/parse_constants.h +++ b/src/parse_constants.h @@ -111,21 +111,30 @@ enum parse_keyword_t { parse_keyword_if, parse_keyword_in, parse_keyword_not, + parse_keyword_exclam, parse_keyword_or, parse_keyword_switch, parse_keyword_while, } __packed; -const enum_map keyword_enum_map[] = { - {parse_keyword_and, L"and"}, {parse_keyword_begin, L"begin"}, - {parse_keyword_builtin, L"builtin"}, {parse_keyword_case, L"case"}, - {parse_keyword_command, L"command"}, {parse_keyword_else, L"else"}, - {parse_keyword_end, L"end"}, {parse_keyword_exec, L"exec"}, - {parse_keyword_for, L"for"}, {parse_keyword_function, L"function"}, - {parse_keyword_if, L"if"}, {parse_keyword_in, L"in"}, - {parse_keyword_not, L"not"}, {parse_keyword_or, L"or"}, - {parse_keyword_switch, L"switch"}, {parse_keyword_while, L"while"}, - {parse_keyword_none, NULL}}; +const enum_map keyword_enum_map[] = {{parse_keyword_exclam, L"!"}, + {parse_keyword_and, L"and"}, + {parse_keyword_begin, L"begin"}, + {parse_keyword_builtin, L"builtin"}, + {parse_keyword_case, L"case"}, + {parse_keyword_command, L"command"}, + {parse_keyword_else, L"else"}, + {parse_keyword_end, L"end"}, + {parse_keyword_exec, L"exec"}, + {parse_keyword_for, L"for"}, + {parse_keyword_function, L"function"}, + {parse_keyword_if, L"if"}, + {parse_keyword_in, L"in"}, + {parse_keyword_not, L"not"}, + {parse_keyword_or, L"or"}, + {parse_keyword_switch, L"switch"}, + {parse_keyword_while, L"while"}, + {parse_keyword_none, NULL}}; #define keyword_enum_map_len (sizeof keyword_enum_map / sizeof *keyword_enum_map) // Node tag values. diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index a54f6fb49..c9bcd6f58 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -924,7 +924,8 @@ bool parse_execution_context_t::determine_io_chain(tnode_t not_statement) { job->set_flag(JOB_NEGATE, !job->get_flag(JOB_NEGATE)); - return this->populate_job_process(job, proc, not_statement.child<1>()); + return this->populate_job_process(job, proc, + not_statement.require_get_child()); } template diff --git a/src/parse_grammar.h b/src/parse_grammar.h index e08ccb62d..488bb9314 100644 --- a/src/parse_grammar.h +++ b/src/parse_grammar.h @@ -312,8 +312,10 @@ DEF(function_header) produces_sequence, argument, argument_list, tok_end>{ BODY(function_header)}; -DEF(not_statement) produces_sequence, statement> { - BODY(not_statement); +DEF_ALT(not_statement) { + using nots = seq, statement>; + using exclams = seq, statement>; + ALT_BODY(not_statement, nots, exclams); }; // An andor_job_list is zero or more job lists, where each starts with an `and` or `or` boolean diff --git a/src/parse_productions.cpp b/src/parse_productions.cpp index a09e28e13..fefb0377b 100644 --- a/src/parse_productions.cpp +++ b/src/parse_productions.cpp @@ -143,7 +143,8 @@ RESOLVE(statement) { switch (token1.type) { case parse_token_type_string: { switch (token1.keyword) { - case parse_keyword_not: { + case parse_keyword_not: + case parse_keyword_exclam: { return production_for(); } case parse_keyword_for: @@ -215,6 +216,19 @@ RESOLVE(case_item_list) { return production_for(); } +RESOLVE(not_statement) { + UNUSED(token2); + UNUSED(out_tag); + switch (token1.keyword) { + case parse_keyword_not: + return production_for(); + case parse_keyword_exclam: + return production_for(); + default: + return NO_PRODUCTION; + } +} + RESOLVE(andor_job_list) { UNUSED(out_tag); diff --git a/src/parse_tree.cpp b/src/parse_tree.cpp index f1f92fa5e..9c51025f4 100644 --- a/src/parse_tree.cpp +++ b/src/parse_tree.cpp @@ -960,7 +960,7 @@ static inline parse_keyword_t keyword_with_name(const wchar_t *name) { static bool is_keyword_char(wchar_t c) { return (c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z') || (c >= L'0' && c <= L'9') || - c == L'\'' || c == L'"' || c == L'\\' || c == '\n'; + c == L'\'' || c == L'"' || c == L'\\' || c == '\n' || c == L'!'; } /// Given a token, returns the keyword it matches, or parse_keyword_none. diff --git a/tests/andandoror.err b/tests/andandoror.err index ce5b602ba..60f61565c 100644 --- a/tests/andandoror.err +++ b/tests/andandoror.err @@ -8,5 +8,8 @@ #################### # && and || in while statements +#################### +# Nots + #################### # Complex scenarios diff --git a/tests/andandoror.in b/tests/andandoror.in index f739cc1ea..fff23d3b9 100644 --- a/tests/andandoror.in +++ b/tests/andandoror.in @@ -28,6 +28,14 @@ while [ $alpha -lt 2 ] && [ $beta -lt 3 ] set delta ( math $delta + 1 ) end +logmsg "Nots" + +true && ! false ; echo $status +not true && ! false ; echo $status +not not not true ; echo $status +not ! ! not true ; echo $status +not ! echo not ! ; echo $status + logmsg "Complex scenarios" begin; echo 1 ; false ; end || begin ; echo 2 && echo 3 ; end diff --git a/tests/andandoror.out b/tests/andandoror.out index 84f9f04f2..649267ebd 100644 --- a/tests/andandoror.out +++ b/tests/andandoror.out @@ -23,6 +23,15 @@ if test 4 ok 3 3 3 4 4 4 +#################### +# Nots +0 +1 +1 +0 +not ! +0 + #################### # Complex scenarios 1