diff options
| author | Leo Liu | 2014-09-26 08:15:21 +0800 |
|---|---|---|
| committer | Leo Liu | 2014-09-26 08:15:21 +0800 |
| commit | 89b354a55e30978444ada5d388e18f5e06bde583 (patch) | |
| tree | 0f272431b9522c96aeff74b5d262869d26c4bc3f | |
| parent | b8e352d077f14c52d7e6baa1800def8d3ec61f06 (diff) | |
| download | emacs-89b354a55e30978444ada5d388e18f5e06bde583.tar.gz emacs-89b354a55e30978444ada5d388e18f5e06bde583.zip | |
Add cl-parse-integer based on parse-integer
* doc/misc/cl.texi (Predicates on Numbers): Document cl-digit-char-p.
(Numerical Functions): Document cl-parse-integer.
* lisp/calendar/parse-time.el (parse-time-digits): Remove.
(digit-char-p, parse-integer) Moved to cl-lib.el.
(parse-time-tokenize, parse-time-rules, parse-time-string): Use
cl-parse-integer.
* lisp/emacs-lisp/cl-extra.el (cl-parse-integer): New function.
* lisp/emacs-lisp/cl-lib.el (cl-digit-char-table): New var.
(cl-digit-char-p): New function.
* test/automated/cl-lib.el (cl-digit-char-p, cl-parse-integer): New
tests.
Fixes: debbugs:18557
| -rw-r--r-- | doc/misc/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/misc/cl.texi | 15 | ||||
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/calendar/parse-time.el | 46 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-extra.el | 35 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-lib.el | 19 | ||||
| -rw-r--r-- | test/ChangeLog | 5 | ||||
| -rw-r--r-- | test/automated/cl-lib.el | 19 |
8 files changed, 118 insertions, 39 deletions
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog index 2963bde04e1..a7244f12aba 100644 --- a/doc/misc/ChangeLog +++ b/doc/misc/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2014-09-26 Leo Liu <sdl.web@gmail.com> | ||
| 2 | |||
| 3 | * cl.texi (Predicates on Numbers): Document cl-digit-char-p. | ||
| 4 | (Numerical Functions): Document cl-parse-integer. (Bug#18557) | ||
| 5 | |||
| 1 | 2014-09-24 Ulf Jasper <ulf.jasper@web.de> | 6 | 2014-09-24 Ulf Jasper <ulf.jasper@web.de> |
| 2 | 7 | ||
| 3 | * newsticker.texi: Reworked. Document new treeview group | 8 | * newsticker.texi: Reworked. Document new treeview group |
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index b2914adc062..04a0e5725e8 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi | |||
| @@ -2929,6 +2929,12 @@ This predicate tests whether @var{integer} is even. It is an | |||
| 2929 | error if the argument is not an integer. | 2929 | error if the argument is not an integer. |
| 2930 | @end defun | 2930 | @end defun |
| 2931 | 2931 | ||
| 2932 | @defun cl-digit-char-p char radix | ||
| 2933 | Test if @var{char} is a digit in the specified @var{radix} (default is | ||
| 2934 | 10). If true return the decimal value of digit @var{char} in | ||
| 2935 | @var{radix}. | ||
| 2936 | @end defun | ||
| 2937 | |||
| 2932 | @node Numerical Functions | 2938 | @node Numerical Functions |
| 2933 | @section Numerical Functions | 2939 | @section Numerical Functions |
| 2934 | 2940 | ||
| @@ -3011,6 +3017,15 @@ This function returns the same value as the second return value | |||
| 3011 | of @code{cl-truncate}. | 3017 | of @code{cl-truncate}. |
| 3012 | @end defun | 3018 | @end defun |
| 3013 | 3019 | ||
| 3020 | @defun cl-parse-integer string &key start end radix junk-allowed | ||
| 3021 | This function implements the Common Lisp @code{parse-integer} | ||
| 3022 | function. It parses an integer in the specified @var{radix} from the | ||
| 3023 | substring of @var{string} between @var{start} and @var{end}. Any | ||
| 3024 | leading and trailing whitespace chars are ignored. It signals an error | ||
| 3025 | if the substring between @var{start} and @var{end} cannot be parsed as | ||
| 3026 | an integer unless @var{junk-allowed} is non-nil. | ||
| 3027 | @end defun | ||
| 3028 | |||
| 3014 | @node Random Numbers | 3029 | @node Random Numbers |
| 3015 | @section Random Numbers | 3030 | @section Random Numbers |
| 3016 | 3031 | ||
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index eb52886a4a9..4c4941d982d 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | 2014-09-26 Leo Liu <sdl.web@gmail.com> | ||
| 2 | |||
| 3 | Add cl-parse-integer based on parse-integer (Bug#18557) | ||
| 4 | * calendar/parse-time.el (parse-time-digits): Remove. | ||
| 5 | (digit-char-p, parse-integer) Moved to cl-lib.el. | ||
| 6 | (parse-time-tokenize, parse-time-rules, parse-time-string): Use | ||
| 7 | cl-parse-integer. | ||
| 8 | |||
| 9 | * emacs-lisp/cl-extra.el (cl-parse-integer): New function. | ||
| 10 | |||
| 11 | * emacs-lisp/cl-lib.el (cl-digit-char-table): New var. | ||
| 12 | (cl-digit-char-p): New function. | ||
| 13 | |||
| 1 | 2014-09-25 Juri Linkov <juri@jurta.org> | 14 | 2014-09-25 Juri Linkov <juri@jurta.org> |
| 2 | 15 | ||
| 3 | * vc/add-log.el (change-log-next-buffer): Don't create an empty | 16 | * vc/add-log.el (change-log-next-buffer): Don't create an empty |
diff --git a/lisp/calendar/parse-time.el b/lisp/calendar/parse-time.el index 6c88210030b..142e69ecfe6 100644 --- a/lisp/calendar/parse-time.el +++ b/lisp/calendar/parse-time.el | |||
| @@ -34,21 +34,12 @@ | |||
| 34 | 34 | ||
| 35 | ;;; Code: | 35 | ;;; Code: |
| 36 | 36 | ||
| 37 | (eval-when-compile (require 'cl-lib)) | 37 | (require 'cl-lib) |
| 38 | |||
| 39 | (defvar parse-time-digits (make-vector 256 nil)) | ||
| 40 | 38 | ||
| 41 | ;; Byte-compiler warnings | 39 | ;; Byte-compiler warnings |
| 42 | (defvar parse-time-elt) | 40 | (defvar parse-time-elt) |
| 43 | (defvar parse-time-val) | 41 | (defvar parse-time-val) |
| 44 | 42 | ||
| 45 | (unless (aref parse-time-digits ?0) | ||
| 46 | (cl-loop for i from ?0 to ?9 | ||
| 47 | do (aset parse-time-digits i (- i ?0)))) | ||
| 48 | |||
| 49 | (defsubst digit-char-p (char) | ||
| 50 | (aref parse-time-digits char)) | ||
| 51 | |||
| 52 | (defsubst parse-time-string-chars (char) | 43 | (defsubst parse-time-string-chars (char) |
| 53 | (save-match-data | 44 | (save-match-data |
| 54 | (let (case-fold-search str) | 45 | (let (case-fold-search str) |
| @@ -59,30 +50,6 @@ | |||
| 59 | ((string-match "[[:lower:]]" str) ?a) | 50 | ((string-match "[[:lower:]]" str) ?a) |
| 60 | ((string-match "[[:digit:]]" str) ?0))))) | 51 | ((string-match "[[:digit:]]" str) ?0))))) |
| 61 | 52 | ||
| 62 | (put 'parse-error 'error-conditions '(parse-error error)) | ||
| 63 | (put 'parse-error 'error-message "Parsing error") | ||
| 64 | |||
| 65 | (defsubst parse-integer (string &optional start end) | ||
| 66 | "[CL] Parse and return the integer in STRING, or nil if none." | ||
| 67 | (let ((integer 0) | ||
| 68 | (digit 0) | ||
| 69 | (index (or start 0)) | ||
| 70 | (end (or end (length string)))) | ||
| 71 | (when (< index end) | ||
| 72 | (let ((sign (aref string index))) | ||
| 73 | (if (or (eq sign ?+) (eq sign ?-)) | ||
| 74 | (setq sign (parse-time-string-chars sign) | ||
| 75 | index (1+ index)) | ||
| 76 | (setq sign 1)) | ||
| 77 | (while (and (< index end) | ||
| 78 | (setq digit (digit-char-p (aref string index)))) | ||
| 79 | (setq integer (+ (* integer 10) digit) | ||
| 80 | index (1+ index))) | ||
| 81 | (if (/= index end) | ||
| 82 | (signal 'parse-error `("not an integer" | ||
| 83 | ,(substring string (or start 0) end))) | ||
| 84 | (* sign integer)))))) | ||
| 85 | |||
| 86 | (defun parse-time-tokenize (string) | 53 | (defun parse-time-tokenize (string) |
| 87 | "Tokenize STRING into substrings." | 54 | "Tokenize STRING into substrings." |
| 88 | (let ((start nil) | 55 | (let ((start nil) |
| @@ -100,7 +67,7 @@ | |||
| 100 | (setq c (parse-time-string-chars (aref string index)))) | 67 | (setq c (parse-time-string-chars (aref string index)))) |
| 101 | (setq all-digits (and all-digits (eq c ?0)))) | 68 | (setq all-digits (and all-digits (eq c ?0)))) |
| 102 | (if (<= index end) | 69 | (if (<= index end) |
| 103 | (push (if all-digits (parse-integer string start index) | 70 | (push (if all-digits (cl-parse-integer string :start start :end index) |
| 104 | (substring string start index)) | 71 | (substring string start index)) |
| 105 | list))) | 72 | list))) |
| 106 | (nreverse list))) | 73 | (nreverse list))) |
| @@ -147,8 +114,8 @@ | |||
| 147 | (= 5 (length parse-time-elt)) | 114 | (= 5 (length parse-time-elt)) |
| 148 | (or (= (aref parse-time-elt 0) ?+) | 115 | (or (= (aref parse-time-elt 0) ?+) |
| 149 | (= (aref parse-time-elt 0) ?-)))) | 116 | (= (aref parse-time-elt 0) ?-)))) |
| 150 | ,#'(lambda () (* 60 (+ (parse-integer parse-time-elt 3 5) | 117 | ,#'(lambda () (* 60 (+ (cl-parse-integer parse-time-elt :start 3 :end 5) |
| 151 | (* 60 (parse-integer parse-time-elt 1 3))) | 118 | (* 60 (cl-parse-integer parse-time-elt :start 1 :end 3))) |
| 152 | (if (= (aref parse-time-elt 0) ?-) -1 1)))) | 119 | (if (= (aref parse-time-elt 0) ?-) -1 1)))) |
| 153 | ((5 4 3) | 120 | ((5 4 3) |
| 154 | ,#'(lambda () (and (stringp parse-time-elt) | 121 | ,#'(lambda () (and (stringp parse-time-elt) |
| @@ -210,9 +177,10 @@ unknown are returned as nil." | |||
| 210 | (let ((new-val (if rule | 177 | (let ((new-val (if rule |
| 211 | (let ((this (pop rule))) | 178 | (let ((this (pop rule))) |
| 212 | (if (vectorp this) | 179 | (if (vectorp this) |
| 213 | (parse-integer | 180 | (cl-parse-integer |
| 214 | parse-time-elt | 181 | parse-time-elt |
| 215 | (aref this 0) (aref this 1)) | 182 | :start (aref this 0) |
| 183 | :end (aref this 1)) | ||
| 216 | (funcall this))) | 184 | (funcall this))) |
| 217 | parse-time-val))) | 185 | parse-time-val))) |
| 218 | (rplaca (nthcdr (pop slots) time) new-val)))))))) | 186 | (rplaca (nthcdr (pop slots) time) new-val)))))))) |
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index 3761d04c2c2..c8404e0bc2d 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el | |||
| @@ -383,6 +383,41 @@ With two arguments, return rounding and remainder of their quotient." | |||
| 383 | "Return 1 if X is positive, -1 if negative, 0 if zero." | 383 | "Return 1 if X is positive, -1 if negative, 0 if zero." |
| 384 | (cond ((> x 0) 1) ((< x 0) -1) (t 0))) | 384 | (cond ((> x 0) 1) ((< x 0) -1) (t 0))) |
| 385 | 385 | ||
| 386 | ;;;###autoload | ||
| 387 | (cl-defun cl-parse-integer (string &key start end radix junk-allowed) | ||
| 388 | "Parse integer from the substring of STRING from START to END. | ||
| 389 | STRING may be surrounded by whitespace chars (chars with syntax ` '). | ||
| 390 | Other non-digit chars are considered junk. | ||
| 391 | RADIX is an integer between 2 and 36, the default is 10. Signal | ||
| 392 | an error if the substring between START and END cannot be parsed | ||
| 393 | as an integer unless JUNK-ALLOWED is non-nil." | ||
| 394 | (cl-check-type string string) | ||
| 395 | (let* ((start (or start 0)) | ||
| 396 | (len (length string)) | ||
| 397 | (end (or end len)) | ||
| 398 | (radix (or radix 10))) | ||
| 399 | (or (<= start end len) | ||
| 400 | (error "Bad interval: [%d, %d)" start end)) | ||
| 401 | (cl-flet ((skip-whitespace () | ||
| 402 | (while (and (< start end) | ||
| 403 | (= 32 (char-syntax (aref string start)))) | ||
| 404 | (setq start (1+ start))))) | ||
| 405 | (skip-whitespace) | ||
| 406 | (let ((sign (cl-case (and (< start end) (aref string start)) | ||
| 407 | (?+ (cl-incf start) +1) | ||
| 408 | (?- (cl-incf start) -1) | ||
| 409 | (t +1))) | ||
| 410 | digit sum) | ||
| 411 | (while (and (< start end) | ||
| 412 | (setq digit (cl-digit-char-p (aref string start) radix))) | ||
| 413 | (setq sum (+ (* (or sum 0) radix) digit) | ||
| 414 | start (1+ start))) | ||
| 415 | (skip-whitespace) | ||
| 416 | (cond ((and junk-allowed (null sum)) sum) | ||
| 417 | (junk-allowed (* sign sum)) | ||
| 418 | ((/= start end) (error "Not an integer string: %s" string)) | ||
| 419 | (t (* sign sum))))))) | ||
| 420 | |||
| 386 | 421 | ||
| 387 | ;; Random numbers. | 422 | ;; Random numbers. |
| 388 | 423 | ||
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index c4b9673aa2a..09cc3eee985 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el | |||
| @@ -279,6 +279,25 @@ so that they are registered at compile-time as well as run-time." | |||
| 279 | "Return t if INTEGER is even." | 279 | "Return t if INTEGER is even." |
| 280 | (eq (logand integer 1) 0)) | 280 | (eq (logand integer 1) 0)) |
| 281 | 281 | ||
| 282 | (defconst cl-digit-char-table | ||
| 283 | (let* ((digits (make-vector 256 nil)) | ||
| 284 | (populate (lambda (start end base) | ||
| 285 | (mapc (lambda (i) | ||
| 286 | (aset digits i (+ base (- i start)))) | ||
| 287 | (number-sequence start end))))) | ||
| 288 | (funcall populate ?0 ?9 0) | ||
| 289 | (funcall populate ?A ?Z 10) | ||
| 290 | (funcall populate ?a ?z 10) | ||
| 291 | digits)) | ||
| 292 | |||
| 293 | (defun cl-digit-char-p (char &optional radix) | ||
| 294 | "Test if CHAR is a digit in the specified RADIX (default 10). | ||
| 295 | If true return the decimal value of digit CHAR in RADIX." | ||
| 296 | (or (<= 2 (or radix 10) 36) | ||
| 297 | (signal 'args-out-of-range (list 'radix radix '(2 36)))) | ||
| 298 | (let ((n (aref cl-digit-char-table char))) | ||
| 299 | (and n (< n (or radix 10)) n))) | ||
| 300 | |||
| 282 | (defvar cl--random-state | 301 | (defvar cl--random-state |
| 283 | (vector 'cl--random-state-tag -1 30 (cl--random-time))) | 302 | (vector 'cl--random-state-tag -1 30 (cl--random-time))) |
| 284 | 303 | ||
diff --git a/test/ChangeLog b/test/ChangeLog index 6d64da10a33..041ed7c1754 100644 --- a/test/ChangeLog +++ b/test/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2014-09-26 Leo Liu <sdl.web@gmail.com> | ||
| 2 | |||
| 3 | * automated/cl-lib.el (cl-digit-char-p, cl-parse-integer): New | ||
| 4 | tests. (Bug#18557) | ||
| 5 | |||
| 1 | 2014-09-24 Ulf Jasper <ulf.jasper@web.de> | 6 | 2014-09-24 Ulf Jasper <ulf.jasper@web.de> |
| 2 | 7 | ||
| 3 | * automated/newsticker-tests.el | 8 | * automated/newsticker-tests.el |
diff --git a/test/automated/cl-lib.el b/test/automated/cl-lib.el index 6bbd9a5e81d..e4c6e914ee2 100644 --- a/test/automated/cl-lib.el +++ b/test/automated/cl-lib.el | |||
| @@ -223,6 +223,25 @@ | |||
| 223 | (should (= (cl-the integer (cl-incf side-effect)) 1)) | 223 | (should (= (cl-the integer (cl-incf side-effect)) 1)) |
| 224 | (should (= side-effect 1)))) | 224 | (should (= side-effect 1)))) |
| 225 | 225 | ||
| 226 | (ert-deftest cl-digit-char-p () | ||
| 227 | (should (cl-digit-char-p ?3)) | ||
| 228 | (should (cl-digit-char-p ?a 11)) | ||
| 229 | (should-not (cl-digit-char-p ?a)) | ||
| 230 | (should (cl-digit-char-p ?w 36)) | ||
| 231 | (should-error (cl-digit-char-p ?a 37)) | ||
| 232 | (should-error (cl-digit-char-p ?a 1))) | ||
| 233 | |||
| 234 | (ert-deftest cl-parse-integer () | ||
| 235 | (should-error (cl-parse-integer "abc")) | ||
| 236 | (should (null (cl-parse-integer "abc" :junk-allowed t))) | ||
| 237 | (should (null (cl-parse-integer "" :junk-allowed t))) | ||
| 238 | (should (= 342391 (cl-parse-integer "0123456789" :radix 8 :junk-allowed t))) | ||
| 239 | (should-error (cl-parse-integer "0123456789" :radix 8)) | ||
| 240 | (should (= -239 (cl-parse-integer "-efz" :radix 16 :junk-allowed t))) | ||
| 241 | (should-error (cl-parse-integer "efz" :radix 16)) | ||
| 242 | (should (= 239 (cl-parse-integer "zzef" :radix 16 :start 2))) | ||
| 243 | (should (= -123 (cl-parse-integer " -123 ")))) | ||
| 244 | |||
| 226 | (ert-deftest cl-loop-destructuring-with () | 245 | (ert-deftest cl-loop-destructuring-with () |
| 227 | (should (equal (cl-loop with (a b c) = '(1 2 3) return (+ a b c)) 6))) | 246 | (should (equal (cl-loop with (a b c) = '(1 2 3) return (+ a b c)) 6))) |
| 228 | 247 | ||