diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2011-03-01 17:52:03 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2011-03-01 17:52:03 -0800 |
commit | ba46f4d85a6938273f52a8cdf7e09d9afee61d7f (patch) | |
tree | 606ec46b703532d463ccddf287f0053430eb1f4a /lisp/emacs-lisp | |
parent | d9d0d182da35312ed0d7a9859b9c6a03994d86d8 (diff) | |
parent | 0dc3e4109e0c41bbf5fdcae0ff1156162719693e (diff) | |
download | emacs-ba46f4d85a6938273f52a8cdf7e09d9afee61d7f.tar.gz emacs-ba46f4d85a6938273f52a8cdf7e09d9afee61d7f.tar.bz2 emacs-ba46f4d85a6938273f52a8cdf7e09d9afee61d7f.zip |
Merge from mainline.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r-- | lisp/emacs-lisp/assoc.el | 10 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-loaddefs.el | 4 | ||||
-rw-r--r-- | lisp/emacs-lisp/cl-macs.el | 2 | ||||
-rw-r--r-- | lisp/emacs-lisp/package-x.el | 89 | ||||
-rw-r--r-- | lisp/emacs-lisp/pcase.el | 111 |
5 files changed, 167 insertions, 49 deletions
diff --git a/lisp/emacs-lisp/assoc.el b/lisp/emacs-lisp/assoc.el index aa85916cc3f..31be851f2dd 100644 --- a/lisp/emacs-lisp/assoc.el +++ b/lisp/emacs-lisp/assoc.el @@ -1,4 +1,4 @@ -;;; assoc.el --- insert/delete/sort functions on association lists +;;; assoc.el --- insert/delete functions on association lists ;; Copyright (C) 1996, 2001-2011 Free Software Foundation, Inc. @@ -35,7 +35,7 @@ head is one matching KEY. Returns the sorted list and doesn't affect the order of any other key-value pair. Side effect sets alist to new sorted list." (set alist-symbol - (sort (copy-alist (eval alist-symbol)) + (sort (copy-alist (symbol-value alist-symbol)) (function (lambda (a b) (equal (car a) key)))))) @@ -75,7 +75,7 @@ of the alist (with value nil if VALUE is nil or not supplied)." (lexical-let ((elem (aelement key value)) alist) (asort alist-symbol key) - (setq alist (eval alist-symbol)) + (setq alist (symbol-value alist-symbol)) (cond ((null alist) (set alist-symbol elem)) ((anot-head-p alist key) (set alist-symbol (nconc elem alist))) (value (setcar alist (car elem))) @@ -87,7 +87,7 @@ of the alist (with value nil if VALUE is nil or not supplied)." Alist is referenced by ALIST-SYMBOL and the key-value pair to remove is pair matching KEY. Returns the altered alist." (asort alist-symbol key) - (lexical-let ((alist (eval alist-symbol))) + (lexical-let ((alist (symbol-value alist-symbol))) (cond ((null alist) nil) ((anot-head-p alist key) alist) (t (set alist-symbol (cdr alist)))))) @@ -133,7 +133,7 @@ extra values are ignored. Returns the created alist." (t (amake alist-symbol keycdr valcdr) (aput alist-symbol keycar valcar)))) - (eval alist-symbol)) + (symbol-value alist-symbol)) (provide 'assoc) diff --git a/lisp/emacs-lisp/cl-loaddefs.el b/lisp/emacs-lisp/cl-loaddefs.el index 8e192a18459..08001171ed1 100644 --- a/lisp/emacs-lisp/cl-loaddefs.el +++ b/lisp/emacs-lisp/cl-loaddefs.el @@ -282,7 +282,7 @@ Not documented ;;;;;; do-all-symbols do-symbols dotimes dolist do* do loop return-from ;;;;;; return block etypecase typecase ecase case load-time-value ;;;;;; eval-when destructuring-bind function* defmacro* defun* gentemp -;;;;;; gensym) "cl-macs" "cl-macs.el" "0904b956872432ae7cc5fa9abcefce63") +;;;;;; gensym) "cl-macs" "cl-macs.el" "b3031039e82679e5b013ce1cbf174ee8") ;;; Generated autoloads from cl-macs.el (autoload 'gensym "cl-macs" "\ @@ -505,7 +505,7 @@ lexical closures as in Common Lisp. (autoload 'lexical-let* "cl-macs" "\ Like `let*', but lexically scoped. The main visible difference is that lambdas inside BODY, and in -successive bindings within BINDINGS, will create lexical closures +successive bindings within VARLIST, will create lexical closures as in Common Lisp. This is similar to the behavior of `let*' in Common Lisp. diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el index 80e95724f1f..c57d37703b0 100644 --- a/lisp/emacs-lisp/cl-macs.el +++ b/lisp/emacs-lisp/cl-macs.el @@ -1470,7 +1470,7 @@ lexical closures as in Common Lisp. (defmacro lexical-let* (bindings &rest body) "Like `let*', but lexically scoped. The main visible difference is that lambdas inside BODY, and in -successive bindings within BINDINGS, will create lexical closures +successive bindings within VARLIST, will create lexical closures as in Common Lisp. This is similar to the behavior of `let*' in Common Lisp. \n(fn VARLIST BODY)" diff --git a/lisp/emacs-lisp/package-x.el b/lisp/emacs-lisp/package-x.el index b9994be3d39..61f23abf0a7 100644 --- a/lisp/emacs-lisp/package-x.el +++ b/lisp/emacs-lisp/package-x.el @@ -40,6 +40,9 @@ (defvar package-archive-upload-base nil "Base location for uploading to package archive.") +(defvar package-update-news-on-upload nil + "Whether package upload should also update NEWS and RSS feeds.") + (defun package--encode (string) "Encode a string by replacing some characters with XML entities." ;; We need a special case for translating "&" to "&". @@ -86,6 +89,36 @@ (unless old-buffer (kill-buffer (current-buffer))))))) +(defun package--archive-contents-from-url (archive-url) + "Parse archive-contents file at ARCHIVE-URL. +Return the file contents, as a string, or nil if unsuccessful." + (ignore-errors + (when archive-url + (let* ((buffer (url-retrieve-synchronously + (concat archive-url "archive-contents")))) + (set-buffer buffer) + (package-handle-response) + (re-search-forward "^$" nil 'move) + (forward-char) + (delete-region (point-min) (point)) + (prog1 (package-read-from-string + (buffer-substring-no-properties (point-min) (point-max))) + (kill-buffer buffer)))))) + +(defun package--archive-contents-from-file (file) + "Parse the given archive-contents file." + (if (not (file-exists-p file)) + ;; no existing archive-contents, possibly a new ELPA repo. + (list package-archive-version) + (let ((dont-kill (find-buffer-visiting file))) + (with-current-buffer (let ((find-file-visit-truename t)) + (find-file-noselect file)) + (prog1 + (package-read-from-string + (buffer-substring-no-properties (point-min) (point-max))) + (unless dont-kill + (kill-buffer (current-buffer)))))))) + (defun package-maint-add-news-item (title description archive-url) "Add a news item to the ELPA web pages. TITLE is the title of the news item. @@ -111,11 +144,20 @@ PKG-INFO is the package info, see `package-buffer-info'. EXTENSION is the file extension, a string. It can be either \"el\" or \"tar\". +The variable `package-archive-upload-base' specifies the upload +destination. If this is nil, signal an error. + Optional arg ARCHIVE-URL is the URL of the destination archive. -If nil, the \"gnu\" archive is used." - (unless archive-url - (or (setq archive-url (cdr (assoc "gnu" package-archives))) - (error "No destination URL"))) +If it is non-nil, compute the new \"archive-contents\" file +starting from the existing \"archive-contents\" at that URL. In +addition, if `package-update-news-on-upload' is non-nil, call +`package--update-news' to add a news item at that URL. + +If ARCHIVE-URL is nil, compute the new \"archive-contents\" file +from the \"archive-contents\" at `package-archive-upload-base', +if it exists." + (unless package-archive-upload-base + (error "No destination specified in `package-archive-upload-base'")) (save-excursion (save-restriction (let* ((file-type (cond @@ -131,21 +173,14 @@ If nil, the \"gnu\" archive is used." (pkg-version (aref pkg-info 3)) (commentary (aref pkg-info 4)) (split-version (version-to-list pkg-version)) - (pkg-buffer (current-buffer)) + (pkg-buffer (current-buffer))) - ;; Download latest archive-contents. - (buffer (url-retrieve-synchronously - (concat archive-url "archive-contents")))) - - ;; Parse archive-contents. - (set-buffer buffer) - (package-handle-response) - (re-search-forward "^$" nil 'move) - (forward-char) - (delete-region (point-min) (point)) - (let ((contents (package-read-from-string - (buffer-substring-no-properties (point-min) - (point-max)))) + ;; Get archive-contents from ARCHIVE-URL if it's non-nil, or + ;; from `package-archive-upload-base' otherwise. + (let ((contents (or (package--archive-contents-from-url archive-url) + (package--archive-contents-from-file + (concat package-archive-upload-base + "archive-contents")))) (new-desc (vector split-version requires desc file-type))) (if (> (car contents) package-archive-version) (error "Unrecognized archive version %d" (car contents))) @@ -176,7 +211,6 @@ If nil, the \"gnu\" archive is used." (symbol-name pkg-name) "-readme.txt"))) (set-buffer pkg-buffer) - (kill-buffer buffer) (write-region (point-min) (point-max) (concat package-archive-upload-base file-name "-" pkg-version @@ -184,8 +218,10 @@ If nil, the \"gnu\" archive is used." nil nil nil 'excl) ;; Write a news entry. - (package--update-news (concat file-name "." extension) - pkg-version desc archive-url) + (and package-update-news-on-upload + archive-url + (package--update-news (concat file-name "." extension) + pkg-version desc archive-url)) ;; special-case "package": write a second copy so that the ;; installer can easily find the latest version. @@ -196,7 +232,9 @@ If nil, the \"gnu\" archive is used." nil nil nil 'ask))))))) (defun package-upload-buffer () - "Upload a single .el file to ELPA from the current buffer." + "Upload the current buffer as a single-file Emacs Lisp package. +The variable `package-archive-upload-base' specifies the upload +destination." (interactive) (save-excursion (save-restriction @@ -205,6 +243,13 @@ If nil, the \"gnu\" archive is used." (package-upload-buffer-internal pkg-info "el"))))) (defun package-upload-file (file) + "Upload the Emacs Lisp package FILE to the package archive. +Interactively, prompt for FILE. The package is considered a +single-file package if FILE ends in \".el\", and a multi-file +package if FILE ends in \".tar\". + +The variable `package-archive-upload-base' specifies the upload +destination." (interactive "fPackage file name: ") (with-temp-buffer (insert-file-contents-literally file) diff --git a/lisp/emacs-lisp/pcase.el b/lisp/emacs-lisp/pcase.el index 3179672a3ec..916dcd4785c 100644 --- a/lisp/emacs-lisp/pcase.el +++ b/lisp/emacs-lisp/pcase.el @@ -3,7 +3,7 @@ ;; Copyright (C) 2010-2011 Free Software Foundation, Inc. ;; Author: Stefan Monnier <monnier@iro.umontreal.ca> -;; Keywords: +;; Keywords: ;; This file is part of GNU Emacs. @@ -32,6 +32,14 @@ ;; 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 ;; extension provide its own `pcase--split-<foo>' thingy. +;; - provide something like (setq VAR) so a var can be set rather than +;; let-bound. +;; - provide a way to fallthrough to other cases. +;; - try and be more clever to reduce the size of the decision tree, and +;; to reduce the number of leafs that need to be turned into function: +;; - first, do the tests shared by all remaining branches (it will have +;; to be performed anyway, so better so it first so it's shared). +;; - then choose the test that discriminates more (?). ;; - 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. @@ -67,12 +75,12 @@ If a SYMBOL is used twice in the same pattern (i.e. the pattern is QPatterns can take the following forms: (QPAT1 . QPAT2) matches if QPAT1 matches the car and QPAT2 the cdr. ,UPAT matches if the UPattern UPAT matches. - STRING matches if the object is `equal' to STRING. + STRING matches if the object is `equal' to STRING. ATOM matches if the object is `eq' to ATOM. QPatterns for vectors are not implemented yet. PRED can take the form - FUNCTION in which case it gets called with one argument. + FUNCTION in which case it gets called with one argument. (FUN ARG1 .. ARGN) in which case it gets called with N+1 arguments. A PRED of the form FUNCTION is equivalent to one of the form (FUNCTION). PRED patterns can refer to variables bound earlier in the pattern. @@ -209,6 +217,7 @@ of the form (UPAT EXP)." (defun pcase--if (test then else) (cond ((eq else :pcase--dontcare) then) + ((eq then :pcase--dontcare) (debug) else) ;Can/should this ever happen? ((eq (car-safe else) 'if) (if (equal test (nth 1 else)) ;; Doing a test a second time: get rid of the redundancy. @@ -223,6 +232,8 @@ of the form (UPAT EXP)." `(cond (,test ,then) ;; Doing a test a second time: get rid of the redundancy, as above. ,@(remove (assoc test else) (cdr else)))) + ;; Invert the test if that lets us reduce the depth of the tree. + ((memq (car-safe then) '(if cond)) (pcase--if `(not ,test) else then)) (t `(if ,test ,then ,else)))) (defun pcase--upat (qpattern) @@ -264,6 +275,22 @@ MATCH is the pattern that needs to be matched, of the form: (defun pcase--and (match matches) (if matches `(and ,match ,@matches) match)) +(defconst pcase-mutually-exclusive-predicates + '((symbolp . integerp) + (symbolp . numberp) + (symbolp . consp) + (symbolp . arrayp) + (symbolp . stringp) + (integerp . consp) + (integerp . arrayp) + (integerp . stringp) + (numberp . consp) + (numberp . arrayp) + (numberp . stringp) + (consp . arrayp) + (consp . stringp) + (arrayp . stringp))) + (defun pcase--split-match (sym splitter match) (case (car match) ((match) @@ -324,8 +351,14 @@ MATCH is the pattern that needs to be matched, of the form: (cons `(and (match ,syma . ,(pcase--upat (car qpat))) (match ,symd . ,(pcase--upat (cdr qpat)))) :pcase--fail))) - ;; A QPattern but not for a cons, can only go the `else' side. - ((eq (car-safe pat) '\`) (cons :pcase--fail nil)))) + ;; A QPattern but not for a cons, can only go to the `else' side. + ((eq (car-safe pat) '\`) (cons :pcase--fail nil)) + ((and (eq (car-safe pat) 'pred) + (or (member (cons 'consp (cadr pat)) + pcase-mutually-exclusive-predicates) + (member (cons (cadr pat) 'consp) + pcase-mutually-exclusive-predicates))) + (cons :pcase--fail nil)))) (defun pcase--split-equal (elem pat) (cond @@ -337,7 +370,12 @@ MATCH is the pattern that needs to be matched, of the form: ;; (or (integerp (cadr pat)) (symbolp (cadr pat)) ;; (consp (cadr pat))) ) - (cons :pcase--fail nil)))) + (cons :pcase--fail nil)) + ((and (eq (car-safe pat) 'pred) + (symbolp (cadr pat)) + (get (cadr pat) 'side-effect-free) + (funcall (cadr pat) elem)) + (cons :pcase--succeed nil)))) (defun pcase--split-member (elems pat) ;; Based on pcase--split-equal. @@ -354,13 +392,39 @@ MATCH is the pattern that needs to be matched, of the form: ;; (or (integerp (cadr pat)) (symbolp (cadr pat)) ;; (consp (cadr pat))) ) - (cons :pcase--fail nil)))) + (cons :pcase--fail nil)) + ((and (eq (car-safe pat) 'pred) + (symbolp (cadr pat)) + (get (cadr pat) 'side-effect-free) + (let ((p (cadr pat)) (all t)) + (dolist (elem elems) + (unless (funcall p elem) (setq all nil))) + all)) + (cons :pcase--succeed nil)))) (defun pcase--split-pred (upat pat) ;; FIXME: For predicates like (pred (> a)), two such predicates may ;; actually refer to different variables `a'. - (if (equal upat pat) - (cons :pcase--succeed :pcase--fail))) + (cond + ((equal upat pat) (cons :pcase--succeed :pcase--fail)) + ((and (eq 'pred (car upat)) + (eq 'pred (car-safe pat)) + (or (member (cons (cadr upat) (cadr pat)) + pcase-mutually-exclusive-predicates) + (member (cons (cadr pat) (cadr upat)) + pcase-mutually-exclusive-predicates))) + (cons :pcase--fail nil)) + ;; ((and (eq 'pred (car upat)) + ;; (eq '\` (car-safe pat)) + ;; (symbolp (cadr upat)) + ;; (or (symbolp (cadr pat)) (stringp (cadr pat)) (numberp (cadr pat))) + ;; (get (cadr upat) 'side-effect-free) + ;; (progn (message "Trying predicate %S" (cadr upat)) + ;; (ignore-errors + ;; (funcall (cadr upat) (cadr pat))))) + ;; (message "Simplify pred %S against %S" upat pat) + ;; (cons nil :pcase--fail)) + )) (defun pcase--fgrep (vars sexp) "Check which of the symbols VARS appear in SEXP." @@ -375,7 +439,7 @@ MATCH is the pattern that needs to be matched, of the form: ;; bootstrapping problems. (defun pcase--u1 (matches code vars rest) "Return code that runs CODE (with VARS) if MATCHES match. -and otherwise defers to REST which is a list of branches of the form +Otherwise, it defers to REST which is a list of branches of the form \(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 @@ -433,6 +497,7 @@ and otherwise defers to REST which is a list of branches of the form ((eq upat 'dontcare) :pcase--dontcare) ((functionp upat) (error "Feature removed, use (pred %s)" upat)) ((memq (car-safe upat) '(guard pred)) + (if (eq (car upat) 'pred) (put sym 'pcase-used t)) (destructuring-bind (then-rest &rest else-rest) (pcase--split-rest sym (apply-partially #'pcase--split-pred upat) rest) @@ -459,6 +524,7 @@ and otherwise defers to REST which is a list of branches of the form (pcase--u1 matches code vars then-rest) (pcase--u else-rest)))) ((symbolp upat) + (put sym 'pcase-used t) (if (not (assq upat vars)) (pcase--u1 matches code (cons (cons upat sym) vars) rest) ;; Non-linear pattern. Turn it into an `eq' test. @@ -466,6 +532,7 @@ and otherwise defers to REST which is a list of branches of the form matches) code vars rest))) ((eq (car-safe upat) '\`) + (put sym 'pcase-used t) (pcase--q1 sym (cadr upat) matches code vars rest)) ((eq (car-safe upat) 'or) (let ((all (> (length (cdr upat)) 1)) @@ -524,7 +591,7 @@ and otherwise defers to REST which is a list of branches of the form (defun pcase--q1 (sym qpat matches code vars rest) "Return code that runs CODE if SYM matches QPAT and if MATCHES match. -and if not, defers to REST which is a list of branches of the form +Otherwise, it defers to REST which is a list of branches of the form \(OTHER_MATCH OTHER-CODE . OTHER-VARS)." (cond ((eq (car-safe qpat) '\,) (error "Can't use `,UPATTERN")) @@ -539,14 +606,20 @@ and if not, defers to REST which is a list of branches of the form (pcase--split-rest sym (apply-partially #'pcase--split-consp syma symd) rest) - (pcase--if `(consp ,sym) - `(let ((,syma (car ,sym)) - (,symd (cdr ,sym))) - ,(pcase--u1 `((match ,syma . ,(pcase--upat (car qpat))) - (match ,symd . ,(pcase--upat (cdr qpat))) - ,@matches) - code vars then-rest)) - (pcase--u else-rest))))) + (let ((then-body (pcase--u1 `((match ,syma . ,(pcase--upat (car qpat))) + (match ,symd . ,(pcase--upat (cdr qpat))) + ,@matches) + code vars then-rest))) + (pcase--if + `(consp ,sym) + ;; We want to be careful to only add bindings that are used. + ;; The byte-compiler could do that for us, but it would have to pay + ;; attention to the `consp' test in order to figure out that car/cdr + ;; can't signal errors and our byte-compiler is not that clever. + `(let (,@(if (get syma 'pcase-used) `((,syma (car ,sym)))) + ,@(if (get symd 'pcase-used) `((,symd (cdr ,sym))))) + ,then-body) + (pcase--u else-rest)))))) ((or (integerp qpat) (symbolp qpat) (stringp qpat)) (destructuring-bind (then-rest &rest else-rest) (pcase--split-rest sym (apply-partially 'pcase--split-equal qpat) rest) |