From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20705 invoked by alias); 26 Dec 2009 22:48:27 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 27542 Received: (qmail 19594 invoked from network); 26 Dec 2009 22:48:14 -0000 X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=AWL,BAYES_00 autolearn=ham version=3.2.5 Received-SPF: pass (ns1.primenet.com.au: SPF record at _spf.google.com designates 74.125.78.144 as permitted sender) MIME-Version: 1.0 Date: Sat, 26 Dec 2009 17:48:07 -0500 Message-ID: <22a0ef080912261448x3d14b301yc4082a924cd760d8@mail.gmail.com> Subject: [PATCH]: Revamped (P) expansion flag From: Michael Hwang To: zsh-workers@zsh.org Content-Type: multipart/mixed; boundary=0016e6d7ec2045588c047ba97718 --0016e6d7ec2045588c047ba97718 Content-Type: text/plain; charset=ISO-8859-1 Hello all, In my opinion, the current behavior of the P expansion flag is not intuitive, and possibly even buggy. For instance: % FOO='hello!' % REF='FOO BAR' % print ${(P)${REF}} hello! In this case, ${(P)${REF}} should expand to nothing, because 'FOO BAR' is not a proper parameter name. However, the current logic takes only as much as makes sense, and ignores the rest. This creates confusion with arrays: % ARRAY=(FOO CLUE SHOE) % FOO=zsh % CLUE=is % SHOE=awesome % print ${(P)${ARRAY}} zsh One would think that each element of the reference ARRAY would replaced by the value of the variable in that element. However, zsh will just take the value of FOO, as it's the longest string that makes sense as a variable name. On the more buggy-ish side: % STRING='zsh is awesome!' % STR='zsh sucks... :-/' % REF=STRING % print ${(P)REF[1,3]} zsh sucks... :-/ As ${(P)REF} is really ${(P)${REF}}, one would think that that ${(P)REF[1,3]} would be expanded as ${(P)${REF}[1,3]}. But as you can see, it is instead expanded as ${(P)${REF[1,3]}}. This patch fixes all these problems. The concept of "subexpression" no longer applies with the P flag. Instead, one should consider whether or not the "inside" expression (I call it a "reference") expands to more than one word. Notably: 1.) A reference can now be a mix of plain text and expansions. For example, ${(P)${FOO}_BAR}. 2.) A reference can be quoted. Note that ${(P)"REF"} is now possible, and expands as if it were ${(P)"${REF}"}. 3.) If the reference expands to more than one word, then each element will be expanded to take on the value of that variable. (See below.) It is simplest with quotes: % FOO='zsh.org' % REF=FOO % print ${(P)"REF"} zsh.org % print ${(P)"${REF}"} zsh.org Fairly straight forward. But notice what happens when our reference expands to a non-valid parameter name: % FOO='merry xmas!' % REF='FOO FOO' % print ${(P)"${REF}"} % print ${(P)"REF"} Now try mixing (in quotes): % FOOBAR='buy champagne for new year' % REF=FOO % print ${(P)"${REF}BAR"} buy champagne for new year The expansion takes on the value of the variable name that the insides expand to. Without quotes, array references are possible. % REFS=(A B C) % A=1 % B=2 % C=3 % print -l -- ${(P)${REFS}} 1 2 3 It is also possible to have an array reference with an element that refers to an array parameter: % REFS=(A B C) % A=1 % B=(2 two) % C=3 % print -l -- ${(P)${REFS}} 1 2 two 3 And finally, mixing, non-quoted. % REFS=(FOO CLUE SHOE) % FOOBAR=zsh % CLUEBAR=is % SHOEBAR=awesome % print ${(P)${^REFS}BAR} zsh is awesome Note that ${(P)${REFS}BAR} would just expand to "awesome", as ${REFS}BAR expands to the words "FOO" "CLUE" "SHOEBAR", with FOO and CLUE not being set. Please test these changes. paramsubst() took a long time to understand, so I'm sure that I've introduced a bug or two. Michael Hwang --0016e6d7ec2045588c047ba97718--