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:
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>
|
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 $
|
||||||
*****************************************************
|
*****************************************************
|
||||||
|
|
|
@ -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,
|
||||||
|
|
13
Src/exec.c
13
Src/exec.c
|
@ -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;
|
||||||
|
|
30
Src/parse.c
30
Src/parse.c
|
@ -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;
|
||||||
|
|
30
Src/text.c
30
Src/text.c
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue