Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: 3.1.5-pws-3: Associative arrays and ${...:=...}



This patch permits associative arrays to be created or assigned-to using
the := and ::= parameter substitution syntax.  This is more convenient than
having to use `typeset -A name` before any other references to an AA.  The
syntax is simply to double the `A' substitution flag, like so:

zsh% echo ${(AA)=assoc::=key1 value1 key2 value2}
value2 value1

Note that, as usual for AAs, only the values are substituted, and they may
not be substituted in the same order that they were assigned.

The reason for the = between (AA) and assoc is to turn on shwordsplit.  If
this is not done, "key1 value1 key2 value2" is taken as a single string,
and the assignment fails.  You can also cause splitting in other ways; e.g.
this copies the entire command hash table into the parameter `commands':

zsh% : ${(AAs:=:)commands::=${(j:=:)$(hash -f;hash)}}

(I suspect something like that could be extremely useful when programming
completions.)

There are two quirks that should be mentioned.  The first is that you
can't presently assign to a subscripted AA element this way; e.g. this
works for arrays (always did, my patch has nothing to do with it):

zsh% : ${(A)array[2]::=two}

But this fails for AAs:

zsh% : ${(AA)assoc[two]::=2}
zsh: attempt to set slice of associative array

I now believe I know how to fix this, but I hadn't figured it out yet
when I fixed up sethparam() a few patches ago.

The second quirk is that ${(A)name::=...} (note, only one `A') doesn't
convert associations into ordinary arrays.  If $name exists and is an
AA, it's assigned to as an AA, just as happens with regular name=(...)
assignment syntax.

zsh% echo ${(A)bar:=x}
x
zsh% echo ${(AA)=foo::=one 1 two 2}
2 1
zsh% echo ${(A)foo:=x}
zsh: bad set of key/value pairs for associative array

This patch also makes use of the SCANPM flags in paramsubst(), now that
they're available outside of params.c.

Index: Src/subst.c
===================================================================
--- subst.c	1998/12/13 23:40:57	1.6
+++ subst.c	1998/12/14 09:17:38
@@ -720,8 +720,8 @@
     int eval = 0;
     int nojoin = 0;
     char inbrace = 0;		/* != 0 means ${...}, otherwise $... */
-    char hkeys = 0;		/* 1 means get keys from associative array */
-    char hvals = 0;		/* > hkeys get values of associative array */
+    char hkeys = 0;
+    char hvals = 0;
 
     *s++ = '\0';
     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@@ -739,7 +739,7 @@
 	inbrace = 1;
 	s++;
 	if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) {
-	    hkeys = 1;
+	    hkeys = SCANPM_WANTKEYS;
 	    s++;
 	} else if (*s == '(' || *s == Inpar) {
 	    char *t, sav;
@@ -762,7 +762,7 @@
 		case Outpar:
 		    break;
 		case 'A':
-		    arrasg = 1;
+		    ++arrasg;
 		    break;
 		case '@':
 		    nojoin = 1;
@@ -897,10 +897,10 @@
 		    break;
 
 		case 'k':
-		    hkeys = 1;
+		    hkeys = SCANPM_WANTKEYS;
 		    break;
 		case 'v':
-		    hvals = 2;
+		    hvals = SCANPM_WANTVALS;
 		    break;
 
 		default:
@@ -979,9 +979,8 @@
 	*s = sav;
 	v = (Value) NULL;
     } else {
-	/* 2 == SCANPM_WANTKEYS, 1 == SCANPM_WANTVALS, see params.c */
 	if (!(v = fetchvalue(&s, (unset(KSHARRAYS) || inbrace) ? 1 : -1,
-			     (hkeys ? 2 : 0) + ((hvals > hkeys) ? 1 : 0))))
+			     hkeys|hvals)))
 	    vunset = 1;
     }
     while (v || ((inbrace || (unset(KSHARRAYS) && vunset)) && isbrack(*s))) {
@@ -1260,7 +1259,12 @@
 			*p++ = ztrdup(*t++);
 		    }
 		    *p++ = NULL;
-		    setaparam(idbeg, a);
+		    if (arrasg > 1) {
+			Param pm = sethparam(idbeg, a);
+			if (pm)
+			    aval = paramvalarr(pm->gets.hfn(pm), hkeys|hvals);
+		    } else
+			setaparam(idbeg, a);
 		} else {
 		    untokenize(val);
 		    setsparam(idbeg, ztrdup(val));

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



Messages sorted by: Reverse Date, Date, Thread, Author