1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-30 19:20:53 +02:00

29492: add argument handling to anonymous functions

This commit is contained in:
Peter Stephenson 2011-06-19 20:12:00 +00:00
parent 437d5d98f6
commit 6062529d3f
6 changed files with 133 additions and 40 deletions

View file

@ -1,5 +1,8 @@
2011-06-19 Peter Stephenson <p.w.stephenson@ntlworld.com> 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 * unposted: Src/Zle/zle_refresh.c: remove additional loop
noticed by Mikael. noticed by Mikael.
@ -15019,5 +15022,5 @@
***************************************************** *****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL * This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.5375 $ * $Revision: 1.5376 $
***************************************************** *****************************************************

View file

@ -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 specially. Either form of function definition may be used: a `tt(())' with
no preceding name, or a `tt(function)' with an immediately following open no preceding name, or a `tt(function)' with an immediately following open
brace. The function is executed immediately at the point of definition and 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 is not stored for future use. The function name is set to `tt((anon))'.
the parameter list passed to the function is empty. Note that this means
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. the argument list of any enclosing script or function is hidden.
Redirections may be applied to the anonymous function in the same manner as 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 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 functions is to provide a scope for local variables. This is particularly
@ -172,13 +176,13 @@ For example,
example(variable=outside example(variable=outside
function { function {
local variable=inside local variable=inside
print "I am $variable" print "I am $variable with arguments $*"
} } this and that
print "I am $variable") print "I am $variable")
outputs the following: outputs the following:
example(I am inside example(I am inside with arguments this and that
I am outside) I am outside)
Note that function definitions with arguments that expand to nothing, Note that function definitions with arguments that expand to nothing,

View file

@ -4184,10 +4184,19 @@ execfuncdef(Estate state, UNUSED(int do_exec))
* Anonymous function, execute immediately. * Anonymous function, execute immediately.
* Function name is "(anon)", parameter list is empty. * 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)"; shf->node.nam = "(anon)";
addlinknode(args, shf->node.nam); pushnode(args, shf->node.nam);
execshfunc(shf, args); execshfunc(shf, args);
ret = lastval; ret = lastval;

View file

@ -1480,12 +1480,25 @@ par_funcdef(void)
ecbuf[p + num + 4] = ecnpats; ecbuf[p + num + 4] = ecnpats;
ecbuf[p + 1] = num; ecbuf[p + 1] = num;
lineno += oldlineno;
ecnpats = onp; ecnpats = onp;
ecssub = oecssub; ecssub = oecssub;
ecnfunc++; ecnfunc++;
ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); 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 + 3] = ecsoffs - so;
ecbuf[p + argc + 4] = ecnpats; ecbuf[p + argc + 4] = ecnpats;
lineno += oldlineno;
ecnpats = onp; ecnpats = onp;
ecssub = oecssub; ecssub = oecssub;
ecnfunc++; ecnfunc++;
ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); 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; isfunc = 1;
isnull = 0; isnull = 0;
break; break;

View file

@ -253,6 +253,7 @@ struct tstack {
struct { struct {
char *strs; char *strs;
Wordcode end; Wordcode end;
int nargs;
} _funcdef; } _funcdef;
struct { struct {
Wordcode end; Wordcode end;
@ -456,19 +457,31 @@ gettext2(Estate state)
if (!s) { if (!s) {
Wordcode p = state->pc; Wordcode p = state->pc;
Wordcode end = p + WC_FUNCDEF_SKIP(code); Wordcode end = p + WC_FUNCDEF_SKIP(code);
int nargs = *state->pc++;
taddlist(state, *state->pc++); taddlist(state, nargs);
if (nargs)
taddstr(" ");
if (tjob) { if (tjob) {
taddstr(" () { ... }"); taddstr("() { ... }");
state->pc = end; 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; stack = 1;
} else { } else {
taddstr(" () {"); taddstr("() {");
tindent++; tindent++;
taddnl(1); taddnl(1);
n = tpush(code, 1); n = tpush(code, 1);
n->u._funcdef.strs = state->strs; n->u._funcdef.strs = state->strs;
n->u._funcdef.end = end; n->u._funcdef.end = end;
n->u._funcdef.nargs = nargs;
state->strs += *state->pc; state->strs += *state->pc;
state->pc += 3; state->pc += 3;
} }
@ -478,6 +491,17 @@ gettext2(Estate state)
dec_tindent(); dec_tindent();
taddnl(0); taddnl(0);
taddstr("}"); 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; stack = 1;
} }
break; break;

View file

@ -26,7 +26,7 @@
print regress expansion of function names print regress expansion of function names
} }
f$$ f$$
0:Regression test: `function f$$ () { ... }' 0:Regression test: 'function f$$ () { ... }'
>regress expansion of function names >regress expansion of function names
function foo () print bar function foo () print bar
@ -109,6 +109,8 @@
>really useful >really useful
>args >args
# ' deconfuse emacs
command_not_found_handler() { command_not_found_handler() {
print "Your command:" >&2 print "Your command:" >&2
print "$1" >&2 print "$1" >&2
@ -201,6 +203,31 @@
>Da de da >Da de da
>Do be do >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 %clean
rm -f file.in file.out rm -f file.in file.out