]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/emacs-lisp/pcase.el (pcase-defmacro): New macro.
authorStefan Monnier <monnier@iro.umontreal.ca>
Mon, 22 Sep 2014 15:04:12 +0000 (11:04 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Mon, 22 Sep 2014 15:04:12 +0000 (11:04 -0400)
(pcase--macroexpand): New function.
(pcase--expand): Use it.

etc/NEWS
lisp/ChangeLog
lisp/emacs-lisp/pcase.el

index cbad7c5b54b5e8a36152422ca516ec8df895504c..397b8866f6b52c761a8fa2725f2ff098b4c2fd07 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -104,6 +104,7 @@ performance improvements when pasting large amounts of text.
 
 ** pcase
 *** New UPatterns `quote' and `app'.
+*** New UPatterns can be defined with `pcase-defmacro'.
 
 ** Lisp mode
 *** Strings after `:documentation' are highlighted as docstrings.
index 1aad2004d6ad05ad5531174adb20860fe20b5b97..32843569edad7cc38293f395972b9e48225b06ba 100644 (file)
@@ -1,5 +1,9 @@
 2014-09-22  Stefan Monnier  <monnier@iro.umontreal.ca>
 
+       * emacs-lisp/pcase.el (pcase-defmacro): New macro.
+       (pcase--macroexpand): New function.
+       (pcase--expand): Use it.
+
        Add support for `quote' and `app'.
        * emacs-lisp/pcase.el (pcase--app-subst-match, pcase--app-subst-rest):
        New optimization functions.
index fbe241b6fc85cc6375074d8d8d9ddb41b2da0ef5..2d5f19fe5f7c659fd79d1d8be3d6d3c79a19fc5d 100644 (file)
@@ -284,7 +284,7 @@ of the form (UPAT EXP)."
            (main
             (pcase--u
              (mapcar (lambda (case)
-                       `((match ,val . ,(car case))
+                       `((match ,val . ,(pcase--macroexpand (car case)))
                          ,(lambda (vars)
                             (unless (memq case used-cases)
                               ;; Keep track of the cases that are used.
@@ -303,6 +303,31 @@ of the form (UPAT EXP)."
           (message "Redundant pcase pattern: %S" (car case))))
       (macroexp-let* defs main))))
 
+(defun pcase--macroexpand (pat)
+  "Expands all macro-patterns in PAT."
+  (let ((head (car-safe pat)))
+    (cond
+     ((memq head '(nil pred guard quote)) pat)
+     ((memq head '(or and)) `(,head ,@(mapcar #'pcase--macroexpand (cdr pat))))
+     ((eq head 'let) `(let ,(pcase--macroexpand (cadr pat)) ,@(cddr pat)))
+     ((eq head 'app) `(app ,(nth 1 pat) ,(pcase--macroexpand (nth 2 pat))))
+     (t
+      (let* ((expander (get head 'pcase-macroexpander))
+             (npat (if expander (apply expander (cdr pat)))))
+        (if (null npat)
+            (error (if expander
+                       "Unexpandable %s pattern: %S"
+                     "Unknown %s pattern: %S")
+                   head pat)
+          (pcase--macroexpand npat)))))))
+
+;;;###autoload
+(defmacro pcase-defmacro (name args &rest body)
+  "Define a pcase UPattern macro."
+  (declare (indent 2) (debug (def-name sexp def-body)) (doc-string 3))
+  `(put ',name 'pcase-macroexpander
+        (lambda ,args ,@body)))
+
 (defun pcase-codegen (code vars)
   ;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding
   ;; let* which might prevent the setcar/setcdr in pcase--expand's fancy