annotate lisp/emacs-lisp/pcase.el @ 110258:1af4bf1c3af4

gnus-async.el (gnus-async-article-callback): Always prefetch images for groups that want that.
author Katsumi Yamaoka <yamaoka@jpl.org>
date Tue, 07 Sep 2010 00:05:59 +0000
parents b84898221ef1
children ba4c4d4dddf5
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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