home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v92.tgz
/
v92.tar
/
v92
/
src
/
runtime
/
invoke.r
< prev
next >
Wrap
Text File
|
1996-03-22
|
9KB
|
384 lines
/*
* invoke.r - contains invoke, apply
*/
#if COMPILER
/*
* invoke - perform general invocation on a value.
*/
int invoke(nargs, args, rslt, succ_cont)
int nargs;
dptr args;
dptr rslt;
continuation succ_cont;
{
tended struct descrip callee;
struct b_proc *proc;
C_integer n;
/*
* remove the operation being called from the argument list.
*/
deref(&args[0], &callee);
++args;
nargs -= 1;
if (is:proc(callee))
return (*((struct b_proc *)BlkLoc(callee))->ccode)(nargs, args, rslt,
succ_cont);
else if (cnv:C_integer(callee, n)) {
if (n <= 0)
n += nargs + 1;
if (n <= 0 || n > nargs)
return A_Resume;
*rslt = args[n - 1];
return A_Continue;
}
else if (cnv:string(callee, callee)) {
proc = strprc(&callee, (C_integer)nargs);
if (proc == NULL)
RunErr(106, &callee);
return (*(proc)->ccode)(nargs, args, rslt, succ_cont);
}
else
RunErr(106, &callee);
}
/*
* apply - implement binary bang. Construct an argument list for
* invoke() from the callee and the list it is applied to.
*/
int apply(callee, strct, rslt, succ_cont)
dptr callee;
dptr strct;
dptr rslt;
continuation succ_cont;
{
tended struct descrip dstrct;
struct tend_desc *tnd_args; /* place to tend arguments to invoke() */
union block *ep;
int nargs;
word i, j;
word indx;
int signal;
deref(strct, &dstrct);
switch (Type(dstrct)) {
case T_List: {
/*
* Copy the arguments from the list into an tended array of descriptors.
*/
nargs = BlkLoc(dstrct)->list.size + 1;
tnd_args = (struct tend_desc *)malloc((msize)(sizeof(struct tend_desc)
+ (nargs - 1) * sizeof(struct descrip)));
if (tnd_args == NULL)
RunErr(305, NULL);
tnd_args->d[0] = *callee;
indx = 1;
for (ep = BlkLoc(dstrct)->list.listhead;
ep != NULL; ep = ep->lelem.listnext) {
for (i = 0; i < ep->lelem.nused; i++) {
j = ep->lelem.first + i;
if (j >= ep->lelem.nslots)
j -= ep->lelem.nslots;
tnd_args->d[indx++] = ep->lelem.lslots[j];
}
}
tnd_args->num = nargs;
tnd_args->previous = tend;
tend = tnd_args;
signal = invoke(indx, tnd_args->d, rslt, succ_cont);
tend = tnd_args->previous;
free(tnd_args);
return signal;
}
case T_Record: {
/*
* Copy the arguments from the record into an tended array
* of descriptors.
*/
nargs = BlkLoc(dstrct)->record.recdesc->proc.nfields;
tnd_args = (struct tend_desc *)malloc((msize)(sizeof(struct tend_desc)
+ (nargs - 1) * sizeof(struct descrip)));
if (tnd_args == NULL)
RunErr(305, NULL);
tnd_args->d[0] = *callee;
indx = 1;
ep = BlkLoc(dstrct);
for (i = 0; i < nargs; i++)
tnd_args->d[indx++] = ep->record.fields[i];
tnd_args->num = nargs;
tnd_args->previous = tend;
tend = tnd_args;
signal = invoke(indx, tnd_args->d, rslt, succ_cont);
tend = tnd_args->previous;
free(tnd_args);
return signal;
}
default: {
RunErr(126, &dstrct);
}
}
}
#else /* COMPILER */
#ifdef EventMon
#include "::h:opdefs.h"
#endif /* EventMon */
/*
* invoke -- Perform setup for invocation.
*/
invoke(nargs,cargp,n)
dptr *cargp;
int nargs, *n;
{
register struct pf_marker *newpfp;
register dptr newargp;
register word *newsp = sp;
tended struct descrip arg_sv;
#ifdef SCO_XENIX
register dptr p;
#endif /* SCO_XENIX */
register word i;
struct b_proc *proc;
int nparam;
char strbuf[MaxCvtLen];
/*
* Point newargp at Arg0 and dereference it.
*/
newargp = (dptr )(sp - 1) - nargs;
xnargs = nargs;
xargp = newargp;
Deref(newargp[0]);
/*
* See what course the invocation is to take.
*/
if (newargp->dword != D_Proc) {
C_integer tmp;
/*
* Arg0 is not a procedure.
*/
if (cnv:C_integer(newargp[0], tmp)) {
MakeInt(tmp,&newargp[0]);
/*
* Arg0 is an integer, select result.
*/
i = cvpos(IntVal(newargp[0]), (word)nargs);
if (i == CvtFail || i > nargs)
return I_Fail;
#ifdef SCO_XENIX
p = newargp + i;
newargp[0] = *p;
#else /* SCO_XENIX */
newargp[0] = newargp[i];
#endif /* SCO_XENIX */
sp = (word *)newargp + 1;
return I_Continue;
}
else {
struct b_proc *tmp;
/*
* See if Arg0 can be converted to a string that names a procedure
* or operator. If not, generate run-time error 106.
*/
if (!cnv:tmp_string(newargp[0],newargp[0]) ||
((tmp = strprc(newargp, (C_integer)nargs)) == NULL)) {
err_msg(106, newargp);
return I_Fail;
}
BlkLoc(newargp[0]) = (union block *)tmp;
newargp[0].dword = D_Proc;
}
}
/*
* newargp[0] is now a descriptor suitable for invocation. Dereference
* the supplied arguments.
*/
proc = (struct b_proc *)BlkLoc(newargp[0]);
if (proc->nstatic >= 0) /* if negative, don't reference arguments */
for (i = 1; i <= nargs; i++)
Deref(newargp[i]);
/*
* Adjust the argument list to conform to what the routine being invoked
* expects (proc->nparam). If nparam is less than 0, the number of
* arguments is variable. For functions (ndynam = -1) with a
* variable number of arguments, nothing need be done. For Icon procedures
* with a variable number of arguments, arguments beyond abs(nparam) are
* put in a list which becomes the last argument. For fix argument
* routines, if too many arguments were supplied, adjusting the stack
* pointer is all that is necessary. If too few arguments were supplied,
* null descriptors are pushed for each missing argument.
*/
proc = (struct b_proc *)BlkLoc(newargp[0]);
nparam = (int)proc->nparam;
if (nparam >= 0) {
if (nargs > nparam)
newsp -= (nargs - nparam) * 2;
else if (nargs < nparam) {
i = nparam - nargs;
while (i--) {
*++newsp = D_Null;
*++newsp = 0;
}
}
nargs = nparam;
xnargs = nargs;
}
else {
if (proc->ndynam >= 0) { /* this is a procedure */
int lelems;
dptr llargp;
if (nargs < abs(nparam) - 1) {
i = abs(nparam) - 1 - nargs;
while (i--) {
*++newsp = D_Null;
*++newsp = 0;
}
nargs = abs(nparam) - 1;
}
lelems = nargs - (abs(nparam) - 1);
llargp = &newargp[abs(nparam)];
arg_sv = llargp[-1];
Ollist(lelems, &llargp[-1]);
llargp[0] = llargp[-1];
llargp[-1] = arg_sv;
/*
* Reload proc pointer in case Ollist triggered a garbage collection.
*/
proc = (struct b_proc *)BlkLoc(newargp[0]);
newsp = (word *)llargp + 1;
nargs = abs(nparam);
}
}
if (proc->ndynam < 0) {
/*
* A function is being invoked, so nothing else here needs to be done.
*/
if (nargs < abs(nparam) - 1) {
i = abs(nparam) - 1 - nargs;
while (i--) {
*++newsp = D_Null;
*++newsp = 0;
}
nargs = abs(nparam) - 1;
}
*n = nargs;
*cargp = newargp;
sp = newsp;
EVVal((word)Op_Invoke,E_Ecall);
if ((nparam < 0) || (proc->ndynam == -2))
return I_Vararg;
else
return I_Builtin;
}
#ifndef MultiThread
/*
* Make a stab at catching interpreter stack overflow. This does
* nothing for invocation in a co-expression other than &main.
*/
if (BlkLoc(k_current) == BlkLoc(k_main) &&
((char *)sp + PerilDelta) > (char *)stackend)
fatalerr(301, NULL);
#endif /* MultiThread */
/*
* Build the procedure frame.
*/
newpfp = (struct pf_marker *)(newsp + 1);
newpfp->pf_nargs = nargs;
newpfp->pf_argp = argp;
newpfp->pf_pfp = pfp;
newpfp->pf_ilevel = ilevel;
newpfp->pf_scan = NULL;
newpfp->pf_ipc = ipc;
newpfp->pf_gfp = gfp;
newpfp->pf_efp = efp;
#ifdef MultiThread
newpfp->pf_prog = curpstate;
#endif /* MultiThread */
argp = newargp;
pfp = newpfp;
newsp += Vwsizeof(*pfp);
/*
* If tracing is on, use ctrace to generate a message.
*/
if (k_trace) {
k_trace--;
ctrace(&(proc->pname), nargs, &newargp[1]);
}
/*
* Point ipc at the icode entry point of the procedure being invoked.
*/
ipc.opnd = (word *)proc->entryp.icode;
#ifdef MultiThread
/*
* Enter the program state of the procedure being invoked.
*/
ENTERPSTATE(proc->program);
#endif /* MultiThread */
efp = 0;
gfp = 0;
/*
* Push a null descriptor on the stack for each dynamic local.
*/
for (i = proc->ndynam; i > 0; i--) {
*++newsp = D_Null;
*++newsp = 0;
}
sp = newsp;
k_level++;
EVValD(newargp, E_Pcall);
return I_Continue;
}
#endif /* COMPILER */