zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] Declaring the same variable "private" more than once
@ 2023-09-05  3:52 Bart Schaefer
  0 siblings, 0 replies; only message in thread
From: Bart Schaefer @ 2023-09-05  3:52 UTC (permalink / raw)
  To: Zsh hackers list

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

Given that it's relatively harmless to do something like

  for x in *
  do
    local y=$x:r
    # etc.
  done

It occurred to me that it should similarly be possible to do that with
"local -P" or "private", but without the appended patch that generates
a warning message and leaves $y unchanged without aborting the loop.

With the below it remains an error to try to change the type of a
private parameter (and that is an actual error rather than just a
warning, like most other typeset errors) but simply reassigning
something of the same type is allowed.

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

diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c
index 8e04b2b95..7ef6633da 100644
--- a/Src/Modules/param_private.c
+++ b/Src/Modules/param_private.c
@@ -87,9 +87,52 @@ makeprivate(HashNode hn, UNUSED(int flags))
 	      ((pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL &&
 	       /* typeset_single() line 2300 discards PM_REMOVABLE -- why? */
 	       !is_private(pm->old))))) {
-	    zwarnnam("private", "can't change scope of existing param: %s",
-		     pm->node.nam);
-	    makeprivate_error = 1;
+	    if (is_private(pm->old)) {
+		if (pm->old->node.flags & PM_READONLY) {
+		    zerr("read-only variable: %s", pm->node.nam);
+		    makeprivate_error = 1;
+		} else if ((pm->node.flags | pm->old->node.flags) ==
+		    pm->old->node.flags) {
+		    /* private called twice on same parameter */
+		    Param tpm = pm;
+		    pm = pm->old;
+		    --locallevel;
+		    /* why have a union if we need this switch anyway? */
+		    switch (PM_TYPE(pm->node.flags)) {
+		    case PM_SCALAR:
+			pm->gsu.s->setfn(pm, tpm->u.str);
+			tpm->u.str = NULL;
+			break;
+		    case PM_INTEGER:
+			pm->gsu.i->setfn(pm, tpm->u.val);
+			break;
+		    case PM_EFLOAT:
+		    case PM_FFLOAT:
+			pm->gsu.f->setfn(pm, tpm->u.dval);
+			break;
+		    case PM_ARRAY:
+			pm->gsu.a->setfn(pm, tpm->u.arr);
+			tpm->u.arr = NULL;
+			break;
+		    case PM_HASHED:
+			pm->gsu.h->setfn(pm, tpm->u.hash);
+			tpm->u.hash = NULL;
+			break;
+		    }
+		    ++locallevel;
+		    if (!(tpm->node.flags & PM_UNSET))
+			pm->node.flags &= ~PM_UNSET;
+		} else {
+		    zerrnam("private",
+			    "can't change type of private param: %s",
+			    pm->node.nam);
+		    makeprivate_error = 1;
+		}
+	    } else {
+		zerrnam("private", "can't change scope of existing param: %s",
+			pm->node.nam);
+		makeprivate_error = 1;
+	    }
 	    return;
 	}
 	struct gsu_closure *gsu = zalloc(sizeof(struct gsu_closure));
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index b876f548d..d902cac56 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -384,6 +384,23 @@ F:Should we allow "public" namerefs to private parameters?
  }
 0:regression test for unset private
 
+ () {
+   private x=1
+   unset x
+   private x=2
+   print $x
+ }
+0:private may be called twice
+>2
+
+ () {
+   private x=1
+   private -a x
+   print $x
+ }
+1:private may not change parameter type
+?(anon):private:2: can't change type of private param: x
+
 %clean
 
   rm -r private.TMP

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-09-05  3:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-09-05  3:52 [PATCH] Declaring the same variable "private" more than once 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).