zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH 2/3] Special named references
@ 2023-02-27  4:08 Bart Schaefer
  0 siblings, 0 replies; only message in thread
From: Bart Schaefer @ 2023-02-27  4:08 UTC (permalink / raw)
  To: Zsh hackers list

[-- 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);
 	}
     }


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

only message in thread, other threads:[~2023-02-27  4:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-27  4:08 [PATCH 2/3] Special named references 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).