zsh-workers
 help / color / mirror / code / Atom feed
* Re:  Associative array ordering and selective unset (Re: Example function)
@ 1999-02-02 16:58 Sven Wischnowsky
  1999-02-02 17:41 ` ${(P)${foo}} (Re: Associative array ordering) Bart Schaefer
  0 siblings, 1 reply; 8+ messages in thread
From: Sven Wischnowsky @ 1999-02-02 16:58 UTC (permalink / raw)
  To: zsh-workers


I wrote:

> Maybe yet another flag? E.g.: `P' makes the thing after the
> flags be used as the name of a parameter. So `${(P)foo}' is the same
> as `$foo', but `${(P)${foo}}' will take the value of `foo' as the name 
> of a parameter and work on it. So your example would become:
> 
>   if [[ $#arg > 1 && ${(Pt)${argv[1]}} == association ]] ...

The patch below does this (it was quite easy). With it you can do
things like the above or `${(P)+${foo}}' to see if the parameter whose 
name is stored in `foo' is set. If the inner `${...}' produces
multiple words they are joind using IFS which will result in an
invalid parameter name (which is reported as being unset). Maybe we
should make the code test if it is a valid name and barf otherwise. Or 
we could use only the first word. Any other suggestions?

But I don't know if you like this anyway...

The patch also changes the docs and the new-completion-examples.

Bye
 Sven

--- os/subst.c	Mon Feb  1 10:53:56 1999
+++ Src/subst.c	Tue Feb  2 17:27:50 1999
@@ -718,10 +718,12 @@
     int copied = 0;
     int arrasg = 0;
     int eval = 0;
+    int aspar = 0;
     int nojoin = 0;
     char inbrace = 0;		/* != 0 means ${...}, otherwise $... */
     char hkeys = 0;
     char hvals = 0;
+    int subexp;
 
     *s++ = '\0';
     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@@ -813,6 +815,9 @@
 		case 'e':
 		    eval = 1;
 		    break;
+		case 'P':
+		    aspar = 1;
+		    break;
 
 		case 'c':
 		    whichlen = 1;
@@ -949,7 +954,8 @@
 	    } else
 		globsubst = 1;
 	} else if (*s == '+') {
-	    if (iident(s[1]))
+	    if (iident(s[1]) || (aspar && isstring(s[1]) &&
+				 (s[2] == Inbrace || s[2] == Inpar)))
 		chkset = 1, s++;
 	    else if (!inbrace) {
 		*aptr = '$';
@@ -965,7 +971,8 @@
     globsubst = globsubst && !qt;
 
     idbeg = s;
-    if (s[-1] && isstring(*s) && (s[1] == Inbrace || s[1] == Inpar)) {
+    if ((subexp = (s[-1] && isstring(*s) &&
+		   (s[1] == Inbrace || s[1] == Inpar)))) {
 	int sav;
 	int quoted = *s == Qstring;
 
@@ -973,17 +980,22 @@
 	skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s);
 	sav = *s;
 	*s = 0;
-	if (multsub(&val, &aval, &isarr, NULL) && quoted) {
+	if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) {
 	    isarr = -1;
 	    aval = alloc(sizeof(char *));
-	}
+	    aspar = 0;
+	} else if (aspar)
+	    idbeg = val;
 	if (isarr)
 	    isarr = -1;
 	copied = 1;
 	*s = sav;
 	v = (Value) NULL;
-    } else {
-	if (!(v = fetchvalue(&s, (wantt ? -1 :
+    }
+    if (!subexp || aspar) {
+	char *ov = val;
+
+	if (!(v = fetchvalue((subexp ? &ov : &s), (wantt ? -1 :
 				  ((unset(KSHARRAYS) || inbrace) ? 1 : -1)),
 			     hkeys|hvals)))
 	    vunset = 1;
--- od/Zsh/expn.yo	Mon Feb  1 10:53:36 1999
+++ Doc/Zsh/expn.yo	Tue Feb  2 17:51:35 1999
@@ -477,9 +477,10 @@
 pindex(GLOB_SUBST)
 Turn on the tt(GLOB_SUBST) option for the evaluation of
 var(spec); if the `tt(~)' is doubled, turn it off.  When this option is
-set, any pattern characters resulting
-from parameter expansion are eligible for filename expansion and filename
-generation.
+set, the string resulting from the expansion will be interpreted as a
+pattern thus becoming eligible for filename expansion and filename
+generation and usable as a pattern in pattern-matching contexts like
+the `tt(=)' and `tt(!=)' operators in conditions.
 )
 enditem()
 
@@ -522,6 +523,15 @@
 Perform em(parameter expansion), em(command substitution) and
 em(arithmetic expansion) on the result. Such expansions can be
 nested but too deep recursion may have unpredictable effects.
+)
+item(tt(P))(
+If used with a parameter name, this flag has no effect. But if it is
+used with a tt(${)...tt(}) type parameter expression or a
+tt($LPAR())...tt(RPAR()) type command substitution in place of
+the parameter name this flag makes the result of the expansion be
+taken as a parameter name which is then used. E.g. if you have
+`tt(foo=bar)' and `tt(bar=baz)', the string `tt(${(P)${foo}})' will be 
+expanded to `tt(baz)'.
 )
 item(tt(o))(
 Sort the resulting words in ascending order.
diff -u om/new-completion-examples Misc/new-completion-examples
--- om/new-completion-examples	Mon Feb  1 10:53:27 1999
+++ Misc/new-completion-examples	Tue Feb  2 17:43:34 1999
@@ -75,11 +75,8 @@
 # the arguments from the command line as its arguments.
 
 call-complete() {
-  local var
-
-  eval var\=\$\{\+$1\}
-  if (( var )); then
-    eval complist \$\{${1}\[\@\]\}
+  if [[ ${(P)+${1}} -eq 1 ]] then
+    complist ${(@P)${1}}
   else
     "$@"
   fi
@@ -96,15 +93,6 @@
   setopt localoptions nullglob rcexpandparam globdots
   unsetopt markdirs globsubst shwordsplit nounset
 
-  # We first try the `compctl's. This is without first (-T) and default (-D)
-  # completion. If you want them add `-T' and/or `-D' to this command.
-  # If this produces any matches, we don't try new style completion. If you
-  # want to have that tried anyway, remove the `[[ -nmatches ... ]] ...'
-  # below.
-
-  compcall
-  [[ -nmatches 0 ]] || return
-
   # An entry for `--first--' is the replacement for `compctl -T'
   # The `|| return 1' is used throughout: if a function producing matches
   # returns non-zero this is interpreted as `do not try to produce more matches'
@@ -117,6 +105,15 @@
   # convenience alias `compsub'.
 
   if [[ $CONTEXT == argument || $CONTEXT == command ]] then
+    # We first try the `compctl's. This is without first (-T) and default (-D)
+    # completion. If you want them add `-T' and/or `-D' to this command.
+    # If this produces any matches, we don't try new style completion. If you
+    # want to have that tried anyway, remove the `[[ -nmatches ... ]] ...'
+    # below.
+
+    compcall
+    [[ -nmatches 0 ]] || return
+
     compsub
   else
     # Let's see if we have a special completion definition for the other
@@ -205,7 +202,7 @@
     if [[ "$a[1]" = '(' ]] then
       ppres=( $a[2,-2]/ )
     else
-      eval ppres\=\( \$$a/ \)
+      ppres=( ${(P)${a}} )
       [[ $#ppres -eq 0 ]] && ppres=( $a/ )
     fi
     [[ $#ppres -eq 0 ]] && ppres=( '' )
@@ -329,11 +326,8 @@
 
 defcomp __subscr --subscr--
 __subscr() {
-  local t
-
-  eval t\=\$\{\(t\)$COMMAND\}
   compalso --math-- "$@"
-  [[ $t = assoc* ]] && eval complist -k \"\(\$\{\(k\)$COMMAND\}\)\"
+  [[ ${(Pt)${COMMAND}} = assoc* ]] && complist -k "( ${(kP)${COMMAND}} )"
 }
 
 # Do sub-completion for pre-command modifiers.

--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


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

* ${(P)${foo}} (Re: Associative array ordering)
  1999-02-02 16:58 Associative array ordering and selective unset (Re: Example function) Sven Wischnowsky
@ 1999-02-02 17:41 ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 1999-02-02 17:41 UTC (permalink / raw)
  To: zsh-workers

On Feb 2,  5:58pm, Sven Wischnowsky wrote:
} Subject: Re:  Associative array ordering and selective unset (Re: Example 
}
} I wrote:
} 
} > Maybe yet another flag? E.g.: `P' makes the thing after the
} > flags be used as the name of a parameter. So `${(P)foo}' is the same
} > as `$foo', but `${(P)${foo}}' will take the value of `foo' as the name 
} > of a parameter and work on it.
} 
} The patch below does this (it was quite easy).

Well, you got to that before I got around to responding to that particular
tidbit.

The other day someone asked about ksh namerefs in zsh, and I said that with
${(e)...} you didn't really need them.  Here's a case where they would have
been exactly what the doctor ordered; in an appropriate muddle of ksh and
zsh syntax,

	nameref ref=$arg[1]
	echo ${(t)!ref}

which is a whole lot easier on the eyes, it must be admitted.

} With it you can do
} things like the above or `${(P)+${foo}}' to see if the parameter whose 
} name is stored in `foo' is set.

There are actually several ways we can go from here.

We can keep Sven's syntax as is.

We can modify Sven's syntax so that ${(P)foo} is the same as ${(P)${foo}},
and make ${!foo} a synonym for it in ksh compatibility mode.  This is
almost like ksh namerefs except that they don't get their own namespace.

We can make ${!foo} a synonym for ${(P)${foo}} (either in ksh mode or all
the time), leaving ${(P)foo} alone.  I'm not too thrilled about this one.

We can add another hash table to be the nameref namespace, implement the
nameref and `typeset -n' builtins, and make ${(P)foo} [or another letter]
and ${!foo} synonyms where `foo' must be a nameref.  That would deprecate
${(P)${foo}}.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


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

* Re: Associative array ordering and selective unset (Re: Example function)
  1999-02-01 17:02 ` Associative array ordering and selective unset (Re: Example function) Bart Schaefer
  1999-02-01 17:39   ` Bruce Stephens
@ 1999-02-02 20:07   ` Phil Pennock
  1 sibling, 0 replies; 8+ messages in thread
From: Phil Pennock @ 1999-02-02 20:07 UTC (permalink / raw)
  To: zsh-workers

Typing away merrily, Bart Schaefer produced the immortal words:
> On Feb 1, 11:48am, Sven Wischnowsky wrote:
> } I was thinking about this... we could make the code keep a counter in
> } assoc arrays, increment it whenever a new key is added and store the
> } current value in the structure for this new element. Then we can treat 
> } the whole thing as being sorted by `time of addition'.
> } 
> } Hm, does this sound like the right thing?
> 
> Almost.  Something about it doesn't seem quite right to me, but I can't
> put my finger on what different behavior I'd expect.
> 
> I don't like the idea that every parameter table hash would end up with
> another integer of overhead in every entry, but maybe that's not so bad.

A pointer in each to embed a linked list?
-- 
--> Phil Pennock ; GAT d- s+:+ a23 C++(++++) UL++++/I+++/S+++/B++/H+$ P++@$
L+++ E-@ W(+) N>++ o !K w--- O>+ M V !PS PE Y+ PGP+ t-- 5++ X+ R !tv b++>+++
DI+ D+ G+ e+ h* r y?


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

* Re: Associative array ordering and selective unset (Re: Example function)
@ 1999-02-02  8:01 Sven Wischnowsky
  0 siblings, 0 replies; 8+ messages in thread
From: Sven Wischnowsky @ 1999-02-02  8:01 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> (Note that I moved the (qQ) into the subscript flags, which is probably
> where it really has to be.  And I still hope for a better letter.)
> 
> Now change the assignment a little:
> 
>         map=('*.(gz|Z)' ': 1; zcat
>              '*.bz2' ': 2; bzip2 -dc'
>              '*.bz' ': 3; bzip -dc'
>              '*' ': 4; <')
> 
> Now we can use the (o) substitution flag like so:
> 
> 	eval ${${(o)map[(Q)$argv[i]]}[1]} '$argv[i]'
> 
> That says "find all the values for which the key is a pattern that matches
> $argv[i], sort them in ascending order, take the first one, and evaluate
> it as a command with argument $argv[i]."  By embedding the "preferred"
> ordering in the value as a leading ":" command, we're assured of always
> getting the most-specific match.

Hmm, I like this. For bigger arrays one would have to use `01' and so
on, but this should be acceptible.

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


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

* Re:  Associative array ordering and selective unset (Re: Example function)
@ 1999-02-02  7:52 Sven Wischnowsky
  0 siblings, 0 replies; 8+ messages in thread
From: Sven Wischnowsky @ 1999-02-02  7:52 UTC (permalink / raw)
  To: zsh-workers


Bart Schaefer wrote:

> ...
> 
> We could go the ksh route and make `noglob unset foo[key]` work.  Like:
> 
> 	function unset() {
> 	    emulate -R zsh
> 	    setopt localoptions extendedglob
> 	    local arg i
> 	    for i
> 	    do
> 		arg=( "${(@s:[:)i}" )
> 		if [[ $#arg > 1 &&
> 		    $(eval print '${(t)'${arg[1]}'}') == association ]]
> 		then
> 		    eval "$arg[1]=( \${(kv)$arg[1][(I)^${(j:[:)arg[2,-1]} )"
> 		else
> 		    builtin unset $i
> 		fi
> 	    done
> 	}

Since even `vared' can now understand the subscripted syntax, I think
adding this to unset (even in C) would be a good thing. (I'm pretty
sure people will want to have a easy way to remove key/value-pairs
from associative arrays).

> Can you think of a better idiom than $(eval print '${(t)'${arg[1]}'}') to
> get the type of the variable whose name is the value of $arg[1] ?  I keep
> thinking there ought to be a way with ${(e)...} but couldn't make it work.

When implementing the new completion example stuff I was somewhat
irritated that there is no easy way to get the value of a parameter of 
which one only has the name in another parameter. Trying to get the
type of that parameter is indeed even more complicated.

Hm, `(e)' is used at the very end and I wouldn't like to change
that. Maybe yet another flag? E.g.: `P' makes the thing after the
flags be used as the name of a parameter. So `${(P)foo}' is the same
as `$foo', but `${(P)${foo}}' will take the value of `foo' as the name 
of a parameter and work on it. So your example would become:

  if [[ $#arg > 1 && ${(Pt)${argv[1]}} == association ]] ...

Looking at the code this doesn't seem too hard to implement (well, I
said `seem'...).

Bye
 Sven


--
Sven Wischnowsky                         wischnow@informatik.hu-berlin.de


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

* Re: Associative array ordering and selective unset (Re: Example function)
  1999-02-01 17:39   ` Bruce Stephens
@ 1999-02-01 19:09     ` Bart Schaefer
  0 siblings, 0 replies; 8+ messages in thread
From: Bart Schaefer @ 1999-02-01 19:09 UTC (permalink / raw)
  To: zsh-workers

On Feb 1,  5:39pm, Bruce Stephens wrote:
} Subject: Re: Associative array ordering and selective unset (Re: Example f
}
} It would be a bit tricky to reorder the associative array, wouldn't
} it?  i.e., if I set up some configuration, and then want to insert
} some pattern before some others, then I'd need to recreate the
} associative array.  Maybe that's OK, but it feels a bit awkward.

I just thought of a really clever way to do the specific example that I
gave.  Assume for a moment that the (q) modifier were implemented, i.e.
that (almost repeating the original example) given

        typeset -A map
        map=('*.(gz|Z)' zcat
             '*.bz2' 'bzip2 -dc'
             '*.bz' 'bzip -dc'
             '*' '<')

then ${map[(q)$argv[i]]} returns the value for the first subscript match
found, and ${map[(Q)$argv[i]]} returns the array of values for every key
that matches the subscript.

(Note that I moved the (qQ) into the subscript flags, which is probably
where it really has to be.  And I still hope for a better letter.)

Now change the assignment a little:

        map=('*.(gz|Z)' ': 1; zcat
             '*.bz2' ': 2; bzip2 -dc'
             '*.bz' ': 3; bzip -dc'
             '*' ': 4; <')

Now we can use the (o) substitution flag like so:

	eval ${${(o)map[(Q)$argv[i]]}[1]} '$argv[i]'

That says "find all the values for which the key is a pattern that matches
$argv[i], sort them in ascending order, take the first one, and evaluate
it as a command with argument $argv[i]."  By embedding the "preferred"
ordering in the value as a leading ":" command, we're assured of always
getting the most-specific match.

Now, if only this actually worked ... I'm about to be tied up in a several-
week consulting job, so I probably won't get a chance to do anything with
this anytime soon.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


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

* Re: Associative array ordering and selective unset  (Re: Example function)
  1999-02-01 17:02 ` Associative array ordering and selective unset (Re: Example function) Bart Schaefer
@ 1999-02-01 17:39   ` Bruce Stephens
  1999-02-01 19:09     ` Bart Schaefer
  1999-02-02 20:07   ` Phil Pennock
  1 sibling, 1 reply; 8+ messages in thread
From: Bruce Stephens @ 1999-02-01 17:39 UTC (permalink / raw)
  To: zsh-workers

"Bart Schaefer" <schaefer@brasslantern.com> writes:

> On Feb 1, 11:48am, Sven Wischnowsky wrote:
> } Subject: Re: Example function
> }
> } I was thinking about this... we could make the code keep a counter in
> } assoc arrays, increment it whenever a new key is added and store the
> } current value in the structure for this new element. Then we can treat 
> } the whole thing as being sorted by `time of addition'.
> } 
> } Hm, does this sound like the right thing?
> 
> Almost.  Something about it doesn't seem quite right to me, but I
> can't put my finger on what different behavior I'd expect.

It would be a bit tricky to reorder the associative array, wouldn't
it?  i.e., if I set up some configuration, and then want to insert
some pattern before some others, then I'd need to recreate the
associative array.  Maybe that's OK, but it feels a bit awkward.

Emacs (and other Lisps) has assoc-lists, which is maybe a better model
for this: they're explicitly lists (so they have ordering), but you
can access them by key.  I've no idea how this would map onto a shell,
but perhaps this is saying that associative arrays don't quite fit
what's wanted.

> I don't like the idea that every parameter table hash would end up
> with another integer of overhead in every entry, but maybe that's
> not so bad.

I agree, the extra integer is probably trivial.


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

* Associative array ordering and selective unset (Re: Example function)
  1999-02-01 10:48 Example function Sven Wischnowsky
@ 1999-02-01 17:02 ` Bart Schaefer
  1999-02-01 17:39   ` Bruce Stephens
  1999-02-02 20:07   ` Phil Pennock
  0 siblings, 2 replies; 8+ messages in thread
From: Bart Schaefer @ 1999-02-01 17:02 UTC (permalink / raw)
  To: zsh-workers

On Feb 1, 11:48am, Sven Wischnowsky wrote:
} Subject: Re: Example function
}
} I was thinking about this... we could make the code keep a counter in
} assoc arrays, increment it whenever a new key is added and store the
} current value in the structure for this new element. Then we can treat 
} the whole thing as being sorted by `time of addition'.
} 
} Hm, does this sound like the right thing?

Almost.  Something about it doesn't seem quite right to me, but I can't
put my finger on what different behavior I'd expect.

I don't like the idea that every parameter table hash would end up with
another integer of overhead in every entry, but maybe that's not so bad.

} P.S.: Is `foo=( ${(kv)foo[(I)^key]} )' the easiest way to remove a
}       key/value-pair from an associative array?

Probably, if you have extendedglob set.  If you don't have extendedglob,
that's a moderately hard way to remove -all- the key/value pairs.

We could go the ksh route and make `noglob unset foo[key]` work.  Like:

	function unset() {
	    emulate -R zsh
	    setopt localoptions extendedglob
	    local arg i
	    for i
	    do
		arg=( "${(@s:[:)i}" )
		if [[ $#arg > 1 &&
		    $(eval print '${(t)'${arg[1]}'}') == association ]]
		then
		    eval "$arg[1]=( \${(kv)$arg[1][(I)^${(j:[:)arg[2,-1]} )"
		else
		    builtin unset $i
		fi
	    done
	}

Can you think of a better idiom than $(eval print '${(t)'${arg[1]}'}') to
get the type of the variable whose name is the value of $arg[1] ?  I keep
thinking there ought to be a way with ${(e)...} but couldn't make it work.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com


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

end of thread, other threads:[~1999-02-02 20:07 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-02-02 16:58 Associative array ordering and selective unset (Re: Example function) Sven Wischnowsky
1999-02-02 17:41 ` ${(P)${foo}} (Re: Associative array ordering) Bart Schaefer
  -- strict thread matches above, loose matches on Subject: below --
1999-02-02  8:01 Associative array ordering and selective unset (Re: Example function) Sven Wischnowsky
1999-02-02  7:52 Sven Wischnowsky
1999-02-01 10:48 Example function Sven Wischnowsky
1999-02-01 17:02 ` Associative array ordering and selective unset (Re: Example function) Bart Schaefer
1999-02-01 17:39   ` Bruce Stephens
1999-02-01 19:09     ` Bart Schaefer
1999-02-02 20:07   ` Phil Pennock

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