commit 244de7b0ed3bb23e700c9edef51e413602d8720a (HEAD, refs/remotes/origin/master) Author: Tino Calancha Date: Fri Mar 3 18:26:30 2017 +0900 Use lexical binding in benchmark.el * lisp/emacs-lisp/benchmark.el: Enable lexical binding. (benchmark-elapse): Use 'declare'. * test/lisp/emacs-lisp/benchmark-tests.el: Add test suite. diff --git a/lisp/emacs-lisp/benchmark.el b/lisp/emacs-lisp/benchmark.el index 25eddf5f6b..a2217d2095 100644 --- a/lisp/emacs-lisp/benchmark.el +++ b/lisp/emacs-lisp/benchmark.el @@ -1,4 +1,4 @@ -;;; benchmark.el --- support for benchmarking code +;;; benchmark.el --- support for benchmarking code -*- lexical-binding: t -*- ;; Copyright (C) 2003-2017 Free Software Foundation, Inc. @@ -33,6 +33,7 @@ (defmacro benchmark-elapse (&rest forms) "Return the time in seconds elapsed for execution of FORMS." + (declare (indent 0) (debug t)) (let ((t1 (make-symbol "t1")) (t2 (make-symbol "t2"))) `(let (,t1 ,t2) @@ -41,9 +42,6 @@ (setq ,t2 (current-time)) (float-time (time-subtract ,t2 ,t1))))) -(put 'benchmark-elapse 'edebug-form-spec t) -(put 'benchmark-elapse 'lisp-indent-function 0) - ;;;###autoload (defmacro benchmark-run (&optional repetitions &rest forms) "Time execution of FORMS. diff --git a/test/lisp/emacs-lisp/benchmark-tests.el b/test/lisp/emacs-lisp/benchmark-tests.el new file mode 100644 index 0000000000..14426aeec4 --- /dev/null +++ b/test/lisp/emacs-lisp/benchmark-tests.el @@ -0,0 +1,51 @@ +;;; benchmark-tests.el --- Test suite for benchmark. -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; 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 +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'benchmark) +(require 'ert) + +(ert-deftest benchmark-tests () + (let (str t-long t-short) + (should (consp (benchmark-run nil (1+ 0)))) + (should (consp (benchmark-run 1 (1+ 0)))) + (should (stringp (benchmark nil (1+ 0)))) + (should (stringp (benchmark 1 (1+ 0)))) + (should (consp (benchmark-run-compiled nil (1+ 0)))) + (should (consp (benchmark-run-compiled 1 (1+ 0)))) + ;; First test is heavier, must need longer time. + (should (> (car (benchmark-run nil + (let ((n 100000)) (while (> n 1) (setq n (1- n)))))) + (car (benchmark-run nil (1+ 0))))) + (should (> (car (benchmark-run nil + (let ((n 100000)) (while (> n 1) (setq n (1- n)))))) + (car (benchmark-run nil (1+ 0))))) + (should (> (car (benchmark-run-compiled nil + (let ((n 100000)) (while (> n 1) (setq n (1- n)))))) + (car (benchmark-run-compiled nil (1+ 0))))) + (setq str (benchmark nil '(let ((n 100000)) (while (> n 1) (setq n (1- n)))))) + (string-match "Elapsed time: \\([0-9.]+\\)" str) + (setq t-long (string-to-number (match-string 1 str))) + (setq str (benchmark nil '(1+ 0))) + (string-match "Elapsed time: \\([0-9.]+\\)" str) + (setq t-short (string-to-number (match-string 1 str))) + (should (> t-long t-short)))) + +;;; benchmark-tests.el ends here. commit f5388ba8a7f3970afd0e2bcc52c834ae56178442 Author: Noam Postavsky Date: Thu Mar 2 22:37:03 2017 -0500 Switch pp.el to lexical binding Additionally, do some minor code cleanup. * lisp/emacs-lisp/pp.el: Set lexical-binding. (pp-buffer): Use skip-syntax-forward. (pp-eval-expression): Use push. (pp-last-sexp): Use with-syntax-table. * test/lisp/emacs-lisp/pp-tests.el: New tests. diff --git a/lisp/emacs-lisp/pp.el b/lisp/emacs-lisp/pp.el index 2938c37e8a..7ef46a48bd 100644 --- a/lisp/emacs-lisp/pp.el +++ b/lisp/emacs-lisp/pp.el @@ -1,4 +1,4 @@ -;;; pp.el --- pretty printer for Emacs Lisp +;;; pp.el --- pretty printer for Emacs Lisp -*- lexical-binding: t -*- ;; Copyright (C) 1989, 1993, 2001-2017 Free Software Foundation, Inc. @@ -67,8 +67,7 @@ to make output that `read' can handle, whenever this is possible." (progn (skip-chars-backward " \t\n") (point))) (insert "\n")))) ((ignore-errors (up-list 1) t) - (while (looking-at-p "\\s)") - (forward-char 1)) + (skip-syntax-forward ")") (delete-region (point) (progn (skip-chars-forward " \t\n") (point))) @@ -129,7 +128,7 @@ Also add the value to the front of the list in the variable `values'." (interactive (list (read--expression "Eval: "))) (message "Evaluating...") - (setq values (cons (eval expression lexical-binding) values)) + (push (eval expression lexical-binding) values) (pp-display-expression (car values) "*Pp Eval Output*")) ;;;###autoload @@ -141,22 +140,21 @@ Also add the value to the front of the list in the variable `values'." (defun pp-last-sexp () "Read sexp before point. Ignores leading comment characters." - (let ((stab (syntax-table)) (pt (point)) start exp) - (set-syntax-table emacs-lisp-mode-syntax-table) - (save-excursion - (forward-sexp -1) - ;; If first line is commented, ignore all leading comments: - (if (save-excursion (beginning-of-line) (looking-at-p "[ \t]*;")) - (progn - (setq exp (buffer-substring (point) pt)) - (while (string-match "\n[ \t]*;+" exp start) - (setq start (1+ (match-beginning 0)) - exp (concat (substring exp 0 start) - (substring exp (match-end 0))))) - (setq exp (read exp))) - (setq exp (read (current-buffer))))) - (set-syntax-table stab) - exp)) + (with-syntax-table emacs-lisp-mode-syntax-table + (let ((pt (point))) + (save-excursion + (forward-sexp -1) + (read + ;; If first line is commented, ignore all leading comments: + (if (save-excursion (beginning-of-line) (looking-at-p "[ \t]*;")) + (let ((exp (buffer-substring (point) pt)) + (start nil)) + (while (string-match "\n[ \t]*;+" exp start) + (setq start (1+ (match-beginning 0)) + exp (concat (substring exp 0 start) + (substring exp (match-end 0))))) + exp) + (current-buffer))))))) ;;;###autoload (defun pp-eval-last-sexp (arg) @@ -178,19 +176,6 @@ Ignores leading comment characters." (insert (pp-to-string (macroexpand-1 (pp-last-sexp)))) (pp-macroexpand-expression (pp-last-sexp)))) -;;; Test cases for quote -;; (pp-eval-expression ''(quote quote)) -;; (pp-eval-expression ''((quote a) (quote b))) -;; (pp-eval-expression ''('a 'b)) ; same as above -;; (pp-eval-expression ''((quote (quote quote)) (quote quote))) -;; These do not satisfy the quote test. -;; (pp-eval-expression ''quote) -;; (pp-eval-expression ''(quote)) -;; (pp-eval-expression ''(quote . quote)) -;; (pp-eval-expression ''(quote a b)) -;; (pp-eval-expression ''(quotefoo)) -;; (pp-eval-expression ''(a b)) - (provide 'pp) ; so (require 'pp) works ;;; pp.el ends here diff --git a/test/lisp/emacs-lisp/pp-tests.el b/test/lisp/emacs-lisp/pp-tests.el new file mode 100644 index 0000000000..b9ed79c774 --- /dev/null +++ b/test/lisp/emacs-lisp/pp-tests.el @@ -0,0 +1,35 @@ +;;; pp-tests.el --- Test suite for pretty printer. -*- lexical-binding: t -*- + +;; Copyright (C) 2017 Free Software Foundation, Inc. + +;; 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 +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'pp) + +(ert-deftest pp-print-quote () + (should (string= (pp-to-string 'quote) "quote")) + (should (string= (pp-to-string ''quote) "'quote")) + (should (string= (pp-to-string '('a 'b)) "('a 'b)\n")) + (should (string= (pp-to-string '(''quote 'quote)) "(''quote 'quote)\n")) + (should (string= (pp-to-string '(quote)) "(quote)\n")) + (should (string= (pp-to-string '(quote . quote)) "(quote . quote)\n")) + (should (string= (pp-to-string '(quote a b)) "(quote a b)\n")) + (should (string= (pp-to-string '(quotefoo)) "(quotefoo)\n")) + (should (string= (pp-to-string '(a b)) "(a b)\n"))) + +;;; pp-tests.el ends here. commit 55c0c3e31bc3dff83753cdba6288228bd025ac84 Author: Chunyang Xu Date: Sat Feb 11 14:17:26 2017 +0800 Fix completing-read call in reb-change-syntax * lisp/emacs-lisp/re-builder.el (reb-change-syntax): Use 'default' arg of completing-read. Copyright-paperwork-exempt: yes diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el index 5264dae52a..f60d723a88 100644 --- a/lisp/emacs-lisp/re-builder.el +++ b/lisp/emacs-lisp/re-builder.el @@ -488,10 +488,10 @@ If the optional PAUSE is non-nil then pause at the end in any case." Optional argument SYNTAX must be specified if called non-interactively." (interactive (list (intern - (completing-read "Select syntax: " - (mapcar (lambda (el) (cons (symbol-name el) 1)) - '(read string sregex rx)) - nil t (symbol-name reb-re-syntax))))) + (completing-read + (format "Select syntax (default %s): " reb-re-syntax) + '(read string sregex rx) + nil t nil nil (symbol-name reb-re-syntax))))) (if (memq syntax '(read string sregex rx)) (let ((buffer (get-buffer reb-buffer))) commit 71871670c816f2ecc4383ef0fe516cbd9c9f781f Author: Rolf Ade Date: Sun Feb 5 19:46:24 2017 +0100 sql-mode w/ sqlite: In-memory database Enable the usage of an in-memory database. Prior to this, sql-mode w/ sqlite could only be used with file databases. * list/progmodes/sql.el (sql-get-login-ext): Don't expand an empty file name provided by the user, but call sub-process sqlite with that, in which case it uses an in-memory database. Copyright-paperwork-exempt: yes diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el index 8868343129..634c6b57bd 100644 --- a/lisp/progmodes/sql.el +++ b/lisp/progmodes/sql.el @@ -2952,17 +2952,20 @@ value. (The property value is used as the PREDICATE argument to (use-dialog-box nil)) (cond ((plist-member plist :file) - (expand-file-name - (read-file-name prompt - (file-name-directory last-value) default 'confirm - (file-name-nondirectory last-value) - (when (plist-get plist :file) - `(lambda (f) - (if (not (file-regular-p f)) - t - (string-match - (concat "\\<" ,(plist-get plist :file) "\\>") - (file-name-nondirectory f)))))))) + (let ((file-name + (read-file-name prompt + (file-name-directory last-value) default 'confirm + (file-name-nondirectory last-value) + (when (plist-get plist :file) + `(lambda (f) + (if (not (file-regular-p f)) + t + (string-match + (concat "\\<" ,(plist-get plist :file) "\\>") + (file-name-nondirectory f)))))))) + (if (string= file-name "") + "" + (expand-file-name file-name)))) ((plist-member plist :completion) (completing-read prompt-def (plist-get plist :completion) nil t commit c733d9169ce44f5600d41cf0e67e021371954c8e Author: Allen Li Date: Thu Mar 2 07:56:53 2017 -0500 Stop abbrev-prefix-mark from adding extra newline (Bug#25767) `abbrev--before-point' does not adjust `pos' to account for when it deletes the "-" left by abbrev-prefix-mark. Therefore, when `abbrev-before-point' goes to restore point, it moves point one character too far forward. * lisp/abbrev.el (abbrev--before-point): Adjust pos when deleting "-". diff --git a/lisp/abbrev.el b/lisp/abbrev.el index cbc604c23d..01ad3d478f 100644 --- a/lisp/abbrev.el +++ b/lisp/abbrev.el @@ -720,9 +720,10 @@ then ABBREV is looked up in that table only." (setq start abbrev-start-location) (setq abbrev-start-location nil) ;; Remove the hyphen inserted by `abbrev-prefix-mark'. - (if (and (< start (point-max)) - (eq (char-after start) ?-)) - (delete-region start (1+ start))) + (when (and (< start (point-max)) + (eq (char-after start) ?-)) + (delete-region start (1+ start)) + (setq pos (1- pos))) (skip-syntax-backward " ") (setq end (point)) (when (> end start) commit 6a9ba271a956127e566192b33fc811e802d2d475 Author: Tino Calancha Date: Fri Mar 3 08:37:23 2017 +0900 * lisp/subr.el (apply-partially): Move to 'Basic Lisp functions' section. diff --git a/lisp/subr.el b/lisp/subr.el index 4f848d1400..6b0403890c 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -132,15 +132,6 @@ buffer-local wherever it is set." (list 'progn (list 'defvar var val docstring) (list 'make-variable-buffer-local (list 'quote var)))) -(defun apply-partially (fun &rest args) - "Return a function that is a partial application of FUN to ARGS. -ARGS is a list of the first N arguments to pass to FUN. -The result is a new function which does the same as FUN, except that -the first N arguments are fixed at the values with which this function -was called." - (lambda (&rest args2) - (apply fun (append args args2)))) - (defmacro push (newelt place) "Add NEWELT to the list stored in the generalized variable PLACE. This is morally equivalent to (setf PLACE (cons NEWELT PLACE)), @@ -344,6 +335,15 @@ configuration." (and (consp object) (eq (car object) 'frame-configuration))) +(defun apply-partially (fun &rest args) + "Return a function that is a partial application of FUN to ARGS. +ARGS is a list of the first N arguments to pass to FUN. +The result is a new function which does the same as FUN, except that +the first N arguments are fixed at the values with which this function +was called." + (lambda (&rest args2) + (apply fun (append args args2)))) + ;;;; List functions. commit 56aaaf9bbaf9772ea714b16aa7ed2a9693ac92e3 Author: Paul Eggert Date: Thu Mar 2 13:48:47 2017 -0800 Restore XFLOATINT but with restricted args Turn instances of extract_float into XFLOAT_DATA when possible, and to a resurrected XFLOATINT when the arg is a number. The resurrected XFLOATINT is more like XFLOAT and XINT in that is valid only if its arg is a number. This clarifies the ways in which floats can be extracted at the C level. * src/editfns.c (styled_format): * src/floatfns.c (extract_float, Fexpt): Use XFLOATINT rather than open-coding it. * src/fns.c (internal_equal): * src/image.c (imagemagick_load_image): * src/xdisp.c (resize_mini_window): Prefer XFLOAT_DATA to extract_float on values known to be floats. * src/frame.c (x_set_screen_gamma): * src/frame.h (NUMVAL): * src/image.c (x_edge_detection, compute_image_size): * src/lread.c (read_filtered_event): * src/window.c (Fset_window_vscroll): * src/xdisp.c (handle_single_display_spec, try_scrolling) (redisplay_window, calc_pixel_width_or_height, x_produce_glyphs) (on_hot_spot_p): Prefer XFLOATINT to extract_float on values known to be numbers. * src/lisp.h (XFLOATINT): Bring back this function, except it now assumes its argument is a number. diff --git a/src/editfns.c b/src/editfns.c index e3c8548b5a..8f85f99b94 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -4312,12 +4312,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) char sprintf_buf[SPRINTF_BUFSIZE]; ptrdiff_t sprintf_bytes; if (conversion == 'e' || conversion == 'f' || conversion == 'g') - { - double x = (INTEGERP (args[n]) - ? XINT (args[n]) - : XFLOAT_DATA (args[n])); - sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); - } + sprintf_bytes = sprintf (sprintf_buf, convspec, prec, + XFLOATINT (args[n])); else if (conversion == 'c') { /* Don't use sprintf here, as it might mishandle prec. */ diff --git a/src/floatfns.c b/src/floatfns.c index 737fb22091..dda0369809 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -67,10 +67,7 @@ double extract_float (Lisp_Object num) { CHECK_NUMBER_OR_FLOAT (num); - - if (FLOATP (num)) - return XFLOAT_DATA (num); - return (double) XINT (num); + return XFLOATINT (num); } /* Trig functions. */ @@ -207,8 +204,6 @@ DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0, doc: /* Return the exponential ARG1 ** ARG2. */) (Lisp_Object arg1, Lisp_Object arg2) { - double f1, f2, f3; - CHECK_NUMBER_OR_FLOAT (arg1); CHECK_NUMBER_OR_FLOAT (arg2); if (INTEGERP (arg1) /* common lisp spec */ @@ -232,10 +227,7 @@ DEFUN ("expt", Fexpt, Sexpt, 2, 2, 0, XSETINT (val, acc); return val; } - f1 = FLOATP (arg1) ? XFLOAT_DATA (arg1) : XINT (arg1); - f2 = FLOATP (arg2) ? XFLOAT_DATA (arg2) : XINT (arg2); - f3 = pow (f1, f2); - return make_float (f3); + return make_float (pow (XFLOATINT (arg1), XFLOATINT (arg2))); } DEFUN ("log", Flog, Slog, 1, 2, 0, diff --git a/src/fns.c b/src/fns.c index b4f416f4f5..10653558eb 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2158,10 +2158,8 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, { case Lisp_Float: { - double d1, d2; - - d1 = extract_float (o1); - d2 = extract_float (o2); + double d1 = XFLOAT_DATA (o1); + double d2 = XFLOAT_DATA (o2); /* If d is a NaN, then d != d. Two NaNs should be `equal' even though they are not =. */ return d1 == d2 || (d1 != d1 && d2 != d2); diff --git a/src/frame.c b/src/frame.c index daf424567d..5e1e2f1990 100644 --- a/src/frame.c +++ b/src/frame.c @@ -3530,9 +3530,9 @@ x_set_screen_gamma (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu if (NILP (new_value)) f->gamma = 0; - else if (NUMBERP (new_value) && extract_float (new_value) > 0) + else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0) /* The value 0.4545 is the normal viewing gamma. */ - f->gamma = 1.0 / (0.4545 * extract_float (new_value)); + f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value)); else signal_error ("Invalid screen-gamma", new_value); diff --git a/src/frame.h b/src/frame.h index 6f85f85e79..5f18901a17 100644 --- a/src/frame.h +++ b/src/frame.h @@ -624,7 +624,7 @@ fset_desired_tool_bar_string (struct frame *f, Lisp_Object val) INLINE double NUMVAL (Lisp_Object x) { - return NUMBERP (x) ? extract_float (x) : -1; + return NUMBERP (x) ? XFLOATINT (x) : -1; } INLINE double diff --git a/src/image.c b/src/image.c index 3711dd18d6..3ebf469e8b 100644 --- a/src/image.c +++ b/src/image.c @@ -4915,19 +4915,19 @@ x_edge_detection (struct frame *f, struct image *img, Lisp_Object matrix, for (i = 0; i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); ++i, matrix = XCDR (matrix)) - trans[i] = extract_float (XCAR (matrix)); + trans[i] = XFLOATINT (XCAR (matrix)); } else if (VECTORP (matrix) && ASIZE (matrix) >= 9) { for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) - trans[i] = extract_float (AREF (matrix, i)); + trans[i] = XFLOATINT (AREF (matrix, i)); } if (NILP (color_adjust)) color_adjust = make_number (0xffff / 2); if (i == 9 && NUMBERP (color_adjust)) - x_detect_edges (f, img, trans, extract_float (color_adjust)); + x_detect_edges (f, img, trans, XFLOATINT (color_adjust)); } @@ -8077,7 +8077,7 @@ compute_image_size (size_t width, size_t height, value = image_spec_value (spec, QCscale, NULL); if (NUMBERP (value)) - scale = extract_float (value); + scale = XFLOATINT (value); /* If width and/or height is set in the display spec assume we want to scale to those values. If either h or w is unspecified, the @@ -8684,7 +8684,7 @@ imagemagick_load_image (struct frame *f, struct image *img, value = image_spec_value (img->spec, QCrotation, NULL); if (FLOATP (value)) { - rotation = extract_float (value); + rotation = XFLOAT_DATA (value); status = MagickRotateImage (image_wand, bg_wand, rotation); if (status == MagickFalse) { diff --git a/src/lisp.h b/src/lisp.h index a910411046..220188cdb8 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2803,6 +2803,12 @@ CHECK_NATNUM (Lisp_Object x) CHECK_TYPE (INTEGERP (x), Qinteger_or_marker_p, x); \ } while (false) +INLINE double +XFLOATINT (Lisp_Object n) +{ + return FLOATP (n) ? XFLOAT_DATA (n) : XINT (n); +} + INLINE void CHECK_NUMBER_OR_FLOAT (Lisp_Object x) { diff --git a/src/lread.c b/src/lread.c index 1b154b7326..5c6a7f97f5 100644 --- a/src/lread.c +++ b/src/lread.c @@ -601,7 +601,7 @@ read_filtered_event (bool no_switch_frame, bool ascii_required, /* Compute timeout. */ if (NUMBERP (seconds)) { - double duration = extract_float (seconds); + double duration = XFLOATINT (seconds); struct timespec wait_time = dtotimespec (duration); end_time = timespec_add (current_timespec (), wait_time); } diff --git a/src/window.c b/src/window.c index 3e2eb1664c..95690443f8 100644 --- a/src/window.c +++ b/src/window.c @@ -7129,8 +7129,8 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */) int old_dy = w->vscroll; w->vscroll = - (NILP (pixels_p) - ? FRAME_LINE_HEIGHT (f) * extract_float (vscroll) - : extract_float (vscroll)); + ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll) + : XFLOATINT (vscroll)); w->vscroll = min (w->vscroll, 0); if (w->vscroll != old_dy) diff --git a/src/xdisp.c b/src/xdisp.c index 12f42d14ce..82c4c775c1 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -4870,7 +4870,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, height = safe_call1 (it->font_height, face->lface[LFACE_HEIGHT_INDEX]); if (NUMBERP (height)) - new_height = extract_float (height); + new_height = XFLOATINT (height); } else if (NUMBERP (it->font_height)) { @@ -4879,7 +4879,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, f = FACE_FROM_ID (it->f, lookup_basic_face (it->f, DEFAULT_FACE_ID)); - new_height = (extract_float (it->font_height) + new_height = (XFLOATINT (it->font_height) * XINT (f->lface[LFACE_HEIGHT_INDEX])); } else @@ -4894,7 +4894,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, unbind_to (count, Qnil); if (NUMBERP (value)) - new_height = extract_float (value); + new_height = XFLOATINT (value); } if (new_height > 0) @@ -4916,7 +4916,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, return 0; value = XCAR (XCDR (spec)); - if (NUMBERP (value) && extract_float (value) > 0) + if (NUMBERP (value) && XFLOATINT (value) > 0) it->space_width = value; } @@ -4968,7 +4968,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (NUMBERP (value)) { struct face *face = FACE_FROM_ID (it->f, it->face_id); - it->voffset = - (extract_float (value) + it->voffset = - (XFLOATINT (value) * (normal_char_height (face->font, -1))); } #endif /* HAVE_WINDOW_SYSTEM */ @@ -11058,7 +11058,7 @@ resize_mini_window (struct window *w, bool exact_p) /* Compute the max. number of lines specified by the user. */ if (FLOATP (Vmax_mini_window_height)) - max_height = extract_float (Vmax_mini_window_height) * total_height; + max_height = XFLOAT_DATA (Vmax_mini_window_height) * total_height; else if (INTEGERP (Vmax_mini_window_height)) max_height = XINT (Vmax_mini_window_height) * unit; else @@ -15501,7 +15501,7 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) { - double float_amount = extract_float (aggressive) * height; + double float_amount = XFLOATINT (aggressive) * height; int aggressive_scroll = float_amount; if (aggressive_scroll == 0 && float_amount > 0) aggressive_scroll = 1; @@ -15617,7 +15617,7 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) { - double float_amount = extract_float (aggressive) * height; + double float_amount = XFLOATINT (aggressive) * height; int aggressive_scroll = float_amount; if (aggressive_scroll == 0 && float_amount > 0) aggressive_scroll = 1; @@ -16968,7 +16968,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) scroll-*-aggressively. */ if (!scroll_conservatively && NUMBERP (aggressive)) { - double float_amount = extract_float (aggressive); + double float_amount = XFLOATINT (aggressive); pt_offset = float_amount * WINDOW_BOX_TEXT_HEIGHT (w); if (pt_offset == 0 && float_amount > 0) @@ -24557,7 +24557,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, int base_unit = (width_p ? FRAME_COLUMN_WIDTH (it->f) : FRAME_LINE_HEIGHT (it->f)); - return OK_PIXELS (extract_float (prop) * base_unit); + return OK_PIXELS (XFLOATINT (prop) * base_unit); } if (CONSP (prop)) @@ -24612,7 +24612,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, if (NUMBERP (car)) { double fact; - pixels = extract_float (car); + pixels = XFLOATINT (car); if (NILP (cdr)) return OK_PIXELS (pixels); if (calc_pixel_width_or_height (&fact, it, cdr, @@ -27225,7 +27225,7 @@ x_produce_glyphs (struct it *it) bool stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); if (stretched_p) - it->pixel_width *= extract_float (it->space_width); + it->pixel_width *= XFLOATINT (it->space_width); /* If face has a box, add the box thickness to the character height. If character has a box line to the left and/or @@ -29703,7 +29703,7 @@ on_hot_spot_p (Lisp_Object hot_spot, int x, int y) && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0)) && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0))) { - double r = extract_float (lr); + double r = XFLOATINT (lr); double dx = XINT (lx0) - x; double dy = XINT (ly0) - y; return (dx * dx + dy * dy <= r * r); commit dacafa8c30cdae92f934512664fd2d322d91432b Author: Glenn Morris Date: Thu Mar 2 15:40:15 2017 -0500 Ert commands to error if no test at point (bug#25931) * lisp/emacs-lisp/ert.el (ert-results-mode-menu): Deactivate some items if no test at point. (ert--results-test-at-point-no-redefinition): Add option to signal an error rather than return nil. (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-results-describe-test-at-point): Error if no test at point. diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el index 785f4aca1c..cadd66ca6e 100644 --- a/lisp/emacs-lisp/ert.el +++ b/lisp/emacs-lisp/ert.el @@ -2079,14 +2079,23 @@ and how to display message." '("ERT Results" ["Re-run all tests" ert-results-rerun-all-tests] "--" - ["Re-run test" ert-results-rerun-test-at-point] - ["Debug test" ert-results-rerun-test-at-point-debugging-errors] - ["Show test definition" ert-results-find-test-at-point-other-window] + ;; FIXME? Why are there (at least) 3 different ways to decide if + ;; there is a test at point? + ["Re-run test" ert-results-rerun-test-at-point + :active (car (ert--results-test-at-point-allow-redefinition))] + ["Debug test" ert-results-rerun-test-at-point-debugging-errors + :active (car (ert--results-test-at-point-allow-redefinition))] + ["Show test definition" ert-results-find-test-at-point-other-window + :active (ert-test-at-point)] "--" - ["Show backtrace" ert-results-pop-to-backtrace-for-test-at-point] - ["Show messages" ert-results-pop-to-messages-for-test-at-point] - ["Show `should' forms" ert-results-pop-to-should-forms-for-test-at-point] - ["Describe test" ert-results-describe-test-at-point] + ["Show backtrace" ert-results-pop-to-backtrace-for-test-at-point + :active (ert--results-test-at-point-no-redefinition)] + ["Show messages" ert-results-pop-to-messages-for-test-at-point + :active (ert--results-test-at-point-no-redefinition)] + ["Show `should' forms" ert-results-pop-to-should-forms-for-test-at-point + :active (ert--results-test-at-point-no-redefinition)] + ["Describe test" ert-results-describe-test-at-point + :active (ert--results-test-at-point-no-redefinition)] "--" ["Delete test" ert-delete-test] "--" @@ -2237,22 +2246,24 @@ To be used in the ERT results buffer." (and (ert-test-boundp sym) sym)))) -(defun ert--results-test-at-point-no-redefinition () +(defun ert--results-test-at-point-no-redefinition (&optional error) "Return the test at point, or nil. - +If optional argument ERROR is non-nil, signal an error rather than return nil. To be used in the ERT results buffer." (cl-assert (eql major-mode 'ert-results-mode)) - (if (ert--results-test-node-or-null-at-point) - (let* ((node (ert--results-test-node-at-point)) - (test (ert--ewoc-entry-test (ewoc-data node)))) - test) - (let ((progress-bar-begin ert--results-progress-bar-button-begin)) - (when (and (<= progress-bar-begin (point)) - (< (point) (button-end (button-at progress-bar-begin)))) - (let* ((test-index (- (point) progress-bar-begin)) - (test (aref (ert--stats-tests ert--results-stats) + (or + (if (ert--results-test-node-or-null-at-point) + (let* ((node (ert--results-test-node-at-point)) + (test (ert--ewoc-entry-test (ewoc-data node)))) + test) + (let ((progress-bar-begin ert--results-progress-bar-button-begin)) + (when (and (<= progress-bar-begin (point)) + (< (point) (button-end (button-at progress-bar-begin)))) + (let* ((test-index (- (point) progress-bar-begin)) + (test (aref (ert--stats-tests ert--results-stats) test-index))) - test))))) + test)))) + (if error (user-error "No test at point")))) (defun ert--results-test-at-point-allow-redefinition () "Look up the test at point, and check whether it has been redefined. @@ -2377,7 +2388,7 @@ To be used in the ERT results buffer." To be used in the ERT results buffer." (interactive) - (let* ((test (ert--results-test-at-point-no-redefinition)) + (let* ((test (ert--results-test-at-point-no-redefinition t)) (stats ert--results-stats) (pos (ert--stats-test-pos stats test)) (result (aref (ert--stats-test-results stats) pos))) @@ -2406,7 +2417,7 @@ To be used in the ERT results buffer." To be used in the ERT results buffer." (interactive) - (let* ((test (ert--results-test-at-point-no-redefinition)) + (let* ((test (ert--results-test-at-point-no-redefinition t)) (stats ert--results-stats) (pos (ert--stats-test-pos stats test)) (result (aref (ert--stats-test-results stats) pos))) @@ -2427,7 +2438,7 @@ To be used in the ERT results buffer." To be used in the ERT results buffer." (interactive) - (let* ((test (ert--results-test-at-point-no-redefinition)) + (let* ((test (ert--results-test-at-point-no-redefinition t)) (stats ert--results-stats) (pos (ert--stats-test-pos stats test)) (result (aref (ert--stats-test-results stats) pos))) @@ -2554,7 +2565,7 @@ To be used in the ERT results buffer." To be used in the ERT results buffer." (interactive) - (ert-describe-test (ert--results-test-at-point-no-redefinition))) + (ert-describe-test (ert--results-test-at-point-no-redefinition t))) ;;; Actions on load/unload. commit d0d26c1379598983d2163deb13ba8ab13b14ba2c Author: Paul Eggert Date: Thu Mar 2 09:21:19 2017 -0800 Remove XFLOATINT * src/lisp.h (XFLOATINT): Remove this alias for extract_float. All callers changed to use extract_float. * src/frame.h (NUMVAL): Now an inline function, not a macro. diff --git a/src/floatfns.c b/src/floatfns.c index 96711faff6..737fb22091 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -178,7 +178,7 @@ The function returns the cons cell (SGNFCAND . EXP). If X is zero, both parts (SGNFCAND and EXP) are zero. */) (Lisp_Object x) { - double f = XFLOATINT (x); + double f = extract_float (x); int exponent; double sgnfcand = frexp (f, &exponent); return Fcons (make_float (sgnfcand), make_number (exponent)); @@ -191,7 +191,7 @@ EXPONENT must be an integer. */) { CHECK_NUMBER (exponent); int e = min (max (INT_MIN, XINT (exponent)), INT_MAX); - return make_float (ldexp (XFLOATINT (sgnfcand), e)); + return make_float (ldexp (extract_float (sgnfcand), e)); } DEFUN ("exp", Fexp, Sexp, 1, 1, 0, diff --git a/src/frame.c b/src/frame.c index 5e1e2f1990..daf424567d 100644 --- a/src/frame.c +++ b/src/frame.c @@ -3530,9 +3530,9 @@ x_set_screen_gamma (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu if (NILP (new_value)) f->gamma = 0; - else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0) + else if (NUMBERP (new_value) && extract_float (new_value) > 0) /* The value 0.4545 is the normal viewing gamma. */ - f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value)); + f->gamma = 1.0 / (0.4545 * extract_float (new_value)); else signal_error ("Invalid screen-gamma", new_value); diff --git a/src/frame.h b/src/frame.h index 7331352a20..6f85f85e79 100644 --- a/src/frame.h +++ b/src/frame.h @@ -621,7 +621,11 @@ fset_desired_tool_bar_string (struct frame *f, Lisp_Object val) } #endif /* HAVE_WINDOW_SYSTEM && !USE_GTK && !HAVE_NS */ -#define NUMVAL(X) (NUMBERP (X) ? XFLOATINT (X) : -1) +INLINE double +NUMVAL (Lisp_Object x) +{ + return NUMBERP (x) ? extract_float (x) : -1; +} INLINE double default_pixels_per_inch_x (void) diff --git a/src/image.c b/src/image.c index fc396c7353..3711dd18d6 100644 --- a/src/image.c +++ b/src/image.c @@ -4915,19 +4915,19 @@ x_edge_detection (struct frame *f, struct image *img, Lisp_Object matrix, for (i = 0; i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix)); ++i, matrix = XCDR (matrix)) - trans[i] = XFLOATINT (XCAR (matrix)); + trans[i] = extract_float (XCAR (matrix)); } else if (VECTORP (matrix) && ASIZE (matrix) >= 9) { for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i) - trans[i] = XFLOATINT (AREF (matrix, i)); + trans[i] = extract_float (AREF (matrix, i)); } if (NILP (color_adjust)) color_adjust = make_number (0xffff / 2); if (i == 9 && NUMBERP (color_adjust)) - x_detect_edges (f, img, trans, XFLOATINT (color_adjust)); + x_detect_edges (f, img, trans, extract_float (color_adjust)); } diff --git a/src/lisp.h b/src/lisp.h index a757dfdbb3..a910411046 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2803,12 +2803,6 @@ CHECK_NATNUM (Lisp_Object x) CHECK_TYPE (INTEGERP (x), Qinteger_or_marker_p, x); \ } while (false) -INLINE double -XFLOATINT (Lisp_Object n) -{ - return extract_float (n); -} - INLINE void CHECK_NUMBER_OR_FLOAT (Lisp_Object x) { diff --git a/src/nsterm.m b/src/nsterm.m index eaefea7985..80261d6d76 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -4814,7 +4814,7 @@ Needs to be here because ns_initialize_display_info () uses AppKit classes. /* this is a standard variable */ ns_default ("AppleAntiAliasingThreshold", &tmp, make_float (10.0), make_float (6.0), YES, NO); - ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp); + ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp); } NSTRACE_MSG ("Colors"); diff --git a/src/window.c b/src/window.c index 95690443f8..3e2eb1664c 100644 --- a/src/window.c +++ b/src/window.c @@ -7129,8 +7129,8 @@ If PIXELS-P is non-nil, the return value is VSCROLL. */) int old_dy = w->vscroll; w->vscroll = - (NILP (pixels_p) - ? FRAME_LINE_HEIGHT (f) * XFLOATINT (vscroll) - : XFLOATINT (vscroll)); + ? FRAME_LINE_HEIGHT (f) * extract_float (vscroll) + : extract_float (vscroll)); w->vscroll = min (w->vscroll, 0); if (w->vscroll != old_dy) diff --git a/src/xdisp.c b/src/xdisp.c index 851a32b4f8..12f42d14ce 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -4870,7 +4870,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, height = safe_call1 (it->font_height, face->lface[LFACE_HEIGHT_INDEX]); if (NUMBERP (height)) - new_height = XFLOATINT (height); + new_height = extract_float (height); } else if (NUMBERP (it->font_height)) { @@ -4879,7 +4879,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, f = FACE_FROM_ID (it->f, lookup_basic_face (it->f, DEFAULT_FACE_ID)); - new_height = (XFLOATINT (it->font_height) + new_height = (extract_float (it->font_height) * XINT (f->lface[LFACE_HEIGHT_INDEX])); } else @@ -4894,7 +4894,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, unbind_to (count, Qnil); if (NUMBERP (value)) - new_height = XFLOATINT (value); + new_height = extract_float (value); } if (new_height > 0) @@ -4916,7 +4916,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, return 0; value = XCAR (XCDR (spec)); - if (NUMBERP (value) && XFLOATINT (value) > 0) + if (NUMBERP (value) && extract_float (value) > 0) it->space_width = value; } @@ -4968,7 +4968,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (NUMBERP (value)) { struct face *face = FACE_FROM_ID (it->f, it->face_id); - it->voffset = - (XFLOATINT (value) + it->voffset = - (extract_float (value) * (normal_char_height (face->font, -1))); } #endif /* HAVE_WINDOW_SYSTEM */ @@ -11058,7 +11058,7 @@ resize_mini_window (struct window *w, bool exact_p) /* Compute the max. number of lines specified by the user. */ if (FLOATP (Vmax_mini_window_height)) - max_height = XFLOATINT (Vmax_mini_window_height) * total_height; + max_height = extract_float (Vmax_mini_window_height) * total_height; else if (INTEGERP (Vmax_mini_window_height)) max_height = XINT (Vmax_mini_window_height) * unit; else @@ -15501,7 +15501,7 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) { - double float_amount = XFLOATINT (aggressive) * height; + double float_amount = extract_float (aggressive) * height; int aggressive_scroll = float_amount; if (aggressive_scroll == 0 && float_amount > 0) aggressive_scroll = 1; @@ -15617,7 +15617,7 @@ try_scrolling (Lisp_Object window, bool just_this_one_p, height = WINDOW_BOX_TEXT_HEIGHT (w); if (NUMBERP (aggressive)) { - double float_amount = XFLOATINT (aggressive) * height; + double float_amount = extract_float (aggressive) * height; int aggressive_scroll = float_amount; if (aggressive_scroll == 0 && float_amount > 0) aggressive_scroll = 1; @@ -16968,7 +16968,7 @@ redisplay_window (Lisp_Object window, bool just_this_one_p) scroll-*-aggressively. */ if (!scroll_conservatively && NUMBERP (aggressive)) { - double float_amount = XFLOATINT (aggressive); + double float_amount = extract_float (aggressive); pt_offset = float_amount * WINDOW_BOX_TEXT_HEIGHT (w); if (pt_offset == 0 && float_amount > 0) @@ -24557,7 +24557,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, int base_unit = (width_p ? FRAME_COLUMN_WIDTH (it->f) : FRAME_LINE_HEIGHT (it->f)); - return OK_PIXELS (XFLOATINT (prop) * base_unit); + return OK_PIXELS (extract_float (prop) * base_unit); } if (CONSP (prop)) @@ -24612,7 +24612,7 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, if (NUMBERP (car)) { double fact; - pixels = XFLOATINT (car); + pixels = extract_float (car); if (NILP (cdr)) return OK_PIXELS (pixels); if (calc_pixel_width_or_height (&fact, it, cdr, @@ -27225,7 +27225,7 @@ x_produce_glyphs (struct it *it) bool stretched_p = it->char_to_display == ' ' && !NILP (it->space_width); if (stretched_p) - it->pixel_width *= XFLOATINT (it->space_width); + it->pixel_width *= extract_float (it->space_width); /* If face has a box, add the box thickness to the character height. If character has a box line to the left and/or @@ -29703,7 +29703,7 @@ on_hot_spot_p (Lisp_Object hot_spot, int x, int y) && (lx0 = XCAR (XCAR (circ)), INTEGERP (lx0)) && (ly0 = XCDR (XCAR (circ)), INTEGERP (ly0))) { - double r = XFLOATINT (lr); + double r = extract_float (lr); double dx = XINT (lx0) - x; double dy = XINT (ly0) - y; return (dx * dx + dy * dy <= r * r); commit 4e2622bf0d63c40f447d44e6401ea054ef55b261 Author: Paul Eggert Date: Thu Mar 2 09:11:11 2017 -0800 Fix rounding errors in <, =, etc. * etc/NEWS: Document this. * src/bytecode.c (exec_byte_code): * src/data.c (arithcompare): Do not lose information when comparing floats to integers. * test/src/data-tests.el (data-tests-=, data-tests-<) (data-tests->, data-tests-<=, data-tests->=): Test this. diff --git a/etc/NEWS b/etc/NEWS index 5b5baff44e..17353936e7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -902,6 +902,11 @@ interpreting consecutive runs of numerical characters as numbers, and compares their numerical values. According to this predicate, "foo2.png" is smaller than "foo12.png". +--- +** Numeric comparisons no longer return incorrect answers due to +internal rounding errors. For example, (< most-positive-fixnum (+ 1.0 +most-positive-fixnum)) now correctly returns t on 64-bit hosts. + +++ ** The new function 'char-from-name' converts a Unicode name string to the corresponding character code. diff --git a/src/bytecode.c b/src/bytecode.c index 4414b077bb..e781a87d16 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -992,18 +992,14 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, CASE (Beqlsign): { Lisp_Object v2 = POP, v1 = TOP; - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1); - CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2); - bool equal; if (FLOATP (v1) || FLOATP (v2)) + TOP = arithcompare (v1, v2, ARITH_EQUAL); + else { - double f1 = FLOATP (v1) ? XFLOAT_DATA (v1) : XINT (v1); - double f2 = FLOATP (v2) ? XFLOAT_DATA (v2) : XINT (v2); - equal = f1 == f2; + CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v1); + CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (v2); + TOP = EQ (v1, v2) ? Qt : Qnil; } - else - equal = XINT (v1) == XINT (v2); - TOP = equal ? Qt : Qnil; NEXT; } diff --git a/src/data.c b/src/data.c index 32ec89871a..88d86697e4 100644 --- a/src/data.c +++ b/src/data.c @@ -2392,68 +2392,90 @@ bool-vector. IDX starts at 0. */) /* Arithmetic functions */ Lisp_Object -arithcompare (Lisp_Object num1, Lisp_Object num2, enum Arith_Comparison comparison) +arithcompare (Lisp_Object num1, Lisp_Object num2, + enum Arith_Comparison comparison) { - double f1 = 0, f2 = 0; - bool floatp = 0; + double f1, f2; + EMACS_INT i1, i2; + bool fneq; + bool test; CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num1); CHECK_NUMBER_OR_FLOAT_COERCE_MARKER (num2); - if (FLOATP (num1) || FLOATP (num2)) + /* If either arg is floating point, set F1 and F2 to the 'double' + approximations of the two arguments. Regardless, set I1 and I2 + to integers that break ties if the floating point comparison is + either not done or reports equality. */ + + if (FLOATP (num1)) + { + f1 = XFLOAT_DATA (num1); + if (FLOATP (num2)) + { + i1 = i2 = 0; + f2 = XFLOAT_DATA (num2); + } + else + i1 = f2 = i2 = XINT (num2); + fneq = f1 != f2; + } + else { - floatp = 1; - f1 = (FLOATP (num1)) ? XFLOAT_DATA (num1) : XINT (num1); - f2 = (FLOATP (num2)) ? XFLOAT_DATA (num2) : XINT (num2); + i1 = XINT (num1); + if (FLOATP (num2)) + { + i2 = f1 = i1; + f2 = XFLOAT_DATA (num2); + fneq = f1 != f2; + } + else + { + i2 = XINT (num2); + fneq = false; + } } switch (comparison) { case ARITH_EQUAL: - if (floatp ? f1 == f2 : XINT (num1) == XINT (num2)) - return Qt; - return Qnil; + test = !fneq && i1 == i2; + break; case ARITH_NOTEQUAL: - if (floatp ? f1 != f2 : XINT (num1) != XINT (num2)) - return Qt; - return Qnil; + test = fneq || i1 != i2; + break; case ARITH_LESS: - if (floatp ? f1 < f2 : XINT (num1) < XINT (num2)) - return Qt; - return Qnil; + test = fneq ? f1 < f2 : i1 < i2; + break; case ARITH_LESS_OR_EQUAL: - if (floatp ? f1 <= f2 : XINT (num1) <= XINT (num2)) - return Qt; - return Qnil; + test = fneq ? f1 <= f2 : i1 <= i2; + break; case ARITH_GRTR: - if (floatp ? f1 > f2 : XINT (num1) > XINT (num2)) - return Qt; - return Qnil; + test = fneq ? f1 > f2 : i1 > i2; + break; case ARITH_GRTR_OR_EQUAL: - if (floatp ? f1 >= f2 : XINT (num1) >= XINT (num2)) - return Qt; - return Qnil; + test = fneq ? f1 >= f2 : i1 >= i2; + break; default: - emacs_abort (); + eassume (false); } + + return test ? Qt : Qnil; } static Lisp_Object arithcompare_driver (ptrdiff_t nargs, Lisp_Object *args, enum Arith_Comparison comparison) { - ptrdiff_t argnum; - for (argnum = 1; argnum < nargs; ++argnum) - { - if (EQ (Qnil, arithcompare (args[argnum - 1], args[argnum], comparison))) - return Qnil; - } + for (ptrdiff_t i = 1; i < nargs; i++) + if (NILP (arithcompare (args[i - 1], args[i], comparison))) + return Qnil; return Qt; } diff --git a/test/src/data-tests.el b/test/src/data-tests.el index 2e4a6aa2e8..d38760cdde 100644 --- a/test/src/data-tests.el +++ b/test/src/data-tests.el @@ -29,6 +29,8 @@ (should (= 1)) (should (= 2 2)) (should (= 9 9 9 9 9 9 9 9 9)) + (should (= most-negative-fixnum (float most-negative-fixnum))) + (should-not (= most-positive-fixnum (+ 1.0 most-positive-fixnum))) (should-not (apply #'= '(3 8 3))) (should-error (= 9 9 'foo)) ;; Short circuits before getting to bad arg @@ -39,6 +41,7 @@ (should (< 1)) (should (< 2 3)) (should (< -6 -1 0 2 3 4 8 9 999)) + (should (< 0.5 most-positive-fixnum (+ 1.0 most-positive-fixnum))) (should-not (apply #'< '(3 8 3))) (should-error (< 9 10 'foo)) ;; Short circuits before getting to bad arg @@ -49,6 +52,7 @@ (should (> 1)) (should (> 3 2)) (should (> 6 1 0 -2 -3 -4 -8 -9 -999)) + (should (> (+ 1.0 most-positive-fixnum) most-positive-fixnum 0.5)) (should-not (apply #'> '(3 8 3))) (should-error (> 9 8 'foo)) ;; Short circuits before getting to bad arg @@ -59,6 +63,7 @@ (should (<= 1)) (should (<= 2 3)) (should (<= -6 -1 -1 0 0 0 2 3 4 8 999)) + (should (<= 0.5 most-positive-fixnum (+ 1.0 most-positive-fixnum))) (should-not (apply #'<= '(3 8 3 3))) (should-error (<= 9 10 'foo)) ;; Short circuits before getting to bad arg @@ -69,6 +74,7 @@ (should (>= 1)) (should (>= 3 2)) (should (>= 666 1 0 0 -2 -3 -3 -3 -4 -8 -8 -9 -999)) + (should (>= (+ 1.0 most-positive-fixnum) most-positive-fixnum)) (should-not (apply #'>= '(3 8 3))) (should-error (>= 9 8 'foo)) ;; Short circuits before getting to bad arg commit d546be31a9320d94769cb322f008f49d08d852a8 Author: Eli Zaretskii Date: Thu Mar 2 17:46:25 2017 +0200 Fix display of mouse-highlight produced by overlapping overlays * src/xfaces.c (face_at_buffer_position): If called to find the mouse-face, only consider the highest-priority source for that face, and ignore the rest. Previously, all the mouse-face definitions at POS were merged in that case. * src/xdisp.c (note_mouse_highlight): Record the overlay that specifies mouse-face _after_ clearing the info about the previous overlay, so as not to clear the information about the just-recorded overlay. (Bug#25906) diff --git a/src/xdisp.c b/src/xdisp.c index 1f8878408b..851a32b4f8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -30439,12 +30439,14 @@ note_mouse_highlight (struct frame *f, int x, int y) no need to do that again. */ if (!NILP (overlay) && EQ (overlay, hlinfo->mouse_face_overlay)) goto check_help_echo; - hlinfo->mouse_face_overlay = overlay; /* Clear the display of the old active region, if any. */ if (clear_mouse_face (hlinfo)) cursor = No_Cursor; + /* Record the overlay, if any, to be highlighted. */ + hlinfo->mouse_face_overlay = overlay; + /* If no overlay applies, get a text property. */ if (NILP (overlay)) mouse_face = Fget_text_property (position, Qmouse_face, object); diff --git a/src/xfaces.c b/src/xfaces.c index b5dbb53ca2..7fcaef4e41 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -5869,7 +5869,10 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) LIMIT is a position not to scan beyond. That is to limit the time this function can take. - If MOUSE, use the character's mouse-face, not its face. + If MOUSE, use the character's mouse-face, not its face, and only + consider the highest-priority source of mouse-face at POS, + i.e. don't merge different mouse-face values if more than one + source specifies it. BASE_FACE_ID, if non-negative, specifies a base face id to use instead of DEFAULT_FACE_ID. @@ -5949,19 +5952,47 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, /* Now merge the overlay data. */ noverlays = sort_overlays (overlay_vec, noverlays, w); - for (i = 0; i < noverlays; i++) + /* For mouse-face, we need only the single highest-priority face + from the overlays, if any. */ + if (mouse) { - Lisp_Object oend; - ptrdiff_t oendpos; + for (prop = Qnil, i = noverlays - 1; i >= 0 && NILP (prop); --i) + { + Lisp_Object oend; + ptrdiff_t oendpos; - prop = Foverlay_get (overlay_vec[i], propname); - if (!NILP (prop)) - merge_face_ref (f, prop, attrs, true, 0); + prop = Foverlay_get (overlay_vec[i], propname); + if (!NILP (prop)) + { + /* Overlays always take priority over text properties, + so discard the mouse-face text property, if any, and + use the overlay property instead. */ + memcpy (attrs, default_face->lface, sizeof attrs); + merge_face_ref (f, prop, attrs, true, 0); + } - oend = OVERLAY_END (overlay_vec[i]); - oendpos = OVERLAY_POSITION (oend); - if (oendpos < endpos) - endpos = oendpos; + oend = OVERLAY_END (overlay_vec[i]); + oendpos = OVERLAY_POSITION (oend); + if (oendpos < endpos) + endpos = oendpos; + } + } + else + { + for (i = 0; i < noverlays; i++) + { + Lisp_Object oend; + ptrdiff_t oendpos; + + prop = Foverlay_get (overlay_vec[i], propname); + if (!NILP (prop)) + merge_face_ref (f, prop, attrs, true, 0); + + oend = OVERLAY_END (overlay_vec[i]); + oendpos = OVERLAY_POSITION (oend); + if (oendpos < endpos) + endpos = oendpos; + } } *endptr = endpos; commit 511a3c3ba27352fde26ae2371a9d4a64c6418122 Author: Eli Zaretskii Date: Thu Mar 2 17:37:18 2017 +0200 Fix display of strike-through text in variable-height lines * src/nsterm.m (ns_draw_text_decoration): * src/xterm.c (x_draw_glyph_string): * src/w32term.c (x_draw_glyph_string): Fix calculation of the strike-through y-coordinate for a glyph row which is taller than the strike-through text. (Bug#25907) diff --git a/src/nsterm.m b/src/nsterm.m index 28764c8a4f..eaefea7985 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3107,10 +3107,19 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. if (face->strike_through_p) { NSRect r; + /* Y-coordinate and height of the glyph string's first glyph. + We cannot use s->y and s->height because those could be + larger if there are taller display elements (e.g., characters + displayed with a larger font) in the same glyph row. */ + int glyph_y = s->ybase - s->first_glyph->ascent; + int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; + /* Strike-through width and offset from the glyph string's + top edge. */ + unsigned long h = 1; unsigned long dy; - dy = lrint ((s->height - 1) / 2); - r = NSMakeRect (x, s->y + dy, width, 1); + dy = lrint ((glyph_height - h) / 2); + r = NSMakeRect (x, glyph_y + dy, width, 1); if (face->strike_through_color_defaulted_p) [defaultCol set]; diff --git a/src/w32term.c b/src/w32term.c index 3d41c30dfe..28bf6fb3d9 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2500,18 +2500,27 @@ x_draw_glyph_string (struct glyph_string *s) if (s->face->strike_through_p && !FONT_TEXTMETRIC (s->font).tmStruckOut) { + /* Y-coordinate and height of the glyph string's first + glyph. We cannot use s->y and s->height because those + could be larger if there are taller display elements + (e.g., characters displayed with a larger font) in the + same glyph row. */ + int glyph_y = s->ybase - s->first_glyph->ascent; + int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; + /* Strike-through width and offset from the glyph string's + top edge. */ unsigned long h = 1; - unsigned long dy = (s->height - h) / 2; + unsigned long dy = (glyph_height - h) / 2; if (s->face->strike_through_color_defaulted_p) { - w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, s->y + dy, - s->width, h); + w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, + glyph_y + dy, s->width, h); } else { w32_fill_area (s->f, s->hdc, s->face->strike_through_color, s->x, - s->y + dy, s->width, h); + glyph_y + dy, s->width, h); } } diff --git a/src/xterm.c b/src/xterm.c index c3af28e571..24d1702cec 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3708,18 +3708,27 @@ x_draw_glyph_string (struct glyph_string *s) /* Draw strike-through. */ if (s->face->strike_through_p) { - unsigned long h = 1; - unsigned long dy = (s->height - h) / 2; + /* Y-coordinate and height of the glyph string's first + glyph. We cannot use s->y and s->height because those + could be larger if there are taller display elements + (e.g., characters displayed with a larger font) in the + same glyph row. */ + int glyph_y = s->ybase - s->first_glyph->ascent; + int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; + /* Strike-through width and offset from the glyph string's + top edge. */ + unsigned long h = 1; + unsigned long dy = (glyph_height - h) / 2; if (s->face->strike_through_color_defaulted_p) - x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, glyph_y + dy, s->width, h); else { XGCValues xgcv; XGetGCValues (s->display, s->gc, GCForeground, &xgcv); XSetForeground (s->display, s->gc, s->face->strike_through_color); - x_fill_rectangle (s->f, s->gc, s->x, s->y + dy, + x_fill_rectangle (s->f, s->gc, s->x, glyph_y + dy, s->width, h); XSetForeground (s->display, s->gc, xgcv.foreground); } commit ae8835619655a0e28c4d84bbd8c46cc29aac6ad3 Author: Martin Rudalics Date: Thu Mar 2 11:31:20 2017 +0100 Don't call x_net_wm_state for scroll bar windows (Bug#24963, Bug#25887) * src/xterm.c (handle_one_xevent): For ConfigureNotify events don't call x_net_wm_state when the window is a scroll bar window. (Bug#24963, Bug#25887) diff --git a/src/xterm.c b/src/xterm.c index 52bc8f9eca..c3af28e571 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -8551,8 +8551,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif if (f) { - - x_net_wm_state (f, configureEvent.xconfigure.window); + /* Don't call x_net_wm_state for the scroll bar window. + (Bug#24963, Bug#25887) */ + if (configureEvent.xconfigure.window == FRAME_X_WINDOW (f)) + x_net_wm_state (f, configureEvent.xconfigure.window); #ifdef USE_X_TOOLKIT /* Tip frames are pure X window, set size for them. */