1 (in-package "SPECIALIZABLE")
4 ((used :initform nil :accessor used)))
6 (defun make-env (bindings env)
8 (defun find-binding (env var)
11 (defun bindings-from-ll (ll)
12 (mapcar (lambda (n) (cons n (make-instance 'binding))) ll))
14 (define-condition walker-warning (warning)
15 ((env :initarg :env :reader env)
16 (call-stack :initarg :call-stack :reader call-stack)))
17 (define-condition unused-variable (walker-warning)
18 ((name :initarg :name :reader name)))
19 (define-condition unbound-variable-referenced (walker-warning)
20 ((name :initarg :name :reader name)))
23 (defgeneric walk (form env vars)
24 (:generic-function-class cons-generic-function))
26 (defmethod walk ((expr cons) env call-stack)
27 (let ((cs (cons expr call-stack)))
28 (when (consp (car expr))
29 (walk (car expr) env cs))
30 (dolist (e (cdr expr))
31 (walk e env (cons e cs)))))
32 (defmethod walk ((expr symbol) env call-stack)
35 (let ((binding (find-binding env expr)))
37 (setf (used binding) t)
38 (warn 'unbound-variable-referenced :name expr
39 :env env :call-stack call-stack)))))
40 (defmethod walk ((expr t) env call-stack)
42 (defmacro with-checked-bindings ((bindings env call-stack) &body body)
43 `(let* ((bindings ,bindings)
44 (,env (make-env bindings ,env)))
46 (dolist (binding bindings)
47 (unless (used (cdr binding))
48 (warn 'unused-variable :name (car binding)
49 :env ,env :call-stack ,call-stack)))))
50 (defmethod walk ((expr (cons lambda)) env call-stack)
51 (let ((lambda-list (cadr expr))
53 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
55 (walk form env (cons form call-stack))))))
56 (defmethod walk ((expr (cons multiple-value-bind)) env call-stack)
57 (let ((lambda-list (cadr expr))
58 (value-form (caddr expr))
60 (walk value-form env (cons value-form call-stack))
61 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
63 (walk form env (cons form call-stack))))))
64 (defmethod walk ((expr (cons let)) env call-stack)
65 (with-checked-bindings ((mapcar (lambda (x) (walk (cadr x) env (cons (cadr x) call-stack)) (cons (car x) (make-instance 'binding))) (cadr expr)) env call-stack)
66 (dolist (form (cddr expr))
67 (walk form env (cons form call-stack)))))
69 (defun walk/case (expr env call-stack)
74 (let ((binding (find-binding env expr)))
76 (setf (used binding) t)
77 (warn 'unbound-variable-referenced :name expr
78 :env env :call-stack call-stack)))))
80 (let ((lambda-list (cadr expr))
82 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
84 (walk/case form env (cons form call-stack))))))
85 ((cons (eql multiple-value-bind))
86 (let ((lambda-list (cadr expr))
87 (value-form (caddr expr))
89 (walk/case value-form env (cons value-form call-stack))
90 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
92 (walk/case form env (cons form call-stack))))))
93 ((cons (eql macrolet)))
96 ((cons (eql symbol-macrolet)))
99 ((cons (eql tagbody)))
100 ((cons (eql return-from)))
101 ((cons (eql multiple-value-call)))
106 (with-checked-bindings ((mapcar (lambda (x) (walk/case (cadr x) env (cons (cadr x) call-stack)) (cons (car x) (make-instance 'binding))) (cadr expr)) env call-stack)
107 (dolist (form (cddr expr))
108 (walk/case form env (cons form call-stack)))))
110 (let ((cs (cons expr call-stack)))
111 (when (consp (car expr))
112 (walk/case (car expr) env cs))
113 (dolist (e (cdr expr))
114 (walk/case e env (cons e cs)))))
117 (defgeneric walk/meth (expr env call-stack))
119 (defmethod walk/meth ((expr symbol) env call-stack)
122 (let ((binding (find-binding env expr)))
124 (setf (used binding) t)
125 (warn 'unbound-variable-referenced :name expr
126 :env env :call-stack call-stack)))))
127 (defmethod walk/meth ((expr t) env call-stack)
130 (defmethod walk/meth ((expr cons) env call-stack)
133 (let ((lambda-list (cadr expr))
135 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
137 (walk/meth form env (cons form call-stack))))))
138 ((cons (eql multiple-value-bind))
139 (let ((lambda-list (cadr expr))
140 (value-form (caddr expr))
142 (walk/meth value-form env (cons value-form call-stack))
143 (with-checked-bindings ((bindings-from-ll lambda-list) env call-stack)
145 (walk/meth form env (cons form call-stack))))))
146 ((cons (eql macrolet)))
148 ((cons (eql labels)))
149 ((cons (eql symbol-macrolet)))
152 ((cons (eql tagbody)))
153 ((cons (eql return-from)))
154 ((cons (eql multiple-value-call)))
159 (with-checked-bindings ((mapcar (lambda (x) (walk/meth (cadr x) env (cons (cadr x) call-stack)) (cons (car x) (make-instance 'binding))) (cadr expr)) env call-stack)
160 (dolist (form (cddr expr))
161 (walk/meth form env (cons form call-stack)))))
163 (let ((cs (cons expr call-stack)))
164 (when (consp (car expr))
165 (walk/meth (car expr) env cs))
166 (dolist (e (cdr expr))
167 (walk/meth e env (cons e cs)))))))