diff options
author | Michael Albinus <michael.albinus@gmx.de> | 2018-05-29 10:07:21 +0200 |
---|---|---|
committer | Michael Albinus <michael.albinus@gmx.de> | 2018-05-29 10:07:21 +0200 |
commit | 8a09ec0d45cdc8fa54203a0f7cc1a8c909627497 (patch) | |
tree | 2b7516e767bea0d86e3f819b6856841083f138b9 /lisp/emacs-lisp | |
parent | 0f48d18fd2a30f29cc3592a835d2a2254c9b0afb (diff) | |
parent | 9d6a3ac73af66184e5bb23555b93833f6a4d9f2e (diff) | |
download | emacs-8a09ec0d45cdc8fa54203a0f7cc1a8c909627497.tar.gz emacs-8a09ec0d45cdc8fa54203a0f7cc1a8c909627497.tar.bz2 emacs-8a09ec0d45cdc8fa54203a0f7cc1a8c909627497.zip |
Merge from origin/emacs-26
9d6a3ac73a Mention pcase as a fifth conditional form
567cb9046d Overhaul pcase documentation
4d7e54acff Use EXPVAL in docstrings of patterns defined using pcase-d...
7e8227ed68 Introduce EXPVAL for pcase, pcase-defmacro docstrings
e6de5b3d51 Ensure pcase doc shows `QPAT first among extensions
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 8 | ||||
-rw-r--r-- | lisp/emacs-lisp/eieio.el | 8 | ||||
-rw-r--r-- | lisp/emacs-lisp/pcase.el | 143 | ||||
-rw-r--r-- | lisp/emacs-lisp/radix-tree.el | 2 | ||||
-rw-r--r-- | lisp/emacs-lisp/rx.el | 2 |
5 files changed, 92 insertions, 71 deletions
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 9600230c076..d7e4b4e611a 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -2964,10 +2964,10 @@ non-nil value, that slot cannot be set via `setf'. ;;;###autoload (pcase-defmacro cl-struct (type &rest fields) - "Pcase patterns to match cl-structs. -Elements of FIELDS can be of the form (NAME PAT) in which case the contents of -field NAME is matched against PAT, or they can be of the form NAME which -is a shorthand for (NAME NAME)." + "Pcase patterns that match cl-struct EXPVAL of type TYPE. +Elements of FIELDS can be of the form (NAME PAT) in which case the +contents of field NAME is matched against PAT, or they can be of +the form NAME which is a shorthand for (NAME NAME)." (declare (debug (sexp &rest [&or (sexp pcase-PAT) sexp]))) `(and (pred (pcase--flip cl-typep ',type)) ,@(mapcar diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el index 1e1419f6eb7..98cdd4fd903 100644 --- a/lisp/emacs-lisp/eieio.el +++ b/lisp/emacs-lisp/eieio.el @@ -346,10 +346,10 @@ variable name of the same name as the slot." index)))) (pcase-defmacro eieio (&rest fields) - "Pcase patterns to match EIEIO objects. -Elements of FIELDS can be of the form (NAME PAT) in which case the contents of -field NAME is matched against PAT, or they can be of the form NAME which -is a shorthand for (NAME NAME)." + "Pcase patterns that match EIEIO object EXPVAL. +Elements of FIELDS can be of the form (NAME PAT) in which case the +contents of field NAME is matched against PAT, or they can be of + the form NAME which is a shorthand for (NAME NAME)." (declare (debug (&rest [&or (sexp pcase-PAT) sexp]))) (let ((is (make-symbol "table"))) ;; FIXME: This generates a horrendous mess of redundant let bindings. diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index ce148c9e1a9..fa7b1de8b4d 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -108,58 +108,43 @@ ;;;###autoload (defmacro pcase (exp &rest cases) - "Evaluate EXP and attempt to match it against structural patterns. + "Evaluate EXP to get EXPVAL; try passing control to one of CASES. CASES is a list of elements of the form (PATTERN CODE...). - -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. The CODE -expression corresponding to the matching pattern determines the -return value. If there is no match the returned value is nil. - -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. - 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. - 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. +For the first CASE whose PATTERN \"matches\" EXPVAL, +evaluate its CODE..., and return the value of the last form. +If no CASE has a PATTERN that matches, return nil. + +Each PATTERN expands, in essence, to a predicate to call +on EXPVAL. When the return value of that call is non-nil, +PATTERN matches. PATTERN can take one of the forms: + + _ matches anything. + \\='VAL matches if EXPVAL is `equal' to VAL. + KEYWORD shorthand for \\='KEYWORD + INTEGER shorthand for \\='INTEGER + STRING shorthand for \\='STRING + 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. + (pred FUN) matches if FUN called on EXPVAL returns non-nil. + (app FUN PAT) matches if FUN called on EXPVAL matches PAT. + (guard BOOLEXP) matches if BOOLEXP evaluates to non-nil. + (let PAT EXPR) matches if EXPR matches PAT. + (and PAT...) matches if all the patterns match. + (or PAT...) matches if any of the patterns matches. + +FUN in `pred' and `app' can take one of the forms: + SYMBOL or (lambda ARGS BODY) + call it with one argument + (F ARG1 .. ARGn) + call F with ARG1..ARGn and EXPVAL as n+1'th argument + +FUN, BOOLEXP, EXPR, and subsequent PAT can refer to variables +bound earlier in the pattern by a SYMBOL pattern. 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 (FUN). -FUN can refer to variables bound earlier in the pattern. - -See Info node `(elisp) Pattern matching case statement' in the +See Info node `(elisp) Pattern-Matching Conditional' 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 @@ -199,15 +184,30 @@ Emacs Lisp manual for more information and examples." (require 'help-fns) (with-temp-buffer (insert (or (cdr ud) main)) - (mapatoms - (lambda (symbol) - (let ((me (get symbol 'pcase-macroexpander))) - (when me - (insert "\n\n-- ") - (let* ((doc (documentation me 'raw))) - (setq doc (help-fns--signature symbol doc me - (indirect-function me) nil)) - (insert "\n" (or doc "Not documented."))))))) + ;; Presentation Note: For conceptual continuity, we guarantee + ;; that backquote doc immediately follows main pcase doc. + ;; (The order of the other extensions is unimportant.) + (let (more) + ;; Collect all the extensions. + (mapatoms (lambda (symbol) + (let ((me (get symbol 'pcase-macroexpander))) + (when me + (push (cons symbol me) + more))))) + ;; Ensure backquote is first. + (let ((x (assq '\` more))) + (setq more (cons x (delq x more)))) + ;; Do the output. + (while more + (let* ((pair (pop more)) + (symbol (car pair)) + (me (cdr pair)) + (doc (documentation me 'raw))) + (insert "\n\n-- ") + (setq doc (help-fns--signature symbol doc 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))))) @@ -412,7 +412,11 @@ any kind of error." (defmacro pcase-defmacro (name args &rest body) "Define a new kind of pcase PATTERN, by macro expansion. Patterns of the form (NAME ...) will be expanded according -to this macro." +to this macro. + +By convention, DOC should use \"EXPVAL\" to stand +for the result of evaluating EXP (first arg to `pcase'). +\n(fn NAME ARGS [DOC] &rest BODY...)" (declare (indent 2) (debug defun) (doc-string 3)) ;; Add the function via `fsym', so that an autoload cookie placed ;; on a pcase-defmacro will cause the macro to be loaded on demand. @@ -907,14 +911,29 @@ Otherwise, it defers to REST which is a list of branches of the form sexp)) (pcase-defmacro \` (qpat) - "Backquote-style pcase patterns. + "Backquote-style pcase patterns: \\=`QPAT QPAT can take the following forms: (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 pcase pattern PAT matches. - ATOM matches if the object is `equal' to ATOM. - ATOM can be a symbol, an integer, or a string." + ,PAT matches if the `pcase' pattern PAT matches. + SYMBOL matches if EXPVAL is `equal' to SYMBOL. + KEYWORD likewise for KEYWORD. + INTEGER likewise for INTEGER. + STRING likewise for STRING. + +The list or vector QPAT is a template. The predicate formed +by a backquote-style pattern is a combination of those +formed by any sub-patterns, wrapped in a top-level condition: +EXPVAL must be \"congruent\" with the template. For example: + + \\=`(technical ,forum) + +The predicate is the logical-AND of: + - Is EXPVAL a list of two elements? + - Is the first element the symbol `technical'? + - True! (The second element can be anything, and for the sake + of the body forms, its value is bound to the symbol `forum'.)" (declare (debug (pcase-QPAT))) (cond ((eq (car-safe qpat) '\,) (cadr qpat)) diff --git a/lisp/emacs-lisp/radix-tree.el b/lisp/emacs-lisp/radix-tree.el index e3c5800efb1..2491ccea95b 100644 --- a/lisp/emacs-lisp/radix-tree.el +++ b/lisp/emacs-lisp/radix-tree.el @@ -196,6 +196,8 @@ If not found, return nil." (eval-and-compile (pcase-defmacro radix-tree-leaf (vpat) + "Build a `pcase' pattern that matches radix-tree leaf EXPVAL. +VPAT is a `pcase' pattern to extract the value." ;; FIXME: We'd like to use a negative pattern (not consp), but pcase ;; doesn't support it. Using `atom' works but generates sub-optimal code. `(or `(t . ,,vpat) (and (pred atom) ,vpat)))) diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el index 8059bf2a6e1..358f9db36c1 100644 --- a/lisp/emacs-lisp/rx.el +++ b/lisp/emacs-lisp/rx.el @@ -1179,7 +1179,7 @@ enclosed in `(and ...)'. (pcase-defmacro rx (&rest regexps) "Build a `pcase' pattern matching `rx' regexps. The REGEXPS are interpreted as by `rx'. The pattern matches if -the regular expression so constructed matches the object, as if +the regular expression so constructed matches EXPVAL, as if by `string-match'. In addition to the usual `rx' constructs, REGEXPS can contain the |