update.
[elisp/apel.git] / calist.el
index 3c27b9f..22cb3ec 100644 (file)
--- a/calist.el
+++ b/calist.el
@@ -1,8 +1,10 @@
 ;;; calist.el --- Condition functions
 
-;; Copyright (C) 1998 MORIOKA Tomohiko.
+;; Copyright (C) 1998 Free Software Foundation, Inc.
+;; Copyright (C) 1999 Electrotechnical Laboratory, JAPAN.
+;; Licensed to the Free Software Foundation.
 
-;; Author: MORIOKA Tomohiko <morioka@jaist.ac.jp>
+;; Author: MORIOKA Tomohiko <tomo@m17n.org>
 ;; Keywords: condition, alist, tree
 
 ;; This file is part of APEL (A Portable Emacs Library).
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 ;;; Code:
 
 (eval-when-compile (require 'cl))
 
-(defvar calist-field-match-method-obarray [nil])
+(require 'alist)
+
+(defvar calist-package-alist nil)
+(defvar calist-field-match-method-obarray nil)
+
+(defun find-calist-package (name)
+  "Return a calist-package by NAME."
+  (cdr (assq name calist-package-alist)))
 
 (defun define-calist-field-match-method (field-type function)
   "Set field-match-method for FIELD-TYPE to FUNCTION."
   (fset (intern (symbol-name field-type) calist-field-match-method-obarray)
        function))
 
+(defun use-calist-package (name)
+  "Make the symbols of package NAME accessible in the current package."
+  (mapatoms (lambda (sym)
+             (if (intern-soft (symbol-name sym)
+                              calist-field-match-method-obarray)
+                 (signal 'conflict-of-calist-symbol
+                         (list (format "Conflict of symbol %s" sym)))
+               (if (fboundp sym)
+                   (define-calist-field-match-method
+                     sym (symbol-function sym))
+                 )))
+           (find-calist-package name)))
+
+(defun make-calist-package (name &optional use)
+  "Create a new calist-package."
+  (let ((calist-field-match-method-obarray (make-vector 7 0)))
+    (set-alist 'calist-package-alist name
+              calist-field-match-method-obarray)
+    (use-calist-package (or use 'standard))
+    calist-field-match-method-obarray))
+
+(defun in-calist-package (name)
+  "Set the current calist-package to a new or existing calist-package."
+  (setq calist-field-match-method-obarray
+       (or (find-calist-package name)
+           (make-calist-package name))))
+
+(in-calist-package 'standard)
+
 (defun calist-default-field-match-method (calist field-type field-value)
   (let ((s-field (assoc field-type calist)))
     (cond ((null s-field)
          ((equal (cdr s-field) field-value)
           calist))))
 
+(define-calist-field-match-method t (function calist-default-field-match-method))
+
 (defsubst calist-field-match-method (field-type)
-  (condition-case nil
-      (symbol-function
-       (intern-soft
-       (symbol-name field-type) calist-field-match-method-obarray))
-    (error (symbol-function 'calist-default-field-match-method))
-    ))
+  (symbol-function
+   (or (intern-soft (if (symbolp field-type)
+                       (symbol-name field-type)
+                     field-type)
+                   calist-field-match-method-obarray)
+       (intern-soft "t" calist-field-match-method-obarray))))
 
 (defsubst calist-field-match (calist field-type field-value)
   (funcall (calist-field-match-method field-type)
   (if (null rule-tree)
       alist
     (let ((type (car rule-tree))
-         (choices (cdr rule-tree)))
+         (choices (cdr rule-tree))
+         default)
       (catch 'tag
        (while choices
          (let* ((choice (car choices))
-                (ret-alist (calist-field-match alist type (car choice))))
-           (if ret-alist
-               (throw 'tag
-                      (if (cdr choice)
-                          (ctree-match-calist (cdr choice) ret-alist)
-                        ret-alist))))
-         (setq choices (cdr choices))))
-      )))
+                (choice-value (car choice)))
+           (if (eq choice-value t)
+               (setq default choice)
+             (let ((ret-alist (calist-field-match alist type (car choice))))
+               (if ret-alist
+                   (throw 'tag
+                          (if (cdr choice)
+                              (ctree-match-calist (cdr choice) ret-alist)
+                            ret-alist))
+                 ))))
+         (setq choices (cdr choices)))
+       (if default
+           (let ((ret-alist (calist-field-match alist type t)))
+             (if ret-alist
+                 (if (cdr default)
+                     (ctree-match-calist (cdr default) ret-alist)
+                   ret-alist))))
+       ))))
+
+(defun ctree-match-calist-partially (rule-tree alist)
+  "Return matched condition-alist if ALIST matches RULE-TREE."
+  (if (null rule-tree)
+      alist
+    (let ((type (car rule-tree))
+         (choices (cdr rule-tree))
+         default)
+      (catch 'tag
+       (while choices
+         (let* ((choice (car choices))
+                (choice-value (car choice)))
+           (if (eq choice-value t)
+               (setq default choice)
+             (let ((ret-alist (calist-field-match alist type (car choice))))
+               (if ret-alist
+                   (throw 'tag
+                          (if (cdr choice)
+                              (ctree-match-calist-partially
+                               (cdr choice) ret-alist)
+                            ret-alist))
+                 ))))
+         (setq choices (cdr choices)))
+       (if default
+           (let ((ret-alist (calist-field-match alist type t)))
+             (if ret-alist
+                 (if (cdr default)
+                     (ctree-match-calist-partially (cdr default) ret-alist)
+                   ret-alist)))
+         (calist-field-match alist type t))
+       ))))
+
+(defun ctree-find-calist (rule-tree alist &optional all)
+  "Return list of condition-alist which matches ALIST in RULE-TREE.
+If optional argument ALL is specified, default rules are not ignored
+even if other rules are matched for ALIST."
+  (if (null rule-tree)
+      (list alist)
+    (let ((type (car rule-tree))
+         (choices (cdr rule-tree))
+         default dest)
+      (while choices
+       (let* ((choice (car choices))
+              (choice-value (car choice)))
+         (if (eq choice-value t)
+             (setq default choice)
+           (let ((ret-alist (calist-field-match alist type (car choice))))
+             (if ret-alist
+                 (if (cdr choice)
+                     (let ((ret (ctree-find-calist
+                                 (cdr choice) ret-alist all)))
+                       (while ret
+                         (let ((elt (car ret)))
+                           (or (member elt dest)
+                               (setq dest (cons elt dest))
+                               ))
+                         (setq ret (cdr ret))
+                         ))
+                   (or (member ret-alist dest)
+                       (setq dest (cons ret-alist dest)))
+                   )))))
+       (setq choices (cdr choices)))
+      (or (and (not all) dest)
+         (if default
+             (let ((ret-alist (calist-field-match alist type t)))
+               (if ret-alist
+                   (if (cdr default)
+                       (let ((ret (ctree-find-calist
+                                   (cdr default) ret-alist all)))
+                         (while ret
+                           (let ((elt (car ret)))
+                             (or (member elt dest)
+                                 (setq dest (cons elt dest))
+                                 ))
+                           (setq ret (cdr ret))
+                           ))
+                     (or (member ret-alist dest)
+                         (setq dest (cons ret-alist dest)))
+                     ))))
+         )
+      dest)))
 
 (defun calist-to-ctree (calist)
   "Convert condition-alist CALIST to condition-tree."
                (type (car cell))
                (value (cdr cell)))
           (cons type
-                (list '(t)
+                (list (list t)
                       (cons value (calist-to-ctree (cdr calist)))))
           ))
        (t
                                         (delete ret (copy-alist calist)))
                                        ))))
                   (setq values (cdr values)))
-                (setcdr ctree (list* '(t)
-                                     (cons (cdr ret)
-                                           (calist-to-ctree
-                                            (delete ret (copy-alist calist))))
-                                     (cdr ctree)))
-                )
+                (if (assq t (cdr ctree))
+                    (setcdr ctree
+                            (cons (cons (cdr ret)
+                                        (calist-to-ctree
+                                         (delete ret (copy-alist calist))))
+                                  (cdr ctree)))
+                  (setcdr ctree
+                          (list* (list t)
+                                 (cons (cdr ret)
+                                       (calist-to-ctree
+                                        (delete ret (copy-alist calist))))
+                                 (cdr ctree)))
+                  ))
             (catch 'tag
               (while values
                 (let ((cell (car values)))
                           (ctree-add-calist-with-default (cdr cell) calist))
                   )
                 (setq values (cdr values)))
-              (let ((elt (cons t (calist-to-ctree calist))))
-                (or (member elt (cdr ctree))
-                    (setcdr ctree (cons elt (cdr ctree)))
-                    )))
+              (let ((cell (assq t (cdr ctree))))
+                (if cell
+                    (setcdr cell
+                            (ctree-add-calist-with-default (cdr cell)
+                                                           calist))
+                  (let ((elt (cons t (calist-to-ctree calist))))
+                    (or (member elt (cdr ctree))
+                        (setcdr ctree (cons elt (cdr ctree)))
+                        ))
+                  )))
             )
           ctree))))
 
 ;;; @ end
 ;;;
 
-(provide 'calist)
+(require 'product)
+(product-provide (provide 'calist) (require 'apel-ver))
 
 ;;; calist.el ends here