mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-26 18:01:03 +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,
|
||||
|
|
65
Src/exec.c
65
Src/exec.c
|
@ -50,20 +50,20 @@ int noerrexit;
|
|||
* noerrs = 1: suppress error messages
|
||||
* noerrs = 2: don't set errflag on parse error, either
|
||||
*/
|
||||
|
||||
|
||||
/**/
|
||||
mod_export int noerrs;
|
||||
|
||||
|
||||
/* do not save history on exec and exit */
|
||||
|
||||
/**/
|
||||
int nohistsave;
|
||||
|
||||
|
||||
/* error/break flag */
|
||||
|
||||
|
||||
/**/
|
||||
mod_export int errflag;
|
||||
|
||||
|
||||
/*
|
||||
* State of trap return value. Value is from enum trap_state.
|
||||
*/
|
||||
|
@ -88,23 +88,23 @@ int trap_state;
|
|||
* - non-negative in a trap once it was triggered. It should remain
|
||||
* non-negative until restored after execution of the trap.
|
||||
*/
|
||||
|
||||
|
||||
/**/
|
||||
int trap_return;
|
||||
|
||||
|
||||
/* != 0 if this is a subshell */
|
||||
|
||||
|
||||
/**/
|
||||
int subsh;
|
||||
|
||||
|
||||
/* != 0 if we have a return pending */
|
||||
|
||||
|
||||
/**/
|
||||
mod_export int retflag;
|
||||
|
||||
/**/
|
||||
long lastval2;
|
||||
|
||||
|
||||
/* The table of file descriptors. A table element is zero if the *
|
||||
* corresponding fd is not used by the shell. It is greater than *
|
||||
* 1 if the fd is used by a <(...) or >(...) substitution and 1 if *
|
||||
|
@ -148,12 +148,12 @@ int fdtable_flocks;
|
|||
mod_export int zleactive;
|
||||
|
||||
/* pid of process undergoing 'process substitution' */
|
||||
|
||||
|
||||
/**/
|
||||
pid_t cmdoutpid;
|
||||
|
||||
|
||||
/* exit status of process undergoing 'process substitution' */
|
||||
|
||||
|
||||
/**/
|
||||
int cmdoutval;
|
||||
|
||||
|
@ -166,7 +166,7 @@ int cmdoutval;
|
|||
/**/
|
||||
int use_cmdoutval;
|
||||
|
||||
/* The context in which a shell function is called, see SFC_* in zsh.h. */
|
||||
/* The context in which a shell function is called, see SFC_* in zsh.h. */
|
||||
|
||||
/**/
|
||||
mod_export int sfcontext;
|
||||
|
@ -239,7 +239,7 @@ parse_string(char *s, int reset_lineno)
|
|||
|
||||
/**/
|
||||
mod_export struct rlimit current_limits[RLIM_NLIMITS], limits[RLIM_NLIMITS];
|
||||
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
zsetlimit(int limnum, char *nam)
|
||||
|
@ -340,7 +340,7 @@ zfork(struct timeval *tv)
|
|||
*
|
||||
* (when waiting for the grep, ignoring execpline2 for now). At this time,
|
||||
* zsh has built two job-table entries for it: one for the cat and one for
|
||||
* the grep. If the user hits ^Z at this point (and jobbing is used), the
|
||||
* the grep. If the user hits ^Z at this point (and jobbing is used), the
|
||||
* shell is notified that the grep was suspended. The list_pipe flag is
|
||||
* used to tell the execpline where it was waiting that it was in a pipeline
|
||||
* with a shell construct at the end (which may also be a shell function or
|
||||
|
@ -351,7 +351,7 @@ zfork(struct timeval *tv)
|
|||
* shell (its pid and the text for it) in the job entry of the cat. The pid
|
||||
* is passed down in the list_pipe_pid variable.
|
||||
* But there is a problem: the suspended grep is a child of the parent shell
|
||||
* and can't be adopted by the sub-shell. So the parent shell also has to
|
||||
* and can't be adopted by the sub-shell. So the parent shell also has to
|
||||
* keep the information about this process (more precisely: this pipeline)
|
||||
* by keeping the job table entry it created for it. The fact that there
|
||||
* are two jobs which have to be treated together is remembered by setting
|
||||
|
@ -528,10 +528,10 @@ isgooderr(int e, char *dir)
|
|||
{
|
||||
/*
|
||||
* Maybe the directory was unreadable, or maybe it wasn't
|
||||
* even a directory.
|
||||
* even a directory.
|
||||
*/
|
||||
return ((e != EACCES || !access(dir, X_OK)) &&
|
||||
e != ENOENT && e != ENOTDIR);
|
||||
e != ENOENT && e != ENOTDIR);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -639,7 +639,7 @@ execute(LinkList args, int flags, int defpath)
|
|||
break;
|
||||
}
|
||||
|
||||
/* for command -p, search the default path */
|
||||
/* for command -p, search the default path */
|
||||
if (defpath) {
|
||||
char *s, pbuf[PATH_MAX];
|
||||
char *dptr, *pe, *ps = DEFAULT_PATH;
|
||||
|
@ -676,7 +676,7 @@ execute(LinkList args, int flags, int defpath)
|
|||
eno = ee;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
|
||||
char nn[PATH_MAX], *dptr;
|
||||
|
||||
|
@ -1312,9 +1312,9 @@ sublist_done:
|
|||
donetrap = 1;
|
||||
}
|
||||
if (lastval) {
|
||||
int errreturn = isset(ERRRETURN) &&
|
||||
int errreturn = isset(ERRRETURN) &&
|
||||
(isset(INTERACTIVE) || locallevel || sourcelevel);
|
||||
int errexit = isset(ERREXIT) ||
|
||||
int errexit = isset(ERREXIT) ||
|
||||
(isset(ERRRETURN) && !errreturn);
|
||||
if (errexit) {
|
||||
if (sigtrapped[SIGEXIT])
|
||||
|
@ -1536,7 +1536,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
|
|||
else if (pid) {
|
||||
char dummy;
|
||||
|
||||
lpforked =
|
||||
lpforked =
|
||||
(killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1);
|
||||
list_pipe_pid = pid;
|
||||
list_pipe_start = bgtime;
|
||||
|
@ -3112,7 +3112,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
|
|||
ESUB_PGRP | ESUB_FAKE;
|
||||
if (type != WC_SUBSH)
|
||||
flags |= ESUB_KEEPTRAP;
|
||||
if ((do_exec || (type >= WC_CURSH && last1 == 1))
|
||||
if ((do_exec || (type >= WC_CURSH && last1 == 1))
|
||||
&& !forked)
|
||||
flags |= ESUB_REVERTPGRP;
|
||||
entersubsh(flags);
|
||||
|
@ -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