zsh-workers
 help / color / mirror / code / Atom feed
* named references
@ 2001-06-24 11:34 Oliver Kiddle
  2001-06-24 18:28 ` Bart Schaefer
  2001-06-25  5:19 ` Andrej Borsenkow
  0 siblings, 2 replies; 16+ messages in thread
From: Oliver Kiddle @ 2001-06-24 11:34 UTC (permalink / raw)
  To: zsh-workers

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

I've had a bit of a look at the possibility of implementing ksh93 style
named references. The purpose of this e-mail is as a feeler to sound out
your opinions.

For the benefit of anyone who is not familiar with them, it involves a
new -n option to typeset so typeset -n ref=val creates a parameter --
ref -- which is then effectively a synonym for the val parameter. unset
also gains a -n option to unset the reference as opposed to what it
refers to. This is handy in the sort of situations where eval or
${(P)var} might currently be used but has certain advantages (in my
opinion) such as cleaner syntax.and the ability to remember the local
level of the variable referenced.

I've attached the text file where I've been jotting down any issues I've
thought of. There are a number of unusual issues (like the one with for
loops) so it is quite possible I've missed something.

I've also attached a patch of what I've done so far in case you are
interested but be aware that it has a number of problems and
limitations. At the moment I'm not interested in minor bug reports
(unless obscure) but am interested if you have more fundamental
suggestions. I'm going to be away until Wednesday but I should have
more time after then to devote to it.

At the moment, the basics work. I have not implemented ksh93's ${!ref}
which expands to whatever ref is a reference to. This syntax is a csh
style history reference in zsh, so I feared that any attempt by me to
implement it would break something else. It might be better to do this
with a parameter expansion flag (possibly two to allow a single
dereference in addition to ksh's full dereference?)? At the moment,
I've crudely implemented this with d as the expansion flag.

Oliver

[-- Attachment #2: nameref.patch --]
[-- Type: text/plain, Size: 23267 bytes --]

Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.47
diff -u -r1.47 builtin.c
--- Src/builtin.c	2001/06/14 09:49:02	1.47
+++ Src/builtin.c	2001/06/24 11:32:04
@@ -111,12 +111,12 @@
     BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
     BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
     BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
-    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFHLRTUZafghilrtuxm", NULL),
+    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AEFHLRTUZafghilnrtuxm", NULL),
     BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
     BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
     BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
     BUILTIN("unhash", 0, bin_unhash, 1, -1, 0, "adfm", NULL),
-    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fm", NULL),
+    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmn", NULL),
     BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
     BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
     BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL),
@@ -1623,7 +1623,7 @@
     if (usepm || newspecial) {
 	int chflags = ((off & pm->flags) | (on & ~pm->flags)) &
 	     (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
-	      PM_ARRAY|PM_TIED|PM_AUTOLOAD);
+	      PM_NAMEREF|PM_ARRAY|PM_TIED|PM_AUTOLOAD);
 	/* keep the parameter if just switching between floating types */
 	if ((tc = chflags && chflags != (PM_EFLOAT|PM_FFLOAT)))
 	    usepm = 0;
@@ -1689,7 +1689,10 @@
 		   PM_EFLOAT | PM_FFLOAT)) &&
 	    auxlen)
 	    pm->ct = auxlen;
-	if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
+	if (pm->flags & PM_NAMEREF) {
+	    if (value && !(pm = setrparam(pname, ztrdup(value))))
+		return NULL;
+	} else if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
 	    if (pm->flags & PM_EXPORTED) {
 		if (!(pm->flags & PM_UNSET) && !pm->env && !value)
 		    pm->env = addenv(pname, getsparam(pname), pm->flags);
@@ -1794,6 +1797,10 @@
 	    zerrnam(cname,
 		    "%s: can't create readonly array elements", pname, 0);
 	    return NULL;
+	} else if (PM_TYPE(on) == PM_NAMEREF) {
+	    zerrnam(cname,
+		    "%s: array elements cannot be a reference", pname, 0);
+	    return NULL;
 	} else if (PM_TYPE(on) == PM_SCALAR) {
 	    /*
 	     * This will either complain about bad identifiers, or will set
@@ -1808,8 +1815,22 @@
 	    zerrnam(cname,
 		    "%s: array elements must be scalar", pname, 0);
 	    return NULL;
+	}
+    } else if (!isident(pname)) {
+	zerr("not an identifier: %s", pname, 0);
+	return NULL;
+    } else if (PM_TYPE(on) == PM_NAMEREF) {
+	if (!value) {
+    	    zerrnam(cname, "%s: must have value for nameref", pname, 0);
+	    return NULL;
 	}
-    } else if (isident(pname)) {
+
+	/* let setrparam call createparam for namerefs because we are  *
+	 * relying on error checking there and don't want to leave the *
+	 * parameter record in an inconsistent state                   */
+	if (!(pm = setrparam(pname, ztrdup(value))))
+	    return NULL;
+    } else {
 	/*
 	 * Create a new node for a parameter with the flags in `on' minus the
 	 * readonly flag
@@ -1817,9 +1838,6 @@
 	pm = createparam(pname, on & ~PM_READONLY);
 	DPUTS(!pm, "BUG: parameter not created");
 	pm->ct = auxlen;
-    } else {
-	zerr("not an identifier: %s", pname, 0);
-	return NULL;
     }
 
     if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) {
@@ -1837,7 +1855,7 @@
 	pm->level = keeplocal;
     else if (on & PM_LOCAL)
 	pm->level = locallevel;
-    if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) {
+    if (value && !(pm->flags & (PM_ARRAY|PM_HASHED|PM_NAMEREF))) {
 	Param ipm = pm;
 	if (!(pm = setsparam(pname, ztrdup(value))))
 	    return NULL;
@@ -1877,7 +1895,6 @@
 	unsetparam_pm(pm, 0, 1);
 	return NULL;
     }
-
     return pm;
 }
 
@@ -1912,16 +1929,16 @@
     /* Sanity checks on the options.  Remove conficting options. */
     if (on & PM_FFLOAT) {
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_EFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_INTEGER | PM_EFLOAT;
 	/* Allow `float -F' to work even though float sets -E by default */
 	on &= ~PM_EFLOAT;
     }
     if (on & PM_EFLOAT)
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_INTEGER | PM_FFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_INTEGER | PM_FFLOAT;
     if (on & PM_INTEGER)
 	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY |
-	    PM_HASHED | PM_EFLOAT | PM_FFLOAT;
+	    PM_HASHED | PM_NAMEREF | PM_EFLOAT | PM_FFLOAT;
     if (on & PM_LEFT)
 	off |= PM_RIGHT_B | PM_INTEGER | PM_EFLOAT | PM_FFLOAT;
     if (on & PM_RIGHT_B)
@@ -1933,9 +1950,12 @@
     if (on & PM_LOWER)
 	off |= PM_UPPER;
     if (on & PM_HASHED)
+	off |= PM_ARRAY | PM_NAMEREF;
+    if (on & PM_NAMEREF)
 	off |= PM_ARRAY;
     if (on & PM_TIED)
-	off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED;
+	off |= PM_INTEGER | PM_EFLOAT | PM_FFLOAT | PM_ARRAY | PM_HASHED |
+	    PM_NAMEREF;
 
     on &= ~off;
 
@@ -2303,6 +2323,8 @@
     char *s;
     int match = 0, returnval = 0;
     int i;
+    int deref=(!ops['n']);
+    int level;
 
     /* unset -f is the same as unfunction */
     if (ops['f'])
@@ -2320,12 +2342,21 @@
 		    for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
 			/* record pointer to next, since we may free this one */
 			next = (Param) pm->next;
-			if ((!(pm->flags & PM_RESTRICTED) ||
-			    unset(RESTRICTED)) &&
-			    pattry(pprog, pm->nam)) {
-			    unsetparam_pm(pm, 0, 1);
-			    match++;
+
+			while (deref && pm && (pm->flags & PM_NAMEREF)) {
+			    level = pm->ct;
+    			    pm = (Param) paramtab->getnode(paramtab,
+			    	pm->gets.cfn(pm));
+	    	    	    while (pm && (pm->level > level)) pm = pm->old;
 			}
+
+			if (pm)
+			    if ((!(pm->flags & PM_RESTRICTED) ||
+				unset(RESTRICTED)) &&
+				pattry(pprog, pm->nam)) {
+				unsetparam_pm(pm, 0, 1);
+				match++;
+			    }
 		    }
 		}
 		unqueue_signals();
@@ -2346,6 +2377,7 @@
     while ((s = *argv++)) {
 	char *ss = strchr(s, '[');
 	char *sse = ss;
+	int level;
 	if (ss) {
 	    if (skipparens('[', ']', &sse) || *sse) {
 		zerrnam(name, "%s: invalid parameter name", s, 0);
@@ -2357,6 +2389,13 @@
 	pm = (Param) (paramtab == realparamtab ?
 		      gethashnode2(paramtab, s) :
 		      paramtab->getnode(paramtab, s));
+
+	while (deref && pm && (pm->flags & PM_NAMEREF)) {
+	    level = pm->ct;
+	    pm = (Param) paramtab->getnode(paramtab, pm->gets.cfn(pm));
+	    while (pm && (pm->level > level)) pm = pm->old;
+	}
+
 	if (!pm)
 	    returnval = 1;
 	else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.50
diff -u -r1.50 params.c
--- Src/params.c	2001/06/15 13:07:50	1.50
+++ Src/params.c	2001/06/24 11:32:04
@@ -456,7 +456,7 @@
 }
 
 /*
- * Split environment string into (name, vlaue) pair.
+ * Split environment string into (name, value) pair.
  * this is used to avoid in-place editing of environment table
  * that results in core dump on some systems
  */
@@ -644,6 +644,10 @@
 	pm->sets.hfn = hashsetfn;
 	pm->gets.hfn = hashgetfn;
 	break;
+    case PM_NAMEREF:
+    	pm->sets.cfn = refsetfn;
+	pm->gets.cfn = refgetfn;
+	break;
     default:
 	DPUTS(1, "BUG: tried to create param node without valid flag");
 	break;
@@ -674,7 +678,7 @@
 			 paramtab->getnode(paramtab, name));
 
 	DPUTS(oldpm && oldpm->level > locallevel,
-	      "BUG:  old local parameter not deleteed");
+	      "BUG:  old local parameter not deleted");
 	if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
 		oldpm->flags &= ~PM_UNSET;
@@ -756,6 +760,9 @@
     case PM_HASHED:
 	tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
 	break;
+    default:
+	DPUTS(1, "BUG: tried to copy param node without valid flag");
+	break;
     }
     /*
      * If called from inside an associative array, that array is later going
@@ -782,7 +789,7 @@
 	return 0;
 
     if (idigit(*s)) {
-	/* If the first character is `s' is a digit, then all must be */
+	/* If the first character in `s' is a digit, then all must be */
 	for (ss = ++s; *ss; ss++)
 	    if (!idigit(*ss))
 		break;
@@ -1288,17 +1295,38 @@
     return 0;
 }
 
+/* dereferences a value, returning also the name of the referenced parameter *
+ * for cases where that parameter might be unset so the name is needed       */
+
+/**/
+Value
+derefvalue(Value v, char **name, int flags)
+{
+    /* will probably merge this into fetchvalue, adding another param to
+       fetchvalue */
+    char *s = *name;
+
+    if (!v) return NULL;
+    
+    v = fetchvalue(v, &s, 1, flags, 0);
+    while (v && (v->pm->flags & PM_NAMEREF)) {
+        *name = s = v->pm->gets.cfn(v->pm);
+        v = fetchvalue(v, &s, 1, flags, 0);
+    }
+    
+    return v;
+}
 
 /**/
 mod_export Value
 getvalue(Value v, char **pptr, int bracks)
 {
-  return fetchvalue(v, pptr, bracks, 0);
+  return fetchvalue(v, pptr, bracks, 0, 1);
 }
 
 /**/
 mod_export Value
-fetchvalue(Value v, char **pptr, int bracks, int flags)
+fetchvalue(Value v, char **pptr, int bracks, int flags, int deref)
 {
     char *s, *t;
     char sav, c;
@@ -1347,12 +1375,21 @@
     } else {
 	Param pm;
 	int isvarat;
+	int level;
 
         isvarat = (t[0] == '@' && !t[1]);
 	pm = (Param) paramtab->getnode(paramtab, *t == '0' ? "0" : t);
 	if (sav)
 	    *s = sav;
 	*pptr = s;
+
+	/* dereference namerefs */
+    	while (deref && pm && (pm->flags & PM_NAMEREF)) {
+	    level = pm->ct;
+	    pm = (Param) paramtab->getnode(paramtab, pm->gets.cfn(pm));
+	    while (pm && (pm->level > level)) pm = pm->old;
+	}
+	
 	if (!pm || (pm->flags & PM_UNSET))
 	    return NULL;
 	if (v)
@@ -1886,12 +1923,12 @@
     queue_signals();
     if ((ss = strchr(s, '['))) {
 	*ss = '\0';
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_ARRAY);
 	*ss = '[';
 	v = NULL;
     } else {
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_SCALAR);
 	else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) {
@@ -1928,7 +1965,7 @@
     queue_signals();
     if ((ss = strchr(s, '['))) {
 	*ss = '\0';
-	if (!(v = getvalue(&vbuf, &s, 1)))
+	if (!(v = derefvalue(&vbuf, &t, 0)))
 	    createparam(t, PM_ARRAY);
 	*ss = '[';
 	if (v && PM_TYPE(v->pm->flags) == PM_HASHED) {
@@ -1941,7 +1978,7 @@
 	}
 	v = NULL;
     } else {
-	if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING)))
 	    createparam(t, PM_ARRAY);
 	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
@@ -1952,7 +1989,7 @@
 	}
     }
     if (!v)
-	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING))) {
 	    unqueue_signals();
 	    return NULL;
 	}
@@ -1982,7 +2019,7 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
+    if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING)))
 	createparam(t, PM_HASHED);
     else if (!(PM_TYPE(v->pm->flags) & PM_HASHED) &&
 	     !(v->pm->flags & PM_SPECIAL)) {
@@ -1991,7 +2028,7 @@
 	v = NULL;
     }
     if (!v)
-	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
+	if (!(v = derefvalue(&vbuf, &t, SCANPM_ASSIGNING))) {
 	    unqueue_signals();
 	    return NULL;
 	}
@@ -2006,7 +2043,7 @@
 {
     struct value vbuf;
     Value v;
-    char *t = s, *ss;
+    char *ss;
     Param pm;
     mnumber mnval;
 
@@ -2016,18 +2053,18 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = getvalue(&vbuf, &s, 1))) {
+    if (!(v = derefvalue(&vbuf, &s, 0))) {
 	if ((ss = strchr(s, '[')))
 	    *ss = '\0';
-	if (!(pm = createparam(t, ss ? PM_ARRAY : PM_INTEGER)))
-	    pm = (Param) paramtab->getnode(paramtab, t);
+	if (!(pm = createparam(s, ss ? PM_ARRAY : PM_INTEGER)))
+	    pm = (Param) paramtab->getnode(paramtab, s);
 	DPUTS(!pm, "BUG: parameter not created");
 	if (ss) {
 	    *ss = '[';
 	} else {
 	    pm->ct = outputradix;
 	}
-	v = getvalue(&vbuf, &t, 1);
+	v = derefvalue(&vbuf, &s, 0);
 	DPUTS(!v, "BUG: value not found for new parameter");
     }
     mnval.type = MN_INTEGER;
@@ -2048,7 +2085,7 @@
 {
     struct value vbuf;
     Value v;
-    char *t = s, *ss = NULL;
+    char *ss;
     Param pm;
 
     if (!isident(s)) {
@@ -2057,20 +2094,20 @@
 	return NULL;
     }
     queue_signals();
-    if (!(v = getvalue(&vbuf, &s, 1))) {
+    if (!(v = derefvalue(&vbuf, &s, 0))) {
 	if ((ss = strchr(s, '[')))
 	    *ss = '\0';
-	pm = createparam(t, ss ? PM_ARRAY :
+	pm = createparam(s, ss ? PM_ARRAY :
 			 (val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
 	if (!pm)
-	    pm = (Param) paramtab->getnode(paramtab, t);
+	    pm = (Param) paramtab->getnode(paramtab, s);
 	DPUTS(!pm, "BUG: parameter not created");
 	if (ss) {
 	    *ss = '[';
 	} else if (val.type & MN_INTEGER) {
 	    pm->ct = outputradix;
 	}
-	v = getvalue(&vbuf, &t, 1);
+	v = derefvalue(&vbuf, &s, 0);
 	DPUTS(!v, "BUG: value not found for new parameter");
     }
     setnumvalue(v, val);
@@ -2078,6 +2115,61 @@
     return v->pm;
 }
 
+/* function for setting a reference to the name of a parameter */
+
+/**/
+Param
+setrparam(char *s, char *val)
+{
+    struct value vbuf;
+    Value v;
+    Param vpm;
+    char *t = s;
+    char *w = val;
+    char *ss;
+
+    if (!isident(s) || idigit(*s) || strchr(s, '[')) {
+	zerr("not an identifier: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+    if (!isident(val) || idigit(*val) || strchr(val, '[')) {
+    	zerr("invalid variable name: %s", val, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+
+    vpm = (Param) paramtab->getnode(paramtab, val);
+    if (!strcmp(s, val) && ((!vpm) || (vpm->level >= locallevel))) {
+    	zerr("invalid self reference: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+    v = derefvalue(&vbuf, &w, 0);
+    if (!strcmp(s, w)) {
+    	zerr("invalid self reference: %s", s, 0);
+	zsfree(val);
+	errflag = 1;
+	return NULL;
+    }
+	
+    queue_signals();
+    if (!(v = fetchvalue(&vbuf, &s, 1, 0, 0)))
+	createparam(t, PM_NAMEREF);
+    if (!v && !(v = fetchvalue(&vbuf, &t, 1, 0, 0))) {
+	unqueue_signals();
+	zsfree(val);
+	return NULL;
+    }
+    v->pm->sets.cfn(v->pm, val);
+    v->pm->ct = (vpm ? vpm->level : 0);
+    unqueue_signals();
+    return v->pm;
+}
+
 /* Unset a parameter */
 
 /**/
@@ -2323,6 +2415,26 @@
     free(val);		/* not freearray() */
 }
 
+
+/* Function to get value of a nameref parameter */
+
+/**/
+char *
+refgetfn(Param pm)
+{
+    return pm->u.str;
+}
+
+/* Function to set value of a nameref parameter */
+
+/**/
+static void
+refsetfn(Param pm, char *x)
+{
+    zsfree(pm->u.str);
+    pm->u.str = x;
+}
+
 /*
  * These functions are used as the set function for special parameters that
  * cannot be set by the user.  The set is incomplete as the only such
@@ -3347,6 +3459,8 @@
 	    printf("array ");
 	else if (p->flags & PM_HASHED)
 	    printf("association ");
+	else if (p->flags & PM_NAMEREF)
+	    printf("nameref ");
 	if (p->level)
 	    printf("local ");
 	if (p->flags & PM_LEFT)
@@ -3389,6 +3503,7 @@
      * on the type of the parameter       */
     switch (PM_TYPE(p->flags)) {
     case PM_SCALAR:
+    case PM_NAMEREF:
 	/* string: simple output */
 	if (p->gets.cfn && (t = p->gets.cfn(p)))
 	    quotedzputs(t, stdout);
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.20
diff -u -r1.20 subst.c
--- Src/subst.c	2001/06/12 10:34:57	1.20
+++ Src/subst.c	2001/06/24 11:32:04
@@ -778,6 +778,7 @@
     zlong prenum = 0, postnum = 0;
     int copied = 0;
     int arrasg = 0;
+    int deref = 0;
     int eval = 0;
     int aspar = 0;
     int presc = 0;
@@ -889,6 +890,9 @@
 		    quoteerr = 1;
 		    break;
 
+    	    	case 'd':
+		    deref = 1;
+		    break;
 		case 'e':
 		    eval = 1;
 		    break;
@@ -1079,7 +1083,7 @@
 	    s++;
 	v = (Value) NULL;
     } else if (aspar) {
-	if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0)))) {
+	if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0), 1))) {
 	    val = idbeg = getstrvalue(v);
 	    subexp = 1;
 	} else
@@ -1088,14 +1092,28 @@
     if (!subexp || aspar) {
 	char *ov = val;
 
+	if (deref) {
+            /* this doesn't work */
+    	    val = s;
+	    v = derefvalue(&vbuf, &val, 0);
+	    val = dupstring(val);
+	    isarr = 0;
+	}
+	
 	if (!(v = fetchvalue(&vbuf, (subexp ? &ov : &s),
 			     (wantt ? -1 :
 			      ((unset(KSHARRAYS) || inbrace) ? 1 : -1)),
 			     hkeys|hvals|
 			     (arrasg ? SCANPM_ASSIGNING : 0)|
-			     (qt ? SCANPM_DQUOTED : 0))) ||
+			     (qt ? SCANPM_DQUOTED : 0), 1)) ||
 	    (v->pm && (v->pm->flags & PM_UNSET)))
 	    vunset = 1;
+	
+	if (deref) {
+	  /* need the updated s from above */
+	  vunset = 0;
+	  v = NULL;
+	}
 
 	if (wantt) {
 	    if (v && v->pm && !(v->pm->flags & PM_UNSET)) {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.31
diff -u -r1.31 zsh.h
--- Src/zsh.h	2001/06/12 10:34:57	1.31
+++ Src/zsh.h	2001/06/24 11:32:04
@@ -1096,46 +1096,47 @@
 #define PM_EFLOAT	(1<<2)	/* double with %e output		    */
 #define PM_FFLOAT	(1<<3)	/* double with %f output		    */
 #define PM_HASHED	(1<<4)	/* association                              */
+#define PM_NAMEREF	(1<<5)  /* named reference                          */
 
 #define PM_TYPE(X) \
-  (X & (PM_SCALAR|PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_ARRAY|PM_HASHED))
+  (X & (PM_SCALAR|PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_ARRAY|PM_HASHED|PM_NAMEREF))
 
-#define PM_LEFT		(1<<5)	/* left justify, remove leading blanks      */
-#define PM_RIGHT_B	(1<<6)	/* right justify, fill with leading blanks  */
-#define PM_RIGHT_Z	(1<<7)	/* right justify, fill with leading zeros   */
-#define PM_LOWER	(1<<8)	/* all lower case                           */
+#define PM_LEFT		(1<<6)	/* left justify, remove leading blanks      */
+#define PM_RIGHT_B	(1<<7)	/* right justify, fill with leading blanks  */
+#define PM_RIGHT_Z	(1<<8)	/* right justify, fill with leading zeros   */
+#define PM_LOWER	(1<<9)	/* all lower case                           */
 
 /* The following are the same since they *
  * both represent -u option to typeset   */
-#define PM_UPPER	(1<<9)	/* all upper case                           */
-#define PM_UNDEFINED	(1<<9)	/* undefined (autoloaded) shell function    */
+#define PM_UPPER	(1<<10)	/* all upper case                           */
+#define PM_UNDEFINED	(1<<10)	/* undefined (autoloaded) shell function    */
 
-#define PM_READONLY	(1<<10)	/* readonly                                 */
-#define PM_TAGGED	(1<<11)	/* tagged                                   */
-#define PM_EXPORTED	(1<<12)	/* exported                                 */
+#define PM_READONLY	(1<<11)	/* readonly                                 */
+#define PM_TAGGED	(1<<12)	/* tagged                                   */
+#define PM_EXPORTED	(1<<13)	/* exported                                 */
 
 /* The following are the same since they *
  * both represent -U option to typeset   */
-#define PM_UNIQUE	(1<<13)	/* remove duplicates                        */
-#define PM_UNALIASED	(1<<13)	/* do not expand aliases when autoloading   */
+#define PM_UNIQUE	(1<<14)	/* remove duplicates                        */
+#define PM_UNALIASED	(1<<14)	/* do not expand aliases when autoloading   */
 
-#define PM_HIDE		(1<<14)	/* Special behaviour hidden by local        */
-#define PM_HIDEVAL	(1<<15)	/* Value not shown in `typeset' commands    */
-#define PM_TIED 	(1<<16)	/* array tied to colon-path or v.v.         */
+#define PM_HIDE		(1<<15)	/* Special behaviour hidden by local        */
+#define PM_HIDEVAL	(1<<16)	/* Value not shown in `typeset' commands    */
+#define PM_TIED 	(1<<17)	/* array tied to colon-path or v.v.         */
 
 /* Remaining flags do not correspond directly to command line arguments */
-#define PM_LOCAL	(1<<17) /* this parameter will be made local        */
-#define PM_SPECIAL	(1<<18) /* special builtin parameter                */
-#define PM_DONTIMPORT	(1<<19)	/* do not import this variable              */
-#define PM_RESTRICTED	(1<<20) /* cannot be changed in restricted mode     */
-#define PM_UNSET	(1<<21)	/* has null value                           */
-#define PM_REMOVABLE	(1<<22)	/* special can be removed from paramtab     */
-#define PM_AUTOLOAD	(1<<23) /* autoloaded from module                   */
-#define PM_NORESTORE	(1<<24)	/* do not restore value of local special    */
-#define PM_HASHELEM     (1<<25) /* is a hash-element */
+#define PM_LOCAL	(1<<18) /* this parameter will be made local        */
+#define PM_SPECIAL	(1<<19) /* special builtin parameter                */
+#define PM_DONTIMPORT	(1<<20)	/* do not import this variable              */
+#define PM_RESTRICTED	(1<<21) /* cannot be changed in restricted mode     */
+#define PM_UNSET	(1<<22)	/* has null value                           */
+#define PM_REMOVABLE	(1<<23)	/* special can be removed from paramtab     */
+#define PM_AUTOLOAD	(1<<24) /* autoloaded from module                   */
+#define PM_NORESTORE	(1<<25)	/* do not restore value of local special    */
+#define PM_HASHELEM     (1<<26) /* is a hash-element */
 
 /* The option string corresponds to the first of the variables above */
-#define TYPESET_OPTSTR "aiEFALRZlurtxUhHT"
+#define TYPESET_OPTSTR "aiEFAnLRZlurtxUhHT"
 
 /* These typeset options take an optional numeric argument */
 #define TYPESET_OPTNUM "LRZiEF"
Index: Src/Zle/compcore.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compcore.c,v
retrieving revision 1.45
diff -u -r1.45 compcore.c
--- Src/Zle/compcore.c	2001/02/28 09:12:57	1.45
+++ Src/Zle/compcore.c	2001/06/24 11:32:05
@@ -1549,7 +1549,7 @@
     queue_signals();
     if (!(v = fetchvalue(&vbuf, &name, 1,
 			 (keys ? SCANPM_WANTKEYS : SCANPM_WANTVALS) |
-			 SCANPM_MATCHMANY)))
+			 SCANPM_MATCHMANY, 1)))
 	ret = NULL;
     else
 	ret = getarrvalue(v);
Index: Src/Zle/zle_main.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_main.c,v
retrieving revision 1.18
diff -u -r1.18 zle_main.c
--- Src/Zle/zle_main.c	2001/05/17 15:56:13	1.18
+++ Src/Zle/zle_main.c	2001/06/24 11:32:05
@@ -839,7 +839,7 @@
     s = args[0];
     queue_signals();
     v = fetchvalue(&vbuf, &s, (!create || type == PM_SCALAR),
-		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY);
+		   SCANPM_WANTKEYS|SCANPM_WANTVALS|SCANPM_MATCHMANY, 1);
     if (!v && !create) {
 	unqueue_signals();
 	zwarnnam(name, "no such variable: %s", args[0], 0);

[-- Attachment #3: nameref --]
[-- Type: text/plain, Size: 3270 bytes --]

ksh93 style named references - semantics

references to references allowed, so:
  $ val=fred
  $ typeset -n ref=val
  $ typeset -n word=ref
  $ echo $word
  fred

can point to an unset variable:
  $ unset val
  $ typeset -n ref=val
  $ echo $ref

  $ echo $val

can point to array, assoc etc and will be treated as such:
  $ arr=(one two three)
  $ typeset -n val=arr
  $ echo ${val[1]}
  two

but cannot point to an array element:
  $ typeset -n val=arr[1]
  ksh: typeset: arr[1]: is not an identifier

also, the element of an array, assoc can not be a reference, just as it can't
be a float etc:
  $ typeset -n ref[1]=val
  ksh: typeset: ref: reference variable cannot be an array

but can't point to an invalid variable name:
  $ typeset -n ref=1val
  ksh: typeset: 1val: invalid variable name

or to nothing:
  $ typeset -n ref
  ksh: typeset: ref: no reference name
  $ typeset -n r=''
  ksh: typeset: : is not an identifier

or to a positional parameter

cycles and self-references blocked
  $ typeset -n ref=val
  $ typeset -n val=ref
  ksh: typeset: val: invalid self reference

references can't be exported
local applies to the reference not the variable

attributes apply to the value not the reference:
  $ typeset -n val=one
  $ typeset -n ref=val
  $ typeset -u ref
  $ echo $ref
  ONE
  $ echo $val
  ONE
this includes readonly

in ksh though:
  $ typeset -n -r ref=val
  ksh: typeset: ref: is read only
might be good if this would define ref as a readonly reference
  
dereference with ${!...}
  $ typeset -n ref=val
  $ echo ${!ref}
  val

dereference goes all the way so
  $ typeset -n ref=val
  $ typeset -n ref2=ref
  $ echo ${!ref2}
  val

ksh has compiled in alias - nameref='typeset -n'

typeset +n lists names of reference variables

typeset -n lists reference variables with values

only with -n will typeset act on the reference not the value

unset applies to the referenced variable

unset has a -n option which will unset the actual reference

typeset +n ref converts ref to a scalar

in ksh, references to positional variables are not allowed:
  $ typeset -n val=3
  ksh: typeset: 3: invalid variable name

if ksh is given an nameref as the index to a for loop it assigns the values as
for the reference, not the value. It could be very useful but isn't what what
you'd first expect. Is there a good alternative to avoid this:
  $ typeset -n ref=dummy
  $ for ref in var1 var2 ...

in ksh, typeset -n ref[one]=val is allowed with [one] ignored

reference records the local level so:
  $ function f {
  $   typeset -n ref=val
  $   typeset val=two
  $   echo $ref
  $ }
  $ val=one
  $ f val
would echo `one'

because of the above, it needs to handle the situation where
unset ref is done in the function above and also where ref is
then also reassigned a value.

ksh is not clever enough to allow typeset -n ref=ref in a function though

Extra issues in zsh:

local should be implied for typeset -n without +l.

what should ${(t)ref} return - the same as what it refers to with -nameref-
inserted?

should we use namerefs for prompt, rprompt, PROMPT-PROMPT4?

how messy will references to specials be?
might we need special references - I hope not.

any uses in completion functions? _call_function for starters.

test vared, read, case etc

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

* Re: named references
  2001-06-24 11:34 named references Oliver Kiddle
@ 2001-06-24 18:28 ` Bart Schaefer
  2001-06-27 19:01   ` Oliver Kiddle
  2001-06-25  5:19 ` Andrej Borsenkow
  1 sibling, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2001-06-24 18:28 UTC (permalink / raw)
  To: Oliver Kiddle, zsh-workers

On Jun 24, 12:34pm, Oliver Kiddle wrote:
} 
} I've attached the text file where I've been jotting down any issues I've
} thought of. There are a number of unusual issues (like the one with for
} loops) so it is quite possible I've missed something.
} 
} I've also attached a patch of what I've done so far

Having had a quick look at your patch, two things come to mind.

First, I wish it wasn't necessary to waste an entire `struct param' on a
nameref.  It's got a bunch of extra fields that a nameref can't possibly
need.  I'd say you should create a new type of hash node, except that the
implementation of `local' depends so much on the guts of `struct param'.

Second, I think you're dealing with dereferencing in too many separate
places.  It's almost always the case that dereference is wanted -- the
only exception seems to be `unset -n'.  This suggests that dereference
should be a hashtable-level operation rather than parameter-name-level.

So I'd suggest adding to the union:

    /* the value of this parameter */
    union {
	void *data;		/* used by special parameter functions    */
	char **arr;		/* value if declared array   (PM_ARRAY)   */
	char *str;		/* value if declared string  (PM_SCALAR)  */
	zlong val;		/* value if declared integer (PM_INTEGER) */
	double dval;		/* value if declared float
				                    (PM_EFLOAT|PM_FFLOAT) */
        HashTable hash;		/* value if declared assoc   (PM_HASHED)  */
	HashNode ref;		/* value if declared nameref (PM_NAMEREF) */
    } u;

Then specialize getparamnode() and related functions to deref through the
u.ref field, and leave most of the rest of the parameter code alone.  Use
another SCANPM_* flag, which can be passed through fetchvalue(), to tell
when NOT to do this extra dereference.

The potential complication of the above is with `unset' of the node that
is pointed-to.  It'll have to be more careful about freeing the memory;
It'll have to set the PM_UNSET flag instead, and re-use the node if it
becomes set again.  The other option is to continue using u.str as your
patch does, and make a recursive call to getnode() or whatever, but that
complicates other operations (like your overloading of `ct' to plus an
extra loop to determine what `level' to look up in the referenced param).

} I have not implemented ksh93's ${!ref}
} which expands to whatever ref is a reference to. This syntax is a csh
} style history reference in zsh, so I feared that any attempt by me to
} implement it would break something else.

I don't think that's an issue.  Just implement it in the most direct
way, without paying any attention to history, and it'll "just work" in
ksh emulation mode when nobanghist is in effect.  Then also provide a
corresponding expansion flag for regular zsh use.

} with a parameter expansion flag (possibly two to allow a single
} dereference in addition to ksh's full dereference?)?

I don't think that's necessary, but it raises the question of what really
happens when a reference-to-a-reference is made.  That is:

	typeset v1 v2
	typeset -n r1=v1
	typeset -n r2=r1
	typeset -n r1=v2

At this point, is r2 still a reference to v1, or has it become a reference
to v2?  That is, is r1 dereferenced at the time of assignment to r2, or
not until time of dereference of r2?  This ...

} cycles and self-references blocked
}   $ typeset -n ref=val
}   $ typeset -n val=ref
}   ksh: typeset: val: invalid self reference

... tends to indicate that a dereference is performed at the time of the
assignment, if only to discover the loop.

I'm also a bit confused by this:

} also, the element of an array, assoc can not be a reference, just as it
} can't be a float etc:
}   $ typeset -n ref[1]=val
}   ksh: typeset: ref: reference variable cannot be an array

Because later you say:

} in ksh, typeset -n ref[one]=val is allowed with [one] ignored

Which is it?

} references can't be exported
} local applies to the reference not the variable

What exactly does "local applies to the reference" mean?  I presume it
means it hides the name of the nameref, turning it into a local name
that may not even be a nameref any more.

} in ksh though:
}   $ typeset -n -r ref=val
}   ksh: typeset: ref: is read only
} might be good if this would define ref as a readonly reference

I don't understand what the ksh error message means has happened.  I do
understand what you mean by a read-only reference:  It would mean that
an assignment `val=newval' would succeed, but `ref=newval' would not.
  
} typeset +n ref converts ref to a scalar

A scalar having what value?  The name of the previously referenced param?

} if ksh is given an nameref as the index to a for loop it assigns the
} values as for the reference, not the value. It could be very useful
} but isn't what what you'd first expect. Is there a good alternative to
} avoid this:
}   $ typeset -n ref=dummy
}   $ for ref in var1 var2 ...

So what you mean is that, in ksh, the two lines above are the same as

    for name in var1 var2; do typeset -n ref=$name; ...

Hence at the end of the loop `typeset ref' will say `nameref ref=var2'?
(Or does `typeset ref' not work that way?  See below.)

} reference records the local level [...]
} because of the above, it needs to handle the situation where
} unset ref is done in the function above and also where ref is
} then also reassigned a value.

Using an actual u.ref pointer to the referenced node would deal with all
of this in a very straightforward manner, I think.
 
} ksh is not clever enough to allow typeset -n ref=ref in a function though

What is the actual complaint?
 
} Extra issues in zsh:
} 
} local should be implied for typeset -n without +l.

You mean without -g ?  +l is `not lowercase'.  I suppose ksh has used -l
for `local'?  (See previous mail I've sent about whether ksh emulation
mode should change the meanings of some options to typeset.)

} what should ${(t)ref} return - the same as what it refers to with -nameref-
} inserted?

It should correspond to `typeset -n ref=val; typeset ref'.
 
} should we use namerefs for prompt, rprompt, PROMPT-PROMPT4?

Possibly.  Definitely we should for ZLS_COLO(|U)RS, colo(|u)rs, etc.

} how messy will references to specials be?

I think they won't be messy with my suggested implementation, but I admit
I haven't tried to work out all the details.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* RE: named references
  2001-06-24 11:34 named references Oliver Kiddle
  2001-06-24 18:28 ` Bart Schaefer
@ 2001-06-25  5:19 ` Andrej Borsenkow
  2001-06-27 16:03   ` Oliver Kiddle
  1 sibling, 1 reply; 16+ messages in thread
From: Andrej Borsenkow @ 2001-06-25  5:19 UTC (permalink / raw)
  To: zsh-workers

>
> I've had a bit of a look at the possibility of implementing ksh93 style
> named references.

Apart from obvious "it was fun to implement" - can somebody give an example
for use of nameref? I mean, real examples, where other means are
impossible/have disatvantage over nameref. To be honest, I've tried to
imagine one and failed (ksh93 compatibility issue aside).

-andrej



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

* Re: named references
  2001-06-25  5:19 ` Andrej Borsenkow
@ 2001-06-27 16:03   ` Oliver Kiddle
  2001-06-27 16:50     ` Peter Stephenson
  2001-06-27 17:14     ` Bart Schaefer
  0 siblings, 2 replies; 16+ messages in thread
From: Oliver Kiddle @ 2001-06-27 16:03 UTC (permalink / raw)
  To: zsh-workers

Andrej wrote:

> Apart from obvious "it was fun to implement" - can somebody give an example
> for use of nameref? I mean, real examples, where other means are
> impossible/have disatvantage over nameref. To be honest, I've tried to
> imagine one and failed (ksh93 compatibility issue aside).

Any situation where you want a function to return a value and the exit
code is not sufficient. This can currently be done with an eval but it
is messy, especially with associative arrays. The nameref can be used
like any normal variable so you end up with more readable code:

at the moment, you would need to define a local for the return value,
and before returning, assign it across with eval:
  typeset -A $1
  eval $1'=( ${(kv)ret} )'
it is much more readable if the function just starts with:
  nameref ret="$1"

If we ever implement other more complex parameter types (such as
something like ksh93 namespaces), it would be even more useful because
the eval code for them could be even more messy.

Also, unlike eval, namerefs can reference variables at a higher local
level so in the above `ret' could be passed as $1 safely. I'd also
expect that if we ever implement anything like dtksh/tksh as a module,
more scripts would be written which would use namerefs.

Namerefs could also be useful for simple cases where an alternate name
is wanted, maybe to allow a different language such as we have already
done with ZLS_COLOURS/ZLS_COLORS or for things like prompt. You even
suggested some sort of parameter aliasing in 12830.

Does anyone else have an opinion on whether namerefs would be a useful
addition? I'd prefer this to be decided now rather than after I spend
more time on them.

Oliver


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

* Re: named references
  2001-06-27 16:03   ` Oliver Kiddle
@ 2001-06-27 16:50     ` Peter Stephenson
  2001-06-27 19:18       ` Oliver Kiddle
  2001-06-27 17:14     ` Bart Schaefer
  1 sibling, 1 reply; 16+ messages in thread
From: Peter Stephenson @ 2001-06-27 16:50 UTC (permalink / raw)
  To: Zsh hackers list

Oliver Kiddle wrote:
> Does anyone else have an opinion on whether namerefs would be a useful
> addition? I'd prefer this to be decided now rather than after I spend
> more time on them.

I'd certainly like to see this included, along with other stuff from ksh93
unless it's obviously stupid.  The question is when to do it:  we have been
planning a neatening up of the parameter setting code, which hasn't got an
interface so much as a backend which happens to include a few functions
callable from outside.  That would probably be a necessary prerequisite for
any attempt at another ksh feature, the ability to tie getting and setting
of parameters to shell functions.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: named references
  2001-06-27 16:03   ` Oliver Kiddle
  2001-06-27 16:50     ` Peter Stephenson
@ 2001-06-27 17:14     ` Bart Schaefer
  1 sibling, 0 replies; 16+ messages in thread
From: Bart Schaefer @ 2001-06-27 17:14 UTC (permalink / raw)
  To: Oliver Kiddle, zsh-workers

On Jun 27,  5:03pm, Oliver Kiddle wrote:
}
} Does anyone else have an opinion on whether namerefs would be a useful
} addition? I'd prefer this to be decided now rather than after I spend
} more time on them.

I think they'd be a very useful addition.  Particularly if you can do:

	typeset -A hash
	hash[key]=value
	nameref 'thing=hash[key]'

Which, of course, would be easily implemented given my scheme of storing
a pointer to the referenced node in the nameref node. :-)

You haven't answered any of my questions from 15059, though ...

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: named references
  2001-06-24 18:28 ` Bart Schaefer
@ 2001-06-27 19:01   ` Oliver Kiddle
  2001-06-28  8:07     ` Andrej Borsenkow
                       ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Oliver Kiddle @ 2001-06-27 19:01 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote:

> First, I wish it wasn't necessary to waste an entire `struct param' on a
> nameref.  It's got a bunch of extra fields that a nameref can't possibly
> need.  I'd say you should create a new type of hash node, except that the
> implementation of `local' depends so much on the guts of `struct param'.

Is a `struct param' big enough to matter? Other than the two environment
char*s, what won't namerefs need? I fear that using another hash node
will cause problems for references to references and local but I'll
definitely look into doing that.

> Second, I think you're dealing with dereferencing in too many separate
> places.  It's almost always the case that dereference is wanted -- the
> only exception seems to be `unset -n'.  This suggests that dereference
> should be a hashtable-level operation rather than parameter-name-level.

I had assumed that the hash table was a generic thing, used for things
other than parameters so had specifically not touched it. I'll look into
doing that though. One concern I have is that in some cases, the code
needs to know the name of the referenced parameter. This is mainly
because the reference is to an unset parameter and the code needs to
know what name to create a new parameter under. Possibly solvable with
a PM_UNSET parameter. Does a `struct param' know its own name because I
can't see that it does. The dereference glob qualifier also needs this.
Could it be passed back from the hashtable code somehow? 

I suspect my current code looks worse than it really is with respect to
dereferencing in too many places. Basically, getting fetchvalue to
dereference covers most cases. derefvalue was just a wrapper to get the
name of the referenced value and I was probably going to merge that into
fetchvalue and extract the basic derefence code to a function which
fetchvalue and unset would call. Certainly, I'll try to do it at the
hashtable level though.

> So I'd suggest adding to the union:
>         HashNode ref;           /* value if declared nameref (PM_NAMEREF) */

Using a pointer for the reference is something I considered when I
started out. The problem is how to deal with references to unset
parameters. The code seemed to do a bit of unsetting, freeing and
recreating parameters which worried me.  Also, for all references to
unset parameters, you would need to create a parameter with PM_UNSET
and either keep a count of the number of references to it each
parameter has, implement garbage collection or never free the memory
for struct params.

In many other ways it does seem better with the pointer though. With
this `HashNode ref' implementation how would you handle locals?
 
> } I have not implemented ksh93's ${!ref}

> I don't think that's an issue.  Just implement it in the most direct
> way, without paying any attention to history, and it'll "just work" in
> ksh emulation mode when nobanghist is in effect.  Then also provide a
> corresponding expansion flag for regular zsh use.

Okay. Thanks.

> I don't think that's necessary, but it raises the question of what really
> happens when a reference-to-a-reference is made.  That is:
> 
>         typeset v1 v2
>         typeset -n r1=v1
>         typeset -n r2=r1
>         typeset -n r1=v2
> 
> At this point, is r2 still a reference to v1, or has it become a reference
> to v2?  That is, is r1 dereferenced at the time of assignment to r2, or
> not until time of dereference of r2?  This ...

not until time of dereference of r2. r2 will be and will remain a
reference to `r1' whatever r1 is whether that be unset, another
reference, an array or scalar.

> }   ksh: typeset: val: invalid self reference
> ... tends to indicate that a dereference is performed at the time of the
> assignment, if only to discover the loop.

It is only to discover the loop as allowing the loop would be fairly
serious.

> I'm also a bit confused by this:
> 
> } also, the element of an array, assoc can not be a reference, just as it
> } can't be a float etc:
> }   $ typeset -n ref[1]=val
> }   ksh: typeset: ref: reference variable cannot be an array
> 
> Because later you say:
> 
> } in ksh, typeset -n ref[one]=val is allowed with [one] ignored
> 
> Which is it?

In ksh:
  $ typeset -n ref[one]=val
  $ typeset -n
  ref=val
  $ typeset -n ref[one]=val
  ksh: typeset: ref: reference variable cannot be an array
So whether ref is set decides the behaviour. The first behaviour is, in
my opinion a bug in ksh. Ultimately, this doesn't really matter
because, I would attempt to implement the second behaviour (i.e. print
an error) for both cases but thanks for pointing that out.

> } references can't be exported
> } local applies to the reference not the variable
> 
> What exactly does "local applies to the reference" mean?  I presume it
> means it hides the name of the nameref, turning it into a local name
> that may not even be a nameref any more.

that the reference variable is local and doesn't overwrite another
variable of the same name. I worded that badly though: `local ref' would
be a new variable ref and the old ref would be hidden whether or not it
is a reference.

> } in ksh though:
> }   $ typeset -n -r ref=val
> }   ksh: typeset: ref: is read only
> } might be good if this would define ref as a readonly reference
> 
> I don't understand what the ksh error message means has happened.

  $ typeset -n -r ref=val
  ksh: typeset: ref: is read only
  $ typeset|grep ref
  readonly ref
  $ echo $ref
  val
so ksh has created a readonly scalar, ref with the value `val'. In my
opinion, it would be more useful to create a readonly reference, ref
pointing to `val' and not print an error message. 

>  I do
> understand what you mean by a read-only reference:  It would mean that
> an assignment `val=newval' would succeed, but `ref=newval' would not.

No, that isn't what I meant. I meant that `unset -n ref' or
`typeset -n ref=newval' would print:
zsh: read-only variable: ref

so the reference variable would be readonly in just the same way as any
other variable. I thought about the reference's flags being used on the
scalar when accessed through the reference (as you describe for
readonly) but don't think it is particularly useful and left/right won't
work if I overload ct.

My basic idea was that if a typeset command includes -n, any other flags
(such as -r) would apply directly to the reference. Otherwise, a
dereference would be done to maintain the transparency of the reference.

> } typeset +n ref converts ref to a scalar
> A scalar having what value?  The name of the previously referenced param?

Yes. The reverse is also true so a scalar converted to a nameref will
use the scalar value for the new nameref. Conversion to and from
arrays/associations is not possible.

> } if ksh is given an nameref as the index to a for loop it assigns the
> } values as for the reference, not the value. It could be very useful
> } but isn't what what you'd first expect. Is there a good alternative to
> } avoid this:
> }   $ typeset -n ref=dummy
> }   $ for ref in var1 var2 ...
> 
> So what you mean is that, in ksh, the two lines above are the same as
> 
>     for name in var1 var2; do typeset -n ref=$name; ...
> 
> Hence at the end of the loop `typeset ref' will say `nameref ref=var2'?
> (Or does `typeset ref' not work that way?  See below.)

That is exactly what ksh does (except `typeset ref' outputs nothing
because ksh doesn't do that. `typeset -n' would output `ref=var2' and
`typeset|grep ref' would output `nameref ref').

The question is should we emulate ksh there (it is a nice feature and
avoids the need for the extra variable) or should we use the more
expected behaviour (dereference ref) or add some other syntax (such as
`for -n ref' or `for nameref ref'. Any other suggestions?

> } reference records the local level [...]
> } because of the above, it needs to handle the situation where
> } unset ref is done in the function above and also where ref is
> } then also reassigned a value.
> 
> Using an actual u.ref pointer to the referenced node would deal with all
> of this in a very straightforward manner, I think.
>  
> } ksh is not clever enough to allow typeset -n ref=ref in a function though
> What is the actual complaint?

I'm sure I had it complaining about an `invalid self reference' but it
seems to work now. I probably used `f()' instead of `function f' syntax
by mistake. Anyway, that is ksh so it is irrelevant.

> } Extra issues in zsh:
> } 
> } local should be implied for typeset -n without +l.
> 
> You mean without -g ?  +l is `not lowercase'.  I suppose ksh has used -l
> for `local'?  (See previous mail I've sent about whether ksh emulation
> mode should change the meanings of some options to typeset.)

Sorry, that was me being stupid. I meant without -g. I've just never
used it so didn't think. ksh has no equivalent - just the difference for
the two function syntaxes which isn't nice in my opinion.

> } what should ${(t)ref} return - the same as what it refers to with -nameref-
> } inserted?
> 
> It should correspond to `typeset -n ref=val; typeset ref'.

That just outputs `ref=val' similar to what it would for a scalar. My
thinking was that it should do the dereference here to maintain
compatibility with any code which currently uses ${(t)..}. For example
all the current uses of _parameter -g would want to include namerefs to
arrays if they are completing arrays. Most of these cases use pattern
matching so inserting `-nameref' wouldn't break too much.

In 5068, you said that ksh has "separate namespaces for namerefs and
parameters". Can you remember what you meant by that? Your following
statement about unsetting namerefs is wrong because there is `unset
-n'. As far as I can tell, ksh93 namespaces amount to little more than
allowing `.' in parameter names (apart from nameref logic and composite
assignment statements).

Thanks Bart for your suggestions.

Oliver


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

* Re: named references
  2001-06-27 16:50     ` Peter Stephenson
@ 2001-06-27 19:18       ` Oliver Kiddle
  2001-06-30  8:09         ` Bart Schaefer
  0 siblings, 1 reply; 16+ messages in thread
From: Oliver Kiddle @ 2001-06-27 19:18 UTC (permalink / raw)
  To: Zsh hackers list

Peter Stephenson wrote:

> I'd certainly like to see this included, along with other stuff from ksh93
> unless it's obviously stupid.  The question is when to do it:  we have been
> planning a neatening up of the parameter setting code, which hasn't got an
> interface so much as a backend which happens to include a few functions

>From my perspective, with respect to `when', doing namerefs now allows
me to become more familiar with zsh's C code. Were you thinking of
doing a parameter rewrite soon?

I'd be interested in more detail on the ideas you have for the
parameter code. What sort of thing might the interface provide?

My main thoughts from what I've seen is that it would be good if it was
more flexible so that you could have something like an array of
assocations of floats. Maybe allow arrays of things of mixed type? What
other types might we want other than something like ksh namespaces
(records/structs or whatever you like to call them).

> callable from outside.  That would probably be a necessary prerequisite for
> any attempt at another ksh feature, the ability to tie getting and setting
> of parameters to shell functions.

Do you mean something like ksh93 discipline functions. If we were to be
compatible with ksh93, I think that would also require ksh namespaces
(but I'm not sure). Would it be useful if I post a list of ksh93
features not in zsh?

Bart Schaefer wrote:
> On Jun 27,  5:03pm, Oliver Kiddle wrote:

> I think they'd be a very useful addition.  Particularly if you can do:
> 
>         typeset -A hash
>         hash[key]=value
>         nameref 'thing=hash[key]'
> 
> Which, of course, would be easily implemented given my scheme of storing
> a pointer to the referenced node in the nameref node. :-)

Yes, that would be nice but not necessarily impossible with the string
instead of the pointer. I planned to try to get that working after I had
the basic ksh level of features working.

> You haven't answered any of my questions from 15059, though ...

It took me a while to go through it and think about all the options so I
did the quick reply to Andrej first.

Oliver


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

* RE: named references
  2001-06-27 19:01   ` Oliver Kiddle
@ 2001-06-28  8:07     ` Andrej Borsenkow
  2001-06-28  8:30       ` Bart Schaefer
  2001-06-28  9:39     ` Peter Stephenson
  2001-06-30  7:37     ` Bart Schaefer
  2 siblings, 1 reply; 16+ messages in thread
From: Andrej Borsenkow @ 2001-06-28  8:07 UTC (permalink / raw)
  To: zsh-workers

This does not touch everything (I need some time to swallow the rest :-)

>
> > So I'd suggest adding to the union:
> >         HashNode ref;           /* value if declared nameref
> (PM_NAMEREF) */
>
> Using a pointer for the reference is something I considered when I
> started out. The problem is how to deal with references to unset
> parameters.

... and ...

>
> > I don't think that's necessary, but it raises the question of
> what really
> > happens when a reference-to-a-reference is made.  That is:
> >
> >         typeset v1 v2
> >         typeset -n r1=v1
> >         typeset -n r2=r1
> >         typeset -n r1=v2
> >
> > At this point, is r2 still a reference to v1, or has it become
> a reference
> > to v2?  That is, is r1 dereferenced at the time of assignment to r2, or
> > not until time of dereference of r2?  This ...
>
> not until time of dereference of r2. r2 will be and will remain a
> reference to `r1' whatever r1 is whether that be unset, another
> reference, an array or scalar.
>

What happens in this case:

foo() {
  typeset -n r=v
  local v=foo
  echo $r
}

v=bar
foo

I.e. does r refer to outer v ("by address" could you say) or to inner v ("by
name" would it be then)? The latter would be badly broken; but to implement
the former you must have reference to pm not the name.

-andrej


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

* Re: named references
  2001-06-28  8:07     ` Andrej Borsenkow
@ 2001-06-28  8:30       ` Bart Schaefer
  0 siblings, 0 replies; 16+ messages in thread
From: Bart Schaefer @ 2001-06-28  8:30 UTC (permalink / raw)
  To: Andrej Borsenkow, zsh-workers

On Jun 28, 12:07pm, Andrej Borsenkow wrote:
} Subject: RE: named references
}
} This does not touch everything (I need some time to swallow the rest :-)
} 
} What happens in this case:
} 
} foo() {
}   typeset -n r=v
}   local v=foo
}   echo $r
} }
} 
} v=bar
} foo
} 
} I.e. does r refer to outer v ("by address" could you say) or to inner
} v ("by name" would it be then)? The latter would be badly broken; but
} to implement the former you must have reference to pm not the name.

You actually don't need the reference, you just need both the name and the
local-level.

Oliver's partial implementation got this right, by stashing the target
local-level in the reference's `ct' field, and then after looking up the
parameter by name, searching its `old' linked list for the right `level'.
But using a pointer directly to the pm is a lot faster.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: named references
  2001-06-27 19:01   ` Oliver Kiddle
  2001-06-28  8:07     ` Andrej Borsenkow
@ 2001-06-28  9:39     ` Peter Stephenson
  2001-06-30  7:56       ` Bart Schaefer
  2001-06-30  7:37     ` Bart Schaefer
  2 siblings, 1 reply; 16+ messages in thread
From: Peter Stephenson @ 2001-06-28  9:39 UTC (permalink / raw)
  To: Zsh hackers list

Oliver Kiddle wrote:
> Using a pointer for the reference is something I considered when I
> started out. The problem is how to deal with references to unset
> parameters.

I'd be very tempted just to store the name of the object referred to, after
a bit of sanity checking, and dereference it right at the last minute as if
with ${(P)...} --- which I think is what you've got.  This makes problems
like this completely transparent, at the expense of a bit of speed which I
don't think anybody is expecting out of namerefs.

> Were you thinking of doing a parameter rewrite soon?

Er, well, not exactly *soon*...

> I'd be interested in more detail on the ideas you have for the
> parameter code. What sort of thing might the interface provide?

Thinking is the hard bit and I haven't really got that far.  It's really
just an abstraction of what we've got at the moment so that the surrounding
code sees as few parameter functions as possible with, if possible, a
single consistent set of flags etc.  It needs to cover (off the top of my
head):

- creating local parameters; probably quite a lot of what's done directly
  in typeset at the moment can stay there
- entering and leaving parameter scope
- setting and reading parameters

and it needs to do it in such a way that the surrounding code doesn't need
to worry about the underlying parameter type.  We can actually already do
pretty much all of this --- for example, getsparam() will hide the
parameter type and bundle it into a scalar --- but it's all done by ad hoc
code at the next level down.  I'd like to be able to do something like

  char *sret, **aret;
  Param param = paramtab->findparam(paramtab, <however>);

  param->get(param, FLAG_SCALAR, &sret);
  param->get(param, FLAG_ARRAY, &aret);

--- not intended to be concrete, just an example of how it could be a bit
neater.  This particular example could do too much work, since it implies
you can convert all types to all other types.  But the source has been
expanding faster than N**2 for ages now :-/.

> > That would probably be a necessary prerequisite for
> > any attempt at another ksh feature, the ability to tie getting and setting
> > of parameters to shell functions.
> 
> Do you mean something like ksh93 discipline functions. If we were to be
> compatible with ksh93, I think that would also require ksh namespaces
> (but I'm not sure).

Yes, compatibility would imply both.

> Would it be useful if I post a list of ksh93 features not in zsh?

Feel free.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: named references
  2001-06-27 19:01   ` Oliver Kiddle
  2001-06-28  8:07     ` Andrej Borsenkow
  2001-06-28  9:39     ` Peter Stephenson
@ 2001-06-30  7:37     ` Bart Schaefer
  2001-07-09 19:43       ` Oliver Kiddle
  2 siblings, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2001-06-30  7:37 UTC (permalink / raw)
  To: zsh-workers

On Jun 27,  8:01pm, Oliver Kiddle wrote:
> Subject: Re: named references
> Bart Schaefer wrote:
> 
> > First, I wish it wasn't necessary to waste an entire `struct param' on a
> > nameref.
> 
> Is a `struct param' big enough to matter?

Perhaps not.

> I fear that using another hash node will cause problems for references
> to references and local but I'll definitely look into doing that.

I fear that, too, which is why I didn't really suggest an alternative.

> > Second, I think you're dealing with dereferencing in too many separate
> > places.  It's almost always the case that dereference is wanted -- the
> > only exception seems to be `unset -n'.  This suggests that dereference
> > should be a hashtable-level operation rather than parameter-name-level.
> 
> I had assumed that the hash table was a generic thing, used for things
> other than parameters so had specifically not touched it.

Hash tables are sort of a hybrid.  There are a bunch of generic routines,
but there are also a set of callbacks that are allowed to differ from one
hashtable to the next.  The paramter hash table uses a custom routine to
fetch nodes; it's that routine, not the generic code from which it is
called, that I'm suggesting you modify.

I see that PWS disagrees with me, though.

> One concern I have is that in some cases, the code
> needs to know the name of the referenced parameter.

That's why I suggested adding a SCANPM_* flag, to control whether the
dereference occurred.

> Does a `struct param' know its own name because I
> can't see that it does.

Yes.  That's what the `char *nam;' field is.

> [About pointers] The code seemed to do a bit of unsetting, freeing and
> recreating parameters which worried me.  Also, for all references to
> unset parameters, you would need to create a parameter with PM_UNSET
> and either keep a count of the number of references to it each
> parameter has, implement garbage collection or never free the memory
> for struct params.

That's true.  Garbage collection wouldn't be all that hard, though.
There are lots of cases where the code scans through all the params
already; since you don't have to worry about cycles, just piggyback a
mark/sweep on top of one of the scans.

> In many other ways it does seem better with the pointer though. With
> this `HashNode ref' implementation how would you handle locals?

Ideally there wouldn't be any special handling necessary at all. When
a local is created, the pointer to the global gets taken out of the
hash table and put into the `old' field of the local. But that doesn't
affect the pointer in the nameref; it still points at the global. When
the local goes out of scope, its `old' pointer goes back into the hash
table, but that still doesn't affect where the nameref is pointing.

Except of course that that isn't how the `old' pointer works for the
special parameters, nor for parameters that are temporarily replaced
by `param=val command' syntax.  So that stuff would have to be redone,
which brings us back to PWS's remarks about a general parameter code
cleanup.

> > understand what you mean by a read-only reference:  It would mean that
> > an assignment `val=newval' would succeed, but `ref=newval' would not.
> 
> No, that isn't what I meant. I meant that `unset -n ref' or
> `typeset -n ref=newval' would print:
> zsh: read-only variable: ref
> 
> I thought about the reference's flags being used on the scalar when
> accessed through the reference (as you describe for readonly) but
> don't think it is particularly useful and left/right won't work if I
> overload ct.

Hm, I didn't mean for the flags of the reference to be used on the
scalar.  Having a left-justified width-12 float reference to a right-
justified zero-filled width-10 integer wouldn't make a lot of sense.

I meant for the flags to be applied to the action of dereferencing,
if that makes sense.  But maybe you can't know at the point of deref
whether the call came from code that's about to perform an assignment.

> > } typeset +n ref converts ref to a scalar
> > A scalar having what value?  The name of the previously referenced param?
> 
> Yes. The reverse is also true so a scalar converted to a nameref will
> use the scalar value for the new nameref. Conversion to and from
> arrays/associations is not possible.

OK, in that case maybe it *is* best to store the name and use the `ct'
overload or a similar trick to track the local-level.
 
> > }   $ typeset -n ref=dummy
> > }   $ for ref in var1 var2 ...
> > 
> > So what you mean is that, in ksh, the two lines above are the same as
> > 
> >     for name in var1 var2; do typeset -n ref=$name; ...
> 
> That is exactly what ksh does [...]
> 
> The question is should we emulate ksh there (it is a nice feature and
> avoids the need for the extra variable) or should we use the more
> expected behaviour (dereference ref) or add some other syntax (such as
> `for -n ref' or `for nameref ref'. Any other suggestions?

We should emulate ksh when `name' is already a nameref.

However, we could follow our usual pattern of choosing some other syntax
that's illegal in sh/ksh and giving it additional semantics; e.g.

	for (name) in var1 var2 ...

could create an implicit nameref.  The `for (name) (var1 var2) ...' form
looks a bit odd, but it's unambiguously parsable (I think).  Or we could
use `for name = var1 var2 ...' if we're getting tired of the overloading
of parens, but `for name = (var1 var2) ...' looks like an array assign.

Semi-related aside:

zagzig% for name in (a b c)
for> do
for> done
zsh: number expected

Number expected?

> > } ksh is not clever enough to allow typeset -n ref=ref in a function though
> > What is the actual complaint?
> 
> I'm sure I had it complaining about an `invalid self reference' but it
> seems to work now. I probably used `f()' instead of `function f' syntax
> by mistake. Anyway, that is ksh so it is irrelevant.

It's not irrelevant if we're emulating it.
 
> > } what should ${(t)ref} return - the same as what it refers to with
> > } -nameref- inserted?
> > 
> > It should correspond to `typeset -n ref=val; typeset ref'.
> 
> That just outputs `ref=val' similar to what it would for a scalar. My
> thinking was that it should do the dereference here to maintain
> compatibility with any code which currently uses ${(t)..}.

Hmm, that's probably true.  In which case I'm not even sure if it should
insert -nameref- anywhere.  Hard to say.

> In 5068, you said that ksh has "separate namespaces for namerefs and
> parameters". Can you remember what you meant by that?

Exactly what you mentioned before -- `nameref ref=var; typeset ref'
doesn't output anything, and `unset ref' doesn't remove `ref', so the
name `ref' does not behave like a parameter name.  What I didn't realize
at the time was that `unset ref' actually removes `var', nor that there
was such a thing as `unset -n'.  (Flags to `unset'?  Heresy!)

My remark had nothing to do with user-visible ksh93 namespaces; I was
referring to internal implementation namespaces.


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

* Re: named references
  2001-06-28  9:39     ` Peter Stephenson
@ 2001-06-30  7:56       ` Bart Schaefer
  2001-07-02  9:31         ` Peter Stephenson
  0 siblings, 1 reply; 16+ messages in thread
From: Bart Schaefer @ 2001-06-30  7:56 UTC (permalink / raw)
  To: Zsh hackers list

On Jun 28, 10:39am, Peter Stephenson wrote:
> Subject: Re: named references
> 
> I'd be very tempted just to store the name of the object referred to,
> after a bit of sanity checking, and dereference it right at the last
> minute as if with ${(P)...}

The problem with the "at the last minute" approach is that there are a
lot more places where namerefs have to expose the underlying parameter
than just in the parameter substitution code.  If the dereference takes
place too late, it has to be dealt with in multiple places: assignment,
`unset', substitution, etc.

Consider for example:

	typeset -n ref=var
	echo ${(P)ref}

This should, I think, be equivalent to ${(P)var}, which means the
nameref dereference has to happen at a lower level than the current
substitution code.  Then there's the existing problem of `${(P)1}': I'm
concerned that if the dereferencing happens even as late as it did in
Oliver's sample code, we're going to run into that sort of thing in a
lot of other places.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: named references
  2001-06-27 19:18       ` Oliver Kiddle
@ 2001-06-30  8:09         ` Bart Schaefer
  0 siblings, 0 replies; 16+ messages in thread
From: Bart Schaefer @ 2001-06-30  8:09 UTC (permalink / raw)
  To: Zsh hackers list

On Jun 27,  8:18pm, Oliver Kiddle wrote:
> Subject: Re: named references
> 
> I'd be interested in more detail on the ideas you have for the
> parameter code. What sort of thing might the interface provide?
> 
> My main thoughts from what I've seen is that it would be good if it was
> more flexible so that you could have something like an array of
> assocations of floats. Maybe allow arrays of things of mixed type? What
> other types might we want other than something like ksh namespaces
> (records/structs or whatever you like to call them).

All these things are, theoretically, already possible, because the
associative array implementation uses a duplicate of the parameter
hash table -- every associative array element is itself an entire
struct param and *could* have all the attributes of any parameter.

The missing bit is the necessary syntactic constructs to allow one to
manipulate such complex data structures from shell script code.  Even
with zsh's ability to parse multi-level subscript expressions, there
isn't any way to represent the assignment of, say, an entire hash table
from one parameter to another -- assignment expressions, substitutions,
etc. inherently work on text rather than on the internal representation
of the data.  Even namerefs only allow you to pass around the names of
things, not the things themselves.

The fact that functions can't return anything but an exit status is
not helpful either.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* Re: named references
  2001-06-30  7:56       ` Bart Schaefer
@ 2001-07-02  9:31         ` Peter Stephenson
  0 siblings, 0 replies; 16+ messages in thread
From: Peter Stephenson @ 2001-07-02  9:31 UTC (permalink / raw)
  To: Zsh hackers list

"Bart Schaefer" wrote:
> On Jun 28, 10:39am, Peter Stephenson wrote:
> > Subject: Re: named references
> > 
> > I'd be very tempted just to store the name of the object referred to,
> > after a bit of sanity checking, and dereference it right at the last
> > minute as if with ${(P)...}
> 
> The problem with the "at the last minute" approach is that there are a
> lot more places where namerefs have to expose the underlying parameter
> than just in the parameter substitution code.  If the dereference takes
> place too late, it has to be dealt with in multiple places: assignment,
> `unset', substitution, etc.

That's why I mentioned rewriting the parameter code.  The same thing comes
up with ksh `discipline' functions, whose name I couldn't remember.  It
should be possible to intercept gets and sets in this way, even
recursively.  This is certainly not easy with the current code.  If it's
substantially easier to do it the other way for now that's fine.  But I
suspect we (for suitably arbitrary and not necessarily inclusive `we')
might end up rewriting it anyway.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Unit 300, Science Park, Milton Road,
Cambridge, CB4 0XL, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


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

* Re: named references
  2001-06-30  7:37     ` Bart Schaefer
@ 2001-07-09 19:43       ` Oliver Kiddle
  0 siblings, 0 replies; 16+ messages in thread
From: Oliver Kiddle @ 2001-07-09 19:43 UTC (permalink / raw)
  To: zsh-workers

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

On 30 Jun, Bart Schaefer wrote:

> We should emulate ksh when `name' is already a nameref.
> However, we could follow our usual pattern of choosing some other syntax
> that's illegal in sh/ksh and giving it additional semantics; e.g.

Okay, that sounds good though I'll get the basics working first before
any new for syntax.

> > > } what should ${(t)ref} return - the same as what it refers to with
> > > } -nameref- inserted?

> Hmm, that's probably true.  In which case I'm not even sure if it should
> insert -nameref- anywhere.  Hard to say.

I know what you mean. My thinking behind inserting -nameref- was that
it would enable shell code to detect namerefs -- so for example I can
write a proper completion for unset -n -- while being compatible with
any old shell code that pattern matches against the output of ${(t)ref}
(which most probably does).

> > In 5068, you said that ksh has "separate namespaces for namerefs and
> > parameters". Can you remember what you meant by that?
> 
> Exactly what you mentioned before -- `nameref ref=var; typeset ref'
> doesn't output anything, and `unset ref' doesn't remove `ref', so the
> name `ref' does not behave like a parameter name.  What I didn't realize
> at the time was that `unset ref' actually removes `var', nor that there

The name `ref' does behave like a parameter name in ksh. `typeset ref' is just
defining ref if it isn't already defined so it will never output anything for
any variable in ksh. You have to do `typeset|grep ref'.

> was such a thing as `unset -n'.  (Flags to `unset'?  Heresy!)

Well, we already have two flags to unset -- -f and -m (and I've just realised
that I've not done a completion for them).

Anyway, I had a little time on the weekend to look at using a pointer for the
nameref. I am convinced that it is the better way, it'll just be slightly less
easy because I have to meddle more with existing code. The first problem is that
fetchvalue() currently returns NULL for PM_UNSET variables which I'm probably
going to have to change.

In case anyone is interested, attached is a descripton of ksh93 features which
aren't in zsh. Let me know if you know of things to add to it.

Oliver

[-- Attachment #2: ksh93.txt --]
[-- Type: text/plain, Size: 3687 bytes --]

local variables
---------------

The two function definition syntaxes work differently in ksh. function name
syntax is equivalent to using localtraps and typeset defines local variables.
function() syntax uses the same environment as the caller and shares all traps
and variables. This is also the case if the function is invoked with the `.'
special builtin.

Also note that in ksh, local variables are statically scoped (they aren't in
zsh). Dynamic scoping seems more natural for a shell in my opinion. In future
we could have something like Perl's `my' for static scoping (but preferably
using a less cheesy name).

discipline functions
--------------------

Any function with a "." in its name is a "discipline function". Anything up to
the last "." refers to a parameter. Only `get', `set' and `unset' are defined
at the moment and they intercept assignments to the variable.  The trouble is
that functions are not scoped so discipline functions can only be used for
global variables. The situation is actually that if you redefine a discipline
in a function for a local, the discipline is removed after the function returns
and ksh seg faults next time you access the variable because it is pointing to
a removed discipline. I pointed this out to David Korn and he got back to me so
it'll be fixed. Anyway, if anyone thinks about implementing discipline
functions, they might want to consider scoped functions first (in case it isn't
clear, ksh does *not* do scoped functions).

hierarchical variables
----------------------

If namerefs are the equivalent of pointers, these are the equivalent of
structs/records. They, amount to little more than allowing "." in a variable
name with nameref logic so `nameref ref=val; echo ${ref.one}' will output the
value of ${val.one}. There is also a compound assignment statement though so
you can do things like val=(one=1 two=2) instead of val.one=1;val.two=2

There are aspects of this which I don't like though: 
    $ n.o=1
    ksh: n.o=1: no parent
    $ n=
    $ n.o=1
    $ unset n # this unsets just `n' so we now have an orphaned ${n.o}
There is seemingly no way to manipulate a whole hierarchy such as to unset it
or whatever. The idea is that you pass it around by name which is fair enough.

namespaces
----------
I may have confused these with hierarchical variables previously. I get the
impression that these did not exist in the original ksh93 (the latest is
sub-release l). I also suspect that they are not quite finshed yet - I have had
a couple of seg faults and there is no documentation.

Anyway, there is a reserved word, `namespace' which I am guessing is similar to
Pascal's with statement. It seems to be possible to use it like this:
    $ .Z=
    $ .Z.one=hello
    $ namespace Z {
    > echo $one
    > }

set and typeset will then not list variables in the namespace. typeset will
include `namespace Z' in its output though.

These would be nice for hiding the completion system caches out of the way.

nested assignment statements
----------------------------

This is related to hierarchical variables above. Basically, any assignment of
the form var=( ... ) contains other assignment statements within the brackets.

So you can do stuff like:
rec=(integer i=3; arr=(one two three); assoc=([a]=1 [b]=2))

other misc things
-----------------
named references - of course

+= assignment operator (appends to or arithmetic add).

a wrapper (/etc/suid_exec) to allow suid/sgid/unreadable scripts to be run

/dev/fd/n emulated in the script argument to ksh

filenames of the form /dev/{tcp,udp}/hostid/port can be used to create tcp and
udp connections.

two consecutive characters in IFS has a different meaning

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

end of thread, other threads:[~2001-07-09 19:44 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-06-24 11:34 named references Oliver Kiddle
2001-06-24 18:28 ` Bart Schaefer
2001-06-27 19:01   ` Oliver Kiddle
2001-06-28  8:07     ` Andrej Borsenkow
2001-06-28  8:30       ` Bart Schaefer
2001-06-28  9:39     ` Peter Stephenson
2001-06-30  7:56       ` Bart Schaefer
2001-07-02  9:31         ` Peter Stephenson
2001-06-30  7:37     ` Bart Schaefer
2001-07-09 19:43       ` Oliver Kiddle
2001-06-25  5:19 ` Andrej Borsenkow
2001-06-27 16:03   ` Oliver Kiddle
2001-06-27 16:50     ` Peter Stephenson
2001-06-27 19:18       ` Oliver Kiddle
2001-06-30  8:09         ` Bart Schaefer
2001-06-27 17:14     ` 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).