zsh-workers
 help / color / mirror / code / Atom feed
* Is this intentional behavior of typeset -g ?
@ 2024-02-16 20:09 Bart Schaefer
  2024-02-17  6:29 ` Regression of typeset output with "private" Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Bart Schaefer @ 2024-02-16 20:09 UTC (permalink / raw)
  To: Zsh hackers list

Just noticed that this:
  typeset -g foo=global
  local foo=local
changes the scope of "foo" from global** to local, but this:
  local foo=local
  typeset -g foo=global
does NOT assign to "foo" in the global** scope, it just continues to
apply to the local.

** "global" meaning any surrounding dynamic scope possibly up to the top level.

That is, the -g option starts "searching" at the current scope and
stops as soon as it encounters a declaration (even if the name is
unset), rather than (as one might think) starting one level above the
current.  Note prior mention of how ungainly it is to insert new
parameters at a surrounding scope, so I'm pretty sure this has always
been this way.

If this is legitimately the expected behavior (and it seems to be the
historic and possibly necessary behavior) there may be an easy
workaround for the "typeset -n" issue that was reported in
workers/52530 (or maybe this doesn't help at all, I haven't worked
through details yet).

Tangentially, I think there's a regression with "private":

() {
  zmodload zsh/param/private
  private foo=local
  typeset -p foo
}

That now prints nothing, whereas in e.g. 5.7 it would say
  typeset foo=local
which isn't precisely accurate either.


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Regression of typeset output with "private"
  2024-02-16 20:09 Is this intentional behavior of typeset -g ? Bart Schaefer
@ 2024-02-17  6:29 ` Bart Schaefer
  2024-02-18 19:35   ` Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Bart Schaefer @ 2024-02-17  6:29 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, Feb 16, 2024 at 12:09 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> Tangentially, I think there's a regression with "private":
>
> () {
>   zmodload zsh/param/private
>   private foo=local
>   typeset -p foo
> }
>
> That now prints nothing, whereas in e.g. 5.7 it would say
>   typeset foo=local
> which isn't precisely accurate either.

Traced this to here:

>> commit f99f7dca7552d21782354f675c0741896c9785f1
>> Author: Peter Stephenson <p.stephenson@samsung.com>
>> Date:   Mon Oct 8 10:10:42 2018 +0100
>>
>>     43616: Various parameter setting and display fixes.

Specifically to this (pardon any excessive gmail line wrapping):

-    if (printflags & PRINT_TYPESET) {
-       if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
-           (PM_READONLY|PM_SPECIAL) ||
-           (p->node.flags & PM_AUTOLOAD)) {
+    if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
+       if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
            /*
             * It's not possible to restore the state of
             * these, so don't output.
             */
            return;
        }


Leaving out PM_RO_BY_DESIGN restores the old behavior.  I understand
the motivation here (the comment), and if we were printing all values
("typeset -p" with no other arguments) it would make more sense, but
in the context of explicitly asking for "typeset -p foo" it surely
ought to print ... something?


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Regression of typeset output with "private"
  2024-02-17  6:29 ` Regression of typeset output with "private" Bart Schaefer
@ 2024-02-18 19:35   ` Bart Schaefer
  2024-02-20  4:54     ` [PATCH] (take 2) Local specials and " Bart Schaefer
  0 siblings, 1 reply; 4+ messages in thread
From: Bart Schaefer @ 2024-02-18 19:35 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]

On Fri, Feb 16, 2024 at 10:29 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> Traced this to here:
>
> >> commit f99f7dca7552d21782354f675c0741896c9785f1
> >> Author: Peter Stephenson <p.stephenson@samsung.com>
> >> Date:   Mon Oct 8 10:10:42 2018 +0100
> >>
> >>     43616: Various parameter setting and display fixes.
>
> in the context of explicitly asking for "typeset -p foo" it surely
> ought to print ... something?

How about this?  It skips PM_RO_BY_DESIGN for any parameter not
declared in the same scope where "typeset -p" is being run.  This
means that in addition to displaying parameters declared private,
it'll show cases where "local +h" has been used to shadow a special.

No doc included in this patch, but we should probably mention
somewhere that "typeset -p" no longer displays values for the special
parameters $!, $#, $-, $*, $@, $$, $?, $ARGC, etc. (unless "local +h"
per above)  This is actually a change in 5.9 vs. 5.8 that was not
included in the NEWS file.  Should it also be in the Doc?

[-- Attachment #2: private-p.txt --]
[-- Type: text/plain, Size: 1932 bytes --]

diff --git a/Src/params.c b/Src/params.c
index a722a20f6..ee5733af4 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6025,13 +6025,21 @@ printparamnode(HashNode hn, int printflags)
 	printflags |= PRINT_NAMEONLY;
 
     if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
-	if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
+	if (p->node.flags & PM_AUTOLOAD) {
 	    /*
 	     * It's not possible to restore the state of
 	     * these, so don't output.
 	     */
 	    return;
 	}
+	if (p->node.flags & PM_RO_BY_DESIGN) {
+	    /*
+	     * Compromise: cannot be restored out of context,
+	     * but show anyway if printed in scope of declaration
+	     */
+	    if (p->level != locallevel || p->level == 0)
+		return;
+	}
 	/*
 	 * The zsh variants of export -p/readonly -p also report other
 	 * flags to indicate other attributes or scope. The POSIX variants
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 9eeda0f47..11ac92f03 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -328,6 +328,7 @@ F:future revision will create a global with this assignment
 F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 *?*read-only variable: ptr2
 
  () {
@@ -348,10 +349,12 @@ F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 F:Assignment silently fails, is that correct?
 >typeset -n ptr1=ptr2
+>typeset -n ptr2=''
 >ptr1=ptr2
 >ptr1=
 >ptr2=
 >typeset -n ptr1=ptr2
+>typeset -n ptr2=''
 *?*no such variable: ptr2
 
  typeset ptr2
@@ -372,11 +375,13 @@ F:Assignment silently fails, is that correct?
 F:See K01typeset.ztst up-reference part 5
 F:Here ptr1 points to global ptr2 so assignment succeeds
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 >ptr1=ptr2
 >ptr2=val
 >ptr1=val
 >ptr2=val
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 >typeset ptr2=val
 
  () {

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] (take 2) Local specials and Re: Regression of typeset output with "private"
  2024-02-18 19:35   ` Bart Schaefer
@ 2024-02-20  4:54     ` Bart Schaefer
  0 siblings, 0 replies; 4+ messages in thread
From: Bart Schaefer @ 2024-02-20  4:54 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1604 bytes --]

On Sun, Feb 18, 2024 at 11:35 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> How about this?  It skips PM_RO_BY_DESIGN for any parameter not
> declared in the same scope where "typeset -p" is being run.  This
> means that in addition to displaying parameters declared private,
> it'll show cases where "local +h" has been used to shadow a special.

The more I think through this, the more I think it's the right thing
to do.  A couple of related observations:
1) It isn't necessary to use +h unless removing the -h attribute, the
default is to retain specialness even when local.  I usually include
it just for clarity, so in case we want to add it later I've left a
comment in the patch.
2) On the other hand, it is necessary to use -h for hiding, and
typeset -p did not preserve that flag on output before.

Consequently I've revised the patch to add the -h option for
parameters that have it.  This is also consistent with the output of
${(t)var} which shows the substring "hide".  The side-effect of this
is that private parameters are shown as having the -h property, which
is a bit closer to correct.

> [...] we should probably mention
> somewhere that "typeset -p" no longer displays values for the special
> parameters $!, $#, $-, $*, $@, $$, $?, $ARGC, etc.

Doc change added for this.  Also disabled "private -p" (it had already
been removed from the documentation) and update the doc to reflect
this.

> This is actually a change in 5.9 vs. 5.8 that was not
> included in the NEWS file.

I did not edit NEWS, yet.

This replaces workers/52557.

[-- Attachment #2: private-p2.txt --]
[-- Type: text/plain, Size: 7417 bytes --]

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 7a8654f27..784089594 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -2136,6 +2136,14 @@ tt(-p) may be followed by an optional integer argument.  Currently
 only the value tt(1) is supported.  In this case arrays and associative
 arrays are printed with newlines between indented elements for
 readability.
+
+The names and values of readonly special parameters
+(most of the parameters marked `<S>' in
+ifzman(zmanref(zshparam))ifnzman(noderef(Parameters Set By The Shell)),
+except those documented as settable)
+are not printed with `tt(-)tt(p)' because to execute those typeset commands
+would cause errors.  However, these parameters are printed when they
+have been made local to the scope where `tt(typeset -p)' is run.
 )
 item(tt(-T) [ var(scalar)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])(
 This flag has a different meaning when used with tt(-f); see below.
diff --git a/Doc/Zsh/mod_private.yo b/Doc/Zsh/mod_private.yo
index 08ac4cafe..24c099f38 100644
--- a/Doc/Zsh/mod_private.yo
+++ b/Doc/Zsh/mod_private.yo
@@ -16,9 +16,10 @@ The tt(private) builtin accepts all the same options and arguments as tt(local)
 (ifzman(zmanref(zshbuiltins))ifnzman(noderef(Shell Builtin Commands))) except
 for the `tt(-)tt(T)' option.  Tied parameters may not be made private.
 
-The `tt(-)tt(p)' option is presently a no-op because the state of
-private parameters cannot reliably be reloaded.  This also applies
-to printing private parameters with `tt(typeset -p)'.
+The `tt(-)tt(p)' option is presently disabled because the state of
+private parameters cannot reliably be reloaded.  When `tt(typeset -)tt(p)'
+outputs a private parameter, it is treated as a local with the
+`tt(-)tt(h)' (hide) option enabled.
 
 If used at the top level (outside a function scope), tt(private) creates a
 normal parameter in the same manner as tt(declare) or tt(typeset).  A
diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c
index 5003d4627..044617190 100644
--- a/Src/Modules/param_private.c
+++ b/Src/Modules/param_private.c
@@ -646,7 +646,7 @@ printprivatenode(HashNode hn, int printflags)
 
 static struct builtin bintab[] = {
     /* Copied from BUILTIN("local"), "P" added */
-    BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmprtux", "P")
+    BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmrtux", "P")
 };
 
 static struct features module_features = {
diff --git a/Src/params.c b/Src/params.c
index fce3af940..b329d2079 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5896,6 +5896,7 @@ static const struct paramtypes pmtypes[] = {
     { PM_ARRAY, "array", 'a', 0},
     { PM_HASHED, "association", 'A', 0},
     { 0, "local", 0, PMTF_TEST_LEVEL},
+    { PM_HIDE, "hide", 'h', 0 },
     { PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH},
     { PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
     { PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH},
@@ -6025,13 +6026,21 @@ printparamnode(HashNode hn, int printflags)
 	printflags |= PRINT_NAMEONLY;
 
     if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
-	if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
+	if (p->node.flags & PM_AUTOLOAD) {
 	    /*
 	     * It's not possible to restore the state of
 	     * these, so don't output.
 	     */
 	    return;
 	}
+	if (p->node.flags & PM_RO_BY_DESIGN) {
+	    /*
+	     * Compromise: cannot be restored out of context,
+	     * but show anyway if printed in scope of declaration
+	     */
+	    if (p->level != locallevel || p->level == 0)
+		return;
+	}
 	/*
 	 * The zsh variants of export -p/readonly -p also report other
 	 * flags to indicate other attributes or scope. The POSIX variants
@@ -6064,8 +6073,19 @@ printparamnode(HashNode hn, int printflags)
 	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
 	    int doprint = 0;
 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
-		if (p->level)
+		if (p->level) {
+		    /*
+		    if ((p->node.flags & PM_SPECIAL) &&
+			(p->node.flags & PM_LOCAL) &&
+			!(p->node.flags & PM_HIDE)) {
+			if (doneminus)
+			    putchar(' ');
+			printf("+h ");
+			doneminus = 0;
+		    }
+		    */
 		    doprint = 1;
+		}
 	    } else if ((pmptr->binflag != PM_EXPORTED || p->level ||
 			(p->node.flags & (PM_LOCAL|PM_ARRAY|PM_HASHED))) &&
 		       (p->node.flags & pmptr->binflag))
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 8b3988151..d90f17d13 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -959,6 +959,20 @@
 >  [three]=''
 >)
 
+ () {
+  local -h status
+  typeset -p status
+ }
+0:parameter hiding preserved by "typeset -p"
+>typeset -h status=''
+
+ () {
+  local status
+  typeset -p status
+ }
+0:read-only special params are output when localized
+>typeset -i10 -r status=0
+
  (export PATH MANPATH
  path=(/bin)
  MANPATH=/
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index ebb70dd92..ff48e2289 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -464,7 +464,7 @@ F:unexpected side-effects of previous tests
  }
 0:up-reference part 3, hidden global
 >outside
->typeset var
+>typeset -h var
 
  () {
    typeset notdef
@@ -541,7 +541,7 @@ F:Same test, should part 5 output look like this?
  fi
 0:up-reference part 3, autoloading with hidden special
 >nameref-local-nameref-local
->typeset parameters
+>typeset -h parameters
 
  if [[ $options[typesettounset] != on ]]; then
    ZTST_skip='Ignoring zmodload bug that resets TYPESET_TO_UNSET'
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 9eeda0f47..4140d4e96 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -28,7 +28,7 @@
  print $scalar_test
 0:basic scope hiding
 >toplevel
->local scalar_test
+>local hide scalar_test
 >0
 >toplevel
 
@@ -54,7 +54,7 @@
  print $+unset_test
 0:variable defined only in scope
 >0
->local unset_test
+>local hide unset_test
 >setme
 >0
 
@@ -70,7 +70,7 @@
  }
  print $array_test
 0:nested scope with different type, correctly restored
->local array_test
+>local hide array_test
 >in function
 >top level
 
@@ -113,7 +113,7 @@
  typeset -a hash_test=(top level)
  typeset -p hash_test
  inner () {
-  private -p hash_test
+  typeset -p hash_test
   print ${(t)hash_test} ${(kv)hash_test}
  }
  outer () {
@@ -328,6 +328,7 @@ F:future revision will create a global with this assignment
 F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 *?*read-only variable: ptr2
 
  () {
@@ -348,10 +349,12 @@ F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 F:Assignment silently fails, is that correct?
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2=''
 >ptr1=ptr2
 >ptr1=
 >ptr2=
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2=''
 *?*no such variable: ptr2
 
  typeset ptr2
@@ -372,11 +375,13 @@ F:Assignment silently fails, is that correct?
 F:See K01typeset.ztst up-reference part 5
 F:Here ptr1 points to global ptr2 so assignment succeeds
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 >ptr1=ptr2
 >ptr2=val
 >ptr1=val
 >ptr2=val
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 >typeset ptr2=val
 
  () {

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-02-20  4:55 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-16 20:09 Is this intentional behavior of typeset -g ? Bart Schaefer
2024-02-17  6:29 ` Regression of typeset output with "private" Bart Schaefer
2024-02-18 19:35   ` Bart Schaefer
2024-02-20  4:54     ` [PATCH] (take 2) Local specials and " Bart Schaefer

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).