Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: anonymous functions (no documentation yet)
- X-seq: zsh-workers 25246
- From: Peter Stephenson <pws@xxxxxxx>
- To: zsh-workers@xxxxxxxxxx (Zsh hackers list)
- Subject: PATCH: anonymous functions (no documentation yet)
- Date: Thu, 26 Jun 2008 14:51:42 +0100
- Mailing-list: contact zsh-workers-help@xxxxxxxxxx; run by ezmlm
I just spotted that it's very easy to add "anonymous" functions, which
are defined using normal function syntax, but executed immediately.
This creates a local variable context:
(){
local variable="no great"
print "In anonymous function with $variable value";
}
executes immediately but "variable" does not remain set. The most
obvious use of this would be in initialization files: you get a local
variable scope that guarantees not to pollute the function table.
Currently the code gets copied as if for use in the shell structure,
but I can probably optimise that out. This would make it slightly less
efficient than a normal "{ ... }", but not much.
This syntax has always been accepted, oddly, but the code used simply to
be ignored. This is a syntax error in other shells (at least bash, ksh
88, pdksh, Solaris 8 sh), so there's no clash. (If you want protection
against triggering advanced features you have come to completely the
wrong shell anyway.)
Note this does not affect cases like
$emptyvariable() { ... }
since the patch requires that there be nothing before the () even before
expansion. So you're protected against accidental execution. (Should
this be a syntax error? I would think it probably should. This is a
separate issue, however.)
It turns out the same patch works for "function { ... }", too; same
protection against empty expansions; also a syntax error in other
shells.
Is there any interest in pursuing this? (Note that, although I am open
to suggestions, I am quite definitely not asking "is there any interest
in pursuing a dozen more complicated additions I have no time to
write".)
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.132
diff -u -r1.132 exec.c
--- Src/exec.c 11 Jun 2008 09:27:55 -0000 1.132
+++ Src/exec.c 26 Jun 2008 13:31:10 -0000
@@ -3853,7 +3853,7 @@
execfuncdef(Estate state, UNUSED(int do_exec))
{
Shfunc shf;
- char *s;
+ char *s = NULL;
int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0;
Wordcode beg = state->pc, end;
Eprog prog;
@@ -3861,10 +3861,7 @@
LinkList names;
end = beg + WC_FUNCDEF_SKIP(state->pc[-1]);
- if (!(names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
- state->pc = end;
- return 0;
- }
+ names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
nprg = end - beg;
sbeg = *state->pc++;
nstrs = *state->pc++;
@@ -3874,10 +3871,10 @@
plen = nprg * sizeof(wordcode);
len = plen + (npats * sizeof(Patprog)) + nstrs;
- if (htok)
+ if (htok && names)
execsubst(names);
- while ((s = (char *) ugetnode(names))) {
+ while (!names || (s = (char *) ugetnode(names))) {
prog = (Eprog) zalloc(sizeof(*prog));
prog->npats = npats;
prog->nref = 1; /* allocated from permanent storage */
@@ -3906,23 +3903,38 @@
shf->funcdef = prog;
shf->node.flags = 0;
- /* is this shell function a signal trap? */
- if (!strncmp(s, "TRAP", 4) &&
- (signum = getsignum(s + 4)) != -1) {
- if (settrap(signum, NULL, ZSIG_FUNC)) {
- freeeprog(shf->funcdef);
- zfree(shf, sizeof(*shf));
- state->pc = end;
- return 1;
- }
-
+ if (!names) {
/*
- * Remove the old node explicitly in case it has
- * an alternative name
+ * Anonymous function, execute immediately.
*/
- removetrapnode(signum);
+ LinkList args = newlinklist();
+
+ shf->node.nam = "(anon)";
+ addlinknode(args, shf->node.nam);
+ execshfunc(shf, args);
+
+ freeeprog(shf->funcdef);
+ zfree(shf, sizeof(struct shfunc));
+ break;
+ } else {
+ /* is this shell function a signal trap? */
+ if (!strncmp(s, "TRAP", 4) &&
+ (signum = getsignum(s + 4)) != -1) {
+ if (settrap(signum, NULL, ZSIG_FUNC)) {
+ freeeprog(shf->funcdef);
+ zfree(shf, sizeof(*shf));
+ state->pc = end;
+ return 1;
+ }
+
+ /*
+ * Remove the old node explicitly in case it has
+ * an alternative name
+ */
+ removetrapnode(signum);
+ }
+ shfunctab->addnode(shfunctab, ztrdup(s), shf);
}
- shfunctab->addnode(shfunctab, ztrdup(s), shf);
}
state->pc = end;
return 0;
--
Peter Stephenson <pws@xxxxxxx> Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK Tel: +44 (0)1223 692070
Messages sorted by:
Reverse Date,
Date,
Thread,
Author