Fix SETF semantics at compile-time
authorDavid Vázquez <davazp@gmail.com>
Fri, 30 Aug 2013 19:40:04 +0000 (21:40 +0200)
committerDavid Vázquez <davazp@gmail.com>
Fri, 30 Aug 2013 19:40:04 +0000 (21:40 +0200)
src/boot.lisp
src/compiler/compiler.lisp

index cb964e4..8764aa2 100644 (file)
 
 ;;; Generalized references (SETF)
 
-(defvar *setf-expanders* nil)
-
-(defun get-setf-expansion (place)
-  (if (symbolp place)
-      (let ((value (gensym)))
-        (values nil
-                nil
-                `(,value)
-                `(setq ,place ,value)
-                place))
-      (let ((place (!macroexpand-1 place)))
-        (let* ((access-fn (car place))
-               (expander (cdr (assoc access-fn *setf-expanders*))))
-          (when (null expander)
-            (error "Unknown generalized reference."))
-          (apply expander (cdr place))))))
+(eval-when(:compile-toplevel :load-toplevel :execute)
+  (defvar *setf-expanders* nil)
+  (defun !get-setf-expansion (place)
+    (if (symbolp place)
+        (let ((value (gensym)))
+          (values nil
+                  nil
+                  `(,value)
+                  `(setq ,place ,value)
+                  place))
+        (let ((place (!macroexpand-1 place)))
+          (let* ((access-fn (car place))
+                 (expander (cdr (assoc access-fn *setf-expanders*))))
+            (when (null expander)
+              (error "Unknown generalized reference."))
+            (apply expander (cdr place)))))))
+(fset 'get-setf-expansion (fdefinition '!get-setf-expansion))
 
 (defmacro define-setf-expander (access-fn lambda-list &body body)
   (unless (symbolp access-fn)
      (let ((place (!macroexpand-1 (first pairs)))
            (value (second pairs)))
        (multiple-value-bind (vars vals store-vars writer-form reader-form)
-           (get-setf-expansion place)
+           (!get-setf-expansion place)
          ;; TODO: Optimize the expansion a little bit to avoid let*
          ;; or multiple-value-bind when unnecesary.
          `(let* ,(mapcar #'list vars vals)
 
 (defmacro incf (place &optional (delta 1))
   (multiple-value-bind (dummies vals newval setter getter)
-      (get-setf-expansion place)
+      (!get-setf-expansion place)
     (let ((d (gensym)))
       `(let* (,@(mapcar #'list dummies vals)
               (,d ,delta)
 
 (defmacro decf (place &optional (delta 1))
   (multiple-value-bind (dummies vals newval setter getter)
-      (get-setf-expansion place)
+      (!get-setf-expansion place)
     (let ((d (gensym)))
       `(let* (,@(mapcar #'list dummies vals)
               (,d ,delta)
 
 (defmacro push (x place)
   (multiple-value-bind (dummies vals newval setter getter)
-      (get-setf-expansion place)
+      (!get-setf-expansion place)
     (let ((g (gensym)))
       `(let* ((,g ,x)
               ,@(mapcar #'list dummies vals)
 
 (defmacro pop (place)
   (multiple-value-bind (dummies vals newval setter getter)
-    (get-setf-expansion place)
+    (!get-setf-expansion place)
     (let ((head (gensym)))
       `(let* (,@(mapcar #'list dummies vals)
               (,head ,getter)
 (defmacro pushnew (x place &rest keys &key key test test-not)
   (declare (ignore key test test-not))
   (multiple-value-bind (dummies vals newval setter getter)
-      (get-setf-expansion place)
+      (!get-setf-expansion place)
     (let ((g (gensym))
           (v (gensym)))
       `(let* ((,g ,x)
index 5ecc937..cf6bb55 100644 (file)
        (eval (cons 'progn body)))
      ;; `load-toplevel' is given, then just compile the subforms as usual.
      (when (find :load-toplevel situations)
-       (convert `(progn ,@body))))
+       (convert-toplevel `(progn ,@body) *multiple-value-p*)))
     ((find :execute situations)
      (convert `(progn ,@body) *multiple-value-p*))
     (t
     (when expandedp
       (return-from convert-toplevel (convert-toplevel sexp multiple-value-p))))
   ;; Process as toplevel
-  (let ((*toplevel-compilations* nil))
+  (let ((*convert-level* -1)
+        (*toplevel-compilations* nil))
     (cond
       ;; Non-empty toplevel progn
       ((and (consp sexp)