From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14891 invoked by alias); 2 Jan 2014 20:36:01 -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: 32217 Received: (qmail 10286 invoked from network); 2 Jan 2014 20:35:46 -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=-2.6 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:date:from:to:subject:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=JbMkraWYXeheU5Rctz6YeUljlP9erSVh9KXbLjILpU8=; b=WlU6ebwh8tX68GtVtilsLMM15v/9ftK+WLqPDpfcZD7XROwIdVOSz3xZGek/4l2gp+ Q/gYJTIp1Tj3bWaz3qPwu5StId48hvTRDmmq9LHllZDYbeYu50Wyk53iK+nPaWRx9lT4 y7iniBGsz1hJzE4KO1YoT8BUaLdTfnizK+2Fhji4BEhJHYRI35sP5+2CYbc+7LYmyE9M WTnfBdzzxIUXG0H3Cn6c/xcWD3KxVOwhGKsVDLpO7v8a+D5acRwnB7Q4+pGUQ9XlTY6h 9EmwBSfhd6PokVebtEEcdLW4bgeESK3E6BZ7WFoJIz8/xQexffOMfWxCrqFCF+loILDY J41w== X-Gm-Message-State: ALoCoQktcMrBo71saFY/RWRJjj/tpR/xPZ/okpGblD3c2IVkozKiOhjksomn0Wrz9hCJ7UXtB9Dd X-Received: by 10.180.90.230 with SMTP id bz6mr52394442wib.17.1388694943578; Thu, 02 Jan 2014 12:35:43 -0800 (PST) X-ProxyUser-IP: 86.6.157.246 Date: Thu, 2 Jan 2014 20:35:40 +0000 From: Peter Stephenson To: zsh-workers@zsh.org Subject: Re: Parsing of "anonymous" functions Message-ID: <20140102203540.46609ee2@pws-pc.ntlworld.com> In-Reply-To: <131228120730.ZM26843@torch.brasslantern.com> References: <131228120730.ZM26843@torch.brasslantern.com> X-Mailer: Claws Mail 3.8.0 (GTK+ 2.24.7; x86_64-redhat-linux-gnu) Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit On Sat, 28 Dec 2013 12:07:30 -0800 Bart Schaefer wrote: > I just noticed this: > > torch% ()()()()()()()() > function function function function function function function function> > > Did we really mean for this to be possible or should the parser be pickier > about requiring an "ordinary" command structure as the first thing after > the empty parens? It's not just anonymous functions: you can put a name before the parentheses. It's triggered by the ability to write simple functions without braces, one of those "who ordered that?" compatibility nightmares, though I think this is more pukka than most such things since it seems to come from ksh. Given that, actually I don't think this really is a bug. It's a bit bizarre, but it's a logical syntax: fn()() echo foo defines a function fn() that executes an anonymous function that contains the code "echo foo". This does appear to work, even though I don't see any reason for a nested function context when the code inside is limited to a simple command. So I don't think I'm going to commit the code below. Anyway, a potential fix looks easy enough. I spotted and fixed one side effect, which the second regression test checks for, but this is already obscure enough that I'm not too worried about further issues. diff --git a/Src/parse.c b/Src/parse.c index f0d0855..b434b46 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -726,7 +726,7 @@ par_pline(int *complex) p = ecadd(0); - if (!par_cmd(complex)) { + if (!par_cmd(complex, 0)) { ecused--; return 0; } @@ -781,7 +781,7 @@ par_pline(int *complex) /**/ static int -par_cmd(int *complex) +par_cmd(int *complex, int infuncdef) { int r, nr = 0; @@ -877,7 +877,7 @@ par_cmd(int *complex) { int sr; - if (!(sr = par_simple(complex, nr))) { + if (!(sr = par_simple(complex, nr, infuncdef))) { if (!nr) return 0; } else { @@ -1564,7 +1564,7 @@ par_dinbrack(void) /**/ static int -par_simple(int *complex, int nr) +par_simple(int *complex, int nr, int infuncdef) { int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; int c = *complex, nrediradd, assignments = 0; @@ -1701,6 +1701,9 @@ par_simple(int *complex, int nr) /* Error if preceding assignments */ if (assignments) YYERROR(oecused); + /* Error if we've already been here */ + if (infuncdef) + YYERROR(oecused); *complex = c; lineno = 0; @@ -1746,7 +1749,7 @@ par_simple(int *complex, int nr) sl = ecadd(0); (void)ecadd(WCB_PIPE(WC_PIPE_END, 0)); - if (!par_cmd(&c)) { + if (!par_cmd(&c, 1)) { cmdpop(); YYERROR(oecused); } @@ -1787,6 +1790,10 @@ par_simple(int *complex, int nr) } else break; isnull = 0; + /* + * "foo()() blah" is invalid, but "foo() bar() blah" is valid. + */ + infuncdef = 0; } if (isnull && !(sr + nr)) { ecused = p; diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst index 706aa28..2173119 100644 --- a/Test/C04funcdef.ztst +++ b/Test/C04funcdef.ztst @@ -267,6 +267,19 @@ >ignorebraces is off >ignorebraces is still on here +# ` emacs sh-mode deconfusion + + fn()() +1:multiple ()s in a function definition are an error +?(eval): parse error near `()' + +# ` emacs sh-mode deconfusion + + fnfoo() fnbar() echo this is silly but it does work. + fnfoo + fnbar +0:multiple ()s in separate function definitions are OK +>this is silly but it does work. %clean -- Peter Stephenson Web page now at http://homepage.ntlworld.com/p.w.stephenson/