Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: arguments to anonymous function



This adds arguments to anonymous functions.  The only easy way of doing
this without trampling on other syntax is to pass them after the final
brace, where previously it would have caused a syntax error so it's
unproblematic.  I hope that's not going to be too inconvenient.

Index: Doc/Zsh/func.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/func.yo,v
retrieving revision 1.27
diff -p -u -r1.27 func.yo
--- Doc/Zsh/func.yo	13 Jan 2011 09:31:08 -0000	1.27
+++ Doc/Zsh/func.yo	19 Jun 2011 18:08:21 -0000
@@ -158,9 +158,13 @@ If no name is given for a function, it i
 specially.  Either form of function definition may be used: a `tt(())' with
 no preceding name, or a `tt(function)' with an immediately following open
 brace.  The function is executed immediately at the point of definition and
-is not stored for future use.  The function name is set to `tt((anon))' and
-the parameter list passed to the function is empty.  Note that this means
+is not stored for future use.  The function name is set to `tt((anon))'.
+
+Arguments to the function may be specified as words following the
+closing brace defining the function, hence if there are none no
+arguments (other than tt($0)) are set.  Note that this means
 the argument list of any enclosing script or function is hidden.
+
 Redirections may be applied to the anonymous function in the same manner as
 to a current-shell structure enclosed in braces.  The main use of anonymous
 functions is to provide a scope for local variables.  This is particularly
@@ -172,13 +176,13 @@ For example,
 example(variable=outside
 function {
   local variable=inside
-  print "I am $variable"
-}
+  print "I am $variable with arguments $*"
+} this and that
 print "I am $variable")
 
 outputs the following:
 
-example(I am inside
+example(I am inside with arguments this and that
 I am outside)
 
 Note that function definitions with arguments that expand to nothing,
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.196
diff -p -u -r1.196 exec.c
--- Src/exec.c	24 May 2011 15:49:03 -0000	1.196
+++ Src/exec.c	19 Jun 2011 18:08:22 -0000
@@ -4184,10 +4184,19 @@ execfuncdef(Estate state, UNUSED(int do_
 	     * Anonymous function, execute immediately.
 	     * Function name is "(anon)", parameter list is empty.
 	     */
-	    LinkList args = newlinklist();
+	    LinkList args;
 
+	    state->pc = end;
+	    end += *state->pc++;
+	    args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
+	    
+	    if (htok && args)
+		execsubst(args);
+
+	    if (!args)
+		args = newlinklist();
 	    shf->node.nam = "(anon)";
-	    addlinknode(args, shf->node.nam);
+	    pushnode(args, shf->node.nam);
 
 	    execshfunc(shf, args);
 	    ret = lastval;
Index: Src/parse.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/parse.c,v
retrieving revision 1.87
diff -p -u -r1.87 parse.c
--- Src/parse.c	19 Jun 2011 16:26:11 -0000	1.87
+++ Src/parse.c	19 Jun 2011 18:08:22 -0000
@@ -1480,12 +1480,25 @@ par_funcdef(void)
     ecbuf[p + num + 4] = ecnpats;
     ecbuf[p + 1] = num;
 
-    lineno += oldlineno;
     ecnpats = onp;
     ecssub = oecssub;
     ecnfunc++;
 
     ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
+
+    if (num == 0) {
+	/* Unnamed function */
+	int parg = ecadd(0);
+	ecadd(0);
+	while (tok == STRING) {
+	    ecstr(tokstr);
+	    num++;
+	    zshlex();
+	}
+	ecbuf[parg] = ecused - parg; /*?*/
+	ecbuf[parg+1] = num;
+    }
+    lineno += oldlineno;
 }
 
 /*
@@ -1730,13 +1743,26 @@ par_simple(int *complex, int nr)
 	    ecbuf[p + argc + 3] = ecsoffs - so;
 	    ecbuf[p + argc + 4] = ecnpats;
 
-	    lineno += oldlineno;
 	    ecnpats = onp;
 	    ecssub = oecssub;
 	    ecnfunc++;
 
 	    ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
 
+	    if (argc == 0) {
+		/* Unnamed function */
+		int parg = ecadd(0);
+		ecadd(0);
+		while (tok == STRING) {
+		    ecstr(tokstr);
+		    argc++;
+		    zshlex();
+		}
+		ecbuf[parg] = ecused - parg; /*?*/
+		ecbuf[parg+1] = argc;
+	    }
+	    lineno += oldlineno;
+
 	    isfunc = 1;
 	    isnull = 0;
 	    break;
Index: Src/text.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/text.c,v
retrieving revision 1.28
diff -p -u -r1.28 text.c
--- Src/text.c	9 May 2011 10:27:32 -0000	1.28
+++ Src/text.c	19 Jun 2011 18:08:22 -0000
@@ -253,6 +253,7 @@ struct tstack {
 	struct {
 	    char *strs;
 	    Wordcode end;
+	    int nargs;
 	} _funcdef;
 	struct {
 	    Wordcode end;
@@ -456,19 +457,31 @@ gettext2(Estate state)
 	    if (!s) {
 		Wordcode p = state->pc;
 		Wordcode end = p + WC_FUNCDEF_SKIP(code);
+		int nargs = *state->pc++;
 
-		taddlist(state, *state->pc++);
+		taddlist(state, nargs);
+		if (nargs)
+		    taddstr(" ");
 		if (tjob) {
-		    taddstr(" () { ... }");
+		    taddstr("() { ... }");
 		    state->pc = end;
+		    if (!nargs) {
+			/*
+			 * Unnamed fucntion.
+			 * We're not going to pull any arguments off
+			 * later, so skip them now...
+			 */
+			state->pc += *end;
+		    }
 		    stack = 1;
 		} else {
-		    taddstr(" () {");
+		    taddstr("() {");
 		    tindent++;
 		    taddnl(1);
 		    n = tpush(code, 1);
 		    n->u._funcdef.strs = state->strs;
 		    n->u._funcdef.end = end;
+		    n->u._funcdef.nargs = nargs;
 		    state->strs += *state->pc;
 		    state->pc += 3;
 		}
@@ -478,6 +491,17 @@ gettext2(Estate state)
 		dec_tindent();
 		taddnl(0);
 		taddstr("}");
+		if (s->u._funcdef.nargs == 0) {
+		    /* Unnamed function with post-arguments */
+		    int nargs;
+		    s->u._funcdef.end += *state->pc++;
+		    nargs = *state->pc++;
+		    if (nargs) {
+			taddstr(" ");
+			taddlist(state, nargs);
+		    }
+		    state->pc = s->u._funcdef.end;
+		}
 		stack = 1;
 	    }
 	    break;
Index: Test/C04funcdef.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/C04funcdef.ztst,v
retrieving revision 1.7
diff -p -u -r1.7 C04funcdef.ztst
--- Test/C04funcdef.ztst	11 Jul 2009 16:43:01 -0000	1.7
+++ Test/C04funcdef.ztst	19 Jun 2011 18:08:22 -0000
@@ -26,7 +26,7 @@
     print regress expansion of function names
   }
   f$$
-0:Regression test: `function f$$ () { ... }'
+0:Regression test: 'function f$$ () { ... }'
 >regress expansion of function names
 
   function foo () print bar
@@ -109,6 +109,8 @@
 >really useful
 >args
 
+# ' deconfuse emacs
+
   command_not_found_handler() {
      print "Your command:" >&2
      print "$1" >&2
@@ -201,6 +203,31 @@
 >Da de da
 >Do be do
 
+  () { print This has arguments $*; } of all sorts; print After the function
+  function { print More stuff $*; } and why not; print Yet more
+0:Anonymous function with arguments
+>This has arguments of all sorts
+>After the function
+>More stuff and why not
+>Yet more
+
+  fn() {
+    (){ print Anonymous function 1 $*; } with args
+    function { print Anonymous function 2 $*; } with more args
+    print Following bit
+  }
+  functions fn
+0:Text representation of anonymous function with arguments
+>fn () {
+>	() {
+>		print Anonymous function 1 $*
+>	} with args
+>	() {
+>		print Anonymous function 2 $*
+>	} with more args
+>	print Following bit
+>}
+
 %clean
 
  rm -f file.in file.out

-- 
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