@@ -1,1775 +1,1775 @@ -/* eval1.c Copyright (C) 1989-96 Codemist Ltd */ - -/* - * Interpreter (part 1). - */ - -/* Signature: 47f1cfe1 31-May-1997 */ - -#include -#include -#include - -#include "machine.h" -#include "tags.h" -#include "cslerror.h" -#include "externs.h" -#include "entries.h" -#ifdef TIMEOUT -#include "timeout.h" -#endif - - -Lisp_Object nreverse(Lisp_Object a) -{ - Lisp_Object nil = C_nil; - Lisp_Object b = nil; - while (consp(a)) - { Lisp_Object c = a; - a = qcdr(a); - qcdr(c) = b; - b = c; - } - return b; -} - -/* - * Environments are represented as association lists, and have to cope - * with several sorts of things. The items in an environment can be - * in one of the following forms: - * - * (a) (symbol . value) normal lexical variable binding - * (b) (symbol . ~magic~) given symbol is (locally) special - * (c) (0 . tag) (block tag ...) marker - * (d) (1 . (tag ...)) (tagbody ... tag ...) marker - * (e) (2 . ) case (c) or (d) but now invalidated - * (f) (def . symbol) (flet ...) or (macrolet ...) binding, - * where the def is non-atomic. - * - * Format for def in case (f) - * - * (1) (funarg env bvl ...) flet and labels - * (2) (bvl ...) macrolet - * Note that 'funarg is not valid as a bvl - * and indeed in this case bvl is a list - */ - -/* - * In CSL mode flet, macrolet and local declarations are not supported. - */ - -Lisp_Object Ceval(Lisp_Object u, Lisp_Object env) -{ - Lisp_Object nil = C_nil; -#ifdef COMMON - int t; -#ifdef CHECK_STACK - if (check_stack(__FILE__,__LINE__)) return aerror("deep stack in eval"); -#endif -restart: - t = (int)u & TAG_BITS; -/* - * The first case considered is of symbols - lexical and special bindings - * have to be sorted out. - */ - if (t == TAG_SYMBOL) - { - Header h = qheader(u); - if (h & SYM_SPECIAL_VAR) - { Lisp_Object v = qvalue(u); - if (v == unset_var) return error(1, err_unset_var, u); - else return onevalue(v); - } - else - { - while (env != nil) - { Lisp_Object p = qcar(env); - if (qcar(p) == u) - { Lisp_Object v =qcdr(p); -/* - * If a variable is lexically bound to the value work_symbol that means - * that the symbol has been (lexically) declared to be special, so its - * value cell should be inspected. - */ - if (v == work_symbol) - { v = qvalue(u); - if (v == unset_var) return error(1, err_unset_var, u); - } - return onevalue(v); - } - env = qcdr(env); - } -#ifdef ARTHURS_ORIGINAL_INTERPRETATION - return error(1, err_unbound_lexical, u); -#else - { Lisp_Object v = qvalue(u); - if (v == unset_var) return error(1, err_unset_var, u); - else return onevalue(v); - } -#endif - } - } -/* - * Things that are neither symbols nor lists evaluate to themselves, - * e.g. numbers and vectors. - */ - else if (t != TAG_CONS) return onevalue(u); - else -#endif /* COMMON */ - { -/* - * The final case is that of a list (fn ...), and one case that has to - * be checked is if fn is lexically bound. - */ - Lisp_Object fn, args; -#ifdef COMMON -/* - * The test for nil here is because although nil is a symbol the tagging - * structure tested here marks it as a list. - */ - if (u == nil) return onevalue(nil); -#endif - stackcheck2(0, u, env); - fn = qcar(u); - args = qcdr(u); -#ifdef COMMON -/* - * Local function bindings must be looked for first. - */ - { Lisp_Object p; - for (p=env; p!=nil; p=qcdr(p)) - { Lisp_Object w = qcar(p); -/* - * The form ( . sym) is used in an environment to indicate a local - * binding of a function, either as a regular function or as a macro - * (i.e. flet or macrolet). The structure of the list distinguishes - * between these two cases. - */ - if (qcdr(w) == fn && is_cons(w = qcar(w)) && w!=nil) - { - p = qcar(w); - if (p == funarg) /* ordinary function */ - { fn = w; /* (funarg ...) is OK to apply */ - goto ordinary_function; - } -/* - * Here it is a local macro. Observe that the macroexpansion is done - * with respect to an empty environment. Macros that are defined at the same - * time may seem to be mutually recursive but there is a sense in which they - * are not (as well as a sense in which they are) - self and cross references - * only happen AFTER an expansion and can not happen during one. - */ - push2(u, env); - w = cons(lambda, w); - nil = C_nil; - if (!exception_pending()) - p = Lfuncalln(nil, 4, qvalue(macroexpand_hook), - w, u, nil); - pop2(env, u); - nil = C_nil; - if (exception_pending()) - { flip_exception(); - if ((exit_reason & UNWIND_ERROR) != 0) - { err_printf("\nMacroexpanding: "); - loop_print_error(u); - nil = C_nil; - if (exception_pending()) flip_exception(); - } - flip_exception(); - return nil; - } - u = p; - goto restart; - } - } - } -#endif - if (is_symbol(fn)) - { -/* - * Special forms and macros are checked for next. Special forms - * take precedence over macros. - */ - Header h = qheader(fn); - if (h & SYM_SPECIAL_FORM) - { Lisp_Object v; -#ifdef DEBUG - if (qfn1(fn) == NULL) - { term_printf("Illegal special form\n"); - my_exit(EXIT_FAILURE); - } -#endif - v = ((Special_Form *)qfn1(fn))(args, env); - return v; - } - else if (h & SYM_MACRO) - { - push2(u, env); -/* - * the environment passed to macroexpand should only be needed to cope - * with macrolet, I think. Since I use just one datastructure for the - * whole environment I also pass along lexical bindings etc, but I hope that - * they will never be accessed. I do not think that macrolet is important - * enough to call for complication and slow-down in the interpreter this - * way - but then I am not exactly what you would call a Common Lisp Fan! - */ - fn = macroexpand(u, env); - pop2(env, u); - nil = C_nil; - if (exception_pending()) - { flip_exception(); - if ((exit_reason & UNWIND_ERROR) != 0) - { err_printf("\nMacroexpanding: "); - loop_print_error(u); - nil = C_nil; - if (exception_pending()) flip_exception(); - } - flip_exception(); - return nil; - } - return eval(fn, env); - } - } -/* - * Otherwise we have a regular function call. I prepare the args and - * call APPLY. - */ -#ifdef COMMON -ordinary_function: -#endif - { int nargs = 0; - Lisp_Object *save_stack = stack; -/* - * Args are built up on the stack here... - */ - while (consp(args)) - { Lisp_Object w; - push3(fn, args, env); - w = qcar(args); - w = eval(w, env); - pop3(env, args, fn); -/* - * nil having its mark bit set indicates that a special sort of exit - * is in progress. Multiple values can be ignored in this case. - */ - nil = C_nil; - if (exception_pending()) - { flip_exception(); - stack = save_stack; - if ((exit_reason & UNWIND_ERROR) != 0) - { err_printf("\nEvaluating: "); - loop_print_error(qcar(args)); - nil = C_nil; - if (exception_pending()) flip_exception(); - } - flip_exception(); - return nil; - } - push(w); /* args build up on the Lisp stack */ - nargs++; - args = qcdr(args); - } - -/* - * I pass the environment down to apply() because it will be used if the - * function was a simple lambda expression. If the function is a symbol - * or a closure, env will be irrelevant. The arguments are on the Lisp - * stack, and it is the responsibility of apply() to pop them. - */ - return apply(fn, nargs, env, fn); - } - } -} - -#ifdef COMMON -/* - * Keyword arguments are not supported in CSL mode - but &optional - * and &rest and &aux will be (at least for now). Removal of - * support for keywords will save a little space and an even smaller - * amount of time. - */ - -static bool check_no_unwanted_keys(Lisp_Object restarg, Lisp_Object ok_keys) -/* - * verify that there were no unwanted keys in the actual arg list - */ -{ - Lisp_Object nil = C_nil; - bool odd_key_found = NO; - while (restarg!=nil) - { Lisp_Object k = qcar(restarg); - Lisp_Object w; - for (w=ok_keys; w!=nil; w=qcdr(w)) - if (k == qcar(w)) goto is_ok; - odd_key_found = YES; - is_ok: - restarg = qcdr(restarg); - if (restarg==nil) return YES; /* odd length list */ - if (k == allow_key_key && qcar(restarg) != nil) return NO; /* OK */ - restarg = qcdr(restarg); - } - return odd_key_found; -} - -static bool check_keyargs_even(Lisp_Object restarg) -/* - * check that list is even length with alternate items symbols in - * the keyword package. - */ -{ - Lisp_Object nil = C_nil; - while (restarg!=nil) - { Lisp_Object q = qcar(restarg); - if (!is_symbol(q) || qpackage(q) != qvalue(keyword_package)) return YES; - restarg = qcdr(restarg); - if (restarg==nil) return YES; /* Odd length is wrong */ - restarg = qcdr(restarg); - } - return NO; /* OK */ -} - -static Lisp_Object keywordify(Lisp_Object v) -{ -/* - * arg is a non-nil symbol. Should nil be permitted - I think not - * since there seems too much chance of confusion. - */ - Lisp_Object nil, name = get_pname(v); - errexit(); - return Lintern_2(nil, name, qvalue(keyword_package)); -} - -static Lisp_Object key_lookup(Lisp_Object keyname, Lisp_Object args) -{ - Lisp_Object nil = C_nil; - while (args!=nil) - { Lisp_Object next = qcdr(args); - if (next==nil) return nil; - if (qcar(args) == keyname) return next; - else args = qcdr(next); - } - return nil; -} - -#endif - -Lisp_Object apply_lambda(Lisp_Object def, int nargs, - Lisp_Object env, Lisp_Object name) -/* - * Here def is a lambda expression (sans the initial lambda) that is to - * be applied. Much horrible messing about is needed so that I can cope - * with &optional and &rest args (including initialisers and supplied-p - * variables, also &key, &allow-other-keys and &aux). Note the need to find - * any special declarations at the head of the body of the lambda-form. - * Must pop (nargs) items from the stack at exit. - */ -{ -/* - * lambda-lists are parsed using a finite state engine with the - * following states, plus an exit state. - */ -#define STATE_NULL 0 /* at start and during regular args */ -#define STATE_OPT 1 /* after &optional */ -#define STATE_OPT1 2 /* after &optional + at least one var */ -#define STATE_REST 3 /* immediately after &rest */ -#define STATE_REST1 4 /* after &rest vv */ -#ifdef COMMON -#define STATE_KEY 5 /* &key with no &rest */ -#define STATE_ALLOW 6 /* &allow-other-keys */ -#endif -#define STATE_AUX 7 /* &aux */ - - Lisp_Object nil = C_nil; - int opt_rest_state = STATE_NULL; - Lisp_Object *next_arg; - int args_left = nargs; - Lisp_Object w; - if (!consp(def)) - { popv(nargs); - return onevalue(nil); /* Should never happen */ - } - stackcheck3(0, def, env, name); - w = qcar(def); - next_arg = &stack[1-nargs]; /* Points to arg1 */ - push4(w, /* bvl */ - qcdr(def), /* body */ - env, name); -/* - * Here I need to macroexpand the first few items in body and - * look for declare/special items. I will only bother with SPECIAL decls. - * Note that args have been pushed onto the stack first to avoid corruption - * while the interpreter performs macroexpansion. This is the sort of place - * where I feel that Common Lisp has built in causes of inefficiency. - * Well oh well!!! The Common Lisp standardisation group thought so too, - * and have now indicated that DECLARE forms can not be hidden away as - * the result of macros, so some of this is unnecessary. - */ - push5(nil, nil, /* local_decs, ok_keys */ - nil, nil, nil); /* restarg, specenv, val1 */ - push5(nil, nil, /* arg, v1 */ - nil, nil, nil); /* v, p, w */ -/* - * On computers which have unsigned offsets in indexed memory reference - * instructions the negative indexes off the stack suggested here might - * be more expensive than I would like - maybe on such machines the stack - * pointer should be kept offset by 64 bytes (say). Doing so in general - * would be to the disadvantage of machines with auto-index address modes - * that might be used when pushing/popping single items on the stack. - */ -#define w stack[0] -#define p stack[-1] -#define v stack[-2] -#define v1 stack[-3] -#define arg stack[-4] -#define val1 stack[-5] -#define specenv stack[-6] -#define restarg stack[-7] -#ifdef COMMON -#define ok_keys stack[-8] -#define local_decs stack[-9] -#endif -#define name stack[-10] -#define env stack[-11] -#define body stack[-12] -#define bvl stack[-13] -#define arg1 stack[-14] -#define stack_used ((int)(nargs + 14)) - -#ifdef COMMON - for (;;) - { if (!consp(body)) break; - p = macroexpand(qcar(body), env); - nil = C_nil; - if (exception_pending()) - { Lisp_Object qname = name; - popv(stack_used); - return qname; - } - body = qcdr(body); - if (!consp(p)) - { if (stringp(p) && consp(body)) continue; - body = cons(p, body); - break; - } - if (qcar(p) != declare_symbol) - { body = cons(p, body); - break; - } - for (v = qcdr(v); consp(v); v = qcdr(v)) - { v1 = qcar(v); - if (!consp(v1) || qcar(v1) != special_symbol) continue; - /* here v1 says (special ...) */ - for (v1=qcdr(v1); consp(v1); v1 = qcdr(v1)) - { local_decs = cons(qcar(v1), local_decs); - if (exception_pending()) break; - } - } - } - nil = C_nil; - if (exception_pending()) - { Lisp_Object qname = name; - popv(stack_used); - return qname; - } -#endif -/* - * Parse the BVL - */ - for (p = bvl; consp(p); p=qcdr(p)) - { v = qcar(p); - v1 = nil; - arg = nil; - val1 = nil; -/* - * I can break from this switch statement with v a variable to bind - * and arg the value to bind to it, also v1 (if not nil) is a second - * variable to be bound (a supplied-p value) and val1 the value to bind it to. - * If I see &rest or &key the remaining actual args get collected into - * restarg, which takes the place of arg in some respects. - */ - switch (opt_rest_state) - { - - case STATE_NULL: - if (v == opt_key) - { opt_rest_state = STATE_OPT; - continue; - } - -#define BAD1(msg) { error(0, msg); goto unwind_special_bindings; } -#define BAD2(msg, a) { error(1, msg, a); goto unwind_special_bindings; } - -#define collect_rest_arg() \ - while (args_left-- != 0) \ - { if (!exception_pending()) \ - restarg = cons(next_arg[args_left], restarg); \ - nil = C_nil; \ - } - - if (v == rest_key) - { collect_rest_arg(); - if (exception_pending()) goto unwind_special_bindings; - opt_rest_state = STATE_REST; - continue; - } -#ifdef COMMON - if (v == key_key) - { collect_rest_arg(); - if (exception_pending()) goto unwind_special_bindings; - if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); - opt_rest_state = STATE_KEY; - continue; - } - - if (v == aux_key) - { if (args_left != 0) BAD1(err_excess_args); - opt_rest_state = STATE_AUX; - continue; - } - if (v == allow_other_keys) BAD2(err_bad_bvl, v); -#endif - if (args_left == 0) BAD1(err_insufficient_args); - arg = *next_arg++; - args_left--; - v1 = nil; /* no suppliedp mess here, I'm glad to say */ - break; - - case STATE_OPT: - if (v == opt_key - || v == rest_key -#ifdef COMMON - || v == key_key - || v == allow_other_keys - || v == aux_key -#endif - ) BAD2(err_bad_bvl, v); -/* - * Here v may be a simple variable, or a list (var init suppliedp) - */ - opt_rest_state = STATE_OPT1; -process_optional_parameter: - if (args_left != 0) - { arg = *next_arg++; - args_left--; - val1 = lisp_true; - } - else - { arg = nil; - val1 = nil; - } - v1 = nil; - if (!consp(v)) break; /* Simple case */ - { w = qcdr(v); - v = qcar(v); - if (!consp(w)) break; /* (var) */ - if (val1 == nil) /* use the init form */ - { arg = qcar(w); - arg = eval(arg, env); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - } - w = qcdr(w); - if (consp(w)) v1 = qcar(w); /* suppliedp name */ - break; - } - - case STATE_OPT1: - if (v == rest_key) - { collect_rest_arg(); - if (exception_pending()) goto unwind_special_bindings; - opt_rest_state = STATE_REST; - continue; - } -#ifdef COMMON - if (v == key_key) - { collect_rest_arg(); - if (exception_pending()) goto unwind_special_bindings; - if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); - opt_rest_state = STATE_KEY; - continue; - } - if (v == aux_key) - { if (args_left != 0) BAD1(err_excess_args); - opt_rest_state = STATE_AUX; - continue; - } -#endif - if (v == opt_key -#ifdef COMMON - || v == allow_other_keys -#endif - ) BAD2(err_bad_bvl, v); - goto process_optional_parameter; - - case STATE_REST: - if (v == opt_key - || v == rest_key -#ifdef COMMON - || v == key_key - || v == allow_other_keys - || v == aux_key -#endif - ) BAD2(err_bad_bvl, v); - opt_rest_state = STATE_REST1; - arg = restarg; - break; - - case STATE_REST1: -#ifdef COMMON - if (v == key_key) - { if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); - opt_rest_state = STATE_KEY; - continue; - } - if (v == aux_key) - { - opt_rest_state = STATE_AUX; - continue; - } -#endif - BAD2(err_bad_bvl, rest_key); - -#ifdef COMMON - case STATE_KEY: - if (v == allow_other_keys) - { opt_rest_state = STATE_ALLOW; - continue; - } - if (v == aux_key) - { if (check_no_unwanted_keys(restarg, ok_keys)) - BAD2(err_bad_keyargs, restarg); - opt_rest_state = STATE_AUX; - continue; - } - if (v == opt_key || v == rest_key || v == key_key) - BAD2(err_bad_bvl, v); -process_keyword_parameter: -/* - * v needs to expand to ((:kv v) init svar) in effect here. - */ - { Lisp_Object keyname = nil; - w = nil; - if (!consp(v)) - { if (!is_symbol(v)) BAD2(err_bad_bvl, v); - keyname = keywordify(v); - } - else - { w = qcdr(v); - v = qcar(v); - if (!consp(v)) - { if (!is_symbol(v)) BAD2(err_bad_bvl, v); - keyname = keywordify(v); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - } - else - { keyname = qcar(v); - if (!is_symbol(keyname)) BAD2(err_bad_bvl, v); - keyname = keywordify(keyname); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - v = qcdr(v); - if (consp(v)) v = qcar(v); - else BAD2(err_bad_bvl, v); - } - } - ok_keys = cons(keyname, ok_keys); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - arg = key_lookup(qcar(ok_keys), restarg); - if (arg == nil) val1 = nil; - else - { arg = qcar(arg); - val1 = lisp_true; - } - v1 = nil; - if (!consp(w)) break; /* (var) */ - if (val1 == nil) /* use the init form */ - { arg = qcar(w); - arg = eval(arg, env); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - } - w = qcdr(w); - if (consp(w)) v1 = qcar(w); /* suppliedp name */ - break; - } - - case STATE_ALLOW: - if (v == aux_key) - { opt_rest_state = STATE_AUX; - continue; - } - if (v == opt_key || v == rest_key || v == key_key || - v == allow_other_keys) BAD2(err_bad_bvl, v); - goto process_keyword_parameter; - - case STATE_AUX: - if (v == opt_key || v == rest_key || - v == key_key || v == allow_other_keys || - v == aux_key) BAD2(err_bad_bvl, v); - if (consp(v)) - { w = qcdr(v); - v = qcar(v); - if (consp(w)) - { arg = qcar(w); - arg = eval(arg, env); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - } - } - else arg = nil; - v1 = nil; - break; -#endif - } -/* - * This is where I get when I have one or two vars to bind. - */ - -#ifndef COMMON -/* - * CSL mode does not have to mess about looking for local special bindings - * and so is MUCH shorter and neater. I always shallow bind - */ -#define instate_binding(var, val, local_decs1, lab) \ - { if (!is_symbol(var)) BAD2(err_bad_bvl, var); \ - w = acons(var, qvalue(var), specenv); \ - nil = C_nil; \ - if (exception_pending()) goto unwind_special_bindings; \ - specenv = w; \ - qvalue(var) = val; \ - } -#else -#define instate_binding(var, val, local_decs1, lab) \ - { Header h; \ - if (!is_symbol(var)) BAD2(err_bad_bvl, var); \ - h = qheader(var); \ - if ((h & SYM_SPECIAL_VAR) != 0) \ - { w = acons(var, qvalue(var), specenv); \ - nil = C_nil; \ - if (exception_pending()) goto unwind_special_bindings; \ - specenv = w; \ - qvalue(var) = val; \ - } \ - else \ - { for (w = local_decs1; w!=nil; w = qcdr(w)) \ - { if (qcar(w) == var) \ - { qcar(w) = fixnum_of_int(0);/* decl is used up */\ - w = acons(var, work_symbol, env); \ - nil = C_nil; \ - if (exception_pending()) \ - goto unwind_special_bindings; \ - env = w; \ - w = acons(var, qvalue(var), specenv); \ - nil = C_nil; \ - if (exception_pending()) \ - goto unwind_special_bindings; \ - specenv = w; \ - qvalue(var) = val; \ - goto lab; \ - } \ - } \ - w = acons(var, val, env); \ - nil = C_nil; \ - if (exception_pending()) goto unwind_special_bindings; \ - env = w; \ - lab: ; \ - } \ - } -#endif - -#ifdef COMMON -/* - * Must check about local special declarations here... - */ -#endif - instate_binding(v, arg, local_decs, label1); - if (v1 != nil) instate_binding(v1, val1, local_decs, label2); - - } /* End of for loop that scans BVL */ - -#ifdef COMMON -/* - * As well as local special declarations that have applied to bindings here - * there can be some that apply just to variable references within the body. - */ - while (local_decs!=nil) - { Lisp_Object q = qcar(local_decs); - local_decs=qcdr(local_decs); - if (!is_symbol(q)) continue; - w = acons(q, work_symbol, env); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - env = w; - } -#endif - - switch (opt_rest_state) - { -case STATE_NULL: -case STATE_OPT1: /* Ensure there had not been too many args */ - if (args_left != 0) BAD1(err_excess_args); - break; - -case STATE_OPT: /* error if bvl finishes here */ -case STATE_REST: - BAD2(err_bad_bvl, opt_rest_state == STATE_OPT ? opt_key : rest_key); - -#ifdef COMMON -case STATE_KEY: /* ensure only valid keys were given */ - if (check_no_unwanted_keys(restarg, ok_keys)) - BAD2(err_bad_keyargs, restarg); - break; -#endif - -default: -/* in the following cases all is known to be well -case STATE_REST1: -case STATE_ALLOW: -case STATE_AUX: -*/ - break; - } - -/* - * Now all the argument bindings have been performed - it remains to - * process the body of the lambda-expression. - */ - if (specenv == nil) - { Lisp_Object bodyx = body, envx = env; - Lisp_Object qname = name; - popv(stack_used); - push(qname); - bodyx = progn_fn(bodyx, envx); - pop(qname); - nil = C_nil; - if (exception_pending()) return qname; - return bodyx; - } - { body = progn_fn(body, env); - nil = C_nil; - if (exception_pending()) goto unwind_special_bindings; - while (specenv != nil) - { - Lisp_Object bv = qcar(specenv); - qvalue(qcar(bv)) = qcdr(bv); - specenv = qcdr(specenv); - } - { Lisp_Object bodyx = body; - popv(stack_used); -/* - * note that exit_count has not been disturbed since I called progn_fn, - * so the numbert of values that will be returned remains correctly - * established (in Common Lisp mode where it is needed. - */ - return bodyx; - } - } - -unwind_special_bindings: -/* - * I gete here ONLY if nil has its mark bit set, which means that (for - * one reason or another) I am having to unwind the stack, restoring - * special bindings as I go. - */ - nil = C_nil; - flip_exception(); - while (specenv != nil) - { Lisp_Object bv = qcar(specenv); - qvalue(qcar(bv)) = qcdr(bv); - specenv = qcdr(specenv); - } - flip_exception(); - { Lisp_Object qname = name; - popv(stack_used); - return qname; - } -#undef w -#undef p -#undef v -#undef v1 -#undef arg -#undef val1 -#undef specenv -#undef restarg -#undef ok_keys -#undef local_decs -#undef name -#undef env -#undef body -#undef bvl -#undef stack_used -} - -Lisp_Object Leval(Lisp_Object nil, Lisp_Object a) -{ - return eval(a, nil); /* Multiple values may be returned */ -} - -Lisp_Object Levlis(Lisp_Object nil, Lisp_Object a) -{ - Lisp_Object r; - stackcheck1(0, a); - r = nil; - while (consp(a)) - { push2(qcdr(a), r); - a = qcar(a); - a = eval(a, nil); - errexitn(2); - pop(r); - r = cons(a, r); - pop(a); - errexit(); - } - return onevalue(nreverse(r)); -} - -Lisp_Object MS_CDECL Lapply_n(Lisp_Object nil, int nargs, ...) -{ - va_list a; - int i; - Lisp_Object *stack_save = stack, last, fn; - if (nargs == 0) return aerror("apply"); - if (nargs > 1) - { va_start(a, nargs); - fn = va_arg(a, Lisp_Object); - push_args_1(a, nargs); - pop(last); - i = nargs-2; - while (consp(last)) - { push(qcar(last)); - last = qcdr(last); - i++; - } - } - else i = 0; - stackcheck1(stack-stack_save, fn); - return apply(fn, i, nil, fn); -} - -Lisp_Object Lapply_1(Lisp_Object nil, Lisp_Object fn) -{ - return Lapply_n(nil, 1, fn); -} - -Lisp_Object Lapply_2(Lisp_Object nil, Lisp_Object fn, Lisp_Object a1) -{ - return Lapply_n(nil, 2, fn, a1); -} - -Lisp_Object Lapply0(Lisp_Object nil, Lisp_Object fn) -{ - if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 0); - stackcheck1(0, fn); - return apply(fn, 0, C_nil, fn); -} - -Lisp_Object Lapply1(Lisp_Object nil, Lisp_Object fn, Lisp_Object a) -{ - if (is_symbol(fn)) return (*qfn1(fn))(qenv(fn), a); - push(a); - stackcheck1(1, fn); - return apply(fn, 1, C_nil, fn); -} - -Lisp_Object MS_CDECL Lapply2(Lisp_Object nil, int nargs, ...) -{ - va_list aa; - Lisp_Object fn, a, b; - argcheck(nargs, 3, "apply2"); - va_start(aa, nargs); - fn = va_arg(aa, Lisp_Object); - a = va_arg(aa, Lisp_Object); - b = va_arg(aa, Lisp_Object); - va_end(aa); - if (is_symbol(fn)) return (*qfn2(fn))(qenv(fn), a, b); - push2(a, b); - stackcheck1(2, fn); - return apply(fn, 2, C_nil, fn); -} - -Lisp_Object MS_CDECL Lapply3(Lisp_Object nil, int nargs, ...) -{ - va_list aa; - Lisp_Object fn, a, b, c; - argcheck(nargs, 4, "apply3"); - va_start(aa, nargs); - fn = va_arg(aa, Lisp_Object); - a = va_arg(aa, Lisp_Object); - b = va_arg(aa, Lisp_Object); - c = va_arg(aa, Lisp_Object); - va_end(aa); - if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 3, a, b, c); - push3(a, b, c); - stackcheck1(3, fn); - return apply(fn, 3, C_nil, fn); -} - -Lisp_Object Lfuncall1(Lisp_Object nil, Lisp_Object fn) -{ - if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 0); - stackcheck1(0, fn); - return apply(fn, 0, nil, fn); -} - -Lisp_Object Lfuncall2(Lisp_Object nil, Lisp_Object fn, Lisp_Object a1) -{ - if (is_symbol(fn)) return (*qfn1(fn))(qenv(fn), a1); - push(a1); - stackcheck1(1, fn); - return apply(fn, 1, nil, fn); -} - -static Lisp_Object MS_CDECL Lfuncalln_sub(Lisp_Object nil, int nargs, va_list a) -{ - Lisp_Object *stack_save = stack, fn; - fn = va_arg(a, Lisp_Object); - push_args_1(a, nargs); - stackcheck1(stack-stack_save, fn); - return apply(fn, nargs-1, nil, fn); -} - -Lisp_Object MS_CDECL Lfuncalln(Lisp_Object nil, int nargs, ...) -{ - va_list a; - Lisp_Object fn, a1, a2, a3, a4; - va_start(a, nargs); - switch (nargs) - { -case 0: return aerror("funcall"); -case 1: /* cases 1 and 2 should go through Lfuncall1,2 not here */ -case 2: return aerror("funcall wrong call"); -case 3: fn = va_arg(a, Lisp_Object); - a1 = va_arg(a, Lisp_Object); - a2 = va_arg(a, Lisp_Object); - if (is_symbol(fn)) return (*qfn2(fn))(qenv(fn), a1, a2); - push2(a1, a2); - return apply(fn, 2, nil, fn); -case 4: fn = va_arg(a, Lisp_Object); - a1 = va_arg(a, Lisp_Object); - a2 = va_arg(a, Lisp_Object); - a3 = va_arg(a, Lisp_Object); - if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 3, a1, a2, a3); - push3(a1, a2, a3); - return apply(fn, 3, nil, fn); -case 5: fn = va_arg(a, Lisp_Object); - a1 = va_arg(a, Lisp_Object); - a2 = va_arg(a, Lisp_Object); - a3 = va_arg(a, Lisp_Object); - a4 = va_arg(a, Lisp_Object); - if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 4, a1, a2, a3, a4); - push4(a1, a2, a3, a4); - return apply(fn, 4, nil, fn); -default: - return Lfuncalln_sub(nil, nargs, a); - } -} - -#ifdef COMMON - -Lisp_Object MS_CDECL Lvalues(Lisp_Object nil, int nargs, ...) -{ - va_list a; - Lisp_Object *p = &mv_2, w; - int i; -/* - * Because multiple-values get passed back in static storage there is - * a fixed upper limit to how many I can handle - truncate here to allow - * for that. - */ - if (nargs > 50) nargs = 50; - if (nargs == 0) return nvalues(nil, 0); - va_start(a, nargs); - push_args(a, nargs); - for (i=1; i nil */ - stackcheck2(0, args, env); - push2(args, env); - fn = qcar(args); - fn = eval(fn, env); - pop2(env, args); - errexit(); - args = qcdr(args); - while (consp(args)) - { Lisp_Object r1; - push2(args, env); - r1 = qcar(args); - r1 = eval(r1, env); - nil = C_nil; - if (exception_pending()) - { stack = stack_save; - return nil; - } -/* - * It is critical here that push does not check for stack overflow and - * thus can not call the garbage collector, or otherwise lead to calculation - * that could possibly clobber the multiple results that I am working with - * here. - */ - pop2(env, args); - push(r1); - i++; - for (j = 2; j<=exit_count; j++) - { push((&work_0)[j]); - i++; - } - args = qcdr(args); - } - stackcheck2(stack-stack_save, fn, env); - return apply(fn, i, env, fn); -} - -#endif - -Lisp_Object interpreted1(Lisp_Object def, Lisp_Object a1) -{ - Lisp_Object nil = C_nil; - push(a1); - stackcheck1(1, def); - return apply_lambda(def, 1, nil, def); -} - -Lisp_Object interpreted2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) -{ - Lisp_Object nil = C_nil; - push2(a1, a2); - stackcheck1(2, def); - return apply_lambda(def, 2, nil, def); -} - -Lisp_Object MS_CDECL interpretedn(Lisp_Object def, int nargs, ...) -{ -/* - * The messing about here is to get the (unknown number of) args - * into a nice neat vector so that they can be indexed into. If I knew - * that the args were in consecutive locations on the stack I could - * probably save a copying operation. - */ - Lisp_Object nil = C_nil; - Lisp_Object *stack_save = stack; - va_list a; - if (nargs != 0) - { va_start(a, nargs); - push_args(a, nargs); - } - stackcheck1(stack-stack_save, def); - return apply_lambda(def, nargs, nil, def); -} - -Lisp_Object funarged1(Lisp_Object def, Lisp_Object a1) -{ - Lisp_Object nil = C_nil; - push(a1); - stackcheck1(1, def); - return apply_lambda(qcdr(def), 1, qcar(def), qcdr(def)); -} - -Lisp_Object funarged2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) -{ - Lisp_Object nil = C_nil; - push2(a1, a2); - stackcheck1(2, def); - return apply_lambda(qcdr(def), 2, qcar(def), qcdr(def)); -} - -Lisp_Object MS_CDECL funargedn(Lisp_Object def, int nargs, ...) -{ - Lisp_Object nil = C_nil; - Lisp_Object *stack_save = stack; - va_list a; - if (nargs != 0) - { va_start(a, nargs); - push_args(a, nargs); - } - stackcheck1(stack-stack_save, def); - return apply_lambda(qcdr(def), nargs, qcar(def), qcdr(def)); -} - -/* - * Now some execution-doubling versions... - */ - -Lisp_Object double_interpreted1(Lisp_Object def, Lisp_Object a1) -{ - Lisp_Object nil = C_nil; - push(a1); - stackcheck1(1, def); - return apply_lambda(def, 1, nil, def); -} - -Lisp_Object double_interpreted2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) -{ - Lisp_Object nil = C_nil; - push2(a1, a2); - stackcheck1(2, def); - return apply_lambda(def, 2, nil, def); -} - -Lisp_Object MS_CDECL double_interpretedn(Lisp_Object def, int nargs, ...) -{ -/* - * The messing about here is to get the (unknown number of) args - * into a nice neat vector so that they can be indexed into. If I knew - * that the args were in consecutive locations on the stack I could - * probably save a copying operation. - */ - Lisp_Object nil = C_nil; - Lisp_Object *stack_save = stack; - va_list a; - if (nargs != 0) - { va_start(a, nargs); - push_args(a, nargs); - } - stackcheck1(stack-stack_save, def); - return apply_lambda(def, nargs, nil, def); -} - -Lisp_Object double_funarged1(Lisp_Object def, Lisp_Object a1) -{ - Lisp_Object nil = C_nil; - push(a1); - stackcheck1(1, def); - return apply_lambda(qcdr(def), 1, qcar(def), qcdr(def)); -} - -Lisp_Object double_funarged2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) -{ - Lisp_Object nil = C_nil; - push2(a1, a2); - stackcheck1(2, def); - return apply_lambda(qcdr(def), 2, qcar(def), qcdr(def)); -} - -Lisp_Object MS_CDECL double_funargedn(Lisp_Object def, int nargs, ...) -{ - Lisp_Object nil = C_nil; - Lisp_Object *stack_save = stack; - va_list a; - if (nargs != 0) - { va_start(a, nargs); - push_args(a, nargs); - } - stackcheck1(stack-stack_save, def); - return apply_lambda(qcdr(def), nargs, qcar(def), qcdr(def)); -} - -int trace_depth = 0; - -static void trace_entering(char *s) -{ - int i; - for (i=0; i0)", env); - return (*qfnn(env))(qenv(env), 0); -} - -Lisp_Object f1_as_0(Lisp_Object env, Lisp_Object a) -{ - return (*qfnn(env))(qenv(env), 0); -} - -Lisp_Object f2_as_0(Lisp_Object env, Lisp_Object a, Lisp_Object b) -{ - return (*qfnn(env))(qenv(env), 0); -} - -Lisp_Object MS_CDECL f3_as_0(Lisp_Object env, int nargs, ...) -{ - if (nargs != 3) return aerror1("wrong number of args (3->0)", env); - return (*qfnn(env))(qenv(env), 0); -} - -Lisp_Object f1_as_1(Lisp_Object env, Lisp_Object a) -{ - return (*qfn1(env))(qenv(env), a); -} - -Lisp_Object f2_as_1(Lisp_Object env, Lisp_Object a, Lisp_Object b) -{ - return (*qfn1(env))(qenv(env), a); -} - -Lisp_Object MS_CDECL f3_as_1(Lisp_Object env, int nargs, ...) -{ - va_list a; - Lisp_Object a1; - if (nargs != 3) return aerror1("wrong number of args (3->1)", env); - va_start(a, nargs); - a1 = va_arg(a, Lisp_Object); - va_end(a); - return (*qfn1(env))(qenv(env), a1); -} - -Lisp_Object f2_as_2(Lisp_Object env, Lisp_Object a, Lisp_Object b) -{ - return (*qfn2(env))(qenv(env), a, b); -} - -Lisp_Object MS_CDECL f3_as_2(Lisp_Object env, int nargs, ...) -{ - va_list a; - Lisp_Object a1, a2; - if (nargs != 3) return aerror1("wrong number of args (3->2)", env); - va_start(a, nargs); - a1 = va_arg(a, Lisp_Object); - a2 = va_arg(a, Lisp_Object); - va_end(a); - return (*qfn2(env))(qenv(env), a1, a2); -} - -Lisp_Object MS_CDECL f3_as_3(Lisp_Object env, int nargs, ...) -{ - va_list a; - Lisp_Object a1, a2, a3; - if (nargs != 3) return aerror1("wrong number of args (3->3)", env); - va_start(a, nargs); - a1 = va_arg(a, Lisp_Object); - a2 = va_arg(a, Lisp_Object); - a3 = va_arg(a, Lisp_Object); - va_end(a); - return (*qfnn(env))(qenv(env), 3, a1, a2, a3); -} - -setup_type const eval1_setup[] = -{ - {"bytecounts", wrong_no_na, wrong_no_nb, bytecounts}, - {"apply", Lapply_1, Lapply_2, Lapply_n}, - {"apply0", Lapply0, too_many_1, wrong_no_1}, - {"apply1", too_few_2, Lapply1, wrong_no_2}, - {"apply2", wrong_no_na, wrong_no_nb, Lapply2}, - {"apply3", wrong_no_na, wrong_no_nb, Lapply3}, - {"evlis", Levlis, too_many_1, wrong_no_1}, - {"funcall", Lfuncall1, Lfuncall2, Lfuncalln}, - {"funcall*", Lfuncall1, Lfuncall2, Lfuncalln}, -#ifdef COMMON - {"values", Lvalues_1, Lvalues_2, Lvalues}, - {"macroexpand", Lmacroexpand, Lmacroexpand_2, wrong_no_1}, - {"macroexpand-1", Lmacroexpand_1, Lmacroexpand_1_2, wrong_no_1}, -#else - {"macroexpand", Lmacroexpand, too_many_1, wrong_no_1}, - {"macroexpand-1", Lmacroexpand_1, too_many_1, wrong_no_1}, -#endif - {NULL, 0, 0, 0} -}; - -/* end of eval1.c */ - +/* eval1.c Copyright (C) 1989-96 Codemist Ltd */ + +/* + * Interpreter (part 1). + */ + +/* Signature: 47f1cfe1 31-May-1997 */ + +#include +#include +#include + +#include "machine.h" +#include "tags.h" +#include "cslerror.h" +#include "externs.h" +#include "entries.h" +#ifdef TIMEOUT +#include "timeout.h" +#endif + + +Lisp_Object nreverse(Lisp_Object a) +{ + Lisp_Object nil = C_nil; + Lisp_Object b = nil; + while (consp(a)) + { Lisp_Object c = a; + a = qcdr(a); + qcdr(c) = b; + b = c; + } + return b; +} + +/* + * Environments are represented as association lists, and have to cope + * with several sorts of things. The items in an environment can be + * in one of the following forms: + * + * (a) (symbol . value) normal lexical variable binding + * (b) (symbol . ~magic~) given symbol is (locally) special + * (c) (0 . tag) (block tag ...) marker + * (d) (1 . (tag ...)) (tagbody ... tag ...) marker + * (e) (2 . ) case (c) or (d) but now invalidated + * (f) (def . symbol) (flet ...) or (macrolet ...) binding, + * where the def is non-atomic. + * + * Format for def in case (f) + * + * (1) (funarg env bvl ...) flet and labels + * (2) (bvl ...) macrolet + * Note that 'funarg is not valid as a bvl + * and indeed in this case bvl is a list + */ + +/* + * In CSL mode flet, macrolet and local declarations are not supported. + */ + +Lisp_Object Ceval(Lisp_Object u, Lisp_Object env) +{ + Lisp_Object nil = C_nil; +#ifdef COMMON + int t; +#ifdef CHECK_STACK + if (check_stack(__FILE__,__LINE__)) return aerror("deep stack in eval"); +#endif +restart: + t = (int)u & TAG_BITS; +/* + * The first case considered is of symbols - lexical and special bindings + * have to be sorted out. + */ + if (t == TAG_SYMBOL) + { + Header h = qheader(u); + if (h & SYM_SPECIAL_VAR) + { Lisp_Object v = qvalue(u); + if (v == unset_var) return error(1, err_unset_var, u); + else return onevalue(v); + } + else + { + while (env != nil) + { Lisp_Object p = qcar(env); + if (qcar(p) == u) + { Lisp_Object v =qcdr(p); +/* + * If a variable is lexically bound to the value work_symbol that means + * that the symbol has been (lexically) declared to be special, so its + * value cell should be inspected. + */ + if (v == work_symbol) + { v = qvalue(u); + if (v == unset_var) return error(1, err_unset_var, u); + } + return onevalue(v); + } + env = qcdr(env); + } +#ifdef ARTHURS_ORIGINAL_INTERPRETATION + return error(1, err_unbound_lexical, u); +#else + { Lisp_Object v = qvalue(u); + if (v == unset_var) return error(1, err_unset_var, u); + else return onevalue(v); + } +#endif + } + } +/* + * Things that are neither symbols nor lists evaluate to themselves, + * e.g. numbers and vectors. + */ + else if (t != TAG_CONS) return onevalue(u); + else +#endif /* COMMON */ + { +/* + * The final case is that of a list (fn ...), and one case that has to + * be checked is if fn is lexically bound. + */ + Lisp_Object fn, args; +#ifdef COMMON +/* + * The test for nil here is because although nil is a symbol the tagging + * structure tested here marks it as a list. + */ + if (u == nil) return onevalue(nil); +#endif + stackcheck2(0, u, env); + fn = qcar(u); + args = qcdr(u); +#ifdef COMMON +/* + * Local function bindings must be looked for first. + */ + { Lisp_Object p; + for (p=env; p!=nil; p=qcdr(p)) + { Lisp_Object w = qcar(p); +/* + * The form ( . sym) is used in an environment to indicate a local + * binding of a function, either as a regular function or as a macro + * (i.e. flet or macrolet). The structure of the list distinguishes + * between these two cases. + */ + if (qcdr(w) == fn && is_cons(w = qcar(w)) && w!=nil) + { + p = qcar(w); + if (p == funarg) /* ordinary function */ + { fn = w; /* (funarg ...) is OK to apply */ + goto ordinary_function; + } +/* + * Here it is a local macro. Observe that the macroexpansion is done + * with respect to an empty environment. Macros that are defined at the same + * time may seem to be mutually recursive but there is a sense in which they + * are not (as well as a sense in which they are) - self and cross references + * only happen AFTER an expansion and can not happen during one. + */ + push2(u, env); + w = cons(lambda, w); + nil = C_nil; + if (!exception_pending()) + p = Lfuncalln(nil, 4, qvalue(macroexpand_hook), + w, u, nil); + pop2(env, u); + nil = C_nil; + if (exception_pending()) + { flip_exception(); + if ((exit_reason & UNWIND_ERROR) != 0) + { err_printf("\nMacroexpanding: "); + loop_print_error(u); + nil = C_nil; + if (exception_pending()) flip_exception(); + } + flip_exception(); + return nil; + } + u = p; + goto restart; + } + } + } +#endif + if (is_symbol(fn)) + { +/* + * Special forms and macros are checked for next. Special forms + * take precedence over macros. + */ + Header h = qheader(fn); + if (h & SYM_SPECIAL_FORM) + { Lisp_Object v; +#ifdef DEBUG + if (qfn1(fn) == NULL) + { term_printf("Illegal special form\n"); + my_exit(EXIT_FAILURE); + } +#endif + v = ((Special_Form *)qfn1(fn))(args, env); + return v; + } + else if (h & SYM_MACRO) + { + push2(u, env); +/* + * the environment passed to macroexpand should only be needed to cope + * with macrolet, I think. Since I use just one datastructure for the + * whole environment I also pass along lexical bindings etc, but I hope that + * they will never be accessed. I do not think that macrolet is important + * enough to call for complication and slow-down in the interpreter this + * way - but then I am not exactly what you would call a Common Lisp Fan! + */ + fn = macroexpand(u, env); + pop2(env, u); + nil = C_nil; + if (exception_pending()) + { flip_exception(); + if ((exit_reason & UNWIND_ERROR) != 0) + { err_printf("\nMacroexpanding: "); + loop_print_error(u); + nil = C_nil; + if (exception_pending()) flip_exception(); + } + flip_exception(); + return nil; + } + return eval(fn, env); + } + } +/* + * Otherwise we have a regular function call. I prepare the args and + * call APPLY. + */ +#ifdef COMMON +ordinary_function: +#endif + { int nargs = 0; + Lisp_Object *save_stack = stack; +/* + * Args are built up on the stack here... + */ + while (consp(args)) + { Lisp_Object w; + push3(fn, args, env); + w = qcar(args); + w = eval(w, env); + pop3(env, args, fn); +/* + * nil having its mark bit set indicates that a special sort of exit + * is in progress. Multiple values can be ignored in this case. + */ + nil = C_nil; + if (exception_pending()) + { flip_exception(); + stack = save_stack; + if ((exit_reason & UNWIND_ERROR) != 0) + { err_printf("\nEvaluating: "); + loop_print_error(qcar(args)); + nil = C_nil; + if (exception_pending()) flip_exception(); + } + flip_exception(); + return nil; + } + push(w); /* args build up on the Lisp stack */ + nargs++; + args = qcdr(args); + } + +/* + * I pass the environment down to apply() because it will be used if the + * function was a simple lambda expression. If the function is a symbol + * or a closure, env will be irrelevant. The arguments are on the Lisp + * stack, and it is the responsibility of apply() to pop them. + */ + return apply(fn, nargs, env, fn); + } + } +} + +#ifdef COMMON +/* + * Keyword arguments are not supported in CSL mode - but &optional + * and &rest and &aux will be (at least for now). Removal of + * support for keywords will save a little space and an even smaller + * amount of time. + */ + +static bool check_no_unwanted_keys(Lisp_Object restarg, Lisp_Object ok_keys) +/* + * verify that there were no unwanted keys in the actual arg list + */ +{ + Lisp_Object nil = C_nil; + bool odd_key_found = NO; + while (restarg!=nil) + { Lisp_Object k = qcar(restarg); + Lisp_Object w; + for (w=ok_keys; w!=nil; w=qcdr(w)) + if (k == qcar(w)) goto is_ok; + odd_key_found = YES; + is_ok: + restarg = qcdr(restarg); + if (restarg==nil) return YES; /* odd length list */ + if (k == allow_key_key && qcar(restarg) != nil) return NO; /* OK */ + restarg = qcdr(restarg); + } + return odd_key_found; +} + +static bool check_keyargs_even(Lisp_Object restarg) +/* + * check that list is even length with alternate items symbols in + * the keyword package. + */ +{ + Lisp_Object nil = C_nil; + while (restarg!=nil) + { Lisp_Object q = qcar(restarg); + if (!is_symbol(q) || qpackage(q) != qvalue(keyword_package)) return YES; + restarg = qcdr(restarg); + if (restarg==nil) return YES; /* Odd length is wrong */ + restarg = qcdr(restarg); + } + return NO; /* OK */ +} + +static Lisp_Object keywordify(Lisp_Object v) +{ +/* + * arg is a non-nil symbol. Should nil be permitted - I think not + * since there seems too much chance of confusion. + */ + Lisp_Object nil, name = get_pname(v); + errexit(); + return Lintern_2(nil, name, qvalue(keyword_package)); +} + +static Lisp_Object key_lookup(Lisp_Object keyname, Lisp_Object args) +{ + Lisp_Object nil = C_nil; + while (args!=nil) + { Lisp_Object next = qcdr(args); + if (next==nil) return nil; + if (qcar(args) == keyname) return next; + else args = qcdr(next); + } + return nil; +} + +#endif + +Lisp_Object apply_lambda(Lisp_Object def, int nargs, + Lisp_Object env, Lisp_Object name) +/* + * Here def is a lambda expression (sans the initial lambda) that is to + * be applied. Much horrible messing about is needed so that I can cope + * with &optional and &rest args (including initialisers and supplied-p + * variables, also &key, &allow-other-keys and &aux). Note the need to find + * any special declarations at the head of the body of the lambda-form. + * Must pop (nargs) items from the stack at exit. + */ +{ +/* + * lambda-lists are parsed using a finite state engine with the + * following states, plus an exit state. + */ +#define STATE_NULL 0 /* at start and during regular args */ +#define STATE_OPT 1 /* after &optional */ +#define STATE_OPT1 2 /* after &optional + at least one var */ +#define STATE_REST 3 /* immediately after &rest */ +#define STATE_REST1 4 /* after &rest vv */ +#ifdef COMMON +#define STATE_KEY 5 /* &key with no &rest */ +#define STATE_ALLOW 6 /* &allow-other-keys */ +#endif +#define STATE_AUX 7 /* &aux */ + + Lisp_Object nil = C_nil; + int opt_rest_state = STATE_NULL; + Lisp_Object *next_arg; + int args_left = nargs; + Lisp_Object w; + if (!consp(def)) + { popv(nargs); + return onevalue(nil); /* Should never happen */ + } + stackcheck3(0, def, env, name); + w = qcar(def); + next_arg = &stack[1-nargs]; /* Points to arg1 */ + push4(w, /* bvl */ + qcdr(def), /* body */ + env, name); +/* + * Here I need to macroexpand the first few items in body and + * look for declare/special items. I will only bother with SPECIAL decls. + * Note that args have been pushed onto the stack first to avoid corruption + * while the interpreter performs macroexpansion. This is the sort of place + * where I feel that Common Lisp has built in causes of inefficiency. + * Well oh well!!! The Common Lisp standardisation group thought so too, + * and have now indicated that DECLARE forms can not be hidden away as + * the result of macros, so some of this is unnecessary. + */ + push5(nil, nil, /* local_decs, ok_keys */ + nil, nil, nil); /* restarg, specenv, val1 */ + push5(nil, nil, /* arg, v1 */ + nil, nil, nil); /* v, p, w */ +/* + * On computers which have unsigned offsets in indexed memory reference + * instructions the negative indexes off the stack suggested here might + * be more expensive than I would like - maybe on such machines the stack + * pointer should be kept offset by 64 bytes (say). Doing so in general + * would be to the disadvantage of machines with auto-index address modes + * that might be used when pushing/popping single items on the stack. + */ +#define w stack[0] +#define p stack[-1] +#define v stack[-2] +#define v1 stack[-3] +#define arg stack[-4] +#define val1 stack[-5] +#define specenv stack[-6] +#define restarg stack[-7] +#ifdef COMMON +#define ok_keys stack[-8] +#define local_decs stack[-9] +#endif +#define name stack[-10] +#define env stack[-11] +#define body stack[-12] +#define bvl stack[-13] +#define arg1 stack[-14] +#define stack_used ((int)(nargs + 14)) + +#ifdef COMMON + for (;;) + { if (!consp(body)) break; + p = macroexpand(qcar(body), env); + nil = C_nil; + if (exception_pending()) + { Lisp_Object qname = name; + popv(stack_used); + return qname; + } + body = qcdr(body); + if (!consp(p)) + { if (stringp(p) && consp(body)) continue; + body = cons(p, body); + break; + } + if (qcar(p) != declare_symbol) + { body = cons(p, body); + break; + } + for (v = qcdr(v); consp(v); v = qcdr(v)) + { v1 = qcar(v); + if (!consp(v1) || qcar(v1) != special_symbol) continue; + /* here v1 says (special ...) */ + for (v1=qcdr(v1); consp(v1); v1 = qcdr(v1)) + { local_decs = cons(qcar(v1), local_decs); + if (exception_pending()) break; + } + } + } + nil = C_nil; + if (exception_pending()) + { Lisp_Object qname = name; + popv(stack_used); + return qname; + } +#endif +/* + * Parse the BVL + */ + for (p = bvl; consp(p); p=qcdr(p)) + { v = qcar(p); + v1 = nil; + arg = nil; + val1 = nil; +/* + * I can break from this switch statement with v a variable to bind + * and arg the value to bind to it, also v1 (if not nil) is a second + * variable to be bound (a supplied-p value) and val1 the value to bind it to. + * If I see &rest or &key the remaining actual args get collected into + * restarg, which takes the place of arg in some respects. + */ + switch (opt_rest_state) + { + + case STATE_NULL: + if (v == opt_key) + { opt_rest_state = STATE_OPT; + continue; + } + +#define BAD1(msg) { error(0, msg); goto unwind_special_bindings; } +#define BAD2(msg, a) { error(1, msg, a); goto unwind_special_bindings; } + +#define collect_rest_arg() \ + while (args_left-- != 0) \ + { if (!exception_pending()) \ + restarg = cons(next_arg[args_left], restarg); \ + nil = C_nil; \ + } + + if (v == rest_key) + { collect_rest_arg(); + if (exception_pending()) goto unwind_special_bindings; + opt_rest_state = STATE_REST; + continue; + } +#ifdef COMMON + if (v == key_key) + { collect_rest_arg(); + if (exception_pending()) goto unwind_special_bindings; + if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); + opt_rest_state = STATE_KEY; + continue; + } + + if (v == aux_key) + { if (args_left != 0) BAD1(err_excess_args); + opt_rest_state = STATE_AUX; + continue; + } + if (v == allow_other_keys) BAD2(err_bad_bvl, v); +#endif + if (args_left == 0) BAD1(err_insufficient_args); + arg = *next_arg++; + args_left--; + v1 = nil; /* no suppliedp mess here, I'm glad to say */ + break; + + case STATE_OPT: + if (v == opt_key + || v == rest_key +#ifdef COMMON + || v == key_key + || v == allow_other_keys + || v == aux_key +#endif + ) BAD2(err_bad_bvl, v); +/* + * Here v may be a simple variable, or a list (var init suppliedp) + */ + opt_rest_state = STATE_OPT1; +process_optional_parameter: + if (args_left != 0) + { arg = *next_arg++; + args_left--; + val1 = lisp_true; + } + else + { arg = nil; + val1 = nil; + } + v1 = nil; + if (!consp(v)) break; /* Simple case */ + { w = qcdr(v); + v = qcar(v); + if (!consp(w)) break; /* (var) */ + if (val1 == nil) /* use the init form */ + { arg = qcar(w); + arg = eval(arg, env); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + } + w = qcdr(w); + if (consp(w)) v1 = qcar(w); /* suppliedp name */ + break; + } + + case STATE_OPT1: + if (v == rest_key) + { collect_rest_arg(); + if (exception_pending()) goto unwind_special_bindings; + opt_rest_state = STATE_REST; + continue; + } +#ifdef COMMON + if (v == key_key) + { collect_rest_arg(); + if (exception_pending()) goto unwind_special_bindings; + if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); + opt_rest_state = STATE_KEY; + continue; + } + if (v == aux_key) + { if (args_left != 0) BAD1(err_excess_args); + opt_rest_state = STATE_AUX; + continue; + } +#endif + if (v == opt_key +#ifdef COMMON + || v == allow_other_keys +#endif + ) BAD2(err_bad_bvl, v); + goto process_optional_parameter; + + case STATE_REST: + if (v == opt_key + || v == rest_key +#ifdef COMMON + || v == key_key + || v == allow_other_keys + || v == aux_key +#endif + ) BAD2(err_bad_bvl, v); + opt_rest_state = STATE_REST1; + arg = restarg; + break; + + case STATE_REST1: +#ifdef COMMON + if (v == key_key) + { if (check_keyargs_even(restarg)) BAD2(err_bad_keyargs, restarg); + opt_rest_state = STATE_KEY; + continue; + } + if (v == aux_key) + { + opt_rest_state = STATE_AUX; + continue; + } +#endif + BAD2(err_bad_bvl, rest_key); + +#ifdef COMMON + case STATE_KEY: + if (v == allow_other_keys) + { opt_rest_state = STATE_ALLOW; + continue; + } + if (v == aux_key) + { if (check_no_unwanted_keys(restarg, ok_keys)) + BAD2(err_bad_keyargs, restarg); + opt_rest_state = STATE_AUX; + continue; + } + if (v == opt_key || v == rest_key || v == key_key) + BAD2(err_bad_bvl, v); +process_keyword_parameter: +/* + * v needs to expand to ((:kv v) init svar) in effect here. + */ + { Lisp_Object keyname = nil; + w = nil; + if (!consp(v)) + { if (!is_symbol(v)) BAD2(err_bad_bvl, v); + keyname = keywordify(v); + } + else + { w = qcdr(v); + v = qcar(v); + if (!consp(v)) + { if (!is_symbol(v)) BAD2(err_bad_bvl, v); + keyname = keywordify(v); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + } + else + { keyname = qcar(v); + if (!is_symbol(keyname)) BAD2(err_bad_bvl, v); + keyname = keywordify(keyname); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + v = qcdr(v); + if (consp(v)) v = qcar(v); + else BAD2(err_bad_bvl, v); + } + } + ok_keys = cons(keyname, ok_keys); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + arg = key_lookup(qcar(ok_keys), restarg); + if (arg == nil) val1 = nil; + else + { arg = qcar(arg); + val1 = lisp_true; + } + v1 = nil; + if (!consp(w)) break; /* (var) */ + if (val1 == nil) /* use the init form */ + { arg = qcar(w); + arg = eval(arg, env); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + } + w = qcdr(w); + if (consp(w)) v1 = qcar(w); /* suppliedp name */ + break; + } + + case STATE_ALLOW: + if (v == aux_key) + { opt_rest_state = STATE_AUX; + continue; + } + if (v == opt_key || v == rest_key || v == key_key || + v == allow_other_keys) BAD2(err_bad_bvl, v); + goto process_keyword_parameter; + + case STATE_AUX: + if (v == opt_key || v == rest_key || + v == key_key || v == allow_other_keys || + v == aux_key) BAD2(err_bad_bvl, v); + if (consp(v)) + { w = qcdr(v); + v = qcar(v); + if (consp(w)) + { arg = qcar(w); + arg = eval(arg, env); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + } + } + else arg = nil; + v1 = nil; + break; +#endif + } +/* + * This is where I get when I have one or two vars to bind. + */ + +#ifndef COMMON +/* + * CSL mode does not have to mess about looking for local special bindings + * and so is MUCH shorter and neater. I always shallow bind + */ +#define instate_binding(var, val, local_decs1, lab) \ + { if (!is_symbol(var)) BAD2(err_bad_bvl, var); \ + w = acons(var, qvalue(var), specenv); \ + nil = C_nil; \ + if (exception_pending()) goto unwind_special_bindings; \ + specenv = w; \ + qvalue(var) = val; \ + } +#else +#define instate_binding(var, val, local_decs1, lab) \ + { Header h; \ + if (!is_symbol(var)) BAD2(err_bad_bvl, var); \ + h = qheader(var); \ + if ((h & SYM_SPECIAL_VAR) != 0) \ + { w = acons(var, qvalue(var), specenv); \ + nil = C_nil; \ + if (exception_pending()) goto unwind_special_bindings; \ + specenv = w; \ + qvalue(var) = val; \ + } \ + else \ + { for (w = local_decs1; w!=nil; w = qcdr(w)) \ + { if (qcar(w) == var) \ + { qcar(w) = fixnum_of_int(0);/* decl is used up */\ + w = acons(var, work_symbol, env); \ + nil = C_nil; \ + if (exception_pending()) \ + goto unwind_special_bindings; \ + env = w; \ + w = acons(var, qvalue(var), specenv); \ + nil = C_nil; \ + if (exception_pending()) \ + goto unwind_special_bindings; \ + specenv = w; \ + qvalue(var) = val; \ + goto lab; \ + } \ + } \ + w = acons(var, val, env); \ + nil = C_nil; \ + if (exception_pending()) goto unwind_special_bindings; \ + env = w; \ + lab: ; \ + } \ + } +#endif + +#ifdef COMMON +/* + * Must check about local special declarations here... + */ +#endif + instate_binding(v, arg, local_decs, label1); + if (v1 != nil) instate_binding(v1, val1, local_decs, label2); + + } /* End of for loop that scans BVL */ + +#ifdef COMMON +/* + * As well as local special declarations that have applied to bindings here + * there can be some that apply just to variable references within the body. + */ + while (local_decs!=nil) + { Lisp_Object q = qcar(local_decs); + local_decs=qcdr(local_decs); + if (!is_symbol(q)) continue; + w = acons(q, work_symbol, env); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + env = w; + } +#endif + + switch (opt_rest_state) + { +case STATE_NULL: +case STATE_OPT1: /* Ensure there had not been too many args */ + if (args_left != 0) BAD1(err_excess_args); + break; + +case STATE_OPT: /* error if bvl finishes here */ +case STATE_REST: + BAD2(err_bad_bvl, opt_rest_state == STATE_OPT ? opt_key : rest_key); + +#ifdef COMMON +case STATE_KEY: /* ensure only valid keys were given */ + if (check_no_unwanted_keys(restarg, ok_keys)) + BAD2(err_bad_keyargs, restarg); + break; +#endif + +default: +/* in the following cases all is known to be well +case STATE_REST1: +case STATE_ALLOW: +case STATE_AUX: +*/ + break; + } + +/* + * Now all the argument bindings have been performed - it remains to + * process the body of the lambda-expression. + */ + if (specenv == nil) + { Lisp_Object bodyx = body, envx = env; + Lisp_Object qname = name; + popv(stack_used); + push(qname); + bodyx = progn_fn(bodyx, envx); + pop(qname); + nil = C_nil; + if (exception_pending()) return qname; + return bodyx; + } + { body = progn_fn(body, env); + nil = C_nil; + if (exception_pending()) goto unwind_special_bindings; + while (specenv != nil) + { + Lisp_Object bv = qcar(specenv); + qvalue(qcar(bv)) = qcdr(bv); + specenv = qcdr(specenv); + } + { Lisp_Object bodyx = body; + popv(stack_used); +/* + * note that exit_count has not been disturbed since I called progn_fn, + * so the numbert of values that will be returned remains correctly + * established (in Common Lisp mode where it is needed. + */ + return bodyx; + } + } + +unwind_special_bindings: +/* + * I gete here ONLY if nil has its mark bit set, which means that (for + * one reason or another) I am having to unwind the stack, restoring + * special bindings as I go. + */ + nil = C_nil; + flip_exception(); + while (specenv != nil) + { Lisp_Object bv = qcar(specenv); + qvalue(qcar(bv)) = qcdr(bv); + specenv = qcdr(specenv); + } + flip_exception(); + { Lisp_Object qname = name; + popv(stack_used); + return qname; + } +#undef w +#undef p +#undef v +#undef v1 +#undef arg +#undef val1 +#undef specenv +#undef restarg +#undef ok_keys +#undef local_decs +#undef name +#undef env +#undef body +#undef bvl +#undef stack_used +} + +Lisp_Object Leval(Lisp_Object nil, Lisp_Object a) +{ + return eval(a, nil); /* Multiple values may be returned */ +} + +Lisp_Object Levlis(Lisp_Object nil, Lisp_Object a) +{ + Lisp_Object r; + stackcheck1(0, a); + r = nil; + while (consp(a)) + { push2(qcdr(a), r); + a = qcar(a); + a = eval(a, nil); + errexitn(2); + pop(r); + r = cons(a, r); + pop(a); + errexit(); + } + return onevalue(nreverse(r)); +} + +Lisp_Object MS_CDECL Lapply_n(Lisp_Object nil, int nargs, ...) +{ + va_list a; + int i; + Lisp_Object *stack_save = stack, last, fn; + if (nargs == 0) return aerror("apply"); + if (nargs > 1) + { va_start(a, nargs); + fn = va_arg(a, Lisp_Object); + push_args_1(a, nargs); + pop(last); + i = nargs-2; + while (consp(last)) + { push(qcar(last)); + last = qcdr(last); + i++; + } + } + else i = 0; + stackcheck1(stack-stack_save, fn); + return apply(fn, i, nil, fn); +} + +Lisp_Object Lapply_1(Lisp_Object nil, Lisp_Object fn) +{ + return Lapply_n(nil, 1, fn); +} + +Lisp_Object Lapply_2(Lisp_Object nil, Lisp_Object fn, Lisp_Object a1) +{ + return Lapply_n(nil, 2, fn, a1); +} + +Lisp_Object Lapply0(Lisp_Object nil, Lisp_Object fn) +{ + if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 0); + stackcheck1(0, fn); + return apply(fn, 0, C_nil, fn); +} + +Lisp_Object Lapply1(Lisp_Object nil, Lisp_Object fn, Lisp_Object a) +{ + if (is_symbol(fn)) return (*qfn1(fn))(qenv(fn), a); + push(a); + stackcheck1(1, fn); + return apply(fn, 1, C_nil, fn); +} + +Lisp_Object MS_CDECL Lapply2(Lisp_Object nil, int nargs, ...) +{ + va_list aa; + Lisp_Object fn, a, b; + argcheck(nargs, 3, "apply2"); + va_start(aa, nargs); + fn = va_arg(aa, Lisp_Object); + a = va_arg(aa, Lisp_Object); + b = va_arg(aa, Lisp_Object); + va_end(aa); + if (is_symbol(fn)) return (*qfn2(fn))(qenv(fn), a, b); + push2(a, b); + stackcheck1(2, fn); + return apply(fn, 2, C_nil, fn); +} + +Lisp_Object MS_CDECL Lapply3(Lisp_Object nil, int nargs, ...) +{ + va_list aa; + Lisp_Object fn, a, b, c; + argcheck(nargs, 4, "apply3"); + va_start(aa, nargs); + fn = va_arg(aa, Lisp_Object); + a = va_arg(aa, Lisp_Object); + b = va_arg(aa, Lisp_Object); + c = va_arg(aa, Lisp_Object); + va_end(aa); + if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 3, a, b, c); + push3(a, b, c); + stackcheck1(3, fn); + return apply(fn, 3, C_nil, fn); +} + +Lisp_Object Lfuncall1(Lisp_Object nil, Lisp_Object fn) +{ + if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 0); + stackcheck1(0, fn); + return apply(fn, 0, nil, fn); +} + +Lisp_Object Lfuncall2(Lisp_Object nil, Lisp_Object fn, Lisp_Object a1) +{ + if (is_symbol(fn)) return (*qfn1(fn))(qenv(fn), a1); + push(a1); + stackcheck1(1, fn); + return apply(fn, 1, nil, fn); +} + +static Lisp_Object MS_CDECL Lfuncalln_sub(Lisp_Object nil, int nargs, va_list a) +{ + Lisp_Object *stack_save = stack, fn; + fn = va_arg(a, Lisp_Object); + push_args_1(a, nargs); + stackcheck1(stack-stack_save, fn); + return apply(fn, nargs-1, nil, fn); +} + +Lisp_Object MS_CDECL Lfuncalln(Lisp_Object nil, int nargs, ...) +{ + va_list a; + Lisp_Object fn, a1, a2, a3, a4; + va_start(a, nargs); + switch (nargs) + { +case 0: return aerror("funcall"); +case 1: /* cases 1 and 2 should go through Lfuncall1,2 not here */ +case 2: return aerror("funcall wrong call"); +case 3: fn = va_arg(a, Lisp_Object); + a1 = va_arg(a, Lisp_Object); + a2 = va_arg(a, Lisp_Object); + if (is_symbol(fn)) return (*qfn2(fn))(qenv(fn), a1, a2); + push2(a1, a2); + return apply(fn, 2, nil, fn); +case 4: fn = va_arg(a, Lisp_Object); + a1 = va_arg(a, Lisp_Object); + a2 = va_arg(a, Lisp_Object); + a3 = va_arg(a, Lisp_Object); + if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 3, a1, a2, a3); + push3(a1, a2, a3); + return apply(fn, 3, nil, fn); +case 5: fn = va_arg(a, Lisp_Object); + a1 = va_arg(a, Lisp_Object); + a2 = va_arg(a, Lisp_Object); + a3 = va_arg(a, Lisp_Object); + a4 = va_arg(a, Lisp_Object); + if (is_symbol(fn)) return (*qfnn(fn))(qenv(fn), 4, a1, a2, a3, a4); + push4(a1, a2, a3, a4); + return apply(fn, 4, nil, fn); +default: + return Lfuncalln_sub(nil, nargs, a); + } +} + +#ifdef COMMON + +Lisp_Object MS_CDECL Lvalues(Lisp_Object nil, int nargs, ...) +{ + va_list a; + Lisp_Object *p = &mv_2, w; + int i; +/* + * Because multiple-values get passed back in static storage there is + * a fixed upper limit to how many I can handle - truncate here to allow + * for that. + */ + if (nargs > 50) nargs = 50; + if (nargs == 0) return nvalues(nil, 0); + va_start(a, nargs); + push_args(a, nargs); + for (i=1; i nil */ + stackcheck2(0, args, env); + push2(args, env); + fn = qcar(args); + fn = eval(fn, env); + pop2(env, args); + errexit(); + args = qcdr(args); + while (consp(args)) + { Lisp_Object r1; + push2(args, env); + r1 = qcar(args); + r1 = eval(r1, env); + nil = C_nil; + if (exception_pending()) + { stack = stack_save; + return nil; + } +/* + * It is critical here that push does not check for stack overflow and + * thus can not call the garbage collector, or otherwise lead to calculation + * that could possibly clobber the multiple results that I am working with + * here. + */ + pop2(env, args); + push(r1); + i++; + for (j = 2; j<=exit_count; j++) + { push((&work_0)[j]); + i++; + } + args = qcdr(args); + } + stackcheck2(stack-stack_save, fn, env); + return apply(fn, i, env, fn); +} + +#endif + +Lisp_Object interpreted1(Lisp_Object def, Lisp_Object a1) +{ + Lisp_Object nil = C_nil; + push(a1); + stackcheck1(1, def); + return apply_lambda(def, 1, nil, def); +} + +Lisp_Object interpreted2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) +{ + Lisp_Object nil = C_nil; + push2(a1, a2); + stackcheck1(2, def); + return apply_lambda(def, 2, nil, def); +} + +Lisp_Object MS_CDECL interpretedn(Lisp_Object def, int nargs, ...) +{ +/* + * The messing about here is to get the (unknown number of) args + * into a nice neat vector so that they can be indexed into. If I knew + * that the args were in consecutive locations on the stack I could + * probably save a copying operation. + */ + Lisp_Object nil = C_nil; + Lisp_Object *stack_save = stack; + va_list a; + if (nargs != 0) + { va_start(a, nargs); + push_args(a, nargs); + } + stackcheck1(stack-stack_save, def); + return apply_lambda(def, nargs, nil, def); +} + +Lisp_Object funarged1(Lisp_Object def, Lisp_Object a1) +{ + Lisp_Object nil = C_nil; + push(a1); + stackcheck1(1, def); + return apply_lambda(qcdr(def), 1, qcar(def), qcdr(def)); +} + +Lisp_Object funarged2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) +{ + Lisp_Object nil = C_nil; + push2(a1, a2); + stackcheck1(2, def); + return apply_lambda(qcdr(def), 2, qcar(def), qcdr(def)); +} + +Lisp_Object MS_CDECL funargedn(Lisp_Object def, int nargs, ...) +{ + Lisp_Object nil = C_nil; + Lisp_Object *stack_save = stack; + va_list a; + if (nargs != 0) + { va_start(a, nargs); + push_args(a, nargs); + } + stackcheck1(stack-stack_save, def); + return apply_lambda(qcdr(def), nargs, qcar(def), qcdr(def)); +} + +/* + * Now some execution-doubling versions... + */ + +Lisp_Object double_interpreted1(Lisp_Object def, Lisp_Object a1) +{ + Lisp_Object nil = C_nil; + push(a1); + stackcheck1(1, def); + return apply_lambda(def, 1, nil, def); +} + +Lisp_Object double_interpreted2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) +{ + Lisp_Object nil = C_nil; + push2(a1, a2); + stackcheck1(2, def); + return apply_lambda(def, 2, nil, def); +} + +Lisp_Object MS_CDECL double_interpretedn(Lisp_Object def, int nargs, ...) +{ +/* + * The messing about here is to get the (unknown number of) args + * into a nice neat vector so that they can be indexed into. If I knew + * that the args were in consecutive locations on the stack I could + * probably save a copying operation. + */ + Lisp_Object nil = C_nil; + Lisp_Object *stack_save = stack; + va_list a; + if (nargs != 0) + { va_start(a, nargs); + push_args(a, nargs); + } + stackcheck1(stack-stack_save, def); + return apply_lambda(def, nargs, nil, def); +} + +Lisp_Object double_funarged1(Lisp_Object def, Lisp_Object a1) +{ + Lisp_Object nil = C_nil; + push(a1); + stackcheck1(1, def); + return apply_lambda(qcdr(def), 1, qcar(def), qcdr(def)); +} + +Lisp_Object double_funarged2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2) +{ + Lisp_Object nil = C_nil; + push2(a1, a2); + stackcheck1(2, def); + return apply_lambda(qcdr(def), 2, qcar(def), qcdr(def)); +} + +Lisp_Object MS_CDECL double_funargedn(Lisp_Object def, int nargs, ...) +{ + Lisp_Object nil = C_nil; + Lisp_Object *stack_save = stack; + va_list a; + if (nargs != 0) + { va_start(a, nargs); + push_args(a, nargs); + } + stackcheck1(stack-stack_save, def); + return apply_lambda(qcdr(def), nargs, qcar(def), qcdr(def)); +} + +int trace_depth = 0; + +static void trace_entering(char *s) +{ + int i; + for (i=0; i0)", env); + return (*qfnn(env))(qenv(env), 0); +} + +Lisp_Object f1_as_0(Lisp_Object env, Lisp_Object a) +{ + return (*qfnn(env))(qenv(env), 0); +} + +Lisp_Object f2_as_0(Lisp_Object env, Lisp_Object a, Lisp_Object b) +{ + return (*qfnn(env))(qenv(env), 0); +} + +Lisp_Object MS_CDECL f3_as_0(Lisp_Object env, int nargs, ...) +{ + if (nargs != 3) return aerror1("wrong number of args (3->0)", env); + return (*qfnn(env))(qenv(env), 0); +} + +Lisp_Object f1_as_1(Lisp_Object env, Lisp_Object a) +{ + return (*qfn1(env))(qenv(env), a); +} + +Lisp_Object f2_as_1(Lisp_Object env, Lisp_Object a, Lisp_Object b) +{ + return (*qfn1(env))(qenv(env), a); +} + +Lisp_Object MS_CDECL f3_as_1(Lisp_Object env, int nargs, ...) +{ + va_list a; + Lisp_Object a1; + if (nargs != 3) return aerror1("wrong number of args (3->1)", env); + va_start(a, nargs); + a1 = va_arg(a, Lisp_Object); + va_end(a); + return (*qfn1(env))(qenv(env), a1); +} + +Lisp_Object f2_as_2(Lisp_Object env, Lisp_Object a, Lisp_Object b) +{ + return (*qfn2(env))(qenv(env), a, b); +} + +Lisp_Object MS_CDECL f3_as_2(Lisp_Object env, int nargs, ...) +{ + va_list a; + Lisp_Object a1, a2; + if (nargs != 3) return aerror1("wrong number of args (3->2)", env); + va_start(a, nargs); + a1 = va_arg(a, Lisp_Object); + a2 = va_arg(a, Lisp_Object); + va_end(a); + return (*qfn2(env))(qenv(env), a1, a2); +} + +Lisp_Object MS_CDECL f3_as_3(Lisp_Object env, int nargs, ...) +{ + va_list a; + Lisp_Object a1, a2, a3; + if (nargs != 3) return aerror1("wrong number of args (3->3)", env); + va_start(a, nargs); + a1 = va_arg(a, Lisp_Object); + a2 = va_arg(a, Lisp_Object); + a3 = va_arg(a, Lisp_Object); + va_end(a); + return (*qfnn(env))(qenv(env), 3, a1, a2, a3); +} + +setup_type const eval1_setup[] = +{ + {"bytecounts", wrong_no_na, wrong_no_nb, bytecounts}, + {"apply", Lapply_1, Lapply_2, Lapply_n}, + {"apply0", Lapply0, too_many_1, wrong_no_1}, + {"apply1", too_few_2, Lapply1, wrong_no_2}, + {"apply2", wrong_no_na, wrong_no_nb, Lapply2}, + {"apply3", wrong_no_na, wrong_no_nb, Lapply3}, + {"evlis", Levlis, too_many_1, wrong_no_1}, + {"funcall", Lfuncall1, Lfuncall2, Lfuncalln}, + {"funcall*", Lfuncall1, Lfuncall2, Lfuncalln}, +#ifdef COMMON + {"values", Lvalues_1, Lvalues_2, Lvalues}, + {"macroexpand", Lmacroexpand, Lmacroexpand_2, wrong_no_1}, + {"macroexpand-1", Lmacroexpand_1, Lmacroexpand_1_2, wrong_no_1}, +#else + {"macroexpand", Lmacroexpand, too_many_1, wrong_no_1}, + {"macroexpand-1", Lmacroexpand_1, too_many_1, wrong_no_1}, +#endif + {NULL, 0, 0, 0} +}; + +/* end of eval1.c */ +