From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20890 invoked by alias); 25 Sep 2014 11:39:16 -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: 33242 Received: (qmail 11770 invoked from network); 25 Sep 2014 11:39:12 -0000 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI, SPF_HELO_PASS autolearn=ham version=3.3.2 X-AuditID: cbfec7f5-b7f776d000003e54-99-5423fedbc1ed Date: Thu, 25 Sep 2014 12:39:06 +0100 From: Peter Stephenson To: Mikael Magnusson , zsh workers Subject: Re: Surprising parsing result with anonymous functions and for loops Message-id: <20140925123906.53c1d853@pwslap01u.europe.root.pri> In-reply-to: References: <20140924152625.73dfa6d9@pwslap01u.europe.root.pri> Organization: Samsung Cambridge Solution Centre X-Mailer: Claws Mail 3.7.9 (GTK+ 2.22.0; i386-redhat-linux-gnu) MIME-version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprOLMWRmVeSWpSXmKPExsVy+t/xy7q3/ymHGPw+aWNxbup3RouDzQ+Z HJg8ds66y+6x6uAHpgCmKC6blNSczLLUIn27BK6MI/OusxSckqs4u+IySwNjm3gXIyeHhICJ xOVNExghbDGJC/fWs3UxcnEICSxllDj1fx0LhNPPJDFn82FWkCoWAVWJNRubwTrYBAwlpm6a DWaLCHhL9C5aw9TFyMEhLOAr0fdSFCTMK2AvcXn5T3YQm1MgWOLgvx4miJl3mSQ+LF/MDJLg F9CXuPr3ExPEFfYSM6+cYYRoFpT4MfkeC4jNLKAlsXlbEyuELS+xec1b5gmMArOQlM1CUjYL SdkCRuZVjKKppckFxUnpuUZ6xYm5xaV56XrJ+bmbGCGB+XUH49JjVocYBTgYlXh4PfyVQ4RY E8uKK3MPMUpwMCuJ8K78BBTiTUmsrEotyo8vKs1JLT7EyMTBKdXA2PGhcaf27nsv07/5JrJ9 P3/nqkZf+h4OsaBQgW1TDFNm72a8ntV+5sI9mYeVhw4u67pveoKtULAqnWE6n6mdUEcRQ+dX zyuWz52Wr41JXNMhL/Ri86FFqtI/Rdjen5rSoP31x1quCrFpEtN8tL3YAtgmNb189Oqmaau3 HLfys/qngSd7l0XMUmIpzkg01GIuKk4EAJxe5m8qAgAA On Thu, 25 Sep 2014 12:02:55 +0200 Mikael Magnusson wrote: > Okay, but does anyone at least agree that doing alias expansion at > that point is highly surprising? You mean regardless of function behaviour? % alias foo=bar % for i in 1; do : ; done foo zsh: parse error near `bar' The parser doesn't expect anything there so doesn't make special arrangements not to treat it as a command word because it doesn't mean anything anyway, but this one is easy to fix. The cases with standard keywords are the simple ones as there must be a separator next --- closing braces are harder because there are so many cases, but I think loops are unproblematic (this is special to zsh). Anything similar requires some different ad hoc change. I had a go at if and there are gotchas: if (true) { : } else { : } is valid syntax (again this is annoying zsh-specific stuff I wish we didn't have to maintain) so we need to be in command position after any closing braces except after the final "else". We've already got a reasonable set of tests in this area for the more important non-error case. "while" and "repeat" look similar to "for". The more standard uses of braces for functions are explicitly setting incmdpos = 1 --- I can't remember why, but I've a vague memory it's complicated. It looks like I added a special case for anonymous functions to set incmdpos = 0. So you still get % alias foo=bar % foo() { : } foo zsh: parse error near `bar' and I'm not sure how much I want to look --- it would be easy to break something here. If we fix redirections at this point the answer may become more obvious. For current shell { ... } this also happens but it's a bit more understandable as an "always" keyword can follow. pws diff --git a/Src/parse.c b/Src/parse.c index 5f1303f..3633417 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -997,17 +997,20 @@ par_for(int *complex) par_save_list(complex); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); par_save_list(complex); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (csh || isset(CSHJUNKIELOOPS)) { par_save_list(complex); if (tok != ZEND) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (unset(SHORTLOOPS)) { YYERRORV(oecused); @@ -1186,9 +1189,12 @@ par_if(int *complex) for (;;) { xtok = tok; cmdpush(xtok == IF ? CS_IF : CS_ELIF); - zshlex(); - if (xtok == FI) + if (xtok == FI) { + incmdpos = 0; + zshlex(); break; + } + zshlex(); if (xtok == ELSE) break; while (tok == SEPER) @@ -1229,6 +1235,7 @@ par_if(int *complex) YYERRORV(oecused); } ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); + /* command word (else) allowed to follow immediately */ zshlex(); incmdpos = 1; if (tok == SEPER) @@ -1266,6 +1273,7 @@ par_if(int *complex) YYERRORV(oecused); } } + incmdpos = 0; ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp); zshlex(); cmdpop(); @@ -1296,12 +1304,14 @@ par_while(int *complex) par_save_list(complex); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); par_save_list(complex); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (isset(CSHJUNKIELOOPS)) { par_save_list(complex); @@ -1340,12 +1350,14 @@ par_repeat(int *complex) par_save_list(complex); if (tok != DONE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (tok == INBRACE) { zshlex(); par_save_list(complex); if (tok != OUTBRACE) YYERRORV(oecused); + incmdpos = 0; zshlex(); } else if (isset(CSHJUNKIELOOPS)) { par_save_list(complex);