Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: All the way up or current scope
Here is my comparison doc, more details in the introduction.
It still needs work but it's already way too long and it should be good enough for our current purpose.
In attachment the patch that I used for zsh-loose. Obviously not something you would like to merge. I just did the minimum to get the behavior I expected from loose references. I didn't have time to find and remove all the code that is no longer needed nor did I update the tests.
Philippe
Thanks, I think that I managed to get the behavior I wanted. I will now work on the side-by-side comparison during my ferry trip. I'll probably have no Internet connection. Hopefully I can send it Saturday.
Philippe
On Tue, May 13, 2025 at 5:09 AM Philippe Altherr
<philippe.altherr@xxxxxxxxx> wrote:
>
> One thing that would help me for creating that side-by-side comparisons is the ability to test -u0 references with a real implementation rather than simulating them in my head.
I still plan to respond to the discussion when I have a chance, but
for the sake of argument, I believe if you apply this patch, then
"setopt warn_nested_var" will (instead of warning) change the behavior
to scope "typeset -n" references in the way you suggest.
diff --git a/Src/params.c b/Src/params.c
index 7b515515e..680547938 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6430,9 +6430,13 @@ setscope(Param pm)
zerr("%s: global reference cannot refer to local variable",
pm->node.nam);
unsetparam_pm(pm, 0, 1);
- } else if (isset(WARNNESTEDVAR))
+ } else if (isset(WARNNESTEDVAR)) {
+ pm->base = pm->level;
+ /*
zwarn("reference %s in enclosing scope set to local
variable %s",
pm->node.nam, refname);
+ */
+ }
}
if (refname && upscope(pm, pm->base) == pm &&
strcmp(pm->node.nam, refname) == 0) {
diff --git a/Src/builtin.c b/Src/builtin.c
index 5563bdba9..48f7a330b 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2303,6 +2303,9 @@ typeset_single(char *cname, char *pname, Param pm, int func,
if (typeset_setbase(cname, pm, ops, on, 0))
return NULL;
}
+ if (on & (PM_NAMEREF)) {
+ pm->upper = pm->node.flags & PM_UPPER ? 1 : 0;
+ }
if (!(pm->node.flags & (PM_ARRAY|PM_HASHED))) {
if (pm->node.flags & PM_EXPORTED) {
if (!(pm->node.flags & PM_UNSET) && !pm->env && !ASG_VALUEP(asg))
@@ -2457,6 +2460,9 @@ typeset_single(char *cname, char *pname, Param pm, int func,
if (typeset_setbase(cname, pm, ops, on, 1))
return NULL;
}
+ if (on & (PM_NAMEREF)) {
+ pm->upper = pm->node.flags & PM_UPPER ? 1 : 0;
+ }
} else if ((subscript = strchr(pname, '['))) {
if (on & PM_NAMEREF) {
zerrnam(cname,
@@ -2549,6 +2555,10 @@ typeset_single(char *cname, char *pname, Param pm, int func,
return NULL;
}
}
+ if (on & (PM_NAMEREF)) {
+ pm->upper = pm->node.flags & PM_UPPER ? 1 : 0;
+ }
+ // zwarnnam(cname, "!!! TYPEREF CC5: %s - %d", pname, pm->upper);
if (isset(TYPESETTOUNSET))
pm->node.flags |= PM_DEFAULTED;
} else {
@@ -2608,6 +2618,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
if (!(pm=assignaparam(pname, arrayval, flags)))
return NULL;
} else {
+ // zwarnnam(cname, "!!! TYPEREF DD2: %s", pname);
DPUTS(ASG_ARRAYP(asg), "BUG: inconsistent array value for scalar");
if (!(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
return NULL;
diff --git a/Src/params.c b/Src/params.c
index 7b515515e..865951e6a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -1019,7 +1019,7 @@ createparam(char *name, int flags)
if (!(flags & PM_LOCAL)) {
/* Must call the API for namerefs and specials to work */
pm = (Param) paramtab->getnode2(paramtab, oldpm->node.nam);
- if (!pm || ((pm->node.flags & PM_NAMEREF) &&
+ if (!pm || ((pm->node.flags & PM_NAMEREF) && // OK
pm->level != locallevel)) {
zerr("%s: can't modify read-only parameter", name);
return NULL;
@@ -1034,19 +1034,19 @@ createparam(char *name, int flags)
**/
}
- if (oldpm && !(flags & PM_NAMEREF) &&
+ if (oldpm && !(flags & PM_NAMEREF) && // OK
(oldpm->level == locallevel ?
!(oldpm->node.flags & PM_RO_BY_DESIGN) : !(flags & PM_LOCAL)) &&
- (oldpm->node.flags & PM_NAMEREF) &&
- (oldpm = upscope(oldpm, oldpm->base))) {
+ (oldpm->node.flags & PM_NAMEREF) && // ???
+ (oldpm = upscope(oldpm, oldpm->base))) { // ???
Param lastpm;
struct asgment stop;
- stop.flags = PM_NAMEREF | (flags & PM_LOCAL);
+ stop.flags = PM_NAMEREF | (flags & PM_LOCAL); // OK
stop.name = oldpm->node.nam;
stop.value.scalar = GETREFNAME(oldpm);
lastpm = (Param)resolve_nameref(oldpm, &stop);
if (lastpm) {
- if (lastpm->node.flags & PM_NAMEREF) {
+ if (lastpm->node.flags & PM_NAMEREF) { // ???
char *refname = GETREFNAME(lastpm);
if (refname && *refname) {
name = refname;
@@ -1102,7 +1102,7 @@ createparam(char *name, int flags)
}
pm = oldpm;
- pm->base = pm->width = 0;
+ pm->base = pm->width = 0; // OK
oldpm = pm->old;
} else {
pm = (Param) zshcalloc(sizeof *pm);
@@ -1214,7 +1214,7 @@ copyparam(Param tpm, Param pm, int fakecopy)
* with sets.?fn() usage).
*/
tpm->node.flags = pm->node.flags;
- tpm->base = pm->base;
+ tpm->base = pm->base; // OK
tpm->width = pm->width;
tpm->level = pm->level;
if (!fakecopy) {
@@ -2220,7 +2220,7 @@ 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) && !(flags & SCANPM_NONAMEREF)) {
+ if ((pm->node.flags & PM_NAMEREF) && !(flags & SCANPM_NONAMEREF)) { // OK
char *refname = GETREFNAME(pm);
if (refname && *refname) {
/* only happens for namerefs pointing to array elements */
@@ -2232,10 +2232,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
}
Param p1 = (Param)gethashnode2(paramtab, ref);
if (p1) {
- int scope = ((pm->node.flags & PM_NAMEREF) ?
- ((pm->node.flags & PM_UPPER) ? -(pm->base) :
- pm->base) : locallevel);
- pm = upscope(p1, scope);
+ pm = upscope2(p1, pm->level - pm->upper);
}
if (!(p1 && pm) ||
((pm->node.flags & PM_UNSET) &&
@@ -2344,13 +2341,13 @@ getstrvalue(Value v)
}
return s;
case PM_INTEGER:
- convbase(buf, v->pm->gsu.i->getfn(v->pm), v->pm->base);
+ convbase(buf, v->pm->gsu.i->getfn(v->pm), v->pm->base); // OK
s = dupstring(buf);
break;
case PM_EFLOAT:
case PM_FFLOAT:
s = convfloat(v->pm->gsu.f->getfn(v->pm),
- v->pm->base, v->pm->node.flags, NULL);
+ v->pm->base, v->pm->node.flags, NULL); // OK
break;
case PM_SCALAR:
s = v->pm->gsu.s->getfn(v->pm);
@@ -2477,11 +2474,11 @@ getstrvalue(Value v)
break;
}
}
- switch (v->pm->node.flags & (PM_LOWER | PM_UPPER)) {
+ switch (v->pm->node.flags & (PM_LOWER | PM_UPPER)) { // OK
case PM_LOWER:
s = casemodify(s, CASMOD_LOWER);
break;
- case PM_UPPER:
+ case PM_UPPER: // OK
if (!(v->pm->node.flags & PM_NAMEREF))
s = casemodify(s, CASMOD_UPPER);
break;
@@ -2642,9 +2639,9 @@ export_param(Param pm)
#endif
return;
} else if (PM_TYPE(pm->node.flags) == PM_INTEGER)
- convbase(val = buf, pm->gsu.i->getfn(pm), pm->base);
+ convbase(val = buf, pm->gsu.i->getfn(pm), pm->base); // OK
else if (pm->node.flags & (PM_EFLOAT|PM_FFLOAT))
- val = convfloat(pm->gsu.f->getfn(pm), pm->base,
+ val = convfloat(pm->gsu.f->getfn(pm), pm->base, // OK
pm->node.flags, NULL);
else
val = pm->gsu.s->getfn(pm);
@@ -2774,8 +2771,8 @@ assignstrvalue(Value v, char *val, int flags)
v->pm->width = strlen(val);
zsfree(val);
}
- if (!v->pm->base && lastbase != -1)
- v->pm->base = lastbase;
+ if (!v->pm->base && lastbase != -1) // OK
+ v->pm->base = lastbase; // OK
break;
case PM_EFLOAT:
case PM_FFLOAT:
@@ -3156,7 +3153,7 @@ check_warn_pm(Param pm, const char *pmtype, int created,
} else
return;
- if (pm->node.flags & (PM_SPECIAL|PM_NAMEREF))
+ if (pm->node.flags & (PM_SPECIAL|PM_NAMEREF)) // OK
return;
for (i = funcstack; i; i = i->prev) {
@@ -3233,7 +3230,7 @@ assignsparam(char *s, char *val, int flags)
/* errflag |= ERRFLAG_ERROR; */
return NULL;
}
- if (*val && (v->pm->node.flags & PM_NAMEREF)) {
+ if (*val && (v->pm->node.flags & PM_NAMEREF)) { // OK
if (!valid_refname(val)) {
zerr("invalid variable name: %s", val);
zsfree(val);
@@ -3677,7 +3674,7 @@ assignnparam(char *s, mnumber val, int flags)
if (ss) {
*ss = '[';
} else if (val.type & MN_INTEGER) {
- pm->base = outputradix;
+ pm->base = outputradix; // OK
}
if (!(v = getvalue(&vbuf, &t, 1))) {
DPUTS(!v, "BUG: value not found for new parameter");
@@ -3765,7 +3762,7 @@ unsetparam(char *s)
/* getnode2() to avoid autoloading */
paramtab->getnode2(paramtab, s) :
paramtab->getnode(paramtab, s))) &&
- !(pm->node.flags & PM_NAMEREF))
+ !(pm->node.flags & PM_NAMEREF)) // OK
unsetparam_pm(pm, 0, 1);
unqueue_signals();
}
@@ -3785,7 +3782,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
if ((pm->node.flags & PM_READONLY) && pm->level <= locallevel) {
zerr("read-only %s: %s",
- (pm->node.flags & PM_NAMEREF) ? "reference" : "variable",
+ (pm->node.flags & PM_NAMEREF) ? "reference" : "variable", // OK
pm->node.nam);
return 1;
}
@@ -5381,7 +5378,7 @@ copyenvstr(char *s, char *value, int flags)
*s = *value++ ^ 32;
if (flags & PM_LOWER)
*s = tulower(*s);
- else if (flags & PM_UPPER)
+ else if (flags & PM_UPPER) // OK
*s = tuupper(*s);
}
}
@@ -5864,7 +5861,7 @@ scanendscope(HashNode hn, UNUSED(int flags))
pm->old = tpm->old;
pm->node.flags = (tpm->node.flags & ~PM_NORESTORE);
pm->level = tpm->level;
- pm->base = tpm->base;
+ pm->base = tpm->base; // OK
pm->width = tpm->width;
if (pm->env)
delenv(pm);
@@ -5898,10 +5895,10 @@ scanendscope(HashNode hn, UNUSED(int flags))
}
if (hidden)
pm = hidden;
- if (pm && (pm->node.flags & PM_NAMEREF) &&
- pm->base >= pm->level && pm->base >= locallevel) {
+ if (pm && (pm->node.flags & PM_NAMEREF) && // ?
+ pm->base >= pm->level && pm->base >= locallevel) { // ? kill ?
/* Should never get here for a -u reference */
- pm->base = locallevel;
+ pm->base = locallevel; // ? kill ?
}
}
@@ -5958,13 +5955,13 @@ static const struct paramtypes pmtypes[] = {
{ PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
{ PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH},
{ PM_LOWER, "lowercase", 'l', 0},
- { PM_UPPER, "uppercase", 'u', 0},
+ { PM_UPPER, "uppercase", 'u', 0}, // OK
{ PM_READONLY, "readonly", 'r', 0},
{ PM_TAGGED, "tagged", 't', 0},
{ PM_EXPORTED, "exported", 'x', 0},
{ PM_UNIQUE, "unique", 'U', 0},
{ PM_TIED, "tied", 'T', 0},
- { PM_NAMEREF, "nameref", 'n', 0}
+ { PM_NAMEREF, "nameref", 'n', 0} // OK
};
#define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
@@ -5996,7 +5993,7 @@ printparamvalue(Param p, int printflags)
case PM_EFLOAT:
case PM_FFLOAT:
/* float */
- convfloat(p->gsu.f->getfn(p), p->base, p->node.flags, stdout);
+ convfloat(p->gsu.f->getfn(p), p->base, p->node.flags, stdout); // OK
break;
case PM_ARRAY:
/* array */
@@ -6174,8 +6171,8 @@ printparamnode(HashNode hn, int printflags)
}
} else
printf("%s ", pmptr->string);
- if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
- printf("%d ", p->base);
+ if ((pmptr->flags & PMTF_USE_BASE) && p->base) { // OK
+ printf("%d ", p->base); // OK
doneminus = 0;
}
if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
@@ -6264,7 +6261,7 @@ resolve_nameref(Param pm, const Asgment stop)
HashNode hn = (HashNode)pm;
const char *seek = stop ? stop->value.scalar : NULL;
- if (pm && (pm->node.flags & PM_NAMEREF)) {
+ if (pm && (pm->node.flags & PM_NAMEREF)) { // OK
char *refname = GETREFNAME(pm);
if (pm->node.flags & (PM_UNSET|PM_TAGGED)) {
/* Semaphore with createparam() */
@@ -6285,17 +6282,17 @@ resolve_nameref(Param pm, const Asgment stop)
}
}
else if (pm) {
- if (!(stop && (stop->flags & PM_NAMEREF)))
+ if (!(stop && (stop->flags & PM_NAMEREF))) // OK
return (HashNode)pm;
- if (!(pm->node.flags & PM_NAMEREF))
+ if (!(pm->node.flags & PM_NAMEREF)) // OK
return (pm->level < locallevel ? NULL : (HashNode)pm);
}
if (seek) {
queue_signals();
/* pm->width is the offset of any subscript */
- if (pm && (pm->node.flags & PM_NAMEREF) && pm->width) {
+ if (pm && (pm->node.flags & PM_NAMEREF) && pm->width) { // OK
if (stop) {
- if (stop->flags & PM_NAMEREF)
+ if (stop->flags & PM_NAMEREF) // OK
hn = (HashNode)pm;
else
hn = NULL;
@@ -6306,12 +6303,10 @@ resolve_nameref(Param pm, const Asgment stop)
} else if ((hn = gethashnode2(realparamtab, seek))) {
if (pm) {
if (!(stop && (stop->flags & (PM_LOCAL)))) {
- int scope = ((pm->node.flags & PM_NAMEREF) ?
- ((pm->node.flags & PM_UPPER) ?
- /* pm->base == 0 means not set yet */
- -(pm->base ? pm->base : pm->level) :
- pm->base) : ((Param)hn)->level);
- hn = (HashNode)upscope((Param)hn, scope);
+ int scope = ((pm->node.flags & PM_NAMEREF) // OK
+ ? pm->level - pm->upper
+ : ((Param)hn)->level); // ?
+ hn = (HashNode)upscope2((Param)hn, scope);
}
/* user can't tag a nameref, safe for loop detection */
pm->node.flags |= PM_TAGGED;
@@ -6324,7 +6319,7 @@ resolve_nameref(Param pm, const Asgment stop)
}
if (pm)
pm->node.flags &= ~PM_TAGGED;
- } else if (stop && (stop->flags & PM_NAMEREF))
+ } else if (stop && (stop->flags & PM_NAMEREF)) // OK
hn = (pm && (pm->node.flags & PM_NEWREF)) ? NULL : (HashNode)pm;
unqueue_signals();
}
@@ -6338,13 +6333,13 @@ setloopvar(char *name, char *value)
{
Param pm = (Param) gethashnode2(realparamtab, name);
- if (pm && (pm->node.flags & PM_NAMEREF)) {
+ if (pm && (pm->node.flags & PM_NAMEREF)) { // OK
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->base = pm->width = 0; // Remove pm->base?
SETREFNAME(pm, ztrdup(value));
pm->node.flags &= ~PM_UNSET;
pm->node.flags |= PM_NEWREF;
@@ -6360,7 +6355,7 @@ static void
setscope(Param pm)
{
queue_signals();
- if (pm->node.flags & PM_NAMEREF) do {
+ if (pm->node.flags & PM_NAMEREF) do { // OK
Param basepm;
struct asgment stop;
char *refname = GETREFNAME(pm);
@@ -6374,8 +6369,8 @@ setscope(Param pm)
t = 0;
stop.name = "";
stop.value.scalar = NULL;
- stop.flags = PM_NAMEREF;
- if (locallevel && !(pm->node.flags & PM_UPPER))
+ stop.flags = PM_NAMEREF; // OK
+ if (locallevel && !(pm->node.flags & PM_UPPER)) // ?
stop.flags |= PM_LOCAL;
dont_queue_signals(); /* Prevent unkillable loops */
basepm = (Param)resolve_nameref(pm, &stop);
@@ -6386,17 +6381,17 @@ setscope(Param pm)
refname = dupstrpfx(refname, pm->width);
}
if (basepm) {
- if (basepm->node.flags & PM_NAMEREF) {
+ if (basepm->node.flags & PM_NAMEREF) { // OK
if (pm == basepm) {
if (pm->node.flags & PM_SELFREF) {
/* Loop signalled by resolve_nameref() */
- if (upscope(pm, pm->base) == pm) {
+ if (upscope(pm, pm->base) == pm) { // ?
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
break;
}
pm->node.flags &= ~PM_SELFREF;
- } else if (pm->base == pm->level) {
+ } else if (pm->base == pm->level) { // ?
if (refname && *refname &&
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
@@ -6405,27 +6400,27 @@ setscope(Param pm)
}
}
} else if ((t = GETREFNAME(basepm))) {
- if (basepm->base <= basepm->level &&
+ if (basepm->base <= basepm->level && // ?
strcmp(pm->node.nam, t) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
break;
}
}
- } else if (!pm->base) {
- pm->base = basepm->level;
- if ((pm->node.flags & PM_UPPER) &&
+ } else if (!pm->base) { // ?
+ pm->base = basepm->level; // ?
+ if ((pm->node.flags & PM_UPPER) && // ?
(basepm = upscope(basepm, -(pm->level))))
- pm->base = basepm->level;
+ pm->base = basepm->level; // ?
}
- } else if (pm->base < locallevel && refname &&
+ } else if (pm->base < locallevel && refname && // ?
(basepm = (Param)getparamnode(realparamtab, refname))) {
- pm->base = basepm->level;
- if ((pm->node.flags & PM_UPPER) &&
+ pm->base = basepm->level; // ?
+ if ((pm->node.flags & PM_UPPER) && // ?
(basepm = upscope(basepm, -(pm->level))))
- pm->base = basepm->level;
+ pm->base = basepm->level; // ?
}
- if (pm->base > pm->level) {
+ if (pm->base > pm->level) { // ?
if (EMULATION(EMULATE_KSH)) {
zerr("%s: global reference cannot refer to local variable",
pm->node.nam);
@@ -6434,7 +6429,7 @@ setscope(Param pm)
zwarn("reference %s in enclosing scope set to local variable %s",
pm->node.nam, refname);
}
- if (refname && upscope(pm, pm->base) == pm &&
+ if (refname && upscope(pm, pm->base) == pm && // ?
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
unsetparam_pm(pm, 0, 1);
@@ -6443,6 +6438,16 @@ setscope(Param pm)
unqueue_signals();
}
+/**/
+mod_export Param
+upscope2(Param pm, int reflevel)
+{
+ while (pm && pm->level > reflevel) {
+ pm = pm->old;
+ }
+ return pm;
+}
+
/**/
mod_export Param
upscope(Param pm, int reflevel)
diff --git a/Src/zsh.h b/Src/zsh.h
index 4e5c02980..6d31c9af8 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1859,6 +1859,7 @@ struct param {
char *ename; /* name of corresponding environment var */
Param old; /* old struct for use with local */
int level; /* if (old != NULL), level of localness */
+ int upper; /* upper count of named references */
};
/* structure stored in struct param's u.data by tied arrays */
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 54f0aaf68..70ec8e316 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -567,12 +567,14 @@ F:unexpected side-effects of previous tests
typeset gval=global
() {
typeset -n ptr=gval
+ print $ptr
local gval=local
print $ptr
}
typeset -p ptr gval
1:up-reference part 2
>global
+>local
*?*no such variable: ptr
>typeset gval=global
@@ -593,9 +595,11 @@ F:unexpected side-effects of previous tests
typeset -A var=(myself outside)
() {
typeset -n myself=var[myself]
- local -h var
- print -r -- $myself
- typeset -p var
+ () {
+ local -h var
+ print -r -- $myself
+ typeset -p var
+ }
}
0:up-reference part 3, hidden global
>outside
Messages sorted by:
Reverse Date,
Date,
Thread,
Author