summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp/eieio.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2015-03-23 18:24:30 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2015-03-23 18:24:30 -0400
commitae277259b1cf8d913893417e4ca284040f5a543f (patch)
tree42d607424f8666780abe25fd49d9664abd13d81f /lisp/emacs-lisp/eieio.el
parent1b5c411e6a4dffd6a8dec9846da0d1650a85b879 (diff)
downloademacs-ae277259b1cf8d913893417e4ca284040f5a543f.tar.gz
Add new `cl-struct' and `eieio' pcase patterns.
* lisp/emacs-lisp/cl-macs.el (cl-struct): New pcase pattern. * lisp/emacs-lisp/eieio.el (eieio-pcase-slot-index-table) (eieio-pcase-slot-index-from-index-table): New functions. (eieio): New pcase pattern. * lisp/emacs-lisp/pcase.el (pcase--make-docstring): New function. (pcase): Use it to build the docstring. (pcase-defmacro): Make sure the macro is lazy-loaded. (\`): Move its docstring from `pcase'.
Diffstat (limited to 'lisp/emacs-lisp/eieio.el')
-rw-r--r--lisp/emacs-lisp/eieio.el38
1 files changed, 38 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 8d76df874e5..27725148ff6 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -328,6 +328,44 @@ variable name of the same name as the slot."
(list var `(slot-value ,object ',slot))))
spec-list)
,@body)))
+
+;; Keep it as a non-inlined function, so the internals of object don't get
+;; hard-coded in random .elc files.
+(defun eieio-pcase-slot-index-table (obj)
+ "Return some data structure from which can be extracted the slot offset."
+ (eieio--class-index-table
+ (symbol-value (eieio--object-class-tag obj))))
+
+(defun eieio-pcase-slot-index-from-index-table (index-table slot)
+ "Find the index to pass to `aref' to access SLOT."
+ (let ((index (gethash slot index-table)))
+ (if index (+ (eval-when-compile
+ (length (cl-struct-slot-info 'eieio--object)))
+ index))))
+
+(pcase-defmacro eieio (&rest fields)
+ "Pcase patterns to match EIEIO objects.
+Elements of FIELDS can be of the form (NAME UPAT) in which case the contents of
+field NAME is matched against UPAT, or they can be of the form NAME which
+is a shorthand for (NAME NAME)."
+ (let ((is (make-symbol "table")))
+ ;; FIXME: This generates a horrendous mess of redundant let bindings.
+ ;; `pcase' needs to be improved somehow to introduce let-bindings more
+ ;; sparingly, or the byte-compiler needs to be taught to optimize
+ ;; them away.
+ ;; FIXME: `pcase' does not do a good job here of sharing tests&code among
+ ;; various branches.
+ `(and (pred eieio-object-p)
+ (app eieio-pcase-slot-index-table ,is)
+ ,@(mapcar (lambda (field)
+ (let* ((name (if (consp field) (car field) field))
+ (pat (if (consp field) (cadr field) field))
+ (i (make-symbol "index")))
+ `(and (let (and ,i (pred natnump))
+ (eieio-pcase-slot-index-from-index-table
+ ,is ',name))
+ (app (pcase--flip aref ,i) ,pat))))
+ fields))))
;;; Simple generators, and query functions. None of these would do
;; well embedded into an object.