51484: Extend named reference handling for special parameters, improve doc.

This commit is contained in:
Bart Schaefer 2023-03-05 14:06:25 -08:00
parent a9ba166216
commit 4bc1f6e0d2
3 changed files with 69 additions and 44 deletions

View file

@ -1,5 +1,8 @@
2023-03-05 Bart Schaefer <schaefer@zsh.org>
* 51484: Src/builtins.yo Src/params.c: Extend named reference
handling for special parameters, improve doc.
* 51483: Src/Zle/compcore.c, Src/Zle/zle_tricky.c, Src/lex.c,
Src/params.c, Src/subst.c, Src/utils.c, Src/zsh.h, Src/ztype.h:
Enable assignment and expansion of parameters with ksh-like

View file

@ -1924,6 +1924,8 @@ redef(SPACES)(0)(tt(ifztexi(NOTRANS(@ @ @ @ @ @ @ @ ))ifnztexi( )))
xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(AHUaghlmrtux) ] \
[ {tt(PLUS())|tt(-)}tt(EFLRZip) [ var(n) ] ])
xitem(SPACES()[ tt(+) ] [ var(name)[tt(=)var(value)] ... ])
xitem(tt(typeset )[ {tt(PLUS())|tt(-)}tt(n) ] \
[ tt(-gr) ] [ var(name)[tt(=)var(value)] ... ])
xitem(tt(typeset )tt(-T) [ {tt(PLUS())|tt(-)}tt(Uglrux) ] [ {tt(PLUS())|tt(-)}tt(LRZp) [ var(n) ] ])
xitem(SPACES()[ tt(+) | var(SCALAR)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])
item(tt(typeset) tt(-f) [ {tt(PLUS())|tt(-)}tt(TUkmtuz) ] [ tt(+) ] [ var(name) ... ])(

View file

@ -475,6 +475,15 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
!(V)->pm->node.nam || !*(V)->pm->node.nam))
/*
* For named references. Simple named references are just like scalars
* for efficiency, but special named references need get/set functions.
*/
#define GETREFNAME(PM) (((PM)->node.flags & PM_SPECIAL) ? \
(PM)->gsu.s->getfn(PM) : (PM)->u.str)
#define SETREFNAME(PM,S) (((PM)->node.flags & PM_SPECIAL) ? \
(PM)->gsu.s->setfn(PM,(S)) : ((PM)->u.str = (S)))
static Param argvparam;
/* "parameter table" - hash table containing the parameters
@ -520,7 +529,7 @@ getparamnode(HashTable ht, const char *nam)
HashNode hn = gethashnode2(ht, nam);
Param pm = (Param) hn;
if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
if (pm && (pm->node.flags & PM_AUTOLOAD) && pm->u.str) {
char *mn = dupstring(pm->u.str);
(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
@ -1002,12 +1011,13 @@ createparam(char *name, int flags)
struct asgment stop;
stop.flags = PM_NAMEREF | (flags & PM_LOCAL);
stop.name = oldpm->node.nam;
stop.value.scalar = oldpm->u.str;
stop.value.scalar = GETREFNAME(oldpm);
lastpm = (Param)resolve_nameref(oldpm, &stop);
if (lastpm) {
if (lastpm->node.flags & PM_NAMEREF) {
if (lastpm->u.str && *(lastpm->u.str)) {
name = lastpm->u.str;
char *refname = GETREFNAME(lastpm);
if (refname && *refname) {
name = refname;
oldpm = NULL;
} else {
if (!(lastpm->node.flags & PM_READONLY))
@ -2145,25 +2155,28 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
memset(v, 0, sizeof(*v));
else
v = (Value) hcalloc(sizeof *v);
if ((pm->node.flags & PM_NAMEREF) && pm->u.str && *(pm->u.str)) {
/* only happens for namerefs pointing to array elements */
char *ref = dupstring(pm->u.str);
char *ss = pm->width ? ref + pm->width : NULL;
if (ss) {
sav = *ss;
*ss = 0;
if (pm->node.flags & PM_NAMEREF) {
char *refname = GETREFNAME(pm);
if (refname && *refname) {
/* only happens for namerefs pointing to array elements */
char *ref = dupstring(refname);
char *ss = pm->width ? ref + pm->width : NULL;
if (ss) {
sav = *ss;
*ss = 0;
}
Param p1 = (Param)gethashnode2(paramtab, ref);
if (!(p1 && (pm = upscope(p1, pm->base))) ||
((pm->node.flags & PM_UNSET) &&
!(pm->node.flags & PM_DECLARED)))
return NULL;
if (ss) {
flags |= SCANPM_NOEXEC;
*ss = sav;
s = dyncat(ss,*pptr);
} else
s = *pptr;
}
Param p1 = (Param)gethashnode2(paramtab, ref);
if (!(p1 && (pm = upscope(p1, pm->base))) ||
((pm->node.flags & PM_UNSET) &&
!(pm->node.flags & PM_DECLARED)))
return NULL;
if (ss) {
flags |= SCANPM_NOEXEC;
*ss = sav;
s = dyncat(ss,*pptr);
} else
s = *pptr;
}
if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
/* Overload v->isarr as the flag bits for hashed arrays. */
@ -3648,7 +3661,7 @@ mod_export Param
setiparam_no_convert(char *s, zlong val)
{
/*
* If the target is already an integer, thisgets converted
* If the target is already an integer, this gets converted
* back. Low technology rules.
*/
char buf[BDIGBUFSIZE];
@ -6115,22 +6128,23 @@ resolve_nameref(Param pm, const Asgment stop)
const char *seek = stop ? stop->value.scalar : NULL;
if (pm && (pm->node.flags & PM_NAMEREF)) {
if (pm && (pm->node.flags & (PM_UNSET|PM_TAGGED))) {
char *refname = GETREFNAME(pm);
if (pm->node.flags & (PM_UNSET|PM_TAGGED)) {
/* Semaphore with createparam() */
pm->node.flags &= ~PM_UNSET;
if (pm->node.flags & PM_NEWREF) /* See setloopvar() */
return NULL;
if (pm->u.str && *(pm->u.str) && (pm->node.flags & PM_TAGGED))
if (refname && *refname && (pm->node.flags & PM_TAGGED))
pm->node.flags |= PM_SELFREF; /* See setscope() */
return (HashNode) pm;
} else if (pm->u.str) {
} else if (refname) {
if ((pm->node.flags & PM_TAGGED) ||
(stop && strcmp(pm->u.str, stop->name) == 0)) {
/* zwarnnam(pm->u.str, "invalid self reference"); */
(stop && strcmp(refname, stop->name) == 0)) {
/* zwarnnam(refname, "invalid self reference"); */
return stop ? (HashNode)pm : NULL;
}
if (*(pm->u.str))
seek = pm->u.str;
if (*refname)
seek = refname;
}
}
else if (pm && !(stop && (stop->flags & PM_NAMEREF)))
@ -6180,8 +6194,13 @@ setloopvar(char *name, char *value)
Param pm = (Param) gethashnode2(realparamtab, name);
if (pm && (pm->node.flags & PM_NAMEREF)) {
if (pm->node.flags & PM_READONLY) {
/* Bash error is: "%s: readonly variable" */
zerr("read-only reference: %s", pm->node.nam);
return;
}
pm->base = pm->width = 0;
pm->u.str = ztrdup(value);
SETREFNAME(pm, ztrdup(value));
pm->node.flags &= ~PM_UNSET;
pm->node.flags |= PM_NEWREF;
setscope(pm);
@ -6197,7 +6216,8 @@ setscope(Param pm)
if (pm->node.flags & PM_NAMEREF) {
Param basepm;
struct asgment stop;
char *t = pm->u.str ? itype_end(pm->u.str, INAMESPC, 0) : NULL;
char *refname = GETREFNAME(pm);
char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
/* Temporarily change nameref to array parameter itself */
if (t && *t == '[')
@ -6211,7 +6231,7 @@ setscope(Param pm)
stop.flags |= PM_LOCAL;
basepm = (Param)resolve_nameref(pm, &stop);
if (t) {
pm->width = t - pm->u.str;
pm->width = t - refname;
*t = '[';
}
if (basepm) {
@ -6220,23 +6240,23 @@ setscope(Param pm)
if (pm->node.flags & PM_SELFREF) {
/* Loop signalled by resolve_nameref() */
if (upscope(pm, pm->base) == pm) {
zerr("%s: invalid self reference", pm->u.str);
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
pm->node.flags &= ~PM_SELFREF;
} else if (pm->base == pm->level) {
if (pm->u.str && *(pm->u.str) &&
strcmp(pm->node.nam, pm->u.str) == 0) {
zerr("%s: invalid self reference", pm->u.str);
if (refname && *refname &&
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
}
} else if (basepm->u.str) {
} else if ((t = GETREFNAME(basepm))) {
if (basepm->base <= basepm->level &&
strcmp(pm->node.nam, basepm->u.str) == 0) {
zerr("%s: invalid self reference", pm->u.str);
strcmp(pm->node.nam, t) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
return;
}
@ -6251,11 +6271,11 @@ setscope(Param pm)
unsetparam_pm(pm, 0, 1);
} else if (isset(WARNNESTEDVAR))
zwarn("reference %s in enclosing scope set to local variable %s",
pm->node.nam, pm->u.str);
pm->node.nam, refname);
}
if (pm->u.str && upscope(pm, pm->base) == pm &&
strcmp(pm->node.nam, pm->u.str) == 0) {
zerr("%s: invalid self reference", pm->u.str);
if (refname && upscope(pm, pm->base) == pm &&
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
}
}