3 ;; Copyright (C) 2012, 2013 David Vazquez
4 ;; Copyright (C) 2012 Raimon Grau
6 ;; JSCL is free software: you can redistribute it and/or
7 ;; modify it under the terms of the GNU General Public License as
8 ;; published by the Free Software Foundation, either version 3 of the
9 ;; License, or (at your option) any later version.
11 ;; JSCL is distributed in the hope that it will be useful, but
12 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;; General Public License for more details.
16 ;; You should have received a copy of the GNU General Public License
17 ;; along with JSCL. If not, see <http://www.gnu.org/licenses/>.
22 ;;; The Lisp reader, parse strings and return Lisp objects. The main
23 ;;; entry points are `ls-read' and `ls-read-from-string'.
25 (defun make-string-stream (string)
28 (defun %peek-char (stream)
29 (and (< (cdr stream) (length (car stream)))
30 (char (car stream) (cdr stream))))
32 (defun %read-char (stream)
33 (and (< (cdr stream) (length (car stream)))
34 (prog1 (char (car stream) (cdr stream))
35 (rplacd stream (1+ (cdr stream))))))
37 (defun whitespacep (ch)
38 (or (char= ch #\space) (char= ch #\newline) (char= ch #\tab)))
40 (defun skip-whitespaces (stream)
42 (setq ch (%peek-char stream))
43 (while (and ch (whitespacep ch))
45 (setq ch (%peek-char stream)))))
48 (or (null ch) (whitespacep ch) (char= #\) ch) (char= #\( ch)))
50 (defun read-until (stream func)
53 (setq ch (%peek-char stream))
54 (while (and ch (not (funcall func ch)))
55 (setq string (concat string (string ch)))
57 (setq ch (%peek-char stream)))
60 (defun read-escaped-until (stream func)
63 (setq ch (%peek-char stream))
64 (while (and ch (not (funcall func ch)))
65 (setq string (concat string (string ch)))
68 ;; Note... escape char has been left in the string!
69 (setq string (concat string (string (%read-char stream)))))
70 (setq ch (%peek-char stream)))
73 (defun skip-whitespaces-and-comments (stream)
75 (skip-whitespaces stream)
76 (setq ch (%peek-char stream))
77 (while (and ch (char= ch #\;))
78 (read-until stream (lambda (x) (char= x #\newline)))
79 (skip-whitespaces stream)
80 (setq ch (%peek-char stream)))))
82 (defun %read-list (stream)
83 (skip-whitespaces-and-comments stream)
84 (let ((ch (%peek-char stream)))
87 (error "Unspected EOF"))
92 (let ((car (ls-read-1 stream)))
93 (skip-whitespaces-and-comments stream)
95 (if (char= (%peek-char stream) #\.)
98 (if (terminalp (%peek-char stream))
99 (ls-read-1 stream) ; Dotted pair notation
100 (cons (let ((string (concat "." (read-escaped-until stream #'terminalp))))
101 (or (values (!parse-integer string nil))
103 (read-symbol string)))
104 (%read-list stream))))
105 (%read-list stream))))))))
107 (defun read-string (stream)
110 (setq ch (%read-char stream))
111 (while (not (eql ch #\"))
113 (error "Unexpected EOF"))
115 (setq ch (%read-char stream)))
116 (setq string (concat string (string ch)))
117 (setq ch (%read-char stream)))
120 (defun read-sharp (stream)
122 (ecase (%read-char stream)
124 (list 'function (ls-read-1 stream)))
125 (#\( (list-to-vector (%read-list stream)))
126 (#\: (make-symbol (string-upcase (read-until stream #'terminalp))))
129 (concat (string (%read-char stream))
130 (read-until stream #'terminalp))))
132 ((string= cname "space") (char-code #\space))
133 ((string= cname "tab") (char-code #\tab))
134 ((string= cname "newline") (char-code #\newline))
135 (t (char-code (char cname 0))))))
137 (let ((feature (read-until stream #'terminalp)))
139 ((string= feature "common-lisp")
140 (ls-read-1 stream) ;ignore
142 ((string= feature "jscl")
145 (error "Unknown reader form.")))))))
149 (dotimes (i (length x))
150 (unless (char= (char x i) #\\)
151 (setq result (concat result (string (char x i))))))
154 ;;; Parse a string of the form NAME, PACKAGE:NAME or
155 ;;; PACKAGE::NAME and return the name. If the string is of the
156 ;;; form 1) or 3), but the symbol does not exist, it will be created
157 ;;; and interned in that package.
158 (defun read-symbol (string)
159 (let ((size (length string))
160 package name internalp index)
162 (while (and (< index size)
163 (not (char= (char string index) #\:)))
164 (when (char= (char string index) #\\)
170 (setq name (unescape string))
171 (setq package *package*)
176 (setq package "KEYWORD")
177 (setq package (string-upcase (unescape (subseq string 0 index)))))
179 (when (char= (char string index) #\:)
182 (setq name (unescape (subseq string index)))))
183 ;; Canonalize symbol name and package
184 (when (not (eq package "JS"))
185 (setq name (string-upcase name)))
186 (setq package (find-package package))
187 ;; TODO: PACKAGE:SYMBOL should signal error if SYMBOL is not an
188 ;; external symbol from PACKAGE.
190 (eq package (find-package "KEYWORD"))
191 (eq package (find-package "JS")))
192 (intern name package)
193 (find-symbol name package))))
195 (defun read-integer (string)
198 (size (length string)))
200 (let ((elt (char string i)))
203 (setq number (+ (* (or number 0) 10) (digit-char-p elt))))
208 (otherwise (return-from read-integer))))
209 ((and (= i (1- size)) (char= elt #\.)) nil)
210 (t (return-from read-integer)))))
211 (and number (* sign number))))
213 (defun read-float (string)
217 (fractional-part nil)
222 (size (length string))
224 (when (zerop size) (return))
226 (case (char string index)
230 (unless (< index size) (return))
231 ;; Optional integer part
232 (awhen (digit-char-p (char string index))
233 (setq integer-part t)
234 (while (and (< index size)
235 (setq it (digit-char-p (char string index))))
236 (setq number (+ (* number 10) it))
238 (unless (< index size) (return))
239 ;; Decimal point is mandatory if there's no integer part
240 (unless (or integer-part (char= #\. (char string index))) (return))
241 ;; Optional fractional part
242 (when (char= #\. (char string index))
244 (unless (< index size) (return))
245 (awhen (digit-char-p (char string index))
246 (setq fractional-part t)
247 (while (and (< index size)
248 (setq it (digit-char-p (char string index))))
249 (setq number (+ (* number 10) it))
250 (setq divisor (* divisor 10))
252 ;; Either left or right part of the dot must be present
253 (unless (or integer-part fractional-part) (return))
254 ;; Exponent is mandatory if there is no fractional part
255 (when (and (= index size) (not fractional-part)) (return))
256 ;; Optional exponent part
259 (unless (member (string-upcase (string (char string index)))
260 '("E" "S" "F" "D" "L"))
263 (unless (< index size) (return))
264 ;; Optional exponent sign
265 (case (char string index)
267 (#\- (setq exponent-sign -1)
269 (unless (< index size) (return))
271 (let ((value (digit-char-p (char string index))))
272 (unless value (return))
273 (while (and (< index size)
274 (setq value (digit-char-p (char string index))))
275 (setq exponent (+ (* exponent 10) value))
277 (unless (= index size) (return))
278 ;; Everything went ok, we have a float
279 ;; XXX: Use FLOAT when implemented.
280 (/ (* sign (expt 10.0 (* exponent-sign exponent)) number) divisor))))
282 (defun !parse-integer (string junk-allow)
286 (size (length string))
288 ;; Leading whitespace
289 (while (and (< index size)
290 (whitespacep (char string index)))
292 (unless (< index size) (return (values nil 0)))
294 (case (char string 0)
299 (unless (and (< index size)
300 (setq value (digit-char-p (char string index))))
301 (return (values nil index)))
304 (while (< index size)
305 (let ((digit (digit-char-p (char string index))))
306 (unless digit (return))
307 (setq value (+ (* value 10) digit))
309 ;; Trailing whitespace
310 (do ((i index (1+ i)))
311 ((or (= i size) (not (whitespacep (char string i))))
312 (and (= i size) (setq index i))))
315 (values (* sign value) index)
316 (values nil index)))))
319 (defun parse-integer (string &key junk-allowed)
320 (multiple-value-bind (num index)
321 (!parse-integer string junk-allowed)
324 (error "junk detected."))))
326 (defvar *eof* (gensym))
327 (defun ls-read-1 (stream)
328 (skip-whitespaces-and-comments stream)
329 (let ((ch (%peek-char stream)))
331 ((or (null ch) (char= ch #\)))
338 (list 'quote (ls-read-1 stream)))
341 (list 'backquote (ls-read-1 stream)))
344 (read-string stream))
347 (if (eql (%peek-char stream) #\@)
348 (progn (%read-char stream) (list 'unquote-splicing (ls-read-1 stream)))
349 (list 'unquote (ls-read-1 stream))))
354 (let ((string (read-escaped-until stream (lambda (x) (char= x #\|)))))
356 (read-symbol string)))
358 (let ((string (read-escaped-until stream #'terminalp)))
359 (or (read-integer string)
361 (read-symbol string)))))))
363 (defun ls-read (stream &optional (eof-error-p t) eof-value)
364 (let ((x (ls-read-1 stream)))
366 (if eof-error-p (error "EOF") eof-value)
369 (defun ls-read-from-string (string &optional (eof-error-p t) eof-value)
370 (ls-read (make-string-stream string) eof-error-p eof-value))
373 (defun read-from-string (string &optional (eof-errorp t) eof-value)
374 (ls-read-from-string string eof-errorp eof-value))