zsh-workers
 help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: [PATCH 2/3] Special named references
Date: Sun, 26 Feb 2023 20:08:22 -0800	[thread overview]
Message-ID: <CAH+w=7YkPv9g8-jPF3CRc+H_DGjP67eRYWN32oSTT_QJL10HPg@mail.gmail.com> (raw)

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

The previously-posted implementation of named references assumes all
PM_NAMEREF parameters are created as simple scalars with the referent
parameter name stored in the u.str field of the referencing param
structure.  This is efficient but complicates the creation of special
named references, for example in modules.

This patch changes the implementation to call the get/set/unset
function pointers when the PM_SPECIAL flag is present, and otherwise
to continue directly accessing u.str.  This should be applied after
the namespace-syntax patch, though if wanted independently there is
only a single line of overlap with an obvious adjustment.

Included is a fix to builtins.yo to add an explicit summary line for
"typeset -n".

[-- Attachment #2: nameref-improve.txt --]
[-- Type: text/plain, Size: 8344 bytes --]

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 92917c06c..5393cb149 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1924,6 +1924,8 @@ redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi(        )))
 xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(AHUaghlmrtux) ] \
 [ {tt(PLUS())|tt(-)}tt(EFLRZip) [ var(n) ] ])
 xitem(SPACES()[ tt(+) ] [ var(name)[tt(=)var(value)] ... ])
+xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(n) ] \
+[ tt(-gr) ] [ var(name)[tt(=)var(value)] ... ])
 xitem(tt(typeset )tt(-T) [ {tt(PLUS())|tt(-)}tt(Uglrux) ] [ {tt(PLUS())|tt(-)}tt(LRZp) [ var(n) ] ])
 xitem(SPACES()[ tt(+) | var(SCALAR)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])
 item(tt(typeset) tt(-f) [ {tt(PLUS())|tt(-)}tt(TUkmtuz) ] [ tt(+) ] [ var(name) ... ])(

diff --git a/Src/params.c b/Src/params.c
index d3b6a7d43..c9f4b3017 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -475,6 +475,15 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
 	((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
 		 !(V)->pm->node.nam || !*(V)->pm->node.nam))
 
+/*
+ * For named references.  Simple named references are just like scalars
+ * for efficiency, but special named references need get/set functions.
+ */
+#define GETREFNAME(PM) (((PM)->node.flags & PM_SPECIAL) ?	\
+			(PM)->gsu.s->getfn(PM) : (PM)->u.str)
+#define SETREFNAME(PM,S) (((PM)->node.flags & PM_SPECIAL) ?		\
+			  (PM)->gsu.s->setfn(PM,(S)) : ((PM)->u.str = (S)))
+
 static Param argvparam;
 
 /* "parameter table" - hash table containing the parameters
@@ -520,7 +529,7 @@ getparamnode(HashTable ht, const char *nam)
     HashNode hn = gethashnode2(ht, nam);
     Param pm = (Param) hn;
 
-    if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
+    if (pm && (pm->node.flags & PM_AUTOLOAD) && pm->u.str) {
 	char *mn = dupstring(pm->u.str);
 
 	(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
@@ -1002,12 +1011,13 @@ createparam(char *name, int flags)
 	    struct asgment stop;
 	    stop.flags = PM_NAMEREF | (flags & PM_LOCAL);
 	    stop.name = oldpm->node.nam;
-	    stop.value.scalar = oldpm->u.str;
+	    stop.value.scalar = GETREFNAME(oldpm);
 	    lastpm = (Param)resolve_nameref(oldpm, &stop);
 	    if (lastpm) {
 		if (lastpm->node.flags & PM_NAMEREF) {
-		    if (lastpm->u.str && *(lastpm->u.str)) {
-			name = lastpm->u.str;
+		    char *refname = GETREFNAME(lastpm);
+		    if (refname && *refname) {
+			name = refname;
 			oldpm = NULL;
 		    } else {
 			if (!(lastpm->node.flags & PM_READONLY))
@@ -2145,25 +2155,28 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
 	    memset(v, 0, sizeof(*v));
 	else
 	    v = (Value) hcalloc(sizeof *v);
-	if ((pm->node.flags & PM_NAMEREF) && pm->u.str && *(pm->u.str)) {
-	    /* only happens for namerefs pointing to array elements */
-	    char *ref = dupstring(pm->u.str);
-	    char *ss = pm->width ? ref + pm->width : NULL;
-	    if (ss) {
-		sav = *ss;
-		*ss = 0;
+	if (pm->node.flags & PM_NAMEREF) {
+	    char *refname = GETREFNAME(pm);
+	    if (refname && *refname) {
+		/* only happens for namerefs pointing to array elements */
+		char *ref = dupstring(refname);
+		char *ss = pm->width ? ref + pm->width : NULL;
+		if (ss) {
+		    sav = *ss;
+		    *ss = 0;
+		}
+		Param p1 = (Param)gethashnode2(paramtab, ref);
+		if (!(p1 && (pm = upscope(p1, pm->base))) ||
+		    ((pm->node.flags & PM_UNSET) &&
+		     !(pm->node.flags & PM_DECLARED)))
+		    return NULL;
+		if (ss) {
+		    flags |= SCANPM_NOEXEC;
+		    *ss = sav;
+		    s = dyncat(ss,*pptr);
+		} else
+		    s = *pptr;
 	    }
-	    Param p1 = (Param)gethashnode2(paramtab, ref);
-	    if (!(p1 && (pm = upscope(p1, pm->base))) ||
-		((pm->node.flags & PM_UNSET) &&
-		!(pm->node.flags & PM_DECLARED)))
-		return NULL;
-	    if (ss) {
-		flags |= SCANPM_NOEXEC;
-		*ss = sav;
-		s = dyncat(ss,*pptr);
-	    } else
-		s = *pptr;
 	}
 	if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
 	    /* Overload v->isarr as the flag bits for hashed arrays. */
@@ -3648,7 +3661,7 @@ mod_export Param
 setiparam_no_convert(char *s, zlong val)
 {
     /*
-     * If the target is already an integer, thisgets converted
+     * If the target is already an integer, this gets converted
      * back.  Low technology rules.
      */
     char buf[BDIGBUFSIZE];
@@ -6115,22 +6128,23 @@ resolve_nameref(Param pm, const Asgment stop)
     const char *seek = stop ? stop->value.scalar : NULL;
 
     if (pm && (pm->node.flags & PM_NAMEREF)) {
-	if (pm && (pm->node.flags & (PM_UNSET|PM_TAGGED))) {
+	char *refname = GETREFNAME(pm);
+	if (pm->node.flags & (PM_UNSET|PM_TAGGED)) {
 	    /* Semaphore with createparam() */
 	    pm->node.flags &= ~PM_UNSET;
 	    if (pm->node.flags & PM_NEWREF)	/* See setloopvar() */
 		return NULL;
-	    if (pm->u.str && *(pm->u.str) && (pm->node.flags & PM_TAGGED))
+	    if (refname && *refname && (pm->node.flags & PM_TAGGED))
 		pm->node.flags |= PM_SELFREF;	/* See setscope() */
 	    return (HashNode) pm;
-	} else if (pm->u.str) {
+	} else if (refname) {
 	    if ((pm->node.flags & PM_TAGGED) ||
-		(stop && strcmp(pm->u.str, stop->name) == 0)) {
-		/* zwarnnam(pm->u.str, "invalid self reference"); */
+		(stop && strcmp(refname, stop->name) == 0)) {
+		/* zwarnnam(refname, "invalid self reference"); */
 		return stop ? (HashNode)pm : NULL;
 	    }
-	    if (*(pm->u.str))
-		seek = pm->u.str;
+	    if (*refname)
+		seek = refname;
 	}
     }
     else if (pm && !(stop && (stop->flags & PM_NAMEREF)))
@@ -6180,8 +6194,13 @@ setloopvar(char *name, char *value)
   Param pm = (Param) gethashnode2(realparamtab, name);
 
   if (pm && (pm->node.flags & PM_NAMEREF)) {
+      if (pm->node.flags & PM_READONLY) {
+	  /* Bash error is: "%s: readonly variable" */
+	  zerr("read-only reference: %s", pm->node.nam);
+	  return;
+      }
       pm->base = pm->width = 0;
-      pm->u.str = ztrdup(value);
+      SETREFNAME(pm, ztrdup(value));
       pm->node.flags &= ~PM_UNSET;
       pm->node.flags |= PM_NEWREF;
       setscope(pm);
@@ -6197,7 +6216,8 @@ setscope(Param pm)
     if (pm->node.flags & PM_NAMEREF) {
 	Param basepm;
 	struct asgment stop;
-	char *t = pm->u.str ? itype_end(pm->u.str, INAMESPC, 0) : NULL;
+	char *refname = GETREFNAME(pm);
+	char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
 
 	/* Temporarily change nameref to array parameter itself */
 	if (t && *t == '[')
@@ -6211,7 +6231,7 @@ setscope(Param pm)
 	    stop.flags |= PM_LOCAL;
 	basepm = (Param)resolve_nameref(pm, &stop);
 	if (t) {
-	    pm->width = t - pm->u.str;
+	    pm->width = t - refname;
 	    *t = '[';
 	}
 	if (basepm) {
@@ -6220,23 +6240,23 @@ setscope(Param pm)
 		    if (pm->node.flags & PM_SELFREF) {
 			/* Loop signalled by resolve_nameref() */
 			if (upscope(pm, pm->base) == pm) {
-			    zerr("%s: invalid self reference", pm->u.str);
+			    zerr("%s: invalid self reference", refname);
 			    unsetparam_pm(pm, 0, 1);
 			    return;
 			}
 			pm->node.flags &= ~PM_SELFREF;
 		    } else if (pm->base == pm->level) {
-			if (pm->u.str && *(pm->u.str) &&
-			    strcmp(pm->node.nam, pm->u.str) == 0) {
-			    zerr("%s: invalid self reference", pm->u.str);
+			if (refname && *refname &&
+			    strcmp(pm->node.nam, refname) == 0) {
+			    zerr("%s: invalid self reference", refname);
 			    unsetparam_pm(pm, 0, 1);
 			    return;
 			}
 		    }
-		} else if (basepm->u.str) {
+		} else if ((t = GETREFNAME(basepm))) {
 		    if (basepm->base <= basepm->level &&
-			strcmp(pm->node.nam, basepm->u.str) == 0) {
-			zerr("%s: invalid self reference", pm->u.str);
+			strcmp(pm->node.nam, t) == 0) {
+			zerr("%s: invalid self reference", refname);
 			unsetparam_pm(pm, 0, 1);
 			return;
 		    }
@@ -6251,11 +6271,11 @@ setscope(Param pm)
 		unsetparam_pm(pm, 0, 1);
 	    } else if (isset(WARNNESTEDVAR))
 		zwarn("reference %s in enclosing scope set to local variable %s",
-		      pm->node.nam, pm->u.str);
+		      pm->node.nam, refname);
 	}
-	if (pm->u.str && upscope(pm, pm->base) == pm &&
-	    strcmp(pm->node.nam, pm->u.str) == 0) {
-	    zerr("%s: invalid self reference", pm->u.str);
+	if (refname && upscope(pm, pm->base) == pm &&
+	    strcmp(pm->node.nam, refname) == 0) {
+	    zerr("%s: invalid self reference", refname);
 	    unsetparam_pm(pm, 0, 1);
 	}
     }


                 reply	other threads:[~2023-02-27  4:08 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=7YkPv9g8-jPF3CRc+H_DGjP67eRYWN32oSTT_QJL10HPg@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).