diff options
| author | Philippe Altherr <philippe.altherr@gmail.com> | 2025-11-09 15:28:13 -0800 |
|---|---|---|
| committer | Bart Schaefer <schaefer@zsh.org> | 2025-11-09 15:28:13 -0800 |
| commit | 0d76a82c77706e6ab2adbb91d1d306824dfa6f33 (patch) | |
| tree | a890a308c0199568c3dec5d53db84c6d6154e0a6 | |
| parent | github #148: complete fortune databases (diff) | |
| download | zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar.gz zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar.bz2 zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar.lz zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar.xz zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.tar.zst zsh-0d76a82c77706e6ab2adbb91d1d306824dfa6f33.zip | |
54057: enable assignment through named reference to change type of the referent
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | Src/params.c | 68 | ||||
| -rw-r--r-- | Src/zsh.h | 7 | ||||
| -rw-r--r-- | Test/K01nameref.ztst | 159 |
4 files changed, 221 insertions, 19 deletions
@@ -1,3 +1,9 @@ +2025-11-09 Bart Schaefer <schaefer@zsh.org> + + * Philippe: 54057: Src/params.c, Src/zsh.h, Test/K01nameref.ztst: + add VALFLAG_REFSLICE to enable assignment through named reference + to change type of the referent + 2025-11-03 Oliver Kiddle <opk@zsh.org> * Christopher Bock: github #148: Completion/Unix/Command/_fortune: diff --git a/Src/params.c b/Src/params.c index 5a0434e40..b76fb8a6b 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2203,6 +2203,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) } else { Param pm; int isvarat; + int isrefslice = 0; isvarat = (t[0] == '@' && !t[1]); if (flags & SCANPM_NONAMEREF) @@ -2250,6 +2251,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) flags |= SCANPM_NOEXEC; *ss = sav; s = dyncat(ss,*pptr); + isrefslice = 1; } else s = *pptr; } @@ -2264,7 +2266,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags) v->isarr = SCANPM_ARRONLY; } v->pm = pm; - v->flags = 0; + v->flags = isrefslice ? VALFLAG_REFSLICE : 0; v->start = 0; v->end = -1; if (bracks > 0 && (*s == '[' || *s == Inbrack)) { @@ -3222,12 +3224,18 @@ assignsparam(char *s, char *val, int flags) if (!(v = getvalue(&vbuf, &s, 1))) { createparam(t, PM_SCALAR); created = 1; - } else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) || - (v->pm->node.flags & PM_HASHED)) && - !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) && - unset(KSHARRAYS)) { - unsetparam(t); - createparam(t, PM_SCALAR); + } else if ((((v->pm->node.flags & PM_ARRAY) && + !(v->flags & VALFLAG_REFSLICE) && + !(flags & ASSPM_AUGMENT)) || + (v->pm->node.flags & PM_HASHED)) && + !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) && + unset(KSHARRAYS)) { + if (resetparam(v->pm, PM_SCALAR)) { + unqueue_signals(); + zsfree(val); + errflag |= ERRFLAG_ERROR; + return NULL; + } /* not regarded as a new creation */ v = NULL; } @@ -3378,7 +3386,8 @@ assignaparam(char *s, char **val, int flags) createparam(t, PM_ARRAY); created = 1; } else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) && - !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) { + !(v->flags & VALFLAG_REFSLICE) && + !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) { int uniq = v->pm->node.flags & PM_UNIQUE; if ((flags & ASSPM_AUGMENT) && !(v->pm->node.flags & PM_UNSET)) { /* insert old value at the beginning of the val array */ @@ -3391,8 +3400,12 @@ assignaparam(char *s, char **val, int flags) free(val); val = new; } - unsetparam(t); - createparam(t, PM_ARRAY | uniq); + if (resetparam(v->pm, PM_ARRAY | uniq)) { + unqueue_signals(); + freearray(val); + errflag |= ERRFLAG_ERROR; + return NULL; + } v = NULL; } } @@ -3600,11 +3613,15 @@ sethparam(char *s, char **val) if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING))) { createparam(t, PM_HASHED); checkcreate = 1; - } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED)) { + } else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) && + !(v->flags & VALFLAG_REFSLICE)) { if (!(v->pm->node.flags & PM_SPECIAL)) { - unsetparam(t); - /* no WARNCREATEGLOBAL check here as parameter already existed */ - createparam(t, PM_HASHED); + if (resetparam(v->pm, PM_HASHED)) { + unqueue_signals(); + freearray(val); + errflag |= ERRFLAG_ERROR; + return NULL; + } v = NULL; } else { zerr("%s: can't change type of a special parameter", t); @@ -3761,6 +3778,29 @@ setiparam_no_convert(char *s, zlong val) return assignsparam(s, ztrdup(buf), ASSPM_WARN); } +/* Reset a parameter */ + +/**/ +mod_export int +resetparam(Param pm, int flags) +{ + char *s = pm->node.nam; + queue_signals(); + if (pm != (Param)(paramtab == realparamtab ? + /* getnode2() to avoid autoloading */ + paramtab->getnode2(paramtab, s) : + paramtab->getnode(paramtab, s))) { + unqueue_signals(); + zerr("can't change type of hidden variable: %s", s); + return 1; + } + s = dupstring(s); + unsetparam_pm(pm, 0, 1); + unqueue_signals(); + createparam(s, flags); + return 0; +} + /* Unset a parameter */ /**/ @@ -742,18 +742,19 @@ struct multio { /* lvalue for variable assignment/expansion */ struct value { - int isarr; Param pm; /* parameter node */ + char **arr; /* cache for hash turned into array */ + int isarr; int flags; /* flags defined below */ int start; /* first element of array slice, or -1 */ int end; /* 1-rel last element of array slice, or -1 */ - char **arr; /* cache for hash turned into array */ }; enum { VALFLAG_INV = 0x0001, /* We are performing inverse subscripting */ VALFLAG_EMPTY = 0x0002, /* Subscripted range is empty */ - VALFLAG_SUBST = 0x0004 /* Substitution, so apply padding, case flags */ + VALFLAG_SUBST = 0x0004, /* Substitution, so apply padding, case flags */ + VALFLAG_REFSLICE= 0x0008 /* Value is a reference to an array slice */ }; #define MAX_ARRLEN 262144 diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index de9707c5e..5d229a94e 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -753,9 +753,9 @@ F:Same test, should part 5 output look like this? outer() { local foo=outer; inner foo; typeset -p foo; } foo=3 ; { outer foo } always { typeset -p foo } ) -1:up-reference part 11, assignment to enclosing scope, type mismatch +0:up-reference part 11, assignment to enclosing scope, type mismatch +>typeset -a foo=( alpha beta gamma ) >typeset -g foo=3 -?inner: foo: attempt to assign array value to non-array ( inner() { local -n var="${1:?}"; unset var; var=(alpha beta gamma); } @@ -1372,4 +1372,159 @@ F:previously this could create an infinite recursion and crash >reached *?*: ref1: invalid self reference + typeset -A -g VAR0=(aa AA) + typeset -n -g REF0=VAR0 + typeset -A -g var0=(aa AA) + typeset -A var1=(aa AA) + () { + typeset -A var2=(aa AA) + typeset -n ref0=var0 ref1=var1 ref2=var2 + # Test initial association + typeset -pm VAR0 var\? + REF0=(zz ZZ); ref0=(zz ZZ); ref1=(zz ZZ); ref2=(zz ZZ); + typeset -pm VAR0 var\? + # Test change from association to string + REF0=foo; ref0=foo; ref1=foo; ref2=foo; + typeset -pm VAR0 var\? + REF0=bar; ref0=bar; ref1=bar; ref2=bar; + typeset -pm VAR0 var\? + # Test change from string to array + REF0=(aa AA); ref0=(aa AA); ref1=(aa AA); ref2=(aa AA); + typeset -pm VAR0 var\? + REF0=(zz ZZ); ref0=(zz ZZ); ref1=(zz ZZ); ref2=(zz ZZ); + typeset -pm VAR0 var\? + # Test change from array to string + REF0=foo; ref0=foo; ref1=foo; ref2=foo; + typeset -pm VAR0 var\? + } +0:type changes via assignments to references +>typeset -g -A VAR0=( [aa]=AA ) +>typeset -g -A var0=( [aa]=AA ) +>typeset -g -A var1=( [aa]=AA ) +>typeset -A var2=( [aa]=AA ) +>typeset -g -A VAR0=( [zz]=ZZ ) +>typeset -g -A var0=( [zz]=ZZ ) +>typeset -g -A var1=( [zz]=ZZ ) +>typeset -A var2=( [zz]=ZZ ) +>typeset -g VAR0=foo +>typeset -g var0=foo +>typeset -g var1=foo +>typeset var2=foo +>typeset -g VAR0=bar +>typeset -g var0=bar +>typeset -g var1=bar +>typeset var2=bar +>typeset -g -a VAR0=( aa AA ) +>typeset -g -a var0=( aa AA ) +>typeset -g -a var1=( aa AA ) +>typeset -a var2=( aa AA ) +>typeset -g -a VAR0=( zz ZZ ) +>typeset -g -a var0=( zz ZZ ) +>typeset -g -a var1=( zz ZZ ) +>typeset -a var2=( zz ZZ ) +>typeset -g VAR0=foo +>typeset -g var0=foo +>typeset -g var1=foo +>typeset var2=foo + + typeset -A -g ass0=(aa AA) + typeset -A ass1=(aa AA) + typeset -a -g arr0=(aa AA) + typeset -a arr1=(aa AA) + typeset -g str0=foo + typeset str1=foo + () { + typeset -n Ass0=ass0 Ass1=ass1 Arr0=arr0 Arr1=arr1 Str0=str0 Str1=str1 + typeset ass0 ass1 arr0 arr1 str0 str1 + { Ass0=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { Ass1=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { Arr0=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { Arr1=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { Str0=(x) } always { TRY_BLOCK_ERROR=0 }; echo $? + { Str1=(x) } always { TRY_BLOCK_ERROR=0 }; echo $? + } + typeset -p ass0 ass1 arr0 arr1 str0 str1 +0:can't change type of hidden variables via assignments to references +>1 +>1 +>1 +>1 +>1 +>1 +>typeset -g -A ass0=( [aa]=AA ) +>typeset -A ass1=( [aa]=AA ) +>typeset -g -a arr0=( aa AA ) +>typeset -a arr1=( aa AA ) +>typeset -g str0=foo +>typeset str1=foo +?(anon):3: can't change type of hidden variable: ass0 +?(anon):4: can't change type of hidden variable: ass1 +?(anon):5: can't change type of hidden variable: arr0 +?(anon):6: can't change type of hidden variable: arr1 +?(anon):7: can't change type of hidden variable: str0 +?(anon):8: can't change type of hidden variable: str1 + + typeset -A ass=(aa AA) + typeset -a arr=(aa AA) + typeset -i int=42 + typeset str=foo + typeset -n Ass=ass Arr=arr Int=int Str=str + { typeset Ass=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { typeset Arr=foo } always { TRY_BLOCK_ERROR=0 }; echo $? + { typeset Int=(aa AA) } always { TRY_BLOCK_ERROR=0 }; echo $? + { typeset Str=(aa AA) } always { TRY_BLOCK_ERROR=0 }; echo $? + typeset -p ass arr int str +0:type changes via plain typeset to references +F:converting from association/array to string should work here too +>1 +>1 +>0 +>0 +>typeset -A ass=( [aa]=AA ) +>typeset -a arr=( aa AA ) +>typeset -a int=( aa AA ) +>typeset -a str=( aa AA ) +?(eval):typeset:6: ass: inconsistent type for assignment +?(eval):typeset:7: arr: inconsistent type for assignment + + typeset var + typeset -n ref=var + # Change type to string + unset var; typeset var=fubar; typeset ref=barfu; typeset -p var + unset var; typeset -i var=12345; typeset +i ref=barfu; typeset -p var + unset var; typeset -a var=(a A); typeset +a ref=barfu; typeset -p var + unset var; typeset -A var=(a A); typeset +A ref=barfu; typeset -p var + # Change type to integer + unset var; typeset var=fubar; typeset -i ref=56789; typeset -p var + unset var; typeset -i var=12345; typeset -i ref=56789; typeset -p var + unset var; typeset -a var=(a A); typeset -i ref=56789; typeset -p var + unset var; typeset -A var=(a A); typeset -i ref=56789; typeset -p var + # Change type to array + unset var; typeset var=fubar; typeset -a ref=(z Z); typeset -p var + unset var; typeset -i var=12345; typeset -a ref=(z Z); typeset -p var + unset var; typeset -a var=(a A); typeset -a ref=(z Z); typeset -p var + unset var; typeset -A var=(a A); typeset -a ref=(z Z); typeset -p var + # Change type to association + unset var; typeset var=fubar; typeset -A ref=(z Z); typeset -p var + unset var; typeset -i var=12345; typeset -A ref=(z Z); typeset -p var + unset var; typeset -a var=(a A); typeset -A ref=(z Z); typeset -p var + unset var; typeset -A var=(a A); typeset -A ref=(z Z); typeset -p var +0:type changes via typed typeset to references +>typeset var=barfu +>typeset var=barfu +>typeset var=barfu +>typeset var=barfu +>typeset -i var=56789 +>typeset -i var=56789 +>typeset -i var=56789 +>typeset -i var=56789 +>typeset -a var=( z Z ) +>typeset -a var=( z Z ) +>typeset -a var=( z Z ) +>typeset -a var=( z Z ) +>typeset -A var=( [z]=Z ) +>typeset -A var=( [z]=Z ) +>typeset -A var=( [z]=Z ) +>typeset -A var=( [z]=Z ) + %clean |
