* lisp/emacs-lisp/pcase.el (pcase--let*): New function.
[bpt/emacs.git] / lisp / emacs-lisp / pcase.el
CommitLineData
513749ee 1;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t; coding: utf-8 -*-
d02c9bcd 2
acaf905b 3;; Copyright (C) 2010-2012 Free Software Foundation, Inc.
d02c9bcd
SM
4
5;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
ca3afb79 6;; Keywords:
d02c9bcd
SM
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;; ML-style pattern matching.
26;; The entry points are autoloaded.
27
dcc029e0
SM
28;; Todo:
29
ca105506
SM
30;; - (pcase e (`(,x . ,x) foo)) signals an "x unused" warning if `foo' doesn't
31;; use x, because x is bound separately for the equality constraint
32;; (as well as any pred/guard) and for the body, so uses at one place don't
33;; count for the other.
dcc029e0
SM
34;; - provide ways to extend the set of primitives, with some kind of
35;; define-pcase-matcher. We could easily make it so that (guard BOOLEXP)
36;; could be defined this way, as a shorthand for (pred (lambda (_) BOOLEXP)).
37;; But better would be if we could define new ways to match by having the
872ab164 38;; extension provide its own `pcase--split-<foo>' thingy.
ca105506 39;; - along these lines, provide patterns to match CL structs.
1f0816b6
SM
40;; - provide something like (setq VAR) so a var can be set rather than
41;; let-bound.
a179e3f7
SM
42;; - provide a way to fallthrough to subsequent cases (not sure what I meant by
43;; this :-()
1f0816b6 44;; - try and be more clever to reduce the size of the decision tree, and
ca105506 45;; to reduce the number of leaves that need to be turned into function:
1f0816b6 46;; - first, do the tests shared by all remaining branches (it will have
a179e3f7 47;; to be performed anyway, so better do it first so it's shared).
1f0816b6 48;; - then choose the test that discriminates more (?).
a179e3f7
SM
49;; - provide Agda's `with' (along with its `...' companion).
50;; - implement (not UPAT). This might require a significant redesign.
dcc029e0
SM
51;; - ideally we'd want (pcase s ((re RE1) E1) ((re RE2) E2)) to be able to
52;; generate a lex-style DFA to decide whether to run E1 or E2.
53
d02c9bcd
SM
54;;; Code:
55
4dd1c416
SM
56(require 'macroexp)
57
d02c9bcd
SM
58;; Macro-expansion of pcase is reasonably fast, so it's not a problem
59;; when byte-compiling a file, but when interpreting the code, if the pcase
60;; is in a loop, the repeated macro-expansion becomes terribly costly, so we
61;; memoize previous macro expansions to try and avoid recomputing them
62;; over and over again.
e2abe5a1 63(defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq))
82ad98e3
SM
64;; (defconst pcase--memoize-1 (make-hash-table :test 'eq))
65;; (defconst pcase--memoize-2 (make-hash-table :weakness 'key :test 'equal))
d02c9bcd 66
872ab164
SM
67(defconst pcase--dontcare-upats '(t _ dontcare))
68
d02c9bcd
SM
69;;;###autoload
70(defmacro pcase (exp &rest cases)
71 "Perform ML-style pattern matching on EXP.
72CASES is a list of elements of the form (UPATTERN CODE...).
73
74UPatterns can take the following forms:
75 _ matches anything.
76 SYMBOL matches anything and binds it to SYMBOL.
77 (or UPAT...) matches if any of the patterns matches.
78 (and UPAT...) matches if all the patterns match.
79 `QPAT matches if the QPattern QPAT matches.
80 (pred PRED) matches if PRED applied to the object returns non-nil.
dcc029e0 81 (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil.
ca105506 82 (let UPAT EXP) matches if EXP matches UPAT.
f9d554dd
SM
83If a SYMBOL is used twice in the same pattern (i.e. the pattern is
84\"non-linear\"), then the second occurrence is turned into an `eq'uality test.
d02c9bcd
SM
85
86QPatterns can take the following forms:
87 (QPAT1 . QPAT2) matches if QPAT1 matches the car and QPAT2 the cdr.
88 ,UPAT matches if the UPattern UPAT matches.
ca3afb79 89 STRING matches if the object is `equal' to STRING.
d02c9bcd
SM
90 ATOM matches if the object is `eq' to ATOM.
91QPatterns for vectors are not implemented yet.
92
93PRED can take the form
ca3afb79 94 FUNCTION in which case it gets called with one argument.
d02c9bcd
SM
95 (FUN ARG1 .. ARGN) in which case it gets called with N+1 arguments.
96A PRED of the form FUNCTION is equivalent to one of the form (FUNCTION).
97PRED patterns can refer to variables bound earlier in the pattern.
98E.g. you can match pairs where the cdr is larger than the car with a pattern
99like `(,a . ,(pred (< a))) or, with more checks:
100`(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))"
4dd1c416 101 (declare (indent 1) (debug cl-case)) ;FIXME: edebug `guard' and vars.
e2abe5a1
SM
102 ;; We want to use a weak hash table as a cache, but the key will unavoidably
103 ;; be based on `exp' and `cases', yet `cases' is a fresh new list each time
104 ;; we're called so it'll be immediately GC'd. So we use (car cases) as key
105 ;; which does come straight from the source code and should hence not be GC'd
106 ;; so easily.
107 (let ((data (gethash (car cases) pcase--memoize)))
108 ;; data = (EXP CASES . EXPANSION)
109 (if (and (equal exp (car data)) (equal cases (cadr data)))
110 ;; We have the right expansion.
111 (cddr data)
82ad98e3
SM
112 ;; (when (gethash (car cases) pcase--memoize-1)
113 ;; (message "pcase-memoize failed because of weak key!!"))
114 ;; (when (gethash (car cases) pcase--memoize-2)
115 ;; (message "pcase-memoize failed because of eq test on %S"
116 ;; (car cases)))
e2abe5a1
SM
117 (when data
118 (message "pcase-memoize: equal first branch, yet different"))
119 (let ((expansion (pcase--expand exp cases)))
82ad98e3
SM
120 (puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize)
121 ;; (puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize-1)
122 ;; (puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize-2)
e2abe5a1 123 expansion))))
d02c9bcd 124
82ad98e3
SM
125(defun pcase--let* (bindings body)
126 (cond
127 ((null bindings) (macroexp-progn body))
128 ((pcase--trivial-upat-p (caar bindings))
129 (macroexp-let* `(,(car bindings)) (pcase--let* (cdr bindings) body)))
130 (t
131 (let ((binding (pop bindings)))
132 (pcase--expand
133 (cadr binding)
134 `((,(car binding) ,(pcase--let* bindings body))
135 ;; We can either signal an error here, or just use `dontcare' which
136 ;; generates more efficient code. In practice, if we use `dontcare'
137 ;; we will still often get an error and the few cases where we don't
138 ;; do not matter that much, so it's a better choice.
139 (dontcare nil)))))))
140
d02c9bcd 141;;;###autoload
872ab164 142(defmacro pcase-let* (bindings &rest body)
d02c9bcd
SM
143 "Like `let*' but where you can use `pcase' patterns for bindings.
144BODY should be an expression, and BINDINGS should be a list of bindings
145of the form (UPAT EXP)."
c41045e6 146 (declare (indent 1)
82ad98e3
SM
147 (debug ((&rest (sexp &optional form)) body)))
148 (let ((cached (gethash bindings pcase--memoize)))
149 ;; cached = (BODY . EXPANSION)
150 (if (equal (car cached) body)
151 (cdr cached)
152 (let ((expansion (pcase--let* bindings body)))
153 (puthash bindings (cons body expansion) pcase--memoize)
154 expansion))))
d02c9bcd
SM
155
156;;;###autoload
872ab164 157(defmacro pcase-let (bindings &rest body)
d02c9bcd 158 "Like `let' but where you can use `pcase' patterns for bindings.
872ab164 159BODY should be a list of expressions, and BINDINGS should be a list of bindings
d02c9bcd 160of the form (UPAT EXP)."
c41045e6 161 (declare (indent 1) (debug pcase-let*))
d02c9bcd 162 (if (null (cdr bindings))
872ab164
SM
163 `(pcase-let* ,bindings ,@body)
164 (let ((matches '()))
165 (dolist (binding (prog1 bindings (setq bindings nil)))
166 (cond
167 ((memq (car binding) pcase--dontcare-upats)
168 (push (cons (make-symbol "_") (cdr binding)) bindings))
169 ((pcase--trivial-upat-p (car binding)) (push binding bindings))
170 (t
171 (let ((tmpvar (make-symbol (format "x%d" (length bindings)))))
172 (push (cons tmpvar (cdr binding)) bindings)
173 (push (list (car binding) tmpvar) matches)))))
174 `(let ,(nreverse bindings) (pcase-let* ,matches ,@body)))))
175
176(defmacro pcase-dolist (spec &rest body)
5342bb06 177 (declare (indent 1))
872ab164
SM
178 (if (pcase--trivial-upat-p (car spec))
179 `(dolist ,spec ,@body)
180 (let ((tmpvar (make-symbol "x")))
181 `(dolist (,tmpvar ,@(cdr spec))
182 (pcase-let* ((,(car spec) ,tmpvar))
183 ,@body)))))
184
185
186(defun pcase--trivial-upat-p (upat)
187 (and (symbolp upat) (not (memq upat pcase--dontcare-upats))))
188
189(defun pcase--expand (exp cases)
e2abe5a1
SM
190 ;; (message "pid=%S (pcase--expand %S ...hash=%S)"
191 ;; (emacs-pid) exp (sxhash cases))
82ad98e3
SM
192 (macroexp-let² macroexp-copyable-p val exp
193 (let* ((defs ())
194 (seen '())
195 (codegen
196 (lambda (code vars)
197 (let ((prev (assq code seen)))
198 (if (not prev)
199 (let ((res (pcase-codegen code vars)))
200 (push (list code vars res) seen)
201 res)
202 ;; Since we use a tree-based pattern matching
203 ;; technique, the leaves (the places that contain the
204 ;; code to run once a pattern is matched) can get
205 ;; copied a very large number of times, so to avoid
206 ;; code explosion, we need to keep track of how many
207 ;; times we've used each leaf and move it
208 ;; to a separate function if that number is too high.
209 ;;
210 ;; We've already used this branch. So it is shared.
211 (let* ((code (car prev)) (cdrprev (cdr prev))
212 (prevvars (car cdrprev)) (cddrprev (cdr cdrprev))
213 (res (car cddrprev)))
214 (unless (symbolp res)
215 ;; This is the first repeat, so we have to move
216 ;; the branch to a separate function.
217 (let ((bsym
218 (make-symbol (format "pcase-%d" (length defs)))))
219 (push `(,bsym (lambda ,(mapcar #'car prevvars) ,@code)) defs)
220 (setcar res 'funcall)
221 (setcdr res (cons bsym (mapcar #'cdr prevvars)))
222 (setcar (cddr prev) bsym)
223 (setq res bsym)))
224 (setq vars (copy-sequence vars))
225 (let ((args (mapcar (lambda (pa)
226 (let ((v (assq (car pa) vars)))
227 (setq vars (delq v vars))
228 (cdr v)))
229 prevvars)))
230 ;; If some of `vars' were not found in `prevvars', that's
231 ;; OK it just means those vars aren't present in all
232 ;; branches, so they can be used within the pattern
233 ;; (e.g. by a `guard/let/pred') but not in the branch.
234 ;; FIXME: But if some of `prevvars' are not in `vars' we
235 ;; should remove them from `prevvars'!
236 `(funcall ,res ,@args)))))))
237 (main
238 (pcase--u
239 (mapcar (lambda (case)
240 `((match ,val . ,(car case))
241 ,(apply-partially
242 (if (pcase--small-branch-p (cdr case))
243 ;; Don't bother sharing multiple
244 ;; occurrences of this leaf since it's small.
245 #'pcase-codegen codegen)
246 (cdr case))))
247 cases))))
4dd1c416 248 (macroexp-let* defs main))))
d02c9bcd
SM
249
250(defun pcase-codegen (code vars)
4dd1c416 251 ;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding
6876a58d
SM
252 ;; let* which might prevent the setcar/setcdr in pcase--expand's fancy
253 ;; codegen from later metamorphosing this let into a funcall.
254 `(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars)
d02c9bcd
SM
255 ,@code))
256
872ab164 257(defun pcase--small-branch-p (code)
d02c9bcd
SM
258 (and (= 1 (length code))
259 (or (not (consp (car code)))
260 (let ((small t))
261 (dolist (e (car code))
262 (if (consp e) (setq small nil)))
263 small))))
264
265;; Try to use `cond' rather than a sequence of `if's, so as to reduce
266;; the depth of the generated tree.
872ab164 267(defun pcase--if (test then else)
d02c9bcd 268 (cond
872ab164 269 ((eq else :pcase--dontcare) then)
1f0816b6 270 ((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen?
4dd1c416 271 (t (macroexp-if test then else))))
5342bb06 272
872ab164 273(defun pcase--upat (qpattern)
d02c9bcd
SM
274 (cond
275 ((eq (car-safe qpattern) '\,) (cadr qpattern))
276 (t (list '\` qpattern))))
277
278;; Note about MATCH:
279;; When we have patterns like `(PAT1 . PAT2), after performing the `consp'
280;; check, we want to turn all the similar patterns into ones of the form
281;; (and (match car PAT1) (match cdr PAT2)), so you naturally need conjunction.
282;; Earlier code hence used branches of the form (MATCHES . CODE) where
283;; MATCHES was a list (implicitly a conjunction) of (SYM . PAT).
284;; But if we have a pattern of the form (or `(PAT1 . PAT2) PAT3), there is
285;; no easy way to eliminate the `consp' check in such a representation.
286;; So we replaced the MATCHES by the MATCH below which can be made up
287;; of conjunctions and disjunctions, so if we know `foo' is a cons, we can
288;; turn (match foo . (or `(PAT1 . PAT2) PAT3)) into
289;; (or (and (match car . `PAT1) (match cdr . `PAT2)) (match foo . PAT3)).
290;; The downside is that we now have `or' and `and' both in MATCH and
291;; in PAT, so there are different equivalent representations and we
292;; need to handle them all. We do not try to systematically
293;; canonicalize them to one form over another, but we do occasionally
294;; turn one into the other.
295
872ab164 296(defun pcase--u (branches)
d02c9bcd
SM
297 "Expand matcher for rules BRANCHES.
298Each BRANCH has the form (MATCH CODE . VARS) where
299CODE is the code generator for that branch.
300VARS is the set of vars already bound by earlier matches.
301MATCH is the pattern that needs to be matched, of the form:
302 (match VAR . UPAT)
303 (and MATCH ...)
304 (or MATCH ...)"
305 (when (setq branches (delq nil branches))
9a05edc4
SM
306 (let* ((carbranch (car branches))
307 (match (car carbranch)) (cdarbranch (cdr carbranch))
308 (code (car cdarbranch))
309 (vars (cdr cdarbranch)))
872ab164 310 (pcase--u1 (list match) code vars (cdr branches)))))
d02c9bcd 311
872ab164 312(defun pcase--and (match matches)
d02c9bcd
SM
313 (if matches `(and ,match ,@matches) match))
314
1f0816b6
SM
315(defconst pcase-mutually-exclusive-predicates
316 '((symbolp . integerp)
317 (symbolp . numberp)
318 (symbolp . consp)
319 (symbolp . arrayp)
320 (symbolp . stringp)
ca105506 321 (symbolp . byte-code-function-p)
1f0816b6
SM
322 (integerp . consp)
323 (integerp . arrayp)
324 (integerp . stringp)
ca105506 325 (integerp . byte-code-function-p)
1f0816b6
SM
326 (numberp . consp)
327 (numberp . arrayp)
328 (numberp . stringp)
ca105506 329 (numberp . byte-code-function-p)
1f0816b6
SM
330 (consp . arrayp)
331 (consp . stringp)
ca105506
SM
332 (consp . byte-code-function-p)
333 (arrayp . stringp)
334 (arrayp . byte-code-function-p)
335 (stringp . byte-code-function-p)))
1f0816b6 336
872ab164 337(defun pcase--split-match (sym splitter match)
9a05edc4
SM
338 (cond
339 ((eq (car match) 'match)
d02c9bcd
SM
340 (if (not (eq sym (cadr match)))
341 (cons match match)
342 (let ((pat (cddr match)))
343 (cond
344 ;; Hoist `or' and `and' patterns to `or' and `and' matches.
345 ((memq (car-safe pat) '(or and))
872ab164
SM
346 (pcase--split-match sym splitter
347 (cons (car pat)
348 (mapcar (lambda (alt)
349 `(match ,sym . ,alt))
350 (cdr pat)))))
d02c9bcd
SM
351 (t (let ((res (funcall splitter (cddr match))))
352 (cons (or (car res) match) (or (cdr res) match))))))))
9a05edc4 353 ((memq (car match) '(or and))
d02c9bcd
SM
354 (let ((then-alts '())
355 (else-alts '())
872ab164
SM
356 (neutral-elem (if (eq 'or (car match))
357 :pcase--fail :pcase--succeed))
358 (zero-elem (if (eq 'or (car match)) :pcase--succeed :pcase--fail)))
d02c9bcd 359 (dolist (alt (cdr match))
872ab164 360 (let ((split (pcase--split-match sym splitter alt)))
d02c9bcd
SM
361 (unless (eq (car split) neutral-elem)
362 (push (car split) then-alts))
363 (unless (eq (cdr split) neutral-elem)
364 (push (cdr split) else-alts))))
365 (cons (cond ((memq zero-elem then-alts) zero-elem)
366 ((null then-alts) neutral-elem)
367 ((null (cdr then-alts)) (car then-alts))
368 (t (cons (car match) (nreverse then-alts))))
369 (cond ((memq zero-elem else-alts) zero-elem)
370 ((null else-alts) neutral-elem)
371 ((null (cdr else-alts)) (car else-alts))
372 (t (cons (car match) (nreverse else-alts)))))))
373 (t (error "Uknown MATCH %s" match))))
374
872ab164 375(defun pcase--split-rest (sym splitter rest)
d02c9bcd
SM
376 (let ((then-rest '())
377 (else-rest '()))
378 (dolist (branch rest)
379 (let* ((match (car branch))
380 (code&vars (cdr branch))
bbd240ce 381 (split
872ab164 382 (pcase--split-match sym splitter match)))
bbd240ce
PE
383 (unless (eq (car split) :pcase--fail)
384 (push (cons (car split) code&vars) then-rest))
385 (unless (eq (cdr split) :pcase--fail)
386 (push (cons (cdr split) code&vars) else-rest))))
d02c9bcd
SM
387 (cons (nreverse then-rest) (nreverse else-rest))))
388
872ab164 389(defun pcase--split-consp (syma symd pat)
d02c9bcd
SM
390 (cond
391 ;; A QPattern for a cons, can only go the `then' side.
392 ((and (eq (car-safe pat) '\`) (consp (cadr pat)))
393 (let ((qpat (cadr pat)))
872ab164
SM
394 (cons `(and (match ,syma . ,(pcase--upat (car qpat)))
395 (match ,symd . ,(pcase--upat (cdr qpat))))
396 :pcase--fail)))
1f0816b6
SM
397 ;; A QPattern but not for a cons, can only go to the `else' side.
398 ((eq (car-safe pat) '\`) (cons :pcase--fail nil))
399 ((and (eq (car-safe pat) 'pred)
400 (or (member (cons 'consp (cadr pat))
401 pcase-mutually-exclusive-predicates)
402 (member (cons (cadr pat) 'consp)
403 pcase-mutually-exclusive-predicates)))
404 (cons :pcase--fail nil))))
d02c9bcd 405
872ab164 406(defun pcase--split-equal (elem pat)
d02c9bcd
SM
407 (cond
408 ;; The same match will give the same result.
409 ((and (eq (car-safe pat) '\`) (equal (cadr pat) elem))
872ab164 410 (cons :pcase--succeed :pcase--fail))
d02c9bcd
SM
411 ;; A different match will fail if this one succeeds.
412 ((and (eq (car-safe pat) '\`)
413 ;; (or (integerp (cadr pat)) (symbolp (cadr pat))
414 ;; (consp (cadr pat)))
415 )
1f0816b6
SM
416 (cons :pcase--fail nil))
417 ((and (eq (car-safe pat) 'pred)
418 (symbolp (cadr pat))
419 (get (cadr pat) 'side-effect-free)
420 (funcall (cadr pat) elem))
421 (cons :pcase--succeed nil))))
d02c9bcd 422
872ab164
SM
423(defun pcase--split-member (elems pat)
424 ;; Based on pcase--split-equal.
d02c9bcd 425 (cond
dcc029e0
SM
426 ;; The same match (or a match of membership in a superset) will
427 ;; give the same result, but we don't know how to check it.
4de81ee0 428 ;; (???
872ab164 429 ;; (cons :pcase--succeed nil))
4de81ee0 430 ;; A match for one of the elements may succeed or fail.
d02c9bcd 431 ((and (eq (car-safe pat) '\`) (member (cadr pat) elems))
4de81ee0 432 nil)
d02c9bcd
SM
433 ;; A different match will fail if this one succeeds.
434 ((and (eq (car-safe pat) '\`)
435 ;; (or (integerp (cadr pat)) (symbolp (cadr pat))
436 ;; (consp (cadr pat)))
437 )
1f0816b6
SM
438 (cons :pcase--fail nil))
439 ((and (eq (car-safe pat) 'pred)
440 (symbolp (cadr pat))
441 (get (cadr pat) 'side-effect-free)
442 (let ((p (cadr pat)) (all t))
443 (dolist (elem elems)
444 (unless (funcall p elem) (setq all nil)))
445 all))
446 (cons :pcase--succeed nil))))
d02c9bcd 447
872ab164 448(defun pcase--split-pred (upat pat)
d02c9bcd
SM
449 ;; FIXME: For predicates like (pred (> a)), two such predicates may
450 ;; actually refer to different variables `a'.
5342bb06
SM
451 (let (test)
452 (cond
453 ((equal upat pat) (cons :pcase--succeed :pcase--fail))
454 ((and (eq 'pred (car upat))
455 (eq 'pred (car-safe pat))
456 (or (member (cons (cadr upat) (cadr pat))
457 pcase-mutually-exclusive-predicates)
458 (member (cons (cadr pat) (cadr upat))
459 pcase-mutually-exclusive-predicates)))
460 (cons :pcase--fail nil))
461 ((and (eq 'pred (car upat))
462 (eq '\` (car-safe pat))
463 (symbolp (cadr upat))
464 (or (symbolp (cadr pat)) (stringp (cadr pat)) (numberp (cadr pat)))
465 (get (cadr upat) 'side-effect-free)
466 (ignore-errors
467 (setq test (list (funcall (cadr upat) (cadr pat))))))
468 (if (car test)
469 (cons nil :pcase--fail)
470 (cons :pcase--fail nil))))))
d02c9bcd 471
872ab164 472(defun pcase--fgrep (vars sexp)
d02c9bcd
SM
473 "Check which of the symbols VARS appear in SEXP."
474 (let ((res '()))
475 (while (consp sexp)
872ab164 476 (dolist (var (pcase--fgrep vars (pop sexp)))
d02c9bcd
SM
477 (unless (memq var res) (push var res))))
478 (and (memq sexp vars) (not (memq sexp res)) (push sexp res))
479 res))
480
481;; It's very tempting to use `pcase' below, tho obviously, it'd create
482;; bootstrapping problems.
872ab164 483(defun pcase--u1 (matches code vars rest)
d02c9bcd 484 "Return code that runs CODE (with VARS) if MATCHES match.
ca3afb79 485Otherwise, it defers to REST which is a list of branches of the form
d02c9bcd
SM
486\(ELSE-MATCH ELSE-CODE . ELSE-VARS)."
487 ;; Depending on the order in which we choose to check each of the MATCHES,
488 ;; the resulting tree may be smaller or bigger. So in general, we'd want
489 ;; to be careful to chose the "optimal" order. But predicate
490 ;; patterns make this harder because they create dependencies
491 ;; between matches. So we don't bother trying to reorder anything.
492 (cond
493 ((null matches) (funcall code vars))
872ab164
SM
494 ((eq :pcase--fail (car matches)) (pcase--u rest))
495 ((eq :pcase--succeed (car matches))
496 (pcase--u1 (cdr matches) code vars rest))
d02c9bcd 497 ((eq 'and (caar matches))
872ab164 498 (pcase--u1 (append (cdar matches) (cdr matches)) code vars rest))
d02c9bcd
SM
499 ((eq 'or (caar matches))
500 (let* ((alts (cdar matches))
501 (var (if (eq (caar alts) 'match) (cadr (car alts))))
502 (simples '()) (others '()))
503 (when var
504 (dolist (alt alts)
505 (if (and (eq (car alt) 'match) (eq var (cadr alt))
506 (let ((upat (cddr alt)))
507 (and (eq (car-safe upat) '\`)
dcc029e0
SM
508 (or (integerp (cadr upat)) (symbolp (cadr upat))
509 (stringp (cadr upat))))))
d02c9bcd
SM
510 (push (cddr alt) simples)
511 (push alt others))))
512 (cond
872ab164 513 ((null alts) (error "Please avoid it") (pcase--u rest))
d02c9bcd
SM
514 ((> (length simples) 1)
515 ;; De-hoist the `or' MATCH into an `or' pattern that will be
516 ;; turned into a `memq' below.
872ab164
SM
517 (pcase--u1 (cons `(match ,var or . ,(nreverse simples)) (cdr matches))
518 code vars
519 (if (null others) rest
9a05edc4 520 (cons (cons
872ab164
SM
521 (pcase--and (if (cdr others)
522 (cons 'or (nreverse others))
523 (car others))
524 (cdr matches))
9a05edc4 525 (cons code vars))
872ab164 526 rest))))
d02c9bcd 527 (t
872ab164
SM
528 (pcase--u1 (cons (pop alts) (cdr matches)) code vars
529 (if (null alts) (progn (error "Please avoid it") rest)
9a05edc4 530 (cons (cons
872ab164
SM
531 (pcase--and (if (cdr alts)
532 (cons 'or alts) (car alts))
533 (cdr matches))
9a05edc4 534 (cons code vars))
872ab164 535 rest)))))))
d02c9bcd 536 ((eq 'match (caar matches))
9a05edc4 537 (let* ((popmatches (pop matches))
d032d5e7 538 (_op (car popmatches)) (cdrpopmatches (cdr popmatches))
9a05edc4
SM
539 (sym (car cdrpopmatches))
540 (upat (cdr cdrpopmatches)))
d02c9bcd 541 (cond
872ab164
SM
542 ((memq upat '(t _)) (pcase--u1 matches code vars rest))
543 ((eq upat 'dontcare) :pcase--dontcare)
dcc029e0 544 ((memq (car-safe upat) '(guard pred))
1f0816b6 545 (if (eq (car upat) 'pred) (put sym 'pcase-used t))
9a05edc4 546 (let* ((splitrest
ca105506 547 (pcase--split-rest
9a05edc4
SM
548 sym (apply-partially #'pcase--split-pred upat) rest))
549 (then-rest (car splitrest))
550 (else-rest (cdr splitrest)))
872ab164
SM
551 (pcase--if (if (and (eq (car upat) 'pred) (symbolp (cadr upat)))
552 `(,(cadr upat) ,sym)
553 (let* ((exp (cadr upat))
554 ;; `vs' is an upper bound on the vars we need.
555 (vs (pcase--fgrep (mapcar #'car vars) exp))
ca105506
SM
556 (env (mapcar (lambda (var)
557 (list var (cdr (assq var vars))))
558 vs))
559 (call (if (eq 'guard (car upat))
560 exp
561 (when (memq sym vs)
562 ;; `sym' is shadowed by `env'.
563 (let ((newsym (make-symbol "x")))
564 (push (list newsym sym) env)
565 (setq sym newsym)))
9abdc45d
SM
566 (if (functionp exp)
567 `(funcall #',exp ,sym)
ca105506 568 `(,@exp ,sym)))))
872ab164
SM
569 (if (null vs)
570 call
571 ;; Let's not replace `vars' in `exp' since it's
572 ;; too difficult to do it right, instead just
573 ;; let-bind `vars' around `exp'.
ca105506 574 `(let* ,env ,call))))
872ab164
SM
575 (pcase--u1 matches code vars then-rest)
576 (pcase--u else-rest))))
d02c9bcd 577 ((symbolp upat)
1f0816b6 578 (put sym 'pcase-used t)
f9d554dd
SM
579 (if (not (assq upat vars))
580 (pcase--u1 matches code (cons (cons upat sym) vars) rest)
581 ;; Non-linear pattern. Turn it into an `eq' test.
582 (pcase--u1 (cons `(match ,sym . (pred (eq ,(cdr (assq upat vars)))))
583 matches)
584 code vars rest)))
ca105506
SM
585 ((eq (car-safe upat) 'let)
586 ;; A upat of the form (let VAR EXP).
587 ;; (pcase--u1 matches code
588 ;; (cons (cons (nth 1 upat) (nth 2 upat)) vars) rest)
4dd1c416
SM
589 (macroexp-let²
590 macroexp-copyable-p sym
591 (let* ((exp (nth 2 upat))
592 (found (assq exp vars)))
593 (if found (cdr found)
594 (let* ((vs (pcase--fgrep (mapcar #'car vars) exp))
595 (env (mapcar (lambda (v) (list v (cdr (assq v vars))))
596 vs)))
597 (if env (macroexp-let* env exp) exp))))
598 (pcase--u1 (cons `(match ,sym . ,(nth 1 upat)) matches)
599 code vars rest)))
d02c9bcd 600 ((eq (car-safe upat) '\`)
1f0816b6 601 (put sym 'pcase-used t)
872ab164 602 (pcase--q1 sym (cadr upat) matches code vars rest))
d02c9bcd 603 ((eq (car-safe upat) 'or)
dcc029e0
SM
604 (let ((all (> (length (cdr upat)) 1))
605 (memq-fine t))
d02c9bcd
SM
606 (when all
607 (dolist (alt (cdr upat))
608 (unless (and (eq (car-safe alt) '\`)
dcc029e0
SM
609 (or (symbolp (cadr alt)) (integerp (cadr alt))
610 (setq memq-fine nil)
611 (stringp (cadr alt))))
d02c9bcd
SM
612 (setq all nil))))
613 (if all
614 ;; Use memq for (or `a `b `c `d) rather than a big tree.
9a05edc4
SM
615 (let* ((elems (mapcar 'cadr (cdr upat)))
616 (splitrest
617 (pcase--split-rest
618 sym (apply-partially #'pcase--split-member elems) rest))
619 (then-rest (car splitrest))
620 (else-rest (cdr splitrest)))
6876a58d 621 (put sym 'pcase-used t)
9a05edc4
SM
622 (pcase--if `(,(if memq-fine #'memq #'member) ,sym ',elems)
623 (pcase--u1 matches code vars then-rest)
624 (pcase--u else-rest)))
872ab164
SM
625 (pcase--u1 (cons `(match ,sym ,@(cadr upat)) matches) code vars
626 (append (mapcar (lambda (upat)
627 `((and (match ,sym . ,upat) ,@matches)
628 ,code ,@vars))
629 (cddr upat))
630 rest)))))
d02c9bcd 631 ((eq (car-safe upat) 'and)
872ab164
SM
632 (pcase--u1 (append (mapcar (lambda (upat) `(match ,sym ,@upat))
633 (cdr upat))
634 matches)
635 code vars rest))
d02c9bcd
SM
636 ((eq (car-safe upat) 'not)
637 ;; FIXME: The implementation below is naive and results in
638 ;; inefficient code.
872ab164 639 ;; To make it work right, we would need to turn pcase--u1's
d02c9bcd
SM
640 ;; `code' and `vars' into a single argument of the same form as
641 ;; `rest'. We would also need to split this new `then-rest' argument
642 ;; for every test (currently we don't bother to do it since
643 ;; it's only useful for odd patterns like (and `(PAT1 . PAT2)
644 ;; `(PAT3 . PAT4)) which the programmer can easily rewrite
645 ;; to the more efficient `(,(and PAT1 PAT3) . ,(and PAT2 PAT4))).
872ab164 646 (pcase--u1 `((match ,sym . ,(cadr upat)))
94d11cb5
IK
647 ;; FIXME: This codegen is not careful to share its
648 ;; code if used several times: code blow up is likely.
d032d5e7 649 (lambda (_vars)
94d11cb5
IK
650 ;; `vars' will likely contain bindings which are
651 ;; not always available in other paths to
652 ;; `rest', so there' no point trying to pass
653 ;; them down.
654 (pcase--u rest))
872ab164
SM
655 vars
656 (list `((and . ,matches) ,code . ,vars))))
d02c9bcd
SM
657 (t (error "Unknown upattern `%s'" upat)))))
658 (t (error "Incorrect MATCH %s" (car matches)))))
659
872ab164 660(defun pcase--q1 (sym qpat matches code vars rest)
d02c9bcd 661 "Return code that runs CODE if SYM matches QPAT and if MATCHES match.
ca3afb79 662Otherwise, it defers to REST which is a list of branches of the form
d02c9bcd
SM
663\(OTHER_MATCH OTHER-CODE . OTHER-VARS)."
664 (cond
665 ((eq (car-safe qpat) '\,) (error "Can't use `,UPATTERN"))
666 ((floatp qpat) (error "Floating point patterns not supported"))
667 ((vectorp qpat)
668 ;; FIXME.
669 (error "Vector QPatterns not implemented yet"))
670 ((consp qpat)
0d6459df
SM
671 (let* ((syma (make-symbol "xcar"))
672 (symd (make-symbol "xcdr"))
673 (splitrest (pcase--split-rest
674 sym
675 (apply-partially #'pcase--split-consp syma symd)
676 rest))
677 (then-rest (car splitrest))
678 (else-rest (cdr splitrest))
679 (then-body (pcase--u1 `((match ,syma . ,(pcase--upat (car qpat)))
680 (match ,symd . ,(pcase--upat (cdr qpat)))
681 ,@matches)
682 code vars then-rest)))
683 (pcase--if
684 `(consp ,sym)
685 ;; We want to be careful to only add bindings that are used.
686 ;; The byte-compiler could do that for us, but it would have to pay
687 ;; attention to the `consp' test in order to figure out that car/cdr
688 ;; can't signal errors and our byte-compiler is not that clever.
5342bb06
SM
689 ;; FIXME: Some of those let bindings occur too early (they are used in
690 ;; `then-body', but only within some sub-branch).
4dd1c416 691 (macroexp-let*
5342bb06 692 `(,@(if (get syma 'pcase-used) `((,syma (car ,sym))))
0d6459df 693 ,@(if (get symd 'pcase-used) `((,symd (cdr ,sym)))))
5342bb06 694 then-body)
0d6459df 695 (pcase--u else-rest))))
dcc029e0 696 ((or (integerp qpat) (symbolp qpat) (stringp qpat))
9a05edc4
SM
697 (let* ((splitrest (pcase--split-rest
698 sym (apply-partially 'pcase--split-equal qpat) rest))
699 (then-rest (car splitrest))
700 (else-rest (cdr splitrest)))
5342bb06
SM
701 (pcase--if (cond
702 ((stringp qpat) `(equal ,sym ,qpat))
703 ((null qpat) `(null ,sym))
704 (t `(eq ,sym ',qpat)))
872ab164
SM
705 (pcase--u1 matches code vars then-rest)
706 (pcase--u else-rest))))
22bcf204 707 (t (error "Unknown QPattern %s" qpat))))
97eedd1b 708
d02c9bcd
SM
709
710(provide 'pcase)
711;;; pcase.el ends here