mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-13 11:21:13 +02:00
29492: add argument handling to anonymous functions
This commit is contained in:
parent
437d5d98f6
commit
6062529d3f
6 changed files with 133 additions and 40 deletions
|
@ -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 $
|
||||
*****************************************************
|
||||
|
|
|
@ -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,
|
||||
|
|
13
Src/exec.c
13
Src/exec.c
|
@ -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;
|
||||
|
|
30
Src/parse.c
30
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;
|
||||
|
|
30
Src/text.c
30
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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue