be more careful about ,@<constant-atom> and ,.<constant-atom>
authorNikodemus Siivola <nikodemus@random-state.net>
Wed, 24 Aug 2011 11:52:38 +0000 (14:52 +0300)
committerNikodemus Siivola <nikodemus@random-state.net>
Wed, 24 Aug 2011 13:18:37 +0000 (16:18 +0300)
  Specifically, signal a read-time error for those things which COMMA
  special-cases when constructing a splice.

  Fixes lp#770184.

NEWS
src/code/backq.lisp
tests/backq.impure.lisp

diff --git a/NEWS b/NEWS
index 8eca65d..c28c716 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ changes relative to sbcl-1.0.50:
     AREF, CHAR, etc. (lp#826971)
   * bug fix: compiler-errors causes by integer arguments with composed of multiple
     ranges to ARRAY-IN-BOUNDS-P. (lp#826970)
+  * bug fix: ,@ and ,. now signal a read-time error for certain non-list
+    expressions. (lp#770184)
 
 changes in sbcl-1.0.51 relative to sbcl-1.0.50:
   * minor incompatible change: SB-BSD-SOCKET socket streams no longer
index fb9bd04..6b615f3 100644 (file)
          (or (eq flag *bq-at-flag*)
              (eq flag *bq-dot-flag*)))))
 
+(defun backquote-splice (method dflag a d what stream)
+  (cond (dflag
+         (values method
+                 (cond ((eq dflag method)
+                        (cons a d))
+                       (t (list a (backquotify-1 dflag d))))))
+        ((expandable-backq-expression-p a)
+         (values method (list a)))
+        ((not (and (atom a) (backq-constant-p a)))
+         ;; COMMA special cases a few constant atoms, which
+         ;; are illegal in splices.
+         (comma a))
+        (t
+         (simple-reader-error stream "Invalid splice in backquote: ~A~A" what a))))
+
 ;;; This does the expansion from table 2.
 (defun backquotify (stream code)
   (cond ((atom code)
                  (simple-reader-error stream ",. after dot in ~S" code))
                (cond
                 ((eq aflag *bq-at-flag*)
-                 (if (null dflag)
-                     (if (expandable-backq-expression-p a)
-                         (values 'append (list a))
-                         (comma a))
-                     (values 'append
-                             (cond ((eq dflag 'append)
-                                    (cons a d ))
-                                   (t (list a (backquotify-1 dflag d)))))))
+                 (backquote-splice 'append dflag a d ",@" stream))
                 ((eq aflag *bq-dot-flag*)
-                 (if (null dflag)
-                     (if (expandable-backq-expression-p a)
-                         (values 'nconc (list a))
-                         (comma a))
-                     (values 'nconc
-                             (cond ((eq dflag 'nconc)
-                                    (cons a d))
-                                   (t (list a (backquotify-1 dflag d)))))))
+                 (backquote-splice 'nconc dflag a d ",." stream))
                 ((null dflag)
                  (if (member aflag '(quote t nil))
                      (values 'quote (list a))
 
 (/show0 "backq.lisp 139")
 
+(defun backq-constant-p (x)
+  (or (numberp x) (eq x t)))
+
 ;;; This handles the <hair> cases.
 (defun comma (code)
   (cond ((atom code)
          (cond ((null code)
                 (values nil nil))
-               ((or (numberp code) (eq code t))
+               ((backq-constant-p code)
                 (values t code))
-               (t (values *bq-comma-flag* code))))
+               (t
+                (values *bq-comma-flag* code))))
         ((and (eq (car code) 'quote)
               (not (expandable-backq-expression-p (cadr code))))
          (values (car code) (cadr code)))
index 6a64703..7632c78 100644 (file)
 
 (let ((s '``(,,@(list 1 2 3) 10)))
   (assert (equal (eval (eval s)) '(1 2 3 10))))
+
+(with-test (:name :comma-at-number-error)
+  (assert (eq :error
+              (handler-case
+                  (read-from-string "`(,@1)")
+                (reader-error ()
+                  :error)))))