1 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; This software is derived from the CMU CL system, which was
5 ;;;; written at Carnegie Mellon University and released into the
6 ;;;; public domain. The software is in the public domain and is
7 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
8 ;;;; files for more information.
10 (in-package "SB-INTERPRETER")
12 ;;; Return a THE form that wraps EXPRESSION, but if CTYPE is NIL,
13 ;;; just return EXPRESSION.
14 (defun cast-to (ctype expression
)
15 (aver (neq ctype
*universal-type
*)) ; should never store this
16 (if ctype
`(the ,ctype
,expression
) expression
))
18 ;;; Given a list of FORMS, return a vector of SEXPRs that will eval those.
19 ;;; There "should" be more than one SEXPR because any PROGN-like form with
20 ;;; less than 2 subforms should have the singleton (or NIL) form lifted
21 ;;; to its containing SEXPR by that SEXPR's digester. Lifting happens
22 ;;; automatically when you use %PROGN to build a list of subforms.
23 ;;; i.e. (PROGN (PROGN FOO)) == FOO after twice lifting.
25 ;;; Pathological silly examples:
26 ;;; 1) Loop using a circular list does not work.
27 ;;; This works ok in purely recursive-descent EVAL, but is precluded
28 ;;; by VECTOR-OF-SEXPR asking for list-length of the PROGN form.
29 ;;; (BLOCK X (let ((I 0)) .
30 ;;; #1=((IF (< (INCF I) 10) (PRINT I) (RETURN-FROM X)) . #1#)))
32 ;;; 2) Factorial by recursing in syntax rather than semantics works
33 ;;; because it's CAR circular, not CDR circular.
34 ;;; (#1=(LAMBDA (N) (IF (ZEROP N) 1 (* N (#1# (1- N))))) 6)
35 ;;; Athough it forces an awful lot of consing on each recursion.
36 (defun vector-of-sexpr (forms)
37 (let ((n (list-length forms
)))
38 (cond ((null n
) (error "Circular form"))
39 ((eql n
0) '#()) ; all empty vectors are the same to me
41 (let ((a (make-array n
)))
42 (loop for i from
0 for elt in forms
43 do
(setf (svref a i
) (%sexpr elt
)))
46 ;;; Return a handler for a SEXPR which reads SYMBOL in ENV.
47 ;;; If TYPE is non-nil, it is a CTYPE to check against.
48 ;;; Unlike for handlers defined with DEFSPECIAL, this one both
49 ;;; preprocesses the sexpr *and* evals the symbol immediately.
51 ;;; Todo: some re-testing of (INFO :VARIABLE :KIND) can be eliminated if
52 ;;; we just touch the *globaldb-cookie* whenever a global macro or symbol-macro
53 ;;; is defined or redefined (incl. a global variable changing its :KIND).
54 ;;; This might be more efficient than, and is definitely simpler than, the
55 ;;; checks below. On the other hand, we only need to kill memoized data
56 ;;; when strange stuff happens that can't be anticipated, of which there
57 ;;; are vanishingly few reasons now.
59 (defun symeval (symbol env sexpr
)
60 (binding* (((binding kind frame-ptr expansion
) (find-lexical-var env symbol
))
61 (type (var-type-assertion env symbol binding
:read
)))
62 (if kind
; lexically apparent binding (possibly special or macro)
64 ;; digest-form would lose the type constraint, so pass it in using
65 ;; a THE wrapper. We use the same hack as in the compiler:
66 ;; THE is supposed to take a type-specifier but we allow a CTYPE
67 ;; to avoid unparsing and reparsing.
68 (digest-form (cast-to type
(symexpand env symbol expansion
))
71 (setf (sexpr-handler sexpr
)
72 (if (eq kind
:special
)
73 (specvar-reffer symbol type
)
74 (lexvar-reffer frame-ptr type
)))
75 (%dispatch sexpr env
))) ; DISPATCH would be fine but for the noise
76 (case (info :variable
:kind symbol
)
78 ;; Interestingly it's not even a style warning to redefine
79 ;; a global symbol-macro.
80 (let* ((expanded-form (symexpand env symbol
))
81 (expanded-sexpr (%sexpr
(cast-to type expanded-form
))))
84 (if (and type
(neq type
*universal-type
*))
85 ;; Don't need to additionally capture the original expansion
86 ;; because it is available as the third subform of (THE).
87 (hlambda SYMEVAL
(symbol expanded-sexpr
) (env sexpr
)
88 (multiple-value-bind (x winp
)
89 (info :variable
:macro-expansion symbol
)
90 (if (and winp
(eq (third (sexpr-form expanded-sexpr
)) x
))
91 (dispatch expanded-sexpr env
)
92 (digest-form symbol env sexpr
))))
93 (hlambda SYMEVAL
(symbol expanded-sexpr
) (env sexpr
)
94 (multiple-value-bind (x winp
)
95 (info :variable
:macro-expansion symbol
)
96 (if (and winp
(eq (sexpr-form expanded-sexpr
) x
))
97 (dispatch expanded-sexpr env
)
98 (digest-form symbol env sexpr
))))))
99 (dispatch expanded-sexpr env
)))
101 ;; can there be a type restriction?
102 (let ((info (info :variable
:alien-info symbol
)))
103 (setf (sexpr-handler sexpr
)
104 (hlambda SYMEVAL
(symbol info
) (env sexpr
)
105 (if (eq (info :variable
:alien-info symbol
) info
)
107 (digest-form symbol env sexpr
))))
110 ;; The PARANOID argument to SPECVAR-REFFER is not a safety-related
111 ;; quality - it affects convenience, which is considered inversely
112 ;; correlated to SPEED.
113 (setf (sexpr-handler sexpr
)
114 (specvar-reffer symbol type
(< (policy env speed
) 2)))
115 (%dispatch sexpr env
)))))) ; DISPATCH would be fine but for the noise
117 (defun immediate-setq-1 (symbol newval env
)
118 (binding* (((binding kind frame-ptr value
) (find-lexical-var env symbol
))
119 (type (var-type-assertion env symbol binding
:write
)))
120 (flet ((setf-it (expansion)
121 (%eval
`(setf ,expansion
,(cast-to type newval
)) env
))
123 (let ((newval (%eval newval env
)))
125 (unless (itypep newval type
)
126 (typecheck-fail symbol newval type
)))
128 (if kind
; lexically apparent binding (possibly special or macro)
130 (setf-it (symexpand env symbol value
))
131 (let ((newval (eval-it)))
132 (if (eq kind
:special
)
134 (setf (%cell-ref env frame-ptr
) newval
))))
135 (case (info :variable
:kind symbol
)
137 (setf-it (symexpand env symbol
)))
140 (declare (muffle-conditions compiler-note
)) ; can't open-code
141 (setf (%heap-alien
(info :variable
:alien-info symbol
))
143 (t ; everything else - no need to check for constants
144 ;; as the runtime will signal an error.
145 (set symbol
(eval-it))))))))
147 ;;; Perform a SETQ, verifying that the variable still is of the kind it was
148 ;;; when the form was digested.
149 ;;; Like SYMEVAL and unlike handlers defined with DEFSPECIAL, this one both
150 ;;; preprocesses the sexpr *and* performs its action.
151 ;;; Todo: figure out what global changes in :KIND are actually possible,
152 ;;; such as :macro -> :constant. Some of them generate continuable errors
153 ;;; and some not; but by hacking on globaldb you can do anything you want.
154 ;;; The globaldb cookie will take care of any loose ends.
155 (defun deferred-setq-1 (symbol newval env sexpr
)
156 (binding* (((binding kind frame-ptr expansion
) (find-lexical-var env symbol
))
157 (type (var-type-assertion env symbol binding
:write
)))
158 (aver (neq type
*universal-type
*))
159 (if kind
; lexically apparent binding (possibly special or macro)
161 ;; symbol-macros are handled as if the form were SETF
162 (digest-form `(setf ,(symexpand env symbol expansion
)
163 ,(cast-to type newval
)) env sexpr
)
164 (let ((newval (%sexpr newval
)))
165 (setf (sexpr-handler sexpr
)
166 (if (eq kind
:special
)
167 ;; It is unusual to more restrictively constrain a
168 ;; special var than by its globally declaimed type
169 ;; which is checked by SET, but check again anyway.
171 (hlambda SETQ
(newval symbol type
) (env)
172 (let ((newval (dispatch newval env
)))
173 (if (itypep newval type
)
175 (typecheck-fail symbol newval type
))))
176 (hlambda SETQ
(newval symbol
) (env)
177 (set symbol
(dispatch newval env
))))
178 (lexvar-setter frame-ptr newval type
)))
179 (%dispatch sexpr env
)))
180 (case (info :variable
:kind symbol
)
182 (digest-form `(setf ,(symexpand env symbol
) ,(cast-to type newval
))
184 (%dispatch sexpr env
))
186 (let ((info (info :variable
:alien-info symbol
))
187 (newval (%sexpr newval
)))
188 ;; don't care that we're unable to optimize %HEAP-ALIEN
189 (setf (sexpr-handler sexpr
)
190 (hlambda SETQ
(newval symbol info
) (env sexpr
)
191 (if (eq (info :variable
:alien-info symbol
) info
)
192 (locally (declare (muffle-conditions compiler-note
))
193 (setf (%heap-alien info
) (dispatch newval env
)))
194 (digest-form (sexpr-form sexpr
) env sexpr
))))
195 (%dispatch sexpr env
)))
197 ;; FIXME: missing type check
198 (let ((newval (%sexpr newval
)))
199 (setf (sexpr-handler sexpr
)
200 (hlambda SETQ
(newval symbol
) (env sexpr
)
201 (if (member (info :variable
:kind symbol
) '(:alien
:macro
))
202 (digest-form (sexpr-form sexpr
) env sexpr
)
203 (set symbol
(dispatch newval env
)))))
204 (set symbol
(dispatch newval env
))))))))
206 ;; Return a handler for, but do not evaluate, a list of FORMS.
207 (defun digest-progn (forms)
208 (cond ((not forms
) (return-constant nil
))
209 ((not (cdr forms
)) (handler #'digest-form
(first forms
)))
211 (let ((one (%sexpr
(first forms
))) (two (%sexpr
(second forms
))))
212 (hlambda PROGN
(one two
) (env)
213 (dispatch one env
) (dispatch two env
))))
214 ((not (list-length forms
))
215 (error "Circular list"))
217 ;; Convert to a vector of sexprs.
218 ;; Alternatively, could express in terms of prog2 and progn,
219 ;; which would allow this evaluator to handle circular forms,
220 ;; albeit with great inefficiency.
221 (let ((forms (nreverse (vector-of-sexpr forms
))))
222 (hlambda PROGN
(forms) (env)
223 (declare (simple-vector forms
))
224 (let ((i (1- (length forms
))))
225 (loop (dispatch (svref forms i
) env
)
226 (if (zerop (decf i
)) (return))))
227 (dispatch (svref forms
0) env
))))))
229 ;;; Some simple handlers
231 (defun eval-progn (body env
) ; Immediate-mode handler for PROGN
232 (let ((previous-exp nil
))
235 (%eval previous-exp env
))
236 (setf previous-exp exp
))
237 ;; Preserve tail call
238 (%eval previous-exp env
)))
240 (defspecial progn
(&rest forms
)
241 :immediate
(env) (eval-progn forms env
)
242 :deferred
() (digest-progn forms
))
244 (defspecial quote
(object)
246 :deferred
() (return-constant object
))
248 ;;; Special operator THE can use local-call for its helper functions.
249 (flet ((enforce-values-types (type &rest values
)
250 (declare (optimize (safety 0)))
251 ;; Check VALUES against TYPE and return all the values.
252 ;; This should not cons except on error.
253 ;; NTH on a &REST list is random-access, not a pointer traversal.
254 ;; [cf. comment in src/code/numbers.lisp re. "very clever"
255 ;; versus "charmingly naive"]
256 (let ((i 0) (n (length values
)) (rest (values-type-rest type
)))
259 (dolist (x (values-type-required type
))
260 (if (or (>= i n
) (not (itypep (nth i values
) x
)))
263 (dolist (x (values-type-optional type
))
264 (cond ((>= i n
) (go done
))
265 ((not (itypep (nth i values
) x
))
268 (if (= i n
) (go done
))
269 (if (not rest
) (go fail
))
271 (unless (itypep (nth i values
) rest
)
273 (if (< (incf i
) n
) (go rest
))
275 (return-from enforce-values-types
(apply #'values values
))
277 ;; Punting keeps the consing out of this function so that I can
278 ;; determine that the non-consing claim remains true.
279 (apply #'values-typecheck-fail type values
)))
281 ;; Check the first of VALUES against TYPE and return all values.
282 ;; Unlike ENFORCE-TYPE, this returns all VALUES though only one
283 ;; was expected. This should not cons except on error.
284 (enforce-single-type (type &rest values
)
286 (error "~S received no values"
287 (list 'the
(specifier-from-checkfun type
))))
288 ((itypep (first values
) type
)
289 (apply #'values values
))
292 :datum
(first values
)
293 :expected-type
(specifier-from-checkfun type
)))))
295 (parse-type (spec-or-obj)
297 (if (ctype-p spec-or-obj
)
299 (values-specifier-type spec-or-obj
)))))
301 ;; If a THE form returns multiple values we have to propagate all of them
302 ;; even if it was not (THE (VALUES ...))
303 ;; If TYPE contains an unknown type, it'll be allowed it as long as it
304 ;; is not reached. (typep 3 '(and (not integer) no-such-type)) returns NIL.
305 (defspecial the
(type-specifier form
)
307 ;; If speed is more important than safety, don't process THE forms.
308 (if (policy env
(> speed safety
))
310 (let ((type (parse-type type-specifier
)))
311 (multiple-value-call (if (sb-kernel::%values-type-p type
)
312 #'enforce-values-types
313 #'enforce-single-type
)
314 type
(%eval form env
))))
316 (if (policy env
(> speed safety
))
317 (handler #'digest-form form
)
318 (let ((type (parse-type type-specifier
)))
319 (if (eq type
*universal-type
*) ; don't type-check if T
320 (handler #'digest-form form
)
321 (let ((form (%sexpr form
)))
322 (if (sb-kernel::%values-type-p type
)
323 (hlambda THE
/MULTI
(type form
) (env)
324 (multiple-value-call #'enforce-values-types
325 type
(dispatch form env
)))
326 (hlambda THE
/SINGLE
(type form
) (env)
327 (multiple-value-call #'enforce-single-type
328 type
(dispatch form env
))))))))))
330 ;;; Even though TRULY-THE has a macroexpander into THE, it would
331 ;;; be suboptimal to use that because it would force type-checking
332 ;;; when the entire point is to skip checking.
333 (defspecial truly-the
(type-specifier form
)
334 ;; Perhaps this should at least parse the specifier?
335 :immediate
(env) type-specifier
; ignoring it
337 :deferred
() type-specifier
; ignoring it
338 (handler #'digest-form form
))
340 (defspecial if
(test then
&optional else
)
341 :immediate
(env) (if (%eval test env
) (%eval then env
) (%eval else env
))
343 ;; Many common idioms (builtin or otherwise) expand to IF with
344 ;; only one consequent.
345 (let ((test (%sexpr test
)) (then (%sexpr then
)) (else (%sexpr else
)))
346 (cond ((and then else
)
347 (hlambda IF
(test then else
) (env)
348 (if (dispatch test env
) (dispatch then env
) (dispatch else env
))))
349 ((and then
(not else
))
350 (hlambda IF
(test then
) (env)
351 (if (dispatch test env
) (dispatch then env
))))
352 ((and (not then
) else
)
353 (hlambda IF
(test else
) (env)
354 (if (dispatch test env
) nil
(dispatch else env
))))
356 ;; Does (IF (HAIRY-TEST) nil nil) actually occur in real life?
357 (hlambda IF
(test) (env)
361 (defspecial catch
(tag &body forms
)
362 :immediate
(env) (catch (%eval tag env
) (eval-progn forms env
))
364 (let ((tag (%sexpr tag
)) (forms (%progn forms
)))
365 (hlambda CATCH
(tag forms
) (env)
366 (catch (dispatch tag env
) (dispatch forms env
)))))
368 (defspecial throw
(tag result
)
369 :immediate
(env) (throw (%eval tag env
) (%eval result env
))
371 (let ((tag (%sexpr tag
)) (result (%sexpr result
)))
372 (hlambda THROW
(tag result
) (env)
373 (throw (dispatch tag env
) (dispatch result env
)))))
375 (defspecial unwind-protect
(protected-form &rest cleanup-forms
)
377 (unwind-protect (%eval protected-form env
)
378 (eval-progn cleanup-forms env
))
380 (let ((protected-form (%sexpr protected-form
))
381 (cleanup-forms (%progn cleanup-forms
)))
382 (hlambda UNWIND-PROTECT
(protected-form cleanup-forms
) (env)
383 (unwind-protect (dispatch protected-form env
)
384 (dispatch cleanup-forms env
)))))
386 (defspecial progv
(symbols values
&body forms
)
388 (progv (%eval symbols env
) (%eval values env
) (eval-progn forms env
))
390 (let ((symbols (%sexpr symbols
)) (values (%sexpr values
))
391 (forms (%progn forms
)))
392 (hlambda PROGV
(symbols values forms
) (env)
393 (progv (dispatch symbols env
) (dispatch values env
)
394 (dispatch forms env
)))))
396 (defspecial load-time-value
(form &optional read-only-p
)
397 (declare (ignore read-only-p
))
398 :immediate
() (%eval form nil
)
399 ;; full-eval used the enviroment here. CLHS says use the null environment.
400 ;; I wonder if the true intent was to use the macro and symbol-macro
401 ;; environment but otherwise have no lexical bindings visible?
402 ;; In other words, is this allowed?
403 ;; (macrolet ((foo (x) `(car ,x))) (load-time-value (foo (thing)))
404 ;; The compiler seems not to think so, but CLHS is ambiguous.
405 :deferred
() (return-constant (%eval form nil
)))
407 (defspecial multiple-value-call
(function &rest forms
)
409 (apply (%eval function env
)
410 (loop for form in forms
411 nconc
(multiple-value-list (%eval form env
))))
412 ;; Todo: specialize when FUNCTION satisfies QUOTED-FUNCTION-NAME-P ?
415 (handler #'digest-form
`(funcall ,function
))
416 (let ((function (%sexpr function
)))
417 (cond ((not (cdr forms
))
418 (let ((form (%sexpr
(car forms
))))
419 (hlambda MULTIPLE-VALUE-CALL
(function form
) (env)
420 (locally (declare (muffle-conditions compiler-note
))
421 (multiple-value-call (dispatch function env
)
422 (dispatch form env
))))))
424 (let ((a (%sexpr
(car forms
))) (b (%sexpr
(cadr forms
))))
425 (hlambda MULTIPLE-VALUE-CALL
(function a b
) (env)
426 (locally (declare (muffle-conditions compiler-note
))
427 (multiple-value-call (dispatch function env
)
428 (dispatch a env
) (dispatch b env
))))))
430 (let ((forms (vector-of-sexpr forms
)))
431 (hlambda MULTIPLE-VALUE-CALL
(function forms
) (env)
432 (locally (declare (muffle-conditions compiler-note
))
433 (apply (dispatch function env
)
434 (loop for x across
(the simple-vector forms
)
435 nconc
(multiple-value-list
436 (dispatch x env
))))))))))))
438 (defspecial multiple-value-prog1
(first-form &rest more-forms
)
440 (multiple-value-prog1 (%eval first-form env
) (eval-progn more-forms env
))
442 (let ((first-form (%sexpr first-form
)) (more-forms (%progn more-forms
)))
443 (hlambda MULTIPLE-VALUE-PROG1
(first-form more-forms
) (env)
444 (multiple-value-prog1 (dispatch first-form env
)
445 (dispatch more-forms env
)))))
447 (defspecial eval-when
(situations &body body
&aux ct lt ex
)
448 ;; FIXME: this might signal a compiler error instead of an IP-ERROR.
449 (multiple-value-setq (ct lt ex
)
450 (parse-eval-when-situations situations
))
451 :immediate
(env) (if ex
(eval-progn body env
))
452 :deferred
() (if ex
(digest-progn body
) (return-constant nil
)))
454 ;;; BLOCK and RETURN-FROM
455 (macrolet ((eval-it (eval-fn)
456 ;; An ENV can not represent itself as a catch point, because
457 ;; freezing changes its identity. Use a fresh cons cell instead.
458 `(let ((env (make-block-env env
(list name
) nil
*vacuous-decls
*)))
459 (catch (env-payload env
) (,eval-fn forms env
)))))
460 (defspecial block
(name &rest forms
)
461 (unless (symbolp name
)
462 (ip-error "~@<The block name ~S is not a symbol.~:@>" name
))
463 :immediate
(env) (eval-it eval-progn
)
465 (let ((forms (%progn forms
)))
466 (hlambda BLOCK
(name forms
) (env) (eval-it dispatch
)))))
468 ;;; Establishing a handler to catch SIMPLE-CONTROL-ERROR would incorrectly
469 ;;; alter the handler chain as established by user code, in addition
470 ;;; to being needlessly slow. The code in 'interr' can recognize when
471 ;;; an invalid control transfer was initiated by interpreted code,
472 ;;; and it adjusts the error message accordingly.
473 (macrolet ((eval-it (tag eval-fn
)
474 `(throw ,tag
(,eval-fn result env
))))
475 (defspecial return-from
(name &optional result
&aux
(block-env env
) (depth 0))
476 ;; unfortunately the only way to write this OAOO is with an &AUX var
477 (declare (fixnum depth
))
478 (unless (symbolp name
)
479 (ip-error "~@<The block name ~S is not a symbol.~:@>" name
))
480 (loop (if (null block-env
)
481 (ip-error "~@<Return for unknown block: ~S~:@>" name
))
482 (when (eq (typecase block-env
483 (lambda-env (car (lambda-env-block block-env
)))
484 (block-env (car (env-payload block-env
)))
488 (setq block-env
(env-parent block-env
)))
490 (eval-it (if (lambda-env-p block-env
)
491 (lambda-env-block block-env
) (env-payload block-env
))
494 (let ((result (%sexpr result
)))
495 (if (lambda-env-p block-env
)
496 (hlambda RETURN-FROM
(depth result
) (env)
497 (eval-it (lambda-env-block (env-ancestor env depth
)) dispatch
))
498 (hlambda RETURN-FROM
(depth result
) (env)
499 (eval-it (env-payload (env-ancestor env depth
)) dispatch
))))))
503 (defun map-into-vector-reversed (f list length
)
504 (let ((output (make-array length
)) (i length
))
505 (loop (if (minusp (decf i
)) (return))
506 (setf (svref output i
) (funcall f
(pop list
))))
509 ;;; A TAGBODY is parsed into a vector of expressions each of which is either
510 ;;; a SEXPR, an unconditional GO, or a conditional GO. Preprocessing speeds
511 ;;; up (DOTIMES (I N) ..) by at least a factor of 10, especially the hoisting
512 ;;; of conditional GO, which would otherwise entail throwing to the catch point
513 ;;; and restarting. Such catch/throw is necessary when the GO is embedded in
514 ;;; deeper subforms, but picking off the shallow cases is easy.
516 (defun parse-tagbody (body env
)
517 (collect ((tags) (new-body))
518 ;; First pass: just collect the tags
521 (cond ((consp item
) (setq any-forms t
))
522 ((or (symbolp item
) (integerp item
))
523 (if (assoc item
(tags))
524 (ip-error "Duplicate tag ~S in tagbody" item
)
527 (ip-error "Bad thing to appear in a tagbody: ~S" item
))))
528 (cond ((not any-forms
)
529 (return-from parse-tagbody
(return-constant nil
)))
531 (return-from parse-tagbody
(digest-progn `(,@body nil
))))))
533 (and (typep form
'(cons (eql go
) (cons t null
)))
534 (assoc (cadr form
) (tags)))))
535 ;; Second pass: rewrite conditioned GO forms appearing directly in
536 ;; this tagbody which transfer control to a tag in this tagbody.
537 ;; Local function bindings for WHEN/UNLESS will inhibit this.
538 (dolist (item (unless (or (find-lexical-fun env
'when
)
539 (find-lexical-fun env
'unless
))
541 (or (and (typep item
'(cons (eql if
)
542 (cons t
(cons t
(or null
(cons t null
))))))
543 ;; Look for IF forms in which either consequent is a branch.
544 (destructuring-bind (test then
&optional else
) (cdr item
)
545 (multiple-value-bind (op branch fallthru
)
546 (cond ((go-p then
) (values 'when then else
))
547 ((go-p else
) (values 'unless else then
)))
549 (new-body `(,op
,test
,branch
))
552 (if (atom fallthru
) `(progn ,fallthru
) fallthru
)))
554 ;; Transform a WHEN or UNLESS if there is more than one subform
555 ;; in the consequent, and the last subform is a control transfer.
556 ;; This is necessary because the tagbody handler recognizes
557 ;; only (WHEN|UNLESS c (GO tag)) as a fast conditional GO.
558 ;; (WHEN (TEST) (stmt1) ... (stmtN) (GO tag)) becomes
559 ;; (WHEN (WHEN (TEST) (stmt1) ... (stmtN) T) (GO tag))
560 ;; (UNLESS (TEST) (stmt1) ... (stmtN) (GO tag)) becomes
561 ;; (WHEN (UNLESS (TEST) (stmt1) ... (stmtN) T) (GO tag))
562 (and (typep item
'(cons (member when unless
)))
564 (awhen (go-p (car (last item
)))
566 `(when (,(car item
) ,(cadr item
) ,@(butlast (cddr item
)) t
)
568 (new-body item
))) ; everything else
569 (let ((body (or (new-body) body
)))
570 ;; Next assign tags their indices. Interleaving this with the final
571 ;; pass would need a fixup step for forward branches, so do this first.
575 (rplacd (assoc item
(tags)) line-num
)
577 ;; Collect the executable statements.
579 (lines (make-array (- (1+ (length body
)) (length (tags))))))
580 (setf (aref lines
0) (tags))
581 (dolist (form body
(handler #'eval-tagbody lines
))
583 (setf (aref lines
(prog1 line-num
(incf line-num
)))
584 (acond ((go-p form
) (cdr it
)) ; just the line number
585 ((and (typep form
'(cons (member when unless
)))
586 (singleton-p (cddr form
))
588 (let ((line (cdr it
)))
589 (cons (%sexpr
(second form
))
590 (if (eq (car form
) 'when
) line
(- line
)))))
591 (t (%sexpr form
)))))))))))
593 (defun eval-tagbody (code env sexpr
)
594 (declare (simple-vector code
) (ignore sexpr
)
595 #.
+handler-optimize
+)
596 ;; Cons a fresh object as the catch tag.
597 (let* ((env (make-tagbody-env env
(list (svref code
0)) nil
*vacuous-decls
*))
598 ;; If the element 1 is an unconditional GO label, such as in a
599 ;; trailing-test loop, then START is that value, otherwise it is 1.
600 (start (let ((elt (svref code
1)))
601 (if (fixnump elt
) elt
1)))
603 (declare (index start end
))
606 (catch (env-payload env
)
607 (let ((line-num start
))
608 (declare (index line-num
))
610 (when (>= line-num end
)
614 (let ((line (svref code line-num
)))
615 (cond ((%instancep line
)
618 ((fixnump line
) line
) ; unconditional GO
619 (t ; otherwise, a conditional GO
620 (let ((test (dispatch (car line
) env
))
621 (target (the fixnum
(cdr line
))))
623 (if test
(1+ line-num
) (- target
))
624 (if test target
(1+ line-num
))))))))))))
625 (if (>= start end
) (return)))))
627 ;;; There is no immediate mode for TAGBODY because its primary use is for loops,
628 ;;; which benefit from preprocessing even when used at toplevel and discarded.
629 (defspecial tagbody
(&rest body
)
630 :deferred
(env) (parse-tagbody body env
))
632 ;;; As a corollary to above, there's no immediate mode processor for GO.
635 (let ((depth 0) cell
)
636 (declare (fixnum depth
))
638 (null (ip-error "~@<Attempt to GO to nonexistent tag: ~S~:@>" tag
))
640 (when (setq cell
(assoc tag
(car (env-payload env
)))) (return))))
641 (setq env
(env-parent env
)) (incf depth
))
642 (let ((index (make-frame-ptr (cdr cell
) depth
)))
643 (hlambda GO
(index) (env)
644 (throw (env-payload (env-ancestor env index
))
645 (frame-ptr-cell-index index
))))))
647 ;;; FIXME: this special case makes it a bit difficult to turn the intepreter
648 ;;; into exactly a minimal compiler, since SETQ always wants to do something
649 ;;; that has an immediate effect.
650 (defun eval-setq (assignments env sexpr
) ; SEXPR is nil for immediate mode
651 (cond ((not assignments
)
653 (setf (sexpr-handler sexpr
) (return-constant nil
)))
655 ((oddp (list-length assignments
)) (ip-error "Bad syntax in SETQ"))
657 (let ((form `(progn ,@(loop for
(sym val
) on assignments by
#'cddr
658 collect
`(setq ,sym
,val
)))))
660 (digest-form form env sexpr
)
663 (let ((sym (first assignments
)) (val (second assignments
)))
664 (unless (symbolp sym
)
665 (ip-error "~S is not a symbol" sym
))
667 (deferred-setq-1 sym val env sexpr
)
668 (immediate-setq-1 sym val env
))))))
670 ;;;; Comment from 'full-eval'
671 ;;; The expansion of SB-SYS:WITH-PINNED-OBJECTS on GENCGC uses some
672 ;;; VOPs which can't be reasonably implemented in the interpreter. So
673 ;;; we special-case the macro.
675 ;;; Unlikely to appear at toplevel, so should not occur in :IMMEDIATE mode.
676 ;;; If it does, just dispatch to the deferred handler.
677 (defspecial sb-sys
:with-pinned-objects
(objects &body forms
)
679 (let ((objects (mapcar #'%sexpr objects
)) (forms (%progn forms
)))
680 (hlambda sb-sys
:with-pinned-objects
(objects forms
) (env)
681 (labels ((recurse (list forms
)
684 (sb-sys:with-pinned-objects
((car list
))
685 (recurse (cdr list
) forms
)))))
686 (recurse objects forms
)))))
688 ;;; Now for the complicated stuff, starting with the simplest
689 ;;; of the complicated ...
691 (defun digest-locally (env body
)
692 (multiple-value-bind (forms decls
) (parse-body body nil t
)
695 (let* ((specials (free-specials env decls
))
696 (scope (process-typedecls
697 (%make-local-scope decls
(new-policy env decls
)
698 (%progn forms
) specials
)
700 (hlambda LOCALLY
(scope) (env)
701 (enforce-types scope env
)
702 (dispatch (local-scope-body scope
)
703 (make-basic-env env nil
704 (local-scope-specials scope
) scope
)))))))
706 (defspecial locally
(&body body
)
708 (multiple-value-bind (forms decls
) (parse-body body nil t
)
709 (let* ((specials (free-specials env decls
))
710 (scope (process-typedecls
711 (make-decl-scope decls
(new-policy env decls
))
713 (enforce-types scope env
)
714 (eval-progn forms
(make-basic-env env nil specials scope
))))
715 :deferred
(env) (digest-locally env body
))
717 (defun parse-symbol-macrolet (env bindings body wrap-fn
)
718 (multiple-value-bind (forms decls
) (parse-body body nil t
)
719 (binding* (((specials n-specials
) (declared-specials decls
))
720 (n-macros (length bindings
))
721 (symbols (make-array (+ n-macros n-specials
)))
722 (expansions (make-array n-macros
))
723 (checker (sb-c::symbol-macrolet-definitionize-fun
:eval
))
725 (with-package-lock-context (env)
726 (dolist (binding bindings
)
727 (let* ((binding (funcall checker binding
))
728 (symbol (car binding
))
729 (expansion (cddr binding
)))
730 (setf (svref symbols
(incf index
)) (list symbol
)
731 (svref expansions index
) expansion
)))
732 (assert-declarable-as-special env specials
))
733 (dolist (symbol specials
)
734 (if (find symbol symbols
:end n-macros
:key
#'car
)
735 (ip-error "~S can not be both a symbol-macro and special" symbol
))
736 (setf (svref symbols
(incf index
)) (find-special-binding env symbol
)))
738 (%make-symbol-macro-scope decls
(new-policy env decls
)
739 symbols expansions
(funcall wrap-fn forms
))
740 env n-macros symbols
))))
742 (macrolet ((new-env ()
743 `(make-symbol-macro-env env
744 (symbol-macro-expansions scope
)
745 (symbol-macro-symbols scope
)
747 (defspecial symbol-macrolet
(defs &rest body
)
749 (let ((scope (parse-symbol-macrolet env defs body
#'identity
)))
750 (enforce-types scope env
)
751 (eval-progn (symbol-macro-body scope
) (new-env)))
754 (digest-locally env body
)
755 (let ((scope (parse-symbol-macrolet env defs body
#'%progn
)))
756 (hlambda SYMBOL-MACROLET
(scope) (env)
757 (enforce-types scope env
)
758 (dispatch (symbol-macro-body scope
) (new-env)))))))
760 (defun parse-let (maker env bindings body specials-listifier
)
761 (multiple-value-bind (forms decls
) (parse-body body nil t
)
762 (binding* (((declared-specials n-declared
) (declared-specials decls
))
765 (let ((boundp 0)) ; mask over declared-specials of bound ones
766 (dolist (binding bindings
(- n-declared
(logcount boundp
)))
767 (let ((p (posq (binding-symbol binding
) declared-specials
)))
768 (when p
(setf (logbitp p boundp
) t
)))
770 (symbols (make-array (+ n-bindings n-free-specials
)))
771 (values (make-array n-bindings
))
773 (dolist (binding bindings
)
774 (multiple-value-bind (symbol value-form
)
777 (with-subforms (symbol &optional value
) binding
778 (values symbol value
)))
779 (unless (symbolp symbol
)
780 (ip-error "~S is not a symbol" symbol
))
782 (setf (svref symbols index
) (list symbol
)
783 (svref values index
) value-form
)))
784 (dolist (sym declared-specials
)
785 (unless (find (the symbol sym
) symbols
:end n-bindings
:key
#'car
)
786 (setf (svref symbols
(incf index
)) (find-special-binding env sym
))))
787 (let ((special-b ; mask over symbols of special ones
788 (mark-bound-specials env declared-specials symbols n-bindings
)))
790 (funcall maker decls
(new-policy env decls
) symbols special-b
791 values
(%progn forms
)
792 (funcall specials-listifier
793 (collect-progv-symbols symbols n-bindings
795 env n-bindings symbols
)))))
797 (defglobal *let-processor
* nil
)
800 ((defspecial* (operator transform-specials
)
801 `(defspecial ,operator
(bindings &body body
)
804 (return-from ,operator
(digest-locally env body
)))
805 ;; For 1 binding always use LET which is semantically the same.
806 ;; It is ever-so-slightly more efficient to use LET than LET*.
807 ,@(when (eq operator
'let
*)
808 `((when (singleton-p bindings
)
810 (funcall *let-processor
* `(,bindings
,@body
) env
)))))
811 ;; FIXME: aren't MAKE-LET*-FRAME and MAKE-LET-FRAME essentially
813 (let ((frame (parse-let ',(symbolicate "MAKE-" operator
"-FRAME")
814 env bindings body
,transform-specials
)))
815 (let ((values (frame-values frame
)))
816 (map-into values
#'%sexpr values
))
817 (symbol-macrolet ((symbols (frame-symbols frame
)))
818 (cond ((zerop (frame-special-b frame
))
819 (hlambda ,operator
(frame) (old-env)
820 (let ((values (make-array (frame-size frame
))))
821 (eval-it (frame-values frame
) dispatch
822 (dispatch (frame-sexpr frame
) new-env
)
824 ((fixnump (frame-special-b frame
))
826 ((special-b (the fixnum
(frame-special-b frame
))))
827 (hlambda ,(sb-int:symbolicate operator
"/SPEC")
829 (let ((values (make-array (frame-size frame
)))
830 (specials (frame-specials frame
)))
831 (eval-it (frame-values frame
) dispatch
832 (dispatch (frame-sexpr frame
) new-env
))))))
833 (t ; a ton of specials
834 (symbol-macrolet ((special-b (frame-special-b frame
)))
835 (hlambda ,(sb-int:symbolicate operator
"/SPEC")
837 (let ((values (make-array (frame-size frame
)))
838 (specials (frame-specials frame
)))
839 (eval-it (frame-values frame
) dispatch
840 (dispatch (frame-sexpr frame
)
843 ((eval-it (value-source-v eval-fn eval-body
&rest more
)
844 `(let ((new-env (make-var-env old-env values symbols frame
))
845 (type-restrictions (binding-typechecks frame
)))
847 (values (length values
) ,@more
849 (,eval-fn
(svref ,value-source-v frame-index
) old-env
)
850 type-restrictions frame-index symbols
)
852 (enforce-types frame env
) ; the OLD env
854 ;; WITH-LET-BINDINGS accumulates special bindings in reverse
855 ;; so we have to reverse the symbols too.
856 (defspecial* LET
#'nreverse
))
859 ((eval-it (value-source-v eval-fn eval-body
&rest more
)
860 ;; (length . vector) is a proxy for a vector with fill-pointer
861 `(let* ((symbol-cells (cons 0 symbols
))
862 (new-env (make-var-env old-env values symbol-cells frame
))
863 (type-restrictions (binding-typechecks frame
)))
865 (values (car symbol-cells
) ,@more
867 (,eval-fn
(svref ,value-source-v frame-index
) new-env
)
868 type-restrictions frame-index symbols
)
869 :specials
(pop specials
))
870 ;; expression to start the recursion
871 (let*-bind
0 (length values
))
872 ;; post-binding actions
873 ;; FIXME: this step is possibly not thread-safe. Figure it out.
874 ;; Maybe "once a mutable env, always a mutable env"?
875 (setf (env-symbols new-env
) symbols
)
876 (enforce-types frame env
) ; the OLD env
878 ;; WITH-LET*-BINDER needs each special in a singleton list
879 (defspecial* LET
* (lambda (x) (mapcar #'list x
)))))
881 (setq *let-processor
* (cdr (!special-form-handler
(find-fdefn 'let
))))
885 ;;; Unlike with local functions, this encloses the macro lambda in the
886 ;;; parse-time environment which is why this is EVAL- and not DIGEST.
887 ;;; It also does not go to the trouble of hiding (making inaccessible)
888 ;;; any lexical names that should not be visible.
889 ;;; This is permissible per CLHS in the description of MACROLET:
890 ;;; "the consequences are undefined if the local macro definitions
891 ;;; reference any local variable or function bindings that are
892 ;;; visible in that lexical environment."
893 ;;; This means: you're wrong for doing that; but in this implementation
894 ;;; your macro functions can look at things they shouldn't.
896 (defun eval-local-macros (env defs
)
897 ;; Is it necessary to freeze a macro env? You shouldn't look at
898 ;; any lexical constructs except macros anyway.
899 (when (must-freeze-p env
) (setq env
(freeze-env env
)))
902 (with-subforms (name lambda-list
&body body
) def
903 (unless (and (symbolp name
)
904 (neq (info :function
:kind name
) :special-form
))
905 (ip-error "~S is not a valid macro name" name
))
907 (with-package-lock-context (env)
908 (program-assert-symbol-home-package-unlocked
909 :eval name
"binding ~S as a local macro")))
911 (make-proto-fn (make-macro-lambda `(macrolet ,name
) lambda-list body
916 ;;; MACROLET has an immediate-mode handler since it is common at toplevel.
917 (defspecial macrolet
(defs &body body
)
919 (multiple-value-bind (forms decls
) (parse-body body nil t
)
920 (let* ((specials (free-specials env decls
))
921 (scope (process-typedecls
922 (make-decl-scope decls
(new-policy env decls
))
924 (enforce-types scope env
)
927 (eval-local-macros env defs
)
931 (digest-locally env body
)
932 (multiple-value-bind (forms decls
) (parse-body body nil t
)
933 (let ((scope (make-local-fn-scope decls
(eval-local-macros env defs
)
935 (hlambda MACROLET
(scope) (env)
936 (enforce-types scope env
)
938 (local-fn-scope-body scope
)
940 (local-fn-scope-funs scope
)
941 (local-fn-scope-specials scope
)
946 (define-load-time-global *last-toplevel-env
*
947 (make-basic-env nil nil nil
(make-decl-scope nil sb-c
::**baseline-policy
**)))
949 (declaim (inline disabled-locks
))
950 ;;; Pull out LIST from `((DECLARE (DISABLE-PACKAGE-LOCKS ,@LIST)))
951 (defun disabled-locks (decls) (cdadar decls
))
953 ;;; Immediate mode FUNCTION when evaluated captures the globally
954 ;;; disabled package-locks, so this works:
955 ;;; * (declaim (disable-package-locks read-byte))
956 ;;; * (defun foo () (flet ((read-byte () 42)) (read-byte)))
957 ;;; * (declaim (enable-package-locks read-byte))
958 ;;; * (something-that-calls-foo)
959 ;;; And conversely the lambda should not observe subsequent
960 ;;; changes that globally unlock a symbol.
961 (defun capture-toplevel-env ()
962 (let* ((disabled-locks sb-c
::*disabled-package-locks
*)
963 (policy sb-c
::*policy
*)
964 ;; Multiple threads can harmlessly share this global variable.
965 ;; At worst, a new environment is consed every time through here.
966 (last-env *last-toplevel-env
*)
967 (contour (env-contour last-env
)))
968 ;; The toplevel environment changes only when the user declaims
969 ;; optimization settings or enables/disables per-symbol package-locks.
970 (unless (and (sb-c::policy
= (%policy contour
) policy
)
971 (equal (disabled-locks (declarations contour
))
975 `((declare (disable-package-locks ,@disabled-locks
))))))
976 (setq last-env
(make-basic-env
977 nil nil nil
(make-decl-scope decls policy
)))
978 ;; Ensure all accessible parts of the new BASIC-ENV
979 ;; are flushed to memory before publishing shared variable.
980 (sb-thread:barrier
(:write
))
981 (setq *last-toplevel-env
* last-env
)))
984 ;;; We have to do some shenanigans with lexical environments that are non-null
985 ;;; but have not captured the toplevel disabled package lock state.
986 ;;; Continuing the example above, suppose we have:
987 ;;; (locally (declare (special ...)) (lambda () (flet ((read-byte ...)))))
988 ;;; This lambda has a non-null environment due to the LOCALLY form.
989 ;;; On account of the interpreter's laziness, it does not decide up front about
990 ;;; whether the lexical binding of #'READ-BYTE is permitted. But to be consistent
991 ;;; with the compiler, it should act like it decides now. To do that, we inject
992 ;;; globally disabled package-locks as if they appeared in a *nested* environment,
993 ;;; carefully ignoring anything global shadowed by a contrary lexical declaration.
994 ;;; The compiler does not have this problem, because compilation isn't lazy.
995 (defun capture-disabled-package-locks (env)
996 (let* ((decls (declarations (env-contour (capture-toplevel-env))))
997 (proclaimed-disabled-locks (disabled-locks decls
)))
998 (when proclaimed-disabled-locks
; usually false
1000 (if (every (lambda (name) (lexically-unlocked-symbol-p name env
))
1001 proclaimed-disabled-locks
)
1002 ;; No local declaration prevailed over the global,
1003 ;; so capture the global list. This is fine even if it
1004 ;; contains a name that is redundant with an explicit
1005 ;; lexically declared unlock. It avoids some consing.
1007 (let (new-list) ; XXX: This code is untested!
1008 (dolist (name proclaimed-disabled-locks
)
1009 (when (lexically-unlocked-symbol-p name env
)
1010 ;; *assume* it was because of the global unlock,
1011 ;; which is to say, it might be redundant with,
1012 ;; a local unlock but at least it wasn't shadowed
1013 ;; by an explicitly declared lexical re-lock.
1014 (push name new-list
)))
1016 `((declare (disable-package-locks ,@new-list
))))))))
1018 (return-from capture-disabled-package-locks
1019 (make-basic-env env nil nil
1020 (make-decl-scope decls
(env-policy env
)))))))
1021 ;; There were no applicable global unlocks, meaning either the list
1022 ;; was empty, or everything in it was shadowed by a lexical lock.
1025 (defun capture-toplevel-stuff (env)
1026 (labels ((captured-p (env) ; true if there is already an ancestor lambda
1027 (acond ((lambda-env-p env
) t
)
1028 ((env-parent env
) (captured-p it
)))))
1029 (cond ((null env
) (capture-toplevel-env))
1030 ((captured-p env
) env
)
1031 (t (capture-disabled-package-locks env
)))))
1033 (defun digest-local-fns (env kind bindings body
) ; KIND is FLET or LABELS
1034 (flet ((proto-functionize (def)
1035 (with-subforms (name lambda-list
&body body
) def
1036 (multiple-value-bind (forms decls docstring
) (parse-body body t t
)
1037 ;; *** Test LEGAL-FUN-NAME-P before asking for an info-value.
1038 ;; This is because (INFO :FUNCTION :KIND) uses FBOUNDP when it
1039 ;; does not have an entry for NAME. But calling FBOUNDP
1040 ;; might call LEGAL-FUN-NAME-OR-TYPE-ERROR.
1041 ;; This ends up producing a different error message instead
1042 ;; of a consistent message as per the format string below.
1043 (unless (and (legal-fun-name-p name
)
1044 (neq (info :function
:kind name
) :special-form
))
1045 (ip-error "~S is not a legal function name" name
))
1046 (when (fboundp name
)
1047 (with-package-lock-context (env)
1048 (program-assert-symbol-home-package-unlocked
1049 :eval name
"binding ~S as a local function")))
1050 ;; Return T if SEXPR contains (RETURN-FROM BLOCK-NAME ...),
1051 ;; or NIL if it definitely does not. While this is an inelegant
1052 ;; kludge, it is extremely effective. Avoiding creation of a
1053 ;; CATCH frame, makes local fun application properly
1054 ;; tail recursive, barring other inhibitors.
1055 ;; FIXME: Macros can be nondeterministic :-( so if any macro
1056 ;; in a non-builtin package is seen, conservatively return T.
1057 (flet ((has-return-p (sexpr env block-name
)
1060 (sb-walker:walk-form
1062 (lambda (subform context env
)
1063 (declare (ignore env
))
1064 (when (and (eq context
:eval
)
1066 '(cons (eql return-from
) list
))
1067 (eq (cadr subform
) block-name
))
1068 (return-from has-return-p t
))
1071 (condition () t
)))) ; conservative answer
1072 (let* ((block (fun-name-block-name name
))
1073 (forms (if (has-return-p `(progn ,@forms
) env block
)
1074 `((block ,block
,@forms
))
1076 (%make-proto-fn
`(,kind
,name
) lambda-list decls forms
1078 (multiple-value-bind (forms decls
) (parse-body body nil t
)
1079 (make-local-fn-scope decls
(map 'vector
#'proto-functionize bindings
)
1082 ;;; There's an improvement that could be made - unless a function name
1083 ;;; appears as the operand to FUNCTION, all internals call could use
1084 ;;; different convention for function application which avoids consing
1085 ;;; a funcallable instance. But you can't now that without walking into the
1086 ;;; body, which means you lose the otherwise nice laziness aspect.
1087 (macrolet ((defspecial* (operator)
1088 `(defspecial ,operator
(defs &body body
)
1090 (cond ((not defs
) (digest-locally env body
))
1091 ((not body
) (return-constant nil
))
1093 (let* ((env (capture-toplevel-stuff env
))
1094 (frame (digest-local-fns env
',operator defs body
)))
1095 (if (must-freeze-p env
)
1096 (handler-guts (freeze-env env
))
1097 (handler-guts env
))))))))
1099 (macrolet ((handler-guts (closed-over-env)
1100 `(hlambda FLET
(frame) (env)
1101 (enforce-types frame env
)
1102 (let* ((closure-env ,closed-over-env
)
1106 (make-function proto-fn closure-env
))
1107 (local-fn-scope-funs frame
))))
1109 (local-fn-scope-body frame
)
1111 env funs
(local-fn-scope-specials frame
) frame
))))))
1114 (macrolet ((handler-guts (closed-over-env)
1115 `(hlambda LABELS
(frame) (env)
1116 (enforce-types frame env
)
1117 (let* ((funs (make-array (length (local-fn-scope-funs frame
))))
1118 (closure-env (make-function-env ,closed-over-env funs
1119 nil
*vacuous-decls
*)))
1120 (map-into funs
(lambda (proto-fn)
1121 (make-function proto-fn closure-env
))
1122 (local-fn-scope-funs frame
))
1124 (local-fn-scope-body frame
)
1125 ;; In the absence of decls, the env in which the body
1126 ;; is eval'ed is the same as the functions' env.
1127 ;; Otherwise, it is yet another new env.
1128 (if (declarations frame
)
1129 (make-basic-env closure-env nil
1130 (local-fn-scope-specials frame
) frame
)
1132 (defspecial* labels
)))
1134 (macrolet ((not-a-function (name)
1135 `(ip-error "~S is a macro." ,name
)))
1136 (defspecial function
(name)
1137 (if (and (symbolp name
) (eq (info :function
:kind name
) :special-form
))
1138 (ip-error "~S names a special operator." name
))
1139 ;; again it's sad that I can't wrap code around both modes
1141 (if (and (listp name
) (memq (car name
) '(named-lambda lambda
)))
1143 (aver (not (must-freeze-p env
)))
1144 (enclose (make-proto-fn name
(not (null env
)))
1145 (capture-toplevel-stuff env
)
1147 ;; immediate mode calls FDEFINITION as needed, so wil err as it should.
1148 (multiple-value-bind (definition macro-p
) (get-function name env
)
1149 (if macro-p
(not-a-function name
) definition
)))
1151 (if (and (listp name
) (memq (car name
) '(named-lambda lambda
)))
1152 (handler (if (must-freeze-p env
) #'enclose-freeze
#'enclose
)
1153 (make-proto-fn name
))
1154 (multiple-value-bind (kind definition frame-ptr
)
1155 (find-lexical-fun env name
)
1157 (if (eq kind
:macro
)
1158 (not-a-function name
)
1159 (hlambda FUNCTION
(frame-ptr) (env)
1160 (local-fdefinition frame-ptr env
)))
1161 ;; Consider (DEFUN GET-THING () #'THING) - it shouldn't return
1162 ;; THING's error trampoline if THING is redefined after
1163 ;; GET-THING was called once.
1164 (let ((fdefn (find-or-create-fdefn name
)))
1165 (if (symbolp name
) ; could be a macro
1166 (hlambda FUNCTION
(fdefn) (env)
1167 (declare (ignore env
))
1168 (let ((fun (sb-c:safe-fdefn-fun fdefn
)))
1169 (if (sb-impl::macro
/special-guard-fun-p fun
)
1170 (not-a-function (fdefn-name fdefn
))
1172 (hlambda FUNCTION
(fdefn) (env) ; could not be a macro
1173 (declare (ignore env
))
1174 (sb-c:safe-fdefn-fun fdefn
)))))))))
1176 ;;;; some extra handlers
1180 ((define-boole (op identity test
)
1181 `(defspecial ,op
(&rest forms
)
1182 :immediate
:none
; just recurse
1184 ;; following the model of PROGN
1185 (case (length forms
)
1186 (0 (return-constant ,identity
))
1187 (1 (handler #'digest-form
(first forms
)))
1188 (2 (let ((one (%sexpr
(first forms
))) (two (%sexpr
(second forms
))))
1189 (hlambda ,op
(one two
) (env)
1190 (,op
(dispatch one env
) (dispatch two env
)))))
1192 (let ((forms (nreverse (vector-of-sexpr forms
))))
1193 (hlambda ,op
(forms) (env)
1194 (declare (simple-vector forms
))
1195 (let ((i (1- (length forms
))))
1196 (loop (let ((result (dispatch (svref forms i
) env
))) ,test
)
1197 (if (zerop (decf i
))
1198 (return (dispatch (svref forms
0) env
))))))))))))
1199 (define-boole OR nil
(when result
(return result
)))
1200 (define-boole AND t
(unless result
(return nil
))))
1202 ;;;; CL functions that are handled semi-magically
1204 (flet ((local-dispatch (sexpr env
)
1205 (declare #.
+handler-optimize
+)
1206 (if (%instancep sexpr
) (%dispatch sexpr env
) sexpr
)))
1208 ;; hand-generated lists of useful functions
1209 (setq *unary-functions
*
1210 (sb-impl::%stuff-hash-table
1211 (make-hash-table :test
#'eq
)
1213 ((def-wrapper (&rest input
)
1218 (named-lambda (EVAL ,f
) (arg env sexpr
)
1219 (declare (ignore sexpr
)
1220 (optimize (sb-c:verify-arg-count
0))
1221 (muffle-conditions compiler-note
))
1222 (,f
(local-dispatch arg env
)))))
1226 -
/ /= 1+ 1-
< <= = > >=
1228 CAR CDR CAAR CADR CDAR CDDR
1229 CAAAR CAADR CADAR CADDR CDAAR CDADR CDDAR CDDDR
1230 CAAAAR CAAADR CAADAR CAADDR CADAAR CADADR CADDAR CADDDR
1231 CDAAAR CDAADR CDADAR CDADDR CDDAAR CDDADR CDDDAR CDDDDR
1232 ;; other list accessors
1234 SECOND THIRD FOURTH FIFTH SIXTH SEVENTH EIGHTH NINTH TENTH
1235 ;; alphabetical order from here down
1238 ALPHA-CHAR-P ALPHANUMERICP
1239 ;;; Compiling ARRAY-ELEMENT-TYPE refers to the type CLASS
1240 ;;; which isn't defined yet. Why does it?
1241 ARRAY-DIMENSIONS
#|ARRAY-ELEMENT-TYPE|
# ARRAY-HAS-FILL-POINTER-P
1242 ARRAY-IN-BOUNDS-P ARRAY-RANK ARRAY-TOTAL-SIZE ARRAYP
1244 BIT-NOT BIT-VECTOR-P BOTH-CASE-P BOUNDP
1245 BUTLAST BYTE-POSITION BYTE-SIZE
1246 CEILING CHAR-CODE CHAR-DOWNCASE CHAR-EQUAL CHAR-GREATERP
1247 CHAR-INT CHAR-LESSP CHAR-NOT-EQUAL
1248 CHAR-NOT-GREATERP CHAR-NOT-LESSP CHAR-UPCASE
1249 CHAR
/= CHAR
< CHAR
<= CHAR
= CHAR
> CHAR
>=
1250 CHARACTER CHARACTERP
1251 CODE-CHAR COMPILED-FUNCTION-P COMPLEMENT
1252 COMPLEX COMPLEXP CONSP
1254 DIGIT-CHAR DIGIT-CHAR-P
1255 ENDP EVENP FBOUNDP FDEFINITION FIND-SYMBOL
1256 FLOAT FLOATP FLOOR FUNCALL FUNCTIONP
1265 LAST LENGTH LIST
* LIST-LENGTH LISTP
1266 LOGCOUNT LOGNOT LOWER-CASE-P
1268 NBUTLAST NOT NREVERSE
1269 NSTRING-CAPITALIZE NSTRING-DOWNCASE NSTRING-UPCASE
1270 NULL NUMBERP NUMERATOR
1272 PACKAGEP PATHNAMEP PLUSP
1275 SIMPLE-BIT-VECTOR-P SIMPLE-STRING-P SIMPLE-VECTOR-P
1276 SPECIAL-OPERATOR-P SQRT
1279 STRING-CAPITALIZE STRING-DOWNCASE STRING-UPCASE STRINGP SXHASH
1280 SYMBOL-FUNCTION SYMBOL-NAME SYMBOL-PACKAGE SYMBOL-PLIST
1281 SYMBOL-VALUE SYMBOLP
1289 (setq *binary-functions
*
1290 (sb-impl::%stuff-hash-table
1291 (make-hash-table :test
#'eq
)
1293 ((def-wrapper (&rest input
)
1298 (named-lambda (.eval.
,(symbolicate "2-ARG-" f
))
1300 (declare (ignore sexpr
)
1301 (optimize (sb-c:verify-arg-count
0))
1302 (muffle-conditions compiler-note
))
1303 (,f
(local-dispatch (car data
) env
)
1304 (local-dispatch (cdr data
) env
)))))
1306 (def-wrapper + -
* / = < > <= >= min max
1307 string
= string
< string
<= string
> string
>=
1308 char
= char
< char
<= char
> char
>=