Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Parsing of "anonymous" functions
- X-seq: zsh-workers 32217
- From: Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: Parsing of "anonymous" functions
- Date: Thu, 2 Jan 2014 20:35:40 +0000
- In-reply-to: <131228120730.ZM26843@torch.brasslantern.com>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- References: <131228120730.ZM26843@torch.brasslantern.com>
On Sat, 28 Dec 2013 12:07:30 -0800
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> 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@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/
Messages sorted by:
Reverse Date,
Date,
Thread,
Author