0.7.1.18:
[sbcl.git] / src / code / eval.lisp
index 23af789..6e8b10f 100644 (file)
@@ -9,36 +9,53 @@
 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
 ;;;; files for more information.
 
 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
 ;;;; files for more information.
 
-(in-package "SB!BYTECODE")
-
-;;; This needs to be initialized in the cold load, since the top-level
-;;; catcher will always restore the initial value.
-(defvar *eval-stack-top* 0)
+(in-package "SB!IMPL")
 
 ;;; general case of EVAL (except in that it can't handle toplevel
 
 ;;; general case of EVAL (except in that it can't handle toplevel
-;;; EVAL-WHEN magic properly): Delegate to the byte compiler.
+;;; EVAL-WHEN magic properly): Delegate to #'COMPILE.
 (defun %eval (expr)
   (funcall (compile (gensym "EVAL-TMPFUN-")
                    `(lambda ()
 
 (defun %eval (expr)
   (funcall (compile (gensym "EVAL-TMPFUN-")
                    `(lambda ()
 
-                      ;; SPEED=0,DEBUG=1 => byte-compile
-                      (declare (optimize (speed 0) (debug 1))) 
+                      ;; The user can reasonably expect that the
+                      ;; interpreter will be safe.
+                      (declare (optimize (safety 3)))
+
+                      ;; It's also good if the interpreter doesn't
+                      ;; spend too long thinking about each input
+                      ;; form, since if the user'd wanted the
+                      ;; tradeoff to favor quality of compiled code
+                      ;; over compilation speed, he'd've explicitly
+                      ;; asked for compilation.
+                      (declare (optimize (compilation-speed 2)))
 
 
-                      ;; Other than that, basically we care about
-                      ;; compilation speed, compilation speed, and
-                      ;; compilation speed. (There are cases where
-                      ;; the user wants something else, but we don't
-                      ;; know enough to guess that; and if he is
-                      ;; unhappy about our guessed emphasis, he
-                      ;; should explicitly compile his code, with
-                      ;; explicit declarations to tell us what to
-                      ;; emphasize.)
-                      (declare (optimize (space 1) (safety 1)))
-                      (declare (optimize (compilation-speed 3)))
+                      ;; Other properties are relatively unimportant.
+                      (declare (optimize (speed 1) (debug 1) (space 1)))
 
                       ,expr))))
 
 
                       ,expr))))
 
-;;; Pick off a few easy cases, and the various top-level EVAL-WHEN
+;;; Handle PROGN and implicit PROGN.
+(defun eval-progn-body (progn-body)
+  (unless (list-with-length-p progn-body)
+    (let ((*print-circle* t))
+      (error 'simple-program-error
+            :format-control
+            "~@<not a proper list in PROGN or implicit PROGN: ~2I~_~S~:>"
+            :format-arguments (list progn-body))))
+  ;; Note:
+  ;;   * We can't just use (MAP NIL #'EVAL PROGN-BODY) here, because we
+  ;;     need to take care to return all the values of the final EVAL.
+  ;;   * It's left as an exercise to the reader to verify that this
+  ;;     gives the right result when PROGN-BODY is NIL, because
+  ;;     (FIRST NIL) = (REST NIL) = NIL.
+  (do* ((i progn-body rest-i)
+       (rest-i (rest i) (rest i)))
+      (nil)
+    (if rest-i ; if not last element of list
+       (eval (first i))
+       (return (eval (first i))))))
+
+;;; Pick off a few easy cases, and the various top level EVAL-WHEN
 ;;; magical cases, and call %EVAL for the rest. 
 (defun eval (original-exp)
   #!+sb-doc
 ;;; magical cases, and call %EVAL for the rest. 
 (defun eval (original-exp)
   #!+sb-doc
          (%eval original-exp))))
       (list
        (let ((name (first exp))
          (%eval original-exp))))
       (list
        (let ((name (first exp))
-            (args (1- (length exp))))
+            (n-args (1- (length exp))))
         (case name
           (function
         (case name
           (function
-           (unless (= args 1)
+           (unless (= n-args 1)
              (error "wrong number of args to FUNCTION:~% ~S" exp))
            (let ((name (second exp)))
              (if (or (atom name)
              (error "wrong number of args to FUNCTION:~% ~S" exp))
            (let ((name (second exp)))
              (if (or (atom name)
                  (fdefinition name)
                  (%eval original-exp))))
           (quote
                  (fdefinition name)
                  (%eval original-exp))))
           (quote
-           (unless (= args 1)
+           (unless (= n-args 1)
              (error "wrong number of args to QUOTE:~% ~S" exp))
            (second exp))
           (setq
              (error "wrong number of args to QUOTE:~% ~S" exp))
            (second exp))
           (setq
-           (unless (evenp args)
+           (unless (evenp n-args)
              (error "odd number of args to SETQ:~% ~S" exp))
              (error "odd number of args to SETQ:~% ~S" exp))
-           (unless (zerop args)
+           (unless (zerop n-args)
              (do ((name (cdr exp) (cddr name)))
                  ((null name)
                   (do ((args (cdr exp) (cddr args)))
              (do ((name (cdr exp) (cddr name)))
                  ((null name)
                   (do ((args (cdr exp) (cddr args)))
                     (set (first args) (eval (second args)))))
                (let ((symbol (first name)))
                  (case (info :variable :kind symbol)
                     (set (first args) (eval (second args)))))
                (let ((symbol (first name)))
                  (case (info :variable :kind symbol)
-                   ;; FIXME: I took out the *TOP-LEVEL-AUTO-DECLARE*
-                   ;; test here, and removed the *TOP-LEVEL-AUTO-DECLARE*
+                   ;; FIXME: I took out the *TOPLEVEL-AUTO-DECLARE*
+                   ;; test here, and removed the *TOPLEVEL-AUTO-DECLARE*
                    ;; variable; the code should now act as though that
                    ;; variable is NIL. This should be tested..
                    (:special)
                    (t (return (%eval original-exp))))))))
           ((progn)
                    ;; variable; the code should now act as though that
                    ;; variable is NIL. This should be tested..
                    (:special)
                    (t (return (%eval original-exp))))))))
           ((progn)
-           (when (> args 0)
-             (dolist (x (butlast (rest exp)) (eval (car (last exp))))
-               (eval x))))
+           (eval-progn-body (rest exp)))
           ((eval-when)
           ((eval-when)
-           (if (and (> args 0)
-                    (or (member 'eval (second exp))
-                        (member :execute (second exp))))
-               (when (> args 1)
-                 (dolist (x (butlast (cddr exp)) (eval (car (last exp))))
-                   (eval x)))
-               (%eval original-exp)))
+           ;; FIXME: DESTRUCTURING-BIND returns ARG-COUNT-ERROR
+           ;; instead of PROGRAM-ERROR when there's something wrong
+           ;; with the syntax here (e.g. missing SITUATIONS). This
+           ;; could be fixed by hand-crafting clauses to catch and
+           ;; report each possibility, but it would probably be
+           ;; cleaner to write a new macro
+           ;; DESTRUCTURING-BIND-PROGRAM-SYNTAX which does
+           ;; DESTRUCTURING-BIND and promotes any mismatch to
+           ;; PROGRAM-ERROR, then to use it here and in (probably
+           ;; dozens of) other places where the same problem arises.
+           (destructuring-bind (eval-when situations &rest body) exp
+             (declare (ignore eval-when))
+             (multiple-value-bind (ct lt e)
+                 (sb!c:parse-eval-when-situations situations)
+               ;; CLHS 3.8 - Special Operator EVAL-WHEN: The use of
+               ;; the situation :EXECUTE (or EVAL) controls whether
+               ;; evaluation occurs for other EVAL-WHEN forms; that
+               ;; is, those that are not top level forms, or those in
+               ;; code processed by EVAL or COMPILE. If the :EXECUTE
+               ;; situation is specified in such a form, then the
+               ;; body forms are processed as an implicit PROGN;
+               ;; otherwise, the EVAL-WHEN form returns NIL.
+               (declare (ignore ct lt))
+               (when e
+                 (eval-progn-body body)))))
           (t
            (if (and (symbolp name)
                     (eq (info :function :kind name) :function))
           (t
            (if (and (symbolp name)
                     (eq (info :function :kind name) :function))
                (%eval original-exp))))))
       (t
        exp))))
                (%eval original-exp))))))
       (t
        exp))))
-
-;;; Given a function, return three values:
-;;; 1] A lambda expression that could be used to define the function,
-;;;    or NIL if the definition isn't available.
-;;; 2] NIL if the function was definitely defined in a null lexical
-;;;    environment, and T otherwise.
-;;; 3] Some object that \"names\" the function. Although this is
-;;;    allowed to be any object, CMU CL always returns a valid
-;;;    function name or a string.
-;;;
-;;; If interpreted, use the interpreter interface. Otherwise, see
-;;; whether it was compiled with COMPILE. If that fails, check for an
-;;; inline expansion.
-(defun function-lambda-expression (fun)
-  (declare (type function fun))
-  (let* ((fun (%function-self fun))
-        (name (%function-name fun))
-        (code (sb!di::function-code-header fun))
-        (info (sb!kernel:%code-debug-info code)))
-    (if info
-       (let ((source (first (sb!c::compiled-debug-info-source info))))
-         (cond ((and (eq (sb!c::debug-source-from source) :lisp)
-                     (eq (sb!c::debug-source-info source) fun))
-                (values (second (svref (sb!c::debug-source-name source) 0))
-                        nil name))
-               ((stringp name)
-                (values nil t name))
-               (t
-                (let ((exp (info :function :inline-expansion name)))
-                  (if exp
-                      (values exp nil name)
-                      (values nil t name))))))
-       (values nil t name))))
 \f
 ;;; miscellaneous full function definitions of things which are
 ;;; ordinarily handled magically by the compiler
 \f
 ;;; miscellaneous full function definitions of things which are
 ;;; ordinarily handled magically by the compiler