Mercurial > emacs
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 |