/* xljump - execution context routines */

#include "xlisp.h"

/* external variables */
extern CONTEXT *xlcontext;
extern NODE *xlvalue;
extern NODE *xlstack,*xlenv,*xlnewenv;
extern int xltrace,xldebug;

/* xlbegin - beginning of an execution context */
xlbegin(cptr,flags,expr)
  CONTEXT *cptr; int flags; NODE *expr;
{
    cptr->c_flags = flags;
    cptr->c_expr = expr;
    cptr->c_xlstack = xlstack;
    cptr->c_xlenv = xlenv;
    cptr->c_xlnewenv = xlnewenv;
    cptr->c_xltrace = xltrace;
    cptr->c_xlcontext = xlcontext;
    xlcontext = cptr;
}

/* xlend - end of an execution context */
xlend(cptr)
  CONTEXT *cptr;
{
    xlcontext = cptr->c_xlcontext;
}

/* xljump - jump to a saved execution context */
xljump(cptr,type,val)
  CONTEXT *cptr; int type; NODE *val;
{
    /* restore the state */
    xlvalue = val;
    xlstack = cptr->c_xlstack;
    xlunbind(cptr->c_xlenv);
    xlnewenv = cptr->c_xlnewenv;
    xltrace = cptr->c_xltrace;

    /* call the handler */
    longjmp(cptr->c_jmpbuf,type);
}

/* xlgo - go to a label */
xlgo(label)
  NODE *label;
{
    CONTEXT *cptr;
    NODE *p;

    /* find a tagbody context */
    for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext)
	if (cptr->c_flags & CF_GO)
	    for (p = cptr->c_expr; consp(p); p = cdr(p))
		if (car(p) == label)
		    xljump(cptr,CF_GO,p);
    xlfail("no target for go");
}

/* xlreturn - return from a block */
xlreturn(val)
  NODE *val;
{
    CONTEXT *cptr;

    /* find a block context */
    for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext)
	if (cptr->c_flags & CF_RETURN)
	    xljump(cptr,CF_RETURN,val);
    xlfail("no target for return");
}

/* xlthrow - throw to a catch */
xlthrow(tag,val)
  NODE *tag,*val;
{
    CONTEXT *cptr;

    /* find a catch context */
    for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext)
	if ((cptr->c_flags & CF_THROW) && cptr->c_expr == tag)
	    xljump(cptr,CF_THROW,val);
    xlfail("no target for throw");
}

/* xlsignal - signal an error */
xlsignal(emsg,arg)
  char *emsg; NODE *arg;
{
    CONTEXT *cptr;

    /* find an error catcher */
    for (cptr = xlcontext; cptr; cptr = cptr->c_xlcontext)
	if (cptr->c_flags & CF_ERROR) {
	    if (cptr->c_expr)
		xlerrprint("error",NULL,emsg,arg);
	    xljump(cptr,CF_ERROR,NULL);
	}
    xlfail("no target for error");
}
