~ubuntu-branches/ubuntu/intrepid/ecl/intrepid

« back to all changes in this revision

Viewing changes to src/clos/method.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Albin Tonnerre
  • Date: 2008-06-20 18:00:19 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080620180019-7fbz1ln5444vtkkr
Tags: 0.9j-20080306-2ubuntu1
* Enabled unicode support. (Closes: LP #123530)
* Modify Maintainer value to match the DebianMaintainerField specification.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;;  -*- Mode: Lisp; Syntax: Common-Lisp; Package: CLOS -*-
 
2
;;;;
1
3
;;;;  Copyright (c) 1992, Giuseppe Attardi.
2
4
;;;;
3
5
;;;;    This program is free software; you can redistribute it and/or
96
98
              ,@(and class-declarations `((declare ,@class-declarations)))
97
99
              ,@real-body))
98
100
           
99
 
           (original-args ())
100
 
           (applyp nil)         ; flag indicating whether or not the
101
 
                                ; method takes &mumble arguments. If
102
 
                                ; it does, it means call-next-method
103
 
                                ; without arguments must be APPLY'd
104
 
                                ; to original-args.  If this gets set
105
 
                                ; true, save-original-args is set so
106
 
                                ; as well
107
101
           (aux-bindings ())    ; Suffice to say that &aux is one of
108
102
                                ; damndest things to have put in a
109
103
                                ; language.
110
104
           (plist ()))
111
 
      (multiple-value-bind (walked-lambda call-next-method-p
112
 
                                          save-original-args next-method-p-p)
 
105
      (multiple-value-bind (call-next-method-p next-method-p-p in-closure-p)
113
106
          (walk-method-lambda method-lambda required-parameters env)
114
107
 
115
 
        ;; Scan the lambda list to determine whether this method
116
 
        ;; takes &mumble arguments.  If it does, we set applyp and
117
 
        ;; save-original-args true.
118
 
        ;;
119
 
        ;; This is also the place where we construct the original
120
 
        ;; arguments lambda list if there has to be one.
121
 
        (dolist (p lambda-list)
122
 
          (if (member p '(&OPTIONAL &REST &KEY &ALLOW-OTHER-KEYS &AUX)
123
 
                      :test #'eq)       ; cant use lambda-list-keywords
124
 
              (if (eq p '&aux)
125
 
                  (progn
126
 
                    (setq aux-bindings (cdr (member '&AUX lambda-list
127
 
                                                    :test #'eq)))
128
 
                    (return nil))
129
 
                  (progn
130
 
                    (setq applyp t
131
 
                          save-original-args t)
132
 
                    (push '&REST original-args)
133
 
                    (push (make-symbol "AMPERSAND-ARGS") original-args)
134
 
                    (return nil)))
135
 
              (push (make-symbol (symbol-name p)) original-args)))
136
 
        (setq original-args (when save-original-args
137
 
                              (nreverse original-args)))
138
 
 
139
 
        (multiple-value-bind (walked-declarations walked-lambda-body)
140
 
            (sys::find-declarations (cdddr walked-lambda) t)
141
 
          (declare (ignore ignore))
142
 
 
143
 
          (when (or next-method-p-p call-next-method-p)
144
 
            (setq plist (list* :needs-next-methods-p 'T plist)))
145
 
 
146
 
          (values
147
 
           (let ((walked-lambda `(ext::lambda-block ,(second walked-lambda)
148
 
                                  ,lambda-list
149
 
                                  ,@walked-declarations
150
 
                                  ,.walked-lambda-body)))
151
 
             (if (or call-next-method-p next-method-p-p)
152
 
                 `(function ,(add-lexical-functions-to-method-lambda
153
 
                              walked-declarations
154
 
                              walked-lambda-body
155
 
                              generic-function-name
156
 
                              walked-lambda
157
 
                              original-args
158
 
                              lambda-list
159
 
                              save-original-args
160
 
                              applyp
161
 
                              aux-bindings
162
 
                              call-next-method-p
163
 
                              next-method-p-p))
164
 
                 `(function ,walked-lambda)))
165
 
           documentation
166
 
           plist))))))
 
108
        (when (or call-next-method-p next-method-p-p)
 
109
          (setf plist '(:needs-next-method-p t)))
 
110
 
 
111
        (when in-closure-p
 
112
          (setf plist '(:needs-next-method-p FUNCTION))
 
113
          (setf real-body
 
114
                `((let* ((.combined-method-args.
 
115
                          (if (listp .combined-method-args.)
 
116
                              .combined-method-args.
 
117
                              (apply #'list .combined-method-args.)))
 
118
                         (.next-methods. *next-methods*))
 
119
                    (flet ((call-next-method (&rest args)
 
120
                             (unless .next-methods.
 
121
                               (error "No next method"))
 
122
                             (funcall (car .next-methods.)
 
123
                                      (or args .combined-method-args.)
 
124
                                      (rest .next-methods.)))
 
125
                           (next-method-p ()
 
126
                             .next-methods.))
 
127
                      ,@real-body)))))
 
128
        (values
 
129
         `(ext::lambda-block ,generic-function-name
 
130
              ,lambda-list
 
131
              ,@(and class-declarations `((declare ,@class-declarations)))
 
132
              ,@real-body)
 
133
         documentation
 
134
         plist)))))
 
135
 
 
136
(defun environment-contains-closure (env)
 
137
  ;;
 
138
  ;; As explained in compiler.d (make_lambda()), we use a symbol with name
 
139
  ;; "FUNCTION" to mark the beginning of a function. If we find that symbol
 
140
  ;; twice, it is quite likely that this form will end up in a closure.
 
141
  ;;
 
142
  (flet ((function-boundary (s)
 
143
           (and (consp s)
 
144
                (symbolp (setf s (first s)))
 
145
                (null (symbol-package s))
 
146
                (equal (symbol-name s) "FUNCTION"))))
 
147
    (> (count-if #'function-boundary (car env)) 1)))
167
148
 
168
149
(defun walk-method-lambda (method-lambda required-parameters env)
169
150
  (declare (si::c-local))
170
151
  (let ((call-next-method-p nil)
171
152
        (next-method-p-p nil)
172
 
        (save-original-args-p nil))
 
153
        (in-closure-p nil))
173
154
    (flet ((code-walker (form env)
174
155
             (unless (atom form)
175
156
               (let ((name (first form)))
176
157
                 (case name
177
158
                   (CALL-NEXT-METHOD
178
159
                    (setf call-next-method-p
179
 
                          (or call-next-method-p T))
180
 
                    (unless (rest form)
181
 
                      (setf save-original-args-p t)))
 
160
                          (or call-next-method-p T)
 
161
                          in-closure-p
 
162
                          (or in-closure-p (environment-contains-closure env))))
182
163
                   (NEXT-METHOD-P
183
 
                    (setf next-method-p-p t))
 
164
                    (setf next-method-p-p t
 
165
                          in-closure-p (or in-closure-p (environment-contains-closure env))))
184
166
                   (FUNCTION
185
167
                    (when (eq (second form) 'CALL-NEXT-METHOD)
186
 
                      (setf save-original-args-p t
 
168
                      (setf in-closure-p t
187
169
                            call-next-method-p 'FUNCTION))
188
170
                    (when (eq (second form) 'NEXT-METHOD-P)
189
 
                      (setf next-method-p-p 'FUNCTION))))))
 
171
                      (setf next-method-p-p 'FUNCTION
 
172
                            in-closure-p t))))))
190
173
             form))
191
174
      (let ((si::*code-walker* #'code-walker))
192
175
        (coerce method-lambda 'function)))
193
 
    (values method-lambda call-next-method-p
194
 
            save-original-args-p
195
 
            next-method-p-p)))
196
 
 
197
 
(defun add-lexical-functions-to-method-lambda (walked-declarations
198
 
                                               walked-lambda-body
199
 
                                               generic-function-name
200
 
                                               walked-lambda
201
 
                                               original-args
202
 
                                               lambda-list
203
 
                                               save-original-args
204
 
                                               applyp
205
 
                                               aux-bindings
206
 
                                               call-next-method-p
207
 
                                               next-method-p-p)
208
 
  (declare (si::c-local))
209
 
  ;;
210
 
  ;; WARNING: these &rest/apply combinations produce useless garbage. Beppe
211
 
  ;;
212
 
  (cond ((and (null save-original-args)
213
 
              (null applyp))
214
 
         ;;
215
 
         ;; We don't have to save the original arguments.  In addition,
216
 
         ;; this method doesn't take any &mumble arguments (this means
217
 
         ;; that there is no way the lexical functions can be used inside
218
 
         ;; of the default value form for an &mumble argument).
219
 
         ;;
220
 
         ;; We can expand this into a simple lambda expression with an
221
 
         ;; FLET to define the lexical functions.
222
 
         ;;
223
 
         `(ext::lambda-block ,generic-function-name ,lambda-list
224
 
            ,@walked-declarations
225
 
           (declare (special *next-methods*))
226
 
            (let* ((.next-method. (car *next-methods*))
227
 
                   (*next-methods* (cdr *next-methods*)))
228
 
              (declare (special *next-methods*))
229
 
              (flet (,@(and call-next-method-p
230
 
                            '((CALL-NEXT-METHOD (&REST CNM-ARGS)
231
 
                                ;; (declare (static-extent cnm-args))
232
 
                                (IF .NEXT-METHOD.
233
 
                                    (APPLY .NEXT-METHOD. CNM-ARGS)
234
 
                                    (ERROR "No next method.")))))
235
 
                     ,@(and next-method-p-p
236
 
                            '((NEXT-METHOD-P ()
237
 
                                (NOT (NULL .NEXT-METHOD.))))))
238
 
                ,@walked-lambda-body)))
239
 
         ;; Assuming that we can determine statically which is the next method,
240
 
         ;; we could use this solution. Compute-effective-method can set
241
 
         ;; the value of .next-method. within each closure at the appropriate
242
 
         ;; value. Same thing for next case.    Beppe
243
 
         ;;      `(let (.next-method.)
244
 
         ;;         (lambda ,lambda-list
245
 
         ;;           ,@walked-declarations
246
 
         ;;           (flet (,@(and call-next-method-p
247
 
         ;;                         '((CALL-NEXT-METHOD (&REST CNM-ARGS)
248
 
         ;;                             ;; (declare (static-extent cnm-args))
249
 
         ;;                             (IF .NEXT-METHOD.
250
 
         ;;                                 (APPLY .NEXT-METHOD. CNM-ARGS)
251
 
         ;;                                 (ERROR "No next method.")))))
252
 
         ;;                  ,@(and next-method-p-p
253
 
         ;;                         '((NEXT-METHOD-P ()
254
 
         ;;                             (NOT (NULL .NEXT-METHOD.))))))
255
 
         ;;             ,@walked-lambda-body)))
256
 
         )
257
 
        ((null applyp)
258
 
         ;;
259
 
         ;; This method doesn't accept any &mumble arguments.  But we
260
 
         ;; do have to save the original arguments (this is because
261
 
         ;; call-next-method is being called with no arguments).
262
 
         ;; Have to be careful though, there may be multiple calls to
263
 
         ;; call-next-method, all we know is that at least one of them
264
 
         ;; is with no arguments.
265
 
         ;;
266
 
         `(ext::lambda-block ,generic-function-name ,original-args
267
 
            (declare (special *next-methods*))
268
 
            (let* ((.next-method. (car *next-methods*))
269
 
                   (*next-methods* (cdr *next-methods*)))
270
 
              (declare (special *next-methods*))
271
 
              (flet (,@(and call-next-method-p
272
 
                            `((call-next-method (&rest cnm-args)
273
 
                                ;; (declare (static-extent cnm-args))
274
 
                                (if .next-method.
275
 
                                    (if cnm-args
276
 
                                        (apply .next-method. cnm-args)
277
 
                                        (funcall .next-method. ,@original-args))
278
 
                                    (error "No next method.")))))
279
 
                     ,@(and next-method-p-p
280
 
                            '((NEXT-METHOD-P ()
281
 
                                (NOT (NULL .NEXT-METHOD.))))))
282
 
                (let* (,@(mapcar #'list
283
 
                                 (subseq lambda-list 0
284
 
                                         (position '&AUX lambda-list))
285
 
                                 original-args)
286
 
                       ,@aux-bindings)
287
 
                  ,@walked-declarations
288
 
                  ,@walked-lambda-body)))))
289
 
        (t
290
 
         ;;
291
 
         ;; This is the fully general case.
292
 
         ;; We must allow for the lexical functions being used inside
293
 
         ;; the default value forms of &mumble arguments, and if must
294
 
         ;; allow for call-next-method being called with no arguments.
295
 
         ;;
296
 
         `(lambda ,original-args
297
 
            (declare (special *next-methods*))
298
 
            (let* ((.next-method. (car *next-methods*))
299
 
                   (*next-methods* (cdr *next-methods*)))
300
 
              (declare (special *next-methods*))
301
 
              (flet (,@(and call-next-method-p
302
 
                            `((call-next-method (&rest cnm-args)
303
 
                                ;; (declare (static-extent cnm-args))
304
 
                                (if .next-method.
305
 
                                    (if cnm-args
306
 
                                        (apply .next-method. cnm-args)
307
 
                                        (apply .next-method.
308
 
                                               ,@(remove '&REST original-args)))
309
 
                                    (error "No next method.")))))
310
 
                     ,@(and next-method-p-p
311
 
                            '((NEXT-METHOD-P ()
312
 
                                (NOT (NULL .NEXT-METHOD.))))))
313
 
                (apply (function ,walked-lambda)
314
 
                       ,@(remove '&REST original-args))))))))
315
 
 
 
176
    (values call-next-method-p
 
177
            next-method-p-p
 
178
            in-closure-p)))
316
179
 
317
180
;;; ----------------------------------------------------------------------
318
181
;;;                                                                parsing