;; Copyright (C) 2012, 2013 David Vazquez
;; Copyright (C) 2012 Raimon Grau
-;; This program is free software: you can redistribute it and/or
+;; JSCL 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.
;;
-;; This program is distributed in the hope that it will be useful, but
+;; JSCL 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 this program. If not, see <http://www.gnu.org/licenses/>.
+;; along with JSCL. If not, see <http://www.gnu.org/licenses/>.
;;;; Reader
nil)
((char= ch #\.)
(%read-char stream)
- (prog1 (ls-read stream)
+ (prog1 (ls-read-1 stream)
(skip-whitespaces-and-comments stream)
(unless (char= (%read-char stream) #\))
(error "')' was expected."))))
(t
- (cons (ls-read stream) (%read-list stream))))))
+ (cons (ls-read-1 stream) (%read-list stream))))))
(defun read-string (stream)
(let ((string "")
(%read-char stream)
(ecase (%read-char stream)
(#\'
- (list 'function (ls-read stream)))
+ (list 'function (ls-read-1 stream)))
(#\( (list-to-vector (%read-list stream)))
(#\: (make-symbol (string-upcase (read-until stream #'terminalp))))
(#\\
(let ((feature (read-until stream #'terminalp)))
(cond
((string= feature "common-lisp")
- (ls-read stream) ;ignore
- (ls-read stream))
- ((string= feature "ecmalisp")
- (ls-read stream))
+ (ls-read-1 stream) ;ignore
+ (ls-read-1 stream))
+ ((string= feature "jscl")
+ (ls-read-1 stream))
(t
(error "Unknown reader form.")))))))
(intern name package)
(find-symbol name package))))
+(defun read-integer (string)
+ (let ((sign 1)
+ (number nil)
+ (size (length string)))
+ (dotimes (i size)
+ (let ((elt (char string i)))
+ (cond
+ ((digit-char-p elt)
+ (setq number (+ (* (or number 0) 10) (digit-char-p elt))))
+ ((zerop i)
+ (case elt
+ (#\+ nil)
+ (#\- (setq sign -1))
+ (otherwise (return-from read-integer))))
+ ((and (= i (1- size)) (char= elt #\.)) nil)
+ (t (return-from read-integer)))))
+ (and number (* sign number))))
+
+(defun read-float (string)
+ (block nil
+ (let ((sign 1)
+ (integer-part nil)
+ (fractional-part nil)
+ (number 0)
+ (divisor 1)
+ (exponent-sign 1)
+ (exponent 0)
+ (size (length string))
+ (index 0))
+ (when (zerop size) (return))
+ ;; Optional sign
+ (case (char string index)
+ (#\+ (incf index))
+ (#\- (setq sign -1)
+ (incf index)))
+ (unless (< index size) (return))
+ ;; Optional integer part
+ (awhen (digit-char-p (char string index))
+ (setq integer-part t)
+ (while (and (< index size)
+ (setq it (digit-char-p (char string index))))
+ (setq number (+ (* number 10) it))
+ (incf index)))
+ (unless (< index size) (return))
+ ;; Decimal point is mandatory if there's no integer part
+ (unless (or integer-part (char= #\. (char string index))) (return))
+ ;; Optional fractional part
+ (when (char= #\. (char string index))
+ (incf index)
+ (unless (< index size) (return))
+ (awhen (digit-char-p (char string index))
+ (setq fractional-part t)
+ (while (and (< index size)
+ (setq it (digit-char-p (char string index))))
+ (setq number (+ (* number 10) it))
+ (setq divisor (* divisor 10))
+ (incf index))))
+ ;; Either left or right part of the dot must be present
+ (unless (or integer-part fractional-part) (return))
+ ;; Exponent is mandatory if there is no fractional part
+ (when (and (= index size) (not fractional-part)) (return))
+ ;; Optional exponent part
+ (when (< index size)
+ ;; Exponent-marker
+ (unless (member (string-upcase (string (char string index)))
+ '("E" "S" "F" "D" "L"))
+ (return))
+ (incf index)
+ (unless (< index size) (return))
+ ;; Optional exponent sign
+ (case (char string index)
+ (#\+ (incf index))
+ (#\- (setq exponent-sign -1)
+ (incf index)))
+ (unless (< index size) (return))
+ ;; Exponent digits
+ (let ((value (digit-char-p (char string index))))
+ (unless value (return))
+ (while (and (< index size)
+ (setq value (digit-char-p (char string index))))
+ (setq exponent (+ (* exponent 10) value))
+ (incf index))))
+ (unless (= index size) (return))
+ ;; Everything went ok, we have a float
+ ;; XXX: Use FLOAT when implemented.
+ (/ (* sign (expt 10.0d0 (* exponent-sign exponent)) number) divisor))))
+
(defun !parse-integer (string junk-allow)
(block nil
(values (* sign value) index)
(values nil index)))))
-#+ecmalisp
+#+jscl
(defun parse-integer (string &key junk-allowed)
(multiple-value-bind (num index)
(!parse-integer string junk-allowed)
(error "junk detected."))))
(defvar *eof* (gensym))
-(defun ls-read (stream)
+(defun ls-read-1 (stream)
(skip-whitespaces-and-comments stream)
(let ((ch (%peek-char stream)))
(cond
(%read-list stream))
((char= ch #\')
(%read-char stream)
- (list 'quote (ls-read stream)))
+ (list 'quote (ls-read-1 stream)))
((char= ch #\`)
(%read-char stream)
- (list 'backquote (ls-read stream)))
+ (list 'backquote (ls-read-1 stream)))
((char= ch #\")
(%read-char stream)
(read-string stream))
((char= ch #\,)
(%read-char stream)
(if (eql (%peek-char stream) #\@)
- (progn (%read-char stream) (list 'unquote-splicing (ls-read stream)))
- (list 'unquote (ls-read stream))))
+ (progn (%read-char stream) (list 'unquote-splicing (ls-read-1 stream)))
+ (list 'unquote (ls-read-1 stream))))
((char= ch #\#)
(read-sharp stream))
(t
(let ((string (read-until stream #'terminalp)))
- (or (values (!parse-integer string nil))
- (read-symbol string)))))))
+ (or (read-integer string)
+ (read-float string)
+ (read-symbol string)))))))
+
+(defun ls-read (stream &optional (eof-error-p t) eof-value)
+ (let ((x (ls-read-1 stream)))
+ (if (eq x *eof*)
+ (if eof-error-p (error "EOF") eof-value)
+ x)))
+
+(defun ls-read-from-string (string &optional (eof-error-p t) eof-value)
+ (ls-read (make-string-stream string) eof-error-p eof-value))
-(defun ls-read-from-string (string)
- (ls-read (make-string-stream string)))
+#+jscl
+(defun read-from-string (string &optional (eof-errorp t) eof-value)
+ (ls-read-from-string string eof-errorp eof-value))