mirror of git://git.code.sf.net/p/zsh/code
25255: add anonymous function capability
This commit is contained in:
parent
d09e51d609
commit
950756d579
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
78
Src/exec.c
78
Src/exec.c
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue