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