zsh-workers
 help / color / mirror / code / Atom feed
* PATCH: += parameter assignments
@ 2001-12-17 12:02 Oliver Kiddle
  2001-12-17 12:11 ` Borsenkow Andrej
  0 siblings, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2001-12-17 12:02 UTC (permalink / raw)
  To: zsh-workers

This adds += assignments -- a ksh93 feature. It is useful as a quick
way to add elements to an array or append to a string. For numeric
variables, it uses arithmetic evaluation to add to the variable. With
indexes specified, it can have other uses like inserting into the
middle of an array or string.

One possible extension beyond what ksh does would be to also add a -=
assignment. It could be made to prepend to string and array values
which would be fairly useful. Or does anyone think that that behaviour
for -= would be too illogical?

Note that unlike ksh, this can't be used with typeset and its variants.
I have followed ksh behaviour with three exceptions that I'm aware of:

  1.  array+=scalar
In ksh this is equivalent to array[0]+=scalar while I've made it
equivalent to array+=( scalar ) which I think is more useful. The ksh
behaviour is a consequence of the ksh implementation of arrays so with
the ksh_arrays option set, it will behave like ksh for compatibility.

  2. array[i]+=( array )
In ksh, the index is ignored so this adds to the end of the array. I
insert the array in the middle after the index. This is useful but
might be regretted if we ever want to implement 2D arrays.

  3. assoc+=scalar
In ksh, this does absolutely nothing and so would assoc=scalar. I'm not
sure about this one but have made it the same as assoc=scalar in zsh -
it replaces the association with a new scalar.

Oliver

Index: Doc/Zsh/params.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/params.yo,v
retrieving revision 1.12
diff -u -r1.12 params.yo
--- Doc/Zsh/params.yo	2001/09/24 16:22:30	1.12
+++ Doc/Zsh/params.yo	2001/12/17 11:57:29
@@ -20,8 +20,9 @@
 indent(var(name)tt(=)var(value))
 
 If the integer attribute, tt(-i), is set for var(name), the var(value)
-is subject to arithmetic evaluation.  See noderef(Array Parameters)
-for additional forms of assignment.
+is subject to arithmetic evaluation.  Furthermore, by replacing `tt(=)'
+with `tt(+=)', a parameter can be added or appended to.  See
+noderef(Array Parameters) for additional forms of assignment.
 
 To refer to the value of a parameter, write `tt($)var(name)' or
 `tt(${)var(name)tt(})'.  See
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.39
diff -u -r1.39 exec.c
--- Src/exec.c	2001/10/13 17:54:28	1.39
+++ Src/exec.c	2001/12/17 11:57:29
@@ -1512,7 +1512,8 @@
 	if (htok)
 	    untokenize(name);
 	if (xtr)
-	    fprintf(xtrerr, "%s=", name);
+	    fprintf(xtrerr,
+	    	WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC ? "%s+=" : "%s=", name);
 	if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) {
 	    init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok));
 	    vl = &svl;
@@ -1561,10 +1562,12 @@
 		}
 		allexp = opts[ALLEXPORT];
 		opts[ALLEXPORT] = 1;
-		pm = setsparam(name, val);
+	    	pm = assignsparam(name, val,
+		    WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
 		opts[ALLEXPORT] = allexp;
 	    } else
-		pm = setsparam(name, val);
+	    	pm = assignsparam(name, val,
+		    WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
 	    if (errflag) {
 		state->pc = opc;
 		return;
@@ -1587,7 +1590,7 @@
 		fprintf(xtrerr, "%s ", *ptr);
 	    fprintf(xtrerr, ") ");
 	}
-	setaparam(name, arr);
+	assignaparam(name, arr, WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
 	if (errflag) {
 	    state->pc = opc;
 	    return;
Index: Src/lex.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/lex.c,v
retrieving revision 1.20
diff -u -r1.20 lex.c
--- Src/lex.c	2001/08/27 07:31:38	1.20
+++ Src/lex.c	2001/12/17 11:57:30
@@ -1140,6 +1140,7 @@
 			skipparens(Inbrack, Outbrack, &t);
 		    }
 		}
+		if (*t == '+') t++;
 		if (t == bptr) {
 		    e = hgetc();
 		    if (e == '(' && incmdpos) {
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.55
diff -u -r1.55 params.c
--- Src/params.c	2001/12/17 11:10:47	1.55
+++ Src/params.c	2001/12/17 11:57:30
@@ -1724,9 +1724,12 @@
     }
     if (v->start == 0 && v->end == -1) {
 	if (PM_TYPE(v->pm->flags) == PM_HASHED)
-	    arrhashsetfn(v->pm, val);
+	    arrhashsetfn(v->pm, val, 0);
 	else
 	    (v->pm->sets.afn) (v->pm, val);
+    } else if (v->start == -1 && v->end == 0 &&
+    	    PM_TYPE(v->pm->flags) == PM_HASHED) {
+    	arrhashsetfn(v->pm, val, 1);
     } else {
 	char **old, **new, **p, **q, **r;
 	int n, ll, i;
@@ -1870,12 +1873,15 @@
 
 /**/
 mod_export Param
-setsparam(char *s, char *val)
+assignsparam(char *s, char *val, int augment)
 {
     struct value vbuf;
     Value v;
     char *t = s;
-    char *ss;
+    char *ss, *copy, *var;
+    size_t lv;
+    mnumber lhs, rhs;
+    int sstart;
 
     if (!isident(s)) {
 	zerr("not an identifier: %s", s, 0);
@@ -1893,8 +1899,10 @@
     } else {
 	if (!(v = getvalue(&vbuf, &s, 1)))
 	    createparam(t, PM_SCALAR);
-	else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
-		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) {
+	else if ((((v->pm->flags & PM_ARRAY) && !augment) ||
+	    	 (v->pm->flags & PM_HASHED)) &&
+		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && 
+		 unset(KSHARRAYS)) {
 	    unsetparam(t);
 	    createparam(t, PM_SCALAR);
 	    v = NULL;
@@ -1905,6 +1913,78 @@
 	zsfree(val);
 	return NULL;
     }
+    if (augment) {
+	if (v->start == 0 && v->end == -1) {
+	    switch (PM_TYPE(v->pm->flags)) {
+	    case PM_SCALAR:
+		v->start = INT_MAX;  /* just append to scalar value */
+		break;
+	    case PM_INTEGER:
+	    case PM_EFLOAT:
+	    case PM_FFLOAT:
+		rhs = matheval(val);
+		lhs = getnumvalue(v);
+		if (lhs.type == MN_FLOAT) {
+		    if ((rhs.type) == MN_FLOAT)
+        		lhs.u.d = lhs.u.d + rhs.u.d;
+		    else
+			lhs.u.d = lhs.u.d + (double)rhs.u.l;
+		} else {
+        	    if ((rhs.type) == MN_INTEGER)
+			lhs.u.l = lhs.u.l + rhs.u.l;
+		    else
+			lhs.u.l = lhs.u.l + (zlong)rhs.u.d;
+		}
+		setnumvalue(v, lhs);
+    	    	unqueue_signals();
+		zsfree(val);
+		return v->pm; /* avoid later setstrvalue() call */
+	    case PM_ARRAY:
+	    	if (unset(KSHARRAYS)) {
+		    v->start = arrlen(v->pm->gets.afn(v->pm));
+		    v->end = v->start + 1;
+		} else {
+		    /* ksh appends scalar to first element */
+		    v->end = 1;
+		    goto kshappend;
+		}
+		break;
+	    }
+	} else {
+	    switch (PM_TYPE(v->pm->flags)) {
+	    case PM_SCALAR:
+    		if (v->end > 0)
+		    v->start = v->end;
+		else
+		    v->start = v->end = strlen(v->pm->gets.cfn(v->pm)) +
+			v->end + 1;
+	    	break;
+	    case PM_INTEGER:
+	    case PM_EFLOAT:
+	    case PM_FFLOAT:
+		unqueue_signals();
+		zerr("attempt to add to slice of a numeric variable",
+		    NULL, 0);
+		zsfree(val);
+		return NULL;
+	    case PM_ARRAY:
+	      kshappend:
+		/* treat slice as the end element */
+		v->start = sstart = v->end > 0 ? v->end - 1 : v->end;
+		v->isarr = 0;
+		var = getstrvalue(v);
+		v->start = sstart;
+		copy = val;
+		lv = strlen(var);
+		val = (char *)zalloc(lv + strlen(var));
+		strcpy(val, var);
+		strcpy(val + lv, copy);
+		zsfree(copy);
+		break;
+	    }
+	}
+    }
+    
     setstrvalue(v, val);
     unqueue_signals();
     return v->pm;
@@ -1912,7 +1992,7 @@
 
 /**/
 mod_export Param
-setaparam(char *s, char **val)
+assignaparam(char *s, char **val, int augment)
 {
     struct value vbuf;
     Value v;
@@ -1946,6 +2026,18 @@
 	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
 		 !(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
 	    int uniq = v->pm->flags & PM_UNIQUE;
+	    if (augment) {
+	    	/* insert old value at the beginning of the val array */
+		char **new;
+		int lv = arrlen(val);
+
+		new = (char **) zalloc(sizeof(char *) * (lv + 2));
+		*new = ztrdup(getstrvalue(v));
+		memcpy(new+1, val, sizeof(char *) * (lv + 1));
+		free(val);
+		val = new;
+		
+	    }
 	    unsetparam(t);
 	    createparam(t, PM_ARRAY | uniq);
 	    v = NULL;
@@ -1954,8 +2046,27 @@
     if (!v)
 	if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
 	    unqueue_signals();
+	    freearray(val);
 	    return NULL;
 	}
+
+    if (augment) {
+    	if (v->start == 0 && v->end == -1) {
+	    if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
+	    	v->start = arrlen(v->pm->gets.afn(v->pm));
+	    	v->end = v->start + 1;
+	    } else if (PM_TYPE(v->pm->flags) & PM_HASHED)
+	    	v->start = -1, v->end = 0;
+	} else {
+	    if (v->end > 0)
+		v->start = v->end--;
+	    else if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
+		v->end = arrlen(v->pm->gets.afn(v->pm)) + v->end;
+		v->start = v->end + 1;
+	    }
+	}
+    }
+
     setarrvalue(v, val);
     unqueue_signals();
     return v->pm;
@@ -2291,7 +2402,7 @@
 
 /**/
 static void
-arrhashsetfn(Param pm, char **val)
+arrhashsetfn(Param pm, char **val, int augment)
 {
     /* Best not to shortcut this by using the existing hash table,   *
      * since that could cause trouble for special hashes.  This way, *
@@ -2309,7 +2420,8 @@
 	return;
     }
     if (alen)
-	ht = paramtab = newparamtable(17, pm->nam);
+    	if (!(augment && (ht = paramtab = pm->gets.hfn(pm))))
+	    ht = paramtab = newparamtable(17, pm->nam);
     while (*aptr) {
 	/* The parameter name is ztrdup'd... */
 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
Index: Src/parse.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/parse.c,v
retrieving revision 1.31
diff -u -r1.31 parse.c
--- Src/parse.c	2001/11/21 17:03:57	1.31
+++ Src/parse.c	2001/12/17 11:57:30
@@ -1488,11 +1488,17 @@
 	} else if (tok == ENVSTRING) {
 	    char *p, *name, *str;
 
-	    ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, 0));
 	    name = tokstr;
-	    for (p = tokstr; *p && *p != Inbrack && *p != '='; p++);
-	    if (*p == Inbrack && !skipparens(Inbrack, Outbrack, &p) &&
-		*p == '=') {
+	    for (p = tokstr; *p && *p != Inbrack && *p != '=' && *p != '+';
+	         p++);
+	    if (*p == Inbrack) skipparens(Inbrack, Outbrack, &p);
+	    if (*p == '+') {
+	    	*p++ = '\0';
+	    	ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0));
+	    } else
+		ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_NEW, 0));
+    	
+	    if (*p == '=') {
 		*p = '\0';
 		str = p + 1;
 	    } else
@@ -1501,15 +1507,20 @@
 	    ecstr(str);
 	    isnull = 0;
 	} else if (tok == ENVARRAY) {
-	    int oldcmdpos = incmdpos, n;
+	    int oldcmdpos = incmdpos, n, type2;
 
 	    p = ecadd(0);
 	    incmdpos = 0;
+	    if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') {
+	    	tokstr[type2] = '\0';
+		type2 = WC_ASSIGN_INC;
+    	    } else
+		type2 = WC_ASSIGN_NEW;
 	    ecstr(tokstr);
 	    cmdpush(CS_ARRAY);
 	    yylex();
 	    n = par_nl_wordlist();
-	    ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, n);
+	    ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, type2, n);
 	    cmdpop();
 	    if (tok != OUTPAR)
 		YYERROR(oecused);
@@ -2288,8 +2299,8 @@
 #define FD_MINMAP 4096
 
 #define FD_PRELEN 12
-#define FD_MAGIC  0x03040506
-#define FD_OMAGIC 0x06050403
+#define FD_MAGIC  0x04050607
+#define FD_OMAGIC 0x07060504
 
 #define FDF_MAP   1
 #define FDF_OTHER 2
Index: Src/text.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/text.c,v
retrieving revision 1.9
diff -u -r1.9 text.c
--- Src/text.c	2001/09/25 12:50:46	1.9
+++ Src/text.c	2001/12/17 11:57:30
@@ -323,6 +323,7 @@
 	    break;
 	case WC_ASSIGN:
 	    taddstr(ecgetstr(state, EC_NODUP, NULL));
+	    if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) taddchr('+');
 	    taddchr('=');
 	    if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
 		taddchr('(');
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.35
diff -u -r1.35 zsh.h
--- Src/zsh.h	2001/11/03 23:36:33	1.35
+++ Src/zsh.h	2001/12/17 11:57:30
@@ -591,10 +591,13 @@
 #define WCB_REDIR(T)        wc_bld(WC_REDIR, (T))
 
 #define WC_ASSIGN_TYPE(C)   (wc_data(C) & ((wordcode) 1))
+#define WC_ASSIGN_TYPE2(C)  ((wc_data(C) & ((wordcode) 2)) >> 1)
 #define WC_ASSIGN_SCALAR    0
 #define WC_ASSIGN_ARRAY     1
-#define WC_ASSIGN_NUM(C)    (wc_data(C) >> 1)
-#define WCB_ASSIGN(T,N)     wc_bld(WC_ASSIGN, ((T) | ((N) << 1)))
+#define WC_ASSIGN_NEW       0
+#define WC_ASSIGN_INC       1
+#define WC_ASSIGN_NUM(C)    (wc_data(C) >> 2)
+#define WCB_ASSIGN(T,A,N)   wc_bld(WC_ASSIGN, ((T) | ((A) << 1) | ((N) << 2)))
 
 #define WC_SIMPLE_ARGC(C)   wc_data(C)
 #define WCB_SIMPLE(N)       wc_bld(WC_SIMPLE, (N))
@@ -1197,6 +1200,9 @@
 #define ARRPARAMDEF(name, var) \
     { name, PM_ARRAY, (void *) var, (void *) arrvarsetfn, \
       (void *) arrvargetfn, (void *) stdunsetfn }
+
+#define setsparam(S,V) assignsparam(S,V,0)
+#define setaparam(S,V) assignaparam(S,V,0)
 
 /* node for named directory hash table (nameddirtab) */
 
Index: Test/A06assign.ztst
===================================================================
RCS file: A06assign.ztst
diff -N A06assign.ztst
--- /dev/null	Thu May 24 22:33:05 2001
+++ A06assign.ztst	Mon Dec 17 03:57:30 2001
@@ -0,0 +1,253 @@
+# Tests of parameter assignments
+
+%test
+
+ typeset -A assoc
+ assoc=(one 1 two 2 odd)
+1:assign to association with odd no. of values
+?(eval):2: bad set of key/value pairs for associative array
+
+# tests of var+=scalar
+
+ s+=foo
+ echo $s
+0:append scalar to unset scalar
+>foo
+
+ s=foo
+ s+=bar
+ echo $s
+0:append to scalar
+>foobar
+
+ set -- a b c
+ 2+=end
+ echo $2
+0:append to positional parameter
+>bend
+
+ a=(first second)
+ a+=last
+ print -l $a
+0:add scalar to array
+>first
+>second
+>last
+
+ setopt ksharrays
+ a=(first second)
+ a+=last
+ print -l $a
+ unsetopt ksharrays
+0:add scalar to array with ksharrays set
+>firstlast
+
+ a=(1 2)
+ a[@]+=3
+ print -l $a
+0:add scalar to array with alternate syntax
+>1
+>2
+>3
+
+ integer i=10
+ i+=20
+ (( i == 30 ))
+0:add to integer
+
+ float f=3.4
+ f+=2.3
+ printf "%g\n" f
+0:add to float
+>5.7
+
+ typeset -A hash
+ hash=(one 1)
+ h+=string
+ [[ $h[@] == string ]]
+0:add scalar to association
+
+# tests of var+=(array)
+
+ unset a
+ a+=(1 2 3)
+ print -l $a
+0:add array to unset parameter
+>1
+>2
+>3
+
+ a=(a)
+ a+=(b)
+ print -l $a
+0:add array to existing array
+>a
+>b
+
+ s=foo
+ s+=(bar)
+ print -l $s
+0:add array to scalar
+>foo
+>bar
+
+ integer i=1
+ i+=(2 3)
+ print -l $i
+0:add array to integer
+>1
+>2
+>3
+
+ float f=2.5
+ f+=(3.5 4.5)
+ printf '%g\n' $f
+0:add array to float
+>2.5
+>3.5
+>4.5
+
+ typeset -A h
+ h+=(a 1 b 2)
+ print -l $h
+0:add to empty association
+>1
+>2
+
+ typeset -A h
+ h=(a 1)
+ h+=(b 2 c 3)
+ print -l $h
+0:add to association
+>1
+>2
+>3
+
+# tests of var[range]+=scalar
+
+ s=sting
+ s[2]+=art
+ echo $s
+0:insert scalar inside another
+>starting
+
+ s=inert
+ s[-4]+=s
+ echo $s
+0:insert scalar inside another with negative index
+>insert
+
+ s=append
+ s[2,6]+=age
+ echo $s
+0:append scalar to scalar using a range
+>appendage
+
+ s=123456789
+ s[3,-5]+=X
+ echo $s
+0:insert scalar inside another, specifying a slice
+>12345X6789
+
+ a=(a b c)
+ a[2]+=oo
+ echo $a
+0:append to array element
+>a boo c
+
+ a=(a b c d)
+ a[-2]+=ool
+ echo $a
+0:append to array element with negative index
+>a b cool d
+
+ a=(a b c d)
+ a[2,-1]+=oom
+ echo $a
+0:append to array element, specifying a slice
+>a b c doom
+
+ setopt ksharrays
+ a=(a b c d)
+ a[0]+=0
+ echo $a
+ unsetopt ksharrays
+0:append to array element with ksharrays set
+>a0
+
+ typeset -A h
+ h=(one foo)
+ h[one]+=bar
+ echo $h
+0:append to association element
+>foobar
+
+ typeset -A h
+ h[foo]+=bar
+ echo ${(kv)h}
+0:append to non-existent association element
+>foo bar
+
+ typeset -A h
+ h=(one a two b three c four d)
+ h[(I)*o*]+=append
+1:attempt to append to slice of association
+?(eval):3: h: attempt to set slice of associative array
+
+ integer i=123
+ i[2]+=6
+1:attempt to add to indexed integer variable
+?(eval):2: attempt to add to slice of a numeric variable
+
+ float f=1234.5
+ f[2,4]+=3
+1:attempt to add to slice of float variable
+?(eval):2: attempt to add to slice of a numeric variable
+
+ unset u
+ u[3]+=third
+ echo $u[1]:$u[3]
+0:append to unset variable with index
+>:third
+ 
+# tests of var[range]+=(array)
+
+ a=(1 2 3)
+ a[2]+=(a b)
+ echo $a
+0:insert array inside another
+>1 2 a b 3
+
+ a=(a b c)
+ a[-1]+=(d)
+ echo $a
+0:append to array using negative index
+>a b c d
+
+ a=(1 2 3 4)
+ a[-1,-3]+=(x)
+ echo $a
+0:insert array using negative range
+>1 2 x 3 4
+
+ s=string
+ s[2]+=(a b)
+1:attempt to insert array into string
+?(eval):2: s: attempt to assign array value to non-array
+
+ integer i=365
+ i[2]+=(1 2)
+1:attempt to insert array into string
+?(eval):2: i: attempt to assign array value to non-array
+
+ typeset -A h
+ h=(a 1)
+ h[a]+=(b 2)
+1:attempt to append array to hash element
+?(eval):3: h: attempt to set slice of associative array
+
+ unset u
+ u[-34,-2]+=(a z)
+ echo $u
+0:add array to indexed unset variable
+>a z

_____________________________________________________________________
This message has been checked for all known viruses by the 
MessageLabs Virus Scanning Service. For further information visit
http://www.messagelabs.com/stats.asp


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

* RE: PATCH: += parameter assignments
  2001-12-17 12:02 PATCH: += parameter assignments Oliver Kiddle
@ 2001-12-17 12:11 ` Borsenkow Andrej
  2001-12-17 12:28   ` Peter Stephenson
  2001-12-17 12:28   ` Oliver Kiddle
  0 siblings, 2 replies; 11+ messages in thread
From: Borsenkow Andrej @ 2001-12-17 12:11 UTC (permalink / raw)
  To: 'Oliver Kiddle', zsh-workers

> 
> One possible extension beyond what ksh does would be to also add a -=
> assignment. It could be made to prepend to string and array values
> which would be fairly useful. Or does anyone think that that behaviour
> for -= would be too illogical?
> 

I would prefer += and =+ but that probably breaks ksh93 compatibility.

-andrej


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

* Re: PATCH: += parameter assignments
  2001-12-17 12:11 ` Borsenkow Andrej
@ 2001-12-17 12:28   ` Peter Stephenson
  2001-12-17 12:28   ` Oliver Kiddle
  1 sibling, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2001-12-17 12:28 UTC (permalink / raw)
  To: Zsh hackers list

Borsenkow Andrej wrote:
> > One possible extension beyond what ksh does would be to also add a -=
> > assignment. It could be made to prepend to string and array values
> > which would be fairly useful. Or does anyone think that that behaviour
> > for -= would be too illogical?
> 
> I would prefer += and =+ but that probably breaks ksh93 compatibility.

Using =+ as a special token would break all sorts of things fairly
horribly.

integer i=+3
i=+6

I don't imagine anyone's crying out for the prepending behaviour at the
moment.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, 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] 11+ messages in thread

* Re: PATCH: += parameter assignments
  2001-12-17 12:11 ` Borsenkow Andrej
  2001-12-17 12:28   ` Peter Stephenson
@ 2001-12-17 12:28   ` Oliver Kiddle
  2002-01-07 17:38     ` Bart Schaefer
  1 sibling, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2001-12-17 12:28 UTC (permalink / raw)
  To: Borsenkow Andrej; +Cc: zsh-workers

Borsenkow Andrej wrote:
> 
> > One possible extension beyond what ksh does would be to also add a -=
> > assignment. It could be made to prepend to string and array values

> I would prefer += and =+ but that probably breaks ksh93 compatibility.

This issue wouldn't be ksh93 compatibility so much as backward
compatibility with old zsh scripts or any other scripts.

% a-=val
zsh: command not found: a-=val
% a=+val
% echo %a
+val

With `-' (or `+') not being legal inside identifiers -= only affects
anyone who happens to have a command with `-=' in its name - that should
be fairly rare. Affecting any script that assigns a variable with `+' as
the first character is much more likely to matter (a quick grep shows
two cases in the completion functions).

Do any other languages use `=+' as an operator. Anyone else have any
views on it?

Oliver

_____________________________________________________________________
This message has been checked for all known viruses by the 
MessageLabs Virus Scanning Service. For further information visit
http://www.messagelabs.com/stats.asp


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

* Re: PATCH: += parameter assignments
  2001-12-17 12:28   ` Oliver Kiddle
@ 2002-01-07 17:38     ` Bart Schaefer
  0 siblings, 0 replies; 11+ messages in thread
From: Bart Schaefer @ 2002-01-07 17:38 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh-workers

On Dec 17, 12:28pm, Oliver Kiddle wrote:
} Subject: Re: PATCH: += parameter assignments
}
} Borsenkow Andrej wrote:
} > 
} > > One possible extension beyond what ksh does would be to also add a -=
} > > assignment. It could be made to prepend to string and array values
} 
} > I would prefer += and =+ but that probably breaks ksh93 compatibility.
} 
} This issue wouldn't be ksh93 compatibility so much as backward
} compatibility with old zsh scripts or any other scripts.

Sorry not to have followed up on this one sooner, but it came along as I
was getting ready for winter holidays and I didn't have time.

I'm not entirely happy with the addition of the a+=val syntax because it
conflicts (conceptually, not mechanically) with the += operator that is
already present in the math syntax.  Consider that the following:

    integer i=4
    typeset s=4
    i+=5
    s+=5
    ((i+=5))
    ((s+=5))
    print $i $s

yields

    14 50
    
However, what I consider to be worse is that:

    s=four
    ((s+=5))
    s+=5
    print $s

yields

    55

Interpreting strings as integers in math context makes some sort of sense,
but doing both that, and also overloading += depending on the parameter
type, is going too far.  I think the suggested change for -= would be even
more confusing.

And the following can't be anything but a bug:

    s=4four
    ((s+=5))
    s+=5
    print $s

yeilds

    zsh: bad math expression: operator expected at `four'
    65

(Previously

    s=4four
    ((s+=5))
    print $s

gave

    zsh: bad math expression: operator expected at `four'
    4four

but now it somehow reassigns s as 6.)

-- 
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] 11+ messages in thread

* Re: PATCH: += parameter assignments
  2002-01-14 18:47 ` Bart Schaefer
  2002-01-15 16:16   ` Oliver Kiddle
@ 2002-01-16 14:43   ` Oliver Kiddle
  1 sibling, 0 replies; 11+ messages in thread
From: Oliver Kiddle @ 2002-01-16 14:43 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

Bart wrote:

> } > About the closest thing I can come up with is that all
assignments
> } > in (( )) should force the parameter type to change to numeric
> } > (integer or float), but that has its own set of potential
gotchas.
> }
> } This would seem sensible to me but is it too late to be changing
> that?
> } If you think it is an option then can you elaborate on the
"gotchas"?
>
> You pointed one of them out yourself:
>
>       ((s+=5))
>       s=foo
>
> produces s=0, which could be surprising if `s' was previously a
scalar.

Yes, unless assignments outside (( )) were always scalar as I think
they should be.

> I'd actually forgotten about that effect of assignment to integers.

Having remembered it, would you now agree that the current += behaviour
of doing arithmetic for numerics is at least consistent with normal
assignments?

> } > Better might be if += outside of (( )) always converted numerics
> } > to strings and then did an append.
> }
> } This is perhaps worth considering. I did actually consider it at
the
> } time but didn't do it because of ksh compatibility. To be
consistent
> } with assignments inside (( )), it would have the convert the result
> of
> } the appending back to a numeric type afterwards (which would limit
> the
> } usefulness of it).
>
> It'd also be impossible; following
>
>       integer s=5
>       s+=four
>
> how would one convert `5four' back to an integer?  If the type
> were going to change to scalar, that change would have to stick.

Convert it back to an integer with math evaluation resulting (for
this example) in a bad math expression error. It wouldn't be much use
and would allow some really nasty tricks to be done. My point being
that assignments inside (( )) converting results back to a scalar is
not a good idea in my opinion.

> } But you can't look at s=foo and know what it is going to do because
> if
> } s is an integer, you end up with s being 0 (or whatever foo
> } arithmetically evaluates to). I think it would be better if this
was
> a
> } scalar assignment but it isn't.
>
> I agree that would be better.  A function that wants to create `s' as
a
> global scalar probably *doesn't* have a `typeset -g s=' in it.  If
`s'
> already exists as an integer, strange things are going to happen.

That's bad!

Basically, I can't see a solution that only involves changes to +=
without either leaving inconsistencies with normal assignments or worse
problems.

In summary, I think the ideal would be to make all assignments depend
on context only. So:
  ((a=5)) would always result in a being of integer type and
  a=5     would always result in a being of scalar type
Any scalars used in integer context would still have to be converted to
be numeric first and vice versa. Using typeset to declare a variable as
an integer would only be useful if initialising the variable.

The trouble with this is it would be a big incompatibility and of
minimal use interactively. An option maybe?

> That whole mailing list has been silent for a long time -- or at
least

True but the list probably still works. Unless I missed it, POSIX
doesn't have assignments in arithmetic context or numeric variables.

> I
> haven't received any messages from it.  (In a related note, Austin
> Group
> just got their spec through another hurdle and are accepting errata.)

Have you looked at it recently? The last time I looked, there was very
little change to the shell spec, all the changes being in other areas.

> Really?  I'd say truncation was the reverse of appending.

Well, at least sort of. Enough that with =+ not being an option, it
seemed like a reasonable idea. I couldn't see us ever wanting -= for
truncation as you can already use subscripts to do truncation (and %=
would be more likely). I quite often do things like `fpath=(~+ $fpath)'
so I thought it'd be useful (though I can use a subscript of [1,0]).

Oliver


__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com


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

* Re: PATCH: += parameter assignments
  2002-01-15 16:16   ` Oliver Kiddle
@ 2002-01-15 17:54     ` Bart Schaefer
  0 siblings, 0 replies; 11+ messages in thread
From: Bart Schaefer @ 2002-01-15 17:54 UTC (permalink / raw)
  To: zsh-workers

On Jan 15,  4:16pm, Oliver Kiddle wrote:
} Subject: Re: PATCH: += parameter assignments
}
} > On Jan 14, 12:45pm, Oliver Kiddle wrote:
} 
} > The point is that I can't think of -anything- reasonable to expect,
} > except perhaps that in a saner world ((s+=5)) would be an error
} > because you can't add an integer to a string. Unfortunately we're
} > beyond hope of changing that (and I wouldn't really want to anyway).
} >
} > About the closest thing I can come up with is that all assignments
} > in (( )) should force the parameter type to change to numeric
} > (integer or float), but that has its own set of potential gotchas.
} 
} This would seem sensible to me but is it too late to be changing that?
} If you think it is an option then can you elaborate on the "gotchas"?

You pointed one of them out yourself:

	((s+=5))
	s=foo

produces s=0, which could be surprising if `s' was previously a scalar.
I'd actually forgotten about that effect of assignment to integers.

} > Better might be if += outside of (( )) always converted numerics
} > to strings and then did an append.
} 
} This is perhaps worth considering. I did actually consider it at the
} time but didn't do it because of ksh compatibility. To be consistent
} with assignments inside (( )), it would have the convert the result of
} the appending back to a numeric type afterwards (which would limit the
} usefulness of it).

It'd also be impossible; following

	integer s=5
	s+=four

how would one convert `5four' back to an integer?  If the type were going
to change to scalar, that change would have to stick.

} But you can't look at s=foo and know what it is going to do because if
} s is an integer, you end up with s being 0 (or whatever foo
} arithmetically evaluates to). I think it would be better if this was a
} scalar assignment but it isn't.

I agree that would be better.  A function that wants to create `s' as a
global scalar probably *doesn't* have a `typeset -g s=' in it.  If `s'
already exists as an integer, strange things are going to happen.
 
} My intention was to never in a script use:
}   numeric+=val using (( numeric+=val )) instead or,
}   array+=val using array+=( val ) instead
} so nobody reading the script might be confused.
} 
} Perhaps we could just make a recommendation in the manual that with
} numeric variables assignments outside of (( )) not be used.

I'm more concerned about people who intended to do exactly that but who
mistakenly left out the parens, ending up with a script that works for a
while and then mysteriously breaks.

} Note that David Korn included += in his "first cut" for the new
} standard (item 48. in 3 Aug e-mail) so it might be worth sending him an
} e-mail about this.

That whole mailing list has been silent for a long time -- or at least I
haven't received any messages from it.  (In a related note, Austin Group
just got their spec through another hurdle and are accepting errata.)

} > To have -= be additive for strings and "subtractive" for numeric
} > types is just compounding the problem.
} 
} That probably just depends on how you think about the operations. `+'
} being used as an appending operation seems fairly logical to me without
} thinking about it as being "additive". `-' is the reverse of `+' and
} prepending the reverse of appending

Really?  I'd say truncation was the reverse of appending.  Pop is the
opposite of push; unshift is the opposite of shift, not of push.

-- 
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] 11+ messages in thread

* Re: PATCH: += parameter assignments
  2002-01-14 18:47 ` Bart Schaefer
@ 2002-01-15 16:16   ` Oliver Kiddle
  2002-01-15 17:54     ` Bart Schaefer
  2002-01-16 14:43   ` Oliver Kiddle
  1 sibling, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2002-01-15 16:16 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

> On Jan 14, 12:45pm, Oliver Kiddle wrote:

> The point is that I can't think of -anything- reasonable to expect,
> except perhaps that in a saner world ((s+=5)) would be an error
because
> you can't add an integer to a string.  Unfortunately we're beyond
hope
> of changing that (and I wouldn't really want to anyway).
>
> About the closest thing I can come up with is that all assignments in
> (( )) should force the parameter type to change to numeric (integer
or
> float), but that has its own set of potential gotchas.

This would seem sensible to me but is it too late to be changing that?
If you think it is an option then can you elaborate on the "gotchas"?

> Better might be if += outside of (( )) always converted numerics
> to strings and then did an append.

This is perhaps worth considering. I did actually consider it at the
time but didn't do it because of ksh compatibility. To be consistent
with assignments inside (( )), it would have the convert the result of
the appending back to a numeric type afterwards (which would limit the
usefulness of it).

> The argument is something like this:  It's OK for += to mean "convert
> to
> number, do arithmetic, then convert back to the original type" as
long
> as
> it *always* means that.  It's confusing when it means one thing in ((
> ))
> and two or more things (depending on the parameter type) outside ((
)).
>
> What I don't like is that I can't look at `s+=5' and know what it's
> going
> to do.  At least I know `((s+=5))' will always add 5 numerically,
even
> if
> it might convert s to 0 first.

But you can't look at s=foo and know what it is going to do because if
s is an integer, you end up with s being 0 (or whatever foo
arithmetically evaluates to). I think it would be better if this was a
scalar assignment but it isn't.

My intention was to never in a script use:
  numeric+=val using (( numeric+=val )) instead or,
  array+=val using array+=( val ) instead
so nobody reading the script might be confused.

Perhaps we could just make a recommendation in the manual that with
numeric variables assignments outside of (( )) not be used.

Note that David Korn included += in his "first cut" for the new
standard (item 48. in 3 Aug e-mail) so it might be worth sending him an
e-mail about this.

> To have -= be additive for strings and "subtractive" for numeric
types
> is just compounding the problem.

That probably just depends on how you think about the operations. `+'
being used as an appending operation seems fairly logical to me without
thinking about it as being "additive". `-' is the reverse of `+' and
prepending the reverse of appending so `-=' for prepending made sense
to me. I suppose I've used languages where `+' is a concatenation
operator quite a lot so am used to it. Anyway, I'm happy to accept that
it might seem less logical to other people and I won't be implementing
it now.

Oliver

__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com


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

* Re: PATCH: += parameter assignments
  2002-01-14 12:45 Oliver Kiddle
  2002-01-14 13:04 ` Peter Stephenson
@ 2002-01-14 18:47 ` Bart Schaefer
  2002-01-15 16:16   ` Oliver Kiddle
  2002-01-16 14:43   ` Oliver Kiddle
  1 sibling, 2 replies; 11+ messages in thread
From: Bart Schaefer @ 2002-01-14 18:47 UTC (permalink / raw)
  To: Oliver Kiddle, zsh-workers

On Jan 14, 12:45pm, Oliver Kiddle wrote:
} Subject: Re: PATCH: += parameter assignments
}
} Bart Schaefer wrote:
} 
} >     integer i=4
} >     typeset s=4
} >     i+=5
} >     s+=5
} >     ((i+=5))
} >     ((s+=5))
} >     print $i $s
} >
} > yields
} >
} >     14 50
} 
} What would you have sooner expected - `14 14'?

The point is that I can't think of -anything- reasonable to expect,
except perhaps that in a saner world ((s+=5)) would be an error because
you can't add an integer to a string.  Unfortunately we're beyond hope
of changing that (and I wouldn't really want to anyway).

About the closest thing I can come up with is that all assignments in
(( )) should force the parameter type to change to numeric (integer or
float), but that has its own set of potential gotchas.  Better might
be if += outside of (( )) always converted numerics to strings and then
did an append.

} > However, what I consider to be worse is that:
} >
} >     s=four
} >     ((s+=5))
} >     s+=5
} >     print $s
} >
} > yields
} >
} >     55

(Incidentally, while were on that subject:

	s=4four
	((s+=5))

gives an error (bad math expression: operator expected at `four'), so why
doesn't that same thing happen when the leading digit is absent?)

} I'm not sure that I've entirely understood your argument here as your
} example doesn't seem particularly confusing to me. The ((s+=5)) results
} in 5 with s remaining a scalar - that was the case before. It remained
} a scalar so the s+=5 results in 55.

The argument is something like this:  It's OK for += to mean "convert to
number, do arithmetic, then convert back to the original type" as long as
it *always* means that.  It's confusing when it means one thing in (( ))
and two or more things (depending on the parameter type) outside (( )).

To have -= be additive for strings and "subtractive" for numeric types
is just compounding the problem.

} The results might not be imediately obvious after a mix of both the
} math and non-math += for scalars but considered on their own I don't
} find them "confusing".

What I don't like is that I can't look at `s+=5' and know what it's going
to do.  At least I know `((s+=5))' will always add 5 numerically, even if
it might convert s to 0 first.

-- 
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] 11+ messages in thread

* Re: PATCH: += parameter assignments
  2002-01-14 12:45 Oliver Kiddle
@ 2002-01-14 13:04 ` Peter Stephenson
  2002-01-14 18:47 ` Bart Schaefer
  1 sibling, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2002-01-14 13:04 UTC (permalink / raw)
  To: Zsh hackers list

Oliver wrote:
> > And the following can't be anything but a bug:
> 
> A bug maybe, but it has bugger all to do with the += code.
> 
> > (Previously
> 
> meaning 4.0.4 but 4.1.0-dev-1 behaves as now so the problem will have
> been introduced sometime before that. 15292 at a guess as that is the
> one in that time frame dealing with math.c.

pop() can now retrieve variables, so we need to check for errors when it
does.

Index: Src/math.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/math.c,v
retrieving revision 1.11
diff -u -r1.11 math.c
--- Src/math.c	2001/07/08 00:30:43	1.11
+++ Src/math.c	2002/01/14 13:02:22
@@ -497,7 +497,7 @@
     if (mv->val.type == MN_UNSET && !noget)
 	mv->val = getnparam(mv->lval);
     sp--;
-    return mv->val;
+    return errflag ? zero_mnumber : mv->val;
 }
 
 /**/
@@ -630,6 +630,8 @@
 	DPUTS(sp < 1, "BUG: math: not enough wallabies in outback.");
 	b = pop(0);
 	a = pop(what == EQ);
+	if (errflag)
+	    return;
 
 	if (tp & (OP_A2IO|OP_E2IO)) {
 	    /* coerce to integers */
@@ -856,6 +858,8 @@
 	c = pop(0);
 	b = pop(0);
 	a = pop(0);
+	if (errflag)
+	    return;
 	/* b and c can stay different types in this case. */
 	push(((a.type & MN_FLOAT) ? a.u.d : a.u.l) ? b : c, NULL, 0);
 	break;

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, 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] 11+ messages in thread

* Re: PATCH: += parameter assignments
@ 2002-01-14 12:45 Oliver Kiddle
  2002-01-14 13:04 ` Peter Stephenson
  2002-01-14 18:47 ` Bart Schaefer
  0 siblings, 2 replies; 11+ messages in thread
From: Oliver Kiddle @ 2002-01-14 12:45 UTC (permalink / raw)
  To: zsh-workers; +Cc: schaefer

Sorry if you get this twice - I'm resending it after it didn't turn up
first time and sorry if Yahoo re-wraps the text horribly.

Bart Schaefer wrote:

> I'm not entirely happy with the addition of the a+=val syntax because
> it
> conflicts (conceptually, not mechanically) with the += operator that
is
> already present in the math syntax.  Consider that the following:
>
>     integer i=4
>     typeset s=4
>     i+=5
>     s+=5
>     ((i+=5))
>     ((s+=5))
>     print $i $s
>
> yields
>
>     14 50

What would you have sooner expected - `14 14'?

>
> However, what I consider to be worse is that:
>
>     s=four
>     ((s+=5))
>     s+=5
>     print $s
>
> yields
>
>     55
>
> Interpreting strings as integers in math context makes some sort of
> sense, but doing both that, and also overloading += depending on the
> parameter type, is going too far.  I think the suggested change for
> -= would be even more confusing.

I'm not sure that I've entirely understood your argument here as your
example doesn't seem particularly confusing to me. The ((s+=5)) results
in 5 with s remaining a scalar - that was the case before. It remained
a scalar so the s+=5 results in 55.

I don't think it is ideal that the new += can be used for numeric
addition. I find += to be useful with arrays, scalars and associations
and it is these (with the addition of compound variables) for which I
imagine this feature was intended in ksh93. My intention was to
continue to use (( ... )) when dealing with numerics  - we could add a
note to recommend this in the documentation.

Have you got any ideas on how to solve this? Short of ditching +=, the
only thing I can think of would be to make scalar+=val identical to
(( scalar+=val )) but I think it would be a pity to lose the appending
to scalars functionality. Does anyone else have any view or ideas?

> type, is going too far.  I think the suggested change for -= would be
> even more confusing.

The results might not be imediately obvious after a mix of both the
math and non-math += for scalars but considered on their own I don't
find them "confusing".

> And the following can't be anything but a bug:

A bug maybe, but it has bugger all to do with the += code.

> (Previously

meaning 4.0.4 but 4.1.0-dev-1 behaves as now so the problem will have
been introduced sometime before that. 15292 at a guess as that is the
one in that time frame dealing with math.c.

Oliver



__________________________________________________
Do You Yahoo!?
Everything you'll ever need on one web page
from News and Sport to Email and Music Charts
http://uk.my.yahoo.com


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

end of thread, other threads:[~2002-01-16 14:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-12-17 12:02 PATCH: += parameter assignments Oliver Kiddle
2001-12-17 12:11 ` Borsenkow Andrej
2001-12-17 12:28   ` Peter Stephenson
2001-12-17 12:28   ` Oliver Kiddle
2002-01-07 17:38     ` Bart Schaefer
2002-01-14 12:45 Oliver Kiddle
2002-01-14 13:04 ` Peter Stephenson
2002-01-14 18:47 ` Bart Schaefer
2002-01-15 16:16   ` Oliver Kiddle
2002-01-15 17:54     ` Bart Schaefer
2002-01-16 14:43   ` Oliver Kiddle

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).