25255: add anonymous function capability

This commit is contained in:
Peter Stephenson 2008-06-30 10:37:11 +00:00
parent d09e51d609
commit 950756d579
4 changed files with 170 additions and 28 deletions

View File

@ -1,3 +1,8 @@
2008-06-30 Peter Stephenson <pws@csr.com>
* 25255: Doc/Zsh/func.yo, Src/exec.c, Test/C04funcdef.ztst:
anonymous functions using "() { ... }" and "function { ... }".
2008-06-24 Clint Adams <clint@zsh.org>
* 25243: Completion/X/Command/_xrandr: patch from Chris Lamb to add

View File

@ -150,6 +150,42 @@ executing tt(myfunc), use:
example(autoload +X myfunc)
sect(Anonymous Functions)
cindex(anonymous functions)
cindex(functions, anonymous)
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
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
convenient in start-up files as these do not provide their own local
variable scope.
For example,
example(variable=outside
function {
local variable=inside
print "I am $variable"
}
print "I am $variable")
outputs the following:
example(I am inside
I am outside)
Note that function definitions with arguments that expand to nothing,
for example `tt(name=; function $name { )var(...)tt( })', are not
treated as anonymous functions. Instead, they are treated as normal
function definitions where the definition is silently discarded.
sect(Special Functions)
Certain functions, if defined, have special meaning to the shell.

View File

@ -3853,7 +3853,7 @@ static int
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 @@ execfuncdef(Estate state, UNUSED(int do_exec))
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,21 +3871,32 @@ execfuncdef(Estate state, UNUSED(int do_exec))
plen = nprg * sizeof(wordcode);
len = plen + (npats * sizeof(Patprog)) + nstrs;
if (htok)
if (htok && names)
execsubst(names);
while ((s = (char *) ugetnode(names))) {
prog = (Eprog) zalloc(sizeof(*prog));
while (!names || (s = (char *) ugetnode(names))) {
if (!names) {
prog = (Eprog) zhalloc(sizeof(*prog));
prog->nref = -1; /* on the heap */
} else {
prog = (Eprog) zalloc(sizeof(*prog));
prog->nref = 1; /* allocated from permanent storage */
}
prog->npats = npats;
prog->nref = 1; /* allocated from permanent storage */
prog->len = len;
if (state->prog->dump) {
prog->flags = EF_MAP;
incrdumpcount(state->prog->dump);
prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
if (state->prog->dump || !names) {
if (!names) {
prog->flags = EF_HEAP;
prog->dump = NULL;
prog->pats = pp = (Patprog *) zhalloc(npats * sizeof(Patprog));
} else {
prog->flags = EF_MAP;
incrdumpcount(state->prog->dump);
prog->dump = state->prog->dump;
prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
}
prog->prog = state->pc;
prog->strs = state->strs + sbeg;
prog->dump = state->prog->dump;
} else {
prog->flags = EF_REAL;
prog->pats = pp = (Patprog *) zalloc(len);
@ -3906,23 +3914,37 @@ execfuncdef(Estate state, UNUSED(int do_exec))
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.
* Function name is "(anon)", parameter list is empty.
*/
removetrapnode(signum);
LinkList args = newlinklist();
shf->node.nam = "(anon)";
addlinknode(args, shf->node.nam);
execshfunc(shf, args);
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;

View File

@ -99,3 +99,82 @@
?ThisCommandDoesNotExistEither
?has gone down the tubes. Sorry.
?(eval):7: command not found: ThisCommandDoesNotExistEither
local variable=outside
print "I am $variable"
function {
local variable=inside
print "I am $variable"
}
print "I am $variable"
() {
local variable="inside again"
print "I am $variable"
}
print "I am $variable"
0:Anonymous function scope
>I am outside
>I am inside
>I am outside
>I am inside again
>I am outside
integer i
for (( i = 0; i < 10; i++ )); do function {
case $i in
([13579])
print $i is odd
;|
([2468])
print $i is even
;|
([2357])
print $i is prime
;;
esac
}; done
0:Anonymous function with patterns in loop
>1 is odd
>2 is even
>2 is prime
>3 is odd
>3 is prime
>4 is even
>5 is odd
>5 is prime
>6 is even
>7 is odd
>7 is prime
>8 is even
>9 is odd
echo stuff in file >file.in
function {
sed 's/stuff/rubbish/'
} <file.in >file.out
cat file.out
0:Anonymous function redirection
>rubbish in file
variable="Do be do"
print $variable
function {
print $variable
local variable="Da de da"
print $variable
function {
print $variable
local variable="Dum da dum"
print $variable
}
print $variable
}
print $variable
0:Nested anonymous functions
>Do be do
>Do be do
>Da de da
>Da de da
>Dum da dum
>Da de da
>Do be do