Hoist for loop control var to enclosing scope (#4376)

* Hoist `for` loop control var to enclosing scope

It should be possible to reference the last value assigned to a `for`
loop control var when the loop terminates. This makes it easier to detect
if we broke out of the loop among other things.  This change makes fish
`for` loops behave like most other shells.

Fixes #1935

* Remove redundant line
This commit is contained in:
Kurtis Rader
2017-09-08 21:14:26 -07:00
committed by ridiculousfish
parent 527e102746
commit 905766fca2
11 changed files with 166 additions and 45 deletions

View File

@@ -32,9 +32,9 @@ argparse: Implicit int short flag '#' does not allow modifiers like '='
####################
# Invalid arg in the face of a "#-val" spec
argparse: Unknown option '-x'
Standard input (line 38):
argparse '#-val' -- abc -x def
^
Standard input (line 41):
argparse '#-val' -- abc -x def
^
####################
# Defining a short flag more than once

View File

@@ -32,28 +32,42 @@ begin
end
logmsg Invalid \"#-val\" spec
argparse '#-val=' -- abc -x def
begin
argparse '#-val=' -- abc -x def
end
logmsg Invalid arg in the face of a \"#-val\" spec
argparse '#-val' -- abc -x def
begin
argparse '#-val' -- abc -x def
end
logmsg Defining a short flag more than once
argparse 's/short' 'x/xray' 's/long' -- -s -x --long
begin
argparse 's/short' 'x/xray' 's/long' -- -s -x --long
end
logmsg Defining a long flag more than once
argparse 's/short' 'x/xray' 'l/short' -- -s -x --long
begin
argparse 's/short' 'x/xray' 'l/short' -- -s -x --long
end
logmsg Defining an implicit int flag more than once
argparse '#-val' 'x/xray' 'v#val' -- -s -x --long
begin
argparse '#-val' 'x/xray' 'v#val' -- -s -x --long
end
logmsg Defining an implicit int flag with modifiers
argparse 'v#val=' --
begin
argparse 'v#val=' --
end
##########
# Now verify that validly formed invocations work as expected.
logmsg No args
argparse h/help --
begin
argparse h/help --
end
logmsg One arg and no matching flags
begin
@@ -80,47 +94,56 @@ begin
end
logmsg Implicit int flags work
for v in (set -l -n); set -e $v; end
argparse '#-val' -- abc -123 def
set -l
for v in (set -l -n); set -e $v; end
argparse 'v/verbose' '#-val' 't/token=' -- -123 a1 --token woohoo --234 -v a2 --verbose
set -l
begin
argparse '#-val' -- abc -123 def
set -l
end
begin
argparse 'v/verbose' '#-val' 't/token=' -- -123 a1 --token woohoo --234 -v a2 --verbose
set -l
end
logmsg Should be set to 987
for v in (set -l -n); set -e $v; end
argparse 'm#max' -- argle -987 bargle
set -l
begin
argparse 'm#max' -- argle -987 bargle
set -l
end
logmsg Should be set to 765
for v in (set -l -n); set -e $v; end
argparse 'm#max' -- argle -987 bargle --max 765
set -l
begin
argparse 'm#max' -- argle -987 bargle --max 765
set -l
end
logmsg Bool short flag only
for v in (set -l -n); set -e $v; end
argparse 'C' 'v' -- -C -v arg1 -v arg2
set -l
begin
argparse 'C' 'v' -- -C -v arg1 -v arg2
set -l
end
logmsg Value taking short flag only
for v in (set -l -n); set -e $v; end
argparse 'x=' 'v/verbose' -- --verbose arg1 -v -x arg2
set -l
begin
argparse 'x=' 'v/verbose' -- --verbose arg1 -v -x arg2
set -l
end
logmsg Implicit int short flag only
for v in (set -l -n); set -e $v; end
argparse 'x#' 'v/verbose' -- -v -v argle -v -x 321 bargle
set -l
begin
argparse 'x#' 'v/verbose' -- -v -v argle -v -x 321 bargle
set -l
end
logmsg Implicit int short flag only with custom validation passes
for v in (set -l -n); set -e $v; end
argparse 'x#!_validate_int --max 500' 'v/verbose' -- -v -v -x 499 -v
set -l
begin
argparse 'x#!_validate_int --max 500' 'v/verbose' -- -v -v -x 499 -v
set -l
end
logmsg Implicit int short flag only with custom validation fails
for v in (set -l -n); set -e $v; end
argparse 'x#!_validate_int --min 500' 'v/verbose' -- -v -v -x 499 -v
set -l
begin
argparse 'x#!_validate_int --min 500' 'v/verbose' -- -v -v -x 499 -v
set -l
end
##########
# Verify that flag value validation works.

View File

@@ -38,6 +38,9 @@ fish: You cannot use read-only variable 'status' in a for loop
for status in a b c
^
####################
# For loop control vars available outside the for block
####################
# Comments allowed in between lines (#1987)

View File

@@ -155,6 +155,35 @@ for status in a b c
echo $status
end
logmsg For loop control vars available outside the for block
begin
set -l loop_var initial-value
for loop_var in a b c
# do nothing
end
set --show loop_var
end
set -g loop_var global_val
function loop_test
for loop_var in a b c
if test $loop_var = b
break
end
end
set --show loop_var
end
loop_test
set --show loop_var
begin
set -l loop_var
for loop_var in aa bb cc
end
set --show loop_var
end
set --show loop_var
logmsg 'Comments allowed in between lines (#1987)'
echo before comment \
# comment

View File

@@ -90,6 +90,36 @@ Checking for infinite loops in no-execute
####################
# For loops with read-only vars is an error (#4342)
####################
# For loop control vars available outside the for block
$loop_var: set in local scope, unexported, with 1 elements
$loop_var[1]: length=1 value=|c|
$loop_var: not set in global scope
$loop_var: not set in universal scope
$loop_var: set in local scope, unexported, with 1 elements
$loop_var[1]: length=1 value=|b|
$loop_var: set in global scope, unexported, with 1 elements
$loop_var[1]: length=10 value=|global_val|
$loop_var: not set in universal scope
$loop_var: not set in local scope
$loop_var: set in global scope, unexported, with 1 elements
$loop_var[1]: length=10 value=|global_val|
$loop_var: not set in universal scope
$loop_var: set in local scope, unexported, with 1 elements
$loop_var[1]: length=2 value=|cc|
$loop_var: set in global scope, unexported, with 1 elements
$loop_var[1]: length=10 value=|global_val|
$loop_var: not set in universal scope
$loop_var: not set in local scope
$loop_var: set in global scope, unexported, with 1 elements
$loop_var[1]: length=10 value=|global_val|
$loop_var: not set in universal scope
####################
# Comments allowed in between lines (#1987)
before comment after comment