X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=luna.el;h=e66d26575e0f9f81864f25ec017c9f9a8fc785de;hb=f3019a9f4a7d1479d0f46cd61c24125acc277e3d;hp=776698c761949167aacd856f5e0bd22c8735dc0a;hpb=e816c5788cd92bf409dde6d58778462789ad38a6;p=elisp%2Fflim.git diff --git a/luna.el b/luna.el index 776698c..e66d265 100644 --- a/luna.el +++ b/luna.el @@ -1,6 +1,7 @@ ;;; luna.el --- tiny OOP system kernel ;; Copyright (C) 1999 Electrotechnical Laboratory, JAPAN. +;; Licensed to the Free Software Foundation. ;; Author: MORIOKA Tomohiko ;; Keywords: OOP @@ -24,6 +25,17 @@ ;;; Code: +(eval-when-compile (require 'cl)) + +(eval-when-compile (require 'static)) + +(static-condition-case nil + :symbol-for-testing-whether-colon-keyword-is-available-or-not + (void-variable + (defconst :before ':before) + (defconst :after ':after) + (defconst :around ':around))) + (defmacro luna-find-class (name) "Return the luna-class of the given NAME." `(get ,name 'luna-class)) @@ -34,6 +46,9 @@ (defmacro luna-class-obarray (class) `(aref ,class 1)) +(defmacro luna-class-parents (class) + `(aref ,class 2)) + (defmacro luna-class-number-of-slots (class) `(aref ,class 3)) @@ -42,70 +57,56 @@ If PARENTS is specified, TYPE inherits PARENTS. Each parent must be name of luna-class (symbol). If SLOTS is specified, TYPE will be defined to have them." + `(luna-define-class-function ',type ',(append parents '(standard-object)) + ',slots)) + +(defun luna-define-class-function (type &optional parents slots) + (static-condition-case nil + :symbol-for-testing-whether-colon-keyword-is-available-or-not + (void-variable + (let (key) + (dolist (slot slots) + (setq key (intern (format ":%s" slot))) + (set key key))))) (let ((oa (make-vector 31 0)) (rest parents) parent name - (i 2)) + (i 2) + b j) (while rest - (setq parent (pop rest)) + (setq parent (pop rest) + b (- i 2)) (mapatoms (lambda (sym) - (when (get sym 'luna-member-index) + (when (setq j (get sym 'luna-slot-index)) (setq name (symbol-name sym)) (unless (intern-soft name oa) - (put (intern name oa) 'luna-member-index i) + (put (intern name oa) 'luna-slot-index (+ j b)) (setq i (1+ i)) ))) - (luna-class-obarray parent)) + (luna-class-obarray (luna-find-class parent))) ) (setq rest slots) (while rest (setq name (symbol-name (pop rest))) (unless (intern-soft name oa) - (put (intern name oa) 'luna-member-index i) + (put (intern name oa) 'luna-slot-index i) (setq i (1+ i)) )) - `(luna-set-class ',type - (vector 'class ,oa ,parents ,i)) + (luna-set-class type (vector 'class oa parents i)) )) -(defmacro luna-class-name (entity) - "Return class-name of the ENTITY." - `(aref ,entity 0)) - -(defmacro luna-set-class-name (entity name) - `(aset ,entity 0 ,name)) - -(defmacro luna-get-obarray (entity) - `(aref ,entity 1)) - -(defmacro luna-set-obarray (entity obarray) - `(aset ,entity 1 ,obarray)) - -(defmacro luna-make-entity (type &rest init-args) - "Make instance of luna-class TYPE and return it. -If INIT-ARGS is specified, it is used as initial values of the slots. -It must be plist and each slot name must have prefix `:'." - `(apply #'luna-make-entity-function ',type ',init-args)) - -(defsubst luna-make-entity-function (type &rest init-args) - (let* ((c (get type 'luna-class)) - (v (make-vector (luna-class-number-of-slots c) nil)) - (oa (luna-class-obarray c)) - s i) - (luna-set-class-name v type) - (luna-set-obarray v (make-vector 7 0)) - (while init-args - (setq s (intern-soft (substring (symbol-name (pop init-args)) 1) oa) - i (pop init-args)) - (if s - (aset v (get s 'luna-member-index) i) - )) - v)) - -(defsubst luna-class-find-member (class member-name) +(defun luna-class-find-member (class member-name) (or (stringp member-name) (setq member-name (symbol-name member-name))) - (intern-soft member-name (luna-class-obarray class))) + (or (intern-soft member-name (luna-class-obarray class)) + (let ((parents (luna-class-parents class)) + ret) + (while (and parents + (null + (setq ret (luna-class-find-member + (luna-find-class (pop parents)) + member-name))))) + ret))) (defsubst luna-class-find-or-make-member (class member-name) (or (stringp member-name) @@ -113,45 +114,166 @@ It must be plist and each slot name must have prefix `:'." (intern member-name (luna-class-obarray class))) (defmacro luna-class-slot-index (class slot-name) - `(get (luna-class-find-member ,class ,slot-name) 'luna-member-index)) + `(get (luna-class-find-member ,class ,slot-name) 'luna-slot-index)) (defmacro luna-slot-index (entity slot-name) `(luna-class-slot-index (luna-find-class (luna-class-name ,entity)) ,slot-name)) -(defsubst luna-slot-value (entity slot-name) - "Return value of SLOT-NAME of ENTITY." - (aref entity (luna-slot-index entity slot-name))) +(defsubst luna-slot-value (entity slot) + "Return the value of SLOT of ENTITY." + (aref entity (luna-slot-index entity slot))) + +(defsubst luna-set-slot-value (entity slot value) + "Store VALUE into SLOT of ENTITY." + (aset entity (luna-slot-index entity slot) value)) + +(defmacro luna-define-method (name &rest definition) + "Define NAME as a method function of a class. -(defmacro luna-define-method (name args &rest body) - "Define NAME as a method function of (nth 1 (car ARGS)) backend. +Usage of this macro follows: -ARGS is like an argument list of lambda, but (car ARGS) must be -specialized parameter. (car (car ARGS)) is name of variable and (nth -1 (car ARGS)) is name of backend." - (let* ((specializer (car args)) - (class (nth 1 specializer)) - (self (car specializer))) + (luna-define-method NAME [METHOD-QUALIFIER] ARGLIST [DOCSTRING] BODY...) + +NAME is the name of method. + +Optional argument METHOD-QUALIFIER must be :before, :after or :around. +If it is :before / :after, the method is called before / after a +method of parent class is finished. ARGLIST is like an argument list +of lambda, but (car ARGLIST) must be specialized parameter. (car (car +ARGLIST)) is name of variable and \(nth 1 (car ARGLIST)) is name of +class. + +Optional argument DOCSTRING is the documentation of method. + +BODY is the body of method." + (let ((method-qualifier (pop definition)) + args specializer class self) + (if (memq method-qualifier '(:before :after :around)) + (setq args (pop definition)) + (setq args method-qualifier + method-qualifier nil) + ) + (setq specializer (car args) + class (nth 1 specializer) + self (car specializer)) `(let ((func (lambda ,(if self (cons self (cdr args)) (cdr args)) - ,@body))) - (fset (luna-class-find-or-make-member (luna-find-class ',class) ',name) - func)))) + ,@definition)) + (sym (luna-class-find-or-make-member + (luna-find-class ',class) ',name))) + (fset sym func) + (put sym 'luna-method-qualifier ,method-qualifier) + ))) (put 'luna-define-method 'lisp-indent-function 'defun) -(defmacro luna-class-find-function (class service) - `(symbol-function (luna-class-find-member ,class ,service))) +(def-edebug-spec luna-define-method + (&define name [&optional &or ":before" ":after" ":around"] + ((arg symbolp) + [&rest arg] + [&optional ["&optional" arg &rest arg]] + &optional ["&rest" arg] + ) + def-body)) + +(defun luna-class-find-parents-functions (class service) + (let ((parents (luna-class-parents class)) + ret) + (while (and parents + (null + (setq ret (luna-class-find-functions + (luna-find-class (pop parents)) + service))))) + ret)) + +(defun luna-class-find-functions (class service) + (let ((sym (luna-class-find-member class service))) + (if (fboundp sym) + (cond ((eq (get sym 'luna-method-qualifier) :before) + (cons (symbol-function sym) + (luna-class-find-parents-functions class service)) + ) + ((eq (get sym 'luna-method-qualifier) :after) + (nconc (luna-class-find-parents-functions class service) + (list (symbol-function sym))) + ) + ((eq (get sym 'luna-method-qualifier) :around) + (cons sym (luna-class-find-parents-functions class service)) + ) + (t + (list (symbol-function sym)) + )) + (luna-class-find-parents-functions class service) + ))) + +(defmacro luna-find-functions (entity service) + `(luna-class-find-functions (luna-find-class (luna-class-name ,entity)) + ,service)) + +(defsubst luna-send (entity message &rest luna-current-method-arguments) + "Send MESSAGE to ENTITY, and return the result. +LUNA-CURRENT-METHOD-ARGUMENTS is arguments of the MESSAGE." + (let ((luna-next-methods (luna-find-functions entity message)) + luna-current-method + luna-previous-return-value) + (while (and luna-next-methods + (progn + (setq luna-current-method (pop luna-next-methods) + luna-previous-return-value + (apply luna-current-method + luna-current-method-arguments)) + (if (symbolp luna-current-method) + (not (eq (get luna-current-method + 'luna-method-qualifier) :around)) + t)))) + luna-previous-return-value)) + +(eval-when-compile + (defvar luna-next-methods nil) + (defvar luna-current-method-arguments nil) + ) + +(defun luna-call-next-method () + "Call the next method in a method with :around qualifier." + (let (luna-current-method + luna-previous-return-value) + (while (and luna-next-methods + (progn + (setq luna-current-method (pop luna-next-methods) + luna-previous-return-value + (apply luna-current-method + luna-current-method-arguments)) + (if (symbolp luna-current-method) + (not (eq (get luna-current-method + 'luna-method-qualifier) :around)) + t)))) + luna-previous-return-value)) -(defmacro luna-find-function (entity service) - `(luna-class-find-function (luna-find-class (luna-class-name ,entity)) - ,service)) +(defmacro luna-class-name (entity) + "Return class-name of the ENTITY." + `(aref ,entity 0)) -(defsubst luna-send (entity message &rest args) - "Send MESSAGE to ENTITY with ARGS, and return the result." - (apply (luna-find-function entity message) - entity args)) +(defmacro luna-set-class-name (entity name) + `(aset ,entity 0 ,name)) + +(defmacro luna-get-obarray (entity) + `(aref ,entity 1)) + +(defmacro luna-set-obarray (entity obarray) + `(aset ,entity 1 ,obarray)) + +(defun luna-make-entity (type &rest init-args) + "Make instance of luna-class TYPE and return it. +If INIT-ARGS is specified, it is used as initial values of the slots. +It must be plist and each slot name must have prefix `:'." + (let* ((c (get type 'luna-class)) + (v (make-vector (luna-class-number-of-slots c) nil))) + (luna-set-class-name v type) + (luna-set-obarray v (make-vector 7 0)) + (apply #'luna-send v 'initialize-instance v init-args) + )) (defsubst luna-arglist-to-arguments (arglist) (let (dest) @@ -170,15 +292,65 @@ ARGS is argument of and DOC is DOC-string." `(defun ,(intern (symbol-name name)) ,args ,doc (luna-send ,(car args) ',name - ,@(luna-arglist-to-arguments (cdr args))) + ,@(luna-arglist-to-arguments args)) ) `(defun ,(intern (symbol-name name)) ,args (luna-send ,(car args) ',name - ,@(luna-arglist-to-arguments (cdr args))) + ,@(luna-arglist-to-arguments args)) ))) (put 'luna-define-generic 'lisp-indent-function 'defun) +(defun luna-define-internal-accessors (class-name) + "Define internal accessors for an entity of CLASS-NAME." + (let ((entity-class (luna-find-class class-name)) + parents parent-class) + (mapatoms + (lambda (slot) + (if (luna-class-slot-index entity-class slot) + (catch 'derived + (setq parents (luna-class-parents entity-class)) + (while parents + (setq parent-class (luna-find-class (car parents))) + (if (luna-class-slot-index parent-class slot) + (throw 'derived nil)) + (setq parents (cdr parents)) + ) + (eval + `(progn + (defmacro ,(intern (format "%s-%s-internal" + class-name slot)) + (entity) + (list 'aref entity + ,(luna-class-slot-index entity-class + (intern (symbol-name slot))) + )) + (defmacro ,(intern (format "%s-set-%s-internal" + class-name slot)) + (entity value) + (list 'aset entity + ,(luna-class-slot-index + entity-class (intern (symbol-name slot))) + value)) + )) + ))) + (luna-class-obarray entity-class)))) + +(luna-define-class-function 'standard-object) + +(luna-define-method initialize-instance ((entity standard-object) + &rest init-args) + (let* ((c (luna-find-class (luna-class-name entity))) + (oa (luna-class-obarray c)) + s i) + (while init-args + (setq s (intern-soft (substring (symbol-name (pop init-args)) 1) oa) + i (pop init-args)) + (if s + (aset entity (get s 'luna-slot-index) i) + )) + entity)) + ;;; @ end ;;;