1 | ;;;-*-Mode: LISP; Package: CCL -*- |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 1994-2001 Digitool, Inc |
---|
4 | ;;; This file is part of OpenMCL. |
---|
5 | ;;; |
---|
6 | ;;; OpenMCL is licensed under the terms of the Lisp Lesser GNU Public |
---|
7 | ;;; License , known as the LLGPL and distributed with OpenMCL as the |
---|
8 | ;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL, |
---|
9 | ;;; which is distributed with OpenMCL as the file "LGPL". Where these |
---|
10 | ;;; conflict, the preamble takes precedence. |
---|
11 | ;;; |
---|
12 | ;;; OpenMCL is referenced in the preamble as the "LIBRARY." |
---|
13 | ;;; |
---|
14 | ;;; The LLGPL is also available online at |
---|
15 | ;;; http://opensource.franz.com/preamble.html |
---|
16 | |
---|
17 | (in-package "CCL") |
---|
18 | |
---|
19 | ;L1-readloop.lisp |
---|
20 | |
---|
21 | |
---|
22 | (defvar *break-on-signals* nil |
---|
23 | "When (TYPEP condition *BREAK-ON-SIGNALS*) is true, then calls to SIGNAL will |
---|
24 | enter the debugger prior to signalling that condition.") |
---|
25 | (defvar *break-on-warnings* nil) |
---|
26 | (defvar *break-on-errors* t "Not CL.") |
---|
27 | (defvar *debugger-hook* nil |
---|
28 | "This is either NIL or a function of two arguments, a condition and the value |
---|
29 | of *DEBUGGER-HOOK*. This function can either handle the condition or return |
---|
30 | which causes the standard debugger to execute. The system passes the value |
---|
31 | of this variable to the function because it binds *DEBUGGER-HOOK* to NIL |
---|
32 | around the invocation.") |
---|
33 | (defvar *backtrace-on-break* nil) |
---|
34 | (defvar *** nil |
---|
35 | "the previous value of **") |
---|
36 | (defvar ** nil |
---|
37 | "the previous value of *") |
---|
38 | (defvar * nil |
---|
39 | "the value of the most recent top level EVAL") |
---|
40 | (defvar /// nil |
---|
41 | "the previous value of //") |
---|
42 | (defvar // nil |
---|
43 | "the previous value of /") |
---|
44 | (defvar / nil |
---|
45 | "a list of all the values returned by the most recent top level EVAL") |
---|
46 | (defvar +++ nil |
---|
47 | "the previous value of ++") |
---|
48 | (defvar ++ nil |
---|
49 | "the previous value of +") |
---|
50 | (defvar + nil |
---|
51 | "the value of the most recent top level READ") |
---|
52 | (defvar - nil |
---|
53 | "the form currently being evaluated") |
---|
54 | |
---|
55 | (defvar *continuablep* nil) |
---|
56 | (defvar *in-read-loop* nil |
---|
57 | "Is T if waiting for input in the read loop") |
---|
58 | |
---|
59 | |
---|
60 | (defvar *did-startup* nil) |
---|
61 | |
---|
62 | |
---|
63 | |
---|
64 | (defmacro catch-cancel (&body body) |
---|
65 | `(catch :cancel ,@body)) |
---|
66 | |
---|
67 | (defmacro throw-cancel (&optional value) |
---|
68 | `(throw :cancel ,value)) |
---|
69 | |
---|
70 | ;;; Throwing like this works in listeners and in the initial process. |
---|
71 | ;;; Can't easily tell if a process is a listener. Should be able to. |
---|
72 | (defun toplevel () |
---|
73 | (throw :toplevel nil)) |
---|
74 | |
---|
75 | |
---|
76 | ;;; It's not clear that this is the right behavior, but aborting CURRENT-PROCESS - |
---|
77 | ;;; when no one's sure just what CURRENT-PROCESS is - doesn't seem right either. |
---|
78 | (defun interactive-abort () |
---|
79 | (interactive-abort-in-process *current-process*)) |
---|
80 | |
---|
81 | (defun interactive-abort-in-process (p) |
---|
82 | (if p (process-interrupt p |
---|
83 | #'(lambda () |
---|
84 | (unless *inhibit-abort* |
---|
85 | (if *in-read-loop* |
---|
86 | (abort-break) |
---|
87 | (abort)) |
---|
88 | ))))) |
---|
89 | |
---|
90 | |
---|
91 | (defun abort (&optional condition) |
---|
92 | "Transfer control to a restart named ABORT, signalling a CONTROL-ERROR if |
---|
93 | none exists." |
---|
94 | (invoke-restart-no-return (find-restart 'abort condition))) |
---|
95 | |
---|
96 | (defun continue (&optional condition) |
---|
97 | "Transfer control to a restart named CONTINUE, or return NIL if none exists." |
---|
98 | (let ((r (find-restart 'continue condition))) |
---|
99 | (if r (invoke-restart r)))) |
---|
100 | |
---|
101 | (defun muffle-warning (&optional condition) |
---|
102 | "Transfer control to a restart named MUFFLE-WARNING, signalling a |
---|
103 | CONTROL-ERROR if none exists." |
---|
104 | (invoke-restart-no-return (find-restart 'muffle-warning condition))) |
---|
105 | |
---|
106 | (defun abort-break () |
---|
107 | (invoke-restart-no-return 'abort-break)) |
---|
108 | |
---|
109 | |
---|
110 | (defun quit (&optional (exit-status 0)) |
---|
111 | (unless (typep exit-status '(signed-byte 32)) |
---|
112 | (report-bad-arg exit-status '(signed-byte 32))) |
---|
113 | (let* ((ip *initial-process*) |
---|
114 | (cp *current-process*)) |
---|
115 | (when (process-verify-quit ip) |
---|
116 | (process-interrupt ip |
---|
117 | #'(lambda () |
---|
118 | (process-exit-application *current-process* |
---|
119 | #'(lambda () |
---|
120 | (%set-toplevel nil) |
---|
121 | (#__exit exit-status))))) |
---|
122 | (unless (eq cp ip) |
---|
123 | (process-kill cp))))) |
---|
124 | |
---|
125 | |
---|
126 | (defloadvar *quitting* nil) |
---|
127 | |
---|
128 | |
---|
129 | (defun prepare-to-quit (&optional part) |
---|
130 | (let-globally ((*quitting* t)) |
---|
131 | (when (or (null part) (eql 0 part)) |
---|
132 | (dolist (f *lisp-cleanup-functions*) |
---|
133 | (funcall f))) |
---|
134 | (let* ((stragglers ())) |
---|
135 | (dolist (p (all-processes)) |
---|
136 | (unless (or (eq p *initial-process*) |
---|
137 | (not (process-active-p p))) |
---|
138 | (if (process-persistent p) |
---|
139 | (process-reset p :shutdown) |
---|
140 | (process-kill p)))) |
---|
141 | (dolist (p (all-processes)) |
---|
142 | (let* ((semaphore (process-termination-semaphore p))) |
---|
143 | (when semaphore |
---|
144 | (unless (eq p *initial-process*) |
---|
145 | (unless (timed-wait-on-semaphore semaphore 0.05) |
---|
146 | (push p stragglers)))))) |
---|
147 | (dolist (p stragglers) |
---|
148 | (let* ((semaphore (process-termination-semaphore p))) |
---|
149 | (maybe-finish-process-kill p :kill) |
---|
150 | (when semaphore |
---|
151 | (timed-wait-on-semaphore semaphore 0.10))))) |
---|
152 | (shutdown-lisp-threads) |
---|
153 | (loop |
---|
154 | (let* ((streams (open-file-streams))) |
---|
155 | (when (null streams) (return)) |
---|
156 | (let* ((ioblock (stream-ioblock (car streams) nil))) |
---|
157 | (when ioblock |
---|
158 | (setf (ioblock-inbuf-lock ioblock) nil |
---|
159 | (ioblock-outbuf-lock ioblock) nil |
---|
160 | (ioblock-owner ioblock) nil))) |
---|
161 | (close (car streams)))) |
---|
162 | (setf (interrupt-level) -1) ; can't abort after this |
---|
163 | ) |
---|
164 | ;; Didn't abort, so really quitting. |
---|
165 | (setq *quitting* t)) |
---|
166 | |
---|
167 | |
---|
168 | (defun signal (condition &rest args) |
---|
169 | "Invokes the signal facility on a condition formed from DATUM and |
---|
170 | ARGUMENTS. If the condition is not handled, NIL is returned. If |
---|
171 | (TYPEP condition *BREAK-ON-SIGNALS*) is true, the debugger is invoked |
---|
172 | before any signalling is done." |
---|
173 | (setq condition (condition-arg condition args 'simple-condition)) |
---|
174 | (let* ((*break-on-signals* *break-on-signals*)) |
---|
175 | (let* ((old-bos *break-on-signals*)) |
---|
176 | (when (unknown-ctype-p (let* ((*break-on-signals* nil)) (specifier-type old-bos))) |
---|
177 | (setq *break-on-signals* nil) |
---|
178 | (warn "~S : Ignoring invalid type specifier ~s." '*break-on-signals old-bos))) |
---|
179 | |
---|
180 | (when (typep condition *break-on-signals*) |
---|
181 | (let ((*break-on-signals* nil)) |
---|
182 | (cbreak-loop "Signal" "Signal the condition." condition (%get-frame-ptr))))) |
---|
183 | (let ((%handlers% %handlers%)) |
---|
184 | (while %handlers% |
---|
185 | (do* ((tag (pop %handlers%)) (handlers tag (cddr handlers))) |
---|
186 | ((null handlers)) |
---|
187 | (when (typep condition (car handlers)) |
---|
188 | (let ((fn (cadr handlers))) |
---|
189 | (cond ((null fn) (throw tag condition)) |
---|
190 | ((fixnump fn) (throw tag (cons fn condition))) |
---|
191 | (t (funcall fn condition))))))))) |
---|
192 | |
---|
193 | (defvar *error-print-circle* nil) ; reset to T when we actually can print-circle |
---|
194 | |
---|
195 | |
---|
196 | |
---|
197 | ;;;*********************************** |
---|
198 | ;;;Mini-evaluator |
---|
199 | ;;;*********************************** |
---|
200 | |
---|
201 | (defun new-lexical-environment (&optional parent) |
---|
202 | (%istruct 'lexical-environment parent nil nil nil nil nil nil)) |
---|
203 | |
---|
204 | (defmethod make-load-form ((e lexical-environment) &optional env) |
---|
205 | (declare (ignore env)) |
---|
206 | nil) |
---|
207 | |
---|
208 | (defun new-definition-environment (&optional (type 'compile-file)) |
---|
209 | (%istruct 'definition-environment (list type) nil nil nil nil nil nil nil nil nil nil nil nil )) |
---|
210 | |
---|
211 | (defun definition-environment (env &optional clean-only &aux parent) |
---|
212 | (if (and env (not (istruct-typep env 'lexical-environment))) (report-bad-arg env 'lexical-environment)) |
---|
213 | (do* () |
---|
214 | ((or (null env) |
---|
215 | (listp (setq parent (lexenv.parent-env env))) |
---|
216 | (and clean-only (or (lexenv.variables env) (lexenv.functions env))))) |
---|
217 | (setq env parent)) |
---|
218 | (if (consp parent) |
---|
219 | env)) |
---|
220 | |
---|
221 | (defvar *symbol-macros* (make-hash-table :test #'eq)) |
---|
222 | |
---|
223 | (defun %define-symbol-macro (name expansion) |
---|
224 | (if (or (constant-symbol-p name) |
---|
225 | (proclaimed-special-p name)) |
---|
226 | (signal-program-error "Symbol ~s already globally defined as a ~A" |
---|
227 | name (if (constant-symbol-p name) |
---|
228 | 'constant |
---|
229 | 'variable))) |
---|
230 | (setf (gethash name *symbol-macros*) expansion) |
---|
231 | name) |
---|
232 | |
---|
233 | (defvar *macroexpand-hook* 'funcall |
---|
234 | "The value of this variable must be a designator for a function that can |
---|
235 | take three arguments, a macro expander function, the macro form to be |
---|
236 | expanded, and the lexical environment to expand in. The function should |
---|
237 | return the expanded form. This function is called by MACROEXPAND-1 |
---|
238 | whenever a runtime expansion is needed. Initially this is set to |
---|
239 | FUNCALL.") ; Should be #'funcall. |
---|
240 | ;(queue-fixup (setq *macroexpand-hook* #'funcall)) ; No it shouldn't. |
---|
241 | |
---|
242 | (defun %symbol-macroexpand-1 (sym env) |
---|
243 | (flet ((expand-it (expansion) |
---|
244 | (funcall *macroexpand-hook* |
---|
245 | (constantly expansion) |
---|
246 | sym |
---|
247 | env))) |
---|
248 | (if (and env (not (istruct-typep env 'lexical-environment))) |
---|
249 | (report-bad-arg env 'lexical-environment)) |
---|
250 | (do* ((env env (lexenv.parent-env env))) |
---|
251 | ((null env)) |
---|
252 | (if (istruct-typep env 'definition-environment) |
---|
253 | (let* ((info (assq sym (defenv.symbol-macros env)))) |
---|
254 | (if info |
---|
255 | (return-from %symbol-macroexpand-1 (values (expand-it (cdr info)) t)) |
---|
256 | (return))) |
---|
257 | (let* ((vars (lexenv.variables env))) |
---|
258 | (when (consp vars) |
---|
259 | (let* ((info (dolist (var vars) |
---|
260 | (if (eq (var-name var) sym) |
---|
261 | (return var))))) |
---|
262 | (when info |
---|
263 | (if (and (consp (setq info (var-expansion info))) |
---|
264 | (eq (%car info) :symbol-macro)) |
---|
265 | (return-from %symbol-macroexpand-1 (values (expand-it (%cdr info)) t)) |
---|
266 | (return-from %symbol-macroexpand-1 (values sym nil))))))))) |
---|
267 | ;; Look it up globally. |
---|
268 | (multiple-value-bind (expansion win) (gethash sym *symbol-macros*) |
---|
269 | (if win (values (expand-it expansion) t) (values sym nil))))) |
---|
270 | |
---|
271 | (defun macroexpand-all (form &optional (env (new-lexical-environment))) |
---|
272 | "Recursivly expand all macros in FORM." |
---|
273 | (flet ((mexpand (forms env) |
---|
274 | (mapcar (lambda (form) (macroexpand-all form env)) forms))) |
---|
275 | (macrolet ((destructuring-bind-body (binds form &body body) |
---|
276 | (if (eql '&body (first (last binds))) |
---|
277 | (let ((&body (gensym "&BODY"))) |
---|
278 | `(destructuring-bind ,(append (butlast binds) (list '&body &body)) |
---|
279 | ,form |
---|
280 | (multiple-value-bind (body decls) |
---|
281 | (parse-body ,&body env nil) |
---|
282 | ,@body))) |
---|
283 | `(destructuring-bind ,binds ,form ,@body)))) |
---|
284 | (multiple-value-bind (expansion win) |
---|
285 | (macroexpand-1 form env) |
---|
286 | (if win |
---|
287 | (macroexpand-all expansion env) |
---|
288 | (if (atom form) |
---|
289 | form |
---|
290 | (case (first form) |
---|
291 | (macrolet |
---|
292 | (destructuring-bind-body (macros &body) (rest form) |
---|
293 | (setf env (augment-environment env |
---|
294 | :macro (mapcar (lambda (macro) |
---|
295 | (destructuring-bind |
---|
296 | (name arglist &body body) |
---|
297 | macro |
---|
298 | (list name (enclose (parse-macro name arglist body env))))) |
---|
299 | macros) |
---|
300 | :declare (decl-specs-from-declarations decls))) |
---|
301 | (let ((body (mexpand body env))) |
---|
302 | (if decls |
---|
303 | `(locally ,@decls ,@body) |
---|
304 | `(progn ,@body))))) |
---|
305 | (symbol-macrolet |
---|
306 | (destructuring-bind-body (symbol-macros &body) (rest form) |
---|
307 | (setf env (augment-environment env :symbol-macro symbol-macros :declare (decl-specs-from-declarations decls))) |
---|
308 | (let ((body (mexpand body env))) |
---|
309 | (if decls |
---|
310 | `(locally ,@decls ,@body) |
---|
311 | `(progn ,@body))))) |
---|
312 | ((let let* compiler-let) |
---|
313 | (destructuring-bind-body (bindings &body) (rest form) |
---|
314 | `(,(first form) |
---|
315 | ,(mapcar (lambda (binding) |
---|
316 | |
---|
317 | (if (listp binding) |
---|
318 | (list (first binding) (macroexpand-all (second binding) env)) |
---|
319 | binding)) |
---|
320 | bindings) |
---|
321 | ,@decls |
---|
322 | ,@(mexpand body env)))) |
---|
323 | ((flet labels) |
---|
324 | (destructuring-bind-body (bindings &body) (rest form) |
---|
325 | `(,(first form) |
---|
326 | ,(mapcar (lambda (binding) |
---|
327 | (list* (first binding) (cdr (macroexpand-all `(lambda ,@(rest binding)) env)))) |
---|
328 | bindings) |
---|
329 | ,@decls |
---|
330 | ,@(mexpand body env)))) |
---|
331 | (nfunction (list* 'nfunction (second form) (macroexpand-all (third form) env))) |
---|
332 | (function |
---|
333 | (if (and (consp (second form)) |
---|
334 | (eql 'lambda (first (second form)))) |
---|
335 | (destructuring-bind (lambda arglist &body body&decls) |
---|
336 | (second form) |
---|
337 | (declare (ignore lambda)) |
---|
338 | (multiple-value-bind (body decls) |
---|
339 | (parse-body body&decls env) |
---|
340 | `(lambda ,arglist ,@decls ,@(mexpand body env)))) |
---|
341 | form)) |
---|
342 | ((eval-when the locally block return-from) |
---|
343 | (list* (first form) (second form) (mexpand (cddr form) env))) |
---|
344 | (setq |
---|
345 | `(setq ,@(loop for (name value) on (rest form) by #'cddr |
---|
346 | collect name |
---|
347 | collect (macroexpand-all value env)))) |
---|
348 | ((go quote) form) |
---|
349 | ((fbind with-c-frame with-variable-c-frame ppc-lap-function) |
---|
350 | (error "Unable to macroexpand ~S." form)) |
---|
351 | ((catch if load-time-value multiple-value-call multiple-value-prog1 progn |
---|
352 | progv tagbody throw unwind-protect) |
---|
353 | (cons (first form) (mexpand (rest form) env))) |
---|
354 | (t |
---|
355 | ;; need to check that (first form) is either fboundp or a local function... |
---|
356 | (cons (first form) (mexpand (rest form) env)))))))))) |
---|
357 | |
---|
358 | (defun macroexpand-1 (form &optional env &aux fn) |
---|
359 | "If form is a macro (or symbol macro), expand it once. Return two values, |
---|
360 | the expanded form and a T-or-NIL flag indicating whether the form was, in |
---|
361 | fact, a macro. ENV is the lexical environment to expand in, which defaults |
---|
362 | to the null environment." |
---|
363 | (declare (resident)) |
---|
364 | (if (and (consp form) |
---|
365 | (symbolp (%car form))) |
---|
366 | (if (setq fn (macro-function (%car form) env)) |
---|
367 | (values (funcall *macroexpand-hook* fn form env) t) |
---|
368 | (values form nil)) |
---|
369 | (if (and form (symbolp form)) |
---|
370 | (%symbol-macroexpand-1 form env) |
---|
371 | (values form nil)))) |
---|
372 | |
---|
373 | (defun macroexpand (form &optional env) |
---|
374 | "Repetitively call MACROEXPAND-1 until the form can no longer be expanded. |
---|
375 | Returns the final resultant form, and T if it was expanded. ENV is the |
---|
376 | lexical environment to expand in, or NIL (the default) for the null |
---|
377 | environment." |
---|
378 | (declare (resident)) |
---|
379 | (multiple-value-bind (new win) (macroexpand-1 form env) |
---|
380 | (do* ((won-at-least-once win)) |
---|
381 | ((null win) (values new won-at-least-once)) |
---|
382 | (multiple-value-setq (new win) (macroexpand-1 new env))))) |
---|
383 | |
---|
384 | (defun %symbol-macroexpand (form env &aux win won) |
---|
385 | ; Keep expanding until no longer a symbol-macro or no longer a symbol. |
---|
386 | (loop |
---|
387 | (unless (and form (symbolp form)) (return)) |
---|
388 | (multiple-value-setq (form win) (macroexpand-1 form env)) |
---|
389 | (if win (setq won t) (return))) |
---|
390 | (values form won)) |
---|
391 | |
---|
392 | (defun retain-lambda-expression (name lambda-expression env) |
---|
393 | (if (and (let* ((lambda-list (cadr lambda-expression))) |
---|
394 | (and (not (memq '&lap lambda-list)) |
---|
395 | (not (memq '&method lambda-list)) |
---|
396 | (not (memq '&lexpr lambda-list)))) |
---|
397 | (nx-declared-inline-p name env) |
---|
398 | (not (gethash name *nx1-alphatizers*)) |
---|
399 | ; A toplevel definition defined inside a (symbol-)macrolet should |
---|
400 | ; be inlineable. It isn't; call DEFINITION-ENVIRONMENT with a |
---|
401 | ; "clean-only" argument to ensure that there are no lexically |
---|
402 | ; bound macros or symbol-macros. |
---|
403 | (definition-environment env t)) |
---|
404 | lambda-expression)) |
---|
405 | |
---|
406 | |
---|
407 | (defun %cons-def-info (type &optional lfbits keyvect lambda specializers qualifiers) |
---|
408 | (ecase type |
---|
409 | (defun nil) |
---|
410 | (defmacro (setq lambda '(macro) lfbits nil)) ;; some code assumes lfbits=nil |
---|
411 | (defgeneric (setq lambda (list :methods))) |
---|
412 | (defmethod (setq lambda (list :methods (cons qualifiers specializers))))) |
---|
413 | (vector lfbits keyvect *loading-file-source-file* lambda)) |
---|
414 | |
---|
415 | (defun def-info.lfbits (def-info) |
---|
416 | (and def-info (svref def-info 0))) |
---|
417 | |
---|
418 | (defun def-info.keyvect (def-info) |
---|
419 | (and def-info (svref def-info 1))) |
---|
420 | |
---|
421 | (defun def-info.file (def-info) |
---|
422 | (and def-info (svref def-info 2))) |
---|
423 | |
---|
424 | (defun def-info.lambda (def-info) |
---|
425 | (let ((data (and def-info (svref def-info 3)))) |
---|
426 | (and (eq (car data) 'lambda) data))) |
---|
427 | |
---|
428 | (defun def-info.methods (def-info) |
---|
429 | (let ((data (and def-info (svref def-info 3)))) |
---|
430 | (and (eq (car data) :methods) (%cdr data)))) |
---|
431 | |
---|
432 | (defun def-info-with-new-methods (def-info new-methods) |
---|
433 | (unless (eq (def-info.type def-info) 'defgeneric) (error "Bug: not method info: ~s" def-info)) |
---|
434 | (if (eq new-methods (def-info.methods def-info)) |
---|
435 | def-info |
---|
436 | (let ((new (copy-seq def-info))) |
---|
437 | (setf (svref new 3) (cons :methods new-methods)) |
---|
438 | new))) |
---|
439 | |
---|
440 | (defun def-info.macro-p (def-info) |
---|
441 | (let ((data (and def-info (svref def-info 3)))) |
---|
442 | (eq (car data) 'macro))) |
---|
443 | |
---|
444 | (defun def-info.type (def-info) |
---|
445 | (if (null def-info) nil ;; means FTYPE decl or lap function |
---|
446 | (let ((data (svref def-info 3))) |
---|
447 | (ecase (car data) |
---|
448 | ((nil lambda) 'defun) |
---|
449 | (:methods 'defgeneric) |
---|
450 | (macro 'defmacro))))) |
---|
451 | |
---|
452 | (defparameter *one-arg-defun-def-info* (%cons-def-info 'defun (encode-lambda-list '(x)))) |
---|
453 | |
---|
454 | (defvar *compiler-warn-on-duplicate-definitions* t) |
---|
455 | |
---|
456 | (defun combine-function-infos (name old-info new-info) |
---|
457 | (let ((old-type (def-info.type old-info)) |
---|
458 | (new-type (def-info.type new-info))) |
---|
459 | (cond ((and (eq old-type 'defgeneric) (eq new-type 'defgeneric)) |
---|
460 | ;; TODO: Check compatibility of lfbits... |
---|
461 | ;; TODO: check that all methods implement defgeneric keys |
---|
462 | (let ((old-methods (def-info.methods old-info)) |
---|
463 | (new-methods (def-info.methods new-info))) |
---|
464 | (loop for new-method in new-methods |
---|
465 | do (if (member new-method old-methods :test #'equal) |
---|
466 | (when *compiler-warn-on-duplicate-definitions* |
---|
467 | (nx1-whine :duplicate-definition |
---|
468 | `(method ,@(car new-method) ,name ,(cdr new-method)) |
---|
469 | (def-info.file old-info) |
---|
470 | (def-info.file new-info))) |
---|
471 | (push new-method old-methods))) |
---|
472 | (def-info-with-new-methods old-info old-methods))) |
---|
473 | ((or (eq (or old-type 'defun) (or new-type 'defun)) |
---|
474 | (eq (or old-type 'defgeneric) (or new-type 'defgeneric))) |
---|
475 | (when (and old-type new-type *compiler-warn-on-duplicate-definitions*) |
---|
476 | (nx1-whine :duplicate-definition name (def-info.file old-info) (def-info.file new-info))) |
---|
477 | (or new-info old-info)) |
---|
478 | (t |
---|
479 | (when *compiler-warn-on-duplicate-definitions* |
---|
480 | (apply #'nx1-whine :duplicate-definition |
---|
481 | name |
---|
482 | (def-info.file old-info) |
---|
483 | (def-info.file new-info) |
---|
484 | (cond ((eq old-type 'defmacro) '("macro" "function")) |
---|
485 | ((eq new-type 'defmacro) '("function" "macro")) |
---|
486 | ((eq old-type 'defgeneric) '("generic function" "function")) |
---|
487 | (t '("function" "generic function"))))) |
---|
488 | new-info)))) |
---|
489 | |
---|
490 | (defun record-function-info (name info env) |
---|
491 | (let* ((definition-env (definition-environment env))) |
---|
492 | (if definition-env |
---|
493 | (let* ((defs (defenv.defined definition-env)) |
---|
494 | (already (if (listp defs) (assq name defs) (gethash name defs)))) |
---|
495 | (if already |
---|
496 | (setf (%cdr already) (combine-function-infos name (%cdr already) info)) |
---|
497 | (let ((new (cons name info))) |
---|
498 | (if (listp defs) |
---|
499 | (setf (defenv.defined definition-env) (cons new defs)) |
---|
500 | (setf (gethash name defs) new)))) |
---|
501 | info)))) |
---|
502 | |
---|
503 | |
---|
504 | ;;; This is different from AUGMENT-ENVIRONMENT. |
---|
505 | (defun note-function-info (name lambda-expression env) |
---|
506 | (let* ((info nil) |
---|
507 | (name (maybe-setf-function-name name))) |
---|
508 | (when (lambda-expression-p lambda-expression) |
---|
509 | (multiple-value-bind (lfbits keyvect) (encode-lambda-list (cadr lambda-expression) t) |
---|
510 | (setq info (%cons-def-info 'defun lfbits keyvect |
---|
511 | (retain-lambda-expression name lambda-expression env))))) |
---|
512 | (record-function-info name info env)) |
---|
513 | name) |
---|
514 | |
---|
515 | ; And this is different from FUNCTION-INFORMATION. |
---|
516 | (defun retrieve-environment-function-info (name env) |
---|
517 | (let ((defenv (definition-environment env))) |
---|
518 | (when defenv |
---|
519 | (let ((defs (defenv.defined defenv)) |
---|
520 | (sym (maybe-setf-function-name name))) |
---|
521 | (if (listp defs) (assq sym defs) (gethash sym defs)))))) |
---|
522 | |
---|
523 | (defun maybe-setf-function-name (name) |
---|
524 | (if (and (consp name) (eq (car name) 'setf)) |
---|
525 | (setf-function-name (cadr name)) |
---|
526 | name)) |
---|
527 | |
---|
528 | ;;; Must differ from -something-, but not sure what ... |
---|
529 | (defun note-variable-info (name info env) |
---|
530 | (let ((definition-env (definition-environment env))) |
---|
531 | (if definition-env (push (cons name info) (defenv.specials definition-env))) |
---|
532 | name)) |
---|
533 | |
---|
534 | (defun compile-file-environment-p (env) |
---|
535 | (let ((defenv (definition-environment env))) |
---|
536 | (and defenv (eq 'compile-file (car (defenv.type defenv)))))) |
---|
537 | |
---|
538 | (defun cheap-eval (form) |
---|
539 | (cheap-eval-in-environment form nil)) |
---|
540 | |
---|
541 | ; used by nfcomp too |
---|
542 | ; Should preserve order of decl-specs; it sometimes matters. |
---|
543 | (defun decl-specs-from-declarations (declarations) |
---|
544 | (let ((decl-specs nil)) |
---|
545 | (dolist (declaration declarations decl-specs) |
---|
546 | ;(unless (eq (car declaration) 'declare) (say "what")) |
---|
547 | (dolist (decl-spec (cdr declaration)) |
---|
548 | (setq decl-specs (nconc decl-specs (list decl-spec))))))) |
---|
549 | |
---|
550 | (defun cheap-eval-in-environment (form env &aux sym) |
---|
551 | (declare (resident)) |
---|
552 | (flet ((progn-in-env (body&decls parse-env base-env) |
---|
553 | (multiple-value-bind (body decls) (parse-body body&decls parse-env) |
---|
554 | (setq base-env (augment-environment base-env :declare (decl-specs-from-declarations decls))) |
---|
555 | (while (cdr body) |
---|
556 | (cheap-eval-in-environment (pop body) base-env)) |
---|
557 | (cheap-eval-in-environment (car body) base-env)))) |
---|
558 | (if form |
---|
559 | (cond ((symbolp form) |
---|
560 | (multiple-value-bind (expansion win) (macroexpand-1 form env) |
---|
561 | (if win |
---|
562 | (cheap-eval-in-environment expansion env) |
---|
563 | (let* ((defenv (definition-environment env)) |
---|
564 | (constant (if defenv (assq form (defenv.constants defenv)))) |
---|
565 | (constval (%cdr constant))) |
---|
566 | (if constant |
---|
567 | (if (neq (%unbound-marker-8) constval) |
---|
568 | constval |
---|
569 | (error "Can't determine value of constant symbol ~s" form)) |
---|
570 | (if (constant-symbol-p form) |
---|
571 | (%sym-global-value form) |
---|
572 | (symbol-value form))))))) |
---|
573 | ((atom form) form) |
---|
574 | ((eq (setq sym (%car form)) 'quote) |
---|
575 | (verify-arg-count form 1 1) |
---|
576 | (%cadr form)) |
---|
577 | ((eq sym 'function) |
---|
578 | (verify-arg-count form 1 1) |
---|
579 | (cond ((symbolp (setq sym (%cadr form))) |
---|
580 | (multiple-value-bind (kind local-p) |
---|
581 | (function-information sym env) |
---|
582 | (if (and local-p (eq kind :macro)) |
---|
583 | (error "~s can't be used to reference lexically defined macro ~S" 'function sym))) |
---|
584 | (%function sym)) |
---|
585 | ((and (consp sym) (eq (%car sym) 'setf) (consp (%cdr sym)) (null (%cddr sym))) |
---|
586 | (multiple-value-bind (kind local-p) |
---|
587 | (function-information sym env) |
---|
588 | (if (and local-p (eq kind :macro)) |
---|
589 | (error "~s can't be used to reference lexically defined macro ~S" 'function sym))) |
---|
590 | (%function (setf-function-name (%cadr sym)))) |
---|
591 | (t (%make-function nil sym env)))) |
---|
592 | ((eq sym 'nfunction) |
---|
593 | (verify-arg-count form 2 2) |
---|
594 | (%make-function (%cadr form) (%caddr form) env)) |
---|
595 | ((eq sym 'progn) (progn-in-env (%cdr form) env env)) |
---|
596 | ((eq sym 'setq) |
---|
597 | (if (not (%ilogbitp 0 (list-length form))) |
---|
598 | (verify-arg-count form 0 0)) ;Invoke a "Too many args" error. |
---|
599 | (let* ((sym nil) |
---|
600 | (val nil)) |
---|
601 | (while (setq form (%cdr form)) |
---|
602 | (setq sym (require-type (pop form) 'symbol)) |
---|
603 | (multiple-value-bind (expansion expanded) |
---|
604 | (macroexpand-1 sym env) |
---|
605 | (if expanded |
---|
606 | (setq val (cheap-eval-in-environment `(setf ,expansion ,(%car form)) env)) |
---|
607 | (set sym (setq val (cheap-eval-in-environment (%car form) env)))))) |
---|
608 | val)) |
---|
609 | ((eq sym 'eval-when) |
---|
610 | (destructuring-bind (when . body) (%cdr form) |
---|
611 | (when (or (memq 'eval when) (memq :execute when)) (progn-in-env body env env)))) |
---|
612 | ((eq sym 'if) |
---|
613 | (destructuring-bind (test true &optional false) (%cdr form) |
---|
614 | (cheap-eval-in-environment (if (cheap-eval-in-environment test env) true false) env))) |
---|
615 | ((eq sym 'locally) (progn-in-env (%cdr form) env env)) |
---|
616 | ((eq sym 'symbol-macrolet) |
---|
617 | (multiple-value-bind (body decls) (parse-body (cddr form) env) |
---|
618 | (progn-in-env body env (augment-environment env :symbol-macro (cadr form) :declare (decl-specs-from-declarations decls))))) |
---|
619 | ((eq sym 'macrolet) |
---|
620 | (let ((temp-env (augment-environment env |
---|
621 | :macro |
---|
622 | (mapcar #'(lambda (m) |
---|
623 | (destructuring-bind (name arglist &body body) m |
---|
624 | (list name (enclose (parse-macro name arglist body env) |
---|
625 | env)))) |
---|
626 | (cadr form))))) |
---|
627 | (progn-in-env (cddr form) temp-env temp-env))) |
---|
628 | ((and (symbolp sym) |
---|
629 | (compiler-special-form-p sym) |
---|
630 | (not (functionp (fboundp sym)))) |
---|
631 | (if (eq sym 'unwind-protect) |
---|
632 | (destructuring-bind (protected-form . cleanup-forms) (cdr form) |
---|
633 | (unwind-protect |
---|
634 | (cheap-eval-in-environment protected-form env) |
---|
635 | (progn-in-env cleanup-forms env env))) |
---|
636 | (funcall (%make-function nil `(lambda () (progn ,form)) env)))) |
---|
637 | ((and (symbolp sym) (macro-function sym env)) |
---|
638 | (if (eq sym 'step) |
---|
639 | (let ((*compile-definitions* nil)) |
---|
640 | (cheap-eval-in-environment (macroexpand-1 form env) env)) |
---|
641 | (cheap-eval-in-environment (macroexpand-1 form env) env))) |
---|
642 | ((or (symbolp sym) |
---|
643 | (and (consp sym) (eq (%car sym) 'lambda))) |
---|
644 | (let ((args nil)) |
---|
645 | (dolist (elt (%cdr form)) (push (cheap-eval-in-environment elt env) args)) |
---|
646 | (apply #'call-check-regs (if (symbolp sym) sym (%make-function nil sym env)) |
---|
647 | (nreverse args)))) |
---|
648 | (t (signal-simple-condition 'simple-program-error "Car of ~S is not a function name or lambda-expression." form)))))) |
---|
649 | |
---|
650 | |
---|
651 | (%fhave 'eval #'cheap-eval) |
---|
652 | |
---|
653 | |
---|
654 | |
---|
655 | |
---|
656 | (defun call-check-regs (fn &rest args) |
---|
657 | (declare (dynamic-extent args) |
---|
658 | (optimize (debug 3))) ; don't use any saved registers |
---|
659 | (let ((old-regs (multiple-value-list (get-saved-register-values)))) |
---|
660 | (declare (dynamic-extent old-regs)) |
---|
661 | (multiple-value-prog1 (apply fn args) |
---|
662 | (let* ((new-regs (multiple-value-list (get-saved-register-values))) |
---|
663 | (new-regs-tail new-regs)) |
---|
664 | (declare (dynamic-extent new-regs)) |
---|
665 | (unless (dolist (old-reg old-regs t) |
---|
666 | (unless (eq old-reg (car new-regs-tail)) |
---|
667 | (return nil)) |
---|
668 | (pop new-regs-tail)) |
---|
669 | (apply 'error "Registers clobbered applying ~s to ~s~%~@{~a sb: ~s, Was: ~s~%~}" |
---|
670 | fn args |
---|
671 | (mapcan 'list |
---|
672 | (let ((res nil)) |
---|
673 | (dotimes (i (length old-regs)) |
---|
674 | (push (format nil "save~d" i) res)) |
---|
675 | (nreverse res)) |
---|
676 | old-regs |
---|
677 | new-regs))))))) |
---|
678 | |
---|
679 | |
---|
680 | |
---|
681 | |
---|
682 | |
---|
683 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
---|
684 | ;; Stack frame accessors. |
---|
685 | |
---|
686 | ; Kinda scant, wouldn't you say ? |
---|
687 | |
---|
688 | |
---|
689 | ;end of L1-readloop.lisp |
---|
690 | |
---|