2015-09-28 22:39:14 +00:00
|
|
|
;;; pcase.el --- ML-style pattern-matching macro for Elisp -*- lexical-binding: t -*-
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2020-01-01 00:19:43 +00:00
|
|
|
;; Copyright (C) 2010-2020 Free Software Foundation, Inc.
|
2010-08-10 13:18:14 +00:00
|
|
|
|
|
|
|
;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
|
2011-02-28 04:24:40 +00:00
|
|
|
;; Keywords:
|
2010-08-10 13:18:14 +00:00
|
|
|
|
|
|
|
;; This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
;; GNU Emacs is free software: you can redistribute it and/or modify
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
|
|
|
;; GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
;; GNU General Public License for more details.
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
2017-09-13 22:52:52 +00:00
|
|
|
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
2010-08-10 13:18:14 +00:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;; ML-style pattern matching.
|
|
|
|
;; The entry points are autoloaded.
|
|
|
|
|
2010-10-29 01:05:38 +00:00
|
|
|
;; Todo:
|
|
|
|
|
2011-03-16 20:08:39 +00:00
|
|
|
;; - (pcase e (`(,x . ,x) foo)) signals an "x unused" warning if `foo' doesn't
|
|
|
|
;; use x, because x is bound separately for the equality constraint
|
|
|
|
;; (as well as any pred/guard) and for the body, so uses at one place don't
|
|
|
|
;; count for the other.
|
2010-10-29 01:05:38 +00:00
|
|
|
;; - provide ways to extend the set of primitives, with some kind of
|
|
|
|
;; define-pcase-matcher. We could easily make it so that (guard BOOLEXP)
|
|
|
|
;; could be defined this way, as a shorthand for (pred (lambda (_) BOOLEXP)).
|
|
|
|
;; But better would be if we could define new ways to match by having the
|
2010-11-24 16:39:51 +00:00
|
|
|
;; extension provide its own `pcase--split-<foo>' thingy.
|
2011-03-16 20:08:39 +00:00
|
|
|
;; - along these lines, provide patterns to match CL structs.
|
2011-02-27 02:50:38 +00:00
|
|
|
;; - provide something like (setq VAR) so a var can be set rather than
|
|
|
|
;; let-bound.
|
2012-05-26 15:52:27 +00:00
|
|
|
;; - provide a way to fallthrough to subsequent cases (not sure what I meant by
|
|
|
|
;; this :-()
|
2011-02-27 02:50:38 +00:00
|
|
|
;; - try and be more clever to reduce the size of the decision tree, and
|
2011-03-16 20:08:39 +00:00
|
|
|
;; to reduce the number of leaves that need to be turned into function:
|
2011-02-27 02:50:38 +00:00
|
|
|
;; - first, do the tests shared by all remaining branches (it will have
|
2012-05-26 15:52:27 +00:00
|
|
|
;; to be performed anyway, so better do it first so it's shared).
|
2011-02-27 02:50:38 +00:00
|
|
|
;; - then choose the test that discriminates more (?).
|
2012-05-26 15:52:27 +00:00
|
|
|
;; - provide Agda's `with' (along with its `...' companion).
|
2015-05-25 02:38:05 +00:00
|
|
|
;; - implement (not PAT). This might require a significant redesign.
|
2010-10-29 01:05:38 +00:00
|
|
|
;; - ideally we'd want (pcase s ((re RE1) E1) ((re RE2) E2)) to be able to
|
|
|
|
;; generate a lex-style DFA to decide whether to run E1 or E2.
|
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;;; Code:
|
|
|
|
|
2012-06-07 19:25:48 +00:00
|
|
|
(require 'macroexp)
|
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;; Macro-expansion of pcase is reasonably fast, so it's not a problem
|
|
|
|
;; when byte-compiling a file, but when interpreting the code, if the pcase
|
|
|
|
;; is in a loop, the repeated macro-expansion becomes terribly costly, so we
|
|
|
|
;; memoize previous macro expansions to try and avoid recomputing them
|
|
|
|
;; over and over again.
|
2012-09-04 17:40:25 +00:00
|
|
|
;; FIXME: Now that macroexpansion is also performed when loading an interpreted
|
|
|
|
;; file, this is not a real problem any more.
|
2011-03-06 04:48:17 +00:00
|
|
|
(defconst pcase--memoize (make-hash-table :weakness 'key :test 'eq))
|
Add portable dumper
Add a new portable dumper as an alternative to unexec. Use it by default.
* src/dmpstruct.awk: New file.
* src/doc.c (get_doc_string): use will_dump_p().
* src/editfns.c (styled_format): silence compiler warning
with UNINIT.
* src/emacs-module.c (syms_of_module): staticpro ltv_mark.
* src/emacs.c (gflags): new variable.
(init_cmdargs): unwrap
(string_starts_with_p, find_argument, dump_error_to_string)
(load_pdump): new functions.
(main): detect pdumper and --temacs invocation; actually load
portable dump when detected; set gflags as appropriate; changes to
init functions throughout to avoid passing explicit
'initialized' argument.
* src/eval.c (inhibit_lisp_code): remove unused variable.
(init_eval_once_for_pdumper): new function.
(init_eval_once): call it.
* src/filelock.c: CANNOT_DUMP -> will_dump_p()
* src/fingerprint-dummy.c: new file
* src/fingerprint.h: new file
* src/fns.c: CANNOT_DUMP -> will_dump_p(), etc.
(weak_hash_tables): remove
(hashfn_equal, hashfn_eql): un-staticify
(make_hash_table): set new 'next_weak' hash table field; drop
global weak_hash_tables logic.
(copy_hash_table): drop global weak_hash_tables logic.
(hash_table_rehash): new function.
(hash_lookup, hash_put, hash_remove_from_table, hash_clear):
rehash if needed.
(sweep_weak_table): un-staticify; explain logic; bool-ify.
(sweep_weak_hash_tables): remove function.
* src/font.c (syms_of_font): remember pdumper stuff.
* src/fontset.c (syms_of_fontset): remember pdumper stuff.
* src/frame.c (make_initial_frame): don't reset Vframe_list.
(init_frame_once_for_pdumper, init_frame_once): new functions.
(syms_of_frame): remove redundant staticpro.
* src/fringe.c (init_fringe_once_for_pdumper): new functin.
(init_fringe_once): call it.
* src/ftcrfont.c (syms_of_ftcrfont_for_pdumper): new function.
(syms_of_ftcrfont): call it.
* src/ftfont.c (syms_of_ftfont_for_pdumper): new function.
(syms_of_ftfont): call it.
* src/ftxont.c (syms_of_ftxfont_for_pdumper): new function.
(syms_of_ftxfont): call it.
* src/gmalloc.c: adjust for pdumper througout
(DUMPED): remove weird custom dumped indicator.
* src/gnutls.c (syms_of_gnutls): pdumper note for
gnutls_global_initialized.
* src/image.c (syms_of_image): add pdumper comment,
initializer note.
* src/insdel.c (prepare_to_modify_buffer_1): account
for buffer contents possibly being in dump image.
* src/keyboard.c (syms_of_keyboard_for_pdumper): new function.
(syms_of_keyboard): staticpro more; call pdumper syms function.
* src/lisp.h: add comments throughout
(gflags): declare.
(will_dump_p, will_bootstrap_p, will_dump_with_pdumper_p)
(dumped_with_pdumper_p, will_dump_with_unexec_p)
(dumped_with_unexec_p, definitely_will_not_unexec_p): new
functions.
(POWER_OF_2, ROUNDUP): move macros.
(PSEUDOVECTOR_TYPE, PSEUDOVECTOR_TYPEP): take vectorlike header
pointer instead of vector; constify.
(Lisp_Hash_Table): add comment about need to rehash on access; add
comment for next_weak.
(HASH_KEY, HASH_VALUE, HASH_HASH, HASH_TABLE_SIZE): const-ify.
(hash_table_rehash): declare.
(hash_rehash_needed_p, hash_rehash_if_needed): new functions.
(finalizers, doomed_finalizers): declare extern.
(SUBR_SECTION_ATTRIBUTE): new macro.
(staticvec, staticidx): un-static-ify.
(sweep_weak_hash_tables): remove declaration.
(sweep_weak_table): declare.
(hashfn_eql, hashfn_equal): declare.
(number_finalizers_run): new variable.
(Vdead): externify when ENABLE_CHECKING.
(gc_root_type): new enumeration.
(gc_root_visitor): new struct.
(visit_static_gc_roots): declare.
(vectorlike_nbytes): declare.
(vector_nbytes): define as trivial inline function wrapper for
vectorlike_nbytes.
(init_obarray_once): change signature.
(primary_thread): extern-ify.
(init_buffer): change signature.
(init_frame_once): declare.
* src/lread.c (readevalloop): adjust for new dumped predicates.
(init_obarray_once): new function.
(ndefsubr): new variable.
(defsubr): increment it.
(load_path_check): adjust for pdumper.
(load_path_default): use pdumper functions; adjust for
dump search.
* src/macfont.m (macfont_init_font_change_handler): avoid
shadowing global.
(syms_of_macfont_for_pdumper): new function.
(syms_of_macfont): call it.
* src/menu.c (syms_of_menu): staticpro more stuff.
* src/minibuf.c (Ftry_completion): rehash if needed.
(init_minibuf_once_for_pdumper): new function.
(init_minibuf_once): call it.
* src/nsfont.m (syms_of_nsfns): staticpro more.
* src/nsfont.m (syms_of_nsfont_for_pdumper): new function.
(syms_of_nsfont): call it.
* src/nsterm.m (syms_of_nsfont): remember pdumper stuff.
* src/pdumper.c: new file.
* src/pdumper.h: new file.
* src/process.c (init_process_emacs): use new pdumper functions
instead of CANNOT_DUMP.
* src/profiler.c (syms_of_profiler_for_pdumper): new function.
(syms_of_profiler_for_pdumper): call it.
* src/search.c (syms_of_search_for_pdumper): new function.
(syms_of_search_for_pdumper): call it.
* src/sheap.c (bss_sbrk_did_unexec): remove.
* src/sheap.h (bss_sbrk_did_unexec): remove.
* src/syntax.c (syms_of_syntax): don't redundantly staticpro
re_match_object.
* src/sysdep.c: use will_dump_with_unexec_p() instead of bss
hack thing.
* src/syssignals.h (init_sigsegv): declare.
* src/systime.h (init_timefns): remove bool from signature.
* src/textprop.c (syms_of_textprop): move staticpro.
* src/thread.c (main_thread_p): constify.
* src/thread.h (main_thread_p): constify.
* src/timefns.c (init_timefns): remove bool from signature.
(syms_of_timefns_for_pdumper): new function.
(syms_of_timefns): call it.
* src/w32.c: rearrange code.
* src/w32.h (w32_relocate): declare.
* src/w32fns.c (syms_of_w32fns): add pdumper note.
* src/w32font.c (syms_of_w32font_for_pdumper): new function.
(syms_of_w32font): call it.
* src/w32heap.c (using_dynamic_heap): new variable.
(init_heap): use it.
* src/w32menu.c (syms_of_w32menu): add pdumper note.
* src/w32proc.c
(ctrl_c_handler, mainCRTStartup, _start, open_input_file)
(rva_to_section, close_file_data): move here.
* src/w32uniscribe.c (syms_of_w32uniscribe_for_pdumper):
new function.
(syms_of_w32uniscribe): call it.
* src/window.c (init_window_once_for_pdumper): new function.
(init_window_once): call it; staticpro more stuff.
* src/xfont.c (syms_of_xfont_for_pdumper): new function.
(syms_of_xfont): call it.
* src/xftfont.c (syms_of_xftfont_for_pdumper): new function.
(syms_of_xftfont): call it.
* src/xmenu.c (syms_of_xmenu_for_pdumper): new function.
(syms_of_xmenu): call it.
* src/xselect.c (syms_of_xselect_for_pdumper): new function.
(syms_of_xselect): call it.
* src/xsettings.c (syms_of_xsettings): add more pdumper notes.
* src/term.c (syms_of_xterm): add pdumper note.
* src/dispnew.c (init_faces_initial): new function.
(init_display_interactive): rename from init_display; use
will_dump_p instead of !initialized. Initialize faces early for
pdumper if needed.
(init_display): new function.
(syms_of_display_for_pdumper): new function.
(syms_of_display): call it.
* src/dbusbind.c (syms_of_dbusbind): Add TODO for bus reset
on pdumper load.
* src/data.c (Fdefalias): Use will_dump_p
instead of Vpurify_flag.
(Fmake_variable_buffer_local): silence compiler warning with -Og
by making valcontents UNINIT.
(arith_driver): silence compiler warning with UNINIT.
* src/conf_post.h (ATTRIBUTE_SECTION): new macro.
* src/composite.c (composition_gstring_put_cache): rehash hash
table if needed.
* src/coding.c (init_coding_once, syms_of_coding): remember
pdumper stuff.
* src/charset.h (charset_table_size, charset_table_user): declare.
* src/charset.c (charset_table_used, charset_table_size): un-static.
(init_charset_oncem, syms_of_charset): remember pdumper stuff.
* src/category.c (category_table_version): remove obsolete
variable.
* src/callint.c (syms_of_callint): staticpro 'preserved_fns'
(init_callproc): use will_dump_p instead of !CANNOT_DUMP.
* src/bytecode.c (exec_byte_code): rehash table tables if needed
* src/buffer.c (alloc_buffer_text, free_buffer_text): account for
pdumper
(init_buffer_once): add TODO; remember stuff for pdumper.
(init_buffer): don't take initialized argument; adjust
for pdumper.
* src/atimer.c (init_atimer): initialize subr only if
!initialized.
* src/alloc.c: (vector_marked_p, set_vector_marked)
(vectorlike_marked_p, set_vectorlike_marked, cons_marked_p)
(set_cons_marked, string_marked_p, set_string_marked)
(symbol_marked_p, set_symbol_marked, interval_marked_p)
(set_interval_marked): new accessor routines. Use them
instead of raw GC access throughout.
(Vdead): make non-static when ENABLE_CHECKING.
(vectorlike_nbytes): rename of 'vector_nbytes'; take a vectorlike
header as input instead of a vector.
(number_finalizers_run): new internal C variable.
(mark_maybe_object): check for pdumper objects.
(valid_pointer_p): don't be gratuitously inefficient under rr(1).
(make_pure_c_string): add support for size_byte = -2 mode
indicating that string data points into Emacs image rodata.
(visit_vectorlike_root): visits GC roots embedded in
vectorlike objects.
(visit_buffer_root): visits GC roots embedded in
our totally-not-a-buffer buffer global objects.
(visit_static_gc_roots): visit GC roots in the Emacs data section.
(mark_object_root_visitor): root callback used for conventional GC
marking
(weak_hash_tables): new internal variable for tracking found weak
hash tables during GC.
(mark_and_sweep_weak_table_contents): new weak hash table marking.
(garbage_collect_1): use new GC root visitor machinery.
(mark_vectorlike): accept a vectorlike_header instead of a
Lisp_Vector.
(mark_frame, mark_window, mark_hash_table): new functions.
(mark_object): initialize 'm'; check for pdumper objects and use
new mark-bit accessors throughout. Remove some object-specific
marking code and move to helper functions above.
(survives_gc_p): check for pdumper objects.
(gc-sweep): clear pdumper mark bits.
(init_alloc_once_for_pdumper): new helper function for early init
called both during normal init and pdumper load.
(init_alloc_once): pdumper integration.
* src/Makefile.in: Rewrite dumping for pdumper; add pdumper.o;
invoke temacs with --temacs command line option; build dmpstruct.h
from dmpstruct.awk; stop relying on CANNOT_DUMP; clean up pdumper
intermediate files during build.
* nextstep/Makefile.in: build emacs.pdmp into NS packages
* lisp/startup.el: account for new '--temacs' and '--dump-file'
command line option.
* lisp/loadup.el: rewrite early init to account for pdumper; use
injected 'dump-mode' variable (set via the new '--temacs' option)
instead of parsing command line.
* lisp/cus-start.el: Check 'dump-mode' instead of 'purify-flag',
since the new 'dump-mode'
* lib-src/make-fingerprint.c: new program
* lib-src/Makefile.in: built make-fingerprint utility program
* configure.ac: Add --with-pdumper toggle to control pdumper
support; add --with-unexec toggle to control unexec support.
Add --with-dumping option to control which dumping strategy we use
by default. Adjust for pdumper throughout. Check for
posix_madvise.
* Makefile.in: Add @DUMPING@ substitution; add pdumper mode.
* .gitignore: Add make-fingerprint, temacs.in, fingerprint.c,
dmpstruct.h, and pdumper dump files.
2019-01-15 22:36:54 +00:00
|
|
|
;; (defconst pcase--memoize (make-hash-table :test 'eq))
|
2012-06-11 00:33:33 +00:00
|
|
|
;; (defconst pcase--memoize-1 (make-hash-table :test 'eq))
|
|
|
|
;; (defconst pcase--memoize-2 (make-hash-table :weakness 'key :test 'equal))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
More CL cleanups and reduction of use of cl.el.
* woman.el, winner.el, vc/vc-rcs.el, vc/vc-hooks.el, vc/vc-hg.el:
* vc/vc-git.el, vc/vc-dir.el, vc/vc-bzr.el, vc/vc-annotate.el:
* textmodes/tex-mode.el, textmodes/sgml-mode.el, tar-mode.el:
* strokes.el, ses.el, server.el, progmodes/js.el, progmodes/gdb-mi.el:
* progmodes/flymake.el, progmodes/ebrowse.el, progmodes/compile.el:
* play/tetris.el, play/snake.el, play/pong.el, play/landmark.el:
* play/hanoi.el, play/decipher.el, play/5x5.el, nxml/nxml-mode.el:
* net/secrets.el, net/quickurl.el, midnight.el, mail/footnote.el:
* image-dired.el, ibuffer.el, ibuf-macs.el, ibuf-ext.el, hexl.el:
* eshell/eshell.el, eshell/esh-io.el, eshell/esh-ext.el:
* eshell/esh-cmd.el, eshell/em-ls.el, eshell/em-hist.el:
* eshell/em-cmpl.el, eshell/em-banner.el:
* url/url.el, url/url-queue.el, url/url-parse.el, url/url-http.el:
* url/url-future.el, url/url-dav.el, url/url-cookie.el:
* calendar/parse-time.el, test/eshell.el: Use cl-lib.
* wid-browse.el, wdired.el, vc/vc.el, vc/vc-mtn.el, vc/vc-cvs.el:
* vc/vc-arch.el, tree-widget.el, textmodes/texinfo.el:
* textmodes/refill.el, textmodes/css-mode.el, term/tvi970.el:
* term/ns-win.el, term.el, shell.el, ps-samp.el:
* progmodes/perl-mode.el, progmodes/pascal.el, progmodes/gud.el:
* progmodes/glasses.el, progmodes/etags.el, progmodes/cwarn.el:
* play/gamegrid.el, play/bubbles.el, novice.el, notifications.el:
* net/zeroconf.el, net/xesam.el, net/snmp-mode.el, net/mairix.el:
* net/ldap.el, net/eudc.el, net/browse-url.el, man.el:
* mail/mailheader.el, mail/feedmail.el:
* url/url-util.el, url/url-privacy.el, url/url-nfs.el, url/url-misc.el:
* url/url-methods.el, url/url-gw.el, url/url-file.el, url/url-expand.el:
Dont use CL.
* ibuf-ext.el (ibuffer-mark-old-buffers): Use float-time.
* eshell/esh-opt.el (eshell-eval-using-options): Quote code with
`lambda' rather than with `quote'.
(eshell-do-opt): Adjust accordingly.
(eshell-process-option): Simplify.
* eshell/esh-var.el:
* eshell/em-script.el: Require `esh-opt' for eshell-eval-using-options.
* emacs-pcase.el (pcase--dontcare-upats, pcase--let*)
(pcase--expand, pcase--u1): Rename pcase's internal `dontcare' pattern
to `pcase--dontcare'.
* emacs-cl.el (labels): Mark obsolete.
(cl--letf, letf): Move to cl-lib.
(cl--letf*, letf*): Remove.
* emacs-cl-lib.el (cl-nth-value): Use defalias.
* emacs-cl-macs.el (cl-dolist, cl-dotimes): Add indent rule.
(cl-progv): Rewrite.
(cl--letf, cl-letf): Move from cl.el.
(cl-letf*): New macro.
* emacs-cl-extra.el (cl--progv-before, cl--progv-after): Remove.
2012-07-11 23:13:41 +00:00
|
|
|
(defconst pcase--dontcare-upats '(t _ pcase--dontcare))
|
2010-11-24 16:39:51 +00:00
|
|
|
|
2014-09-13 16:30:21 +00:00
|
|
|
(defvar pcase--dontwarn-upats '(pcase--dontcare))
|
|
|
|
|
2012-06-11 00:46:21 +00:00
|
|
|
(def-edebug-spec
|
2015-05-25 02:38:05 +00:00
|
|
|
pcase-PAT
|
2012-06-11 00:46:21 +00:00
|
|
|
(&or symbolp
|
2015-05-25 02:38:05 +00:00
|
|
|
("or" &rest pcase-PAT)
|
|
|
|
("and" &rest pcase-PAT)
|
2012-06-11 00:46:21 +00:00
|
|
|
("guard" form)
|
2015-05-25 02:38:05 +00:00
|
|
|
("let" pcase-PAT form)
|
2015-04-12 14:26:51 +00:00
|
|
|
("pred" pcase-FUN)
|
2015-05-25 02:38:05 +00:00
|
|
|
("app" pcase-FUN pcase-PAT)
|
2015-04-12 14:26:52 +00:00
|
|
|
pcase-MACRO
|
2015-04-12 14:26:51 +00:00
|
|
|
sexp))
|
|
|
|
|
|
|
|
(def-edebug-spec
|
|
|
|
pcase-FUN
|
|
|
|
(&or lambda-expr
|
|
|
|
;; Punt on macros/special forms.
|
|
|
|
(functionp &rest form)
|
2012-06-11 00:46:21 +00:00
|
|
|
sexp))
|
|
|
|
|
2017-02-04 11:12:14 +00:00
|
|
|
;; See bug#24717
|
|
|
|
(put 'pcase-MACRO 'edebug-form-spec 'pcase--edebug-match-macro)
|
2015-04-12 14:26:52 +00:00
|
|
|
|
2015-05-01 17:40:31 +00:00
|
|
|
;; Only called from edebug.
|
|
|
|
(declare-function get-edebug-spec "edebug" (symbol))
|
|
|
|
(declare-function edebug-match "edebug" (cursor specs))
|
|
|
|
|
2015-04-12 14:26:52 +00:00
|
|
|
(defun pcase--edebug-match-macro (cursor)
|
|
|
|
(let (specs)
|
|
|
|
(mapatoms
|
|
|
|
(lambda (s)
|
2019-06-26 14:24:59 +00:00
|
|
|
(let ((m (get s 'pcase-macroexpander)))
|
2015-04-12 14:26:52 +00:00
|
|
|
(when (and m (get-edebug-spec m))
|
|
|
|
(push (cons (symbol-name s) (get-edebug-spec m))
|
|
|
|
specs)))))
|
|
|
|
(edebug-match cursor (cons '&or specs))))
|
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;;;###autoload
|
|
|
|
(defmacro pcase (exp &rest cases)
|
2018-05-21 15:11:55 +00:00
|
|
|
"Evaluate EXP to get EXPVAL; try passing control to one of CASES.
|
2015-05-25 02:38:05 +00:00
|
|
|
CASES is a list of elements of the form (PATTERN CODE...).
|
2018-05-21 16:16:35 +00:00
|
|
|
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.
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2016-01-22 07:28:50 +00:00
|
|
|
Additional patterns can be defined using `pcase-defmacro'.
|
2016-01-22 06:07:19 +00:00
|
|
|
|
2018-05-21 16:16:35 +00:00
|
|
|
See Info node `(elisp) Pattern-Matching Conditional' in the
|
2016-01-22 06:07:19 +00:00
|
|
|
Emacs Lisp manual for more information and examples."
|
2015-05-25 02:38:05 +00:00
|
|
|
(declare (indent 1) (debug (form &rest (pcase-PAT body))))
|
2011-03-06 04:48:17 +00:00
|
|
|
;; 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
|
|
|
|
;; we're called so it'll be immediately GC'd. So we use (car cases) as key
|
|
|
|
;; which does come straight from the source code and should hence not be GC'd
|
|
|
|
;; so easily.
|
|
|
|
(let ((data (gethash (car cases) pcase--memoize)))
|
|
|
|
;; data = (EXP CASES . EXPANSION)
|
|
|
|
(if (and (equal exp (car data)) (equal cases (cadr data)))
|
|
|
|
;; We have the right expansion.
|
|
|
|
(cddr data)
|
2012-06-11 00:33:33 +00:00
|
|
|
;; (when (gethash (car cases) pcase--memoize-1)
|
|
|
|
;; (message "pcase-memoize failed because of weak key!!"))
|
|
|
|
;; (when (gethash (car cases) pcase--memoize-2)
|
|
|
|
;; (message "pcase-memoize failed because of eq test on %S"
|
|
|
|
;; (car cases)))
|
2017-03-19 21:54:43 +00:00
|
|
|
;; (when data
|
|
|
|
;; (message "pcase-memoize: equal first branch, yet different"))
|
2011-03-06 04:48:17 +00:00
|
|
|
(let ((expansion (pcase--expand exp cases)))
|
2012-06-11 00:33:33 +00:00
|
|
|
(puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize)
|
|
|
|
;; (puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize-1)
|
|
|
|
;; (puthash (car cases) `(,exp ,cases ,@expansion) pcase--memoize-2)
|
2011-03-06 04:48:17 +00:00
|
|
|
expansion))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2015-05-01 17:40:31 +00:00
|
|
|
(declare-function help-fns--signature "help-fns"
|
2015-09-05 18:22:29 +00:00
|
|
|
(function doc real-def real-function buffer))
|
2015-05-01 17:40:31 +00:00
|
|
|
|
2015-03-23 22:24:30 +00:00
|
|
|
;; FIXME: Obviously, this will collide with nadvice's use of
|
|
|
|
;; function-documentation if we happen to advise `pcase'.
|
2019-02-27 16:01:15 +00:00
|
|
|
;;;###autoload
|
2015-03-23 22:24:30 +00:00
|
|
|
(put 'pcase 'function-documentation '(pcase--make-docstring))
|
2019-02-27 16:01:15 +00:00
|
|
|
;;;###autoload
|
2015-03-23 22:24:30 +00:00
|
|
|
(defun pcase--make-docstring ()
|
|
|
|
(let* ((main (documentation (symbol-function 'pcase) 'raw))
|
|
|
|
(ud (help-split-fundoc main 'pcase)))
|
2015-05-01 17:39:23 +00:00
|
|
|
;; So that eg emacs -Q -l cl-lib --eval "(documentation 'pcase)" works,
|
|
|
|
;; where cl-lib is anything using pcase-defmacro.
|
|
|
|
(require 'help-fns)
|
2015-03-23 22:24:30 +00:00
|
|
|
(with-temp-buffer
|
|
|
|
(insert (or (cdr ud) main))
|
2018-05-21 14:57:49 +00:00
|
|
|
;; 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)
|
2019-06-26 14:24:59 +00:00
|
|
|
(let ((me (get symbol 'pcase-macroexpander)))
|
2018-05-21 14:57:49 +00:00
|
|
|
(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.")))))
|
2015-03-23 22:24:30 +00:00
|
|
|
(let ((combined-doc (buffer-string)))
|
|
|
|
(if ud (help-add-fundoc-usage combined-doc (car ud)) combined-doc)))))
|
|
|
|
|
2014-09-13 16:30:21 +00:00
|
|
|
;;;###autoload
|
|
|
|
(defmacro pcase-exhaustive (exp &rest cases)
|
2018-03-31 04:40:43 +00:00
|
|
|
"The exhaustive version of `pcase' (which see).
|
|
|
|
If EXP fails to match any of the patterns in CASES, an error is signaled."
|
2014-09-13 16:30:21 +00:00
|
|
|
(declare (indent 1) (debug pcase))
|
2017-09-12 15:08:00 +00:00
|
|
|
(let* ((x (gensym "x"))
|
2014-09-13 16:30:21 +00:00
|
|
|
(pcase--dontwarn-upats (cons x pcase--dontwarn-upats)))
|
|
|
|
(pcase--expand
|
2014-09-22 14:30:47 +00:00
|
|
|
;; FIXME: Could we add the FILE:LINE data in the error message?
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 15:41:44 +00:00
|
|
|
exp (append cases `((,x (error "No clause matching `%S'" ,x)))))))
|
2014-09-13 16:30:21 +00:00
|
|
|
|
2015-02-09 02:05:44 +00:00
|
|
|
;;;###autoload
|
|
|
|
(defmacro pcase-lambda (lambda-list &rest body)
|
2015-05-25 02:38:05 +00:00
|
|
|
"Like `lambda' but allow each argument to be a pattern.
|
2015-03-19 17:46:36 +00:00
|
|
|
I.e. accepts the usual &optional and &rest keywords, but every
|
|
|
|
formal argument can be any pattern accepted by `pcase' (a mere
|
|
|
|
variable name being but a special case of it)."
|
2015-02-09 02:05:44 +00:00
|
|
|
(declare (doc-string 2) (indent defun)
|
2017-10-06 18:30:22 +00:00
|
|
|
(debug (&define (&rest pcase-PAT) lambda-doc def-body)))
|
2015-03-19 17:46:36 +00:00
|
|
|
(let* ((bindings ())
|
|
|
|
(parsed-body (macroexp-parse-body body))
|
|
|
|
(args (mapcar (lambda (pat)
|
|
|
|
(if (symbolp pat)
|
|
|
|
;; Simple vars and &rest/&optional are just passed
|
|
|
|
;; through unchanged.
|
|
|
|
pat
|
|
|
|
(let ((arg (make-symbol
|
|
|
|
(format "arg%s" (length bindings)))))
|
|
|
|
(push `(,pat ,arg) bindings)
|
|
|
|
arg)))
|
|
|
|
lambda-list)))
|
|
|
|
`(lambda ,args ,@(car parsed-body)
|
|
|
|
(pcase-let* ,(nreverse bindings) ,@(cdr parsed-body)))))
|
2015-02-09 02:05:44 +00:00
|
|
|
|
2012-06-11 00:33:33 +00:00
|
|
|
(defun pcase--let* (bindings body)
|
|
|
|
(cond
|
|
|
|
((null bindings) (macroexp-progn body))
|
|
|
|
((pcase--trivial-upat-p (caar bindings))
|
|
|
|
(macroexp-let* `(,(car bindings)) (pcase--let* (cdr bindings) body)))
|
|
|
|
(t
|
|
|
|
(let ((binding (pop bindings)))
|
|
|
|
(pcase--expand
|
|
|
|
(cadr binding)
|
|
|
|
`((,(car binding) ,(pcase--let* bindings body))
|
More CL cleanups and reduction of use of cl.el.
* woman.el, winner.el, vc/vc-rcs.el, vc/vc-hooks.el, vc/vc-hg.el:
* vc/vc-git.el, vc/vc-dir.el, vc/vc-bzr.el, vc/vc-annotate.el:
* textmodes/tex-mode.el, textmodes/sgml-mode.el, tar-mode.el:
* strokes.el, ses.el, server.el, progmodes/js.el, progmodes/gdb-mi.el:
* progmodes/flymake.el, progmodes/ebrowse.el, progmodes/compile.el:
* play/tetris.el, play/snake.el, play/pong.el, play/landmark.el:
* play/hanoi.el, play/decipher.el, play/5x5.el, nxml/nxml-mode.el:
* net/secrets.el, net/quickurl.el, midnight.el, mail/footnote.el:
* image-dired.el, ibuffer.el, ibuf-macs.el, ibuf-ext.el, hexl.el:
* eshell/eshell.el, eshell/esh-io.el, eshell/esh-ext.el:
* eshell/esh-cmd.el, eshell/em-ls.el, eshell/em-hist.el:
* eshell/em-cmpl.el, eshell/em-banner.el:
* url/url.el, url/url-queue.el, url/url-parse.el, url/url-http.el:
* url/url-future.el, url/url-dav.el, url/url-cookie.el:
* calendar/parse-time.el, test/eshell.el: Use cl-lib.
* wid-browse.el, wdired.el, vc/vc.el, vc/vc-mtn.el, vc/vc-cvs.el:
* vc/vc-arch.el, tree-widget.el, textmodes/texinfo.el:
* textmodes/refill.el, textmodes/css-mode.el, term/tvi970.el:
* term/ns-win.el, term.el, shell.el, ps-samp.el:
* progmodes/perl-mode.el, progmodes/pascal.el, progmodes/gud.el:
* progmodes/glasses.el, progmodes/etags.el, progmodes/cwarn.el:
* play/gamegrid.el, play/bubbles.el, novice.el, notifications.el:
* net/zeroconf.el, net/xesam.el, net/snmp-mode.el, net/mairix.el:
* net/ldap.el, net/eudc.el, net/browse-url.el, man.el:
* mail/mailheader.el, mail/feedmail.el:
* url/url-util.el, url/url-privacy.el, url/url-nfs.el, url/url-misc.el:
* url/url-methods.el, url/url-gw.el, url/url-file.el, url/url-expand.el:
Dont use CL.
* ibuf-ext.el (ibuffer-mark-old-buffers): Use float-time.
* eshell/esh-opt.el (eshell-eval-using-options): Quote code with
`lambda' rather than with `quote'.
(eshell-do-opt): Adjust accordingly.
(eshell-process-option): Simplify.
* eshell/esh-var.el:
* eshell/em-script.el: Require `esh-opt' for eshell-eval-using-options.
* emacs-pcase.el (pcase--dontcare-upats, pcase--let*)
(pcase--expand, pcase--u1): Rename pcase's internal `dontcare' pattern
to `pcase--dontcare'.
* emacs-cl.el (labels): Mark obsolete.
(cl--letf, letf): Move to cl-lib.
(cl--letf*, letf*): Remove.
* emacs-cl-lib.el (cl-nth-value): Use defalias.
* emacs-cl-macs.el (cl-dolist, cl-dotimes): Add indent rule.
(cl-progv): Rewrite.
(cl--letf, cl-letf): Move from cl.el.
(cl-letf*): New macro.
* emacs-cl-extra.el (cl--progv-before, cl--progv-after): Remove.
2012-07-11 23:13:41 +00:00
|
|
|
;; We can either signal an error here, or just use `pcase--dontcare'
|
|
|
|
;; which generates more efficient code. In practice, if we use
|
|
|
|
;; `pcase--dontcare' we will still often get an error and the few
|
|
|
|
;; cases where we don't do not matter that much, so
|
|
|
|
;; it's a better choice.
|
|
|
|
(pcase--dontcare nil)))))))
|
2012-06-11 00:33:33 +00:00
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;;;###autoload
|
2010-11-24 16:39:51 +00:00
|
|
|
(defmacro pcase-let* (bindings &rest body)
|
2018-11-03 13:11:33 +00:00
|
|
|
"Like `let*', but supports destructuring BINDINGS using `pcase' patterns.
|
|
|
|
As with `pcase-let', BINDINGS are of the form (PATTERN EXP), but the
|
|
|
|
EXP in each binding in BINDINGS can use the results of the destructuring
|
|
|
|
bindings that precede it in BINDINGS' order.
|
|
|
|
|
|
|
|
Each EXP should match (i.e. be of compatible structure) to its
|
|
|
|
respective PATTERN; a mismatch may signal an error or may go
|
|
|
|
undetected, binding variables to arbitrary values, such as nil."
|
2012-05-15 18:45:27 +00:00
|
|
|
(declare (indent 1)
|
2015-05-25 02:38:05 +00:00
|
|
|
(debug ((&rest (pcase-PAT &optional form)) body)))
|
2012-06-11 00:33:33 +00:00
|
|
|
(let ((cached (gethash bindings pcase--memoize)))
|
|
|
|
;; cached = (BODY . EXPANSION)
|
|
|
|
(if (equal (car cached) body)
|
|
|
|
(cdr cached)
|
|
|
|
(let ((expansion (pcase--let* bindings body)))
|
|
|
|
(puthash bindings (cons body expansion) pcase--memoize)
|
|
|
|
expansion))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
|
|
|
;;;###autoload
|
2010-11-24 16:39:51 +00:00
|
|
|
(defmacro pcase-let (bindings &rest body)
|
2018-11-03 13:11:33 +00:00
|
|
|
"Like `let', but supports destructuring BINDINGS using `pcase' patterns.
|
|
|
|
BODY should be a list of expressions, and BINDINGS should be a list of
|
|
|
|
bindings of the form (PATTERN EXP).
|
|
|
|
All EXPs are evaluated first, and then used to perform destructuring
|
|
|
|
bindings by matching each EXP against its respective PATTERN. Then
|
|
|
|
BODY is evaluated with those bindings in effect.
|
|
|
|
|
|
|
|
Each EXP should match (i.e. be of compatible structure) to its
|
|
|
|
respective PATTERN; a mismatch may signal an error or may go
|
|
|
|
undetected, binding variables to arbitrary values, such as nil."
|
2012-05-15 18:45:27 +00:00
|
|
|
(declare (indent 1) (debug pcase-let*))
|
2010-08-10 13:18:14 +00:00
|
|
|
(if (null (cdr bindings))
|
2010-11-24 16:39:51 +00:00
|
|
|
`(pcase-let* ,bindings ,@body)
|
|
|
|
(let ((matches '()))
|
|
|
|
(dolist (binding (prog1 bindings (setq bindings nil)))
|
|
|
|
(cond
|
|
|
|
((memq (car binding) pcase--dontcare-upats)
|
|
|
|
(push (cons (make-symbol "_") (cdr binding)) bindings))
|
|
|
|
((pcase--trivial-upat-p (car binding)) (push binding bindings))
|
|
|
|
(t
|
|
|
|
(let ((tmpvar (make-symbol (format "x%d" (length bindings)))))
|
|
|
|
(push (cons tmpvar (cdr binding)) bindings)
|
|
|
|
(push (list (car binding) tmpvar) matches)))))
|
|
|
|
`(let ,(nreverse bindings) (pcase-let* ,matches ,@body)))))
|
|
|
|
|
2015-04-13 18:46:58 +00:00
|
|
|
;;;###autoload
|
2010-11-24 16:39:51 +00:00
|
|
|
(defmacro pcase-dolist (spec &rest body)
|
2018-11-03 13:11:33 +00:00
|
|
|
"Eval BODY once for each set of bindings defined by PATTERN and LIST elements.
|
|
|
|
PATTERN should be a `pcase' pattern describing the structure of
|
|
|
|
LIST elements, and LIST is a list of objects that match PATTERN,
|
|
|
|
i.e. have a structure that is compatible with PATTERN.
|
|
|
|
For each element of LIST, this macro binds the variables in
|
|
|
|
PATTERN to the corresponding subfields of the LIST element, and
|
|
|
|
then evaluates BODY with these bindings in effect. The
|
|
|
|
destructuring bindings of variables in PATTERN to the subfields
|
|
|
|
of the elements of LIST is performed as if by `pcase-let'.
|
2016-11-04 14:23:46 +00:00
|
|
|
\n(fn (PATTERN LIST) BODY...)"
|
2015-05-25 02:38:05 +00:00
|
|
|
(declare (indent 1) (debug ((pcase-PAT form) body)))
|
2010-11-24 16:39:51 +00:00
|
|
|
(if (pcase--trivial-upat-p (car spec))
|
|
|
|
`(dolist ,spec ,@body)
|
2017-09-12 15:08:00 +00:00
|
|
|
(let ((tmpvar (gensym "x")))
|
2010-11-24 16:39:51 +00:00
|
|
|
`(dolist (,tmpvar ,@(cdr spec))
|
|
|
|
(pcase-let* ((,(car spec) ,tmpvar))
|
|
|
|
,@body)))))
|
|
|
|
|
|
|
|
|
|
|
|
(defun pcase--trivial-upat-p (upat)
|
|
|
|
(and (symbolp upat) (not (memq upat pcase--dontcare-upats))))
|
|
|
|
|
|
|
|
(defun pcase--expand (exp cases)
|
2011-03-06 04:48:17 +00:00
|
|
|
;; (message "pid=%S (pcase--expand %S ...hash=%S)"
|
|
|
|
;; (emacs-pid) exp (sxhash cases))
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 13:42:38 +00:00
|
|
|
(macroexp-let2 macroexp-copyable-p val exp
|
2012-06-11 00:33:33 +00:00
|
|
|
(let* ((defs ())
|
|
|
|
(seen '())
|
|
|
|
(codegen
|
|
|
|
(lambda (code vars)
|
|
|
|
(let ((prev (assq code seen)))
|
|
|
|
(if (not prev)
|
|
|
|
(let ((res (pcase-codegen code vars)))
|
|
|
|
(push (list code vars res) seen)
|
|
|
|
res)
|
|
|
|
;; Since we use a tree-based pattern matching
|
|
|
|
;; technique, the leaves (the places that contain the
|
|
|
|
;; code to run once a pattern is matched) can get
|
|
|
|
;; copied a very large number of times, so to avoid
|
|
|
|
;; code explosion, we need to keep track of how many
|
|
|
|
;; times we've used each leaf and move it
|
|
|
|
;; to a separate function if that number is too high.
|
|
|
|
;;
|
|
|
|
;; We've already used this branch. So it is shared.
|
2016-05-30 20:35:00 +00:00
|
|
|
(let* ((code (car prev)) (cdrprev (cdr prev))
|
2012-06-11 00:33:33 +00:00
|
|
|
(prevvars (car cdrprev)) (cddrprev (cdr cdrprev))
|
|
|
|
(res (car cddrprev)))
|
|
|
|
(unless (symbolp res)
|
|
|
|
;; This is the first repeat, so we have to move
|
|
|
|
;; the branch to a separate function.
|
|
|
|
(let ((bsym
|
|
|
|
(make-symbol (format "pcase-%d" (length defs)))))
|
2012-06-18 19:23:35 +00:00
|
|
|
(push `(,bsym (lambda ,(mapcar #'car prevvars) ,@code))
|
|
|
|
defs)
|
2012-06-11 00:33:33 +00:00
|
|
|
(setcar res 'funcall)
|
|
|
|
(setcdr res (cons bsym (mapcar #'cdr prevvars)))
|
|
|
|
(setcar (cddr prev) bsym)
|
|
|
|
(setq res bsym)))
|
|
|
|
(setq vars (copy-sequence vars))
|
|
|
|
(let ((args (mapcar (lambda (pa)
|
|
|
|
(let ((v (assq (car pa) vars)))
|
|
|
|
(setq vars (delq v vars))
|
|
|
|
(cdr v)))
|
|
|
|
prevvars)))
|
|
|
|
;; If some of `vars' were not found in `prevvars', that's
|
|
|
|
;; OK it just means those vars aren't present in all
|
|
|
|
;; branches, so they can be used within the pattern
|
|
|
|
;; (e.g. by a `guard/let/pred') but not in the branch.
|
|
|
|
;; FIXME: But if some of `prevvars' are not in `vars' we
|
|
|
|
;; should remove them from `prevvars'!
|
|
|
|
`(funcall ,res ,@args)))))))
|
2012-06-18 19:23:35 +00:00
|
|
|
(used-cases ())
|
2012-06-11 00:33:33 +00:00
|
|
|
(main
|
|
|
|
(pcase--u
|
|
|
|
(mapcar (lambda (case)
|
2014-09-22 16:22:50 +00:00
|
|
|
`(,(pcase--match val (pcase--macroexpand (car case)))
|
2012-06-18 19:23:35 +00:00
|
|
|
,(lambda (vars)
|
|
|
|
(unless (memq case used-cases)
|
|
|
|
;; Keep track of the cases that are used.
|
|
|
|
(push case used-cases))
|
|
|
|
(funcall
|
|
|
|
(if (pcase--small-branch-p (cdr case))
|
|
|
|
;; Don't bother sharing multiple
|
|
|
|
;; occurrences of this leaf since it's small.
|
|
|
|
#'pcase-codegen codegen)
|
|
|
|
(cdr case)
|
|
|
|
vars))))
|
2012-06-11 00:33:33 +00:00
|
|
|
cases))))
|
2012-06-18 19:23:35 +00:00
|
|
|
(dolist (case cases)
|
2014-09-13 16:30:21 +00:00
|
|
|
(unless (or (memq case used-cases)
|
|
|
|
(memq (car case) pcase--dontwarn-upats))
|
2012-06-18 19:23:35 +00:00
|
|
|
(message "Redundant pcase pattern: %S" (car case))))
|
2012-06-07 19:25:48 +00:00
|
|
|
(macroexp-let* defs main))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2014-09-22 15:04:12 +00:00
|
|
|
(defun pcase--macroexpand (pat)
|
|
|
|
"Expands all macro-patterns in PAT."
|
|
|
|
(let ((head (car-safe pat)))
|
|
|
|
(cond
|
2014-09-22 16:22:50 +00:00
|
|
|
((null head)
|
|
|
|
(if (pcase--self-quoting-p pat) `',pat pat))
|
2014-09-22 17:24:46 +00:00
|
|
|
((memq head '(pred guard quote)) pat)
|
2014-09-22 15:04:12 +00:00
|
|
|
((memq head '(or and)) `(,head ,@(mapcar #'pcase--macroexpand (cdr pat))))
|
|
|
|
((eq head 'let) `(let ,(pcase--macroexpand (cadr pat)) ,@(cddr pat)))
|
|
|
|
((eq head 'app) `(app ,(nth 1 pat) ,(pcase--macroexpand (nth 2 pat))))
|
|
|
|
(t
|
2019-06-26 14:24:59 +00:00
|
|
|
(let* ((expander (get head 'pcase-macroexpander))
|
2014-09-22 15:04:12 +00:00
|
|
|
(npat (if expander (apply expander (cdr pat)))))
|
|
|
|
(if (null npat)
|
|
|
|
(error (if expander
|
|
|
|
"Unexpandable %s pattern: %S"
|
|
|
|
"Unknown %s pattern: %S")
|
|
|
|
head pat)
|
|
|
|
(pcase--macroexpand npat)))))))
|
|
|
|
|
|
|
|
;;;###autoload
|
|
|
|
(defmacro pcase-defmacro (name args &rest body)
|
2015-05-25 02:38:05 +00:00
|
|
|
"Define a new kind of pcase PATTERN, by macro expansion.
|
|
|
|
Patterns of the form (NAME ...) will be expanded according
|
2018-05-21 15:11:55 +00:00
|
|
|
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...)"
|
2015-03-23 22:24:30 +00:00
|
|
|
(declare (indent 2) (debug defun) (doc-string 3))
|
2015-04-12 14:26:52 +00:00
|
|
|
;; Add the function via `fsym', so that an autoload cookie placed
|
|
|
|
;; on a pcase-defmacro will cause the macro to be loaded on demand.
|
|
|
|
(let ((fsym (intern (format "%s--pcase-macroexpander" name)))
|
|
|
|
(decl (assq 'declare body)))
|
|
|
|
(when decl (setq body (remove decl body)))
|
2015-03-23 22:24:30 +00:00
|
|
|
`(progn
|
|
|
|
(defun ,fsym ,args ,@body)
|
2017-07-28 16:02:01 +00:00
|
|
|
(define-symbol-prop ',fsym 'edebug-form-spec ',(cadr (assq 'debug decl)))
|
|
|
|
(define-symbol-prop ',name 'pcase-macroexpander #',fsym))))
|
2014-09-22 15:04:12 +00:00
|
|
|
|
2014-09-22 16:22:50 +00:00
|
|
|
(defun pcase--match (val upat)
|
|
|
|
"Build a MATCH structure, hoisting all `or's and `and's outside."
|
|
|
|
(cond
|
|
|
|
;; Hoist or/and patterns into or/and matches.
|
|
|
|
((memq (car-safe upat) '(or and))
|
|
|
|
`(,(car upat)
|
|
|
|
,@(mapcar (lambda (upat)
|
|
|
|
(pcase--match val upat))
|
|
|
|
(cdr upat))))
|
|
|
|
(t
|
|
|
|
`(match ,val . ,upat))))
|
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
(defun pcase-codegen (code vars)
|
2012-06-07 19:25:48 +00:00
|
|
|
;; Don't use let*, otherwise macroexp-let* may merge it with some surrounding
|
2012-05-29 14:28:02 +00:00
|
|
|
;; let* which might prevent the setcar/setcdr in pcase--expand's fancy
|
|
|
|
;; codegen from later metamorphosing this let into a funcall.
|
2017-02-16 01:40:46 +00:00
|
|
|
(if vars
|
|
|
|
`(let ,(mapcar (lambda (b) (list (car b) (cdr b))) vars)
|
|
|
|
,@code)
|
|
|
|
`(progn ,@code)))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--small-branch-p (code)
|
2010-08-10 13:18:14 +00:00
|
|
|
(and (= 1 (length code))
|
|
|
|
(or (not (consp (car code)))
|
|
|
|
(let ((small t))
|
|
|
|
(dolist (e (car code))
|
|
|
|
(if (consp e) (setq small nil)))
|
|
|
|
small))))
|
|
|
|
|
|
|
|
;; Try to use `cond' rather than a sequence of `if's, so as to reduce
|
|
|
|
;; the depth of the generated tree.
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--if (test then else)
|
2010-08-10 13:18:14 +00:00
|
|
|
(cond
|
2010-11-24 16:39:51 +00:00
|
|
|
((eq else :pcase--dontcare) then)
|
2011-02-27 02:50:38 +00:00
|
|
|
((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen?
|
2016-05-30 20:35:00 +00:00
|
|
|
(t (macroexp-if test then else))))
|
2012-05-05 02:05:49 +00:00
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;; Note about MATCH:
|
|
|
|
;; When we have patterns like `(PAT1 . PAT2), after performing the `consp'
|
|
|
|
;; check, we want to turn all the similar patterns into ones of the form
|
|
|
|
;; (and (match car PAT1) (match cdr PAT2)), so you naturally need conjunction.
|
|
|
|
;; Earlier code hence used branches of the form (MATCHES . CODE) where
|
|
|
|
;; MATCHES was a list (implicitly a conjunction) of (SYM . PAT).
|
|
|
|
;; But if we have a pattern of the form (or `(PAT1 . PAT2) PAT3), there is
|
|
|
|
;; no easy way to eliminate the `consp' check in such a representation.
|
|
|
|
;; So we replaced the MATCHES by the MATCH below which can be made up
|
|
|
|
;; of conjunctions and disjunctions, so if we know `foo' is a cons, we can
|
|
|
|
;; turn (match foo . (or `(PAT1 . PAT2) PAT3)) into
|
|
|
|
;; (or (and (match car . `PAT1) (match cdr . `PAT2)) (match foo . PAT3)).
|
|
|
|
;; The downside is that we now have `or' and `and' both in MATCH and
|
|
|
|
;; in PAT, so there are different equivalent representations and we
|
|
|
|
;; need to handle them all. We do not try to systematically
|
|
|
|
;; canonicalize them to one form over another, but we do occasionally
|
|
|
|
;; turn one into the other.
|
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--u (branches)
|
2010-08-10 13:18:14 +00:00
|
|
|
"Expand matcher for rules BRANCHES.
|
|
|
|
Each BRANCH has the form (MATCH CODE . VARS) where
|
|
|
|
CODE is the code generator for that branch.
|
|
|
|
VARS is the set of vars already bound by earlier matches.
|
|
|
|
MATCH is the pattern that needs to be matched, of the form:
|
2015-05-25 02:38:05 +00:00
|
|
|
(match VAR . PAT)
|
2010-08-10 13:18:14 +00:00
|
|
|
(and MATCH ...)
|
|
|
|
(or MATCH ...)"
|
|
|
|
(when (setq branches (delq nil branches))
|
2011-02-18 13:55:51 +00:00
|
|
|
(let* ((carbranch (car branches))
|
|
|
|
(match (car carbranch)) (cdarbranch (cdr carbranch))
|
|
|
|
(code (car cdarbranch))
|
|
|
|
(vars (cdr cdarbranch)))
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--u1 (list match) code vars (cdr branches)))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--and (match matches)
|
2010-08-10 13:18:14 +00:00
|
|
|
(if matches `(and ,match ,@matches) match))
|
|
|
|
|
2011-02-27 02:50:38 +00:00
|
|
|
(defconst pcase-mutually-exclusive-predicates
|
|
|
|
'((symbolp . integerp)
|
|
|
|
(symbolp . numberp)
|
|
|
|
(symbolp . consp)
|
|
|
|
(symbolp . arrayp)
|
2013-08-04 20:18:11 +00:00
|
|
|
(symbolp . vectorp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(symbolp . stringp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(symbolp . byte-code-function-p)
|
2017-03-16 02:48:28 +00:00
|
|
|
(symbolp . recordp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(integerp . consp)
|
|
|
|
(integerp . arrayp)
|
2013-08-04 20:18:11 +00:00
|
|
|
(integerp . vectorp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(integerp . stringp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(integerp . byte-code-function-p)
|
2017-03-16 02:48:28 +00:00
|
|
|
(integerp . recordp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(numberp . consp)
|
|
|
|
(numberp . arrayp)
|
2013-08-04 20:18:11 +00:00
|
|
|
(numberp . vectorp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(numberp . stringp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(numberp . byte-code-function-p)
|
2017-03-16 02:48:28 +00:00
|
|
|
(numberp . recordp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(consp . arrayp)
|
2016-05-30 20:33:07 +00:00
|
|
|
(consp . atom)
|
2013-08-04 20:18:11 +00:00
|
|
|
(consp . vectorp)
|
2011-02-27 02:50:38 +00:00
|
|
|
(consp . stringp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(consp . byte-code-function-p)
|
2017-03-16 02:48:28 +00:00
|
|
|
(consp . recordp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(arrayp . byte-code-function-p)
|
2013-08-04 20:18:11 +00:00
|
|
|
(vectorp . byte-code-function-p)
|
2017-03-16 02:48:28 +00:00
|
|
|
(vectorp . recordp)
|
2013-08-04 20:18:11 +00:00
|
|
|
(stringp . vectorp)
|
2017-03-16 02:48:28 +00:00
|
|
|
(stringp . recordp)
|
2011-03-16 20:08:39 +00:00
|
|
|
(stringp . byte-code-function-p)))
|
2011-02-27 02:50:38 +00:00
|
|
|
|
2013-08-04 20:18:11 +00:00
|
|
|
(defun pcase--mutually-exclusive-p (pred1 pred2)
|
|
|
|
(or (member (cons pred1 pred2)
|
|
|
|
pcase-mutually-exclusive-predicates)
|
|
|
|
(member (cons pred2 pred1)
|
|
|
|
pcase-mutually-exclusive-predicates)))
|
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--split-match (sym splitter match)
|
2011-02-18 13:55:51 +00:00
|
|
|
(cond
|
2014-09-27 04:24:06 +00:00
|
|
|
((eq (car-safe match) 'match)
|
2010-08-10 13:18:14 +00:00
|
|
|
(if (not (eq sym (cadr match)))
|
|
|
|
(cons match match)
|
2014-09-22 16:22:50 +00:00
|
|
|
(let ((res (funcall splitter (cddr match))))
|
|
|
|
(cons (or (car res) match) (or (cdr res) match)))))
|
2014-09-27 04:24:06 +00:00
|
|
|
((memq (car-safe match) '(or and))
|
2010-08-10 13:18:14 +00:00
|
|
|
(let ((then-alts '())
|
|
|
|
(else-alts '())
|
2010-11-24 16:39:51 +00:00
|
|
|
(neutral-elem (if (eq 'or (car match))
|
|
|
|
:pcase--fail :pcase--succeed))
|
|
|
|
(zero-elem (if (eq 'or (car match)) :pcase--succeed :pcase--fail)))
|
2010-08-10 13:18:14 +00:00
|
|
|
(dolist (alt (cdr match))
|
2010-11-24 16:39:51 +00:00
|
|
|
(let ((split (pcase--split-match sym splitter alt)))
|
2010-08-10 13:18:14 +00:00
|
|
|
(unless (eq (car split) neutral-elem)
|
|
|
|
(push (car split) then-alts))
|
|
|
|
(unless (eq (cdr split) neutral-elem)
|
|
|
|
(push (cdr split) else-alts))))
|
|
|
|
(cons (cond ((memq zero-elem then-alts) zero-elem)
|
|
|
|
((null then-alts) neutral-elem)
|
|
|
|
((null (cdr then-alts)) (car then-alts))
|
|
|
|
(t (cons (car match) (nreverse then-alts))))
|
|
|
|
(cond ((memq zero-elem else-alts) zero-elem)
|
|
|
|
((null else-alts) neutral-elem)
|
|
|
|
((null (cdr else-alts)) (car else-alts))
|
|
|
|
(t (cons (car match) (nreverse else-alts)))))))
|
2014-09-27 04:24:06 +00:00
|
|
|
((memq match '(:pcase--succeed :pcase--fail)) (cons match match))
|
2010-08-10 13:18:14 +00:00
|
|
|
(t (error "Uknown MATCH %s" match))))
|
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--split-rest (sym splitter rest)
|
2010-08-10 13:18:14 +00:00
|
|
|
(let ((then-rest '())
|
|
|
|
(else-rest '()))
|
|
|
|
(dolist (branch rest)
|
|
|
|
(let* ((match (car branch))
|
|
|
|
(code&vars (cdr branch))
|
2011-12-15 07:24:10 +00:00
|
|
|
(split
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--split-match sym splitter match)))
|
2011-12-15 07:24:10 +00:00
|
|
|
(unless (eq (car split) :pcase--fail)
|
|
|
|
(push (cons (car split) code&vars) then-rest))
|
|
|
|
(unless (eq (cdr split) :pcase--fail)
|
|
|
|
(push (cons (cdr split) code&vars) else-rest))))
|
2010-08-10 13:18:14 +00:00
|
|
|
(cons (nreverse then-rest) (nreverse else-rest))))
|
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--split-equal (elem pat)
|
2010-08-10 13:18:14 +00:00
|
|
|
(cond
|
|
|
|
;; The same match will give the same result.
|
2014-09-22 17:24:46 +00:00
|
|
|
((and (eq (car-safe pat) 'quote) (equal (cadr pat) elem))
|
2013-01-08 22:26:21 +00:00
|
|
|
'(:pcase--succeed . :pcase--fail))
|
2010-08-10 13:18:14 +00:00
|
|
|
;; A different match will fail if this one succeeds.
|
2014-09-22 17:24:46 +00:00
|
|
|
((and (eq (car-safe pat) 'quote)
|
2010-08-10 13:18:14 +00:00
|
|
|
;; (or (integerp (cadr pat)) (symbolp (cadr pat))
|
|
|
|
;; (consp (cadr pat)))
|
|
|
|
)
|
2013-01-08 22:26:21 +00:00
|
|
|
'(:pcase--fail . nil))
|
2011-02-27 02:50:38 +00:00
|
|
|
((and (eq (car-safe pat) 'pred)
|
|
|
|
(symbolp (cadr pat))
|
2013-01-08 22:26:21 +00:00
|
|
|
(get (cadr pat) 'side-effect-free))
|
2014-01-03 04:40:30 +00:00
|
|
|
(ignore-errors
|
|
|
|
(if (funcall (cadr pat) elem)
|
|
|
|
'(:pcase--succeed . nil)
|
|
|
|
'(:pcase--fail . nil))))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--split-member (elems pat)
|
2014-09-22 17:24:46 +00:00
|
|
|
;; FIXME: The new pred-based member code doesn't do these optimizations!
|
2010-11-24 16:39:51 +00:00
|
|
|
;; Based on pcase--split-equal.
|
2010-08-10 13:18:14 +00:00
|
|
|
(cond
|
2010-10-29 01:05:38 +00:00
|
|
|
;; The same match (or a match of membership in a superset) will
|
|
|
|
;; give the same result, but we don't know how to check it.
|
2010-09-01 10:03:08 +00:00
|
|
|
;; (???
|
2013-01-08 22:26:21 +00:00
|
|
|
;; '(:pcase--succeed . nil))
|
2010-09-01 10:03:08 +00:00
|
|
|
;; A match for one of the elements may succeed or fail.
|
2014-09-22 17:24:46 +00:00
|
|
|
((and (eq (car-safe pat) 'quote) (member (cadr pat) elems))
|
2010-09-01 10:03:08 +00:00
|
|
|
nil)
|
2010-08-10 13:18:14 +00:00
|
|
|
;; A different match will fail if this one succeeds.
|
2014-09-22 17:24:46 +00:00
|
|
|
((and (eq (car-safe pat) 'quote)
|
2010-08-10 13:18:14 +00:00
|
|
|
;; (or (integerp (cadr pat)) (symbolp (cadr pat))
|
|
|
|
;; (consp (cadr pat)))
|
|
|
|
)
|
2013-01-08 22:26:21 +00:00
|
|
|
'(:pcase--fail . nil))
|
2011-02-27 02:50:38 +00:00
|
|
|
((and (eq (car-safe pat) 'pred)
|
|
|
|
(symbolp (cadr pat))
|
|
|
|
(get (cadr pat) 'side-effect-free)
|
2014-01-03 04:40:30 +00:00
|
|
|
(ignore-errors
|
|
|
|
(let ((p (cadr pat)) (all t))
|
|
|
|
(dolist (elem elems)
|
|
|
|
(unless (funcall p elem) (setq all nil)))
|
|
|
|
all)))
|
2013-01-08 22:26:21 +00:00
|
|
|
'(:pcase--succeed . nil))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2013-07-08 21:54:54 +00:00
|
|
|
(defun pcase--split-pred (vars upat pat)
|
2012-05-05 02:05:49 +00:00
|
|
|
(let (test)
|
|
|
|
(cond
|
2013-07-08 21:54:54 +00:00
|
|
|
((and (equal upat pat)
|
|
|
|
;; For predicates like (pred (> a)), two such predicates may
|
|
|
|
;; actually refer to different variables `a'.
|
|
|
|
(or (and (eq 'pred (car upat)) (symbolp (cadr upat)))
|
|
|
|
;; FIXME: `vars' gives us the environment in which `upat' will
|
|
|
|
;; run, but we don't have the environment in which `pat' will
|
|
|
|
;; run, so we can't do a reliable verification. But let's try
|
|
|
|
;; and catch at least the easy cases such as (bug#14773).
|
|
|
|
(not (pcase--fgrep (mapcar #'car vars) (cadr upat)))))
|
|
|
|
'(:pcase--succeed . :pcase--fail))
|
2012-05-05 02:05:49 +00:00
|
|
|
((and (eq 'pred (car upat))
|
2013-08-04 20:18:11 +00:00
|
|
|
(let ((otherpred
|
|
|
|
(cond ((eq 'pred (car-safe pat)) (cadr pat))
|
2014-09-22 17:24:46 +00:00
|
|
|
((not (eq 'quote (car-safe pat))) nil)
|
2013-08-04 20:18:11 +00:00
|
|
|
((consp (cadr pat)) #'consp)
|
2015-03-24 03:40:06 +00:00
|
|
|
((stringp (cadr pat)) #'stringp)
|
2013-08-04 20:18:11 +00:00
|
|
|
((vectorp (cadr pat)) #'vectorp)
|
|
|
|
((byte-code-function-p (cadr pat))
|
|
|
|
#'byte-code-function-p))))
|
|
|
|
(pcase--mutually-exclusive-p (cadr upat) otherpred)))
|
2013-01-08 22:26:21 +00:00
|
|
|
'(:pcase--fail . nil))
|
2012-05-05 02:05:49 +00:00
|
|
|
((and (eq 'pred (car upat))
|
2014-09-22 17:24:46 +00:00
|
|
|
(eq 'quote (car-safe pat))
|
2012-05-05 02:05:49 +00:00
|
|
|
(symbolp (cadr upat))
|
|
|
|
(or (symbolp (cadr pat)) (stringp (cadr pat)) (numberp (cadr pat)))
|
|
|
|
(get (cadr upat) 'side-effect-free)
|
|
|
|
(ignore-errors
|
|
|
|
(setq test (list (funcall (cadr upat) (cadr pat))))))
|
|
|
|
(if (car test)
|
2013-01-08 22:26:21 +00:00
|
|
|
'(nil . :pcase--fail)
|
|
|
|
'(:pcase--fail . nil))))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--fgrep (vars sexp)
|
2010-08-10 13:18:14 +00:00
|
|
|
"Check which of the symbols VARS appear in SEXP."
|
|
|
|
(let ((res '()))
|
|
|
|
(while (consp sexp)
|
2010-11-24 16:39:51 +00:00
|
|
|
(dolist (var (pcase--fgrep vars (pop sexp)))
|
2010-08-10 13:18:14 +00:00
|
|
|
(unless (memq var res) (push var res))))
|
|
|
|
(and (memq sexp vars) (not (memq sexp res)) (push sexp res))
|
|
|
|
res))
|
|
|
|
|
2012-07-10 09:26:04 +00:00
|
|
|
(defun pcase--self-quoting-p (upat)
|
2015-06-16 16:37:33 +00:00
|
|
|
(or (keywordp upat) (integerp upat) (stringp upat)))
|
2012-07-10 09:26:04 +00:00
|
|
|
|
2014-09-22 14:30:47 +00:00
|
|
|
(defun pcase--app-subst-match (match sym fun nsym)
|
|
|
|
(cond
|
2014-09-27 04:24:06 +00:00
|
|
|
((eq (car-safe match) 'match)
|
2014-09-22 14:30:47 +00:00
|
|
|
(if (and (eq sym (cadr match))
|
|
|
|
(eq 'app (car-safe (cddr match)))
|
|
|
|
(equal fun (nth 1 (cddr match))))
|
2014-09-22 16:22:50 +00:00
|
|
|
(pcase--match nsym (nth 2 (cddr match)))
|
2014-09-22 14:30:47 +00:00
|
|
|
match))
|
2014-09-27 04:24:06 +00:00
|
|
|
((memq (car-safe match) '(or and))
|
2014-09-22 14:30:47 +00:00
|
|
|
`(,(car match)
|
|
|
|
,@(mapcar (lambda (match)
|
|
|
|
(pcase--app-subst-match match sym fun nsym))
|
|
|
|
(cdr match))))
|
2014-09-27 04:24:06 +00:00
|
|
|
((memq match '(:pcase--succeed :pcase--fail)) match)
|
2014-09-22 14:30:47 +00:00
|
|
|
(t (error "Uknown MATCH %s" match))))
|
|
|
|
|
|
|
|
(defun pcase--app-subst-rest (rest sym fun nsym)
|
|
|
|
(mapcar (lambda (branch)
|
|
|
|
`(,(pcase--app-subst-match (car branch) sym fun nsym)
|
|
|
|
,@(cdr branch)))
|
|
|
|
rest))
|
|
|
|
|
2012-09-28 12:18:38 +00:00
|
|
|
(defsubst pcase--mark-used (sym)
|
|
|
|
;; Exceptionally, `sym' may be a constant expression rather than a symbol.
|
|
|
|
(if (symbolp sym) (put sym 'pcase-used t)))
|
|
|
|
|
2014-09-22 16:22:50 +00:00
|
|
|
(defmacro pcase--flip (fun arg1 arg2)
|
|
|
|
"Helper function, used internally to avoid (funcall (lambda ...) ...)."
|
|
|
|
(declare (debug (sexp body)))
|
|
|
|
`(,fun ,arg2 ,arg1))
|
|
|
|
|
2014-09-22 18:05:22 +00:00
|
|
|
(defun pcase--funcall (fun arg vars)
|
|
|
|
"Build a function call to FUN with arg ARG."
|
|
|
|
(if (symbolp fun)
|
|
|
|
`(,fun ,arg)
|
|
|
|
(let* (;; `vs' is an upper bound on the vars we need.
|
|
|
|
(vs (pcase--fgrep (mapcar #'car vars) fun))
|
|
|
|
(env (mapcar (lambda (var)
|
|
|
|
(list var (cdr (assq var vars))))
|
|
|
|
vs))
|
|
|
|
(call (progn
|
|
|
|
(when (memq arg vs)
|
|
|
|
;; `arg' is shadowed by `env'.
|
2017-09-12 15:08:00 +00:00
|
|
|
(let ((newsym (gensym "x")))
|
2014-09-22 18:05:22 +00:00
|
|
|
(push (list newsym arg) env)
|
|
|
|
(setq arg newsym)))
|
|
|
|
(if (functionp fun)
|
|
|
|
`(funcall #',fun ,arg)
|
|
|
|
`(,@fun ,arg)))))
|
|
|
|
(if (null vs)
|
|
|
|
call
|
|
|
|
;; Let's not replace `vars' in `fun' since it's
|
|
|
|
;; too difficult to do it right, instead just
|
|
|
|
;; let-bind `vars' around `fun'.
|
|
|
|
`(let* ,env ,call)))))
|
|
|
|
|
|
|
|
(defun pcase--eval (exp vars)
|
|
|
|
"Build an expression that will evaluate EXP."
|
|
|
|
(let* ((found (assq exp vars)))
|
|
|
|
(if found (cdr found)
|
|
|
|
(let* ((vs (pcase--fgrep (mapcar #'car vars) exp))
|
|
|
|
(env (mapcar (lambda (v) (list v (cdr (assq v vars))))
|
|
|
|
vs)))
|
|
|
|
(if env (macroexp-let* env exp) exp)))))
|
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
;; It's very tempting to use `pcase' below, tho obviously, it'd create
|
|
|
|
;; bootstrapping problems.
|
2010-11-24 16:39:51 +00:00
|
|
|
(defun pcase--u1 (matches code vars rest)
|
2010-08-10 13:18:14 +00:00
|
|
|
"Return code that runs CODE (with VARS) if MATCHES match.
|
2011-02-28 04:24:40 +00:00
|
|
|
Otherwise, it defers to REST which is a list of branches of the form
|
2010-08-10 13:18:14 +00:00
|
|
|
\(ELSE-MATCH ELSE-CODE . ELSE-VARS)."
|
|
|
|
;; Depending on the order in which we choose to check each of the MATCHES,
|
|
|
|
;; the resulting tree may be smaller or bigger. So in general, we'd want
|
|
|
|
;; to be careful to chose the "optimal" order. But predicate
|
|
|
|
;; patterns make this harder because they create dependencies
|
|
|
|
;; between matches. So we don't bother trying to reorder anything.
|
|
|
|
(cond
|
|
|
|
((null matches) (funcall code vars))
|
2010-11-24 16:39:51 +00:00
|
|
|
((eq :pcase--fail (car matches)) (pcase--u rest))
|
|
|
|
((eq :pcase--succeed (car matches))
|
|
|
|
(pcase--u1 (cdr matches) code vars rest))
|
2010-08-10 13:18:14 +00:00
|
|
|
((eq 'and (caar matches))
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--u1 (append (cdar matches) (cdr matches)) code vars rest))
|
2010-08-10 13:18:14 +00:00
|
|
|
((eq 'or (caar matches))
|
|
|
|
(let* ((alts (cdar matches))
|
|
|
|
(var (if (eq (caar alts) 'match) (cadr (car alts))))
|
2019-05-21 10:19:38 +00:00
|
|
|
(simples '()) (others '()) (mem-fun 'memq))
|
2010-08-10 13:18:14 +00:00
|
|
|
(when var
|
|
|
|
(dolist (alt alts)
|
|
|
|
(if (and (eq (car alt) 'match) (eq var (cadr alt))
|
|
|
|
(let ((upat (cddr alt)))
|
2014-09-22 16:22:50 +00:00
|
|
|
(eq (car-safe upat) 'quote)))
|
|
|
|
(let ((val (cadr (cddr alt))))
|
2019-05-21 10:19:38 +00:00
|
|
|
(cond ((integerp val)
|
|
|
|
(when (eq mem-fun 'memq)
|
|
|
|
(setq mem-fun 'memql)))
|
|
|
|
((not (symbolp val))
|
|
|
|
(setq mem-fun 'member)))
|
|
|
|
(push val simples))
|
2010-08-10 13:18:14 +00:00
|
|
|
(push alt others))))
|
|
|
|
(cond
|
2010-11-24 16:39:51 +00:00
|
|
|
((null alts) (error "Please avoid it") (pcase--u rest))
|
2019-03-12 12:19:35 +00:00
|
|
|
;; Yes, we can use `memql' (or `member')!
|
2010-08-10 13:18:14 +00:00
|
|
|
((> (length simples) 1)
|
2014-09-22 16:22:50 +00:00
|
|
|
(pcase--u1 (cons `(match ,var
|
2019-05-21 10:19:38 +00:00
|
|
|
. (pred (pcase--flip ,mem-fun ',simples)))
|
2014-09-22 16:22:50 +00:00
|
|
|
(cdr matches))
|
2010-11-24 16:39:51 +00:00
|
|
|
code vars
|
|
|
|
(if (null others) rest
|
2011-02-18 13:55:51 +00:00
|
|
|
(cons (cons
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--and (if (cdr others)
|
|
|
|
(cons 'or (nreverse others))
|
|
|
|
(car others))
|
|
|
|
(cdr matches))
|
2011-02-18 13:55:51 +00:00
|
|
|
(cons code vars))
|
2010-11-24 16:39:51 +00:00
|
|
|
rest))))
|
2010-08-10 13:18:14 +00:00
|
|
|
(t
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--u1 (cons (pop alts) (cdr matches)) code vars
|
|
|
|
(if (null alts) (progn (error "Please avoid it") rest)
|
2011-02-18 13:55:51 +00:00
|
|
|
(cons (cons
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--and (if (cdr alts)
|
|
|
|
(cons 'or alts) (car alts))
|
|
|
|
(cdr matches))
|
2011-02-18 13:55:51 +00:00
|
|
|
(cons code vars))
|
2010-11-24 16:39:51 +00:00
|
|
|
rest)))))))
|
2010-08-10 13:18:14 +00:00
|
|
|
((eq 'match (caar matches))
|
2011-02-18 13:55:51 +00:00
|
|
|
(let* ((popmatches (pop matches))
|
2011-03-01 05:03:24 +00:00
|
|
|
(_op (car popmatches)) (cdrpopmatches (cdr popmatches))
|
2011-02-18 13:55:51 +00:00
|
|
|
(sym (car cdrpopmatches))
|
|
|
|
(upat (cdr cdrpopmatches)))
|
2010-08-10 13:18:14 +00:00
|
|
|
(cond
|
2015-06-16 16:37:33 +00:00
|
|
|
((memq upat '(t _))
|
|
|
|
(let ((code (pcase--u1 matches code vars rest)))
|
|
|
|
(if (eq upat '_) code
|
2015-06-17 00:44:57 +00:00
|
|
|
(macroexp--warn-and-return
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 15:41:44 +00:00
|
|
|
"Pattern t is deprecated. Use `_' instead"
|
2015-06-17 00:44:57 +00:00
|
|
|
code))))
|
More CL cleanups and reduction of use of cl.el.
* woman.el, winner.el, vc/vc-rcs.el, vc/vc-hooks.el, vc/vc-hg.el:
* vc/vc-git.el, vc/vc-dir.el, vc/vc-bzr.el, vc/vc-annotate.el:
* textmodes/tex-mode.el, textmodes/sgml-mode.el, tar-mode.el:
* strokes.el, ses.el, server.el, progmodes/js.el, progmodes/gdb-mi.el:
* progmodes/flymake.el, progmodes/ebrowse.el, progmodes/compile.el:
* play/tetris.el, play/snake.el, play/pong.el, play/landmark.el:
* play/hanoi.el, play/decipher.el, play/5x5.el, nxml/nxml-mode.el:
* net/secrets.el, net/quickurl.el, midnight.el, mail/footnote.el:
* image-dired.el, ibuffer.el, ibuf-macs.el, ibuf-ext.el, hexl.el:
* eshell/eshell.el, eshell/esh-io.el, eshell/esh-ext.el:
* eshell/esh-cmd.el, eshell/em-ls.el, eshell/em-hist.el:
* eshell/em-cmpl.el, eshell/em-banner.el:
* url/url.el, url/url-queue.el, url/url-parse.el, url/url-http.el:
* url/url-future.el, url/url-dav.el, url/url-cookie.el:
* calendar/parse-time.el, test/eshell.el: Use cl-lib.
* wid-browse.el, wdired.el, vc/vc.el, vc/vc-mtn.el, vc/vc-cvs.el:
* vc/vc-arch.el, tree-widget.el, textmodes/texinfo.el:
* textmodes/refill.el, textmodes/css-mode.el, term/tvi970.el:
* term/ns-win.el, term.el, shell.el, ps-samp.el:
* progmodes/perl-mode.el, progmodes/pascal.el, progmodes/gud.el:
* progmodes/glasses.el, progmodes/etags.el, progmodes/cwarn.el:
* play/gamegrid.el, play/bubbles.el, novice.el, notifications.el:
* net/zeroconf.el, net/xesam.el, net/snmp-mode.el, net/mairix.el:
* net/ldap.el, net/eudc.el, net/browse-url.el, man.el:
* mail/mailheader.el, mail/feedmail.el:
* url/url-util.el, url/url-privacy.el, url/url-nfs.el, url/url-misc.el:
* url/url-methods.el, url/url-gw.el, url/url-file.el, url/url-expand.el:
Dont use CL.
* ibuf-ext.el (ibuffer-mark-old-buffers): Use float-time.
* eshell/esh-opt.el (eshell-eval-using-options): Quote code with
`lambda' rather than with `quote'.
(eshell-do-opt): Adjust accordingly.
(eshell-process-option): Simplify.
* eshell/esh-var.el:
* eshell/em-script.el: Require `esh-opt' for eshell-eval-using-options.
* emacs-pcase.el (pcase--dontcare-upats, pcase--let*)
(pcase--expand, pcase--u1): Rename pcase's internal `dontcare' pattern
to `pcase--dontcare'.
* emacs-cl.el (labels): Mark obsolete.
(cl--letf, letf): Move to cl-lib.
(cl--letf*, letf*): Remove.
* emacs-cl-lib.el (cl-nth-value): Use defalias.
* emacs-cl-macs.el (cl-dolist, cl-dotimes): Add indent rule.
(cl-progv): Rewrite.
(cl--letf, cl-letf): Move from cl.el.
(cl-letf*): New macro.
* emacs-cl-extra.el (cl--progv-before, cl--progv-after): Remove.
2012-07-11 23:13:41 +00:00
|
|
|
((eq upat 'pcase--dontcare) :pcase--dontcare)
|
2010-10-29 01:05:38 +00:00
|
|
|
((memq (car-safe upat) '(guard pred))
|
2012-09-28 12:18:38 +00:00
|
|
|
(if (eq (car upat) 'pred) (pcase--mark-used sym))
|
2011-02-18 13:55:51 +00:00
|
|
|
(let* ((splitrest
|
2011-03-16 20:08:39 +00:00
|
|
|
(pcase--split-rest
|
2013-07-08 21:54:54 +00:00
|
|
|
sym (lambda (pat) (pcase--split-pred vars upat pat)) rest))
|
2011-02-18 13:55:51 +00:00
|
|
|
(then-rest (car splitrest))
|
|
|
|
(else-rest (cdr splitrest)))
|
2014-09-22 18:05:22 +00:00
|
|
|
(pcase--if (if (eq (car upat) 'pred)
|
|
|
|
(pcase--funcall (cadr upat) sym vars)
|
|
|
|
(pcase--eval (cadr upat) vars))
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--u1 matches code vars then-rest)
|
|
|
|
(pcase--u else-rest))))
|
2015-06-16 16:37:33 +00:00
|
|
|
((and (symbolp upat) upat)
|
2012-09-28 12:18:38 +00:00
|
|
|
(pcase--mark-used sym)
|
2011-02-18 04:58:21 +00:00
|
|
|
(if (not (assq upat vars))
|
|
|
|
(pcase--u1 matches code (cons (cons upat sym) vars) rest)
|
|
|
|
;; Non-linear pattern. Turn it into an `eq' test.
|
|
|
|
(pcase--u1 (cons `(match ,sym . (pred (eq ,(cdr (assq upat vars)))))
|
|
|
|
matches)
|
|
|
|
code vars rest)))
|
2011-03-16 20:08:39 +00:00
|
|
|
((eq (car-safe upat) 'let)
|
|
|
|
;; A upat of the form (let VAR EXP).
|
|
|
|
;; (pcase--u1 matches code
|
|
|
|
;; (cons (cons (nth 1 upat) (nth 2 upat)) vars) rest)
|
Provide generalized variables in core Elisp.
* lisp/emacs-lisp/gv.el: New file.
* lisp/subr.el (push, pop): Extend to generalized variables.
* lisp/loadup.el (macroexp): Unload if preloaded and uncompiled.
* lisp/emacs-lisp/cl-lib.el (cl-pop, cl-push, cl--set-nthcdr): Remove.
* lisp/emacs-lisp/cl-macs.el: Require gv. Use gv-define-setter,
gv-define-simple-setter, and gv-define-expander.
Remove setf-methods defined in gv. Rename cl-setf -> setf.
(cl-setf, cl-do-pop, cl-get-setf-method): Remove.
(cl-letf, cl-letf*, cl-define-modify-macro, cl-defsetf)
(cl-define-setf-expander, cl-struct-setf-expander): Move to cl.el.
(cl-remf, cl-shiftf, cl-rotatef, cl-callf, cl-callf2): Rewrite with
gv-letplace.
(cl-defstruct): Don't define setf-method any more.
* lisp/emacs-lisp/cl.el (flet): Don't autoload.
(cl--letf, letf, cl--letf*, letf*, cl--gv-adapt)
(define-setf-expander, defsetf, define-modify-macro)
(cl-struct-setf-expander): Move from cl-lib.el.
* lisp/emacs-lisp/syntax.el:
* lisp/emacs-lisp/ewoc.el:
* lisp/emacs-lisp/smie.el:
* lisp/emacs-lisp/cconv.el:
* lisp/emacs-lisp/timer.el: Rename cl-setf -> setf, cl-push -> push.
(timer--time): Use gv-define-simple-setter.
* lisp/emacs-lisp/macroexp.el (macroexp-let2): Rename from macroexp-let²
to avoid coding-system problems in subr.el. Adjust all users.
(macroexp--maxsize, macroexp-small-p): New functions.
* lisp/emacs-lisp/bytecomp.el (byte-compile-file): Don't use cl-letf.
* lisp/scroll-bar.el (scroll-bar-mode):
* lisp/simple.el (auto-fill-mode, overwrite-mode, binary-overwrite-mode)
(normal-erase-is-backspace-mode): Don't use the `eq' place.
* lisp/winner.el (winner-configuration, winner-make-point-alist)
(winner-set-conf, winner-get-point, winner-set): Don't abuse letf.
* lisp/files.el (locate-file-completion-table): Avoid list*.
Fixes: debbugs:11657
2012-06-22 13:42:38 +00:00
|
|
|
(macroexp-let2
|
2012-06-07 19:25:48 +00:00
|
|
|
macroexp-copyable-p sym
|
2014-09-22 18:05:22 +00:00
|
|
|
(pcase--eval (nth 2 upat) vars)
|
2014-09-22 16:22:50 +00:00
|
|
|
(pcase--u1 (cons (pcase--match sym (nth 1 upat)) matches)
|
2012-06-07 19:25:48 +00:00
|
|
|
code vars rest)))
|
2014-09-22 14:30:47 +00:00
|
|
|
((eq (car-safe upat) 'app)
|
2015-05-25 02:38:05 +00:00
|
|
|
;; A upat of the form (app FUN PAT)
|
2014-09-22 14:30:47 +00:00
|
|
|
(pcase--mark-used sym)
|
2014-09-22 17:24:46 +00:00
|
|
|
(let* ((fun (nth 1 upat))
|
2017-09-12 15:08:00 +00:00
|
|
|
(nsym (gensym "x"))
|
2014-09-22 17:24:46 +00:00
|
|
|
(body
|
|
|
|
;; We don't change `matches' to reuse the newly computed value,
|
|
|
|
;; because we assume there shouldn't be such redundancy in there.
|
|
|
|
(pcase--u1 (cons (pcase--match nsym (nth 2 upat)) matches)
|
|
|
|
code vars
|
|
|
|
(pcase--app-subst-rest rest sym fun nsym))))
|
|
|
|
(if (not (get nsym 'pcase-used))
|
|
|
|
body
|
|
|
|
(macroexp-let*
|
2014-09-22 18:05:22 +00:00
|
|
|
`((,nsym ,(pcase--funcall fun sym vars)))
|
2014-09-22 17:24:46 +00:00
|
|
|
body))))
|
2014-09-22 14:30:47 +00:00
|
|
|
((eq (car-safe upat) 'quote)
|
2014-09-22 17:24:46 +00:00
|
|
|
(pcase--mark-used sym)
|
2014-09-22 14:30:47 +00:00
|
|
|
(let* ((val (cadr upat))
|
|
|
|
(splitrest (pcase--split-rest
|
|
|
|
sym (lambda (pat) (pcase--split-equal val pat)) rest))
|
|
|
|
(then-rest (car splitrest))
|
|
|
|
(else-rest (cdr splitrest)))
|
|
|
|
(pcase--if (cond
|
|
|
|
((null val) `(null ,sym))
|
2018-10-25 15:19:05 +00:00
|
|
|
((integerp val) `(eql ,sym ,val))
|
|
|
|
((symbolp val)
|
2014-09-22 17:24:46 +00:00
|
|
|
(if (pcase--self-quoting-p val)
|
|
|
|
`(eq ,sym ,val)
|
|
|
|
`(eq ,sym ',val)))
|
2014-09-22 14:30:47 +00:00
|
|
|
(t `(equal ,sym ',val)))
|
|
|
|
(pcase--u1 matches code vars then-rest)
|
|
|
|
(pcase--u else-rest))))
|
2010-08-10 13:18:14 +00:00
|
|
|
((eq (car-safe upat) 'not)
|
|
|
|
;; FIXME: The implementation below is naive and results in
|
|
|
|
;; inefficient code.
|
2010-11-24 16:39:51 +00:00
|
|
|
;; To make it work right, we would need to turn pcase--u1's
|
2010-08-10 13:18:14 +00:00
|
|
|
;; `code' and `vars' into a single argument of the same form as
|
|
|
|
;; `rest'. We would also need to split this new `then-rest' argument
|
|
|
|
;; for every test (currently we don't bother to do it since
|
|
|
|
;; it's only useful for odd patterns like (and `(PAT1 . PAT2)
|
|
|
|
;; `(PAT3 . PAT4)) which the programmer can easily rewrite
|
|
|
|
;; to the more efficient `(,(and PAT1 PAT3) . ,(and PAT2 PAT4))).
|
2010-11-24 16:39:51 +00:00
|
|
|
(pcase--u1 `((match ,sym . ,(cadr upat)))
|
2011-02-10 18:53:49 +00:00
|
|
|
;; FIXME: This codegen is not careful to share its
|
|
|
|
;; code if used several times: code blow up is likely.
|
2011-03-01 05:03:24 +00:00
|
|
|
(lambda (_vars)
|
2011-02-10 18:53:49 +00:00
|
|
|
;; `vars' will likely contain bindings which are
|
|
|
|
;; not always available in other paths to
|
|
|
|
;; `rest', so there' no point trying to pass
|
|
|
|
;; them down.
|
|
|
|
(pcase--u rest))
|
2010-11-24 16:39:51 +00:00
|
|
|
vars
|
|
|
|
(list `((and . ,matches) ,code . ,vars))))
|
Go back to grave quoting in source-code docstrings etc.
This reverts almost all my recent changes to use curved quotes
in docstrings and/or strings used for error diagnostics.
There are a few exceptions, e.g., Bahá’í proper names.
* admin/unidata/unidata-gen.el (unidata-gen-table):
* lisp/abbrev.el (expand-region-abbrevs):
* lisp/align.el (align-region):
* lisp/allout.el (allout-mode, allout-solicit-alternate-bullet)
(outlineify-sticky):
* lisp/apropos.el (apropos-library):
* lisp/bookmark.el (bookmark-default-annotation-text):
* lisp/button.el (button-category-symbol, button-put)
(make-text-button):
* lisp/calc/calc-aent.el (math-read-if, math-read-factor):
* lisp/calc/calc-embed.el (calc-do-embedded):
* lisp/calc/calc-ext.el (calc-user-function-list):
* lisp/calc/calc-graph.el (calc-graph-show-dumb):
* lisp/calc/calc-help.el (calc-describe-key)
(calc-describe-thing, calc-full-help):
* lisp/calc/calc-lang.el (calc-c-language)
(math-parse-fortran-vector-end, math-parse-tex-sum)
(math-parse-eqn-matrix, math-parse-eqn-prime)
(calc-yacas-language, calc-maxima-language, calc-giac-language)
(math-read-giac-subscr, math-read-math-subscr)
(math-read-big-rec, math-read-big-balance):
* lisp/calc/calc-misc.el (calc-help, report-calc-bug):
* lisp/calc/calc-mode.el (calc-auto-why, calc-save-modes)
(calc-auto-recompute):
* lisp/calc/calc-prog.el (calc-fix-token-name)
(calc-read-parse-table-part, calc-user-define-invocation)
(math-do-arg-check):
* lisp/calc/calc-store.el (calc-edit-variable):
* lisp/calc/calc-units.el (math-build-units-table-buffer):
* lisp/calc/calc-vec.el (math-read-brackets):
* lisp/calc/calc-yank.el (calc-edit-mode):
* lisp/calc/calc.el (calc, calc-do, calc-user-invocation):
* lisp/calendar/appt.el (appt-display-message):
* lisp/calendar/diary-lib.el (diary-check-diary-file)
(diary-mail-entries, diary-from-outlook):
* lisp/calendar/icalendar.el (icalendar-export-region)
(icalendar--convert-float-to-ical)
(icalendar--convert-date-to-ical)
(icalendar--convert-ical-to-diary)
(icalendar--convert-recurring-to-diary)
(icalendar--add-diary-entry):
* lisp/calendar/time-date.el (format-seconds):
* lisp/calendar/timeclock.el (timeclock-mode-line-display)
(timeclock-make-hours-explicit, timeclock-log-data):
* lisp/calendar/todo-mode.el (todo-prefix, todo-delete-category)
(todo-item-mark, todo-check-format)
(todo-insert-item--next-param, todo-edit-item--next-key)
(todo-mode):
* lisp/cedet/ede/pmake.el (ede-proj-makefile-insert-dist-rules):
* lisp/cedet/mode-local.el (describe-mode-local-overload)
(mode-local-print-binding, mode-local-describe-bindings-2):
* lisp/cedet/semantic/complete.el (semantic-displayor-show-request):
* lisp/cedet/srecode/srt-mode.el (srecode-macro-help):
* lisp/cus-start.el (standard):
* lisp/cus-theme.el (describe-theme-1):
* lisp/custom.el (custom-add-dependencies, custom-check-theme)
(custom--sort-vars-1, load-theme):
* lisp/descr-text.el (describe-text-properties-1, describe-char):
* lisp/dired-x.el (dired-do-run-mail):
* lisp/dired.el (dired-log):
* lisp/emacs-lisp/advice.el (ad-read-advised-function)
(ad-read-advice-class, ad-read-advice-name, ad-enable-advice)
(ad-disable-advice, ad-remove-advice, ad-set-argument)
(ad-set-arguments, ad--defalias-fset, ad-activate)
(ad-deactivate):
* lisp/emacs-lisp/byte-opt.el (byte-compile-inline-expand)
(byte-compile-unfold-lambda, byte-optimize-form-code-walker)
(byte-optimize-while, byte-optimize-apply):
* lisp/emacs-lisp/byte-run.el (defun, defsubst):
* lisp/emacs-lisp/bytecomp.el (byte-compile-lapcode)
(byte-compile-log-file, byte-compile-format-warn)
(byte-compile-nogroup-warn, byte-compile-arglist-warn)
(byte-compile-cl-warn)
(byte-compile-warn-about-unresolved-functions)
(byte-compile-file, byte-compile--declare-var)
(byte-compile-file-form-defmumble, byte-compile-form)
(byte-compile-normal-call, byte-compile-check-variable)
(byte-compile-variable-ref, byte-compile-variable-set)
(byte-compile-subr-wrong-args, byte-compile-setq-default)
(byte-compile-negation-optimizer)
(byte-compile-condition-case--old)
(byte-compile-condition-case--new, byte-compile-save-excursion)
(byte-compile-defvar, byte-compile-autoload)
(byte-compile-lambda-form)
(byte-compile-make-variable-buffer-local, display-call-tree)
(batch-byte-compile):
* lisp/emacs-lisp/cconv.el (cconv-convert, cconv--analyze-use):
* lisp/emacs-lisp/chart.el (chart-space-usage):
* lisp/emacs-lisp/check-declare.el (check-declare-scan)
(check-declare-warn, check-declare-file)
(check-declare-directory):
* lisp/emacs-lisp/checkdoc.el (checkdoc-this-string-valid-engine)
(checkdoc-message-text-engine):
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer)
(cl--describe-class):
* lisp/emacs-lisp/cl-generic.el (cl-defgeneric)
(cl--generic-describe, cl-generic-generalizers):
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause, cl-tagbody)
(cl-symbol-macrolet):
* lisp/emacs-lisp/cl.el (cl-unload-function, flet):
* lisp/emacs-lisp/copyright.el (copyright)
(copyright-update-directory):
* lisp/emacs-lisp/edebug.el (edebug-read-list):
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-read):
* lisp/emacs-lisp/eieio-core.el (eieio--slot-override)
(eieio-oref):
* lisp/emacs-lisp/eieio-opt.el (eieio-help-constructor):
* lisp/emacs-lisp/eieio-speedbar.el:
(eieio-speedbar-child-make-tag-lines)
(eieio-speedbar-child-description):
* lisp/emacs-lisp/eieio.el (defclass, change-class):
* lisp/emacs-lisp/elint.el (elint-file, elint-get-top-forms)
(elint-init-form, elint-check-defalias-form)
(elint-check-let-form):
* lisp/emacs-lisp/ert.el (ert-get-test, ert-results-mode-menu)
(ert-results-pop-to-backtrace-for-test-at-point)
(ert-results-pop-to-messages-for-test-at-point)
(ert-results-pop-to-should-forms-for-test-at-point)
(ert-describe-test):
* lisp/emacs-lisp/find-func.el (find-function-search-for-symbol)
(find-function-library):
* lisp/emacs-lisp/generator.el (iter-yield):
* lisp/emacs-lisp/gv.el (gv-define-simple-setter):
* lisp/emacs-lisp/lisp-mnt.el (lm-verify):
* lisp/emacs-lisp/macroexp.el (macroexp--obsolete-warning):
* lisp/emacs-lisp/map-ynp.el (map-y-or-n-p):
* lisp/emacs-lisp/nadvice.el (advice--make-docstring)
(advice--make, define-advice):
* lisp/emacs-lisp/package-x.el (package-upload-file):
* lisp/emacs-lisp/package.el (package-version-join)
(package-disabled-p, package-activate-1, package-activate)
(package--download-one-archive)
(package--download-and-read-archives)
(package-compute-transaction, package-install-from-archive)
(package-install, package-install-selected-packages)
(package-delete, package-autoremove, describe-package-1)
(package-install-button-action, package-delete-button-action)
(package-menu-hide-package, package-menu--list-to-prompt)
(package-menu--perform-transaction)
(package-menu--find-and-notify-upgrades):
* lisp/emacs-lisp/pcase.el (pcase-exhaustive, pcase--u1):
* lisp/emacs-lisp/re-builder.el (reb-enter-subexp-mode):
* lisp/emacs-lisp/ring.el (ring-previous, ring-next):
* lisp/emacs-lisp/rx.el (rx-check, rx-anything)
(rx-check-any-string, rx-check-any, rx-check-not, rx-=)
(rx-repeat, rx-check-backref, rx-syntax, rx-check-category)
(rx-form):
* lisp/emacs-lisp/smie.el (smie-config-save):
* lisp/emacs-lisp/subr-x.el (internal--check-binding):
* lisp/emacs-lisp/tabulated-list.el (tabulated-list-put-tag):
* lisp/emacs-lisp/testcover.el (testcover-1value):
* lisp/emacs-lisp/timer.el (timer-event-handler):
* lisp/emulation/viper-cmd.el (viper-toggle-parse-sexp-ignore-comments)
(viper-toggle-search-style, viper-kill-buffer)
(viper-brac-function):
* lisp/emulation/viper-macs.el (viper-record-kbd-macro):
* lisp/env.el (setenv):
* lisp/erc/erc-button.el (erc-nick-popup):
* lisp/erc/erc.el (erc-cmd-LOAD, erc-handle-login, english):
* lisp/eshell/em-dirs.el (eshell/cd):
* lisp/eshell/em-glob.el (eshell-glob-regexp)
(eshell-glob-entries):
* lisp/eshell/em-pred.el (eshell-parse-modifiers):
* lisp/eshell/esh-opt.el (eshell-show-usage):
* lisp/facemenu.el (facemenu-add-new-face)
(facemenu-add-new-color):
* lisp/faces.el (read-face-name, read-face-font, describe-face)
(x-resolve-font-name):
* lisp/files-x.el (modify-file-local-variable):
* lisp/files.el (locate-user-emacs-file, find-alternate-file)
(set-auto-mode, hack-one-local-variable--obsolete)
(dir-locals-set-directory-class, write-file, basic-save-buffer)
(delete-directory, copy-directory, recover-session)
(recover-session-finish, insert-directory)
(file-modes-char-to-who, file-modes-symbolic-to-number)
(move-file-to-trash):
* lisp/filesets.el (filesets-add-buffer, filesets-remove-buffer):
* lisp/find-cmd.el (find-generic, find-to-string):
* lisp/finder.el (finder-commentary):
* lisp/font-lock.el (font-lock-fontify-buffer):
* lisp/format.el (format-write-file, format-find-file)
(format-insert-file):
* lisp/frame.el (get-device-terminal, select-frame-by-name):
* lisp/fringe.el (fringe--check-style):
* lisp/gnus/nnmairix.el (nnmairix-widget-create-query):
* lisp/help-fns.el (help-fns--key-bindings)
(help-fns--compiler-macro, help-fns--parent-mode)
(help-fns--obsolete, help-fns--interactive-only)
(describe-function-1, describe-variable):
* lisp/help.el (describe-mode)
(describe-minor-mode-from-indicator):
* lisp/image.el (image-type):
* lisp/international/ccl.el (ccl-dump):
* lisp/international/fontset.el (x-must-resolve-font-name):
* lisp/international/mule-cmds.el (prefer-coding-system)
(select-safe-coding-system-interactively)
(select-safe-coding-system, activate-input-method)
(toggle-input-method, describe-current-input-method)
(describe-language-environment):
* lisp/international/mule-conf.el (code-offset):
* lisp/international/mule-diag.el (describe-character-set)
(list-input-methods-1):
* lisp/mail/feedmail.el (feedmail-run-the-queue):
* lisp/mouse.el (minor-mode-menu-from-indicator):
* lisp/mpc.el (mpc-playlist-rename):
* lisp/msb.el (msb--choose-menu):
* lisp/net/ange-ftp.el (ange-ftp-shell-command):
* lisp/net/imap.el (imap-interactive-login):
* lisp/net/mairix.el (mairix-widget-create-query):
* lisp/net/newst-backend.el (newsticker--sentinel-work):
* lisp/net/newst-treeview.el (newsticker--treeview-load):
* lisp/net/rlogin.el (rlogin):
* lisp/obsolete/iswitchb.el (iswitchb-possible-new-buffer):
* lisp/obsolete/otodo-mode.el (todo-more-important-p):
* lisp/obsolete/pgg-gpg.el (pgg-gpg-process-region):
* lisp/obsolete/pgg-pgp.el (pgg-pgp-process-region):
* lisp/obsolete/pgg-pgp5.el (pgg-pgp5-process-region):
* lisp/org/ob-core.el (org-babel-goto-named-src-block)
(org-babel-goto-named-result):
* lisp/org/ob-fortran.el (org-babel-fortran-ensure-main-wrap):
* lisp/org/ob-ref.el (org-babel-ref-resolve):
* lisp/org/org-agenda.el (org-agenda-prepare):
* lisp/org/org-clock.el (org-clock-notify-once-if-expired)
(org-clock-resolve):
* lisp/org/org-ctags.el (org-ctags-ask-rebuild-tags-file-then-find-tag):
* lisp/org/org-feed.el (org-feed-parse-atom-entry):
* lisp/org/org-habit.el (org-habit-parse-todo):
* lisp/org/org-mouse.el (org-mouse-popup-global-menu)
(org-mouse-context-menu):
* lisp/org/org-table.el (org-table-edit-formulas):
* lisp/org/ox.el (org-export-async-start):
* lisp/proced.el (proced-log):
* lisp/progmodes/ada-mode.el (ada-get-indent-case)
(ada-check-matching-start, ada-goto-matching-start):
* lisp/progmodes/ada-prj.el (ada-prj-display-page):
* lisp/progmodes/ada-xref.el (ada-find-executable):
* lisp/progmodes/ebrowse.el (ebrowse-tags-apropos):
* lisp/progmodes/etags.el (etags-tags-apropos-additional):
* lisp/progmodes/flymake.el (flymake-parse-err-lines)
(flymake-start-syntax-check-process):
* lisp/progmodes/python.el (python-shell-get-process-or-error)
(python-define-auxiliary-skeleton):
* lisp/progmodes/sql.el (sql-comint):
* lisp/progmodes/verilog-mode.el (verilog-load-file-at-point):
* lisp/progmodes/vhdl-mode.el (vhdl-widget-directory-validate):
* lisp/recentf.el (recentf-open-files):
* lisp/replace.el (query-replace-read-from)
(occur-after-change-function, occur-1):
* lisp/scroll-bar.el (scroll-bar-columns):
* lisp/server.el (server-get-auth-key):
* lisp/simple.el (execute-extended-command)
(undo-outer-limit-truncate, list-processes--refresh)
(compose-mail, set-variable, choose-completion-string)
(define-alternatives):
* lisp/startup.el (site-run-file, tty-handle-args, command-line)
(command-line-1):
* lisp/subr.el (noreturn, define-error, add-to-list)
(read-char-choice, version-to-list):
* lisp/term/common-win.el (x-handle-xrm-switch)
(x-handle-name-switch, x-handle-args):
* lisp/term/x-win.el (x-handle-parent-id, x-handle-smid):
* lisp/textmodes/reftex-ref.el (reftex-label):
* lisp/textmodes/reftex-toc.el (reftex-toc-rename-label):
* lisp/textmodes/two-column.el (2C-split):
* lisp/tutorial.el (tutorial--describe-nonstandard-key)
(tutorial--find-changed-keys):
* lisp/type-break.el (type-break-noninteractive-query):
* lisp/wdired.el (wdired-do-renames, wdired-do-symlink-changes)
(wdired-do-perm-changes):
* lisp/whitespace.el (whitespace-report-region):
Prefer grave quoting in source-code strings used to generate help
and diagnostics.
* lisp/faces.el (face-documentation):
No need to convert quotes, since the result is a docstring.
* lisp/info.el (Info-virtual-index-find-node)
(Info-virtual-index, info-apropos):
Simplify by generating only curved quotes, since info files are
typically that ways nowadays anyway.
* lisp/international/mule-diag.el (list-input-methods):
Don’t assume text quoting style is curved.
* lisp/org/org-bibtex.el (org-bibtex-fields):
Revert my recent changes, going back to the old quoting style.
2015-09-07 15:41:44 +00:00
|
|
|
(t (error "Unknown pattern `%S'" upat)))))
|
2014-09-22 17:24:46 +00:00
|
|
|
(t (error "Incorrect MATCH %S" (car matches)))))
|
2010-08-10 13:18:14 +00:00
|
|
|
|
2015-04-12 14:26:52 +00:00
|
|
|
(def-edebug-spec
|
|
|
|
pcase-QPAT
|
2015-11-15 23:07:06 +00:00
|
|
|
;; Cf. edebug spec for `backquote-form' in edebug.el.
|
2015-05-25 02:38:05 +00:00
|
|
|
(&or ("," pcase-PAT)
|
2015-11-15 23:07:06 +00:00
|
|
|
(pcase-QPAT [&rest [¬ ","] pcase-QPAT]
|
|
|
|
. [&or nil pcase-QPAT])
|
2015-04-12 14:26:52 +00:00
|
|
|
(vector &rest pcase-QPAT)
|
|
|
|
sexp))
|
|
|
|
|
2014-09-22 17:24:46 +00:00
|
|
|
(pcase-defmacro \` (qpat)
|
2018-05-21 16:16:35 +00:00
|
|
|
"Backquote-style pcase patterns: \\=`QPAT
|
2015-03-23 22:24:30 +00:00
|
|
|
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.
|
2018-05-21 16:16:35 +00:00
|
|
|
,PAT matches if the `pcase' pattern PAT matches.
|
|
|
|
SYMBOL matches if EXPVAL is `equal' to SYMBOL.
|
|
|
|
KEYWORD likewise for KEYWORD.
|
2018-06-13 02:37:38 +00:00
|
|
|
NUMBER likewise for NUMBER.
|
2018-05-21 16:16:35 +00:00
|
|
|
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'.)"
|
2015-04-12 14:26:52 +00:00
|
|
|
(declare (debug (pcase-QPAT)))
|
2010-08-10 13:18:14 +00:00
|
|
|
(cond
|
2014-09-22 17:24:46 +00:00
|
|
|
((eq (car-safe qpat) '\,) (cadr qpat))
|
2010-08-10 13:18:14 +00:00
|
|
|
((vectorp qpat)
|
2014-09-22 17:24:46 +00:00
|
|
|
`(and (pred vectorp)
|
|
|
|
(app length ,(length qpat))
|
|
|
|
,@(let ((upats nil))
|
|
|
|
(dotimes (i (length qpat))
|
2014-09-22 18:05:22 +00:00
|
|
|
(push `(app (pcase--flip aref ,i) ,(list '\` (aref qpat i)))
|
2014-09-22 17:24:46 +00:00
|
|
|
upats))
|
|
|
|
(nreverse upats))))
|
2010-08-10 13:18:14 +00:00
|
|
|
((consp qpat)
|
2014-09-22 17:24:46 +00:00
|
|
|
`(and (pred consp)
|
|
|
|
(app car ,(list '\` (car qpat)))
|
|
|
|
(app cdr ,(list '\` (cdr qpat)))))
|
2018-06-13 02:37:38 +00:00
|
|
|
((or (stringp qpat) (numberp qpat) (symbolp qpat)) `',qpat)
|
|
|
|
;; In all other cases just raise an error so we can't break
|
|
|
|
;; backward compatibility when adding \` support for other
|
|
|
|
;; compounded values that are not `consp'
|
2015-06-16 16:37:33 +00:00
|
|
|
(t (error "Unknown QPAT: %S" qpat))))
|
2010-08-11 02:14:53 +00:00
|
|
|
|
2010-08-10 13:18:14 +00:00
|
|
|
(provide 'pcase)
|
|
|
|
;;; pcase.el ends here
|