-;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t; coding: utf-8 -*-
+;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t -*-
-;; Copyright (C) 2010-2015 Free Software Foundation, Inc.
+;; Copyright (C) 2010-2016 Free Software Foundation, Inc.
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
;; Keywords:
;;;###autoload
(defmacro pcase (exp &rest cases)
- "Perform ML-style pattern matching on EXP.
+ "Evaluate EXP and attempt to match it against structural patterns.
CASES is a list of elements of the form (PATTERN CODE...).
-Patterns can take the following forms:
+A structural PATTERN describes a template that identifies a class
+of values. For example, the pattern \\=`(,foo ,bar) matches any
+two element list, binding its elements to symbols named `foo' and
+`bar' -- in much the same way that `cl-destructuring-bind' would.
+
+A significant difference from `cl-destructuring-bind' is that, if
+a pattern match fails, the next case is tried until either a
+successful match is found or there are no more cases.
+
+Another difference is that pattern elements may be quoted,
+meaning they must match exactly: The pattern \\='(foo bar)
+matches only against two element lists containing the symbols
+`foo' and `bar' in that order. (As a short-hand, atoms always
+match themselves, such as numbers or strings, and need not be
+quoted.)
+
+Lastly, a pattern can be logical, such as (pred numberp), that
+matches any number-like element; or the symbol `_', that matches
+anything. Also, when patterns are backquoted, a comma may be
+used to introduce logical patterns inside backquoted patterns.
+
+The complete list of standard patterns is as follows:
+
_ matches anything.
- SELFQUOTING matches itself. This includes keywords, numbers, and strings.
SYMBOL matches anything and binds it to SYMBOL.
+ If a SYMBOL is used twice in the same pattern
+ the second occurrence becomes an `eq'uality test.
(or PAT...) matches if any of the patterns matches.
(and PAT...) matches if all the patterns match.
- 'VAL matches if the object is `equal' to VAL
+ \\='VAL matches if the object is `equal' to VAL.
+ ATOM is a shorthand for \\='ATOM.
+ ATOM can be a keyword, an integer, or a string.
(pred FUN) matches if FUN applied to the object returns non-nil.
(guard BOOLEXP) matches if BOOLEXP evaluates to non-nil.
(let PAT EXP) matches if EXP matches PAT.
(app FUN PAT) matches if FUN applied to the object matches PAT.
-If a SYMBOL is used twice in the same pattern (i.e. the pattern is
-\"non-linear\"), then the second occurrence is turned into an `eq'uality test.
-FUN can take the form
+Additional patterns can be defined using `pcase-defmacro'.
+
+The FUN argument in the `app' pattern may have the following forms:
SYMBOL or (lambda ARGS BODY) in which case it's called with one argument.
(F ARG1 .. ARGn) in which case F gets called with an n+1'th argument
which is the value being matched.
-So a FUN of the form SYMBOL is equivalent to one of the form (FUN).
+So a FUN of the form SYMBOL is equivalent to (FUN).
FUN can refer to variables bound earlier in the pattern.
-FUN is assumed to be pure, i.e. it can be dropped if its result is not used,
-and two identical calls can be merged into one.
-E.g. you can match pairs where the cdr is larger than the car with a pattern
-like \\=`(,a . ,(pred (< a))) or, with more checks:
-\\=`(,(and a (pred numberp)) . ,(and (pred numberp) (pred (< a))))
-
-Additional patterns can be defined via `pcase-defmacro'.
-Currently, the following patterns are provided this way:"
+
+See Info node `(elisp) Pattern matching case statement' in the
+Emacs Lisp manual for more information and examples."
(declare (indent 1) (debug (form &rest (pcase-PAT body))))
;; We want to use a weak hash table as a cache, but the key will unavoidably
;; be based on `exp' and `cases', yet `cases' is a fresh new list each time
expansion))))
(declare-function help-fns--signature "help-fns"
- (function doc real-def real-function))
+ (function doc real-def real-function buffer))
;; FIXME: Obviously, this will collide with nadvice's use of
;; function-documentation if we happen to advise `pcase'.
(insert "\n\n-- ")
(let* ((doc (documentation me 'raw)))
(setq doc (help-fns--signature symbol doc me
- (indirect-function me)))
+ (indirect-function me) nil))
(insert "\n" (or doc "Not documented.")))))))
(let ((combined-doc (buffer-string)))
(if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc)))))
(numberp . stringp)
(numberp . byte-code-function-p)
(consp . arrayp)
+ (consp . atom)
(consp . vectorp)
(consp . stringp)
(consp . byte-code-function-p)
res))
(defun pcase--self-quoting-p (upat)
- (or (keywordp upat) (numberp upat) (stringp upat)))
+ (or (keywordp upat) (integerp upat) (stringp upat)))
(defun pcase--app-subst-match (match sym fun nsym)
(cond
(sym (car cdrpopmatches))
(upat (cdr cdrpopmatches)))
(cond
- ((memq upat '(t _)) (pcase--u1 matches code vars rest))
+ ((memq upat '(t _))
+ (let ((code (pcase--u1 matches code vars rest)))
+ (if (eq upat '_) code
+ (macroexp--warn-and-return
+ "Pattern t is deprecated. Use `_' instead"
+ code))))
((eq upat 'pcase--dontcare) :pcase--dontcare)
((memq (car-safe upat) '(guard pred))
(if (eq (car upat) 'pred) (pcase--mark-used sym))
(pcase--eval (cadr upat) vars))
(pcase--u1 matches code vars then-rest)
(pcase--u else-rest))))
- ((symbolp upat)
+ ((and (symbolp upat) upat)
(pcase--mark-used sym)
(if (not (assq upat vars))
(pcase--u1 matches code (cons (cons upat sym) vars) rest)
(pcase--u rest))
vars
(list `((and . ,matches) ,code . ,vars))))
- (t (error "Unknown internal pattern `%S'" upat)))))
+ (t (error "Unknown pattern `%S'" upat)))))
(t (error "Incorrect MATCH %S" (car matches)))))
(def-edebug-spec
pcase-QPAT
+ ;; Cf. edebug spec for `backquote-form' in edebug.el.
(&or ("," pcase-PAT)
- (pcase-QPAT . pcase-QPAT)
+ (pcase-QPAT [&rest [¬ ","] pcase-QPAT]
+ . [&or nil pcase-QPAT])
(vector &rest pcase-QPAT)
sexp))
(QPAT1 . QPAT2) matches if QPAT1 matches the car and QPAT2 the cdr.
[QPAT1 QPAT2..QPATn] matches a vector of length n and QPAT1..QPATn match
its 0..(n-1)th elements, respectively.
- ,PAT matches if the pattern PAT matches.
- STRING matches if the object is `equal' to STRING.
- ATOM matches if the object is `eq' to ATOM."
+ ,PAT matches if the pcase pattern PAT matches.
+ ATOM matches if the object is `equal' to ATOM.
+ ATOM can be a symbol, an integer, or a string."
(declare (debug (pcase-QPAT)))
(cond
((eq (car-safe qpat) '\,) (cadr qpat))
`(and (pred consp)
(app car ,(list '\` (car qpat)))
(app cdr ,(list '\` (cdr qpat)))))
- ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat)))
+ ((or (stringp qpat) (integerp qpat) (symbolp qpat)) `',qpat)
+ (t (error "Unknown QPAT: %S" qpat))))
(provide 'pcase)