aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Liu2014-09-26 08:15:21 +0800
committerLeo Liu2014-09-26 08:15:21 +0800
commit89b354a55e30978444ada5d388e18f5e06bde583 (patch)
tree0f272431b9522c96aeff74b5d262869d26c4bc3f
parentb8e352d077f14c52d7e6baa1800def8d3ec61f06 (diff)
downloademacs-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/ChangeLog5
-rw-r--r--doc/misc/cl.texi15
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/calendar/parse-time.el46
-rw-r--r--lisp/emacs-lisp/cl-extra.el35
-rw-r--r--lisp/emacs-lisp/cl-lib.el19
-rw-r--r--test/ChangeLog5
-rw-r--r--test/automated/cl-lib.el19
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 @@
12014-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
12014-09-24 Ulf Jasper <ulf.jasper@web.de> 62014-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
2929error if the argument is not an integer. 2929error if the argument is not an integer.
2930@end defun 2930@end defun
2931 2931
2932@defun cl-digit-char-p char radix
2933Test if @var{char} is a digit in the specified @var{radix} (default is
293410). 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
3011of @code{cl-truncate}. 3017of @code{cl-truncate}.
3012@end defun 3018@end defun
3013 3019
3020@defun cl-parse-integer string &key start end radix junk-allowed
3021This function implements the Common Lisp @code{parse-integer}
3022function. It parses an integer in the specified @var{radix} from the
3023substring of @var{string} between @var{start} and @var{end}. Any
3024leading and trailing whitespace chars are ignored. It signals an error
3025if the substring between @var{start} and @var{end} cannot be parsed as
3026an 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 @@
12014-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
12014-09-25 Juri Linkov <juri@jurta.org> 142014-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.
389STRING may be surrounded by whitespace chars (chars with syntax ` ').
390Other non-digit chars are considered junk.
391RADIX is an integer between 2 and 36, the default is 10. Signal
392an error if the substring between START and END cannot be parsed
393as 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).
295If 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 @@
12014-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
12014-09-24 Ulf Jasper <ulf.jasper@web.de> 62014-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