Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Share code for $parameters[var] and ${(t)var}
- X-seq: zsh-workers 55216
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Share code for $parameters[var] and ${(t)var}
- Date: Tue, 13 Oct 2026 18:47:51 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=HzBGwH2mXAnqTMXoM5CYJ+rV3W+3r5np9b0WY/sRq4g=; fh=BgAYDYpL6Ne/A5nWEMVJiHiBtrz8Imz3uf26RDwgQX4=; b=HMnIZ9qFFSWn+MFCAGk/lduxHWc5GlOUpzQUWvopVdKYgBk2fTb5n43UUxIoCf7JBW XwGkV+P6Of6P6qikGE2gMC3oFAOd0gjdITZs6kFLlwcM2KxAuh1mUZQT4mRpqTRMy6bg Bz69kQHDFow1TjK/3c4UdFdd1bEbEw4V6RHfA+r3Ww4A4QEgyCgZod6Dt3SZL21JNNC0 7xe7xA8BBzM5NDj6kS2mhyDClRDRtDBVFRRx11IOZEV5QPrWvNOBx+XCqMIiy2XECpEV wduvmJmomdqEphGCp/VZJ2SCJ5kAcGhn6qMCJGlVP4zaudxh190/EVv5yQ5probswVgN qLcw==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1791910083; cv=none; d=google.com; s=arc-20260327; b=XPJEGNdVSjskv2SjmfvDcd8dgbyULNWyOxANJemXbj2nqvf1c6v5vuCGq/5L1Jl0A6 wjgStkLvltXPkHINVCrH8gvemnMQIHgoCSss6IjYsEqy/Gb/u+Po64x224/xWGMGnR7M dUuM/Rt7YVAYUy5ST00mWixMaG4tDW6BvR1YqScY3q+Mk6B7hp7Hf717i8n+rSVwc1Wj 02QnQjVm+bQ3ObPHv5pzhVX5+Qyr1LeVMBBK+ZdOD/X7rWG7BqDG/XHqhlpG9l6CAJM4 3GEdpxWR4olNf1pfYndsX0XpEeRd2i3FtC7lrVLHP5w0Iyf7hLZZyEvOZiEI6zGuMwmr 8g3A==
- Archived-at: <https://zsh.org/workers/55216>
- List-id: <zsh-workers.zsh.org>
The patch below merges the currently separate implementations of $parameters[var] and ${(t)var} into a single shared one. It also documents that the two expressions produce the same expansions.
The patch slightly changes the behavior of ${(t)var} in two ways:
1) For named references, the expansion now also includes a description of the referred variable
2) For autoloaded variables (only possible if (!) is also used), now expands to "undefined" instead of "scalar".
-
Share code for $parameters[var] and ${(t)var} (depends on
workers/55146 - Eliminate getparamnode() and the distinction between getnode() and getnode2())
Philippe
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 8175a9e5d..bf56d125f 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1185,9 +1185,10 @@ item(tt(t))(
Use a string describing the type of the parameter where the value
of the parameter would usually appear. This string consists of keywords
separated by hyphens (`tt(-)'). The first keyword in the string describes
-the main type, it can be one of `tt(scalar)', `tt(array)', `tt(integer)',
-`tt(float)' or `tt(association)'. The other keywords describe the type in
-more detail, in most cases corresponding to options of the `tt(typeset)'
+the main type, it can be one of `tt(scalar)', `tt(integer)', `tt(float)',
+`tt(array)', `tt(association)' or `tt(nameref)'. The other keywords
+describe the type in more detail, in most cases corresponding to options
+of the `tt(typeset)'
command:
startitem()
@@ -1234,14 +1235,20 @@ for parameters with the `hide' flag (tt(-h))
item(tt(hideval))(
for parameters with the `hideval' flag (tt(-H))
)
-item(tt(nameref))(
-for named references (tt(typeset -n)) either having an empty value or
-when combined with `tt(!)' as in `tt(${LPAR()!t)tt(RPAR()var(rname)})'
-)
item(tt(special))(
for special parameters defined by the shell
)
enditem()
+
+When combined with `tt(!)' as in `tt(${LPAR()!t)tt(RPAR()var(name)})',
+the string may also be `tt(undefined)' if the parameter may be
+autoloaded from a module but has not yet been referenced. When the key
+is the name of a named reference, the type of the referenced parameter
+is appended to the string, for example
+ifzman()
+example(tt(% typeset -nr ref=path)
+tt(% print -r ${(!t)ref})
+tt(nameref-readonly-array-tied-special))
)
item(tt(u))(
Expand only the first occurrence of each unique word, like `tt(typeset -U)'.
diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index 880c070ea..70d8b634d 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -119,16 +119,9 @@ item(tt(parameters))(
The keys in this associative array are the names of the parameters
currently defined. The values are strings describing the type of the
parameter, in the same format used by the tt(t) parameter flag, see
-subref(Parameter Expansion Flags)(zshexpn).
-The value may also be `tt(undefined)' indicating a parameter that
-may be autoloaded from a module but has not yet been referenced.
-When the key is the name of a named reference, the value is
-`tt(nameref-)' prepended to the type of the referenced parameter,
-for example
-ifzman()
-example(tt(% typeset -n parms=parameters)
-tt(% print -r ${parameters[parms]})
-tt(nameref-association-readonly-hide-hideval-special))
+subref(Parameter Expansion Flags)(zshexpn). For any paramater
+`tt(var(name))', the value is the same as the one returned by
+`tt(${LPAR()!t)tt(RPAR()var(name)})'.
Setting or unsetting keys in this array is not possible.
)
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 972496d42..356817bfb 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -36,70 +36,6 @@ static int incleanup;
/* Functions for the parameters special parameter. */
-/* Return a string describing the type of a parameter. */
-
-/**/
-static char *
-paramtypestr(Param pm, int append)
-{
- char *val = NULL;
- int f = pm->node.flags;
-
- if (!(f & PM_UNSET)) {
- if (pm->node.flags & PM_AUTOLOAD)
- return dupstring("undefined");
-
- switch (PM_TYPE(f)) {
- case PM_SCALAR: val = "scalar"; break;
- case PM_NAMEREF: val = "nameref"; break;
- case PM_ARRAY: val = "array"; break;
- case PM_INTEGER: val = "integer"; break;
- case PM_EFLOAT:
- case PM_FFLOAT: val = "float"; break;
- case PM_HASHED: val = "association"; break;
- }
- DPUTS(!val, "BUG: type not handled in parameter");
- val = dupstring(val);
- if (pm->level)
- val = dyncat(val, "-local");
- if (f & PM_LEFT)
- val = dyncat(val, "-left");
- if (f & PM_RIGHT_B)
- val = dyncat(val, "-right_blanks");
- if (f & PM_RIGHT_Z)
- val = dyncat(val, "-right_zeros");
- if (f & PM_LOWER)
- val = dyncat(val, "-lower");
- if (f & PM_UPPER)
- val = dyncat(val, "-upper");
- if (f & PM_READONLY)
- val = dyncat(val, "-readonly");
- if (f & PM_TAGGED)
- val = dyncat(val, "-tag");
- if (f & PM_TIED)
- val = dyncat(val, "-tied");
- if (f & PM_EXPORTED)
- val = dyncat(val, "-export");
- if (f & PM_UNIQUE)
- val = dyncat(val, "-unique");
- if (f & PM_HIDE)
- val = dyncat(val, "-hide");
- if (f & PM_HIDEVAL)
- val = dyncat(val, "-hideval");
- if (f & PM_SPECIAL)
- val = dyncat(val, "-special");
- } else
- val = dupstring("");
-
- if (append) {
- if ((pm->node.flags & PM_NAMEREF) &&
- (pm = asset_pm(resolveparam_pm(pm, 0)))) {
- val = zhtricat(val, "-", paramtypestr(pm, 0));
- }
- }
- return val;
-}
-
/**/
static HashNode
getpmparameter(UNUSED(HashTable ht), const char *name)
@@ -111,7 +47,7 @@ getpmparameter(UNUSED(HashTable ht), const char *name)
pm->node.flags = PM_SCALAR | PM_READONLY;
pm->gsu.s = &nullsetscalar_gsu;
if ((rpm = asset_pm(getparam(name)))) {
- pm->u.str = paramtypestr(rpm, 1);
+ pm->u.str = gettypestr(rpm);
} else {
pm->u.str = dupstring("");
pm->node.flags |= (PM_UNSET|PM_SPECIAL);
@@ -139,7 +75,7 @@ scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags)
if (func != scancountparams &&
((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
!(flags & SCANPM_WANTKEYS)))
- pm.u.str = paramtypestr((Param) hn, 1);
+ pm.u.str = gettypestr((Param) hn);
func(&pm.node, flags);
}
}
diff --git a/Src/params.c b/Src/params.c
index 03ab0479f..5e334075a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2362,6 +2362,65 @@ getindex(char **pptr, Value v, int scanflags)
return 0;
}
+/* Return a string describing the type of a parameter. */
+
+/**/
+mod_export char *
+gettypestr(Param pm)
+{
+ char *val = NULL;
+ int f;
+
+ if (!isset_pm(pm))
+ return dupstring("");
+ if ((f = pm->node.flags) & PM_AUTOLOAD)
+ return dupstring("undefined");
+
+ switch (PM_TYPE(f)) {
+ case PM_SCALAR: val = "scalar"; break;
+ case PM_NAMEREF: val = "nameref"; break;
+ case PM_ARRAY: val = "array"; break;
+ case PM_INTEGER: val = "integer"; break;
+ case PM_EFLOAT:
+ case PM_FFLOAT: val = "float"; break;
+ case PM_HASHED: val = "association"; break;
+ }
+ DPUTS(!val, "BUG: type not handled in parameter");
+ val = dupstring(val);
+ if (pm->level)
+ val = dyncat(val, "-local");
+ if (f & PM_LEFT)
+ val = dyncat(val, "-left");
+ if (f & PM_RIGHT_B)
+ val = dyncat(val, "-right_blanks");
+ if (f & PM_RIGHT_Z)
+ val = dyncat(val, "-right_zeros");
+ if (f & PM_LOWER)
+ val = dyncat(val, "-lower");
+ if (f & PM_UPPER)
+ val = dyncat(val, "-upper");
+ if (f & PM_READONLY)
+ val = dyncat(val, "-readonly");
+ if (f & PM_TAGGED)
+ val = dyncat(val, "-tag");
+ if (f & PM_TIED)
+ val = dyncat(val, "-tied");
+ if (f & PM_EXPORTED)
+ val = dyncat(val, "-export");
+ if (f & PM_UNIQUE)
+ val = dyncat(val, "-unique");
+ if (f & PM_HIDE)
+ val = dyncat(val, "-hide");
+ if (f & PM_HIDEVAL)
+ val = dyncat(val, "-hideval");
+ if (f & PM_SPECIAL)
+ val = dyncat(val, "-special");
+
+ if ((f & PM_NAMEREF) && (pm = asset_pm(resolveparam_pm(pm, 0))))
+ val = zhtricat(val, "-", gettypestr(pm));
+
+ return val;
+}
/**/
mod_export Value
diff --git a/Src/subst.c b/Src/subst.c
index 844ec5e43..79d3d0d76 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2810,48 +2810,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
* Handle the (t) flag: value now becomes the type
* information for the parameter.
*/
- if (v && v->pm && ((v->pm->node.flags & PM_DECLARED) ||
- !(v->pm->node.flags & PM_UNSET))) {
- int f = v->pm->node.flags;
-
- switch (PM_TYPE(f)) {
- case PM_SCALAR: val = "scalar"; break;
- case PM_NAMEREF: val = "nameref"; break;
- case PM_ARRAY: val = "array"; break;
- case PM_INTEGER: val = "integer"; break;
- case PM_EFLOAT:
- case PM_FFLOAT: val = "float"; break;
- case PM_HASHED: val = "association"; break;
- }
- val = dupstring(val);
- if (v->pm->level)
- val = dyncat(val, "-local");
- if (f & PM_LEFT)
- val = dyncat(val, "-left");
- if (f & PM_RIGHT_B)
- val = dyncat(val, "-right_blanks");
- if (f & PM_RIGHT_Z)
- val = dyncat(val, "-right_zeros");
- if (f & PM_LOWER)
- val = dyncat(val, "-lower");
- if (f & PM_UPPER)
- val = dyncat(val, "-upper");
- if (f & PM_READONLY)
- val = dyncat(val, "-readonly");
- if (f & PM_TAGGED)
- val = dyncat(val, "-tag");
- if (f & PM_TIED)
- val = dyncat(val, "-tied");
- if (f & PM_EXPORTED)
- val = dyncat(val, "-export");
- if (f & PM_UNIQUE)
- val = dyncat(val, "-unique");
- if (f & PM_HIDE)
- val = dyncat(val, "-hide");
- if (f & PM_HIDEVAL)
- val = dyncat(val, "-hideval");
- if (f & PM_SPECIAL)
- val = dyncat(val, "-special");
+ if (v && isset_pm(v->pm)) {
+ val = gettypestr(v->pm);
vunset = 0;
} else
val = dupstring("");
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index b80564db2..886b32fe3 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -879,15 +879,54 @@
>
>plit on a
- str=s
- arr=(a)
- typeset -A ass
- ass=(a a)
- integer i
- float f
- print ${(t)str} ${(t)arr} ${(t)ass} ${(t)i} ${(t)f}
-0:${(t)...}
->scalar array association-local integer-local float-local
+ export -L3 -u str=s
+ typeset -g -l -U arr=(a)
+ typeset -A -rt ass=(a a)
+ integer -i8 -Z4 int
+ float -F3 -R5 flt
+ local -nh ref=ass
+ typeset -Ul -T VAR var=(a b c b a)
+ zmodload -ap fake-module auto
+ typeset -n refauto=auto
+ print ${(t)str}; typeset +m str;
+ print ${(t)arr}; typeset +m arr;
+ print ${(t)ass}; typeset +m ass;
+ print ${(t)int}; typeset +m int;
+ print ${(t)flt}; typeset +m flt;
+ print ${(t)ref}; print ${(!t)ref}; typeset +m ref;
+ print ${(t)VAR}; typeset +m VAR;
+ print ${(t)var}; typeset +m var;
+ print ${(t)HOME}; typeset +m HOME;
+ print ${(t)SHLVL}; typeset +m SHLVL;
+ print ${(!t)auto}; typeset +m auto;
+ print ${(!t)refauto}; typeset +m refauto;
+ unset str arr
+0:${(t)...} and typeset +m ...
+>scalar-left-upper-export
+>left justified 3 uppercase str
+>array-lower-unique
+>array lowercase unique arr
+>association-local-readonly-tag
+>association local readonly tagged ass
+>integer-local-right_zeros
+>integer 8 local zero filled 4 int
+>float-local-right_blanks
+>float local right justified 5 flt
+>association-local-readonly-tag
+>nameref-local-hide-association-local-readonly-tag
+>local hide nameref ref
+>scalar-local-lower-tied-unique
+>local lowercase unique tied var VAR
+>array-local-lower-tied-unique
+>array local lowercase unique tied VAR var
+>scalar-export-special
+>HOME
+>integer-export-special
+>integer 10 SHLVL
+>undefined
+>undefined auto
+>nameref-local-undefined
+>local nameref refauto
# it's not quite clear that these are actually right unless you know
# the algorithm: search along the string for the point at which the
Messages sorted by:
Reverse Date,
Date,
Thread,
Author