about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2011-06-19 20:12:00 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2011-06-19 20:12:00 +0000
commit6062529d3fc7c7d29c63d0726d2449d4b56f33ac (patch)
tree8131c4e1678053413559fe71159201f891786a70
parent437d5d98f6d05588e23a6d9fda50184d0b6a80bb (diff)
downloadzsh-6062529d3fc7c7d29c63d0726d2449d4b56f33ac.tar.gz
zsh-6062529d3fc7c7d29c63d0726d2449d4b56f33ac.tar.xz
zsh-6062529d3fc7c7d29c63d0726d2449d4b56f33ac.zip
29492: add argument handling to anonymous functions
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/func.yo14
-rw-r--r--Src/exec.c65
-rw-r--r--Src/parse.c30
-rw-r--r--Src/text.c30
-rw-r--r--Test/C04funcdef.ztst29
6 files changed, 133 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 446bff14b..8eca2d9cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2011-06-19  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
+	* 29492: Doc/Zsh/func.yo, Src/exec.c, Src/parse.c, Src/text.c,
+	Test/C04funcdef.ztst: add argument handling to anonymous functions.
+
 	* unposted: Src/Zle/zle_refresh.c: remove additional loop
 	noticed by Mikael.
 
@@ -15019,5 +15022,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5375 $
+* $Revision: 1.5376 $
 *****************************************************
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index 28bc6329a..89b956cb4 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -158,9 +158,13 @@ If no name is given for a function, it is `anonymous' and is handled
 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,
diff --git a/Src/exec.c b/Src/exec.c
index 2558185c8..87a167ba6 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -50,20 +50,20 @@ int noerrexit;
  * noerrs = 1: suppress error messages
  * noerrs = 2: don't set errflag on parse error, either
  */
- 
+
 /**/
 mod_export int noerrs;
- 
+
 /* do not save history on exec and exit */
 
 /**/
 int nohistsave;
- 
+
 /* error/break flag */
- 
+
 /**/
 mod_export int errflag;
- 
+
 /*
  * State of trap return value.  Value is from enum trap_state.
  */
@@ -88,23 +88,23 @@ int trap_state;
  * - non-negative in a trap once it was triggered.  It should remain
  *   non-negative until restored after execution of the trap.
  */
- 
+
 /**/
 int trap_return;
- 
+
 /* != 0 if this is a subshell */
- 
+
 /**/
 int subsh;
- 
+
 /* != 0 if we have a return pending */
- 
+
 /**/
 mod_export int retflag;
 
 /**/
 long lastval2;
- 
+
 /* The table of file descriptors.  A table element is zero if the  *
  * corresponding fd is not used by the shell.  It is greater than  *
  * 1 if the fd is used by a <(...) or >(...) substitution and 1 if *
@@ -148,12 +148,12 @@ int fdtable_flocks;
 mod_export int zleactive;
 
 /* pid of process undergoing 'process substitution' */
- 
+
 /**/
 pid_t cmdoutpid;
- 
+
 /* exit status of process undergoing 'process substitution' */
- 
+
 /**/
 int cmdoutval;
 
@@ -166,7 +166,7 @@ int cmdoutval;
 /**/
 int use_cmdoutval;
 
-/* The context in which a shell function is called, see SFC_* in zsh.h. */ 
+/* The context in which a shell function is called, see SFC_* in zsh.h. */
 
 /**/
 mod_export int sfcontext;
@@ -239,7 +239,7 @@ parse_string(char *s, int reset_lineno)
 
 /**/
 mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
- 
+
 /**/
 mod_export int
 zsetlimit(int limnum, char *nam)
@@ -340,7 +340,7 @@ zfork(struct timeval *tv)
  *
  * (when waiting for the grep, ignoring execpline2 for now). At this time,
  * zsh has built two job-table entries for it: one for the cat and one for
- * the grep. If the user hits ^Z at this point (and jobbing is used), the 
+ * the grep. If the user hits ^Z at this point (and jobbing is used), the
  * shell is notified that the grep was suspended. The list_pipe flag is
  * used to tell the execpline where it was waiting that it was in a pipeline
  * with a shell construct at the end (which may also be a shell function or
@@ -351,7 +351,7 @@ zfork(struct timeval *tv)
  * shell (its pid and the text for it) in the job entry of the cat. The pid
  * is passed down in the list_pipe_pid variable.
  * But there is a problem: the suspended grep is a child of the parent shell
- * and can't be adopted by the sub-shell. So the parent shell also has to 
+ * and can't be adopted by the sub-shell. So the parent shell also has to
  * keep the information about this process (more precisely: this pipeline)
  * by keeping the job table entry it created for it. The fact that there
  * are two jobs which have to be treated together is remembered by setting
@@ -528,10 +528,10 @@ isgooderr(int e, char *dir)
 {
     /*
      * Maybe the directory was unreadable, or maybe it wasn't
-     * even a directory. 
+     * even a directory.
      */
     return ((e != EACCES || !access(dir, X_OK)) &&
-	    e != ENOENT && e != ENOTDIR); 
+	    e != ENOENT && e != ENOTDIR);
 }
 
 /*
@@ -639,7 +639,7 @@ execute(LinkList args, int flags, int defpath)
 	    break;
 	}
 
-    /* for command -p, search the default path */ 
+    /* for command -p, search the default path */
     if (defpath) {
 	char *s, pbuf[PATH_MAX];
 	char *dptr, *pe, *ps = DEFAULT_PATH;
@@ -676,7 +676,7 @@ execute(LinkList args, int flags, int defpath)
 	    eno = ee;
 
     } else {
-   
+
 	if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
 	    char nn[PATH_MAX], *dptr;
 
@@ -1312,9 +1312,9 @@ sublist_done:
 		donetrap = 1;
 	    }
 	    if (lastval) {
-		int errreturn = isset(ERRRETURN) && 
+		int errreturn = isset(ERRRETURN) &&
 		    (isset(INTERACTIVE) || locallevel || sourcelevel);
-		int errexit = isset(ERREXIT) || 
+		int errexit = isset(ERREXIT) ||
 		    (isset(ERRRETURN) && !errreturn);
 		if (errexit) {
 		    if (sigtrapped[SIGEXIT])
@@ -1536,7 +1536,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		    else if (pid) {
 			char dummy;
 
-			lpforked = 
+			lpforked =
 			    (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
 			list_pipe_pid = pid;
 			list_pipe_start = bgtime;
@@ -3112,7 +3112,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		ESUB_PGRP | ESUB_FAKE;
 	    if (type != WC_SUBSH)
 		flags |= ESUB_KEEPTRAP;
-	    if ((do_exec || (type >= WC_CURSH && last1 == 1)) 
+	    if ((do_exec || (type >= WC_CURSH && last1 == 1))
 		&& !forked)
 		flags |= ESUB_REVERTPGRP;
 	    entersubsh(flags);
@@ -4184,10 +4184,19 @@ execfuncdef(Estate state, UNUSED(int do_exec))
 	     * 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;
diff --git a/Src/parse.c b/Src/parse.c
index 4720dc3cf..5b6f09949 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -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;
diff --git a/Src/text.c b/Src/text.c
index 669037a2d..f55553ed0 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -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;
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
index f71e5ce77..0cc5e5a2f 100644
--- a/Test/C04funcdef.ztst
+++ b/Test/C04funcdef.ztst
@@ -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