1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-06-08 08:16:05 +02:00

51403: Tests and documentation for 51402, clean up some other tests.

This commit is contained in:
Bart Schaefer 2023-02-12 11:57:31 -08:00
parent 3eed6f70cd
commit acb15e3cc9
7 changed files with 218 additions and 18 deletions

View File

@ -1,5 +1,9 @@
2023-02-12 Bart Schaefer <schaefer@zsh.org>
* 51403: Doc/Zsh/builtins.yo, Doc/Zsh/expn.yo, Doc/Zsh/func.yo,
Doc/Zsh/grammar.yo, Doc/Zsh/params.yo, Test/K01nameref.ztst:
Tests and documentation for 51402, clean up some other tests.
* 51402: Src/builtin.c, Src/loop.c, Src/params.c, Src/zsh.h:
Add ksh/bash features (unset -n, for ref), readonly refs,
better error checking and messages, code injection safety,

View File

@ -2041,12 +2041,13 @@ cindex(named reference)
cindex(reference, named)
The flag tt(-n) creates a em(named reference) to another parameter.
The second parameter need not exist at the time the reference is
created. No attributes except tt(-g) may be used in conjunction with
created. Only tt(-g) and tt(-r) may be used in conjunction with
tt(-n). The var(name) so created may not be an array element nor use
a subscript, but the var(value) assigned may be any valid parameter
name syntax, even a subscripted array element (including an associative
array element) or an array slice, which is evaluated when the named
reference is expanded.
reference is expanded. It is an error for a named reference to refer
to itself, even indirectly through a chain of references.
See ifzman(zmanref(zshexpn))ifnzman(noderef(Parameter Expansion)) and
ifzman(zmanref(zshparam))ifnzman(noderef(Parameters)) for details of the
behavior of named references.
@ -2443,7 +2444,7 @@ with the command `tt(zmodload -F zsh/rlimits b:unlimit)'.
)
findex(unset)
cindex(parameters, unsetting)
item(tt(unset) [ tt(-fmv) ] var(name) ...)(
item(tt(unset) [ tt(-fmv) ] [ tt(-n) ] var(name) ...)(
Each named parameter is unset.
Local parameters remain local even if unset; they appear unset within scope,
but the previous value will still reappear when the scope ends.
@ -2457,10 +2458,13 @@ be quoted) and all parameters with matching names are unset. Note that this
cannot be used when unsetting associative array elements, as the subscript
will be treated as part of the pattern.
The tt(-v) flag specifies that var(name) refers to parameters. This is the
default behaviour.
The tt(-v) flag specifies that var(name) refers to parameters. This is
the default behaviour. If the tt(-n) option is supplied, and
var(name) is a a named reference, var(name) will be unset rather than
the variable it references.
tt(unset -f) is equivalent to tt(unfunction).
tt(unset -f) is equivalent to tt(unfunction). The tt(-n) option has
no effect with tt(-f).
)
findex(unsetopt)
cindex(options, unsetting)

View File

@ -1581,7 +1581,10 @@ is interpreted at the time tt(${)var(pname)tt(}) is expanded. Any
form of subscript is allowed, including those that select individual
elements, substrings of scalar strings, or multiple elements as with
array slices or the `tt((i))', `tt((I))', `tt((r))', `tt((R))' and
`tt((w))' subscript flags.
`tt((w))' subscript flags. However, the subscript is evaluated with
the tt(NO_EXEC) option in effect, so command substitution and other
similar constructs produce no output, although are not syntactically
excluded.
When var(rname) is an array (but not an array element or slice), the
named reference may also be used in substitutions requiring an

View File

@ -13,6 +13,40 @@ Functions are executed like commands with the arguments
passed as positional parameters.
(See noderef(Command Execution).)
Parameters declared by any of the `tt(typeset)' family of commands
during the execution of a function become em(local) to the function
unless the `tt(-g)' option is used. This is the em(scope) of the
parameter, which extends dynamically to any other functions called by
the declaring function. In most cases, local parameters take the
place of any other parameter having the same name that was assigned or
declared in an earlier function scope.
(See noderef(Local Parameters).)
A named parameter declared with the `tt(-n)' option to any of the
`tt(typeset)' commands becomes a reference to a parameter in scope at
the time of assignment to the named reference, which may be at a
different call level than the declaring function. For this reason,
it is good practice to declare a named reference as soon as the
referent parameter is in scope, and as early as possible in the
function if the reference is to a parameter in a calling scope.
A typical use of named references is to pass the name
of the referent as a positional parameter. For example,
ifzman()
example(pop+LPAR()RPAR() {
local -n ref=$1
local last=$ref[$#ref]
ref[$#ref]=LPAR()RPAR()
print -r -- $last
}
array=LPAR() a list of five values RPAR()
pop array)
prints the word `tt(values)' and shortens `tt($array)' to
`tt(LPAR() a list of five RPAR())'. There are no local parameters in
tt(pop) at the time `tt(ref=$1)' is assigned, so `tt(ref)' becomes a
reference to `tt(array)' in the caller.
Functions execute in the same process as the caller and
share all files
and present working directory with the

View File

@ -187,6 +187,9 @@ Expand the list of var(word)s, and set the parameter
var(name) to each of them in turn, executing var(list)
each time. If the `tt(in) var(word)' is omitted,
use the positional parameters instead of the var(word)s.
If any var(name) has been declared as a named reference,
the corresponding var(word) is treated as the name of a
parameter and var(name) is made a reference to that.
The var(term) consists of one or more newline or tt(;)
which terminate the var(word)s, and are optional when the

View File

@ -656,8 +656,8 @@ When a em(named reference) is created with `tt(typeset -n)', all uses
of var(pname) in assignments and expansions instead assign to or
expand var(rname). This also applies to `tt(unset )var(pname)' and to
most subsequent uses of `tt(typeset)' with the exception of
`tt(typeset -n)' and `tt(typeset +n)', so to remove a named reference
it is necessary to use one of:
`tt(typeset -n)' and `tt(typeset +n)', so to remove a named reference,
use either `tt(unset -n )var(pname)' or one of:
ifzman()
example(tt(typeset -n )var(pname)
tt(typeset +n )var(pname))

View File

@ -23,6 +23,12 @@
ptr=var
typeset -n
0:assign nameref placeholder
>ptr=var
typeset ptr=var
typeset -n ptr
typeset -n
0:convert scalar to nameref
>ptr=var
typeset -n ptr=var
@ -46,6 +52,11 @@ F:Other type changes are fatal errors, should this also be?
>typeset -n ptr=var
>typeset -t var
typeset -n ptr=var[2]
typeset -t ptr
1:change type of referenced array element
*?*var\[2\]: can't change type via subscript reference
typeset -n ptr[1]=var
1:illegal nameref name
*?*reference variable cannot be an array
@ -91,6 +102,14 @@ F:Other type changes are fatal errors, should this also be?
typeset -p var
0:unset via nameref
typeset -n ptr=var
typeset var=value
unset -n ptr
typeset -p var ptr
0:unset of the nameref itself
F:If earlier tests change, might get "no such variable" here
>typeset var=value
typeset -n ptr=var
typeset var=value
typeset -p ptr var
@ -105,11 +124,11 @@ F:Other type changes are fatal errors, should this also be?
typeset -n ptr=var
ptr=value
typeset -p var ptr
unset var # for next test
0:assign new scalar via nameref
>typeset -g var=value
>typeset -n ptr=var
unset var
typeset -n ptr=var
typeset var=(val1 val2)
typeset -p ptr var
@ -132,11 +151,11 @@ F:unexpected side-effects of previous tests
typeset -n ptr=var
ptr=(val1 val2)
typeset -p var ptr
unset var # for next test
0:assign new array via nameref
>typeset -g -a var=( val1 val2 )
>typeset -n ptr=var
unset var
typeset -n ptr2=var
typeset -n ptr1=ptr2
typeset var=value
@ -178,12 +197,12 @@ F:unexpected side-effects of previous tests
typeset -n ptr1=ptr2
typeset ptr1=newvalue
typeset -p ptr1 ptr2 var
unset var # for next test
0:typeset new parameter indirectly
>typeset -n ptr1=ptr2
>typeset -n ptr2=var
>typeset var=newvalue
unset var
typeset -n ptr2=var
typeset -n ptr1=ptr2
typeset var=value
@ -219,19 +238,18 @@ F:unexpected side-effects of previous tests
typeset -n ptr1=ptr2
typeset ptr1=(val1 val2)
typeset -p ptr1 ptr2 var
unset var # for next test
0:typeset new array indirectly
>typeset -n ptr1=ptr2
>typeset -n ptr2=var
>typeset -a var=( val1 val2 )
typeset -p ptr1 ptr2 var
typeset -p ptr1 ptr2
1:check state of paramtab FOUR
F:unexpected side-effects of previous tests
*?*no such variable: ptr1
*?*no such variable: ptr2
*?*no such variable: var
unset var
typeset -n ptr2=var
typeset -n ptr1=ptr2
ptr1=(val1 val2)
@ -244,6 +262,20 @@ F:unexpected side-effects of previous tests
typeset -n ptr1=ptr2
typeset -n ptr2=ptr1
1:direct nameref loop not allowed
*?*invalid self reference
unset var
typeset -gn ptr1=var
typeset -p ptr1
0:global reference to unset var
>typeset -g -n ptr1=var
unset -n ptr1
typeset -gn ptr1
typeset -p ptr1
ptr1=ptr1
1:global direct reference
>typeset -g -n ptr1
*?*invalid self reference
typeset -n ptr1=ptr2
@ -252,28 +284,39 @@ F:unexpected side-effects of previous tests
1:indirect nameref loop not allowed
*?*invalid self reference
typeset -n ptr1 ptr2
ptr1=ptr2
ptr2=ptr1
1:looping assignment not allowed
*?*invalid self reference
unset -n ptr2
typeset -n ptr2='path[2]'
print -r -- $ptr2
0q:nameref to array element, no braces
>${path[2]}
unset -n ptr2
typeset -n ptr2='path[2]'
print -r -- ${ptr2}
0q:nameref to array element, with braces
>${path[2]}
unset -n ptr1
typeset -A hash=(x MISS y HIT)
typeset -n ptr1='hash[y]'
print -r -- $ptr1
0:nameref to hash element, no braces
>HIT
unset -n ptr1
typeset -A hash=(x MISS y HIT)
typeset -n ptr1='hash[y]'
print -r -- ${ptr1}
0:nameref to hash element, with braces
>HIT
unset -n ptr2
typeset -a ary=(1 2)
typeset -n ptr2='ary[2]'
ptr2=TWO
@ -281,6 +324,7 @@ F:unexpected side-effects of previous tests
0:assign array element by nameref
>typeset -a ary=( 1 TWO )
unset -n ptr2
typeset -n ptr2='ary[2]'
ptr2=TWO
typeset -p ary
@ -288,6 +332,7 @@ F:unexpected side-effects of previous tests
F:ksh93 does not implement this either
>typeset -a ary=( '' TWO )
unset -n ptr1
typeset -A hash=(x MISS y MISS)
typeset -n ptr1='hash[y]'
ptr1=HIT
@ -295,6 +340,7 @@ F:ksh93 does not implement this either
0:assign to hash element by nameref
>typeset -A hash=( [x]=MISS [y]=HIT )
unset -n ptr1
typeset -A hash
typeset -n ptr1='hash[y]'
ptr1=HIT
@ -303,10 +349,13 @@ F:ksh93 does not implement this either
F:ksh93 does not implement this either
>typeset -A hash=( [y]=HIT )
unset -n ptr1
typeset -n ptr1='not good'
1:invalid nameref
*?*invalid variable name: not good
unset -n ptr1
unset hash
typeset -A hash
typeset -n ptr1='hash[y]'
print ${ptr1::=HIT}
@ -316,24 +365,25 @@ F:ksh93 does not implement this either
>typeset -n ptr1='hash[y]'
>typeset -A hash=( [y]=HIT )
unset -n ptr
unset gval
typeset -n ptr=gval
gval=global
() { local gval=local; print $ptr; typeset -p ptr gval }
unset gval # for next test
0:up-reference part 1
>global
>typeset -g -n ptr=gval
>typeset gval=local
typeset -p ptr ptr1 ptr2 val gval
typeset -p ptr ptr1 ptr2 val
1:check state of paramtab FIVE
F:unexpected side-effects of previous tests
*?*no such variable: ptr
*?*no such variable: ptr1
*?*no such variable: ptr2
*?*no such variable: val
*?*no such variable: gval
unset gval
typeset -n ptr1=gval
typeset gval
() { typeset gval=local; ptr1=global }
@ -509,4 +559,106 @@ F:Same test, should part 5 output look like this?
>bry[2]
>ipsum
unset -n ref
unset var
typeset -n ref=var
typeset var=GLOBAL
() {
typeset -n ref=$1
print -r $ref
ref=RESET
typeset -p ref var
} ref
typeset -p ref var
0:local reference points to same-name global reference, part 1
>GLOBAL
>typeset -n ref=ref
>typeset -g var=RESET
>typeset -n ref=var
>typeset var=RESET
unset -n ref
unset var
typeset -n ref=var
() {
typeset -n ref=$1
print -r $ref
ref=RESET
typeset -p ref var
} ref
typeset -p ref var
0:local reference points to same-name global reference, part 2
>
>typeset -n ref=ref
>typeset -g var=RESET
>typeset -n ref=var
>typeset -g var=RESET
unset -n ref
unset one
typeset -n ref
typeset one=ONE
for ref in one ref two; do print -r $ref; done
1:for-loop variable is a reference, part 1
>ONE
*?*ref: invalid self reference
unset -n ref
unset one
typeset -n ref
() {
typeset one=ONE
for ref in one ref two; do print -r ${(t)ref}; done
}
1:for-loop variable is a reference, part 2
>scalar-local
*?*ref: invalid self reference
unset -n ref
unset one var
typeset -n ref=var
() {
typeset one=ONE
typeset -n ref=ref
for ref in one ref two; do
typeset -p ref
print -r $ref
done
typeset -p ref
}
typeset -p ref
0:for-loop variable is a reference, part 3
>typeset -n ref=one
>ONE
>typeset -n ref=ref
>
>typeset -n ref=two
>
>typeset -n ref=two
>typeset -n ref=var
unset -n ref
unset one
typeset -n ref
() {
setopt localoptions warn_nested_var
typeset one=ONE
for ref in one two; do print -r ${(t)ref}; done
typeset -n ref
for ref in one two; do print -r ${(t)ref}; done
}
0:for-loop variable is a reference, part 4, warnings
>scalar-local
>
>scalar-local
>
*?*ref: global reference to local variable: one
typeset -n ptr='ary[$(echo 2)]'
typeset -a ary=(one two three)
print $ptr
1:attempt deferred command substitution in subscript
F:runs in `setopt noexec` so $(...) returns nothing
*?*bad math expression: empty string
%clean