From e1dafeab01ae5b081af8016814725d3624eb953a Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Fri, 2 Mar 2018 10:23:57 -0800 Subject: [PATCH] Add && and || support to the conditions of if and while This updates the "boolean tail" feature of the if and while conditions to know about job_conjunction, thereby respecting && and || --- src/fish_indent.cpp | 2 +- src/parse_execution.cpp | 8 ++++---- src/parse_grammar.h | 5 +++-- src/parse_util.cpp | 8 ++++---- tests/andandoror.err | 12 ++++++++++++ tests/andandoror.in | 28 +++++++++++++++++++++++++++- tests/andandoror.out | 24 ++++++++++++++++++++++++ 7 files changed, 75 insertions(+), 12 deletions(-) diff --git a/src/fish_indent.cpp b/src/fish_indent.cpp index 801b835ca..12545786d 100644 --- a/src/fish_indent.cpp +++ b/src/fish_indent.cpp @@ -121,7 +121,7 @@ static void prettify_node_recursive(const wcstring &source, const parse_node_tre const bool is_root_case_list = node_type == symbol_case_item_list && parent_type != symbol_case_item_list; const bool is_if_while_header = - (node_type == symbol_job || node_type == symbol_andor_job_list) && + (node_type == symbol_job_conjunction || node_type == symbol_andor_job_list) && (parent_type == symbol_if_clause || parent_type == symbol_while_header); if (is_root_job_list || is_root_case_list || is_if_while_header) { diff --git a/src/parse_execution.cpp b/src/parse_execution.cpp index c23ca3fc8..06f31a624 100644 --- a/src/parse_execution.cpp +++ b/src/parse_execution.cpp @@ -244,12 +244,12 @@ parse_execution_result_t parse_execution_context_t::run_if_statement( } // An if condition has a job and a "tail" of andor jobs, e.g. "foo ; and bar; or baz". - tnode_t condition_head = if_clause.child<1>(); + tnode_t condition_head = if_clause.child<1>(); tnode_t condition_boolean_tail = if_clause.child<3>(); // Check the condition and the tail. We treat parse_execution_errored here as failure, in // accordance with historic behavior. - parse_execution_result_t cond_ret = run_1_job(condition_head, ib); + parse_execution_result_t cond_ret = run_job_conjunction(condition_head, ib); if (cond_ret == parse_execution_success) { cond_ret = run_job_list(condition_boolean_tail, ib); } @@ -527,13 +527,13 @@ parse_execution_result_t parse_execution_context_t::run_while_statement( parse_execution_result_t ret = parse_execution_success; // The conditions of the while loop. - tnode_t condition_head = header.child<1>(); + tnode_t condition_head = header.child<1>(); tnode_t condition_boolean_tail = header.child<3>(); // Run while the condition is true. for (;;) { // Check the condition. - parse_execution_result_t cond_ret = this->run_1_job(condition_head, wb); + parse_execution_result_t cond_ret = this->run_job_conjunction(condition_head, wb); if (cond_ret == parse_execution_success) { cond_ret = run_job_list(condition_boolean_tail, wb); } diff --git a/src/parse_grammar.h b/src/parse_grammar.h index 4dff823c2..99b021f4a 100644 --- a/src/parse_grammar.h +++ b/src/parse_grammar.h @@ -245,7 +245,7 @@ produces_sequence, job, tok_end, andor_job_list, job_list>{ +produces_sequence, job_conjunction, tok_end, andor_job_list, job_list>{ BODY(if_clause)}; DEF_ALT(else_clause) { @@ -294,7 +294,8 @@ produces_sequence, tok_string, keyword, job, tok_end, andor_job_list>{BODY(while_header)}; +produces_sequence, job_conjunction, tok_end, andor_job_list>{ + BODY(while_header)}; DEF(begin_header) produces_single>{BODY(begin_header)}; diff --git a/src/parse_util.cpp b/src/parse_util.cpp index d201c651e..83860912a 100644 --- a/src/parse_util.cpp +++ b/src/parse_util.cpp @@ -1057,14 +1057,14 @@ static bool detect_errors_in_backgrounded_job(tnode_t job, // foo & ; or bar // if foo & ; end // while foo & ; end - if (job.try_get_parent()) { + auto job_conj = job.try_get_parent(); + if (job_conj.try_get_parent()) { errored = append_syntax_error(parse_errors, source_range->start, BACKGROUND_IN_CONDITIONAL_ERROR_MSG); - } else if (job.try_get_parent()) { + } else if (job_conj.try_get_parent()) { errored = append_syntax_error(parse_errors, source_range->start, BACKGROUND_IN_CONDITIONAL_ERROR_MSG); - } else if (auto jlist = - job.try_get_parent().try_get_parent()) { + } else if (auto jlist = job_conj.try_get_parent()) { // This isn't very complete, e.g. we don't catch 'foo & ; not and bar'. // Fetch the job list and then advance it by one. auto first_jconj = jlist.next_in_list(); diff --git a/tests/andandoror.err b/tests/andandoror.err index e69de29bb..ce5b602ba 100644 --- a/tests/andandoror.err +++ b/tests/andandoror.err @@ -0,0 +1,12 @@ + +#################### +# Basic && and || support + +#################### +# && and || in if statements + +#################### +# && and || in while statements + +#################### +# Complex scenarios diff --git a/tests/andandoror.in b/tests/andandoror.in index 87b82d0bf..f2093039b 100644 --- a/tests/andandoror.in +++ b/tests/andandoror.in @@ -1,7 +1,33 @@ -# Test && and || support +logmsg "Basic && and || support" echo first && echo second echo third || echo fourth true && false ; echo "true && false: $status" true || false ; echo "true || false: $status" true && false || true ; echo "true && false || true: $status" + +logmsg "&& and || in if statements" + +if true || false ; echo "if test 1 ok" ; end +if true && false ; else; echo "if test 2 ok" ; end +if true && false ; or true ; echo "if test 3 ok" ; end +if [ 0 = 1 ] || [ 5 -ge 3 ] ; echo "if test 4 ok"; end + +logmsg "&& and || in while statements" + +set alpha 0 +set beta 0 +set gamma 0 +set delta 0 +while [ $alpha -lt 2 ] && [ $beta -lt 3 ] + and [ $gamma -lt 4 ] || [ $delta -lt 5 ] + echo $alpha $beta $gamma + set alpha ( math $alpha + 1 ) + set beta ( math $beta + 1 ) + set gamma ( math $gamma + 1 ) + set delta ( math $delta + 1 ) +end + +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 a1a62e7e8..e8f8f8bed 100644 --- a/tests/andandoror.out +++ b/tests/andandoror.out @@ -1,6 +1,30 @@ + +#################### +# Basic && and || support first second third true && false: 1 true || false: 0 true && false || true: 0 + +#################### +# && and || in if statements +if test 1 ok +if test 2 ok +if test 3 ok +if test 4 ok + +#################### +# && and || in while statements +0 0 0 +1 1 1 +2 2 2 +3 3 3 +4 4 4 + +#################### +# Complex scenarios +1 +2 +3