Mercurial > emacs
annotate lisp/emacs-lisp/pcase.el @ 110590:21047b3216d2
Don't break the build if we don't have the gnutls libraries.
author | Lars Magne Ingebrigtsen <larsi@gnus.org> |
---|---|
date | Sun, 26 Sep 2010 17:18:47 +0200 |
parents | b84898221ef1 |
children | ba4c4d4dddf5 |
rev | line source |
---|---|
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
1 ;;; pcase.el --- ML-style pattern-matching macro for Elisp |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
2 |
109743
d40bac543314
* lisp/emacs-lisp/pcase.el: Fix copyright header.
Glenn Morris <rgm@gnu.org>
parents:
109739
diff
changeset
|
3 ;; Copyright (C) 2010 Free Software Foundation, Inc. |
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
4 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
5 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca> |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
6 ;; Keywords: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
7 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
8 ;; This file is part of GNU Emacs. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
9 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
10 ;; GNU Emacs is free software: you can redistribute it and/or modify |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
11 ;; it under the terms of the GNU General Public License as published by |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
12 ;; the Free Software Foundation, either version 3 of the License, or |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
13 ;; (at your option) any later version. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
14 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
15 ;; GNU Emacs is distributed in the hope that it will be useful, |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
18 ;; GNU General Public License for more details. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
19 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
20 ;; You should have received a copy of the GNU General Public License |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
21 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
22 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
23 ;;; Commentary: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
24 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
25 ;; ML-style pattern matching. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
26 ;; The entry points are autoloaded. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
27 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
28 ;;; Code: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
29 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
30 (eval-when-compile (require 'cl)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
31 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
32 ;; Macro-expansion of pcase is reasonably fast, so it's not a problem |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
33 ;; when byte-compiling a file, but when interpreting the code, if the pcase |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
34 ;; is in a loop, the repeated macro-expansion becomes terribly costly, so we |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
35 ;; memoize previous macro expansions to try and avoid recomputing them |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
36 ;; over and over again. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
37 (defconst pcase-memoize (make-hash-table :weakness t :test 'equal)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
38 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
39 ;;;###autoload |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
40 (defmacro pcase (exp &rest cases) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
41 "Perform ML-style pattern matching on EXP. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
42 CASES is a list of elements of the form (UPATTERN CODE...). |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
43 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
44 UPatterns can take the following forms: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
45 _ matches anything. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
46 SYMBOL matches anything and binds it to SYMBOL. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
47 (or UPAT...) matches if any of the patterns matches. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
48 (and UPAT...) matches if all the patterns match. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
49 `QPAT matches if the QPattern QPAT matches. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
50 (pred PRED) matches if PRED applied to the object returns non-nil. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
51 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
52 QPatterns can take the following forms: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
53 (QPAT1 . QPAT2) matches if QPAT1 matches the car and QPAT2 the cdr. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
54 ,UPAT matches if the UPattern UPAT matches. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
55 ATOM matches if the object is `eq' to ATOM. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
56 QPatterns for vectors are not implemented yet. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
57 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
58 PRED can take the form |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
59 FUNCTION in which case it gets called with one argument. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
60 (FUN ARG1 .. ARGN) in which case it gets called with N+1 arguments. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
61 A PRED of the form FUNCTION is equivalent to one of the form (FUNCTION). |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
62 PRED patterns can refer to variables bound earlier in the pattern. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
63 E.g. you can match pairs where the cdr is larger than the car with a pattern |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
64 like `(,a . ,(pred (< a))) or, with more checks: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
65 `(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))" |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
66 (declare (indent 1) (debug case)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
67 (or (gethash (cons exp cases) pcase-memoize) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
68 (puthash (cons exp cases) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
69 (pcase-expand exp cases) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
70 pcase-memoize))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
71 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
72 ;;;###autoload |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
73 (defmacro pcase-let* (bindings body) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
74 "Like `let*' but where you can use `pcase' patterns for bindings. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
75 BODY should be an expression, and BINDINGS should be a list of bindings |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
76 of the form (UPAT EXP)." |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
77 (if (null bindings) body |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
78 `(pcase ,(cadr (car bindings)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
79 (,(caar bindings) (plet* ,(cdr bindings) ,body)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
80 (t (error "Pattern match failure in `plet'"))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
81 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
82 ;;;###autoload |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
83 (defmacro pcase-let (bindings body) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
84 "Like `let' but where you can use `pcase' patterns for bindings. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
85 BODY should be an expression, and BINDINGS should be a list of bindings |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
86 of the form (UPAT EXP)." |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
87 (if (null (cdr bindings)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
88 `(plet* ,bindings ,body) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
89 (setq bindings (mapcar (lambda (x) (cons (make-symbol "x") x)) bindings)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
90 `(let ,(mapcar (lambda (binding) (list (nth 0 binding) (nth 2 binding))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
91 bindings) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
92 (plet* ,(mapcar (lambda (binding) (list (nth 1 binding) (nth 0 binding))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
93 bindings) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
94 ,body)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
95 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
96 (defun pcase-expand (exp cases) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
97 (let* ((defs (if (symbolp exp) '() |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
98 (let ((sym (make-symbol "x"))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
99 (prog1 `((,sym ,exp)) (setq exp sym))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
100 (seen '()) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
101 (codegen |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
102 (lambda (code vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
103 (let ((prev (assq code seen))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
104 (if (not prev) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
105 (let ((res (pcase-codegen code vars))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
106 (push (list code vars res) seen) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
107 res) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
108 ;; Since we use a tree-based pattern matching |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
109 ;; technique, the leaves (the places that contain the |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
110 ;; code to run once a pattern is matched) can get |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
111 ;; copied a very large number of times, so to avoid |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
112 ;; code explosion, we need to keep track of how many |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
113 ;; times we've used each leaf and move it |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
114 ;; to a separate function if that number is too high. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
115 ;; |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
116 ;; We've already used this branch. So it is shared. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
117 (destructuring-bind (code prevvars res) prev |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
118 (unless (symbolp res) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
119 ;; This is the first repeat, so we have to move |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
120 ;; the branch to a separate function. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
121 (let ((bsym |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
122 (make-symbol (format "pcase-%d" (length defs))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
123 (push `(,bsym (lambda ,(mapcar #'car prevvars) ,@code)) defs) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
124 (setcar res 'funcall) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
125 (setcdr res (cons bsym (mapcar #'cdr prevvars))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
126 (setcar (cddr prev) bsym) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
127 (setq res bsym))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
128 (setq vars (copy-sequence vars)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
129 (let ((args (mapcar (lambda (pa) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
130 (let ((v (assq (car pa) vars))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
131 (setq vars (delq v vars)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
132 (cdr v))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
133 prevvars))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
134 (when vars ;New additional vars. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
135 (error "The vars %s are only bound in some paths" |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
136 (mapcar #'car vars))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
137 `(funcall ,res ,@args))))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
138 (main |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
139 (pcase-u |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
140 (mapcar (lambda (case) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
141 `((match ,exp . ,(car case)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
142 ,(apply-partially |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
143 (if (pcase-small-branch-p (cdr case)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
144 ;; Don't bother sharing multiple |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
145 ;; occurrences of this leaf since it's small. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
146 #'pcase-codegen codegen) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
147 (cdr case)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
148 cases)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
149 `(let ,defs ,main))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
150 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
151 (defun pcase-codegen (code vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
152 `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
153 ,@code)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
154 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
155 (defun pcase-small-branch-p (code) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
156 (and (= 1 (length code)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
157 (or (not (consp (car code))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
158 (let ((small t)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
159 (dolist (e (car code)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
160 (if (consp e) (setq small nil))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
161 small)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
162 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
163 ;; Try to use `cond' rather than a sequence of `if's, so as to reduce |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
164 ;; the depth of the generated tree. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
165 (defun pcase-if (test then else) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
166 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
167 ((eq else :pcase-dontcare) then) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
168 ((eq (car-safe else) 'if) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
169 `(cond (,test ,then) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
170 (,(nth 1 else) ,(nth 2 else)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
171 (t ,@(nthcdr 3 else)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
172 ((eq (car-safe else) 'cond) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
173 `(cond (,test ,then) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
174 ,@(cdr else))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
175 (t `(if ,test ,then ,else)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
176 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
177 (defun pcase-upat (qpattern) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
178 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
179 ((eq (car-safe qpattern) '\,) (cadr qpattern)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
180 (t (list '\` qpattern)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
181 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
182 ;; Note about MATCH: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
183 ;; When we have patterns like `(PAT1 . PAT2), after performing the `consp' |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
184 ;; check, we want to turn all the similar patterns into ones of the form |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
185 ;; (and (match car PAT1) (match cdr PAT2)), so you naturally need conjunction. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
186 ;; Earlier code hence used branches of the form (MATCHES . CODE) where |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
187 ;; MATCHES was a list (implicitly a conjunction) of (SYM . PAT). |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
188 ;; But if we have a pattern of the form (or `(PAT1 . PAT2) PAT3), there is |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
189 ;; no easy way to eliminate the `consp' check in such a representation. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
190 ;; So we replaced the MATCHES by the MATCH below which can be made up |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
191 ;; of conjunctions and disjunctions, so if we know `foo' is a cons, we can |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
192 ;; turn (match foo . (or `(PAT1 . PAT2) PAT3)) into |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
193 ;; (or (and (match car . `PAT1) (match cdr . `PAT2)) (match foo . PAT3)). |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
194 ;; The downside is that we now have `or' and `and' both in MATCH and |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
195 ;; in PAT, so there are different equivalent representations and we |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
196 ;; need to handle them all. We do not try to systematically |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
197 ;; canonicalize them to one form over another, but we do occasionally |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
198 ;; turn one into the other. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
199 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
200 (defun pcase-u (branches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
201 "Expand matcher for rules BRANCHES. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
202 Each BRANCH has the form (MATCH CODE . VARS) where |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
203 CODE is the code generator for that branch. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
204 VARS is the set of vars already bound by earlier matches. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
205 MATCH is the pattern that needs to be matched, of the form: |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
206 (match VAR . UPAT) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
207 (and MATCH ...) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
208 (or MATCH ...)" |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
209 (when (setq branches (delq nil branches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
210 (destructuring-bind (match code &rest vars) (car branches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
211 (pcase-u1 (list match) code vars (cdr branches))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
212 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
213 (defun pcase-and (match matches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
214 (if matches `(and ,match ,@matches) match)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
215 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
216 (defun pcase-split-match (sym splitter match) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
217 (case (car match) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
218 ((match) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
219 (if (not (eq sym (cadr match))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
220 (cons match match) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
221 (let ((pat (cddr match))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
222 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
223 ;; Hoist `or' and `and' patterns to `or' and `and' matches. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
224 ((memq (car-safe pat) '(or and)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
225 (pcase-split-match sym splitter |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
226 (cons (car pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
227 (mapcar (lambda (alt) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
228 `(match ,sym . ,alt)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
229 (cdr pat))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
230 (t (let ((res (funcall splitter (cddr match)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
231 (cons (or (car res) match) (or (cdr res) match)))))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
232 ((or and) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
233 (let ((then-alts '()) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
234 (else-alts '()) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
235 (neutral-elem (if (eq 'or (car match)) :pcase-fail :pcase-succeed)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
236 (zero-elem (if (eq 'or (car match)) :pcase-succeed :pcase-fail))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
237 (dolist (alt (cdr match)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
238 (let ((split (pcase-split-match sym splitter alt))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
239 (unless (eq (car split) neutral-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
240 (push (car split) then-alts)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
241 (unless (eq (cdr split) neutral-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
242 (push (cdr split) else-alts)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
243 (cons (cond ((memq zero-elem then-alts) zero-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
244 ((null then-alts) neutral-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
245 ((null (cdr then-alts)) (car then-alts)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
246 (t (cons (car match) (nreverse then-alts)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
247 (cond ((memq zero-elem else-alts) zero-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
248 ((null else-alts) neutral-elem) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
249 ((null (cdr else-alts)) (car else-alts)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
250 (t (cons (car match) (nreverse else-alts))))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
251 (t (error "Uknown MATCH %s" match)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
252 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
253 (defun pcase-split-rest (sym splitter rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
254 (let ((then-rest '()) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
255 (else-rest '())) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
256 (dolist (branch rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
257 (let* ((match (car branch)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
258 (code&vars (cdr branch)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
259 (splitted |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
260 (pcase-split-match sym splitter match))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
261 (unless (eq (car splitted) :pcase-fail) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
262 (push (cons (car splitted) code&vars) then-rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
263 (unless (eq (cdr splitted) :pcase-fail) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
264 (push (cons (cdr splitted) code&vars) else-rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
265 (cons (nreverse then-rest) (nreverse else-rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
266 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
267 (defun pcase-split-consp (syma symd pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
268 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
269 ;; A QPattern for a cons, can only go the `then' side. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
270 ((and (eq (car-safe pat) '\`) (consp (cadr pat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
271 (let ((qpat (cadr pat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
272 (cons `(and (match ,syma . ,(pcase-upat (car qpat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
273 (match ,symd . ,(pcase-upat (cdr qpat)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
274 :pcase-fail))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
275 ;; A QPattern but not for a cons, can only go the `else' side. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
276 ((eq (car-safe pat) '\`) (cons :pcase-fail nil)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
277 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
278 (defun pcase-split-eq (elem pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
279 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
280 ;; The same match will give the same result. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
281 ((and (eq (car-safe pat) '\`) (equal (cadr pat) elem)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
282 (cons :pcase-succeed :pcase-fail)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
283 ;; A different match will fail if this one succeeds. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
284 ((and (eq (car-safe pat) '\`) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
285 ;; (or (integerp (cadr pat)) (symbolp (cadr pat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
286 ;; (consp (cadr pat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
287 ) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
288 (cons :pcase-fail nil)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
289 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
290 (defun pcase-split-memq (elems pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
291 ;; Based on pcase-split-eq. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
292 (cond |
110087
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
293 ;; The same match will give the same result, but we don't know how |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
294 ;; to check it. |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
295 ;; (??? |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
296 ;; (cons :pcase-succeed nil)) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
297 ;; A match for one of the elements may succeed or fail. |
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
298 ((and (eq (car-safe pat) '\`) (member (cadr pat) elems)) |
110087
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
299 nil) |
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
300 ;; A different match will fail if this one succeeds. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
301 ((and (eq (car-safe pat) '\`) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
302 ;; (or (integerp (cadr pat)) (symbolp (cadr pat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
303 ;; (consp (cadr pat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
304 ) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
305 (cons :pcase-fail nil)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
306 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
307 (defun pcase-split-pred (upat pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
308 ;; FIXME: For predicates like (pred (> a)), two such predicates may |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
309 ;; actually refer to different variables `a'. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
310 (if (equal upat pat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
311 (cons :pcase-succeed :pcase-fail))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
312 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
313 (defun pcase-fgrep (vars sexp) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
314 "Check which of the symbols VARS appear in SEXP." |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
315 (let ((res '())) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
316 (while (consp sexp) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
317 (dolist (var (pcase-fgrep vars (pop sexp))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
318 (unless (memq var res) (push var res)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
319 (and (memq sexp vars) (not (memq sexp res)) (push sexp res)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
320 res)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
321 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
322 ;; It's very tempting to use `pcase' below, tho obviously, it'd create |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
323 ;; bootstrapping problems. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
324 (defun pcase-u1 (matches code vars rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
325 "Return code that runs CODE (with VARS) if MATCHES match. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
326 and otherwise defers to REST which is a list of branches of the form |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
327 \(ELSE-MATCH ELSE-CODE . ELSE-VARS)." |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
328 ;; Depending on the order in which we choose to check each of the MATCHES, |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
329 ;; the resulting tree may be smaller or bigger. So in general, we'd want |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
330 ;; to be careful to chose the "optimal" order. But predicate |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
331 ;; patterns make this harder because they create dependencies |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
332 ;; between matches. So we don't bother trying to reorder anything. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
333 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
334 ((null matches) (funcall code vars)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
335 ((eq :pcase-fail (car matches)) (pcase-u rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
336 ((eq :pcase-succeed (car matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
337 (pcase-u1 (cdr matches) code vars rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
338 ((eq 'and (caar matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
339 (pcase-u1 (append (cdar matches) (cdr matches)) code vars rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
340 ((eq 'or (caar matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
341 (let* ((alts (cdar matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
342 (var (if (eq (caar alts) 'match) (cadr (car alts)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
343 (simples '()) (others '())) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
344 (when var |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
345 (dolist (alt alts) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
346 (if (and (eq (car alt) 'match) (eq var (cadr alt)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
347 (let ((upat (cddr alt))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
348 (and (eq (car-safe upat) '\`) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
349 (or (integerp (cadr upat)) (symbolp (cadr upat)))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
350 (push (cddr alt) simples) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
351 (push alt others)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
352 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
353 ((null alts) (error "Please avoid it") (pcase-u rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
354 ((> (length simples) 1) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
355 ;; De-hoist the `or' MATCH into an `or' pattern that will be |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
356 ;; turned into a `memq' below. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
357 (pcase-u1 (cons `(match ,var or . ,(nreverse simples)) (cdr matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
358 code vars |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
359 (if (null others) rest |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
360 (cons (list* |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
361 (pcase-and (if (cdr others) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
362 (cons 'or (nreverse others)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
363 (car others)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
364 (cdr matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
365 code vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
366 rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
367 (t |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
368 (pcase-u1 (cons (pop alts) (cdr matches)) code vars |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
369 (if (null alts) (progn (error "Please avoid it") rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
370 (cons (list* |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
371 (pcase-and (if (cdr alts) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
372 (cons 'or alts) (car alts)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
373 (cdr matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
374 code vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
375 rest))))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
376 ((eq 'match (caar matches)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
377 (destructuring-bind (op sym &rest upat) (pop matches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
378 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
379 ((memq upat '(t _)) (pcase-u1 matches code vars rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
380 ((eq upat 'dontcare) :pcase-dontcare) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
381 ((functionp upat) (error "Feature removed, use (pred %s)" upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
382 ((eq (car-safe upat) 'pred) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
383 (destructuring-bind (then-rest &rest else-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
384 (pcase-split-rest |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
385 sym (apply-partially 'pcase-split-pred upat) rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
386 (pcase-if (if (symbolp (cadr upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
387 `(,(cadr upat) ,sym) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
388 (let* ((exp (cadr upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
389 ;; `vs' is an upper bound on the vars we need. |
110087
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
390 (vs (pcase-fgrep (mapcar #'car vars) exp)) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
391 (call (if (functionp exp) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
392 `(,exp ,sym) `(,@exp ,sym)))) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
393 (if (null vs) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
394 call |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
395 ;; Let's not replace `vars' in `exp' since it's |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
396 ;; too difficult to do it right, instead just |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
397 ;; let-bind `vars' around `exp'. |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
398 `(let ,(mapcar (lambda (var) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
399 (list var (cdr (assq var vars)))) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
400 vs) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
401 ;; FIXME: `vars' can capture `sym'. E.g. |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
402 ;; (pcase x ((and `(,x . ,y) (pred (fun x))))) |
b84898221ef1
* lisp/emacs-lisp/pcase.el (pcase-split-memq): Overenthusiastic optimisation.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
109743
diff
changeset
|
403 ,call)))) |
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
404 (pcase-u1 matches code vars then-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
405 (pcase-u else-rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
406 ((symbolp upat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
407 (pcase-u1 matches code (cons (cons upat sym) vars) rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
408 ((eq (car-safe upat) '\`) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
409 (pcase-q1 sym (cadr upat) matches code vars rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
410 ((eq (car-safe upat) 'or) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
411 (let ((all (> (length (cdr upat)) 1))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
412 (when all |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
413 (dolist (alt (cdr upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
414 (unless (and (eq (car-safe alt) '\`) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
415 (or (symbolp (cadr alt)) (integerp (cadr alt)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
416 (setq all nil)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
417 (if all |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
418 ;; Use memq for (or `a `b `c `d) rather than a big tree. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
419 (let ((elems (mapcar 'cadr (cdr upat)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
420 (destructuring-bind (then-rest &rest else-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
421 (pcase-split-rest |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
422 sym (apply-partially 'pcase-split-memq elems) rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
423 (pcase-if `(memq ,sym ',elems) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
424 (pcase-u1 matches code vars then-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
425 (pcase-u else-rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
426 (pcase-u1 (cons `(match ,sym ,@(cadr upat)) matches) code vars |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
427 (append (mapcar (lambda (upat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
428 `((and (match ,sym . ,upat) ,@matches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
429 ,code ,@vars)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
430 (cddr upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
431 rest))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
432 ((eq (car-safe upat) 'and) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
433 (pcase-u1 (append (mapcar (lambda (upat) `(match ,sym ,@upat)) (cdr upat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
434 matches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
435 code vars rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
436 ((eq (car-safe upat) 'not) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
437 ;; FIXME: The implementation below is naive and results in |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
438 ;; inefficient code. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
439 ;; To make it work right, we would need to turn pcase-u1's |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
440 ;; `code' and `vars' into a single argument of the same form as |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
441 ;; `rest'. We would also need to split this new `then-rest' argument |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
442 ;; for every test (currently we don't bother to do it since |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
443 ;; it's only useful for odd patterns like (and `(PAT1 . PAT2) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
444 ;; `(PAT3 . PAT4)) which the programmer can easily rewrite |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
445 ;; to the more efficient `(,(and PAT1 PAT3) . ,(and PAT2 PAT4))). |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
446 (pcase-u1 `((match ,sym . ,(cadr upat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
447 (lexical-let ((rest rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
448 ;; FIXME: This codegen is not careful to share its |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
449 ;; code if used several times: code blow up is likely. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
450 (lambda (vars) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
451 ;; `vars' will likely contain bindings which are |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
452 ;; not always available in other paths to |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
453 ;; `rest', so there' no point trying to pass |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
454 ;; them down. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
455 (pcase-u rest))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
456 vars |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
457 (list `((and . ,matches) ,code . ,vars)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
458 (t (error "Unknown upattern `%s'" upat))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
459 (t (error "Incorrect MATCH %s" (car matches))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
460 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
461 (defun pcase-q1 (sym qpat matches code vars rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
462 "Return code that runs CODE if SYM matches QPAT and if MATCHES match. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
463 and if not, defers to REST which is a list of branches of the form |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
464 \(OTHER_MATCH OTHER-CODE . OTHER-VARS)." |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
465 (cond |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
466 ((eq (car-safe qpat) '\,) (error "Can't use `,UPATTERN")) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
467 ((floatp qpat) (error "Floating point patterns not supported")) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
468 ((vectorp qpat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
469 ;; FIXME. |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
470 (error "Vector QPatterns not implemented yet")) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
471 ((consp qpat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
472 (let ((syma (make-symbol "xcar")) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
473 (symd (make-symbol "xcdr"))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
474 (destructuring-bind (then-rest &rest else-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
475 (pcase-split-rest sym (apply-partially 'pcase-split-consp syma symd) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
476 rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
477 (pcase-if `(consp ,sym) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
478 `(let ((,syma (car ,sym)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
479 (,symd (cdr ,sym))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
480 ,(pcase-u1 `((match ,syma . ,(pcase-upat (car qpat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
481 (match ,symd . ,(pcase-upat (cdr qpat))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
482 ,@matches) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
483 code vars then-rest)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
484 (pcase-u else-rest))))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
485 ((or (integerp qpat) (symbolp qpat)) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
486 (destructuring-bind (then-rest &rest else-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
487 (pcase-split-rest sym (apply-partially 'pcase-split-eq qpat) rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
488 (pcase-if `(eq ,sym ',qpat) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
489 (pcase-u1 matches code vars then-rest) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
490 (pcase-u else-rest)))) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
491 (t (error "Unkown QPattern %s" qpat)))) |
109743
d40bac543314
* lisp/emacs-lisp/pcase.el: Fix copyright header.
Glenn Morris <rgm@gnu.org>
parents:
109739
diff
changeset
|
492 |
109739
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
493 |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
494 (provide 'pcase) |
405e0ceb00e2
* lisp/emacs-lisp/pcase.el: New file.
Stefan Monnier <monnier@iro.umontreal.ca>
parents:
diff
changeset
|
495 ;;; pcase.el ends here |