/* eval2.c Copyright (C) 1989-96 Codemist Ltd */ /* * Interpreter (part 2). apply & some special forms */ /* Signature: 589bce9e 17-Jan-1999 */ #include #include #include #include "machine.h" #include "tags.h" #include "cslerror.h" #include "externs.h" #include "entries.h" #ifdef TIMEOUT #include "timeout.h" #endif static Lisp_Object apply_lots(int nargs, n_args *f, Lisp_Object def) /* * Cases with 8 or more args are lifted out here into a subroutine * to make APPLY a bit shorter and because these cases should be * uncommon & not worth optimising much. The code that Microsoft C 6.00A * produced for this was utterly DREADFUL - maybe other C compilers will * make a mess of it too. Anyway I hope it will not be called very often. */ { switch(nargs) { case 9: return (*f)(def, 9, stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 10: return (*f)(def, 10, stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 11: return (*f)(def, 11, stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 12: return (*f)(def, 12, stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 13: return (*f)(def, 13, stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 14: return (*f)(def, 14, stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 15: return (*f)(def, 15, stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 16: return (*f)(def, 16, stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 17: return (*f)(def, 17, stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 18: return (*f)(def, 18, stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 19: return (*f)(def, 19, stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 20: return (*f)(def, 20, stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 21: return (*f)(def, 21, stack[-21], stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 22: return (*f)(def, 22, stack[-22], stack[-21], stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 23: return (*f)(def, 23, stack[-23], stack[-22], stack[-21], stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 24: return (*f)(def, 24, stack[-24], stack[-23], stack[-22], stack[-21], stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); case 25: return (*f)(def, 25, stack[-25], stack[-24], stack[-23], stack[-22], stack[-21], stack[-20], stack[-19], stack[-18], stack[-17], stack[-16], stack[-15], stack[-14], stack[-13], stack[-12], stack[-11], stack[-10], stack[-9], stack[-8], stack[-7], stack[-6], stack[-5], stack[-4], stack[-3], stack[-2], stack[-1]); default: /* * If more than 25 args are going to be passed I will arrange that the * final ones are built into a list - as if the 25th arg was specified * as a "&rest" one. Why? Because passing VERY large numbers of arguments * in C is not a good idea - ANSI C compilers are only obliged to support * up to 31 args, and one some machines this limit seems to really matter. * But Common Lisp can need more args than that. I will ignore the fact that * what I do here is slow. I will HOPE that calls with 25 or more args * are very uncommon. */ { int n = nargs; Lisp_Object w, *tsp = stack, nil = C_nil; #if (ARG_CUT_OFF != 25) if (ARG_CUT_OFF != 25) { fprintf(stderr, "\n+++ ARG_CUT_OFF incorrectly configured\n"); my_exit(EXIT_FAILURE); } #endif w = ncons(tsp[-1]); errexit(); tsp[-1] = w; while (n > ARG_CUT_OFF) { w = cons(tsp[-2], tsp[-1]); errexit(); tsp[-2] = w; tsp[-1] = tsp[0]; tsp--; n--; } return (*f)(def, nargs, tsp[-25], tsp[-24], tsp[-23], tsp[-22], tsp[-21], tsp[-20], tsp[-19], tsp[-18], tsp[-17], tsp[-16], tsp[-15], tsp[-14], tsp[-13], tsp[-12], tsp[-11], tsp[-10], tsp[-9], tsp[-8], tsp[-7], tsp[-6], tsp[-5], tsp[-4], tsp[-3], tsp[-2], tsp[-1]); } } } void push_args(va_list a, int nargs) /* * The unpacking here must match "apply_lots" as above. For up to * (and including) ARG_CUT_OFF (=25) args things are passed normally. * beyond that the first ARG_CUT_OFF-1 args are passed normally, and the * rest are in a list as a final actual arg. Note that this list will * have at least two elements. */ { int i; if (nargs <= ARG_CUT_OFF) { for (i = 0; i ) and any call * to it behaves as if the actual function was called with the environment * passed as a forced-in first argument. */ else if (def == cfunarg) { int i; push(nil); def = qcdr(fn); fn = qcar(def); for (i=0; i . ) */ qenv(fname) = args; /* Sort of notional lambda present */ set_fns(fname, interpreted1, interpreted2, interpretedn); if (qvalue(comp_symbol) != nil && qfn1(compiler_symbol) != undefined1) { push(fname); args = ncons(fname); nil = C_nil; if (!exception_pending()) (qfn1(compiler_symbol))(qenv(compiler_symbol), args); pop(fname); } return onevalue(fname); } } return aerror("defun"); } static Lisp_Object defmacro_fn(Lisp_Object args, Lisp_Object env) { /* * defmacro is eventually expected (required!) to be a macro rather than (maybe * as well as?) a special form. For bootstrap purposes it seems useful to * build it in as a special form. */ Lisp_Object fname, nil = C_nil; CSL_IGNORE(env); if (consp(args)) { fname = qcar(args); args = qcdr(args); if (is_symbol(fname)) { if ((qheader(fname) & (SYM_C_DEF | SYM_CODEPTR)) == (SYM_C_DEF | SYM_CODEPTR)) return onevalue(fname); qheader(fname) |= SYM_MACRO; /* * Note that a name can have a definition as a macro and as a special form, * and in that case the qfn() cell gives the special form and the qenv() * cell the macro definition. Otherwise at present I put 'undefined' * in the qfn() cell, but in due course I will want something else as better * protection against compiled code improperly attempting to call a macro. * Note also that if the symbol was a special form before I do not want * to clear the C_DEF flag, since the special form must be re-instated when * I reload the system. */ if ((qheader(fname) & SYM_SPECIAL_FORM) == 0) { qheader(fname) &= ~SYM_C_DEF; if (qfn1(fname) != undefined1 && qvalue(redef_msg) != nil) { debug_printf("\n+++ "); loop_print_debug(fname); debug_printf(" redefined as a macro\n"); errexit(); } set_fns(fname, undefined1, undefined2, undefinedn); } qenv(fname) = args; /* Sort of notional lambda present */ if (qvalue(comp_symbol) != nil && qfn1(compiler_symbol) != undefined1) { Lisp_Object t1, t2; push(fname); if (!(consp(args) && consp(qcdr(args)) && qcdr(qcdr(args)) == nil && (t1 = qcar(args), t2 = qcdr(qcar(qcdr(args))), equal(t1, t2)))) { errexitn(1); fname = stack[0]; args = ncons(fname); nil = C_nil; if (!exception_pending()) (qfn1(compiler_symbol))(qenv(compiler_symbol), args); } pop(fname); errexit(); } return onevalue(fname); } } return aerror("defmacro"); } static Lisp_Object eval_when_fn(Lisp_Object args, Lisp_Object env) /* * When interpreted, eval-when just looks for the situation EVAL. */ { Lisp_Object situations, nil = C_nil; if (!consp(args)) return onevalue(nil); situations = qcar(args); args = qcdr(args); while (consp(situations)) { if (qcar(situations) == eval_symbol) return progn_fn(args, env); situations = qcdr(situations); } return onevalue(nil); } #ifdef COMMON static Lisp_Object flet_fn(Lisp_Object args, Lisp_Object env) { Lisp_Object my_env, d, nil = C_nil; if (!consp(args)) return onevalue(nil); stackcheck2(0, args, env); my_env = env; d = qcar(args); /* The bunch of definitions */ args = qcdr(args); nil = C_nil; while (consp(d)) { Lisp_Object w = qcar(d); if (consp(w) && consp(qcdr(w))) { Lisp_Object w1; push4(args, d, env, w); w1 = list2star(funarg, my_env, qcdr(w)); pop(w); nil = C_nil; if (!exception_pending()) w1 = cons(w1, qcar(w)); pop(env); nil = C_nil; if (!exception_pending()) env = cons(w1, env); pop2(d, args); errexit(); } d = qcdr(d); } /* * Treat body as (let nil ...) to get (declare ...) recognized. */ return let_fn_1(nil, args, env, BODY_LET); } #endif Lisp_Object function_fn(Lisp_Object args, Lisp_Object env) { /* * For most things this behaves just like (quote xxx), but * (function (lambda (x) y)) gets converted to * (funarg env (x) y). */ Lisp_Object nil = C_nil; if (consp(args) && qcdr(args) == nil) { args = qcar(args); if (consp(args) && qcar(args) == lambda) args = list2star(funarg, env, qcdr(args)); return onevalue(args); } return aerror("function"); } static Lisp_Object go_fn(Lisp_Object args, Lisp_Object env) { Lisp_Object p, tag, nil = C_nil; CSL_IGNORE(env); if (!consp(args)) return aerror("go"); else tag = qcar(args); for(p=env; consp(p); p=qcdr(p)) { Lisp_Object w = qcar(p), z; if (!consp(w)) continue; if (qcar(w) == fixnum_of_int(1) && (z = qcar(qcdr(w)), eql(z, tag))) { p = w; goto tag_found; } } return error(1, err_go_tag, tag); tag_found: exit_tag = p; exit_count = 0; exit_reason = UNWIND_GO; flip_exception(); /* Exceptional exit active */ return nil; } static Lisp_Object if_fn(Lisp_Object args, Lisp_Object env) { Lisp_Object nil = C_nil; Lisp_Object p=nil, tr=nil, fs=nil; if (!consp(args)) return aerror("if"); p = qcar(args); args = qcdr(args); if (!consp(args)) return aerror("if"); tr = qcar(args); args = qcdr(args); if (!consp(args)) fs = nil; else { fs = qcar(args); args = qcdr(args); if (args != nil) return aerror("if"); } stackcheck4(0, p, env, tr, fs); push3(fs, tr, env); p = eval(p, env); pop3(env, tr, fs); errexit(); if (p == nil) return eval(fs, env); /* tail call on result */ else return eval(tr, env); /* ... passing back values */ } #ifdef COMMON static Lisp_Object labels_fn(Lisp_Object args, Lisp_Object env) { Lisp_Object my_env, d, nil = C_nil; if (!consp(args)) return onevalue(nil); stackcheck2(0, args, env); my_env = env; d = qcar(args); /* The bunch of definitions */ while (consp(d)) { Lisp_Object w = qcar(d); if (consp(w) && consp(qcdr(w))) { Lisp_Object w1; push4(args, d, env, w); w1 = list2star(funarg, nil, qcdr(w)); pop(w); nil = C_nil; if (!exception_pending()) w1 = cons(w1, qcar(w)); pop(env); nil = C_nil; if (!exception_pending()) env = cons(w1, env); pop2(d, args); errexit(); } d = qcdr(d); } /* * Now patch up the environments stored with the local defs so as to * permit mutual recursion between them all. */ for (d=env; d!=my_env; d=qcdr(d)) qcar(qcdr(qcar(qcar(d)))) = env; return let_fn_1(nil, qcdr(args), env, BODY_LET); } #endif static Lisp_Object let_fn(Lisp_Object args, Lisp_Object env) { Lisp_Object nil = C_nil; if (!consp(args)) return onevalue(nil); return let_fn_1(qcar(args), qcdr(args), env, BODY_LET); } static Lisp_Object letstar_fn(Lisp_Object args, Lisp_Object env) /* * This will have to look for (declare (special ...)), unless * I am in CSL mode. */ { Lisp_Object nil = C_nil; if (!consp(args)) return onevalue(nil); stackcheck2(0, args, env); push3(qcar(args), qcdr(args), env); nil = C_nil; push5(nil, nil, /* p, q */ env, nil, nil); /* env1, specenv, local_decs */ #ifdef COMMON #define local_decs stack[0] #endif #define specenv stack[-1] #define env1 stack[-2] #define p stack[-3] #define q stack[-4] #define env stack[-5] #define body stack[-6] #define bvl stack[-7] #define Return(v) { popv(8); return (v); } #ifdef COMMON for (;;) { if (exception_pending() || !consp(body)) break; p = macroexpand(qcar(body), env); errexitn(8); body = qcdr(body); if (!consp(p)) { if (stringp(p) && consp(body)) continue; body = cons(p, body); nil = C_nil; break; } if (qcar(p) != declare_symbol) { body = cons(p, body); nil = C_nil; break; } for (p = qcdr(p); consp(p); p = qcdr(p)) { q = qcar(p); if (!consp(q) || qcar(q) != special_symbol) continue; /* here q says (special ...) */ for (q=qcdr(q); consp(q); q = qcdr(q)) { local_decs = cons(qcar(q), local_decs); nil = C_nil; if (exception_pending()) break; } if (exception_pending()) break; } } if (exception_pending()) Return(nil); #endif for (; consp(bvl); bvl=qcdr(bvl)) { Lisp_Object z; q = qcar(bvl); if (consp(q)) { z = qcdr(q); q = qcar(q); if (consp(z)) z = qcar(z); else z = nil; } else z = nil; if (!is_symbol(q)) { error(1, err_bad_bvl, q); goto unwind_special_bindings; } else { #ifdef COMMON Header h = qheader(q); #endif if (z != nil) { z = eval(z, env); nil = C_nil; if (exception_pending()) goto unwind_special_bindings; } #ifndef COMMON p = z; z = acons(q, qvalue(q), specenv); nil = C_nil; if (!exception_pending()) specenv = z; qvalue(q) = p; #else if (h & SYM_SPECIAL_VAR) { p = z; z = acons(q, qvalue(q), specenv); nil = C_nil; if (!exception_pending()) specenv = z; qvalue(q) = p; } else { for (p = local_decs; p!=nil; p = qcdr(p)) { Lisp_Object w; if (q != qcar(p)) continue; qcar(p) = fixnum_of_int(0); w = acons(q, qvalue(q), specenv); nil = C_nil; if (exception_pending()) goto unwind_special_bindings; specenv = w; w = acons(q, work_symbol, env); nil = C_nil; if (exception_pending()) goto unwind_special_bindings; env = w; qvalue(q) = z; goto bound; } q = acons(q, z, env); nil = C_nil; if (exception_pending()) goto unwind_special_bindings; env = q; bound: ; } #endif nil = C_nil; if (exception_pending()) goto unwind_special_bindings; } } #ifdef COMMON while (local_decs!=nil) /* Pervasive special declarations */ { q = qcar(local_decs); local_decs=qcdr(local_decs); if (!is_symbol(q)) continue; q = acons(q, work_symbol, env); nil = C_nil; if (!exception_pending()) env = q; else goto unwind_special_bindings; } #endif if (specenv == nil) { Lisp_Object bodyx = body, envx = env; Return(progn_fn(bodyx, envx)); /* beware Return macro! */ } { body = progn_fn(body, env); nil = C_nil; if (exception_pending()) goto unwind_special_bindings; for (bvl = specenv; bvl != nil; bvl = qcdr(bvl)) { Lisp_Object w = qcar(bvl), v = qcar(w), z = qcdr(w); qvalue(v) = z; } { Lisp_Object bodyx = body; Return(bodyx); } } unwind_special_bindings: flip_exception(); for (bvl = specenv; bvl != nil; bvl = qcdr(bvl)) { Lisp_Object w = qcar(bvl), v = qcar(w), z = qcdr(w); qvalue(v) = z; } flip_exception(); popv(8); return nil; #ifdef COMMON #undef local_decs #endif #undef specenv #undef env1 #undef p #undef q #undef env #undef body #undef bvl #undef Return } setup_type const eval2_setup[] = /* * A jolly curiosity - "function" and "declare" are ALSO set up in * restart.c (because handles are needed on the symbols). I leave * the redundant initialisation here too since I find it clearer that * way. */ { {"and", and_fn, bad_special2, bad_specialn}, {"catch", catch_fn, bad_special2, bad_specialn}, {"cond", cond_fn, bad_special2, bad_specialn}, /* * I am not over-enthusiastic about supporting eval-when in CSL, but * something of that sort seems needed by some bits of code that I have * come across... */ {"eval-when", eval_when_fn, bad_special2, bad_specialn}, {"function", function_fn, bad_special2, bad_specialn}, {"go", go_fn, bad_special2, bad_specialn}, {"if", if_fn, bad_special2, bad_specialn}, {"let*", letstar_fn, bad_special2, bad_specialn}, /* DE and DM are used as low level primitives in the Common Lisp bootstrap */ {"de", defun_fn, bad_special2, bad_specialn}, {"dm", defmacro_fn, bad_special2, bad_specialn}, #ifdef COMMON {"block", block_fn, bad_special2, bad_specialn}, {"compiler-let", compiler_let_fn, bad_special2, bad_specialn}, {"declare", declare_fn, bad_special2, bad_specialn}, {"flet", flet_fn, bad_special2, bad_specialn}, {"labels", labels_fn, bad_special2, bad_specialn}, {"let", let_fn, bad_special2, bad_specialn}, #else {"~block", block_fn, bad_special2, bad_specialn}, {"~let", let_fn, bad_special2, bad_specialn}, #endif {NULL, 0, 0, 0}}; /* end of eval2.c */