zsh-workers
 help / color / mirror / code / Atom feed
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).