mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
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 ||
This commit is contained in:
parent
8e9670ccd5
commit
e1dafeab01
7 changed files with 75 additions and 12 deletions
|
@ -121,7 +121,7 @@ static void prettify_node_recursive(const wcstring &source, const parse_node_tre
|
||||||
const bool is_root_case_list =
|
const bool is_root_case_list =
|
||||||
node_type == symbol_case_item_list && parent_type != symbol_case_item_list;
|
node_type == symbol_case_item_list && parent_type != symbol_case_item_list;
|
||||||
const bool is_if_while_header =
|
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);
|
(parent_type == symbol_if_clause || parent_type == symbol_while_header);
|
||||||
|
|
||||||
if (is_root_job_list || is_root_case_list || is_if_while_header) {
|
if (is_root_job_list || is_root_case_list || is_if_while_header) {
|
||||||
|
|
|
@ -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".
|
// An if condition has a job and a "tail" of andor jobs, e.g. "foo ; and bar; or baz".
|
||||||
tnode_t<g::job> condition_head = if_clause.child<1>();
|
tnode_t<g::job_conjunction> condition_head = if_clause.child<1>();
|
||||||
tnode_t<g::andor_job_list> condition_boolean_tail = if_clause.child<3>();
|
tnode_t<g::andor_job_list> condition_boolean_tail = if_clause.child<3>();
|
||||||
|
|
||||||
// Check the condition and the tail. We treat parse_execution_errored here as failure, in
|
// Check the condition and the tail. We treat parse_execution_errored here as failure, in
|
||||||
// accordance with historic behavior.
|
// 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) {
|
if (cond_ret == parse_execution_success) {
|
||||||
cond_ret = run_job_list(condition_boolean_tail, ib);
|
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;
|
parse_execution_result_t ret = parse_execution_success;
|
||||||
|
|
||||||
// The conditions of the while loop.
|
// The conditions of the while loop.
|
||||||
tnode_t<g::job> condition_head = header.child<1>();
|
tnode_t<g::job_conjunction> condition_head = header.child<1>();
|
||||||
tnode_t<g::andor_job_list> condition_boolean_tail = header.child<3>();
|
tnode_t<g::andor_job_list> condition_boolean_tail = header.child<3>();
|
||||||
|
|
||||||
// Run while the condition is true.
|
// Run while the condition is true.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Check the condition.
|
// 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) {
|
if (cond_ret == parse_execution_success) {
|
||||||
cond_ret = run_job_list(condition_boolean_tail, wb);
|
cond_ret = run_job_list(condition_boolean_tail, wb);
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ produces_sequence<if_clause, else_clause, end_command, arguments_or_redirections
|
||||||
BODY(if_statement)};
|
BODY(if_statement)};
|
||||||
|
|
||||||
DEF(if_clause)
|
DEF(if_clause)
|
||||||
produces_sequence<keyword<parse_keyword_if>, job, tok_end, andor_job_list, job_list>{
|
produces_sequence<keyword<parse_keyword_if>, job_conjunction, tok_end, andor_job_list, job_list>{
|
||||||
BODY(if_clause)};
|
BODY(if_clause)};
|
||||||
|
|
||||||
DEF_ALT(else_clause) {
|
DEF_ALT(else_clause) {
|
||||||
|
@ -294,7 +294,8 @@ produces_sequence<keyword<parse_keyword_for>, tok_string, keyword<parse_keyword_
|
||||||
};
|
};
|
||||||
|
|
||||||
DEF(while_header)
|
DEF(while_header)
|
||||||
produces_sequence<keyword<parse_keyword_while>, job, tok_end, andor_job_list>{BODY(while_header)};
|
produces_sequence<keyword<parse_keyword_while>, job_conjunction, tok_end, andor_job_list>{
|
||||||
|
BODY(while_header)};
|
||||||
|
|
||||||
DEF(begin_header) produces_single<keyword<parse_keyword_begin>>{BODY(begin_header)};
|
DEF(begin_header) produces_single<keyword<parse_keyword_begin>>{BODY(begin_header)};
|
||||||
|
|
||||||
|
|
|
@ -1057,14 +1057,14 @@ static bool detect_errors_in_backgrounded_job(tnode_t<grammar::job> job,
|
||||||
// foo & ; or bar
|
// foo & ; or bar
|
||||||
// if foo & ; end
|
// if foo & ; end
|
||||||
// while foo & ; end
|
// while foo & ; end
|
||||||
if (job.try_get_parent<g::if_clause>()) {
|
auto job_conj = job.try_get_parent<g::job_conjunction>();
|
||||||
|
if (job_conj.try_get_parent<g::if_clause>()) {
|
||||||
errored = append_syntax_error(parse_errors, source_range->start,
|
errored = append_syntax_error(parse_errors, source_range->start,
|
||||||
BACKGROUND_IN_CONDITIONAL_ERROR_MSG);
|
BACKGROUND_IN_CONDITIONAL_ERROR_MSG);
|
||||||
} else if (job.try_get_parent<g::while_header>()) {
|
} else if (job_conj.try_get_parent<g::while_header>()) {
|
||||||
errored = append_syntax_error(parse_errors, source_range->start,
|
errored = append_syntax_error(parse_errors, source_range->start,
|
||||||
BACKGROUND_IN_CONDITIONAL_ERROR_MSG);
|
BACKGROUND_IN_CONDITIONAL_ERROR_MSG);
|
||||||
} else if (auto jlist =
|
} else if (auto jlist = job_conj.try_get_parent<g::job_list>()) {
|
||||||
job.try_get_parent<g::job_conjunction>().try_get_parent<g::job_list>()) {
|
|
||||||
// This isn't very complete, e.g. we don't catch 'foo & ; not and bar'.
|
// 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.
|
// Fetch the job list and then advance it by one.
|
||||||
auto first_jconj = jlist.next_in_list<g::job_conjunction>();
|
auto first_jconj = jlist.next_in_list<g::job_conjunction>();
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Basic && and || support
|
||||||
|
|
||||||
|
####################
|
||||||
|
# && and || in if statements
|
||||||
|
|
||||||
|
####################
|
||||||
|
# && and || in while statements
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Complex scenarios
|
|
@ -1,7 +1,33 @@
|
||||||
# Test && and || support
|
logmsg "Basic && and || support"
|
||||||
|
|
||||||
echo first && echo second
|
echo first && echo second
|
||||||
echo third || echo fourth
|
echo third || echo fourth
|
||||||
true && false ; echo "true && false: $status"
|
true && false ; echo "true && false: $status"
|
||||||
true || false ; echo "true || false: $status"
|
true || false ; echo "true || false: $status"
|
||||||
true && false || true ; echo "true && false || true: $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
|
||||||
|
|
|
@ -1,6 +1,30 @@
|
||||||
|
|
||||||
|
####################
|
||||||
|
# Basic && and || support
|
||||||
first
|
first
|
||||||
second
|
second
|
||||||
third
|
third
|
||||||
true && false: 1
|
true && false: 1
|
||||||
true || false: 0
|
true || false: 0
|
||||||
true && false || true: 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
|
||||||
|
|
Loading…
Reference in a new issue