aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-12-28 22:52:06 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2013-12-28 22:52:06 -0800
commita42711e31cdb41e3c504ed161c07e56698d29e7a (patch)
treec07fc05377ac525af7e009046c7bec2565ffc5d1
parentc632307eaa4fdd8ac09bb1a9bf031101b1e0b6a2 (diff)
Support for break/continue with new parser execution
-rw-r--r--parse_execution.cpp31
-rw-r--r--parser.cpp7
-rw-r--r--tests/test9.in34
-rw-r--r--tests/test9.out6
4 files changed, 76 insertions, 2 deletions
diff --git a/parse_execution.cpp b/parse_execution.cpp
index 4201c288..137b7e00 100644
--- a/parse_execution.cpp
+++ b/parse_execution.cpp
@@ -47,7 +47,7 @@ node_offset_t parse_execution_context_t::get_offset(const parse_node_t &node) co
bool parse_execution_context_t::should_cancel_execution(const block_t *block) const
{
- return block && block->skip;
+ return block && (block->skip || block->loop_status != LOOP_NORMAL);
}
int parse_execution_context_t::run_if_statement(const parse_node_t &statement)
@@ -228,6 +228,19 @@ int parse_execution_context_t::run_for_statement(const parse_node_t &header, con
fb->skip = 0;
this->run_job_list(block_contents, fb);
+
+ /* Handle break or continue */
+ if (fb->loop_status == LOOP_CONTINUE)
+ {
+ /* Reset the loop state */
+ fb->loop_status = LOOP_NORMAL;
+ fb->skip = false;
+ continue;
+ }
+ else if (fb->loop_status == LOOP_BREAK)
+ {
+ break;
+ }
}
return proc_get_last_status();
@@ -358,7 +371,21 @@ int parse_execution_context_t::run_while_statement(const parse_node_t &header, c
/* A while loop is a while loop! */
while (! this->should_cancel_execution(wb) && this->run_1_job(while_condition, wb) == EXIT_SUCCESS)
{
+ /* The block ought to go inside the loop (see #1212) */
this->run_job_list(block_contents, wb);
+
+ /* Handle break or continue */
+ if (wb->loop_status == LOOP_CONTINUE)
+ {
+ /* Reset the loop state */
+ wb->loop_status = LOOP_NORMAL;
+ wb->skip = false;
+ continue;
+ }
+ else if (wb->loop_status == LOOP_BREAK)
+ {
+ break;
+ }
}
/* Done */
@@ -562,7 +589,7 @@ wcstring_list_t parse_execution_context_t::determine_arguments(const parse_node_
}
/* Return if we had a wildcard problem */
- if (unmatched_wildcard && ! matched_wildcard)
+ if (out_unmatched_wildcard_node != NULL && unmatched_wildcard && ! matched_wildcard)
{
*out_unmatched_wildcard_node = unmatched_wildcard_node;
}
diff --git a/parser.cpp b/parser.cpp
index c6052781..bd0471df 100644
--- a/parser.cpp
+++ b/parser.cpp
@@ -2602,6 +2602,13 @@ int parser_t::eval_new_parser(const wcstring &cmd, const io_chain_t &io, enum bl
{
CHECK_BLOCK(1);
+ if (block_type != TOP && block_type != SUBST)
+ {
+ debug(1, INVALID_SCOPE_ERR_MSG, parser_t::get_block_desc(block_type));
+ bugreport();
+ return 1;
+ }
+
/* Parse the source into a tree, if we can */
parse_node_tree_t tree;
if (! parse_t::parse(cmd, parse_flag_none, &tree, NULL))
diff --git a/tests/test9.in b/tests/test9.in
index a38fbc7c..a16281f1 100644
--- a/tests/test9.in
+++ b/tests/test9.in
@@ -35,3 +35,37 @@ emit test3 foo bar
# test empty argument
emit
+
+echo "Test break and continue"
+# This should output Ping once
+for i in a b c
+ if not contains $i c ; continue ; end
+ echo Ping
+end
+
+# This should output Pong not at all
+for i in a b c
+ if not contains $i c ; break ; end
+ echo Pong
+end
+
+# This should output Foop three times, and Boop not at all
+set i a a a
+while contains $i a
+ set -e i[-1]
+ echo Foop
+ continue
+ echo Boop
+end
+
+# This should output Doop once
+set i a a a
+while contains $i a
+ set -e i[-1]
+ echo Doop
+ break
+ echo Darp
+end
+
+
+false
diff --git a/tests/test9.out b/tests/test9.out
index 8e19365c..cf9054f8 100644
--- a/tests/test9.out
+++ b/tests/test9.out
@@ -2,3 +2,9 @@ Testing that builtins can truncate files
abc
before:test1
received event test3 with args: foo bar
+Test break and continue
+Ping
+Foop
+Foop
+Foop
+Doop