1 ;;;; a simple code walker
3 ;;;; The code which implements the macroexpansion environment
4 ;;;; manipulation mechanisms is in the first part of the file, the
5 ;;;; real walker follows it.
7 ;;;; This software is part of the SBCL system. See the README file for
10 ;;;; This software is derived from software originally released by Xerox
11 ;;;; Corporation. Copyright and release statements follow. Later modifications
12 ;;;; to the software are in the public domain and are provided with
13 ;;;; absolutely no warranty. See the COPYING and CREDITS files for more
16 ;;;; copyright information from original PCL sources:
18 ;;;; Copyright (c) 1985, 1986, 1987, 1988, 1989, 1990 Xerox Corporation.
19 ;;;; All rights reserved.
21 ;;;; Use and copying of this software and preparation of derivative works based
22 ;;;; upon this software are permitted. Any distribution of this software or
23 ;;;; derivative works must comply with all applicable United States export
26 ;;;; This software is made available AS IS, and Xerox Corporation makes no
27 ;;;; warranty about the software, its performance or its conformity to any
30 (in-package "SB!WALKER")
32 ;;;; forward references
34 (defvar *key-to-walker-environment
*)
36 ;;;; environment hacking stuff, necessarily SBCL-specific
38 ;;; Here in the original PCL were implementations of the
39 ;;; implementation-specific environment hacking functions for each of
40 ;;; the implementations this walker had been ported to. This
41 ;;; functionality was originally factored out in order to make PCL
42 ;;; portable from one Common Lisp to another. As of 19981107, that
43 ;;; portability was fairly stale and (because of the scarcity of CLTL1
44 ;;; implementations and the strong interdependence of the rest of ANSI
45 ;;; Common Lisp on the CLOS system) fairly irrelevant. It was fairly
46 ;;; thoroughly put out of its misery by WHN in his quest to clean up
47 ;;; the system enough that it can be built from scratch using any ANSI
50 ;;; This code just hacks 'macroexpansion environments'. That is, it is
51 ;;; only concerned with the function binding of symbols in the
52 ;;; environment. The walker needs to be able to tell if the symbol
53 ;;; names a lexical macro or function, and it needs to be able to
54 ;;; build environments which contain lexical macro or function
55 ;;; bindings. It must be able, when walking a MACROLET, FLET or LABELS
56 ;;; form to construct an environment which reflects the bindings
57 ;;; created by that form. Note that the environment created does NOT
58 ;;; have to be sufficient to evaluate the body, merely to walk its
59 ;;; body. This means that definitions do not have to be supplied for
60 ;;; lexical functions, only the fact that that function is bound is
61 ;;; important. For macros, the macroexpansion function must be
64 ;;; This code is organized in a way that lets it work in
65 ;;; implementations that stack cons their environments. That is
66 ;;; reflected in the fact that the only operation that lets a user
67 ;;; build a new environment is a WITH-BODY macro which executes its
68 ;;; body with the specified symbol bound to the new environment. No
69 ;;; code in this walker or in PCL will hold a pointer to these
70 ;;; environments after the body returns. Other user code is free to do
71 ;;; so in implementations where it works, but that code is not
72 ;;; considered portable.
74 ;;; There are 3 environment hacking tools. One macro,
75 ;;; WITH-AUGMENTED-ENVIRONMENT, which is used to create new
76 ;;; environments, and two functions, ENVIRONMENT-FUNCTION and
77 ;;; ENVIRONMENT-MACRO, which are used to access the bindings of
78 ;;; existing environments
80 ;;; In SBCL, as in CMU CL before it, the environment is represented
81 ;;; with a structure that holds alists for the functional things,
82 ;;; variables, blocks, etc. Except for SYMBOL-MACROLET, only the
83 ;;; SB!C::LEXENV-FUNS slot is relevant. It holds: Alist (Name . What),
84 ;;; where What is either a functional (a local function) or a list
85 ;;; (MACRO . <function>) (a local macro, with the specifier expander.)
86 ;;; Note that Name may be a (SETF <name>) function. Accessors are
87 ;;; defined below, eg (ENV-WALK-FUNCTION ENV).
89 ;;; If WITH-AUGMENTED-ENVIRONMENT is called from WALKER-ENVIRONMENT-BIND
90 ;;; this code hides the WALKER version of an environment
91 ;;; inside the SB!C::LEXENV structure.
93 ;;; In CMUCL (and former SBCL), This used to be a list of lists of form
94 ;;; (<gensym-name> MACRO . #<interpreted-function>) in the :functions slot
96 ;;; This form was accepted by the compiler, but this was a crude hack,
97 ;;; because the <interpreted-function> was used as a structure to hold the
98 ;;; bits of interest, {function, form, declarations, lexical-variables},
99 ;;; a list, which was not really an interpreted function.
100 ;;; Instead this list was COERCEd to a #<FUNCTION ...>!
102 ;;; Instead, we now use a special sort of "function"-type for that
103 ;;; information, because the functions slot in SB!C::LEXENV is
104 ;;; supposed to have a list of <Name MACRO . #<function> elements.
105 ;;; So, now we hide our bits of interest in the walker-info slot in
106 ;;; our new BOGO-FUN.
108 ;;; MACROEXPAND-1 and SB!INT:EVAL-IN-LEXENV are the only SBCL
109 ;;; functions that get called with the constructed environment
112 (/show
"walk.lisp 108")
114 (defmacro with-augmented-environment
115 ((new-env old-env
&key functions macros
) &body body
)
116 `(let ((,new-env
(with-augmented-environment-internal ,old-env
121 ;;; a unique tag to show that we're the intended caller of BOGO-FUN
122 (defvar *bogo-fun-magic-tag
*
123 '(:bogo-fun-magic-tag
))
125 ;;; The interface of BOGO-FUNs (previously implemented as
126 ;;; FUNCALLABLE-INSTANCEs) is just these two operations, so we can do
127 ;;; them with ordinary closures.
129 ;;; KLUDGE: BOGO-FUNs are sorta weird, and MNA and I have both hacked
130 ;;; on this code without quite figuring out what they're for. (He
131 ;;; changed them to work after some changes in the IR1 interpreter
132 ;;; made functions not be built lazily, and I changed them so that
133 ;;; they don't need FUNCALLABLE-INSTANCE stuff, so that the F-I stuff
134 ;;; can become less general.) There may be further simplifications or
135 ;;; clarifications which could be done. -- WHN 2001-10-19
136 (defun walker-info-to-bogo-fun (walker-info)
137 (lambda (magic-tag &rest rest
)
138 (aver (not rest
)) ; else someone is using me in an unexpected way
139 (aver (eql magic-tag
*bogo-fun-magic-tag
*)) ; else ditto
141 (defun bogo-fun-to-walker-info (bogo-fun)
142 (declare (type function bogo-fun
))
143 (funcall bogo-fun
*bogo-fun-magic-tag
*))
145 (defun with-augmented-environment-internal (env funs macros
)
146 ;; Note: In order to record the correct function definition, we
147 ;; would have to create an interpreted closure, but the
148 ;; WITH-NEW-DEFINITION macro down below makes no distinction between
149 ;; FLET and LABELS, so we have no idea what to use for the
150 ;; environment. So we just blow it off, 'cause anything real we do
151 ;; would be wrong. But we still have to make an entry so we can tell
152 ;; functions from macros -- same for telling variables apart from
154 (let ((lexenv (sb!kernel
:coerce-to-lexenv env
)))
157 :vars
(when (eql (caar macros
) *key-to-walker-environment
*)
158 (copy-tree (mapcar (lambda (b)
161 (if (eq info
:lexical-var
)
163 (if (var-special-p name env
)
164 (sb!c
::make-global-var
167 (sb!c
::make-lambda-var
168 :%source-name name
)))
170 (fourth (cadar macros
)))))
171 :funs
(append (mapcar (lambda (f)
173 (sb!c
::make-functional
:lexenv lexenv
)))
179 *key-to-walker-environment
*)
180 (walker-info-to-bogo-fun (cadr m
))
181 (coerce (cadr m
) 'function
))))
184 (defun environment-function (env fn
)
186 (let ((entry (assoc fn
(sb!c
::lexenv-funs env
) :test
#'equal
)))
188 (sb!c
::functional-p
(cdr entry
))
191 (defun environment-macro (env macro
)
193 (let ((entry (assoc macro
(sb!c
::lexenv-funs env
) :test
#'eq
)))
195 (eq (cadr entry
) 'sb
!c
::macro
)
196 (if (eq macro
*key-to-walker-environment
*)
197 (values (bogo-fun-to-walker-info (cddr entry
)))
198 (values (function-lambda-expression (cddr entry
))))))))
200 ;;;; other environment hacking, not so SBCL-specific as the
201 ;;;; environment hacking in the previous section
203 (defmacro with-new-definition-in-environment
204 ((new-env old-env macrolet
/flet
/labels-form
) &body body
)
205 (let ((functions (make-symbol "Functions"))
206 (macros (make-symbol "Macros")))
207 `(let ((,functions
())
209 (ecase (car ,macrolet
/flet
/labels-form
)
211 (dolist (fn (cadr ,macrolet
/flet
/labels-form
))
212 (push fn
,functions
)))
214 (dolist (mac (cadr ,macrolet
/flet
/labels-form
))
215 (push (list (car mac
)
216 (convert-macro-to-lambda (cadr mac
)
221 (with-augmented-environment
222 (,new-env
,old-env
:functions
,functions
:macros
,macros
)
225 (defun convert-macro-to-lambda (llist body env
&optional
(name "dummy macro"))
226 (let ((gensym (make-symbol name
)))
227 (eval-in-lexenv `(defmacro ,gensym
,llist
,@body
)
228 (sb!c
::make-restricted-lexenv env
))
229 (macro-function gensym
)))
231 ;;;; the actual walker
233 ;;; As the walker walks over the code, it communicates information to
234 ;;; itself about the walk. This information includes the walk
235 ;;; function, variable bindings, declarations in effect etc. This
236 ;;; information is inherently lexical, so the walker passes it around
237 ;;; in the actual environment the walker passes to macroexpansion
238 ;;; functions. This is what makes the NESTED-WALK-FORM facility work
240 (defmacro walker-environment-bind
((var env
&rest key-args
)
242 `(with-augmented-environment
243 (,var
,env
:macros
(walker-environment-bind-1 ,env
,.key-args
))
246 (defvar *key-to-walker-environment
* (gensym))
248 (defun env-lock (env)
249 (environment-macro env
*key-to-walker-environment
*))
251 (defun walker-environment-bind-1 (env &key
(walk-function nil wfnp
)
253 (declarations nil decp
)
254 (lexical-vars nil lexp
))
255 (let ((lock (env-lock env
)))
257 (list *key-to-walker-environment
*
258 (list (if wfnp walk-function
(car lock
))
259 (if wfop walk-form
(cadr lock
))
260 (if decp declarations
(caddr lock
))
261 (if lexp lexical-vars
(cadddr lock
)))))))
263 (defun env-walk-function (env)
264 (car (env-lock env
)))
266 (defun env-walk-form (env)
267 (cadr (env-lock env
)))
269 (defun env-declarations (env)
270 (caddr (env-lock env
)))
272 (defun env-var-type (var env
)
273 (dolist (decl (env-declarations env
) t
)
274 (when (and (eq 'type
(car decl
)) (member var
(cddr decl
) :test
'eq
))
275 (return (cadr decl
)))))
277 (defun env-lexical-variables (env)
278 (cadddr (env-lock env
)))
280 (defun note-declaration (declaration env
)
281 (push declaration
(caddr (env-lock env
))))
283 (defun note-var-binding (thing env
)
284 (push (list thing
:lexical-var
) (cadddr (env-lock env
))))
286 (defun var-lexical-p (var env
)
287 (let ((entry (member var
(env-lexical-variables env
) :key
#'car
:test
#'eq
)))
288 (when (eq (cadar entry
) :lexical-var
)
291 (defun variable-symbol-macro-p (var env
)
292 (let ((entry (member var
(env-lexical-variables env
) :key
#'car
:test
#'eq
)))
293 (when (eq (cadar entry
) 'sb
!sys
:macro
)
296 (defun walked-var-declaration-p (declaration)
297 (member declaration
'(sb!pcl
::%class sb
!pcl
::%variable-rebinding special
)))
299 (defun %var-declaration
(declaration var env
)
300 (let ((id (or (var-lexical-p var env
) var
)))
301 (if (eq 'special declaration
)
302 (dolist (decl (env-declarations env
))
303 (when (and (eq (car decl
) declaration
)
304 (or (member var
(cdr decl
))
305 (and id
(member id
(cdr decl
)))))
307 (dolist (decl (env-declarations env
))
308 (when (and (eq (car decl
) declaration
)
312 (defun var-declaration (declaration var env
)
313 (if (walked-var-declaration-p declaration
)
314 (%var-declaration declaration var env
)
315 (error "Not a variable declaration the walker cares about: ~S" declaration
)))
318 (define-compiler-macro var-declaration
(&whole form declaration var env
320 (if (sb!xc
:constantp declaration lexenv
)
321 (let ((decl (constant-form-value declaration lexenv
)))
322 (if (walked-var-declaration-p decl
)
323 `(%var-declaration
,declaration
,var
,env
)
327 (defun var-special-p (var env
)
328 (and (or (var-declaration 'special var env
)
329 (var-globally-special-p var
))
332 (defun var-globally-special-p (symbol)
333 (eq (info :variable
:kind symbol
) :special
))
336 ;;;; handling of special forms
338 ;;; Here are some comments from the original PCL on the difficulty of
339 ;;; doing this portably across different CLTL1 implementations. This
340 ;;; is no longer directly relevant because this code now only runs on
341 ;;; SBCL, but the comments are retained for culture: they might help
342 ;;; explain some of the design decisions which were made in the code.
346 ;;; The set of special forms is purposely kept very small because
347 ;;; any program analyzing program (read code walker) must have
348 ;;; special knowledge about every type of special form. Such a
349 ;;; program needs no special knowledge about macros...
351 ;;; So all we have to do here is a define a way to store and retrieve
352 ;;; templates which describe how to walk the 24 special forms and we
355 ;;; Well, its a nice concept, and I have to admit to being naive
356 ;;; enough that I believed it for a while, but not everyone takes
357 ;;; having only 24 special forms as seriously as might be nice. There
358 ;;; are (at least) 3 ways to lose:
360 ;;; 1 - Implementation x implements a Common Lisp special form as
361 ;;; a macro which expands into a special form which:
362 ;;; - Is a common lisp special form (not likely)
363 ;;; - Is not a common lisp special form (on the 3600 IF --> COND).
365 ;;; * We can save ourselves from this case (second subcase really)
366 ;;; by checking to see whether there is a template defined for
367 ;;; something before we check to see whether we can macroexpand it.
369 ;;; 2 - Implementation x implements a Common Lisp macro as a special form.
371 ;;; * This is a screw, but not so bad, we save ourselves from it by
372 ;;; defining extra templates for the macros which are *likely* to
373 ;;; be implemented as special forms. [Note: As of sbcl-0.6.9, these
374 ;;; extra templates have been deleted, since this is not a problem
375 ;;; in SBCL and we no longer try to make this walker portable
376 ;;; across other possibly-broken CL implementations.]
378 ;;; 3 - Implementation x has a special form which is not on the list of
379 ;;; Common Lisp special forms.
381 ;;; * This is a bad sort of a screw and happens more than I would
382 ;;; like to think, especially in the implementations which provide
383 ;;; more than just Common Lisp (3600, Xerox etc.).
384 ;;; The fix is not terribly satisfactory, but will have to do for
385 ;;; now. There is a hook in get walker-template which can get a
386 ;;; template from the implementation's own walker. That template
387 ;;; has to be converted, and so it may be that the right way to do
388 ;;; this would actually be for that implementation to provide an
389 ;;; interface to its walker which looks like the interface to this
392 (defmacro get-walker-template-internal
(x)
393 `(get ,x
'walker-template
))
395 (defmacro define-walker-template
(name
396 &optional
(template '(nil repeat
(eval))))
397 `(setf (get-walker-template-internal ',name
) ',template
))
399 (defun get-walker-template (x context
)
401 (get-walker-template-internal x
))
402 ((and (listp x
) (eq (car x
) 'lambda
))
403 '(lambda repeat
(eval)))
405 ;; FIXME: In an ideal world we would do something similar to
406 ;; COMPILER-ERROR here, replacing the form within the walker
407 ;; with an error-signalling form. This is slightly less
408 ;; pretty, but informative non the less. Best is the enemy of
410 (error "Illegal function call in method body:~% ~S"
413 ;;;; the actual templates
415 ;;; ANSI special forms
416 (define-walker-template block
(nil nil repeat
(eval)))
417 (define-walker-template catch
(nil eval repeat
(eval)))
418 (define-walker-template declare walk-unexpected-declare
)
419 (define-walker-template eval-when
(nil quote repeat
(eval)))
420 (define-walker-template flet walk-flet
)
421 (define-walker-template function
(nil call
))
422 (define-walker-template go
(nil quote
))
423 (define-walker-template if walk-if
)
424 (define-walker-template labels walk-labels
)
425 (define-walker-template lambda walk-lambda
)
426 (define-walker-template let walk-let
)
427 (define-walker-template let
* walk-let
*)
428 (define-walker-template locally walk-locally
)
429 (define-walker-template macrolet walk-macrolet
)
430 (define-walker-template multiple-value-call
(nil eval repeat
(eval)))
431 (define-walker-template multiple-value-prog1
(nil return repeat
(eval)))
432 (define-walker-template multiple-value-setq walk-multiple-value-setq
)
433 (define-walker-template multiple-value-bind walk-multiple-value-bind
)
434 (define-walker-template progn
(nil repeat
(eval)))
435 (define-walker-template progv
(nil eval eval repeat
(eval)))
436 (define-walker-template quote
(nil quote
))
437 (define-walker-template return-from
(nil quote repeat
(return)))
438 (define-walker-template setq walk-setq
)
439 (define-walker-template symbol-macrolet walk-symbol-macrolet
)
440 (define-walker-template tagbody walk-tagbody
)
441 (define-walker-template the
(nil quote eval
))
442 (define-walker-template throw
(nil eval eval
))
443 (define-walker-template unwind-protect
(nil return repeat
(eval)))
445 ;;; SBCL-only special forms
446 (define-walker-template truly-the
(nil quote eval
))
447 ;;; FIXME: maybe we don't need this one any more, given that
448 ;;; NAMED-LAMBDA now expands into (FUNCTION (NAMED-LAMBDA ...))?
449 (define-walker-template named-lambda walk-named-lambda
)
451 (defvar *walk-form-expand-macros-p
* nil
)
453 (defun walk-form (form
454 &optional environment
456 (lambda (subform context env
)
457 (declare (ignore context env
))
459 (walker-environment-bind (new-env environment
:walk-function walk-function
)
460 (walk-form-internal form
:eval new-env
)))
462 ;;; WALK-FORM-INTERNAL is the main driving function for the code
463 ;;; walker. It takes a form and the current context and walks the form
464 ;;; calling itself or the appropriate template recursively.
466 ;;; "It is recommended that a program-analyzing-program process a form
467 ;;; that is a list whose car is a symbol as follows:
469 ;;; 1. If the program has particular knowledge about the symbol,
470 ;;; process the form using special-purpose code. All of the
471 ;;; standard special forms should fall into this category.
472 ;;; 2. Otherwise, if MACRO-FUNCTION is true of the symbol apply
473 ;;; either MACROEXPAND or MACROEXPAND-1 and start over.
474 ;;; 3. Otherwise, assume it is a function call. "
475 (defun walk-form-internal (form context env
)
476 ;; First apply the walk-function to perform whatever translation
477 ;; the user wants to this form. If the second value returned
478 ;; by walk-function is T then we don't recurse...
480 (multiple-value-bind (newform walk-no-more-p
)
481 (funcall (env-walk-function env
) form context env
)
484 (walk-no-more-p newform
)
485 ((not (eq form newform
))
486 (walk-form-internal newform context env
))
487 ((not (consp newform
))
488 (let ((symmac (car (variable-symbol-macro-p newform env
))))
490 (let* ((newnewform (walk-form-internal (cddr symmac
)
494 (if (eq newnewform
(cddr symmac
))
495 (if *walk-form-expand-macros-p
* newnewform newform
)
497 (type (env-var-type newform env
)))
500 `(the ,type
,resultform
)))
503 (let* ((fn (car newform
))
504 (template (get-walker-template fn newform
)))
506 (if (symbolp template
)
507 (funcall template newform context env
)
508 (walk-template newform template context env
))
509 (multiple-value-bind (newnewform macrop
)
510 (walker-environment-bind
511 (new-env env
:walk-form newform
)
512 (%macroexpand-1 newform new-env
))
515 (let ((newnewnewform (walk-form-internal newnewform
518 (if (eq newnewnewform newnewform
)
519 (if *walk-form-expand-macros-p
* newnewform newform
)
523 (special-operator-p fn
))
524 ;; This shouldn't happen, since this walker is now
525 ;; maintained as part of SBCL, so it should know
526 ;; about all the special forms that SBCL knows
528 (bug "unexpected special form ~S" fn
))
530 ;; Otherwise, walk the form as if it's just a
531 ;; standard function call using a template for
532 ;; standard function call.
534 newnewform
'(call repeat
(eval)) context env
))))))))))))
536 (defun walk-template (form template context env
)
539 ((eval function test effect return
)
540 (walk-form-internal form
:eval env
))
543 (walk-form-internal form
:set env
))
545 (cond ((legal-fun-name-p form
)
547 (t (walk-form-internal form context env
)))))
550 (walk-template-handle-repeat form
552 ;; For the case where nothing
553 ;; happens after the repeat
554 ;; optimize away the call to
556 (if (null (cddr template
))
558 (nthcdr (- (length form
)
566 (if (if (listp (cadr template
))
567 (eval (cadr template
))
568 (funcall (cadr template
) form
))
574 (walk-template form
(cadr template
) context env
))
576 (cond ((atom form
) form
)
579 (car form
) (car template
) context env
)
581 (cdr form
) (cdr template
) context env
))))))))
583 (defun walk-template-handle-repeat (form template stop-form context env
)
584 (if (eq form stop-form
)
585 (walk-template form
(cdr template
) context env
)
586 (walk-template-handle-repeat-1
587 form template
(car template
) stop-form context env
)))
589 (defun walk-template-handle-repeat-1 (form template repeat-template
590 stop-form context env
)
591 (cond ((null form
) ())
593 (if (null repeat-template
)
594 (walk-template stop-form
(cdr template
) context env
)
595 (error "while handling code walker REPEAT:
596 ~%ran into STOP while still in REPEAT template")))
597 ((null repeat-template
)
598 (walk-template-handle-repeat-1
599 form template
(car template
) stop-form context env
))
602 (walk-template (car form
) (car repeat-template
) context env
)
603 (walk-template-handle-repeat-1 (cdr form
)
605 (cdr repeat-template
)
610 (defun walk-repeat-eval (form env
)
613 (walk-form-internal (car form
) :eval env
)
614 (walk-repeat-eval (cdr form
) env
))))
616 (defun recons (x car cdr
)
617 (if (or (not (eq (car x
) car
))
618 (not (eq (cdr x
) cdr
)))
622 (defun relist (x &rest args
)
625 (relist-internal x args nil
)))
627 (defun relist* (x &rest args
)
628 (relist-internal x args t
))
630 (defun relist-internal (x args
*p
)
631 (if (null (cdr args
))
634 (recons x
(car args
) nil
))
637 (relist-internal (cdr x
) (cdr args
) *p
))))
641 (defun walk-declarations (body fn env
642 &optional doc-string-p declarations old-body
643 &aux
(form (car body
)) macrop new-form
)
644 (cond ((and (stringp form
) ;might be a doc string
645 (cdr body
) ;isn't the returned value
646 (null doc-string-p
) ;no doc string yet
647 (null declarations
)) ;no declarations yet
650 (walk-declarations (cdr body
) fn env t
)))
651 ((and (listp form
) (eq (car form
) 'declare
))
652 ;; We got ourselves a real live declaration. Record it, look
654 (dolist (declaration (cdr form
))
655 (let ((type (car declaration
))
656 (name (cadr declaration
))
657 (args (cddr declaration
)))
658 (if (walked-var-declaration-p type
)
659 (note-declaration `(,type
660 ,(or (var-lexical-p name env
) name
)
663 (note-declaration (sb!c
::canonized-decl-spec declaration
) env
))
664 (push declaration declarations
)))
668 (cdr body
) fn env doc-string-p declarations
)))
671 (null (get-walker-template (car form
) form
))
673 (multiple-value-setq (new-form macrop
)
674 (%macroexpand-1 form env
))
676 ;; This form was a call to a macro. Maybe it expanded
677 ;; into a declare? Recurse to find out.
678 (walk-declarations (recons body new-form
(cdr body
))
679 fn env doc-string-p declarations
682 ;; Now that we have walked and recorded the declarations,
683 ;; call the function our caller provided to expand the body.
684 ;; We call that function rather than passing the real-body
685 ;; back, because we are RECONSING up the new body.
686 (funcall fn
(or old-body body
) env
))))
688 (defun walk-unexpected-declare (form context env
)
689 (declare (ignore context env
))
690 (warn "encountered ~S ~_in a place where a DECLARE was not expected"
694 (defun walk-arglist (arglist context env
&optional
(destructuringp nil
)
696 (cond ((null arglist
) ())
697 ((symbolp (setq arg
(car arglist
)))
698 (or (member arg sb
!xc
:lambda-list-keywords
:test
#'eq
)
699 (note-var-binding arg env
))
702 (walk-arglist (cdr arglist
)
706 (not (member arg sb
!xc
:lambda-list-keywords
))))))
708 (prog1 (recons arglist
710 (walk-arglist arg context env destructuringp
)
713 (walk-form-internal (cadr arg
) :eval env
)
715 (walk-arglist (cdr arglist
) context env nil
))
716 (if (symbolp (car arg
))
717 (note-var-binding (car arg
) env
)
718 (note-var-binding (cadar arg
) env
))
719 (or (null (cddr arg
))
720 (not (symbolp (caddr arg
)))
721 (note-var-binding (caddr arg
) env
))))
723 (error "can't understand something in the arglist ~S" arglist
))))
725 (defun walk-let (form context env
)
726 (walk-let/let
* form context env nil
))
728 (defun walk-let* (form context env
)
729 (walk-let/let
* form context env t
))
731 (defun walk-let/let
* (form context old-env sequentialp
)
732 (walker-environment-bind (new-env old-env
)
733 (let* ((let/let
* (car form
))
734 (bindings (cadr form
))
740 (lambda (real-body real-env
)
741 (setf walked-bindings
742 (walk-bindings-1 bindings
747 (walk-repeat-eval real-body real-env
))
750 form let
/let
* walked-bindings walked-body
))))
752 (defun walk-locally (form context old-env
)
753 (declare (ignore context
))
754 (walker-environment-bind (new-env old-env
)
755 (let* ((locally (car form
))
758 (walk-declarations body
#'walk-repeat-eval new-env
)))
760 form locally walked-body
))))
762 (defun walk-multiple-value-setq (form context env
)
763 (let ((vars (cadr form
)))
764 (if (some (lambda (var)
765 (variable-symbol-macro-p var env
))
767 (let* ((temps (mapcar (lambda (var)
768 (declare (ignore var
))
771 (sets (mapcar (lambda (var temp
) `(setq ,var
,temp
))
774 (expanded `(multiple-value-bind ,temps
,(caddr form
)
776 (walked (walk-form-internal expanded context env
)))
777 (if (eq walked expanded
)
780 (walk-template form
'(nil (repeat (set)) eval
) context env
))))
782 (defun walk-multiple-value-bind (form context old-env
)
783 (walker-environment-bind (new-env old-env
)
784 (let* ((mvb (car form
))
785 (bindings (cadr form
))
786 (mv-form (walk-template (caddr form
) 'eval context old-env
))
792 (lambda (real-body real-env
)
793 (setq walked-bindings
794 (walk-bindings-1 bindings
799 (walk-repeat-eval real-body real-env
))
801 (relist* form mvb walked-bindings mv-form walked-body
))))
803 (defun walk-bindings-1 (bindings old-env new-env context sequentialp
)
805 (let ((binding (car bindings
)))
807 (if (symbolp binding
)
809 (note-var-binding binding new-env
))
810 (prog1 (relist* binding
812 (walk-form-internal (cadr binding
)
817 ;; Save cddr for DO/DO*; it is
818 ;; the next value form. Don't
819 ;; walk it now, though.
821 (note-var-binding (car binding
) new-env
)))
822 (walk-bindings-1 (cdr bindings
)
828 (defun walk-bindings-2 (bindings walked-bindings context env
)
830 (let ((binding (car bindings
))
831 (walked-binding (car walked-bindings
)))
833 (if (symbolp binding
)
837 (cadr walked-binding
)
838 (walk-template (cddr binding
)
842 (walk-bindings-2 (cdr bindings
)
843 (cdr walked-bindings
)
847 (defun walk-lambda (form context old-env
)
848 (walker-environment-bind (new-env old-env
)
849 (let* ((arglist (cadr form
))
851 (walked-arglist (walk-arglist arglist context new-env
))
853 (walk-declarations body
#'walk-repeat-eval new-env
)))
859 (defun walk-named-lambda (form context old-env
)
860 (walker-environment-bind (new-env old-env
)
861 (let* ((name (second form
))
862 (arglist (third form
))
864 (walked-arglist (walk-arglist arglist context new-env
))
866 (walk-declarations body
#'walk-repeat-eval new-env
)))
873 (defun walk-setq (form context env
)
875 (let* ((expanded (let ((rforms nil
)
877 (loop (when (null tail
) (return (nreverse rforms
)))
878 (let ((var (pop tail
)) (val (pop tail
)))
879 (push `(setq ,var
,val
) rforms
)))))
880 (walked (walk-repeat-eval expanded env
)))
881 (if (eq expanded walked
)
884 (let* ((var (cadr form
))
886 (symmac (car (variable-symbol-macro-p var env
))))
888 (let* ((type (env-var-type var env
))
889 (expanded (if (eq t type
)
890 `(setf ,(cddr symmac
) ,val
)
891 `(setf ,(cddr symmac
) (the ,type
,val
))))
892 (walked (walk-form-internal expanded context env
)))
893 (if (eq expanded walked
)
897 (walk-form-internal var
:set env
)
898 (walk-form-internal val
:eval env
))))))
900 (defun walk-symbol-macrolet (form context old-env
)
901 (declare (ignore context
))
902 (let* ((bindings (cadr form
))
904 (walker-environment-bind
907 (append (mapcar (lambda (binding)
909 sb
!sys
:macro .
,(cadr binding
)))
911 (env-lexical-variables old-env
)))
912 (relist* form
'symbol-macrolet bindings
913 (walk-declarations body
#'walk-repeat-eval new-env
)))))
915 (defun walk-tagbody (form context env
)
916 (recons form
(car form
) (walk-tagbody-1 (cdr form
) context env
)))
918 (defun walk-tagbody-1 (form context env
)
921 (walk-form-internal (car form
)
922 (if (symbolp (car form
)) 'quote context
)
924 (walk-tagbody-1 (cdr form
) context env
))))
926 (defun walk-macrolet (form context old-env
)
927 (walker-environment-bind (old-env old-env
)
928 (walker-environment-bind (macro-env
930 :walk-function
(env-walk-function old-env
))
931 (labels ((walk-definitions (definitions)
933 (let ((definition (car definitions
)))
937 (walk-arglist (cadr definition
)
941 (walk-declarations (cddr definition
)
944 (walk-definitions (cdr definitions
)))))))
945 (with-new-definition-in-environment (new-env old-env form
)
948 (walk-definitions (cadr form
))
949 (walk-declarations (cddr form
)
953 (defun walk-flet (form context old-env
)
954 (walker-environment-bind (old-env old-env
)
955 (labels ((walk-definitions (definitions)
956 (if (null definitions
)
959 (walk-lambda (car definitions
) context old-env
)
960 (walk-definitions (cdr definitions
))))))
964 (walk-definitions (cadr form
))
965 (with-new-definition-in-environment (new-env old-env form
)
966 (walk-declarations (cddr form
)
970 (defun walk-labels (form context old-env
)
971 (walker-environment-bind (old-env old-env
)
972 (with-new-definition-in-environment (new-env old-env form
)
973 (labels ((walk-definitions (definitions)
974 (if (null definitions
)
977 (walk-lambda (car definitions
) context new-env
)
978 (walk-definitions (cdr definitions
))))))
982 (walk-definitions (cadr form
))
983 (walk-declarations (cddr form
)
987 (defun walk-if (form context env
)
988 (destructuring-bind (if predicate arm1
&optional arm2
) form
989 (declare (ignore if
)) ; should be 'IF
992 (walk-form-internal predicate context env
)
993 (walk-form-internal arm1 context env
)
994 (walk-form-internal arm2 context env
))))
999 ;;; Here are some examples of the kinds of things you should be able
1000 ;;; to do with your implementation of the macroexpansion environment
1001 ;;; hacking mechanism.
1003 ;;; WITH-LEXICAL-MACROS is kind of like MACROLET, but it only takes
1004 ;;; names of the macros and actual macroexpansion functions to use to
1005 ;;; macroexpand them. The win about that is that for macros which want
1006 ;;; to wrap several MACROLETs around their body, they can do this but
1007 ;;; have the macroexpansion functions be compiled. See the WITH-RPUSH
1010 ;;; If the implementation had a special way of communicating the
1011 ;;; augmented environment back to the evaluator that would be totally
1012 ;;; great. It would mean that we could just augment the environment
1013 ;;; then pass control back to the implementations own compiler or
1014 ;;; interpreter. We wouldn't have to call the actual walker. That
1015 ;;; would make this much faster. Since the principal client of this is
1016 ;;; defmethod it would make compiling defmethods faster and that would
1017 ;;; certainly be a win.
1019 (defmacro with-lexical-macros
(macros &body body
&environment old-env
)
1020 (with-augmented-environment (new-env old-env
:macros macros
)
1021 (walk-form (cons 'progn body
) :environment new-env
)))
1023 (defun expand-rpush (form env
)
1024 (declare (ignore env
))
1025 `(push ,(caddr form
) ,(cadr form
)))
1027 (defmacro with-rpush
(&body body
)
1028 `(with-lexical-macros ,(list (list 'rpush
#'expand-rpush
)) ,@body
))