12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775 |
- /* eval1.c Copyright (C) 1989-2002 Codemist Ltd */
- /*
- * Interpreter (part 1).
- */
- /*
- * This code may be used and modified, and redistributed in binary
- * or source form, subject to the "CCL Public License", which should
- * accompany it. This license is a variant on the BSD license, and thus
- * permits use of code derived from this in either open and commercial
- * projects: but it does require that updates to this code be made
- * available back to the originators of the package.
- * Before merging other code in with this or linking this code
- * with other packages or libraries please check that the license terms
- * of the other material are compatible with those of this.
- */
- /* Signature: 7b09cda9 10-Oct-2002 */
- #include <stdarg.h>
- #include <string.h>
- #include <ctype.h>
- #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 . <anything>) 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 (<list> . 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 CSLbool 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;
- CSLbool 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 CSLbool 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 = nil;
- if (nargs == 0) return aerror("apply");
- else 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<nargs; i++)
- { pop(w);
- p[nargs-i-1] = w;
- }
- pop(w);
- return nvalues(w, nargs);
- }
- Lisp_Object Lvalues_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
- {
- return Lvalues(nil, 2, a, b);
- }
- Lisp_Object Lvalues_1(Lisp_Object nil, Lisp_Object a)
- {
- return Lvalues(nil, 1, a);
- }
- Lisp_Object mv_call_fn(Lisp_Object args, Lisp_Object env)
- /*
- * here with the rest of the interpreter rather than in specforms.c
- */
- {
- Lisp_Object nil = C_nil;
- Lisp_Object fn, *stack_save = stack;
- int i=0, j=0;
- if (!consp(args)) return nil; /* (multiple-value-call) => 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));
- }
- Lisp_Object traceinterpreted1(Lisp_Object def, Lisp_Object a1)
- /*
- * Like interpreted() but the definition has the fn name consed on the front
- */
- {
- Lisp_Object nil = C_nil, r;
- push(a1);
- stackcheck1(1, def);
- freshline_trace();
- trace_printf("Entering ");
- loop_print_trace(qcar(def));
- trace_printf(" (1 arg)\n");
- trace_printf("Arg1: ");
- loop_print_trace(stack[0]);
- trace_printf("\n");
- r = apply_lambda(qcdr(def), 1, nil, def);
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- Lisp_Object traceinterpreted2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2)
- /*
- * Like interpreted() but the definition has the fn name consed on the front
- */
- {
- Lisp_Object nil = C_nil, r;
- int i;
- push2(a1, a2);
- stackcheck1(2, def);
- freshline_trace();
- trace_printf("Entering ");
- loop_print_trace(qcar(def));
- trace_printf(" (2 args)\n");
- for (i=1; i<=2; i++)
- { trace_printf("Arg%d: ", i);
- loop_print_trace(stack[i-2]);
- trace_printf("\n");
- }
- r = apply_lambda(qcdr(def), 2, nil, def);
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- Lisp_Object MS_CDECL traceinterpretedn(Lisp_Object def, int nargs, ...)
- /*
- * Like interpreted() but the definition has the fn name consed on the front
- */
- {
- int i;
- Lisp_Object nil = C_nil, r;
- Lisp_Object *stack_save = stack;
- va_list a;
- if (nargs != 0)
- { va_start(a, nargs);
- push_args(a, nargs);
- }
- stackcheck1(stack-stack_save, def);
- freshline_trace();
- trace_printf("Entering ");
- loop_print_trace(qcar(def));
- trace_printf(" (%d args)\n", nargs);
- for (i=1; i<=nargs; i++)
- { trace_printf("Arg%d: ", i);
- loop_print_trace(stack[i-nargs]);
- trace_printf("\n");
- }
- r = apply_lambda(qcdr(def), nargs, nil, def);
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- Lisp_Object tracefunarged1(Lisp_Object def, Lisp_Object a1)
- /*
- * Like funarged() but with some printing
- */
- {
- Lisp_Object nil = C_nil, r;
- push(a1);
- stackcheck1(1, def);
- freshline_trace();
- trace_printf("Entering funarg ");
- loop_print_trace(qcar(def));
- trace_printf(" (1 arg)\n");
- def = qcdr(def);
- r = apply_lambda(qcdr(def), 1, qcar(def), qcdr(def));
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- Lisp_Object tracefunarged2(Lisp_Object def, Lisp_Object a1, Lisp_Object a2)
- /*
- * Like funarged() but with some printing
- */
- {
- Lisp_Object nil = C_nil, r;
- push2(a1, a2);
- stackcheck1(2, def);
- freshline_trace();
- trace_printf("Entering funarg ");
- loop_print_trace(qcar(def));
- trace_printf(" (2 args)\n");
- def = qcdr(def);
- r = apply_lambda(qcdr(def), 2, qcar(def), qcdr(def));
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- Lisp_Object MS_CDECL tracefunargedn(Lisp_Object def, int nargs, ...)
- /*
- * Like funarged() but with some printing
- */
- {
- Lisp_Object nil = C_nil, r;
- Lisp_Object *stack_save = stack;
- va_list a;
- if (nargs != 0)
- { va_start(a, nargs);
- push_args(a, nargs);
- }
- stackcheck1(stack-stack_save, def);
- freshline_trace();
- trace_printf("Entering funarg ");
- loop_print_trace(qcar(def));
- trace_printf(" (%d args)\n", nargs);
- def = qcdr(def);
- r = apply_lambda(qcdr(def), nargs, qcar(def), qcdr(def));
- errexit();
- push(r);
- trace_printf("Value = ");
- loop_print_trace(r);
- trace_printf("\n");
- pop(r);
- return r;
- }
- static Lisp_Object macroexpand_1(Lisp_Object form, Lisp_Object env)
- { /* The environment here seems only necessary for macrolet */
- Lisp_Object done;
- Lisp_Object f, nil;
- nil = C_nil;
- stackcheck2(0, form, env);
- done = nil;
- if (consp(form))
- { f = qcar(form);
- #ifdef COMMON
- /*
- * look for local macro definitions
- */
- { Lisp_Object p;
- for (p=env; p!=nil; p=qcdr(p))
- { Lisp_Object w = qcar(p);
- if (qcdr(w) == f && is_cons(w = qcar(w)) && w!=nil)
- {
- p = qcar(w);
- if (p == funarg) /* ordinary function */
- { mv_2 = nil;
- return nvalues(form, 2);
- }
- push2(form, done);
- w = cons(lambda, w);
- errexitn(1);
- p = Lfuncalln(nil, 4, qvalue(macroexpand_hook),
- w, stack[-1], nil);
- pop2(done, form);
- nil = C_nil;
- if (exception_pending())
- { flip_exception();
- if ((exit_reason & UNWIND_ERROR) != 0)
- { err_printf("\nMacroexpanding: ");
- loop_print_error(form);
- nil = C_nil;
- if (exception_pending()) flip_exception();
- }
- flip_exception();
- return nil;
- }
- mv_2 = lisp_true;
- return nvalues(p, 2);
- }
- }
- }
- /*
- * If there is no local macro definition I need to look for a global one
- */
- #endif
- if (symbolp(f) && (qheader(f) & SYM_MACRO) != 0)
- {
- done = qvalue(macroexpand_hook);
- if (done == unset_var)
- return error(1, err_macroex_hook, macroexpand_hook);
- push3(form, env, done);
- f = cons(lambda, qenv(f));
- pop3(done, env, form);
- nil = C_nil;
- if (!exception_pending())
- {
- #ifndef COMMON
- /* CSL does not pass an environment down here, so does not demand &opt arg */
- form = Lfuncalln(nil, 3, done, f, form);
- #else
- form = Lfuncalln(nil, 4, done, f, form, env);
- #endif
- nil = C_nil;
- }
- if (exception_pending()) return nil;
- done = lisp_true;
- }
- }
- mv_2 = done;
- return nvalues(form, 2); /* Multiple values handed back */
- }
- Lisp_Object macroexpand(Lisp_Object form, Lisp_Object env)
- { /* The environment here seems only necessary for macrolet */
- Lisp_Object done, nil;
- nil = C_nil;
- stackcheck2(0, form, env);
- done = nil;
- for (;;)
- { push2(env, done);
- form = macroexpand_1(form, env);
- pop2(done, env);
- errexit();
- if (mv_2 == nil) break;
- done = lisp_true;
- }
- mv_2 = done;
- return nvalues(form, 2); /* Multiple values handed back */
- }
- Lisp_Object Lmacroexpand(Lisp_Object nil, Lisp_Object a)
- {
- return macroexpand(a, nil);
- }
- #ifdef COMMON
- Lisp_Object Lmacroexpand_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
- {
- CSL_IGNORE(nil);
- return macroexpand(a, b);
- }
- #endif
- Lisp_Object Lmacroexpand_1(Lisp_Object nil, Lisp_Object a)
- {
- return macroexpand_1(a, nil);
- }
- #ifdef COMMON
- Lisp_Object Lmacroexpand_1_2(Lisp_Object nil, Lisp_Object a, Lisp_Object b)
- {
- CSL_IGNORE(nil);
- return macroexpand_1(a, b);
- }
- #endif
- /*
- * To make something autoloadable I should set the environment cell to
- * (name-of-self module-name-1 module-name-2 ...)
- * and when invoked the function will do a load-module on each of the
- * modules specified and then re-attempt to call. Loading the
- * modules is expected to establish a proper definition for the
- * function involved.
- */
- Lisp_Object autoload1(Lisp_Object fname, Lisp_Object a1)
- {
- Lisp_Object nil = C_nil;
- push2(a1, qcar(fname));
- set_fns(qcar(fname), undefined1, undefined2, undefinedn);
- qenv(qcar(fname)) = qcar(fname);
- fname = qcdr(fname);
- while (consp(fname))
- { push(qcdr(fname));
- Lload_module(nil, qcar(fname));
- errexitn(3);
- pop(fname);
- }
- pop(fname);
- return apply(fname, 1, nil, fname);
- }
- Lisp_Object autoload2(Lisp_Object fname, Lisp_Object a1, Lisp_Object a2)
- {
- Lisp_Object nil = C_nil;
- push3(a1, a2, qcar(fname));
- set_fns(qcar(fname), undefined1, undefined2, undefinedn);
- qenv(qcar(fname)) = qcar(fname);
- fname = qcdr(fname);
- while (consp(fname))
- { push(qcdr(fname));
- Lload_module(nil, qcar(fname));
- errexitn(4);
- pop(fname);
- }
- pop(fname);
- return apply(fname, 2, nil, fname);
- }
- Lisp_Object MS_CDECL autoloadn(Lisp_Object fname, int nargs, ...)
- {
- Lisp_Object nil = C_nil;
- va_list a;
- va_start(a, nargs);
- push_args(a, nargs);
- push(qcar(fname));
- set_fns(qcar(fname), undefined1, undefined2, undefinedn);
- qenv(qcar(fname)) = qcar(fname);
- fname = qcdr(fname);
- while (consp(fname))
- { push(qcdr(fname));
- Lload_module(nil, qcar(fname));
- errexitn(nargs+2);
- pop(fname);
- }
- pop(fname);
- return apply(fname, nargs, nil, fname);
- }
- Lisp_Object undefined1(Lisp_Object fname, Lisp_Object a1)
- {
- /*
- * It would be perfectly possible to grab and save the args here, and retry
- * the function call after error has patched things up. Again
- * this entrypoint is for compiled code calling something that is undefined,
- * and so no lexical environment is needed.
- */
- CSL_IGNORE(a1);
- return error(1, err_undefined_function_1, fname);
- }
- Lisp_Object undefined2(Lisp_Object fname, Lisp_Object a1, Lisp_Object a2)
- {
- CSL_IGNORE(a1);
- CSL_IGNORE(a2);
- return error(1, err_undefined_function_2, fname);
- }
- Lisp_Object MS_CDECL undefinedn(Lisp_Object fname, int nargs, ...)
- {
- CSL_IGNORE(nargs);
- return error(1, err_undefined_function_n, fname);
- }
- /*
- * The next few functions allow me to create variants on things! The
- * entrypoint fX_as_Y goes in the function cell of a symbol, and the name
- * of a function with Y arguments goes in is environment cell. The result will
- * be a function that accepts X arguments and discards all but the first Y of
- * them, then chains to the other function. The purpose is to support goo
- * compilation of things like
- * (de funny_equal (a b c) (equal a b))
- */
- Lisp_Object MS_CDECL f0_as_0(Lisp_Object env, int nargs, ...)
- {
- if (nargs != 0) return aerror1("wrong number of args (0->0)", env);
- return (*qfnn(env))(qenv(env), 0);
- }
- Lisp_Object f1_as_0(Lisp_Object env, Lisp_Object a)
- {
- CSL_IGNORE(a);
- return (*qfnn(env))(qenv(env), 0);
- }
- Lisp_Object f2_as_0(Lisp_Object env, Lisp_Object a, Lisp_Object b)
- {
- CSL_IGNORE(a);
- CSL_IGNORE(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)
- {
- CSL_IGNORE(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 */
|