Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: break/continue vs. try-always



On Sun, 08 Jun 2014 19:11:15 -0700
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> On Jun 8, 10:50pm, Peter Stephenson wrote:
> } Subject: Re: break/continue vs. try-always
> }
> } On Sun, 08 Jun 2014 14:01:46 -0700
> } Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> } > } neater way to handle this would be to add an option to force break and
> } > } continue to respect function scope.
> } > 
> } > The problem with that solution is that it propagates downward
> } 
> } This is why I pointed out you could do
> }  
> } setopt localoptions localloops
> } () {
> }    setopt nolocalloops # or emulation or whatever
> }    # call user code
> } }
> } # localloops is restored on return here and used to cancel breaks /
> } # contflag before resuming user code at this point.
> 
> Ah, you didn't have the "setopt nolocalloops" in the anonymous scope
> the last time.   OK, this is fine, and it sets up up well in the event
> that the austin-group decides to impose this semantics for Issue 8
> (though it looks like they're going to make it unspecified instead).

This makes a break or continue at the end of a function produce a
warning.  It didn't seem worth a hard error, but presumably a break or
continue is usually intended to do something so it should be reported if
it doesn't.

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 7788cd7..31247f5 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1631,6 +1631,19 @@ tt(FUNCTION_ARGZERO) from on to off (or off to on) does not change the
 current value of tt($0).  Only the state upon entry to the function or
 script has an effect.  Compare tt(POSIX_ARGZERO).
 )
+pindex(LOCAL_LOOPS)
+pindex(NO_LOCAL_LOOPS)
+pindex(LOCALLOOPS)
+pindex(NOLOCALLOOPS)
+cindex(break, inside function)
+cindex(continue, inside function)
+cinde(function, scope of break and continue)
+item(tt(LOCAL_LOOPS))(
+When this option is not set, the effect of tt(break) and tt(continue)
+commands may propagate outside function scope, affecting loops in
+calling functions.  When this option is not set, a tt(break) or
+a tt(continue) that is not caught within a function produces a warning.
+)
 pindex(LOCAL_OPTIONS)
 pindex(NO_LOCAL_OPTIONS)
 pindex(LOCALOPTIONS)
diff --git a/Src/exec.c b/Src/exec.c
index 8249def..a5982a7 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4814,6 +4814,15 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	opts[XTRACE] = saveopts[XTRACE];
 	opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
 	opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+	opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
+    }
+
+    if (opts[LOCALLOOPS]) {
+	if (contflag)
+	    zwarn("`continue' active at end of function scope");
+	if (breaks)
+	    zwarn("`break' active at end of function scope");
+	contflag = breaks = 0;
     }
 
     endtrapscope();
diff --git a/Src/options.c b/Src/options.c
index 2163bff..6e4e7b9 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -180,6 +180,7 @@ static struct optname optns[] = {
 {{NULL, "listrowsfirst",      0},			 LISTROWSFIRST},
 {{NULL, "listtypes",	      OPT_ALL},			 LISTTYPES},
 {{NULL, "localoptions",	      OPT_EMULATE|OPT_KSH},	 LOCALOPTIONS},
+{{NULL, "localloops",	      OPT_EMULATE},		 LOCALLOOPS},
 {{NULL, "localpatterns",      OPT_EMULATE},		 LOCALPATTERNS},
 {{NULL, "localtraps",	      OPT_EMULATE|OPT_KSH},	 LOCALTRAPS},
 {{NULL, "login",	      OPT_SPECIAL},		 LOGINSHELL},
diff --git a/Src/zsh.h b/Src/zsh.h
index 05d582c..fa73961 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2129,6 +2129,7 @@ enum {
     LISTPACKED,
     LISTROWSFIRST,
     LISTTYPES,
+    LOCALLOOPS,
     LOCALOPTIONS,
     LOCALPATTERNS,
     LOCALTRAPS,
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index d9f2191..46b1837 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -430,7 +430,7 @@
   foo
   unfunction foo
 0:FUNCTION_ARGZERO option
->My name is ZTST_execchunk
+>My name is (anon)
 >My name is foo
 
   setopt _NO_glob_
@@ -1114,3 +1114,45 @@
 >1
 >1
 >2
+
+  for (( i = 0; i < 10; i++ )); do
+     () {
+        print $i
+        break
+     }
+  done
+0:NO_LOCAL_LOOPS
+>0
+
+  () {
+      emulate -L zsh
+      setopt localloops
+      for (( i = 0; i < 10; i++ )); do
+	  () {
+              setopt nolocalloops # ignored in parent
+              print $i
+              break
+	  }
+      done
+  }
+0:LOCAL_LOOPS
+>0
+>1
+>2
+>3
+>4
+>5
+>6
+>7
+>8
+>9
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index 745a13c..74111f6 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -260,8 +260,12 @@ $ZTST_redir"
 # Execute an indented chunk.  Redirections will already have
 # been set up, but we need to handle the options.
 ZTST_execchunk() {
+  setopt localloops # don't let continue & break propagate out
   options=($ZTST_testopts)
-  eval "$ZTST_code"
+  () {
+      unsetopt localloops
+      eval "$ZTST_code"
+  }
   ZTST_status=$?
   # careful... ksh_arrays may be in effect.
   ZTST_testopts=(${(kv)options[*]})

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author