quoted symbols, better handling of dotted pairs
authorAndrea Griffini <agriff@tin.it>
Tue, 30 Apr 2013 19:41:43 +0000 (21:41 +0200)
committerAndrea Griffini <agriff@tin.it>
Tue, 30 Apr 2013 19:41:43 +0000 (21:41 +0200)
src/read.lisp
tests/read.lisp

index c99604a..6d015f7 100644 (file)
       (setq ch (%peek-char stream)))
     string))
 
+(defun read-escaped-until (stream func)
+  (let ((string "")
+        (ch))
+    (setq ch (%peek-char stream))
+    (while (and ch (not (funcall func ch)))
+      (setq string (concat string (string ch)))
+      (%read-char stream)
+      (when (char= ch #\\)
+        ;; Note... escape char has been left in the string!
+        (setq string (concat string (string (%read-char stream)))))
+      (setq ch (%peek-char stream)))
+    string))
+
 (defun skip-whitespaces-and-comments (stream)
   (let (ch)
     (skip-whitespaces stream)
       ((char= ch #\))
        (%read-char stream)
        nil)
-      ((char= ch #\.)
-       (%read-char stream)
-       (prog1 (ls-read-1 stream)
-         (skip-whitespaces-and-comments stream)
-         (unless (char= (%read-char stream) #\))
-           (error "')' was expected."))))
       (t
-       (cons (ls-read-1 stream) (%read-list stream))))))
+       (let ((car (ls-read-1 stream)))
+         (skip-whitespaces-and-comments stream)
+         (cons car
+               (if (char= (%peek-char stream) #\.)
+                   (progn
+                     (%read-char stream)
+                     (if (terminalp (%peek-char stream))
+                         (ls-read-1 stream) ; Dotted pair notation
+                         (cons (let ((string (concat "." (read-escaped-until stream #'terminalp))))
+                                 (or (values (!parse-integer string nil))
+                                     (read-float string)
+                                     (read-symbol string)))
+                               (%read-list stream))))
+                   (%read-list stream))))))))
 
 (defun read-string (stream)
   (let ((string "")
          (t
           (error "Unknown reader form.")))))))
 
+(defun unescape (x)
+  (let ((result ""))
+    (dotimes (i (length x))
+      (unless (char= (char x i) #\\)
+        (setq result (concat result (string (char x i))))))
+    result))
+
 ;;; Parse a string of the form NAME, PACKAGE:NAME or
 ;;; PACKAGE::NAME and return the name. If the string is of the
 ;;; form 1) or 3), but the symbol does not exist, it will be created
     (setq index 0)
     (while (and (< index size)
                 (not (char= (char string index) #\:)))
+      (when (char= (char string index) #\\)
+        (incf index))
       (incf index))
     (cond
       ;; No package prefix
       ((= index size)
-       (setq name string)
+       (setq name (unescape string))
        (setq package *package*)
        (setq internalp t))
       (t
        ;; Package prefix
        (if (zerop index)
            (setq package "KEYWORD")
-           (setq package (string-upcase (subseq string 0 index))))
+           (setq package (string-upcase (unescape (subseq string 0 index)))))
        (incf index)
        (when (char= (char string index) #\:)
          (setq internalp t)
          (incf index))
-       (setq name (subseq string index))))
+       (setq name (unescape (subseq string index)))))
     ;; Canonalize symbol name and package
     (when (not (eq package "JS"))
       (setq name (string-upcase name)))
             (incf index))))
       (unless (= index size) (return))
       ;; Everything went ok, we have a float
-      (/ (* sign (expt 10 (* exponent-sign exponent)) number) divisor))))
+      (/ (* sign (expt 10.0 (* exponent-sign exponent)) number) divisor))))
 
 
 (defun !parse-integer (string junk-allow)
 (defun parse-integer (string &key junk-allowed)
   (multiple-value-bind (num index)
       (!parse-integer string junk-allowed)
-    (when num
-      (values num index)
-      (error "junk detected."))))
+    (if num
+        (values num index)
+        (error "junk detected."))))
 
 (defvar *eof* (gensym))
 (defun ls-read-1 (stream)
            (list 'unquote (ls-read-1 stream))))
       ((char= ch #\#)
        (read-sharp stream))
+      ((char= ch #\|)
+       (%read-char stream)
+       (let ((string (read-escaped-until stream (lambda (x) (char= x #\|)))))
+         (%read-char stream)
+         (read-symbol string)))
       (t
-       (let ((string (read-until stream #'terminalp)))
+       (let ((string (read-escaped-until stream #'terminalp)))
          (or (values (!parse-integer string nil))
              (read-float string)
              (read-symbol string)))))))
index b8e851c..516790e 100644 (file)
@@ -3,3 +3,9 @@
 ;; (test (equal (read-from-string " 1 3 5" t nil :start 2) (values 3 5)))
 (expected-failure
  (equal (read-from-string "(a b c)") (values '(A B C) 7)))
+
+(test (equal (read-from-string "|.|") '\.))
+(test (equal (read-from-string "(1 .25)") '(1 0.25)))
+(test (equal (read-from-string ".25") 0.25))
+(test (equal (read-from-string "(1 |.| 25)") '(1 |.| 25)))
+(test (equal (read-from-string "(1 . 25)") '(1 . 25)))