Mercurial > emacs
comparison lisp/emacs-lisp/eieio.el @ 104431:a64f3429f0ac
emacs-lisp/eieio-base.el, emacs-lisp/eieio-comp.el,
emacs-lisp/eieio-custom.el, emacs-lisp/eieio-datadebug.el,
emacs-lisp/eieio-doc.el, emacs-lisp/eieio-opt.el,
emacs-lisp/eieio-speedbar.el, emacs-lisp/eieio.el: Move from eieio/directory.
author | Chong Yidong <cyd@stupidchicken.com> |
---|---|
date | Sun, 30 Aug 2009 02:02:15 +0000 |
parents | |
children | 5fabb7947fa5 |
comparison
equal
deleted
inserted
replaced
104430:b93dbe652ecd | 104431:a64f3429f0ac |
---|---|
1 ;;; eieio.el --- Enhanced Implementation of Emacs Interpreted Objects | |
2 ;;; or maybe Eric's Implementation of Emacs Intrepreted Objects | |
3 | |
4 ;;; Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, | |
5 ;;; 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. | |
6 | |
7 ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
8 ;; Version: 0.2 | |
9 ;; Keywords: OO, lisp | |
10 | |
11 ;; This file is part of GNU Emacs. | |
12 | |
13 ;; GNU Emacs is free software: you can redistribute it and/or modify | |
14 ;; it under the terms of the GNU General Public License as published by | |
15 ;; the Free Software Foundation, either version 3 of the License, or | |
16 ;; (at your option) any later version. | |
17 | |
18 ;; GNU Emacs is distributed in the hope that it will be useful, | |
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 ;; GNU General Public License for more details. | |
22 | |
23 ;; You should have received a copy of the GNU General Public License | |
24 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | |
25 | |
26 ;;; Commentary: | |
27 ;; | |
28 ;; EIEIO is a series of Lisp routines which implements a subset of | |
29 ;; CLOS, the Common Lisp Object System. In addition, EIEIO also adds | |
30 ;; a few new features which help it integrate more strongly with the | |
31 ;; Emacs running environment. | |
32 ;; | |
33 ;; See eieio.texi for complete documentation on using this package. | |
34 | |
35 ;; There is funny stuff going on with typep and deftype. This | |
36 ;; is the only way I seem to be able to make this stuff load properly. | |
37 | |
38 ;; @TODO - fix :initform to be a form, not a quoted value | |
39 ;; @TODO - For API calls like `object-p', replace with something | |
40 ;; that does not conflict with "object", meaning a lisp object. | |
41 ;; @TODO - Prefix non-clos functions with `eieio-'. | |
42 | |
43 ;;; Code: | |
44 | |
45 (defvar eieio-version "1.2" | |
46 "Current version of EIEIO.") | |
47 | |
48 (require 'cl) | |
49 | |
50 (defun eieio-version () | |
51 "Display the current version of EIEIO." | |
52 (interactive) | |
53 (message eieio-version)) | |
54 | |
55 (eval-and-compile | |
56 ;; Abount the above. EIEIO must process it's own code when it compiles | |
57 ;; itself, thus, by eval-and-compiling outselves, we solve the problem. | |
58 | |
59 ;; Compatibility | |
60 (if (fboundp 'compiled-function-arglist) | |
61 | |
62 ;; XEmacs can only access a compiled functions arglist like this: | |
63 (defalias 'eieio-compiled-function-arglist 'compiled-function-arglist) | |
64 | |
65 ;; Emacs doesn't have this function, but since FUNC is a vector, we can just | |
66 ;; grab the appropriate element. | |
67 (defun eieio-compiled-function-arglist (func) | |
68 "Return the argument list for the compiled function FUNC." | |
69 (aref func 0)) | |
70 | |
71 ) | |
72 | |
73 | |
74 ;;; | |
75 ;; Variable declarations. | |
76 ;; | |
77 | |
78 (defvar eieio-hook nil | |
79 "*This hook is executed, then cleared each time `defclass' is called.") | |
80 | |
81 (defvar eieio-error-unsupported-class-tags nil | |
82 "*Non nil to throw an error if an encountered tag us unsupported. | |
83 This may prevent classes from CLOS applications from being used with EIEIO | |
84 since EIEIO does not support all CLOS tags.") | |
85 | |
86 (defvar eieio-skip-typecheck nil | |
87 "*If non-nil, skip all slot typechecking. | |
88 Set this to t permanently if a program is functioning well to get a | |
89 small speed increase. This variable is also used internally to handle | |
90 default setting for optimization purposes.") | |
91 | |
92 (defvar eieio-optimize-primary-methods-flag t | |
93 "Non-nil means to optimize the method dispatch on primary methods.") | |
94 | |
95 ;; State Variables | |
96 (defvar this nil | |
97 "Inside a method, this variable is the object in question. | |
98 DO NOT SET THIS YOURSELF unless you are trying to simulate friendly slots. | |
99 | |
100 Note: Embedded methods are no longer supported. The variable THIS is | |
101 still set for CLOS methods for the sake of routines like | |
102 `call-next-method'") | |
103 | |
104 (defvar scoped-class nil | |
105 "This is set to a class when a method is running. | |
106 This is so we know we are allowed to check private parts or how to | |
107 execute a `call-next-method'. DO NOT SET THIS YOURSELF!") | |
108 | |
109 (defvar eieio-initializing-object nil | |
110 "Set to non-nil while initializing an object.") | |
111 | |
112 (defconst eieio-unbound (make-symbol "unbound") | |
113 "Uninterned symbol representing an unbound slot in an object.") | |
114 | |
115 ;; This is a bootstrap for eieio-default-superclass so it has a value | |
116 ;; while it is being built itself. | |
117 (defvar eieio-default-superclass nil) | |
118 | |
119 (defconst class-symbol 1 "Class's symbol (self-referencing.).") | |
120 (defconst class-parent 2 "Class parent slot.") | |
121 (defconst class-children 3 "Class children class slot.") | |
122 (defconst class-symbol-obarray 4 "Obarray permitting fast access to variable position indexes.") | |
123 ;; @todo | |
124 ;; the word "public" here is leftovers from the very first version. | |
125 ;; Get rid of it! | |
126 (defconst class-public-a 5 "Class attribute index.") | |
127 (defconst class-public-d 6 "Class attribute defaults index.") | |
128 (defconst class-public-doc 7 "Class documentation strings for attributes.") | |
129 (defconst class-public-type 8 "Class type for a slot.") | |
130 (defconst class-public-custom 9 "Class custom type for a slot.") | |
131 (defconst class-public-custom-label 10 "Class custom group for a slot.") | |
132 (defconst class-public-custom-group 11 "Class custom group for a slot.") | |
133 (defconst class-public-printer 12 "Printer for a slot.") | |
134 (defconst class-protection 13 "Class protection for a slot.") | |
135 (defconst class-initarg-tuples 14 "Class initarg tuples list.") | |
136 (defconst class-class-allocation-a 15 "Class allocated attributes.") | |
137 (defconst class-class-allocation-doc 16 "Class allocated documentation.") | |
138 (defconst class-class-allocation-type 17 "Class allocated value type.") | |
139 (defconst class-class-allocation-custom 18 "Class allocated custom descriptor.") | |
140 (defconst class-class-allocation-custom-label 19 "Class allocated custom descriptor.") | |
141 (defconst class-class-allocation-custom-group 20 "Class allocated custom group.") | |
142 (defconst class-class-allocation-printer 21 "Class allocated printer for a slot.") | |
143 (defconst class-class-allocation-protection 22 "Class allocated protection list.") | |
144 (defconst class-class-allocation-values 23 "Class allocated value vector.") | |
145 (defconst class-default-object-cache 24 | |
146 "Cache index of what a newly created object would look like. | |
147 This will speed up instantiation time as only a `copy-sequence' will | |
148 be needed, instead of looping over all the values and setting them | |
149 from the default.") | |
150 (defconst class-options 25 | |
151 "Storage location of tagged class options. | |
152 Stored outright without modifications or stripping.") | |
153 | |
154 (defconst class-num-slots 26 | |
155 "Number of slots in the class definition object.") | |
156 | |
157 (defconst object-class 1 "Index in an object vector where the class is stored.") | |
158 (defconst object-name 2 "Index in an object where the name is stored.") | |
159 | |
160 (defconst method-static 0 "Index into :static tag on a method.") | |
161 (defconst method-before 1 "Index into :before tag on a method.") | |
162 (defconst method-primary 2 "Index into :primary tag on a method.") | |
163 (defconst method-after 3 "Index into :after tag on a method.") | |
164 (defconst method-num-lists 4 "Number of indexes into methods vector in which groups of functions are kept.") | |
165 (defconst method-generic-before 4 "Index into generic :before tag on a method.") | |
166 (defconst method-generic-primary 5 "Index into generic :primary tag on a method.") | |
167 (defconst method-generic-after 6 "Index into generic :after tag on a method.") | |
168 (defconst method-num-slots 7 "Number of indexes into a method's vector.") | |
169 | |
170 ;; How to specialty compile stuff. | |
171 (autoload 'byte-compile-file-form-defmethod "eieio-comp" | |
172 "This function is used to byte compile methods in a nice way.") | |
173 (put 'defmethod 'byte-hunk-handler 'byte-compile-file-form-defmethod) | |
174 | |
175 (eval-when-compile (require 'eieio-comp)) | |
176 | |
177 | |
178 ;;; Important macros used in eieio. | |
179 ;; | |
180 (defmacro class-v (class) | |
181 "Internal: Return the class vector from the CLASS symbol." | |
182 ;; No check: If eieio gets this far, it's probably been checked already. | |
183 `(get ,class 'eieio-class-definition)) | |
184 | |
185 (defmacro class-p (class) | |
186 "Return t if CLASS is a valid class vector. | |
187 CLASS is a symbol." | |
188 ;; this new method is faster since it doesn't waste time checking lots of | |
189 ;; things. | |
190 `(condition-case nil | |
191 (eq (aref (class-v ,class) 0) 'defclass) | |
192 (error nil))) | |
193 | |
194 ;;;###autoload | |
195 (defmacro eieio-object-p (obj) | |
196 "Return non-nil if OBJ is an EIEIO object." | |
197 `(condition-case nil | |
198 (let ((tobj ,obj)) | |
199 (and (eq (aref tobj 0) 'object) | |
200 (class-p (aref tobj object-class)))) | |
201 (error nil))) | |
202 (defalias 'object-p 'eieio-object-p) | |
203 | |
204 (defmacro class-constructor (class) | |
205 "Return the symbol representing the constructor of CLASS." | |
206 `(aref (class-v ,class) class-symbol)) | |
207 | |
208 (defmacro generic-p (method) | |
209 "Return t if symbol METHOD is a generic function. | |
210 Only methods have the symbol `eieio-method-obarray' as a property (which | |
211 contains a list of all bindings to that method type.)" | |
212 `(and (fboundp ,method) (get ,method 'eieio-method-obarray))) | |
213 | |
214 (defun generic-primary-only-p (method) | |
215 "Return t if symbol METHOD is a generic function with only primary methods. | |
216 Only methods have the symbol `eieio-method-obarray' as a property (which | |
217 contains a list of all bindings to that method type.) | |
218 Methods with only primary implementations are executed in an optimized way." | |
219 (and (generic-p method) | |
220 (let ((M (get method 'eieio-method-tree))) | |
221 (and (< 0 (length (aref M method-primary))) | |
222 (not (aref M method-static)) | |
223 (not (aref M method-before)) | |
224 (not (aref M method-after)) | |
225 (not (aref M method-generic-before)) | |
226 (not (aref M method-generic-primary)) | |
227 (not (aref M method-generic-after)))) | |
228 )) | |
229 | |
230 (defun generic-primary-only-one-p (method) | |
231 "Return t if symbol METHOD is a generic function with only primary methods. | |
232 Only methods have the symbol `eieio-method-obarray' as a property (which | |
233 contains a list of all bindings to that method type.) | |
234 Methods with only primary implementations are executed in an optimized way." | |
235 (and (generic-p method) | |
236 (let ((M (get method 'eieio-method-tree))) | |
237 (and (= 1 (length (aref M method-primary))) | |
238 (not (aref M method-static)) | |
239 (not (aref M method-before)) | |
240 (not (aref M method-after)) | |
241 (not (aref M method-generic-before)) | |
242 (not (aref M method-generic-primary)) | |
243 (not (aref M method-generic-after)))) | |
244 )) | |
245 | |
246 (defmacro class-option-assoc (list option) | |
247 "Return from LIST the found OPTION. Nil if it doesn't exist." | |
248 `(car-safe (cdr (memq ,option ,list)))) | |
249 | |
250 (defmacro class-option (class option) | |
251 "Return the value stored for CLASS' OPTION. | |
252 Return nil if that option doesn't exist." | |
253 `(class-option-assoc (aref (class-v ,class) class-options) ',option)) | |
254 | |
255 (defmacro class-abstract-p (class) | |
256 "Return non-nil if CLASS is abstract. | |
257 Abstract classes cannot be instantiated." | |
258 `(class-option ,class :abstract)) | |
259 | |
260 (defmacro class-method-invocation-order (class) | |
261 "Return the invocation order of CLASS. | |
262 Abstract classes cannot be instantiated." | |
263 `(or (class-option ,class :method-invocation-order) | |
264 :breadth-first)) | |
265 | |
266 | |
267 ;;; Defining a new class | |
268 ;; | |
269 (defmacro defclass (name superclass slots &rest options-and-doc) | |
270 "Define NAME as a new class derived from SUPERCLASS with SLOTS. | |
271 OPTIONS-AND-DOC is used as the class' options and base documentation. | |
272 SUPERCLASS is a list of superclasses to inherit from, with SLOTS | |
273 being the slots residing in that class definition. NOTE: Currently | |
274 only one slot may exist in SUPERCLASS as multiple inheritance is not | |
275 yet supported. Supported tags are: | |
276 | |
277 :initform - initializing form | |
278 :initarg - tag used during initialization | |
279 :accessor - tag used to create a function to access this slot | |
280 :allocation - specify where the value is stored. | |
281 defaults to `:instance', but could also be `:class' | |
282 :writer - a function symbol which will `write' an object's slot | |
283 :reader - a function symbol which will `read' an object | |
284 :type - the type of data allowed in this slot (see `typep') | |
285 :documentation | |
286 - A string documenting use of this slot. | |
287 | |
288 The following are extensions on CLOS: | |
289 :protection - Specify protection for this slot. | |
290 Defaults to `:public'. Also use `:protected', or `:private' | |
291 :custom - When customizing an object, the custom :type. Public only. | |
292 :label - A text string label used for a slot when customizing. | |
293 :group - Name of a customization group this slot belongs in. | |
294 :printer - A function to call to print the value of a slot. | |
295 See `eieio-override-prin1' as an example. | |
296 | |
297 A class can also have optional options. These options happen in place | |
298 of documentation, (including a :documentation tag) in addition to | |
299 documentation, or not at all. Supported options are: | |
300 | |
301 :documentation - The doc-string used for this class. | |
302 | |
303 Options added to EIEIO: | |
304 | |
305 :allow-nil-initform - Non-nil to skip typechecking of initforms if nil. | |
306 :custom-groups - List of custom group names. Organizes slots into | |
307 reasonable groups for customizations. | |
308 :abstract - Non-nil to prevent instances of this class. | |
309 If a string, use as an error string if someone does | |
310 try to make an instance. | |
311 :method-invocation-order | |
312 - Control the method invokation order if there is | |
313 multiple inheritance. Valid values are: | |
314 :breadth-first - The default. | |
315 :depth-first | |
316 | |
317 Options in CLOS not supported in EIEIO: | |
318 | |
319 :metaclass - Class to use in place of `standard-class' | |
320 :default-initargs - Initargs to use when initializing new objects of | |
321 this class. | |
322 | |
323 Due to the way class options are set up, you can add any tags in you | |
324 wish, and reference them using the function `class-option'." | |
325 ;; We must `eval-and-compile' this so that when we byte compile | |
326 ;; an eieio program, there is no need to load it ahead of time. | |
327 ;; It also provides lots of nice debugging errors at compile time. | |
328 `(eval-and-compile | |
329 (eieio-defclass ',name ',superclass ',slots ',options-and-doc))) | |
330 | |
331 (defvar eieio-defclass-autoload-map (make-vector 7 nil) | |
332 "Symbol map of superclasses we find in autoloads.") | |
333 | |
334 (defun eieio-defclass-autoload (cname superclasses filename doc) | |
335 "Create autoload symbols for the EIEIO class CNAME. | |
336 SUPERCLASSES are the superclasses that CNAME inherites from. | |
337 DOC is the docstring for CNAME. | |
338 This function creates a mock-class for CNAME and adds it into | |
339 SUPERCLASSES as children. | |
340 It creates an autoload function for CNAME's constructor." | |
341 ;; Assume we've already debugged inputs. | |
342 | |
343 (let* ((oldc (when (class-p cname) (class-v cname))) | |
344 (newc (make-vector class-num-slots nil)) | |
345 ) | |
346 (if oldc | |
347 nil ;; Do nothing if we already have this class. | |
348 | |
349 ;; Create the class in NEWC, but don't fill anything else in. | |
350 (aset newc 0 'defclass) | |
351 (aset newc class-symbol cname) | |
352 | |
353 (let ((clear-parent nil)) | |
354 ;; No parents? | |
355 (when (not superclasses) | |
356 (setq superclasses '(eieio-default-superclass) | |
357 clear-parent t) | |
358 ) | |
359 | |
360 ;; Hook our new class into the existing structures so we can | |
361 ;; autoload it later. | |
362 (dolist (SC superclasses) | |
363 | |
364 | |
365 ;; TODO - If we create an autoload that is in the map, that | |
366 ;; map needs to be cleared! | |
367 | |
368 | |
369 ;; Does our parent exist? | |
370 (if (not (class-p SC)) | |
371 | |
372 ;; Create a symbol for this parent, and then store this | |
373 ;; parent on that symbol. | |
374 (let ((sym (intern (symbol-name SC) eieio-defclass-autoload-map))) | |
375 (if (not (boundp sym)) | |
376 (set sym (list cname)) | |
377 (add-to-list sym cname)) | |
378 ) | |
379 | |
380 ;; We have a parent, save the child in there. | |
381 (when (not (member cname (aref (class-v SC) class-children))) | |
382 (aset (class-v SC) class-children | |
383 (cons cname (aref (class-v SC) class-children))))) | |
384 | |
385 ;; save parent in child | |
386 (aset newc class-parent (cons SC (aref newc class-parent))) | |
387 ) | |
388 | |
389 ;; turn this into a useable self-pointing symbol | |
390 (set cname cname) | |
391 | |
392 ;; Store the new class vector definition into the symbol. We need to | |
393 ;; do this first so that we can call defmethod for the accessor. | |
394 ;; The vector will be updated by the following while loop and will not | |
395 ;; need to be stored a second time. | |
396 (put cname 'eieio-class-definition newc) | |
397 | |
398 ;; Clear the parent | |
399 (if clear-parent (aset newc class-parent nil)) | |
400 | |
401 ;; Create an autoload on top of our constructor function. | |
402 (autoload cname filename doc nil nil) | |
403 (autoload (intern (concat (symbol-name cname) "-p")) filename "" nil nil) | |
404 (autoload (intern (concat (symbol-name cname) "-child-p")) filename "" nil nil) | |
405 | |
406 )))) | |
407 | |
408 (defsubst eieio-class-un-autoload (cname) | |
409 "If class CNAME is in an autoload state, load it's file." | |
410 (when (eq (car-safe (symbol-function cname)) 'autoload) | |
411 (load-library (car (cdr (symbol-function cname)))))) | |
412 | |
413 (defun eieio-defclass (cname superclasses slots options-and-doc) | |
414 "See `defclass' for more information. | |
415 Define CNAME as a new subclass of SUPERCLASSES, with SLOTS being the | |
416 slots residing in that class definition, and with options or documentation | |
417 OPTIONS-AND-DOC as the toplevel documentation for this class." | |
418 ;; Run our eieio-hook each time, and clear it when we are done. | |
419 ;; This way people can add hooks safely if they want to modify eieio | |
420 ;; or add definitions when eieio is loaded or something like that. | |
421 (run-hooks 'eieio-hook) | |
422 (setq eieio-hook nil) | |
423 | |
424 (if (not (symbolp cname)) (signal 'wrong-type-argument '(symbolp cname))) | |
425 (if (not (listp superclasses)) (signal 'wrong-type-argument '(listp superclasses))) | |
426 | |
427 (let* ((pname (if superclasses superclasses nil)) | |
428 (newc (make-vector class-num-slots nil)) | |
429 (oldc (when (class-p cname) (class-v cname))) | |
430 (groups nil) ;; list of groups id'd from slots | |
431 (options nil) | |
432 (clearparent nil)) | |
433 | |
434 (aset newc 0 'defclass) | |
435 (aset newc class-symbol cname) | |
436 | |
437 ;; If this class already existed, and we are updating it's structure, | |
438 ;; make sure we keep the old child list. This can cause bugs, but | |
439 ;; if no new slots are created, it also saves time, and prevents | |
440 ;; method table breakage, particularly when the users is only | |
441 ;; byte compiling an EIEIO file. | |
442 (if oldc | |
443 (aset newc class-children (aref oldc class-children)) | |
444 ;; If the old class did not exist, but did exist in the autoload map, then adopt those children. | |
445 ;; This is like the above, but deals with autoloads nicely. | |
446 (let ((sym (intern-soft (symbol-name cname) eieio-defclass-autoload-map))) | |
447 (when sym | |
448 (condition-case nil | |
449 (aset newc class-children (symbol-value sym)) | |
450 (error nil)) | |
451 (unintern (symbol-name cname) eieio-defclass-autoload-map) | |
452 )) | |
453 ) | |
454 | |
455 (cond ((and (stringp (car options-and-doc)) | |
456 (/= 1 (% (length options-and-doc) 2))) | |
457 (error "Too many arguments to `defclass'")) | |
458 ((and (symbolp (car options-and-doc)) | |
459 (/= 0 (% (length options-and-doc) 2))) | |
460 (error "Too many arguments to `defclass'")) | |
461 ) | |
462 | |
463 (setq options | |
464 (if (stringp (car options-and-doc)) | |
465 (cons :documentation options-and-doc) | |
466 options-and-doc)) | |
467 | |
468 (if pname | |
469 (progn | |
470 (while pname | |
471 (if (and (car pname) (symbolp (car pname))) | |
472 (if (not (class-p (car pname))) | |
473 ;; bad class | |
474 (error "Given parent class %s is not a class" (car pname)) | |
475 ;; good parent class... | |
476 ;; save new child in parent | |
477 (when (not (member cname (aref (class-v (car pname)) class-children))) | |
478 (aset (class-v (car pname)) class-children | |
479 (cons cname (aref (class-v (car pname)) class-children)))) | |
480 ;; Get custom groups, and store them into our local copy. | |
481 (mapc (lambda (g) (add-to-list 'groups g)) | |
482 (class-option (car pname) :custom-groups)) | |
483 ;; save parent in child | |
484 (aset newc class-parent (cons (car pname) (aref newc class-parent)))) | |
485 (error "Invalid parent class %s" pname)) | |
486 (setq pname (cdr pname))) | |
487 ;; Reverse the list of our parents so that they are prioritized in | |
488 ;; the same order as specified in the code. | |
489 (aset newc class-parent (nreverse (aref newc class-parent))) ) | |
490 ;; If there is nothing to loop over, then inherit from the | |
491 ;; default superclass. | |
492 (unless (eq cname 'eieio-default-superclass) | |
493 ;; adopt the default parent here, but clear it later... | |
494 (setq clearparent t) | |
495 ;; save new child in parent | |
496 (if (not (member cname (aref (class-v 'eieio-default-superclass) class-children))) | |
497 (aset (class-v 'eieio-default-superclass) class-children | |
498 (cons cname (aref (class-v 'eieio-default-superclass) class-children)))) | |
499 ;; save parent in child | |
500 (aset newc class-parent (list eieio-default-superclass)))) | |
501 | |
502 ;; turn this into a useable self-pointing symbol | |
503 (set cname cname) | |
504 | |
505 ;; These two tests must be created right away so we can have self- | |
506 ;; referencing classes. ei, a class whose slot can contain only | |
507 ;; pointers to itself. | |
508 | |
509 ;; Create the test function | |
510 (let ((csym (intern (concat (symbol-name cname) "-p")))) | |
511 (fset csym | |
512 (list 'lambda (list 'obj) | |
513 (format "Test OBJ to see if it an object of type %s" cname) | |
514 (list 'and '(eieio-object-p obj) | |
515 (list 'same-class-p 'obj cname))))) | |
516 | |
517 ;; Make sure the method invocation order is a valid value. | |
518 (let ((io (class-option-assoc options :method-invocation-order))) | |
519 (when (and io (not (member io '(:depth-first :breadth-first)))) | |
520 (error "Method invocation order %s is not allowed" io) | |
521 )) | |
522 | |
523 ;; Create a handy child test too | |
524 (let ((csym (intern (concat (symbol-name cname) "-child-p")))) | |
525 (fset csym | |
526 `(lambda (obj) | |
527 ,(format | |
528 "Test OBJ to see if it an object is a child of type %s" | |
529 cname) | |
530 (and (eieio-object-p obj) | |
531 (object-of-class-p obj ,cname)))) | |
532 | |
533 ;; When using typep, (typep OBJ 'myclass) returns t for objects which | |
534 ;; are subclasses of myclass. For our predicates, however, it is | |
535 ;; important for EIEIO to be backwards compatible, where | |
536 ;; myobject-p, and myobject-child-p are different. | |
537 ;; "cl" uses this technique to specify symbols with specific typep | |
538 ;; test, so we can let typep have the CLOS documented behavior | |
539 ;; while keeping our above predicate clean. | |
540 (eval `(deftype ,cname () | |
541 '(satisfies | |
542 ,(intern (concat (symbol-name cname) "-child-p"))))) | |
543 | |
544 ) | |
545 | |
546 ;; before adding new slots, lets add all the methods and classes | |
547 ;; in from the parent class | |
548 (eieio-copy-parents-into-subclass newc superclasses) | |
549 | |
550 ;; Store the new class vector definition into the symbol. We need to | |
551 ;; do this first so that we can call defmethod for the accessor. | |
552 ;; The vector will be updated by the following while loop and will not | |
553 ;; need to be stored a second time. | |
554 (put cname 'eieio-class-definition newc) | |
555 | |
556 ;; Query each slot in the declaration list and mangle into the | |
557 ;; class structure I have defined. | |
558 (while slots | |
559 (let* ((slot1 (car slots)) | |
560 (name (car slot1)) | |
561 (slot (cdr slot1)) | |
562 (acces (plist-get slot ':accessor)) | |
563 (init (or (plist-get slot ':initform) | |
564 (if (member ':initform slot) nil | |
565 eieio-unbound))) | |
566 (initarg (plist-get slot ':initarg)) | |
567 (docstr (plist-get slot ':documentation)) | |
568 (prot (plist-get slot ':protection)) | |
569 (reader (plist-get slot ':reader)) | |
570 (writer (plist-get slot ':writer)) | |
571 (alloc (plist-get slot ':allocation)) | |
572 (type (plist-get slot ':type)) | |
573 (custom (plist-get slot ':custom)) | |
574 (label (plist-get slot ':label)) | |
575 (customg (plist-get slot ':group)) | |
576 (printer (plist-get slot ':printer)) | |
577 | |
578 (skip-nil (class-option-assoc options :allow-nil-initform)) | |
579 ) | |
580 | |
581 (if eieio-error-unsupported-class-tags | |
582 (let ((tmp slot)) | |
583 (while tmp | |
584 (if (not (member (car tmp) '(:accessor | |
585 :initform | |
586 :initarg | |
587 :documentation | |
588 :protection | |
589 :reader | |
590 :writer | |
591 :allocation | |
592 :type | |
593 :custom | |
594 :label | |
595 :group | |
596 :printer | |
597 :allow-nil-initform | |
598 :custom-groups))) | |
599 (signal 'invalid-slot-type (list (car tmp)))) | |
600 (setq tmp (cdr (cdr tmp)))))) | |
601 | |
602 ;; Clean up the meaning of protection. | |
603 (cond ((or (eq prot 'public) (eq prot :public)) (setq prot nil)) | |
604 ((or (eq prot 'protected) (eq prot :protected)) (setq prot 'protected)) | |
605 ((or (eq prot 'private) (eq prot :private)) (setq prot 'private)) | |
606 ((eq prot nil) nil) | |
607 (t (signal 'invalid-slot-type (list ':protection prot)))) | |
608 | |
609 ;; Make sure the :allocation parameter has a valid value. | |
610 (if (not (or (not alloc) (eq alloc :class) (eq alloc :instance))) | |
611 (signal 'invalid-slot-type (list ':allocation alloc))) | |
612 | |
613 ;; The default type specifier is supposed to be t, meaning anything. | |
614 (if (not type) (setq type t)) | |
615 | |
616 ;; Label is nil, or a string | |
617 (if (not (or (null label) (stringp label))) | |
618 (signal 'invalid-slot-type (list ':label label))) | |
619 | |
620 ;; Is there an initarg, but allocation of class? | |
621 (if (and initarg (eq alloc :class)) | |
622 (message "Class allocated slots do not need :initarg")) | |
623 | |
624 ;; intern the symbol so we can use it blankly | |
625 (if initarg (set initarg initarg)) | |
626 | |
627 ;; The customgroup should be a list of symbols | |
628 (cond ((null customg) | |
629 (setq customg '(default))) | |
630 ((not (listp customg)) | |
631 (setq customg (list customg)))) | |
632 ;; The customgroup better be a symbol, or list of symbols. | |
633 (mapc (lambda (cg) | |
634 (if (not (symbolp cg)) | |
635 (signal 'invalid-slot-type (list ':group cg)))) | |
636 customg) | |
637 | |
638 ;; First up, add this slot into our new class. | |
639 (eieio-add-new-slot newc name init docstr type custom label customg printer | |
640 prot initarg alloc 'defaultoverride skip-nil) | |
641 | |
642 ;; We need to id the group, and store them in a group list attribute. | |
643 (mapc (lambda (cg) (add-to-list 'groups cg)) customg) | |
644 | |
645 ;; anyone can have an accessor function. This creates a function | |
646 ;; of the specified name, and also performs a `defsetf' if applicable | |
647 ;; so that users can `setf' the space returned by this function | |
648 (if acces | |
649 (progn | |
650 (eieio-defmethod acces | |
651 (list (if (eq alloc :class) :static :primary) | |
652 (list (list 'this cname)) | |
653 (format | |
654 "Retrieves the slot `%s' from an object of class `%s'" | |
655 name cname) | |
656 (list 'if (list 'slot-boundp 'this (list 'quote name)) | |
657 (list 'eieio-oref 'this (list 'quote name)) | |
658 ;; Else - Some error? nil? | |
659 nil | |
660 ))) | |
661 ;; Thanks Pascal Bourguignon <pjb@informatimago.com> | |
662 ;; For this complex macro. | |
663 (eval (macroexpand | |
664 (list 'defsetf acces '(widget) '(store) | |
665 (list 'list ''eieio-oset 'widget | |
666 (list 'quote (list 'quote name)) 'store)))) | |
667 ;;`(defsetf ,acces (widget) (store) (eieio-oset widget ',cname store)) | |
668 ) | |
669 ) | |
670 ;; If a writer is defined, then create a generic method of that | |
671 ;; name whose purpose is to set the value of the slot. | |
672 (if writer | |
673 (progn | |
674 (eieio-defmethod writer | |
675 (list (list (list 'this cname) 'value) | |
676 (format "Set the slot `%s' of an object of class `%s'" | |
677 name cname) | |
678 `(setf (slot-value this ',name) value))) | |
679 )) | |
680 ;; If a reader is defined, then create a generic method | |
681 ;; of that name whose purpose is to access this slot value. | |
682 (if reader | |
683 (progn | |
684 (eieio-defmethod reader | |
685 (list (list (list 'this cname)) | |
686 (format "Access the slot `%s' from object of class `%s'" | |
687 name cname) | |
688 `(slot-value this ',name))))) | |
689 ) | |
690 (setq slots (cdr slots))) | |
691 | |
692 ;; Now that everything has been loaded up, all our lists are backwards! Fix that up now. | |
693 (aset newc class-public-a (nreverse (aref newc class-public-a))) | |
694 (aset newc class-public-d (nreverse (aref newc class-public-d))) | |
695 (aset newc class-public-doc (nreverse (aref newc class-public-doc))) | |
696 (aset newc class-public-type | |
697 (apply 'vector (nreverse (aref newc class-public-type)))) | |
698 (aset newc class-public-custom (nreverse (aref newc class-public-custom))) | |
699 (aset newc class-public-custom-label (nreverse (aref newc class-public-custom-label))) | |
700 (aset newc class-public-custom-group (nreverse (aref newc class-public-custom-group))) | |
701 (aset newc class-public-printer (nreverse (aref newc class-public-printer))) | |
702 (aset newc class-protection (nreverse (aref newc class-protection))) | |
703 (aset newc class-initarg-tuples (nreverse (aref newc class-initarg-tuples))) | |
704 | |
705 ;; The storage for class-class-allocation-type needs to be turned into | |
706 ;; a vector now. | |
707 (aset newc class-class-allocation-type | |
708 (apply 'vector (aref newc class-class-allocation-type))) | |
709 | |
710 ;; Also, take class allocated values, and vectorize them for speed. | |
711 (aset newc class-class-allocation-values | |
712 (apply 'vector (aref newc class-class-allocation-values))) | |
713 | |
714 ;; Attach slot symbols into an obarray, and store the index of | |
715 ;; this slot as the variable slot in this new symbol. We need to | |
716 ;; know about primes, because obarrays are best set in vectors of | |
717 ;; prime number length, and we also need to make our vector small | |
718 ;; to save space, and also optimal for the number of items we have. | |
719 (let* ((cnt 0) | |
720 (pubsyms (aref newc class-public-a)) | |
721 (prots (aref newc class-protection)) | |
722 (l (length pubsyms)) | |
723 (vl (let ((primes '( 3 5 7 11 13 17 19 23 29 31 37 41 43 47 | |
724 53 59 61 67 71 73 79 83 89 97 101 ))) | |
725 (while (and primes (< (car primes) l)) | |
726 (setq primes (cdr primes))) | |
727 (car primes))) | |
728 (oa (make-vector vl 0)) | |
729 (newsym)) | |
730 (while pubsyms | |
731 (setq newsym (intern (symbol-name (car pubsyms)) oa)) | |
732 (set newsym cnt) | |
733 (setq cnt (1+ cnt)) | |
734 (if (car prots) (put newsym 'protection (car prots))) | |
735 (setq pubsyms (cdr pubsyms) | |
736 prots (cdr prots))) | |
737 (aset newc class-symbol-obarray oa) | |
738 ) | |
739 | |
740 ;; Create the constructor function | |
741 (if (class-option-assoc options :abstract) | |
742 ;; Abstract classes cannot be instantiated. Say so. | |
743 (let ((abs (class-option-assoc options :abstract))) | |
744 (if (not (stringp abs)) | |
745 (setq abs (format "Class %s is abstract" cname))) | |
746 (fset cname | |
747 `(lambda (&rest stuff) | |
748 ,(format "You cannot create a new object of type %s" cname) | |
749 (error ,abs)))) | |
750 | |
751 ;; Non-abstract classes need a constructor. | |
752 (fset cname | |
753 `(lambda (newname &rest slots) | |
754 ,(format "Create a new object with name NAME of class type %s" cname) | |
755 (apply 'constructor ,cname newname slots))) | |
756 ) | |
757 | |
758 ;; Set up a specialized doc string. | |
759 ;; Use stored value since it is calculated in a non-trivial way | |
760 (put cname 'variable-documentation | |
761 (class-option-assoc options :documentation)) | |
762 | |
763 ;; We have a list of custom groups. Store them into the options. | |
764 (let ((g (class-option-assoc options :custom-groups))) | |
765 (mapc (lambda (cg) (add-to-list 'g cg)) groups) | |
766 (if (memq :custom-groups options) | |
767 (setcar (cdr (memq :custom-groups options)) g) | |
768 (setq options (cons :custom-groups (cons g options))))) | |
769 | |
770 ;; Set up the options we have collected. | |
771 (aset newc class-options options) | |
772 | |
773 ;; if this is a superclass, clear out parent (which was set to the | |
774 ;; default superclass eieio-default-superclass) | |
775 (if clearparent (aset newc class-parent nil)) | |
776 | |
777 ;; Create the cached default object. | |
778 (let ((cache (make-vector (+ (length (aref newc class-public-a)) | |
779 3) nil))) | |
780 (aset cache 0 'object) | |
781 (aset cache object-class cname) | |
782 (aset cache object-name 'default-cache-object) | |
783 (let ((eieio-skip-typecheck t)) | |
784 ;; All type-checking has been done to our satisfaction | |
785 ;; before this call. Don't waste our time in this call.. | |
786 (eieio-set-defaults cache t)) | |
787 (aset newc class-default-object-cache cache)) | |
788 | |
789 ;; Return our new class object | |
790 ;; newc | |
791 cname | |
792 )) | |
793 | |
794 (defun eieio-perform-slot-validation-for-default (slot spec value skipnil) | |
795 "For SLOT, signal if SPEC does not match VALUE. | |
796 If SKIPNIL is non-nil, then if VALUE is nil, return t." | |
797 (let ((val (eieio-default-eval-maybe value))) | |
798 (if (and (not eieio-skip-typecheck) | |
799 (not (and skipnil (null val))) | |
800 (not (eieio-perform-slot-validation spec val))) | |
801 (signal 'invalid-slot-type (list slot spec val))))) | |
802 | |
803 (defun eieio-add-new-slot (newc a d doc type cust label custg print prot init alloc | |
804 &optional defaultoverride skipnil) | |
805 "Add into NEWC attribute A. | |
806 If A already exists in NEWC, then do nothing. If it doesn't exist, | |
807 then also add in D (defualt), DOC, TYPE, CUST, LABEL, CUSTG, PRINT, PROT, and INIT arg. | |
808 Argument ALLOC specifies if the slot is allocated per instance, or per class. | |
809 If optional DEFAULTOVERRIDE is non-nil, then if A exists in NEWC, | |
810 we must override it's value for a default. | |
811 Optional argument SKIPNIL indicates if type checking should be skipped | |
812 if default value is nil." | |
813 ;; Make sure we duplicate those items that are sequences. | |
814 (condition-case nil | |
815 (if (sequencep d) (setq d (copy-sequence d))) | |
816 ;; This copy can fail on a cons cell with a non-cons in the cdr. Lets skip it if it doesn't work. | |
817 (error nil)) | |
818 (if (sequencep type) (setq type (copy-sequence type))) | |
819 (if (sequencep cust) (setq cust (copy-sequence cust))) | |
820 (if (sequencep custg) (setq custg (copy-sequence custg))) | |
821 | |
822 ;; To prevent override information w/out specification of storage, | |
823 ;; we need to do this little hack. | |
824 (if (member a (aref newc class-class-allocation-a)) (setq alloc ':class)) | |
825 | |
826 (if (or (not alloc) (and (symbolp alloc) (eq alloc ':instance))) | |
827 ;; In this case, we modify the INSTANCE version of a given slot. | |
828 | |
829 (progn | |
830 | |
831 ;; Only add this element if it is so-far unique | |
832 (if (not (member a (aref newc class-public-a))) | |
833 (progn | |
834 (eieio-perform-slot-validation-for-default a type d skipnil) | |
835 (aset newc class-public-a (cons a (aref newc class-public-a))) | |
836 (aset newc class-public-d (cons d (aref newc class-public-d))) | |
837 (aset newc class-public-doc (cons doc (aref newc class-public-doc))) | |
838 (aset newc class-public-type (cons type (aref newc class-public-type))) | |
839 (aset newc class-public-custom (cons cust (aref newc class-public-custom))) | |
840 (aset newc class-public-custom-label (cons label (aref newc class-public-custom-label))) | |
841 (aset newc class-public-custom-group (cons custg (aref newc class-public-custom-group))) | |
842 (aset newc class-public-printer (cons print (aref newc class-public-printer))) | |
843 (aset newc class-protection (cons prot (aref newc class-protection))) | |
844 (aset newc class-initarg-tuples (cons (cons init a) (aref newc class-initarg-tuples))) | |
845 ) | |
846 ;; When defaultoverride is true, we are usually adding new local | |
847 ;; attributes which must override the default value of any slot | |
848 ;; passed in by one of the parent classes. | |
849 (when defaultoverride | |
850 ;; There is a match, and we must override the old value. | |
851 (let* ((ca (aref newc class-public-a)) | |
852 (np (member a ca)) | |
853 (num (- (length ca) (length np))) | |
854 (dp (if np (nthcdr num (aref newc class-public-d)) | |
855 nil)) | |
856 (tp (if np (nth num (aref newc class-public-type)))) | |
857 ) | |
858 (if (not np) | |
859 (error "Eieio internal error overriding default value for %s" | |
860 a) | |
861 ;; If type is passed in, is it the same? | |
862 (if (not (eq type t)) | |
863 (if (not (equal type tp)) | |
864 (error | |
865 "Child slot type `%s' does not match inherited type `%s' for `%s'" | |
866 type tp a))) | |
867 ;; If we have a repeat, only update the initarg... | |
868 (unless (eq d eieio-unbound) | |
869 (eieio-perform-slot-validation-for-default a tp d skipnil) | |
870 (setcar dp d)) | |
871 ;; If we have a new initarg, check for it. | |
872 (when init | |
873 (let* ((inits (aref newc class-initarg-tuples)) | |
874 (inita (rassq a inits))) | |
875 ;; Replace the CAR of the associate INITA. | |
876 ;;(message "Initarg: %S replace %s" inita init) | |
877 (setcar inita init) | |
878 )) | |
879 | |
880 ;; PLN Tue Jun 26 11:57:06 2007 : The protection is | |
881 ;; checked and SHOULD match the superclass | |
882 ;; protection. Otherwise an error is thrown. However | |
883 ;; I wonder if a more flexible schedule might be | |
884 ;; implemented. | |
885 ;; | |
886 ;; EML - We used to have (if prot... here, | |
887 ;; but a prot of 'nil means public. | |
888 ;; | |
889 (let ((super-prot (nth num (aref newc class-protection))) | |
890 ) | |
891 (if (not (eq prot super-prot)) | |
892 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'" | |
893 prot super-prot a))) | |
894 ;; End original PLN | |
895 | |
896 ;; PLN Tue Jun 26 11:57:06 2007 : | |
897 ;; We do a non redundant combination of ancient | |
898 ;; custom groups and new ones using the common lisp | |
899 ;; `union' method. | |
900 (when custg | |
901 (let ((where-groups | |
902 (nthcdr num (aref newc class-public-custom-group)))) | |
903 (setcar where-groups | |
904 (union (car where-groups) | |
905 (if (listp custg) custg (list custg)))))) | |
906 ;; End PLN | |
907 | |
908 ;; PLN Mon Jun 25 22:44:34 2007 : If a new cust is | |
909 ;; set, simply replaces the old one. | |
910 (when cust | |
911 ;; (message "Custom type redefined to %s" cust) | |
912 (setcar (nthcdr num (aref newc class-public-custom)) cust)) | |
913 | |
914 ;; If a new label is specified, it simply replaces | |
915 ;; the old one. | |
916 (when label | |
917 ;; (message "Custom label redefined to %s" label) | |
918 (setcar (nthcdr num (aref newc class-public-custom-label)) label)) | |
919 ;; End PLN | |
920 | |
921 ;; PLN Sat Jun 30 17:24:42 2007 : when a new | |
922 ;; doc is specified, simply replaces the old one. | |
923 (when doc | |
924 ;;(message "Documentation redefined to %s" doc) | |
925 (setcar (nthcdr num (aref newc class-public-doc)) | |
926 doc)) | |
927 ;; End PLN | |
928 | |
929 ;; If a new printer is specified, it simply replaces | |
930 ;; the old one. | |
931 (when print | |
932 ;; (message "printer redefined to %s" print) | |
933 (setcar (nthcdr num (aref newc class-public-printer)) print)) | |
934 | |
935 ))) | |
936 )) | |
937 | |
938 ;; CLASS ALLOCATED SLOTS | |
939 (let ((value (eieio-default-eval-maybe d))) | |
940 (if (not (member a (aref newc class-class-allocation-a))) | |
941 (progn | |
942 (eieio-perform-slot-validation-for-default a type value skipnil) | |
943 ;; Here we have found a :class version of a slot. This | |
944 ;; requires a very different aproach. | |
945 (aset newc class-class-allocation-a (cons a (aref newc class-class-allocation-a))) | |
946 (aset newc class-class-allocation-doc (cons doc (aref newc class-class-allocation-doc))) | |
947 (aset newc class-class-allocation-type (cons type (aref newc class-class-allocation-type))) | |
948 (aset newc class-class-allocation-custom (cons cust (aref newc class-class-allocation-custom))) | |
949 (aset newc class-class-allocation-custom-label (cons label (aref newc class-class-allocation-custom-label))) | |
950 (aset newc class-class-allocation-custom-group (cons custg (aref newc class-class-allocation-custom-group))) | |
951 (aset newc class-class-allocation-protection (cons prot (aref newc class-class-allocation-protection))) | |
952 ;; Default value is stored in the 'values section, since new objects | |
953 ;; can't initialize from this element. | |
954 (aset newc class-class-allocation-values (cons value (aref newc class-class-allocation-values)))) | |
955 (when defaultoverride | |
956 ;; There is a match, and we must override the old value. | |
957 (let* ((ca (aref newc class-class-allocation-a)) | |
958 (np (member a ca)) | |
959 (num (- (length ca) (length np))) | |
960 (dp (if np | |
961 (nthcdr num | |
962 (aref newc class-class-allocation-values)) | |
963 nil)) | |
964 (tp (if np (nth num (aref newc class-class-allocation-type)) | |
965 nil))) | |
966 (if (not np) | |
967 (error "Eieio internal error overriding default value for %s" | |
968 a) | |
969 ;; If type is passed in, is it the same? | |
970 (if (not (eq type t)) | |
971 (if (not (equal type tp)) | |
972 (error | |
973 "Child slot type `%s' does not match inherited type `%s' for `%s'" | |
974 type tp a))) | |
975 ;; EML - Note: the only reason to override a class bound slot | |
976 ;; is to change the default, so allow unbound in. | |
977 | |
978 ;; If we have a repeat, only update the vlaue... | |
979 (eieio-perform-slot-validation-for-default a tp value skipnil) | |
980 (setcar dp value)) | |
981 | |
982 ;; PLN Tue Jun 26 11:57:06 2007 : The protection is | |
983 ;; checked and SHOULD match the superclass | |
984 ;; protection. Otherwise an error is thrown. However | |
985 ;; I wonder if a more flexible schedule might be | |
986 ;; implemented. | |
987 (let ((super-prot | |
988 (car (nthcdr num (aref newc class-class-allocation-protection))))) | |
989 (if (not (eq prot super-prot)) | |
990 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'" | |
991 prot super-prot a))) | |
992 ;; We do a non redundant combination of ancient | |
993 ;; custom groups and new ones using the common lisp | |
994 ;; `union' method. | |
995 (when custg | |
996 (let ((where-groups | |
997 (nthcdr num (aref newc class-class-allocation-custom-group)))) | |
998 (setcar where-groups | |
999 (union (car where-groups) | |
1000 (if (listp custg) custg (list custg)))))) | |
1001 ;; End PLN | |
1002 | |
1003 ;; PLN Sat Jun 30 17:24:42 2007 : when a new | |
1004 ;; doc is specified, simply replaces the old one. | |
1005 (when doc | |
1006 ;;(message "Documentation redefined to %s" doc) | |
1007 (setcar (nthcdr num (aref newc class-class-allocation-doc)) | |
1008 doc)) | |
1009 ;; End PLN | |
1010 | |
1011 ;; If a new printer is specified, it simply replaces | |
1012 ;; the old one. | |
1013 (when print | |
1014 ;; (message "printer redefined to %s" print) | |
1015 (setcar (nthcdr num (aref newc class-class-allocation-printer)) print)) | |
1016 | |
1017 )) | |
1018 )) | |
1019 )) | |
1020 | |
1021 (defun eieio-copy-parents-into-subclass (newc parents) | |
1022 "Copy into NEWC the slots of PARENTS. | |
1023 Follow the rules of not overwritting early parents when applying to | |
1024 the new child class." | |
1025 (let ((ps (aref newc class-parent)) | |
1026 (sn (class-option-assoc (aref newc class-options) | |
1027 ':allow-nil-initform))) | |
1028 (while ps | |
1029 ;; First, duplicate all the slots of the parent. | |
1030 (let ((pcv (class-v (car ps)))) | |
1031 (let ((pa (aref pcv class-public-a)) | |
1032 (pd (aref pcv class-public-d)) | |
1033 (pdoc (aref pcv class-public-doc)) | |
1034 (ptype (aref pcv class-public-type)) | |
1035 (pcust (aref pcv class-public-custom)) | |
1036 (plabel (aref pcv class-public-custom-label)) | |
1037 (pcustg (aref pcv class-public-custom-group)) | |
1038 (printer (aref pcv class-public-printer)) | |
1039 (pprot (aref pcv class-protection)) | |
1040 (pinit (aref pcv class-initarg-tuples)) | |
1041 (i 0)) | |
1042 (while pa | |
1043 (eieio-add-new-slot newc | |
1044 (car pa) (car pd) (car pdoc) (aref ptype i) | |
1045 (car pcust) (car plabel) (car pcustg) | |
1046 (car printer) | |
1047 (car pprot) (car-safe (car pinit)) nil nil sn) | |
1048 ;; Increment each value. | |
1049 (setq pa (cdr pa) | |
1050 pd (cdr pd) | |
1051 pdoc (cdr pdoc) | |
1052 i (1+ i) | |
1053 pcust (cdr pcust) | |
1054 plabel (cdr plabel) | |
1055 pcustg (cdr pcustg) | |
1056 printer (cdr printer) | |
1057 pprot (cdr pprot) | |
1058 pinit (cdr pinit)) | |
1059 )) ;; while/let | |
1060 ;; Now duplicate all the class alloc slots. | |
1061 (let ((pa (aref pcv class-class-allocation-a)) | |
1062 (pdoc (aref pcv class-class-allocation-doc)) | |
1063 (ptype (aref pcv class-class-allocation-type)) | |
1064 (pcust (aref pcv class-class-allocation-custom)) | |
1065 (plabel (aref pcv class-class-allocation-custom-label)) | |
1066 (pcustg (aref pcv class-class-allocation-custom-group)) | |
1067 (printer (aref pcv class-class-allocation-printer)) | |
1068 (pprot (aref pcv class-class-allocation-protection)) | |
1069 (pval (aref pcv class-class-allocation-values)) | |
1070 (i 0)) | |
1071 (while pa | |
1072 (eieio-add-new-slot newc | |
1073 (car pa) (aref pval i) (car pdoc) (aref ptype i) | |
1074 (car pcust) (car plabel) (car pcustg) | |
1075 (car printer) | |
1076 (car pprot) nil ':class sn) | |
1077 ;; Increment each value. | |
1078 (setq pa (cdr pa) | |
1079 pdoc (cdr pdoc) | |
1080 pcust (cdr pcust) | |
1081 plabel (cdr plabel) | |
1082 pcustg (cdr pcustg) | |
1083 printer (cdr printer) | |
1084 pprot (cdr pprot) | |
1085 i (1+ i)) | |
1086 ))) ;; while/let | |
1087 ;; Loop over each parent class | |
1088 (setq ps (cdr ps))) | |
1089 )) | |
1090 | |
1091 ;;; CLOS style implementation of object creators. | |
1092 ;; | |
1093 (defun make-instance (class &rest initargs) | |
1094 "Make a new instance of CLASS based on INITARGS. | |
1095 CLASS is a class symbol. For example: | |
1096 | |
1097 (make-instance 'foo) | |
1098 | |
1099 INITARGS is a property list with keywords based on the :initarg | |
1100 for each slot. For example: | |
1101 | |
1102 (make-instance 'foo :slot1 value1 :slotN valueN) | |
1103 | |
1104 Compatability note: | |
1105 | |
1106 If the first element of INITARGS is a string, it is used as the | |
1107 name of the class. | |
1108 | |
1109 In EIEIO, the class' constructor requires a name for use when printing. | |
1110 `make-instance' in CLOS doesn't use names the way Emacs does, so the | |
1111 class is used as the name slot instead when INITARGS doesn't start with | |
1112 a string." | |
1113 (if (and (car initargs) (stringp (car initargs))) | |
1114 (apply (class-constructor class) initargs) | |
1115 (apply (class-constructor class) | |
1116 (cond ((symbolp class) (symbol-name class)) | |
1117 (t (format "%S" class))) | |
1118 initargs))) | |
1119 | |
1120 | |
1121 ;;; CLOS methods and generics | |
1122 ;; | |
1123 (defmacro defgeneric (method args &optional doc-string) | |
1124 "Create a generic function METHOD. ARGS is ignored. | |
1125 DOC-STRING is the base documentation for this class. A generic | |
1126 function has no body, as it's purpose is to decide which method body | |
1127 is appropriate to use. Use `defmethod' to create methods, and it | |
1128 calls defgeneric for you. With this implementation the arguments are | |
1129 currently ignored. You can use `defgeneric' to apply specialized | |
1130 top level documentation to a method." | |
1131 `(eieio-defgeneric (quote ,method) ,doc-string)) | |
1132 | |
1133 (defun eieio-defgeneric-form (method doc-string) | |
1134 "The lambda form that would be used as the function defined on METHOD. | |
1135 All methods should call the same EIEIO function for dispatch. | |
1136 DOC-STRING is the documentation attached to METHOD." | |
1137 `(lambda (&rest local-args) | |
1138 ,doc-string | |
1139 (eieio-generic-call (quote ,method) local-args))) | |
1140 | |
1141 (defsubst eieio-defgeneric-reset-generic-form (method) | |
1142 "Setup METHOD to call the generic form." | |
1143 (let ((doc-string (documentation method))) | |
1144 (fset method (eieio-defgeneric-form method doc-string)))) | |
1145 | |
1146 (defun eieio-defgeneric-form-primary-only (method doc-string) | |
1147 "The lambda form that would be used as the function defined on METHOD. | |
1148 All methods should call the same EIEIO function for dispatch. | |
1149 DOC-STRING is the documentation attached to METHOD." | |
1150 `(lambda (&rest local-args) | |
1151 ,doc-string | |
1152 (eieio-generic-call-primary-only (quote ,method) local-args))) | |
1153 | |
1154 (defsubst eieio-defgeneric-reset-generic-form-primary-only (method) | |
1155 "Setup METHOD to call the generic form." | |
1156 (let ((doc-string (documentation method))) | |
1157 (fset method (eieio-defgeneric-form-primary-only method doc-string)))) | |
1158 | |
1159 (defun eieio-defgeneric-form-primary-only-one (method doc-string | |
1160 class | |
1161 impl | |
1162 ) | |
1163 "The lambda form that would be used as the function defined on METHOD. | |
1164 All methods should call the same EIEIO function for dispatch. | |
1165 DOC-STRING is the documentation attached to METHOD. | |
1166 CLASS is the class symbol needed for private method access. | |
1167 IMPL is the symbol holding the method implementation." | |
1168 ;; NOTE: I tried out byte compiling this little fcn. Turns out it | |
1169 ;; is faster to execute this for not byte-compiled. ie, install this, | |
1170 ;; then measure calls going through here. I wonder why. | |
1171 (require 'bytecomp) | |
1172 (let ((byte-compile-free-references nil) | |
1173 (byte-compile-warnings nil) | |
1174 ) | |
1175 (byte-compile-lambda | |
1176 `(lambda (&rest local-args) | |
1177 ,doc-string | |
1178 ;; This is a cool cheat. Usually we need to look up in the | |
1179 ;; method table to find out if there is a method or not. We can | |
1180 ;; instead make that determination at load time when there is | |
1181 ;; only one method. If the first arg is not a child of the class | |
1182 ;; of that one implementation, then clearly, there is no method def. | |
1183 (if (not (eieio-object-p (car local-args))) | |
1184 ;; Not an object. Just signal. | |
1185 (signal 'no-method-definition (list ,(list 'quote method) local-args)) | |
1186 | |
1187 ;; We do have an object. Make sure it is the right type. | |
1188 (if ,(if (eq class eieio-default-superclass) | |
1189 nil ; default superclass means just an obj. Already asked. | |
1190 `(not (child-of-class-p (aref (car local-args) object-class) | |
1191 ,(list 'quote class))) | |
1192 ) | |
1193 | |
1194 ;; If not the right kind of object, call no applicable | |
1195 (apply 'no-applicable-method (car local-args) | |
1196 ,(list 'quote method) local-args) | |
1197 | |
1198 ;; It is ok, do the call. | |
1199 ;; Fill in inter-call variables then evaluate the method. | |
1200 (let ((scoped-class ,(list 'quote class)) | |
1201 (eieio-generic-call-next-method-list nil) | |
1202 (eieio-generic-call-key method-primary) | |
1203 (eieio-generic-call-methodname ,(list 'quote method)) | |
1204 (eieio-generic-call-arglst local-args) | |
1205 ) | |
1206 (apply ,(list 'quote impl) local-args) | |
1207 ;(,impl local-args) | |
1208 )))) | |
1209 ) | |
1210 )) | |
1211 | |
1212 (defsubst eieio-defgeneric-reset-generic-form-primary-only-one (method) | |
1213 "Setup METHOD to call the generic form." | |
1214 (let* ((doc-string (documentation method)) | |
1215 (M (get method 'eieio-method-tree)) | |
1216 (entry (car (aref M method-primary))) | |
1217 ) | |
1218 (fset method (eieio-defgeneric-form-primary-only-one | |
1219 method doc-string | |
1220 (car entry) | |
1221 (cdr entry) | |
1222 )))) | |
1223 | |
1224 (defun eieio-defgeneric (method doc-string) | |
1225 "Engine part to `defgeneric' macro defining METHOD with DOC-STRING." | |
1226 (if (and (fboundp method) (not (generic-p method)) | |
1227 (or (byte-code-function-p (symbol-function method)) | |
1228 (not (eq 'autoload (car (symbol-function method))))) | |
1229 ) | |
1230 (error "You cannot create a generic/method over an existing symbol: %s" | |
1231 method)) | |
1232 ;; Don't do this over and over. | |
1233 (unless (fboundp 'method) | |
1234 ;; This defun tells emacs where the first definition of this | |
1235 ;; method is defined. | |
1236 `(defun ,method nil) | |
1237 ;; Make sure the method tables are installed. | |
1238 (eieiomt-install method) | |
1239 ;; Apply the actual body of this function. | |
1240 (fset method (eieio-defgeneric-form method doc-string)) | |
1241 ;; Return the method | |
1242 'method)) | |
1243 | |
1244 (defun eieio-unbind-method-implementations (method) | |
1245 "Make the generic method METHOD have no implementations.. | |
1246 It will leave the original generic function in place, but remove | |
1247 reference to all implementations of METHOD." | |
1248 (put method 'eieio-method-tree nil) | |
1249 (put method 'eieio-method-obarray nil)) | |
1250 | |
1251 (defmacro defmethod (method &rest args) | |
1252 "Create a new METHOD through `defgeneric' with ARGS. | |
1253 | |
1254 The second optional argument KEY is a specifier that | |
1255 modifies how the method is called, including: | |
1256 :before - Method will be called before the :primary | |
1257 :primary - The default if not specified. | |
1258 :after - Method will be called after the :primary | |
1259 :static - First arg could be an object or class | |
1260 The next argument is the ARGLIST. The ARGLIST specifies the arguments | |
1261 to the method as with `defun'. The first argument can have a type | |
1262 specifier, such as: | |
1263 ((VARNAME CLASS) ARG2 ...) | |
1264 where VARNAME is the name of the local variable for the method being | |
1265 created. The CLASS is a class symbol for a class made with `defclass'. | |
1266 A DOCSTRING comes after the ARGLIST, and is optional. | |
1267 All the rest of the args are the BODY of the method. A method will | |
1268 return the value of the last form in the BODY. | |
1269 | |
1270 Summary: | |
1271 | |
1272 (defmethod mymethod [:before | :primary | :after | :static] | |
1273 ((typearg class-name) arg2 &optional opt &rest rest) | |
1274 \"doc-string\" | |
1275 body)" | |
1276 `(eieio-defmethod (quote ,method) (quote ,args))) | |
1277 | |
1278 (defun eieio-defmethod (method args) | |
1279 "Work part of the `defmethod' macro defining METHOD with ARGS." | |
1280 (let ((key nil) (body nil) (firstarg nil) (argfix nil) (argclass nil) loopa) | |
1281 ;; find optional keys | |
1282 (setq key | |
1283 (cond ((or (eq ':BEFORE (car args)) | |
1284 (eq ':before (car args))) | |
1285 (setq args (cdr args)) | |
1286 method-before) | |
1287 ((or (eq ':AFTER (car args)) | |
1288 (eq ':after (car args))) | |
1289 (setq args (cdr args)) | |
1290 method-after) | |
1291 ((or (eq ':PRIMARY (car args)) | |
1292 (eq ':primary (car args))) | |
1293 (setq args (cdr args)) | |
1294 method-primary) | |
1295 ((or (eq ':STATIC (car args)) | |
1296 (eq ':static (car args))) | |
1297 (setq args (cdr args)) | |
1298 method-static) | |
1299 ;; Primary key | |
1300 (t method-primary))) | |
1301 ;; get body, and fix contents of args to be the arguments of the fn. | |
1302 (setq body (cdr args) | |
1303 args (car args)) | |
1304 (setq loopa args) | |
1305 ;; Create a fixed version of the arguments | |
1306 (while loopa | |
1307 (setq argfix (cons (if (listp (car loopa)) (car (car loopa)) (car loopa)) | |
1308 argfix)) | |
1309 (setq loopa (cdr loopa))) | |
1310 ;; make sure there is a generic | |
1311 (eieio-defgeneric | |
1312 method | |
1313 (if (stringp (car body)) | |
1314 (car body) (format "Generically created method `%s'" method))) | |
1315 ;; create symbol for property to bind to. If the first arg is of | |
1316 ;; the form (varname vartype) and `vartype' is a class, then | |
1317 ;; that class will be the type symbol. If not, then it will fall | |
1318 ;; under the type `primary' which is a non-specific calling of the | |
1319 ;; function. | |
1320 (setq firstarg (car args)) | |
1321 (if (listp firstarg) | |
1322 (progn | |
1323 (setq argclass (nth 1 firstarg)) | |
1324 (if (not (class-p argclass)) | |
1325 (error "Unknown class type %s in method parameters" | |
1326 (nth 1 firstarg)))) | |
1327 (if (= key -1) | |
1328 (signal 'wrong-type-argument (list :static 'non-class-arg))) | |
1329 ;; generics are higher | |
1330 (setq key (+ key 3))) | |
1331 ;; Put this lambda into the symbol so we can find it | |
1332 (if (byte-code-function-p (car-safe body)) | |
1333 (eieiomt-add method (car-safe body) key argclass) | |
1334 (eieiomt-add method (append (list 'lambda (reverse argfix)) body) | |
1335 key argclass)) | |
1336 ) | |
1337 | |
1338 (when eieio-optimize-primary-methods-flag | |
1339 ;; Optimizing step: | |
1340 ;; | |
1341 ;; If this method, after this setup, only has primary methods, then | |
1342 ;; we can setup the generic that way. | |
1343 (if (generic-primary-only-p method) | |
1344 ;; If there is only one primary method, then we can go one more | |
1345 ;; optimization step. | |
1346 (if (generic-primary-only-one-p method) | |
1347 (eieio-defgeneric-reset-generic-form-primary-only-one method) | |
1348 (eieio-defgeneric-reset-generic-form-primary-only method)) | |
1349 (eieio-defgeneric-reset-generic-form method))) | |
1350 | |
1351 method) | |
1352 | |
1353 ;;; Slot type validation | |
1354 ;; | |
1355 (defun eieio-perform-slot-validation (spec value) | |
1356 "Return non-nil if SPEC does not match VALUE." | |
1357 ;; typep is in cl-macs | |
1358 (or (eq spec t) ; t always passes | |
1359 (eq value eieio-unbound) ; unbound always passes | |
1360 (typep value spec))) | |
1361 | |
1362 (defun eieio-validate-slot-value (class slot-idx value slot) | |
1363 "Make sure that for CLASS referencing SLOT-IDX, that VALUE is valid. | |
1364 Checks the :type specifier. | |
1365 SLOT is the slot that is being checked, and is only used when throwing | |
1366 and error." | |
1367 (if eieio-skip-typecheck | |
1368 nil | |
1369 ;; Trim off object IDX junk added in for the object index. | |
1370 (setq slot-idx (- slot-idx 3)) | |
1371 (let ((st (aref (aref (class-v class) class-public-type) slot-idx))) | |
1372 (if (not (eieio-perform-slot-validation st value)) | |
1373 (signal 'invalid-slot-type (list class slot st value)))))) | |
1374 | |
1375 (defun eieio-validate-class-slot-value (class slot-idx value slot) | |
1376 "Make sure that for CLASS referencing SLOT-IDX, that VALUE is valid. | |
1377 Checks the :type specifier. | |
1378 SLOT is the slot that is being checked, and is only used when throwing | |
1379 and error." | |
1380 (if eieio-skip-typecheck | |
1381 nil | |
1382 (let ((st (aref (aref (class-v class) class-class-allocation-type) | |
1383 slot-idx))) | |
1384 (if (not (eieio-perform-slot-validation st value)) | |
1385 (signal 'invalid-slot-type (list class slot st value)))))) | |
1386 | |
1387 (defun eieio-barf-if-slot-unbound (value instance slotname fn) | |
1388 "Throw a signal if VALUE is a representation of an UNBOUND slot. | |
1389 INSTANCE is the object being referenced. SLOTNAME is the offending | |
1390 slot. If the slot is ok, return VALUE. | |
1391 Argument FN is the function calling this verifier." | |
1392 (if (and (eq value eieio-unbound) (not eieio-skip-typecheck)) | |
1393 (slot-unbound instance (object-class instance) slotname fn) | |
1394 value)) | |
1395 | |
1396 ;;; Missing types that are useful to me. | |
1397 ;; | |
1398 (defun boolean-p (bool) | |
1399 "Return non-nil if BOOL is nil or t." | |
1400 (or (null bool) (eq bool t))) | |
1401 | |
1402 ;;; Get/Set slots in an object. | |
1403 ;; | |
1404 (defmacro oref (obj slot) | |
1405 "Retrieve the value stored in OBJ in the slot named by SLOT. | |
1406 Slot is the name of the slot when created by `defclass' or the label | |
1407 created by the :initarg tag." | |
1408 `(eieio-oref ,obj (quote ,slot))) | |
1409 | |
1410 (defun eieio-oref (obj slot) | |
1411 "Return the value in OBJ at SLOT in the object vector." | |
1412 (if (not (or (eieio-object-p obj) (class-p obj))) | |
1413 (signal 'wrong-type-argument (list '(or eieio-object-p class-p) obj))) | |
1414 (if (not (symbolp slot)) | |
1415 (signal 'wrong-type-argument (list 'symbolp slot))) | |
1416 (if (class-p obj) (eieio-class-un-autoload obj)) | |
1417 (let* ((class (if (class-p obj) obj (aref obj object-class))) | |
1418 (c (eieio-slot-name-index class obj slot))) | |
1419 (if (not c) | |
1420 ;; It might be missing because it is a :class allocated slot. | |
1421 ;; Lets check that info out. | |
1422 (if (setq c (eieio-class-slot-name-index class slot)) | |
1423 ;; Oref that slot. | |
1424 (aref (aref (class-v class) class-class-allocation-values) c) | |
1425 ;; The slot-missing method is a cool way of allowing an object author | |
1426 ;; to intercept missing slot definitions. Since it is also the LAST | |
1427 ;; thing called in this fn, it's return value would be retrieved. | |
1428 (slot-missing obj slot 'oref) | |
1429 ;;(signal 'invalid-slot-name (list (object-name obj) slot)) | |
1430 ) | |
1431 (if (not (eieio-object-p obj)) | |
1432 (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1433 (eieio-barf-if-slot-unbound (aref obj c) obj slot 'oref)))) | |
1434 | |
1435 (defalias 'slot-value 'eieio-oref) | |
1436 (defalias 'set-slot-value 'eieio-oset) | |
1437 | |
1438 (defmacro oref-default (obj slot) | |
1439 "Gets the default value of OBJ (maybe a class) for SLOT. | |
1440 The default value is the value installed in a class with the :initform | |
1441 tag. SLOT can be the slot name, or the tag specified by the :initarg | |
1442 tag in the `defclass' call." | |
1443 `(eieio-oref-default ,obj (quote ,slot))) | |
1444 | |
1445 (defun eieio-oref-default (obj slot) | |
1446 "Does the work for the macro `oref-default' with similar parameters. | |
1447 Fills in OBJ's SLOT with it's default value." | |
1448 (if (not (or (eieio-object-p obj) (class-p obj))) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1449 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot))) | |
1450 (let* ((cl (if (eieio-object-p obj) (aref obj object-class) obj)) | |
1451 (c (eieio-slot-name-index cl obj slot))) | |
1452 (if (not c) | |
1453 ;; It might be missing because it is a :class allocated slot. | |
1454 ;; Lets check that info out. | |
1455 (if (setq c | |
1456 (eieio-class-slot-name-index cl slot)) | |
1457 ;; Oref that slot. | |
1458 (aref (aref (class-v cl) class-class-allocation-values) | |
1459 c) | |
1460 (slot-missing obj slot 'oref-default) | |
1461 ;;(signal 'invalid-slot-name (list (class-name cl) slot)) | |
1462 ) | |
1463 (eieio-barf-if-slot-unbound | |
1464 (let ((val (nth (- c 3) (aref (class-v cl) class-public-d)))) | |
1465 (eieio-default-eval-maybe val)) | |
1466 obj cl 'oref-default)))) | |
1467 | |
1468 (defun eieio-default-eval-maybe (val) | |
1469 "Check VAL, and return what `oref-default' would provide." | |
1470 ;; check for quoted things, and unquote them | |
1471 (if (and (listp val) (eq (car val) 'quote)) | |
1472 (car (cdr val)) | |
1473 ;; return it verbatim | |
1474 val)) | |
1475 | |
1476 ;;; Object Set macros | |
1477 ;; | |
1478 (defmacro oset (obj slot value) | |
1479 "Set the value in OBJ for slot SLOT to VALUE. | |
1480 SLOT is the slot name as specified in `defclass' or the tag created | |
1481 with in the :initarg slot. VALUE can be any Lisp object." | |
1482 `(eieio-oset ,obj (quote ,slot) ,value)) | |
1483 | |
1484 (defun eieio-oset (obj slot value) | |
1485 "Does the work for the macro `oset'. | |
1486 Fills in OBJ's SLOT with VALUE." | |
1487 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1488 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot))) | |
1489 (let ((c (eieio-slot-name-index (object-class-fast obj) obj slot))) | |
1490 (if (not c) | |
1491 ;; It might be missing because it is a :class allocated slot. | |
1492 ;; Lets check that info out. | |
1493 (if (setq c | |
1494 (eieio-class-slot-name-index (aref obj object-class) slot)) | |
1495 ;; Oset that slot. | |
1496 (progn | |
1497 (eieio-validate-class-slot-value (object-class-fast obj) c value slot) | |
1498 (aset (aref (class-v (aref obj object-class)) | |
1499 class-class-allocation-values) | |
1500 c value)) | |
1501 ;; See oref for comment on `slot-missing' | |
1502 (slot-missing obj slot 'oset value) | |
1503 ;;(signal 'invalid-slot-name (list (object-name obj) slot)) | |
1504 ) | |
1505 (eieio-validate-slot-value (object-class-fast obj) c value slot) | |
1506 (aset obj c value)))) | |
1507 | |
1508 (defmacro oset-default (class slot value) | |
1509 "Set the default slot in CLASS for SLOT to VALUE. | |
1510 The default value is usually set with the :initform tag during class | |
1511 creation. This allows users to change the default behavior of classes | |
1512 after they are created." | |
1513 `(eieio-oset-default ,class (quote ,slot) ,value)) | |
1514 | |
1515 (defun eieio-oset-default (class slot value) | |
1516 "Does the work for the macro `oset-default'. | |
1517 Fills in the default value in CLASS' in SLOT with VALUE." | |
1518 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1519 (if (not (symbolp slot)) (signal 'wrong-type-argument (list 'symbolp slot))) | |
1520 (let* ((scoped-class class) | |
1521 (c (eieio-slot-name-index class nil slot))) | |
1522 (if (not c) | |
1523 ;; It might be missing because it is a :class allocated slot. | |
1524 ;; Lets check that info out. | |
1525 (if (setq c (eieio-class-slot-name-index class slot)) | |
1526 (progn | |
1527 ;; Oref that slot. | |
1528 (eieio-validate-class-slot-value class c value slot) | |
1529 (aset (aref (class-v class) class-class-allocation-values) c | |
1530 value)) | |
1531 (signal 'invalid-slot-name (list (class-name class) slot))) | |
1532 (eieio-validate-slot-value class c value slot) | |
1533 ;; Set this into the storage for defaults. | |
1534 (setcar (nthcdr (- c 3) (aref (class-v class) class-public-d)) | |
1535 value) | |
1536 ;; Take the value, and put it into our cache object. | |
1537 (eieio-oset (aref (class-v class) class-default-object-cache) | |
1538 slot value) | |
1539 ))) | |
1540 | |
1541 ;;; Handy CLOS macros | |
1542 ;; | |
1543 (defmacro with-slots (spec-list object &rest body) | |
1544 "Bind SPEC-LIST lexically to slot values in OBJECT, and execute BODY. | |
1545 This establishes a lexical environment for referring to the slots in | |
1546 the instance named by the given slot-names as though they were | |
1547 variables. Within such a context the value of the slot can be | |
1548 specified by using its slot name, as if it were a lexically bound | |
1549 variable. Both setf and setq can be used to set the value of the | |
1550 slot. | |
1551 | |
1552 SPEC-LIST is of a form similar to `let'. For example: | |
1553 | |
1554 ((VAR1 SLOT1) | |
1555 SLOT2 | |
1556 SLOTN | |
1557 (VARN+1 SLOTN+1)) | |
1558 | |
1559 Where each VAR is the local variable given to the associated | |
1560 SLOT. A Slot specified without a variable name is given a | |
1561 variable name of the same name as the slot." | |
1562 ;; Transform the spec-list into a symbol-macrolet spec-list. | |
1563 (let ((mappings (mapcar (lambda (entry) | |
1564 (let ((var (if (listp entry) (car entry) entry)) | |
1565 (slot (if (listp entry) (cadr entry) entry))) | |
1566 (list var `(slot-value ,object ',slot)))) | |
1567 spec-list))) | |
1568 (append (list 'symbol-macrolet mappings) | |
1569 body))) | |
1570 (put 'with-slots 'lisp-indent-function 2) | |
1571 | |
1572 | |
1573 ;;; Simple generators, and query functions. None of these would do | |
1574 ;; well embedded into an object. | |
1575 ;; | |
1576 (defmacro object-class-fast (obj) "Return the class struct defining OBJ with no check." | |
1577 `(aref ,obj object-class)) | |
1578 | |
1579 (defun class-name (class) "Return a Lisp like symbol name for CLASS." | |
1580 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1581 ;; I think this is supposed to return a symbol, but to me CLASS is a symbol, | |
1582 ;; and I wanted a string. Arg! | |
1583 (format "#<class %s>" (symbol-name class))) | |
1584 | |
1585 (defun object-name (obj &optional extra) | |
1586 "Return a Lisp like symbol string for object OBJ. | |
1587 If EXTRA, include that in the string returned to represent the symbol." | |
1588 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1589 (format "#<%s %s%s>" (symbol-name (object-class-fast obj)) | |
1590 (aref obj object-name) (or extra ""))) | |
1591 | |
1592 (defun object-name-string (obj) "Return a string which is OBJ's name." | |
1593 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1594 (aref obj object-name)) | |
1595 | |
1596 (defun object-set-name-string (obj name) "Set the string which is OBJ's NAME." | |
1597 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1598 (if (not (stringp name)) (signal 'wrong-type-argument (list 'stringp name))) | |
1599 (aset obj object-name name)) | |
1600 | |
1601 (defun object-class (obj) "Return the class struct defining OBJ." | |
1602 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1603 (object-class-fast obj)) | |
1604 (defalias 'class-of 'object-class) | |
1605 | |
1606 (defun object-class-name (obj) "Return a Lisp like symbol name for OBJ's class." | |
1607 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1608 (class-name (object-class-fast obj))) | |
1609 | |
1610 (defmacro class-parents-fast (class) "Return parent classes to CLASS with no check." | |
1611 `(aref (class-v ,class) class-parent)) | |
1612 | |
1613 (defun class-parents (class) | |
1614 "Return parent classes to CLASS. (overload of variable). | |
1615 | |
1616 The CLOS function `class-direct-superclasses' is aliased to this function." | |
1617 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1618 (class-parents-fast class)) | |
1619 | |
1620 (defmacro class-children-fast (class) "Return child classes to CLASS with no check." | |
1621 `(aref (class-v ,class) class-children)) | |
1622 | |
1623 (defun class-children (class) | |
1624 "Return child classses to CLASS. | |
1625 | |
1626 The CLOS function `class-direct-subclasses' is aliased to this function." | |
1627 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1628 (class-children-fast class)) | |
1629 | |
1630 ;; Official CLOS functions. | |
1631 (defalias 'class-direct-superclasses 'class-parents) | |
1632 (defalias 'class-direct-subclasses 'class-children) | |
1633 | |
1634 (defmacro class-parent-fast (class) "Return first parent class to CLASS with no check." | |
1635 `(car (class-parents-fast ,class))) | |
1636 | |
1637 (defmacro class-parent (class) "Return first parent class to CLASS. (overload of variable)." | |
1638 `(car (class-parents ,class))) | |
1639 | |
1640 (defmacro same-class-fast-p (obj class) "Return t if OBJ is of class-type CLASS with no error checking." | |
1641 `(eq (aref ,obj object-class) ,class)) | |
1642 | |
1643 (defun same-class-p (obj class) "Return t if OBJ is of class-type CLASS." | |
1644 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1645 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1646 (same-class-fast-p obj class)) | |
1647 | |
1648 (defun object-of-class-p (obj class) | |
1649 "Return non-nil if OBJ is an instance of CLASS or CLASS' subclasses." | |
1650 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1651 ;; class will be checked one layer down | |
1652 (child-of-class-p (aref obj object-class) class)) | |
1653 ;; Backwards compatibility | |
1654 (defalias 'obj-of-class-p 'object-of-class-p) | |
1655 | |
1656 (defun child-of-class-p (child class) | |
1657 "If CHILD class is a subclass of CLASS." | |
1658 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1659 (if (not (class-p child)) (signal 'wrong-type-argument (list 'class-p child))) | |
1660 (let ((p nil)) | |
1661 (while (and child (not (eq child class))) | |
1662 (setq p (append p (aref (class-v child) class-parent)) | |
1663 child (car p) | |
1664 p (cdr p))) | |
1665 (if child t))) | |
1666 | |
1667 (defun object-slots (obj) "List of slots available in OBJ." | |
1668 (if (not (eieio-object-p obj)) (signal 'wrong-type-argument (list 'eieio-object-p obj))) | |
1669 (aref (class-v (object-class-fast obj)) class-public-a)) | |
1670 | |
1671 (defun class-slot-initarg (class slot) "Fetch from CLASS, SLOT's :initarg." | |
1672 (if (not (class-p class)) (signal 'wrong-type-argument (list 'class-p class))) | |
1673 (let ((ia (aref (class-v class) class-initarg-tuples)) | |
1674 (f nil)) | |
1675 (while (and ia (not f)) | |
1676 (if (eq (cdr (car ia)) slot) | |
1677 (setq f (car (car ia)))) | |
1678 (setq ia (cdr ia))) | |
1679 f)) | |
1680 | |
1681 ;;; CLOS queries into classes and slots | |
1682 ;; | |
1683 (defun slot-boundp (object slot) | |
1684 "Non-nil if OBJECT's SLOT is bound. | |
1685 Setting a slot's value makes it bound. Calling `slot-makeunbound' will | |
1686 make a slot unbound. | |
1687 OBJECT can be an instance or a class." | |
1688 ;; Skip typechecking while retrieving this value. | |
1689 (let ((eieio-skip-typecheck t)) | |
1690 ;; Return nil if the magic symbol is in there. | |
1691 (if (eieio-object-p object) | |
1692 (if (eq (eieio-oref object slot) eieio-unbound) nil t) | |
1693 (if (class-p object) | |
1694 (if (eq (eieio-oref-default object slot) eieio-unbound) nil t) | |
1695 (signal 'wrong-type-argument (list 'eieio-object-p object)))))) | |
1696 | |
1697 (defun slot-makeunbound (object slot) | |
1698 "In OBJECT, make SLOT unbound." | |
1699 (eieio-oset object slot eieio-unbound)) | |
1700 | |
1701 (defun slot-exists-p (object-or-class slot) | |
1702 "Non-nil if OBJECT-OR-CLASS has SLOT." | |
1703 (let ((cv (class-v (cond ((eieio-object-p object-or-class) | |
1704 (object-class object-or-class)) | |
1705 ((class-p object-or-class) | |
1706 object-or-class)) | |
1707 ))) | |
1708 (or (memq slot (aref cv class-public-a)) | |
1709 (memq slot (aref cv class-class-allocation-a))) | |
1710 )) | |
1711 | |
1712 (defun find-class (symbol &optional errorp) | |
1713 "Return the class that SYMBOL represents. | |
1714 If there is no class, nil is returned if ERRORP is nil. | |
1715 If ERRORP is non-nil, `wrong-argument-type' is signaled." | |
1716 (if (not (class-p symbol)) | |
1717 (if errorp (signal 'wrong-type-argument (list 'class-p symbol)) | |
1718 nil) | |
1719 (class-v symbol))) | |
1720 | |
1721 ;;; Slightly more complex utility functions for objects | |
1722 ;; | |
1723 (defun object-assoc (key slot list) | |
1724 "Return an object if KEY is `equal' to SLOT's value of an object in LIST. | |
1725 LIST is a list of objects who's slots are searched. | |
1726 Objects in LIST do not need to have a slot named SLOT, nor does | |
1727 SLOT need to be bound. If these errors occur, those objects will | |
1728 be ignored." | |
1729 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list))) | |
1730 (while (and list (not (condition-case nil | |
1731 ;; This prevents errors for missing slots. | |
1732 (equal key (eieio-oref (car list) slot)) | |
1733 (error nil)))) | |
1734 (setq list (cdr list))) | |
1735 (car list)) | |
1736 | |
1737 (defun object-assoc-list (slot list) | |
1738 "Return an association list with the contents of SLOT as the key element. | |
1739 LIST must be a list of objects with SLOT in it. | |
1740 This is useful when you need to do completing read on an object group." | |
1741 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list))) | |
1742 (let ((assoclist nil)) | |
1743 (while list | |
1744 (setq assoclist (cons (cons (eieio-oref (car list) slot) | |
1745 (car list)) | |
1746 assoclist)) | |
1747 (setq list (cdr list))) | |
1748 (nreverse assoclist))) | |
1749 | |
1750 (defun object-assoc-list-safe (slot list) | |
1751 "Return an association list with the contents of SLOT as the key element. | |
1752 LIST must be a list of objects, but those objects do not need to have | |
1753 SLOT in it. If it does not, then that element is left out of the association | |
1754 list." | |
1755 (if (not (listp list)) (signal 'wrong-type-argument (list 'listp list))) | |
1756 (let ((assoclist nil)) | |
1757 (while list | |
1758 (if (slot-exists-p (car list) slot) | |
1759 (setq assoclist (cons (cons (eieio-oref (car list) slot) | |
1760 (car list)) | |
1761 assoclist))) | |
1762 (setq list (cdr list))) | |
1763 (nreverse assoclist))) | |
1764 | |
1765 (defun object-add-to-list (object slot item &optional append) | |
1766 "In OBJECT's SLOT, add ITEM to the list of elements. | |
1767 Optional argument APPEND indicates we need to append to the list. | |
1768 If ITEM already exists in the list in SLOT, then it is not added. | |
1769 Comparison is done with `equal' through the `member' function call. | |
1770 If SLOT is unbound, bind it to the list containing ITEM." | |
1771 (let (ov) | |
1772 ;; Find the originating list. | |
1773 (if (not (slot-boundp object slot)) | |
1774 (setq ov (list item)) | |
1775 (setq ov (eieio-oref object slot)) | |
1776 ;; turn it into a list. | |
1777 (unless (listp ov) | |
1778 (setq ov (list ov))) | |
1779 ;; Do the combination | |
1780 (if (not (member item ov)) | |
1781 (setq ov | |
1782 (if append | |
1783 (append ov (list item)) | |
1784 (cons item ov))))) | |
1785 ;; Set back into the slot. | |
1786 (eieio-oset object slot ov))) | |
1787 | |
1788 (defun object-remove-from-list (object slot item) | |
1789 "In OBJECT's SLOT, remove occurrences of ITEM. | |
1790 Deletion is done with `delete', which deletes by side effect | |
1791 and comparisons are done with `equal'. | |
1792 If SLOT is unbound, do nothing." | |
1793 (if (not (slot-boundp object slot)) | |
1794 nil | |
1795 (eieio-oset object slot (delete item (eieio-oref object slot))))) | |
1796 | |
1797 ;;; EIEIO internal search functions | |
1798 ;; | |
1799 (defun eieio-slot-originating-class-p (start-class slot) | |
1800 "Return Non-nil if START-CLASS is the first class to define SLOT. | |
1801 This is for testing if `scoped-class' is the class that defines SLOT | |
1802 so that we can protect private slots." | |
1803 (let ((par (class-parents start-class)) | |
1804 (ret t)) | |
1805 (if (not par) | |
1806 t | |
1807 (while (and par ret) | |
1808 (if (intern-soft (symbol-name slot) | |
1809 (aref (class-v (car par)) | |
1810 class-symbol-obarray)) | |
1811 (setq ret nil)) | |
1812 (setq par (cdr par))) | |
1813 ret))) | |
1814 | |
1815 (defun eieio-slot-name-index (class obj slot) | |
1816 "In CLASS for OBJ find the index of the named SLOT. | |
1817 The slot is a symbol which is installed in CLASS by the `defclass' | |
1818 call. OBJ can be nil, but if it is an object, and the slot in question | |
1819 is protected, access will be allowed if obj is a child of the currently | |
1820 `scoped-class'. | |
1821 If SLOT is the value created with :initarg instead, | |
1822 reverse-lookup that name, and recurse with the associated slot value." | |
1823 ;; Removed checks to outside this call | |
1824 (let* ((fsym (intern-soft (symbol-name slot) | |
1825 (aref (class-v class) | |
1826 class-symbol-obarray))) | |
1827 (fsi (if (symbolp fsym) (symbol-value fsym) nil))) | |
1828 (if (integerp fsi) | |
1829 (cond | |
1830 ((not (get fsym 'protection)) | |
1831 (+ 3 fsi)) | |
1832 ((and (eq (get fsym 'protection) 'protected) | |
1833 scoped-class | |
1834 (or (child-of-class-p class scoped-class) | |
1835 (and (eieio-object-p obj) | |
1836 (child-of-class-p class (object-class obj))))) | |
1837 (+ 3 fsi)) | |
1838 ((and (eq (get fsym 'protection) 'private) | |
1839 (or (and scoped-class | |
1840 (eieio-slot-originating-class-p scoped-class slot)) | |
1841 eieio-initializing-object)) | |
1842 (+ 3 fsi)) | |
1843 (t nil)) | |
1844 (let ((fn (eieio-initarg-to-attribute class slot))) | |
1845 (if fn (eieio-slot-name-index class obj fn) nil))))) | |
1846 | |
1847 (defun eieio-class-slot-name-index (class slot) | |
1848 "In CLASS find the index of the named SLOT. | |
1849 The slot is a symbol which is installed in CLASS by the `defclass' | |
1850 call. If SLOT is the value created with :initarg instead, | |
1851 reverse-lookup that name, and recurse with the associated slot value." | |
1852 ;; This will happen less often, and with fewer slots. Do this the | |
1853 ;; storage cheap way. | |
1854 (let* ((a (aref (class-v class) class-class-allocation-a)) | |
1855 (l1 (length a)) | |
1856 (af (memq slot a)) | |
1857 (l2 (length af))) | |
1858 ;; Slot # is length of the total list, minus the remaining list of | |
1859 ;; the found slot. | |
1860 (if af (- l1 l2)))) | |
1861 | |
1862 ;;; CLOS generics internal function handling | |
1863 ;; | |
1864 (defvar eieio-generic-call-methodname nil | |
1865 "When using `call-next-method', provides a context on how to do it.") | |
1866 (defvar eieio-generic-call-arglst nil | |
1867 "When using `call-next-method', provides a context for parameters.") | |
1868 (defvar eieio-generic-call-key nil | |
1869 "When using `call-next-method', provides a context for the current key. | |
1870 Keys are a number representing :before, :primary, and :after methods.") | |
1871 (defvar eieio-generic-call-next-method-list nil | |
1872 "When executing a PRIMARY or STATIC method, track the 'next-method'. | |
1873 During executions, the list is first generated, then as each next method | |
1874 is called, the next method is popped off the stack.") | |
1875 | |
1876 (defvar eieio-pre-method-execution-hooks nil | |
1877 "*Hooks run just before a method is executed. | |
1878 The hook function must accept on argument, this list of forms | |
1879 about to be executed.") | |
1880 | |
1881 (defun eieio-generic-call (method args) | |
1882 "Call METHOD with ARGS. | |
1883 ARGS provides the context on which implementation to use. | |
1884 This should only be called from a generic function." | |
1885 ;; We must expand our arguments first as they are always | |
1886 ;; passed in as quoted symbols | |
1887 (let ((newargs nil) (mclass nil) (lambdas nil) (tlambdas nil) (keys nil) | |
1888 (eieio-generic-call-methodname method) | |
1889 (eieio-generic-call-arglst args) | |
1890 (firstarg nil) | |
1891 (primarymethodlist nil)) | |
1892 ;; get a copy | |
1893 (setq newargs args | |
1894 firstarg (car newargs)) | |
1895 ;; Is the class passed in autoloaded? | |
1896 ;; Since class names are also constructors, they can be autoloaded | |
1897 ;; via the autoload command. Check for this, and load them in. | |
1898 ;; It's ok if it doesn't turn out to be a class. Probably want that | |
1899 ;; function loaded anyway. | |
1900 (if (and (symbolp firstarg) | |
1901 (fboundp firstarg) | |
1902 (listp (symbol-function firstarg)) | |
1903 (eq 'autoload (car (symbol-function firstarg)))) | |
1904 (load (nth 1 (symbol-function firstarg)))) | |
1905 ;; Determine the class to use. | |
1906 (cond ((eieio-object-p firstarg) | |
1907 (setq mclass (object-class-fast firstarg))) | |
1908 ((class-p firstarg) | |
1909 (setq mclass firstarg)) | |
1910 ) | |
1911 ;; Make sure the class is a valid class | |
1912 ;; mclass can be nil (meaning a generic for should be used. | |
1913 ;; mclass cannot have a value that is not a class, however. | |
1914 (when (and (not (null mclass)) (not (class-p mclass))) | |
1915 (error "Cannot dispatch method %S on class %S" | |
1916 method mclass) | |
1917 ) | |
1918 ;; Now create a list in reverse order of all the calls we have | |
1919 ;; make in order to successfully do this right. Rules: | |
1920 ;; 1) Only call generics if scoped-class is not defined | |
1921 ;; This prevents multiple calls in the case of recursion | |
1922 ;; 2) Only call static if this is a static method. | |
1923 ;; 3) Only call specifics if the definition allows for them. | |
1924 ;; 4) Call in order based on :before, :primary, and :after | |
1925 (when (eieio-object-p firstarg) | |
1926 ;; Non-static calls do all this stuff. | |
1927 | |
1928 ;; :after methods | |
1929 (setq tlambdas | |
1930 (if mclass | |
1931 (eieiomt-method-list method method-after mclass) | |
1932 (list (eieio-generic-form method method-after nil))) | |
1933 ;;(or (and mclass (eieio-generic-form method method-after mclass)) | |
1934 ;; (eieio-generic-form method method-after nil)) | |
1935 ) | |
1936 (setq lambdas (append tlambdas lambdas) | |
1937 keys (append (make-list (length tlambdas) method-after) keys)) | |
1938 | |
1939 ;; :primary methods | |
1940 (setq tlambdas | |
1941 (or (and mclass (eieio-generic-form method method-primary mclass)) | |
1942 (eieio-generic-form method method-primary nil))) | |
1943 (when tlambdas | |
1944 (setq lambdas (cons tlambdas lambdas) | |
1945 keys (cons method-primary keys) | |
1946 primarymethodlist | |
1947 (eieiomt-method-list method method-primary mclass))) | |
1948 | |
1949 ;; :before methods | |
1950 (setq tlambdas | |
1951 (if mclass | |
1952 (eieiomt-method-list method method-before mclass) | |
1953 (list (eieio-generic-form method method-before nil))) | |
1954 ;;(or (and mclass (eieio-generic-form method method-before mclass)) | |
1955 ;; (eieio-generic-form method method-before nil)) | |
1956 ) | |
1957 (setq lambdas (append tlambdas lambdas) | |
1958 keys (append (make-list (length tlambdas) method-before) keys)) | |
1959 ) | |
1960 | |
1961 ;; If there were no methods found, then there could be :static methods. | |
1962 (when (not lambdas) | |
1963 (setq tlambdas | |
1964 (eieio-generic-form method method-static mclass)) | |
1965 (setq lambdas (cons tlambdas lambdas) | |
1966 keys (cons method-static keys) | |
1967 primarymethodlist ;; Re-use even with bad name here | |
1968 (eieiomt-method-list method method-static mclass))) | |
1969 | |
1970 (run-hook-with-args 'eieio-pre-method-execution-hooks | |
1971 primarymethodlist) | |
1972 | |
1973 ;; Now loop through all occurances forms which we must execute | |
1974 ;; (which are happily sorted now) and execute them all! | |
1975 (let ((rval nil) (lastval nil) (rvalever nil) (found nil)) | |
1976 (while lambdas | |
1977 (if (car lambdas) | |
1978 (let* ((scoped-class (cdr (car lambdas))) | |
1979 (eieio-generic-call-key (car keys)) | |
1980 (has-return-val | |
1981 (or (= eieio-generic-call-key method-primary) | |
1982 (= eieio-generic-call-key method-static))) | |
1983 (eieio-generic-call-next-method-list | |
1984 ;; Use the cdr, as the first element is the fcn | |
1985 ;; we are calling right now. | |
1986 (when has-return-val (cdr primarymethodlist))) | |
1987 ) | |
1988 (setq found t) | |
1989 ;;(setq rval (apply (car (car lambdas)) newargs)) | |
1990 (setq lastval (apply (car (car lambdas)) newargs)) | |
1991 (when has-return-val | |
1992 (setq rval lastval | |
1993 rvalever t)) | |
1994 )) | |
1995 (setq lambdas (cdr lambdas) | |
1996 keys (cdr keys))) | |
1997 (if (not found) | |
1998 (if (eieio-object-p (car args)) | |
1999 (setq rval (apply 'no-applicable-method (car args) method args) | |
2000 rvalever t) | |
2001 (signal | |
2002 'no-method-definition | |
2003 (list method args)))) | |
2004 ;; Right Here... it could be that lastval is returned when | |
2005 ;; rvalever is nil. Is that right? | |
2006 rval))) | |
2007 | |
2008 (defun eieio-generic-call-primary-only (method args) | |
2009 "Call METHOD with ARGS for methods with only :PRIMARY implementations. | |
2010 ARGS provides the context on which implementation to use. | |
2011 This should only be called from a generic function. | |
2012 | |
2013 This method is like `eieio-generic-call', but only | |
2014 implementations in the :PRIMARY slot are queried. After many | |
2015 years of use, it appears that over 90% of methods in use | |
2016 have :PRIMARY implementations only. We can therefore optimize | |
2017 for this common case to improve performance." | |
2018 ;; We must expand our arguments first as they are always | |
2019 ;; passed in as quoted symbols | |
2020 (let ((newargs nil) (mclass nil) (lambdas nil) | |
2021 (eieio-generic-call-methodname method) | |
2022 (eieio-generic-call-arglst args) | |
2023 (firstarg nil) | |
2024 (primarymethodlist nil) | |
2025 ) | |
2026 ;; get a copy | |
2027 (setq newargs args | |
2028 firstarg (car newargs)) | |
2029 | |
2030 ;; Determine the class to use. | |
2031 (cond ((eieio-object-p firstarg) | |
2032 (setq mclass (object-class-fast firstarg))) | |
2033 ((not firstarg) | |
2034 (error "Method %s called on nil" method)) | |
2035 ((not (eieio-object-p firstarg)) | |
2036 (error "Primary-only method %s called on something not an object" method)) | |
2037 (t | |
2038 (error "EIEIO Error: Improperly classified method %s as primary only" | |
2039 method) | |
2040 )) | |
2041 ;; Make sure the class is a valid class | |
2042 ;; mclass can be nil (meaning a generic for should be used. | |
2043 ;; mclass cannot have a value that is not a class, however. | |
2044 (when (null mclass) | |
2045 (error "Cannot dispatch method %S on class %S" method mclass) | |
2046 ) | |
2047 | |
2048 ;; :primary methods | |
2049 (setq lambdas (eieio-generic-form method method-primary mclass)) | |
2050 (setq primarymethodlist ;; Re-use even with bad name here | |
2051 (eieiomt-method-list method method-primary mclass)) | |
2052 | |
2053 ;; Now loop through all occurances forms which we must execute | |
2054 ;; (which are happily sorted now) and execute them all! | |
2055 (let* ((rval nil) (lastval nil) (rvalever nil) | |
2056 (scoped-class (cdr lambdas)) | |
2057 (eieio-generic-call-key method-primary) | |
2058 ;; Use the cdr, as the first element is the fcn | |
2059 ;; we are calling right now. | |
2060 (eieio-generic-call-next-method-list (cdr primarymethodlist)) | |
2061 ) | |
2062 | |
2063 (if (or (not lambdas) (not (car lambdas))) | |
2064 | |
2065 ;; No methods found for this impl... | |
2066 (if (eieio-object-p (car args)) | |
2067 (setq rval (apply 'no-applicable-method (car args) method args) | |
2068 rvalever t) | |
2069 (signal | |
2070 'no-method-definition | |
2071 (list method args))) | |
2072 | |
2073 ;; Do the regular implementation here. | |
2074 | |
2075 (run-hook-with-args 'eieio-pre-method-execution-hooks | |
2076 lambdas) | |
2077 | |
2078 (setq lastval (apply (car lambdas) newargs)) | |
2079 (setq rval lastval | |
2080 rvalever t) | |
2081 ) | |
2082 | |
2083 ;; Right Here... it could be that lastval is returned when | |
2084 ;; rvalever is nil. Is that right? | |
2085 rval))) | |
2086 | |
2087 (defun eieiomt-method-list (method key class) | |
2088 "Return an alist list of methods lambdas. | |
2089 METHOD is the method name. | |
2090 KEY represents either :before, or :after methods. | |
2091 CLASS is the starting class to search from in the method tree. | |
2092 If CLASS is nil, then an empty list of methods should be returned." | |
2093 ;; Note: eieiomt - the MT means MethodTree. See more comments below | |
2094 ;; for the rest of the eieiomt methods. | |
2095 (let ((lambdas nil) | |
2096 (mclass (list class))) | |
2097 (while mclass | |
2098 ;; Note: a nil can show up in the class list once we start | |
2099 ;; searching through the method tree. | |
2100 (when (car mclass) | |
2101 ;; lookup the form to use for the PRIMARY object for the next level | |
2102 (let ((tmpl (eieio-generic-form method key (car mclass)))) | |
2103 (when (or (not lambdas) | |
2104 ;; This prevents duplicates coming out of the | |
2105 ;; class method optimizer. Perhaps we should | |
2106 ;; just not optimize before/afters? | |
2107 (not (eq (car tmpl) (car (car lambdas))))) | |
2108 (setq lambdas (cons tmpl lambdas)) | |
2109 (if (null (car lambdas)) | |
2110 (setq lambdas (cdr lambdas)))))) | |
2111 ;; Add new classes to mclass. Since our input might not be a class | |
2112 ;; protect against that. | |
2113 (if (car mclass) | |
2114 ;; If there is a class, append any methods it may provide | |
2115 ;; to the remainder of the class list. | |
2116 (let ((io (class-method-invocation-order (car mclass)))) | |
2117 (if (eq io :depth-first) | |
2118 ;; Depth first. | |
2119 (setq mclass (append (eieiomt-next (car mclass)) (cdr mclass))) | |
2120 ;; Breadth first. | |
2121 (setq mclass (append (cdr mclass) (eieiomt-next (car mclass))))) | |
2122 ) | |
2123 ;; Advance to next entry in mclass if it is nil. | |
2124 (setq mclass (cdr mclass))) | |
2125 ) | |
2126 (if (eq key method-after) | |
2127 lambdas | |
2128 (nreverse lambdas)))) | |
2129 | |
2130 (defun next-method-p () | |
2131 "Non-nil if there is a next method. | |
2132 Returns a list of lambda expressions which is the `next-method' | |
2133 order." | |
2134 eieio-generic-call-next-method-list) | |
2135 | |
2136 (defun call-next-method (&rest replacement-args) | |
2137 "Call the superclass method from a subclass method. | |
2138 The superclass method is specified in the current method list, | |
2139 and is called the next method. | |
2140 | |
2141 If REPLACEMENT-ARGS is non-nil, then use them instead of | |
2142 `eieio-generic-call-arglst'. The generic arg list are the | |
2143 arguments passed in at the top level. | |
2144 | |
2145 Use `next-method-p' to find out if there is a next method to call." | |
2146 (if (not scoped-class) | |
2147 (error "Call-next-method not called within a class specific method")) | |
2148 (if (and (/= eieio-generic-call-key method-primary) | |
2149 (/= eieio-generic-call-key method-static)) | |
2150 (error "Cannot `call-next-method' except in :primary or :static methods") | |
2151 ) | |
2152 (let ((newargs (or replacement-args eieio-generic-call-arglst)) | |
2153 (next (car eieio-generic-call-next-method-list)) | |
2154 ) | |
2155 (if (or (not next) (not (car next))) | |
2156 (apply 'no-next-method (car newargs) (cdr newargs)) | |
2157 (let* ((eieio-generic-call-next-method-list | |
2158 (cdr eieio-generic-call-next-method-list)) | |
2159 (scoped-class (cdr next)) | |
2160 (fcn (car next)) | |
2161 ) | |
2162 (apply fcn newargs) | |
2163 )))) | |
2164 | |
2165 ;;; | |
2166 ;; eieio-method-tree : eieiomt- | |
2167 ;; | |
2168 ;; Stored as eieio-method-tree in property list of a generic method | |
2169 ;; | |
2170 ;; (eieio-method-tree . [BEFORE PRIMARY AFTER | |
2171 ;; genericBEFORE genericPRIMARY genericAFTER]) | |
2172 ;; and | |
2173 ;; (eieio-method-obarray . [BEFORE PRIMARY AFTER | |
2174 ;; genericBEFORE genericPRIMARY genericAFTER]) | |
2175 ;; where the association is a vector. | |
2176 ;; (aref 0 -- all static methods. | |
2177 ;; (aref 1 -- all methods classified as :before | |
2178 ;; (aref 2 -- all methods classified as :primary | |
2179 ;; (aref 3 -- all methods classified as :after | |
2180 ;; (aref 4 -- a generic classified as :before | |
2181 ;; (aref 5 -- a generic classified as :primary | |
2182 ;; (aref 6 -- a generic classified as :after | |
2183 ;; | |
2184 (defvar eieiomt-optimizing-obarray nil | |
2185 "While mapping atoms, this contain the obarray being optimized.") | |
2186 | |
2187 (defun eieiomt-install (method-name) | |
2188 "Install the method tree, and obarray onto METHOD-NAME. | |
2189 Do not do the work if they already exist." | |
2190 (let ((emtv (get method-name 'eieio-method-tree)) | |
2191 (emto (get method-name 'eieio-method-obarray))) | |
2192 (if (or (not emtv) (not emto)) | |
2193 (progn | |
2194 (setq emtv (put method-name 'eieio-method-tree | |
2195 (make-vector method-num-slots nil)) | |
2196 emto (put method-name 'eieio-method-obarray | |
2197 (make-vector method-num-slots nil))) | |
2198 (aset emto 0 (make-vector 11 0)) | |
2199 (aset emto 1 (make-vector 11 0)) | |
2200 (aset emto 2 (make-vector 41 0)) | |
2201 (aset emto 3 (make-vector 11 0)) | |
2202 )))) | |
2203 | |
2204 (defun eieiomt-add (method-name method key class) | |
2205 "Add to METHOD-NAME the forms METHOD in a call position KEY for CLASS. | |
2206 METHOD-NAME is the name created by a call to `defgeneric'. | |
2207 METHOD are the forms for a given implementation. | |
2208 KEY is an integer (see comment in eieio.el near this function) which | |
2209 is associated with the :static :before :primary and :after tags. | |
2210 It also indicates if CLASS is defined or not. | |
2211 CLASS is the class this method is associated with." | |
2212 (if (or (> key method-num-slots) (< key 0)) | |
2213 (error "Eieiomt-add: method key error!")) | |
2214 (let ((emtv (get method-name 'eieio-method-tree)) | |
2215 (emto (get method-name 'eieio-method-obarray))) | |
2216 ;; Make sure the method tables are available. | |
2217 (if (or (not emtv) (not emto)) | |
2218 (error "Programmer error: eieiomt-add")) | |
2219 ;; only add new cells on if it doesn't already exist! | |
2220 (if (assq class (aref emtv key)) | |
2221 (setcdr (assq class (aref emtv key)) method) | |
2222 (aset emtv key (cons (cons class method) (aref emtv key)))) | |
2223 ;; Add function definition into newly created symbol, and store | |
2224 ;; said symbol in the correct obarray, otherwise use the | |
2225 ;; other array to keep this stuff | |
2226 (if (< key method-num-lists) | |
2227 (let ((nsym (intern (symbol-name class) (aref emto key)))) | |
2228 (fset nsym method))) | |
2229 ;; Now optimize the entire obarray | |
2230 (if (< key method-num-lists) | |
2231 (let ((eieiomt-optimizing-obarray (aref emto key))) | |
2232 ;; @todo - Is this overkill? Should we just clear the symbol? | |
2233 (mapatoms 'eieiomt-sym-optimize eieiomt-optimizing-obarray))) | |
2234 )) | |
2235 | |
2236 (defun eieiomt-next (class) | |
2237 "Return the next parent class for CLASS. | |
2238 If CLASS is a superclass, return variable `eieio-default-superclass'. If CLASS | |
2239 is variable `eieio-default-superclass' then return nil. This is different from | |
2240 function `class-parent' as class parent returns nil for superclasses. This | |
2241 function performs no type checking!" | |
2242 ;; No type-checking because all calls are made from functions which | |
2243 ;; are safe and do checking for us. | |
2244 (or (class-parents-fast class) | |
2245 (if (eq class 'eieio-default-superclass) | |
2246 nil | |
2247 '(eieio-default-superclass)))) | |
2248 | |
2249 (defun eieiomt-sym-optimize (s) | |
2250 "Find the next class above S which has a function body for the optimizer." | |
2251 ;; (message "Optimizing %S" s) | |
2252 (let* ((es (intern-soft (symbol-name s))) ;external symbol of class | |
2253 (io (class-method-invocation-order es)) | |
2254 (ov nil) | |
2255 (cont t)) | |
2256 ;; This converts ES from a single symbol to a list of parent classes. | |
2257 (setq es (eieiomt-next es)) | |
2258 ;; Loop over ES, then it's children individually. | |
2259 ;; We can have multiple hits only at one level of the parent tree. | |
2260 (while (and es cont) | |
2261 (setq ov (intern-soft (symbol-name (car es)) eieiomt-optimizing-obarray)) | |
2262 (if (fboundp ov) | |
2263 (progn | |
2264 (set s ov) ;store ov as our next symbol | |
2265 (setq cont nil)) | |
2266 (if (eq io :depth-first) | |
2267 ;; Pre-pend the subclasses of (car es) so we get | |
2268 ;; DEPTH FIRST optimization. | |
2269 (setq es (append (eieiomt-next (car es)) (cdr es))) | |
2270 ;; Else, we are breadth first. | |
2271 ;; (message "Class %s is breadth first" es) | |
2272 (setq es (append (cdr es) (eieiomt-next (car es)))) | |
2273 ))) | |
2274 ;; If there is no nearest call, then set our value to nil | |
2275 (if (not es) (set s nil)) | |
2276 )) | |
2277 | |
2278 (defun eieio-generic-form (method key class) | |
2279 "Return the lambda form belonging to METHOD using KEY based upon CLASS. | |
2280 If CLASS is not a class then use `generic' instead. If class has no | |
2281 form, but has a parent class, then trace to that parent class. The | |
2282 first time a form is requested from a symbol, an optimized path is | |
2283 memoized for future faster use." | |
2284 (let ((emto (aref (get method 'eieio-method-obarray) | |
2285 (if class key (+ key 3))))) | |
2286 (if (class-p class) | |
2287 ;; 1) find our symbol | |
2288 (let ((cs (intern-soft (symbol-name class) emto))) | |
2289 (if (not cs) | |
2290 ;; 2) If there isn't one, then make one. | |
2291 ;; This can be slow since it only occurs once | |
2292 (progn | |
2293 (setq cs (intern (symbol-name class) emto)) | |
2294 ;; 2.1) Cache it's nearest neighbor with a quick optimize | |
2295 ;; which should only occur once for this call ever | |
2296 (let ((eieiomt-optimizing-obarray emto)) | |
2297 (eieiomt-sym-optimize cs)))) | |
2298 ;; 3) If it's bound return this one. | |
2299 (if (fboundp cs) | |
2300 (cons cs (aref (class-v class) class-symbol)) | |
2301 ;; 4) If it's not bound then this variable knows something | |
2302 (if (symbol-value cs) | |
2303 (progn | |
2304 ;; 4.1) This symbol holds the next class in it's value | |
2305 (setq class (symbol-value cs) | |
2306 cs (intern-soft (symbol-name class) emto)) | |
2307 ;; 4.2) The optimizer should always have chosen a | |
2308 ;; function-symbol | |
2309 ;;(if (fboundp cs) | |
2310 (cons cs (aref (class-v (intern (symbol-name class))) | |
2311 class-symbol)) | |
2312 ;;(error "EIEIO optimizer: erratic data loss!")) | |
2313 ) | |
2314 ;; There never will be a funcall... | |
2315 nil))) | |
2316 ;; for a generic call, what is a list, is the function body we want. | |
2317 (let ((emtl (aref (get method 'eieio-method-tree) | |
2318 (if class key (+ key 3))))) | |
2319 (if emtl | |
2320 ;; The car of EMTL is supposed to be a class, which in this | |
2321 ;; case is nil, so skip it. | |
2322 (cons (cdr (car emtl)) nil) | |
2323 nil))))) | |
2324 | |
2325 ;;; | |
2326 ;; Way to assign slots based on a list. Used for constructors, or | |
2327 ;; even resetting an object at run-time | |
2328 ;; | |
2329 (defun eieio-set-defaults (obj &optional set-all) | |
2330 "Take object OBJ, and reset all slots to their defaults. | |
2331 If SET-ALL is non-nil, then when a default is nil, that value is | |
2332 reset. If SET-ALL is nil, the slots are only reset if the default is | |
2333 not nil." | |
2334 (let ((scoped-class (aref obj object-class)) | |
2335 (eieio-initializing-object t) | |
2336 (pub (aref (class-v (aref obj object-class)) class-public-a))) | |
2337 (while pub | |
2338 (let ((df (eieio-oref-default obj (car pub)))) | |
2339 (if (or df set-all) | |
2340 (eieio-oset obj (car pub) df))) | |
2341 (setq pub (cdr pub))))) | |
2342 | |
2343 (defun eieio-initarg-to-attribute (class initarg) | |
2344 "For CLASS, convert INITARG to the actual attribute name. | |
2345 If there is no translation, pass it in directly (so we can cheat if | |
2346 need be.. May remove that later...)" | |
2347 (let ((tuple (assoc initarg (aref (class-v class) class-initarg-tuples)))) | |
2348 (if tuple | |
2349 (cdr tuple) | |
2350 nil))) | |
2351 | |
2352 (defun eieio-attribute-to-initarg (class attribute) | |
2353 "In CLASS, convert the ATTRIBUTE into the corresponding init argument tag. | |
2354 This is usually a symbol that starts with `:'." | |
2355 (let ((tuple (rassoc attribute (aref (class-v class) class-initarg-tuples)))) | |
2356 (if tuple | |
2357 (car tuple) | |
2358 nil))) | |
2359 | |
2360 | |
2361 ;;; Here are some special types of errors | |
2362 ;; | |
2363 (intern "no-method-definition") | |
2364 (put 'no-method-definition 'error-conditions '(no-method-definition error)) | |
2365 (put 'no-method-definition 'error-message "No method definition") | |
2366 | |
2367 (intern "no-next-method") | |
2368 (put 'no-next-method 'error-conditions '(no-next-method error)) | |
2369 (put 'no-next-method 'error-message "No next method") | |
2370 | |
2371 (intern "invalid-slot-name") | |
2372 (put 'invalid-slot-name 'error-conditions '(invalid-slot-name error)) | |
2373 (put 'invalid-slot-name 'error-message "Invalid slot name") | |
2374 | |
2375 (intern "invalid-slot-type") | |
2376 (put 'invalid-slot-type 'error-conditions '(invalid-slot-type error nil)) | |
2377 (put 'invalid-slot-type 'error-message "Invalid slot type") | |
2378 | |
2379 (intern "unbound-slot") | |
2380 (put 'unbound-slot 'error-conditions '(unbound-slot error nil)) | |
2381 (put 'unbound-slot 'error-message "Unbound slot") | |
2382 | |
2383 ;;; Here are some CLOS items that need the CL package | |
2384 ;; | |
2385 | |
2386 (defsetf slot-value (obj slot) (store) (list 'eieio-oset obj slot store)) | |
2387 (defsetf eieio-oref (obj slot) (store) (list 'eieio-oset obj slot store)) | |
2388 | |
2389 ;; The below setf method was written by Arnd Kohrs <kohrs@acm.org> | |
2390 (define-setf-method oref (obj slot) | |
2391 (let ((obj-temp (gensym)) | |
2392 (slot-temp (gensym)) | |
2393 (store-temp (gensym))) | |
2394 (list (list obj-temp slot-temp) | |
2395 (list obj `(quote ,slot)) | |
2396 (list store-temp) | |
2397 (list 'set-slot-value obj-temp slot-temp | |
2398 store-temp) | |
2399 (list 'slot-value obj-temp slot-temp)))) | |
2400 | |
2401 | |
2402 ;;; | |
2403 ;; We want all objects created by EIEIO to have some default set of | |
2404 ;; behaviours so we can create object utilities, and allow various | |
2405 ;; types of error checking. To do this, create the default EIEIO | |
2406 ;; class, and when no parent class is specified, use this as the | |
2407 ;; default. (But don't store it in the other classes as the default, | |
2408 ;; allowing for transparent support.) | |
2409 ;; | |
2410 | |
2411 (defclass eieio-default-superclass nil | |
2412 nil | |
2413 "Default parent class for classes with no specified parent class. | |
2414 Its slots are automatically adopted by classes with no specified | |
2415 parents. This class is not stored in the `parent' slot of a class vector." | |
2416 :abstract t) | |
2417 | |
2418 (defalias 'standard-class 'eieio-default-superclass) | |
2419 | |
2420 (defgeneric constructor (class newname &rest slots) | |
2421 "Default constructor for CLASS `eieio-defualt-superclass'.") | |
2422 | |
2423 (defmethod constructor :static | |
2424 ((class eieio-default-superclass) newname &rest slots) | |
2425 "Default constructor for CLASS `eieio-defualt-superclass'. | |
2426 NEWNAME is the name to be given to the constructed object. | |
2427 SLOTS are the initialization slots used by `shared-initialize'. | |
2428 This static method is called when an object is constructed. | |
2429 It allocates the vector used to represent an EIEIO object, and then | |
2430 calls `shared-initialize' on that object." | |
2431 (let* ((new-object (copy-sequence (aref (class-v class) | |
2432 class-default-object-cache)))) | |
2433 ;; Update the name for the newly created object. | |
2434 (aset new-object object-name newname) | |
2435 ;; Call the initialize method on the new object with the slots | |
2436 ;; that were passed down to us. | |
2437 (initialize-instance new-object slots) | |
2438 ;; Return the created object. | |
2439 new-object)) | |
2440 | |
2441 (defgeneric shared-initialize (obj slots) | |
2442 "Set slots of OBJ with SLOTS which is a list of name/value pairs. | |
2443 Called from the constructor routine.") | |
2444 | |
2445 (defmethod shared-initialize ((obj eieio-default-superclass) slots) | |
2446 "Set slots of OBJ with SLOTS which is a list of name/value pairs. | |
2447 Called from the constructor routine." | |
2448 (let ((scoped-class (aref obj object-class))) | |
2449 (while slots | |
2450 (let ((rn (eieio-initarg-to-attribute (object-class-fast obj) | |
2451 (car slots)))) | |
2452 (if (not rn) | |
2453 (slot-missing obj (car slots) 'oset (car (cdr slots))) | |
2454 (eieio-oset obj rn (car (cdr slots))))) | |
2455 (setq slots (cdr (cdr slots)))))) | |
2456 | |
2457 (defgeneric initialize-instance (this &optional slots) | |
2458 "Constructs the new object THIS based on SLOTS.") | |
2459 | |
2460 (defmethod initialize-instance ((this eieio-default-superclass) | |
2461 &optional slots) | |
2462 "Constructs the new object THIS based on SLOTS. | |
2463 SLOTS is a tagged list where odd numbered elements are tags, and | |
2464 even numbered elements are the values to store in the tagged slot. If | |
2465 you overload the `initialize-instance', there you will need to call | |
2466 `shared-initialize' yourself, or you can call `call-next-method' to | |
2467 have this constructor called automatically. If these steps are not | |
2468 taken, then new objects of your class will not have their values | |
2469 dynamically set from SLOTS." | |
2470 ;; First, see if any of our defaults are `lambda', and | |
2471 ;; re-evaluate them and apply the value to our slots. | |
2472 (let* ((scoped-class (class-v (aref this object-class))) | |
2473 (slot (aref scoped-class class-public-a)) | |
2474 (defaults (aref scoped-class class-public-d))) | |
2475 (while slot | |
2476 (setq slot (cdr slot) | |
2477 defaults (cdr defaults)))) | |
2478 ;; Shared initialize will parse our slots for us. | |
2479 (shared-initialize this slots)) | |
2480 | |
2481 (defgeneric slot-missing (object slot-name operation &optional new-value) | |
2482 "Method invoked when an attempt to access a slot in OBJECT fails.") | |
2483 | |
2484 (defmethod slot-missing ((object eieio-default-superclass) slot-name | |
2485 operation &optional new-value) | |
2486 "Method invoked when an attempt to access a slot in OBJECT fails. | |
2487 SLOT-NAME is the name of the failed slot, OPERATION is the type of access | |
2488 that was requested, and optional NEW-VALUE is the value that was desired | |
2489 to be set. | |
2490 | |
2491 This method is called from `oref', `oset', and other functions which | |
2492 directly reference slots in EIEIO objects." | |
2493 (signal 'invalid-slot-name (list (object-name object) | |
2494 slot-name))) | |
2495 | |
2496 (defgeneric slot-unbound (object class slot-name fn) | |
2497 "Slot unbound is invoked during an attempt to reference an unbound slot.") | |
2498 | |
2499 (defmethod slot-unbound ((object eieio-default-superclass) | |
2500 class slot-name fn) | |
2501 "Slot unbound is invoked during an attempt to reference an unbound slot. | |
2502 OBJECT is the instance of the object being reference. CLASS is the | |
2503 class of OBJECT, and SLOT-NAME is the offending slot. This function | |
2504 throws the signal `unbound-slot'. You can overload this function and | |
2505 return the value to use in place of the unbound value. | |
2506 Argument FN is the function signaling this error. | |
2507 Use `slot-boundp' to determine if a slot is bound or not. | |
2508 | |
2509 In CLOS, the argument list is (CLASS OBJECT SLOT-NAME), but | |
2510 EIEIO can only dispatch on the first argument, so the first two are swapped." | |
2511 (signal 'unbound-slot (list (class-name class) (object-name object) | |
2512 slot-name fn))) | |
2513 | |
2514 (defgeneric no-applicable-method (object method &rest args) | |
2515 "Called if there are no implementations for OBJECT in METHOD.") | |
2516 | |
2517 (defmethod no-applicable-method ((object eieio-default-superclass) | |
2518 method &rest args) | |
2519 "Called if there are no implementations for OBJECT in METHOD. | |
2520 OBJECT is the object which has no method implementation. | |
2521 ARGS are the arguments that were passed to METHOD. | |
2522 | |
2523 Implement this for a class to block this signal. The return | |
2524 value becomes the return value of the original method call." | |
2525 (signal 'no-method-definition (list method (object-name object))) | |
2526 ) | |
2527 | |
2528 (defgeneric no-next-method (object &rest args) | |
2529 "Called from `call-next-method' when no additional methods are available.") | |
2530 | |
2531 (defmethod no-next-method ((object eieio-default-superclass) | |
2532 &rest args) | |
2533 "Called from `call-next-method' when no additional methods are available. | |
2534 OBJECT is othe object being called on `call-next-method'. | |
2535 ARGS are the arguments it is called by. | |
2536 This method signals `no-next-method' by default. Override this | |
2537 method to not throw an error, and it's return value becomes the | |
2538 return value of `call-next-method'." | |
2539 (signal 'no-next-method (list (object-name object) args)) | |
2540 ) | |
2541 | |
2542 (defgeneric clone (obj &rest params) | |
2543 "Make a copy of OBJ, and then supply PARAMS. | |
2544 PARAMS is a parameter list of the same form used by `initialize-instance'. | |
2545 | |
2546 When overloading `clone', be sure to call `call-next-method' | |
2547 first and modify the returned object.") | |
2548 | |
2549 (defmethod clone ((obj eieio-default-superclass) &rest params) | |
2550 "Make a copy of OBJ, and then apply PARAMS." | |
2551 (let ((nobj (copy-sequence obj)) | |
2552 (nm (aref obj object-name)) | |
2553 (passname (and params (stringp (car params)))) | |
2554 (num 1)) | |
2555 (if params (shared-initialize nobj (if passname (cdr params) params))) | |
2556 (if (not passname) | |
2557 (save-match-data | |
2558 (if (string-match "-\\([0-9]+\\)" nm) | |
2559 (setq num (1+ (string-to-number (match-string 1 nm))) | |
2560 nm (substring nm 0 (match-beginning 0)))) | |
2561 (aset nobj object-name (concat nm "-" (int-to-string num)))) | |
2562 (aset nobj object-name (car params))) | |
2563 nobj)) | |
2564 | |
2565 (defgeneric destructor (this &rest params) | |
2566 "Destructor for cleaning up any dynamic links to our object.") | |
2567 | |
2568 (defmethod destructor ((this eieio-default-superclass) &rest params) | |
2569 "Destructor for cleaning up any dynamic links to our object. | |
2570 Argument THIS is the object being destroyed. PARAMS are additional | |
2571 ignored parameters." | |
2572 ;; No cleanup... yet. | |
2573 ) | |
2574 | |
2575 (defgeneric object-print (this &rest strings) | |
2576 "Pretty printer for object THIS. Call function `object-name' with STRINGS. | |
2577 | |
2578 It is sometimes useful to put a summary of the object into the | |
2579 default #<notation> string when using eieio browsing tools. | |
2580 Implement this method to customize the summary.") | |
2581 | |
2582 (defmethod object-print ((this eieio-default-superclass) &rest strings) | |
2583 "Pretty printer for object THIS. Call function `object-name' with STRINGS. | |
2584 The default method for printing object THIS is to use the | |
2585 function `object-name'. | |
2586 | |
2587 It is sometimes useful to put a summary of the object into the | |
2588 default #<notation> string when using eieio browsing tools. | |
2589 | |
2590 Implement this function and specify STRINGS in a call to | |
2591 `call-next-method' to provide additional summary information. | |
2592 When passing in extra strings from child classes, always remember | |
2593 to prepend a space." | |
2594 (object-name this (apply 'concat strings))) | |
2595 | |
2596 (defvar eieio-print-depth 0 | |
2597 "When printing, keep track of the current indentation depth.") | |
2598 | |
2599 (defgeneric object-write (this &optional comment) | |
2600 "Write out object THIS to the current stream. | |
2601 Optional COMMENDS will add comments to the beginning of the output.") | |
2602 | |
2603 (defmethod object-write ((this eieio-default-superclass) &optional comment) | |
2604 "Write object THIS out to the current stream. | |
2605 This writes out the vector version of this object. Complex and recursive | |
2606 object are discouraged from being written. | |
2607 If optional COMMENT is non-nil, include comments when outputting | |
2608 this object." | |
2609 (when comment | |
2610 (princ ";; Object ") | |
2611 (princ (object-name-string this)) | |
2612 (princ "\n") | |
2613 (princ comment) | |
2614 (princ "\n")) | |
2615 (let* ((cl (object-class this)) | |
2616 (cv (class-v cl))) | |
2617 ;; Now output readable lisp to recreate this object | |
2618 ;; It should look like this: | |
2619 ;; (<constructor> <name> <slot> <slot> ... ) | |
2620 ;; Each slot's slot is writen using its :writer. | |
2621 (princ (make-string (* eieio-print-depth 2) ? )) | |
2622 (princ "(") | |
2623 (princ (symbol-name (class-constructor (object-class this)))) | |
2624 (princ " \"") | |
2625 (princ (object-name-string this)) | |
2626 (princ "\"\n") | |
2627 ;; Loop over all the public slots | |
2628 (let ((publa (aref cv class-public-a)) | |
2629 (publd (aref cv class-public-d)) | |
2630 (publp (aref cv class-public-printer)) | |
2631 (eieio-print-depth (1+ eieio-print-depth))) | |
2632 (while publa | |
2633 (when (slot-boundp this (car publa)) | |
2634 (let ((i (class-slot-initarg cl (car publa))) | |
2635 (v (eieio-oref this (car publa))) | |
2636 ) | |
2637 (unless (or (not i) (equal v (car publd))) | |
2638 (princ (make-string (* eieio-print-depth 2) ? )) | |
2639 (princ (symbol-name i)) | |
2640 (princ " ") | |
2641 (if (car publp) | |
2642 ;; Use our public printer | |
2643 (funcall (car publp) v) | |
2644 ;; Use our generic override prin1 function. | |
2645 (eieio-override-prin1 v)) | |
2646 (princ "\n")))) | |
2647 (setq publa (cdr publa) publd (cdr publd) | |
2648 publp (cdr publp))) | |
2649 (princ (make-string (* eieio-print-depth 2) ? ))) | |
2650 (princ ")\n"))) | |
2651 | |
2652 (defun eieio-override-prin1 (thing) | |
2653 "Perform a prin1 on THING taking advantage of object knowledge." | |
2654 (cond ((eieio-object-p thing) | |
2655 (object-write thing)) | |
2656 ((listp thing) | |
2657 (eieio-list-prin1 thing)) | |
2658 ((class-p thing) | |
2659 (princ (class-name thing))) | |
2660 ((symbolp thing) | |
2661 (princ (concat "'" (symbol-name thing)))) | |
2662 (t (prin1 thing)))) | |
2663 | |
2664 (defun eieio-list-prin1 (list) | |
2665 "Display LIST where list may contain objects." | |
2666 (if (not (eieio-object-p (car list))) | |
2667 (progn | |
2668 (princ "'") | |
2669 (prin1 list)) | |
2670 (princ "(list ") | |
2671 (if (eieio-object-p (car list)) (princ "\n ")) | |
2672 (while list | |
2673 (if (eieio-object-p (car list)) | |
2674 (object-write (car list)) | |
2675 (princ "'") | |
2676 (prin1 (car list))) | |
2677 (princ " ") | |
2678 (setq list (cdr list))) | |
2679 (princ (make-string (* eieio-print-depth 2) ? )) | |
2680 (princ ")"))) | |
2681 | |
2682 | |
2683 ;;; Unimplemented functions from CLOS | |
2684 ;; | |
2685 (defun change-class (obj class) | |
2686 "Change the class of OBJ to type CLASS. | |
2687 This may create or delete slots, but does not affect the return value | |
2688 of `eq'." | |
2689 (error "Eieio: `change-class' is unimplemented")) | |
2690 | |
2691 ) | |
2692 | |
2693 | |
2694 ;;; Interfacing with edebug | |
2695 ;; | |
2696 (defun eieio-edebug-prin1-to-string (object &optional noescape) | |
2697 "Display eieio OBJECT in fancy format. Overrides the edebug default. | |
2698 Optional argument NOESCAPE is passed to `prin1-to-string' when appropriate." | |
2699 (cond ((class-p object) (class-name object)) | |
2700 ((eieio-object-p object) (object-print object)) | |
2701 ((and (listp object) (or (class-p (car object)) | |
2702 (eieio-object-p (car object)))) | |
2703 (concat "(" (mapconcat 'eieio-edebug-prin1-to-string object " ") ")")) | |
2704 (t (prin1-to-string object noescape)))) | |
2705 | |
2706 (add-hook 'edebug-setup-hook | |
2707 (lambda () | |
2708 (def-edebug-spec defmethod | |
2709 (&define ; this means we are defining something | |
2710 [&or name ("setf" :name setf name)] | |
2711 ;; ^^ This is the methods symbol | |
2712 [ &optional symbolp ] ; this is key :before etc | |
2713 list ; arguments | |
2714 [ &optional stringp ] ; documentation string | |
2715 def-body ; part to be debugged | |
2716 )) | |
2717 ;; The rest of the macros | |
2718 (def-edebug-spec oref (form quote)) | |
2719 (def-edebug-spec oref-default (form quote)) | |
2720 (def-edebug-spec oset (form quote form)) | |
2721 (def-edebug-spec oset-default (form quote form)) | |
2722 (def-edebug-spec class-v form) | |
2723 (def-edebug-spec class-p form) | |
2724 (def-edebug-spec eieio-object-p form) | |
2725 (def-edebug-spec class-constructor form) | |
2726 (def-edebug-spec generic-p form) | |
2727 (def-edebug-spec with-slots (list list def-body)) | |
2728 ;; I suspect this isn't the best way to do this, but when | |
2729 ;; cust-print was used on my system all my objects | |
2730 ;; appeared as "#1 =" which was not useful. This allows | |
2731 ;; edebug to print my objects in the nice way they were | |
2732 ;; meant to with `object-print' and `class-name' | |
2733 ;; (defalias 'edebug-prin1-to-string 'eieio-edebug-prin1-to-string) | |
2734 ) | |
2735 ) | |
2736 | |
2737 (eval-after-load "cedet-edebug" | |
2738 '(progn | |
2739 (cedet-edebug-add-print-override '(class-p object) '(class-name object) ) | |
2740 (cedet-edebug-add-print-override '(eieio-object-p object) '(object-print object) ) | |
2741 (cedet-edebug-add-print-override '(and (listp object) | |
2742 (or (class-p (car object)) (eieio-object-p (car object)))) | |
2743 '(cedet-edebug-prin1-recurse object) ) | |
2744 )) | |
2745 | |
2746 ;;; Interfacing with imenu in emacs lisp mode | |
2747 ;; (Only if the expression is defined) | |
2748 ;; | |
2749 (if (eval-when-compile (boundp 'list-imenu-generic-expression)) | |
2750 (progn | |
2751 | |
2752 (defun eieio-update-lisp-imenu-expression () | |
2753 "Examine `lisp-imenu-generic-expression' and modify it to find `defmethod'." | |
2754 (let ((exp lisp-imenu-generic-expression)) | |
2755 (while exp | |
2756 ;; it's of the form '( ( title expr indx ) ... ) | |
2757 (let* ((subcar (cdr (car exp))) | |
2758 (substr (car subcar))) | |
2759 (if (and (not (string-match "|method\\\\" substr)) | |
2760 (string-match "|advice\\\\" substr)) | |
2761 (setcar subcar | |
2762 (replace-match "|advice\\|method\\" t t substr 0)))) | |
2763 (setq exp (cdr exp))))) | |
2764 | |
2765 (eieio-update-lisp-imenu-expression) | |
2766 | |
2767 )) | |
2768 | |
2769 ;;; Autoloading some external symbols, and hooking into the help system | |
2770 ;; | |
2771 | |
2772 (autoload 'eieio-help-mode-augmentation-maybee "eieio-opt" "For buffers thrown into help mode, augment for eieio.") | |
2773 (autoload 'eieio-browse "eieio-opt" "Create an object browser window" t) | |
2774 (autoload 'eieio-describe-class "eieio-opt" "Describe CLASS defined by a string or symbol" t) | |
2775 (autoload 'eieio-describe-constructor "eieio-opt" "Describe the constructor function FCN." t) | |
2776 (autoload 'describe-class "eieio-opt" "Describe CLASS defined by a string or symbol" t) | |
2777 (autoload 'eieio-describe-generic "eieio-opt" "Describe GENERIC defined by a string or symbol" t) | |
2778 (autoload 'describe-generic "eieio-opt" "Describe GENERIC defined by a string or symbol" t) | |
2779 (autoload 'eieiodoc-class "eieio-doc" "Create texinfo documentation about a class hierarchy." t) | |
2780 | |
2781 (autoload 'customize-object "eieio-custom" "Create a custom buffer editing OBJ.") | |
2782 | |
2783 ;; make sure this shows up after the help mode hook. | |
2784 (add-hook 'temp-buffer-show-hook 'eieio-help-mode-augmentation-maybee t) | |
2785 ;; (require 'advice) | |
2786 ;; (defadvice describe-variable (around eieio-describe activate) | |
2787 ;; "Display the full documentation of FUNCTION (a symbol). | |
2788 ;; Returns the documentation as a string, also." | |
2789 ;; (if (class-p (ad-get-arg 0)) | |
2790 ;; (eieio-describe-class (ad-get-arg 0)) | |
2791 ;; ad-do-it)) | |
2792 | |
2793 ;; (defadvice describe-function (around eieio-describe activate) | |
2794 ;; "Display the full documentation of VARIABLE (a symbol). | |
2795 ;; Returns the documentation as a string, also." | |
2796 ;; (if (generic-p (ad-get-arg 0)) | |
2797 ;; (eieio-describe-generic (ad-get-arg 0)) | |
2798 ;; (if (class-p (ad-get-arg 0)) | |
2799 ;; (eieio-describe-constructor (ad-get-arg 0)) | |
2800 ;; ad-do-it))) | |
2801 | |
2802 (provide 'eieio) | |
2803 ;;; eieio ends here |