From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: [PATCH 7/3] Additional tests and documentation
Date: Sat, 11 Feb 2023 20:44:46 -0800 [thread overview]
Message-ID: <CAH+w=7axxtaqM0z8zYi13+ST7gJq2WBEjEUnmY87-wYjXmZC7w@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 512 bytes --]
I've been trying to keep each of these patches under 20k or so. I
guess 4+5 could have been left as one file, given how large 1 and now
7 ended up. Oh, well.
In addition to adding tests for new code and for the misc. cases
Oliver pointed out, I also moved a number of "unset"s from the end of
the tests that created parameters to the beginning of the next test
case that uses those parameter names. This should make the tests less
order-dependent and maybe the extra tests for side-effects could be
dropped.
[-- Attachment #2: nameref-7-test+doc.txt --]
[-- Type: text/plain, Size: 14088 bytes --]
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 97a82226b..92917c06c 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -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)
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 8b1c69c55..ef01794e6 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -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
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index 12db3f56a..d4914df7a 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -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
diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index 9af211090..1b834f41a 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -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
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index c7ecf0f64..946c00793 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -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))
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index a663194a7..61c2b006a 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -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
reply other threads:[~2023-02-12 4:45 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAH+w=7axxtaqM0z8zYi13+ST7gJq2WBEjEUnmY87-wYjXmZC7w@mail.gmail.com' \
--to=schaefer@brasslantern.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).