comparison lisp/emacs-lisp/eieio.el @ 105547:eff4c06fb1e2

* emacs-lisp/eieio.el: Avoid requiring cl at runtime. (eieio-defclass): Apply deftype handler and setf-method properties directly. (eieio-add-new-slot): Avoid union function from cl library. (eieio--typep): New function. (eieio-perform-slot-validation): Use it.
author Chong Yidong <cyd@stupidchicken.com>
date Sun, 11 Oct 2009 02:19:27 +0000
parents 0a64442c10e3
children 1d1d5d9bd884
comparison
equal deleted inserted replaced
105546:2ee9eaa0490b 105547:eff4c06fb1e2
38 ;; @TODO - fix :initform to be a form, not a quoted value 38 ;; @TODO - fix :initform to be a form, not a quoted value
39 ;; @TODO - Prefix non-clos functions with `eieio-'. 39 ;; @TODO - Prefix non-clos functions with `eieio-'.
40 40
41 ;;; Code: 41 ;;; Code:
42 42
43 (require 'cl) 43 (eval-when-compile
44 (eval-when-compile (require 'eieio-comp)) 44 (require 'cl)
45 (require 'eieio-comp))
45 46
46 (defvar eieio-version "1.2" 47 (defvar eieio-version "1.2"
47 "Current version of EIEIO.") 48 "Current version of EIEIO.")
48 49
49 (defun eieio-version () 50 (defun eieio-version ()
536 ;; important for EIEIO to be backwards compatible, where 537 ;; important for EIEIO to be backwards compatible, where
537 ;; myobject-p, and myobject-child-p are different. 538 ;; myobject-p, and myobject-child-p are different.
538 ;; "cl" uses this technique to specify symbols with specific typep 539 ;; "cl" uses this technique to specify symbols with specific typep
539 ;; test, so we can let typep have the CLOS documented behavior 540 ;; test, so we can let typep have the CLOS documented behavior
540 ;; while keeping our above predicate clean. 541 ;; while keeping our above predicate clean.
541 (eval `(deftype ,cname () 542
542 '(satisfies 543 ;; It would be cleaner to use `defsetf' here, but that requires cl
543 ,(intern (concat (symbol-name cname) "-child-p"))))) 544 ;; at runtime.
544 545 (put cname 'cl-deftype-handler
545 ) 546 (list 'lambda () `(list 'satisfies (quote ,csym)))))
546 547
547 ;; before adding new slots, lets add all the methods and classes 548 ;; before adding new slots, lets add all the methods and classes
548 ;; in from the parent class 549 ;; in from the parent class
549 (eieio-copy-parents-into-subclass newc superclasses) 550 (eieio-copy-parents-into-subclass newc superclasses)
550 551
655 "Retrieves the slot `%s' from an object of class `%s'" 656 "Retrieves the slot `%s' from an object of class `%s'"
656 name cname) 657 name cname)
657 (list 'if (list 'slot-boundp 'this (list 'quote name)) 658 (list 'if (list 'slot-boundp 'this (list 'quote name))
658 (list 'eieio-oref 'this (list 'quote name)) 659 (list 'eieio-oref 'this (list 'quote name))
659 ;; Else - Some error? nil? 660 ;; Else - Some error? nil?
660 nil 661 nil)))
661 ))) 662
662 ;; Thanks Pascal Bourguignon <pjb@informatimago.com> 663 ;; Provide a setf method. It would be cleaner to use
663 ;; For this complex macro. 664 ;; defsetf, but that would require CL at runtime.
664 (eval (macroexpand 665 (put acces 'setf-method
665 (list 'defsetf acces '(widget) '(store) 666 `(lambda (widget)
666 (list 'list ''eieio-oset 'widget 667 (let* ((--widget-sym-- (make-symbol "--widget--"))
667 (list 'quote (list 'quote name)) 'store)))) 668 (--store-sym-- (make-symbol "--store--")))
668 ;;`(defsetf ,acces (widget) (store) (eieio-oset widget ',cname store)) 669 (list
669 ) 670 (list --widget-sym--)
670 ) 671 (list widget)
672 (list --store-sym--)
673 (list 'eieio-oset --widget-sym-- '',name --store-sym--)
674 (list 'getfoo --widget-sym--)))))))
675
671 ;; If a writer is defined, then create a generic method of that 676 ;; If a writer is defined, then create a generic method of that
672 ;; name whose purpose is to set the value of the slot. 677 ;; name whose purpose is to set the value of the slot.
673 (if writer 678 (if writer
674 (progn 679 (progn
675 (eieio-defmethod writer 680 (eieio-defmethod writer
893 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'" 898 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
894 prot super-prot a))) 899 prot super-prot a)))
895 ;; End original PLN 900 ;; End original PLN
896 901
897 ;; PLN Tue Jun 26 11:57:06 2007 : 902 ;; PLN Tue Jun 26 11:57:06 2007 :
898 ;; We do a non redundant combination of ancient 903 ;; Do a non redundant combination of ancient custom
899 ;; custom groups and new ones using the common lisp 904 ;; groups and new ones.
900 ;; `union' method.
901 (when custg 905 (when custg
902 (let ((where-groups 906 (let* ((groups
903 (nthcdr num (aref newc class-public-custom-group)))) 907 (nthcdr num (aref newc class-public-custom-group)))
904 (setcar where-groups 908 (list1 (car groups))
905 (union (car where-groups) 909 (list2 (if (listp custg) custg (list custg))))
906 (if (listp custg) custg (list custg)))))) 910 (if (< (length list1) (length list2))
911 (setq list1 (prog1 list2 (setq list2 list1))))
912 (dolist (elt list2)
913 (unless (memq elt list1)
914 (push elt list1)))
915 (setcar groups list1)))
907 ;; End PLN 916 ;; End PLN
908 917
909 ;; PLN Mon Jun 25 22:44:34 2007 : If a new cust is 918 ;; PLN Mon Jun 25 22:44:34 2007 : If a new cust is
910 ;; set, simply replaces the old one. 919 ;; set, simply replaces the old one.
911 (when cust 920 (when cust
988 (let ((super-prot 997 (let ((super-prot
989 (car (nthcdr num (aref newc class-class-allocation-protection))))) 998 (car (nthcdr num (aref newc class-class-allocation-protection)))))
990 (if (not (eq prot super-prot)) 999 (if (not (eq prot super-prot))
991 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'" 1000 (error "Child slot protection `%s' does not match inherited protection `%s' for `%s'"
992 prot super-prot a))) 1001 prot super-prot a)))
993 ;; We do a non redundant combination of ancient 1002 ;; Do a non redundant combination of ancient custom groups
994 ;; custom groups and new ones using the common lisp 1003 ;; and new ones.
995 ;; `union' method.
996 (when custg 1004 (when custg
997 (let ((where-groups 1005 (let* ((groups
998 (nthcdr num (aref newc class-class-allocation-custom-group)))) 1006 (nthcdr num (aref newc class-class-allocation-custom-group)))
999 (setcar where-groups 1007 (list1 (car groups))
1000 (union (car where-groups) 1008 (list2 (if (listp custg) custg (list custg))))
1001 (if (listp custg) custg (list custg)))))) 1009 (if (< (length list1) (length list2))
1002 ;; End PLN 1010 (setq list1 (prog1 list2 (setq list2 list1))))
1011 (dolist (elt list2)
1012 (unless (memq elt list1)
1013 (push elt list1)))
1014 (setcar groups list1)))
1003 1015
1004 ;; PLN Sat Jun 30 17:24:42 2007 : when a new 1016 ;; PLN Sat Jun 30 17:24:42 2007 : when a new
1005 ;; doc is specified, simply replaces the old one. 1017 ;; doc is specified, simply replaces the old one.
1006 (when doc 1018 (when doc
1007 ;;(message "Documentation redefined to %s" doc) 1019 ;;(message "Documentation redefined to %s" doc)
1350 (eieio-defgeneric-reset-generic-form method))) 1362 (eieio-defgeneric-reset-generic-form method)))
1351 1363
1352 method) 1364 method)
1353 1365
1354 ;;; Slot type validation 1366 ;;; Slot type validation
1355 ;; 1367
1368 ;; This is a hideous hack for replacing `typep' from cl-macs, to avoid
1369 ;; requiring the CL library at run-time. It can be eliminated if/when
1370 ;; `typep' is merged into Emacs core.
1371 (defun eieio--typep (val type)
1372 (if (symbolp type)
1373 (cond ((get type 'cl-deftype-handler)
1374 (eieio--typep val (funcall (get type 'cl-deftype-handler))))
1375 ((eq type t) t)
1376 ((eq type 'null) (null val))
1377 ((eq type 'atom) (atom val))
1378 ((eq type 'float) (and (numberp val) (not (integerp val))))
1379 ((eq type 'real) (numberp val))
1380 ((eq type 'fixnum) (integerp val))
1381 ((memq type '(character string-char)) (characterp val))
1382 (t
1383 (let* ((name (symbol-name type))
1384 (namep (intern (concat name "p"))))
1385 (if (fboundp namep)
1386 (funcall `(lambda () (,namep val)))
1387 (funcall `(lambda ()
1388 (,(intern (concat name "-p")) val)))))))
1389 (cond ((get (car type) 'cl-deftype-handler)
1390 (eieio--typep val (apply (get (car type) 'cl-deftype-handler)
1391 (cdr type))))
1392 ((memq (car type) '(integer float real number))
1393 (and (eieio--typep val (car type))
1394 (or (memq (cadr type) '(* nil))
1395 (if (consp (cadr type))
1396 (> val (car (cadr type)))
1397 (>= val (cadr type))))
1398 (or (memq (caddr type) '(* nil))
1399 (if (consp (car (cddr type)))
1400 (< val (caar (cddr type)))
1401 (<= val (car (cddr type)))))))
1402 ((memq (car type) '(and or not))
1403 (eval (cons (car type)
1404 (mapcar (lambda (x)
1405 `(eieio--typep (quote ,val) (quote ,x)))
1406 (cdr type)))))
1407 ((memq (car type) '(member member*))
1408 (memql val (cdr type)))
1409 ((eq (car type) 'satisfies)
1410 (funcall `(lambda () (,(cadr type) val))))
1411 (t (error "Bad type spec: %s" type)))))
1412
1356 (defun eieio-perform-slot-validation (spec value) 1413 (defun eieio-perform-slot-validation (spec value)
1357 "Return non-nil if SPEC does not match VALUE." 1414 "Return non-nil if SPEC does not match VALUE."
1358 ;; typep is in cl-macs
1359 (or (eq spec t) ; t always passes 1415 (or (eq spec t) ; t always passes
1360 (eq value eieio-unbound) ; unbound always passes 1416 (eq value eieio-unbound) ; unbound always passes
1361 (typep value spec))) 1417 (eieio--typep value spec)))
1362 1418
1363 (defun eieio-validate-slot-value (class slot-idx value slot) 1419 (defun eieio-validate-slot-value (class slot-idx value slot)
1364 "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid. 1420 "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid.
1365 Checks the :type specifier. 1421 Checks the :type specifier.
1366 SLOT is the slot that is being checked, and is only used when throwing 1422 SLOT is the slot that is being checked, and is only used when throwing
2381 (defsetf slot-value (obj slot) (store) (list 'eieio-oset obj slot store)) 2437 (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)) 2438 (defsetf eieio-oref (obj slot) (store) (list 'eieio-oset obj slot store))
2383 2439
2384 ;; The below setf method was written by Arnd Kohrs <kohrs@acm.org> 2440 ;; The below setf method was written by Arnd Kohrs <kohrs@acm.org>
2385 (define-setf-method oref (obj slot) 2441 (define-setf-method oref (obj slot)
2386 (let ((obj-temp (gensym)) 2442 (with-no-warnings
2387 (slot-temp (gensym)) 2443 (require 'cl)
2388 (store-temp (gensym))) 2444 (let ((obj-temp (gensym))
2389 (list (list obj-temp slot-temp) 2445 (slot-temp (gensym))
2390 (list obj `(quote ,slot)) 2446 (store-temp (gensym)))
2391 (list store-temp) 2447 (list (list obj-temp slot-temp)
2392 (list 'set-slot-value obj-temp slot-temp 2448 (list obj `(quote ,slot))
2393 store-temp) 2449 (list store-temp)
2394 (list 'slot-value obj-temp slot-temp)))) 2450 (list 'set-slot-value obj-temp slot-temp
2451 store-temp)
2452 (list 'slot-value obj-temp slot-temp)))))
2395 2453
2396 2454
2397 ;;; 2455 ;;;
2398 ;; We want all objects created by EIEIO to have some default set of 2456 ;; We want all objects created by EIEIO to have some default set of
2399 ;; behaviours so we can create object utilities, and allow various 2457 ;; behaviours so we can create object utilities, and allow various
2766 2824
2767 (autoload 'customize-object "eieio-custom" "Create a custom buffer editing OBJ.") 2825 (autoload 'customize-object "eieio-custom" "Create a custom buffer editing OBJ.")
2768 2826
2769 (provide 'eieio) 2827 (provide 'eieio)
2770 2828
2771 ;; Local variables:
2772 ;; byte-compile-warnings: (not cl-functions)
2773 ;; End:
2774
2775 ;; arch-tag: c1aeab9c-2938-41a3-842b-1a38bd26e9f2 2829 ;; arch-tag: c1aeab9c-2938-41a3-842b-1a38bd26e9f2
2776 ;;; eieio ends here 2830 ;;; eieio ends here