From: Peter Stephenson <p.w.stephenson@ntlworld.com>
To: zsh-workers@zsh.org
Subject: Re: Parsing of "anonymous" functions
Date: Thu, 2 Jan 2014 20:35:40 +0000 [thread overview]
Message-ID: <20140102203540.46609ee2@pws-pc.ntlworld.com> (raw)
In-Reply-To: <131228120730.ZM26843@torch.brasslantern.com>
On Sat, 28 Dec 2013 12:07:30 -0800
Bart Schaefer <schaefer@brasslantern.com> 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 <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/
prev parent reply other threads:[~2014-01-02 20:36 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-28 20:07 Bart Schaefer
2014-01-02 20:35 ` Peter Stephenson [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140102203540.46609ee2@pws-pc.ntlworld.com \
--to=p.w.stephenson@ntlworld.com \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).