;;; general case of EVAL (except in that it can't handle toplevel
;;; EVAL-WHEN magic properly): Delegate to #'COMPILE.
-(defun %eval (expr)
- (funcall (compile (gensym "EVAL-TMPFUN-")
- `(lambda ()
-
- ;; 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 properties are relatively unimportant.
- (declare (optimize (speed 1) (debug 1) (space 1)))
-
- ,expr))))
+(defun %eval (expr lexenv)
+ (funcall (sb!c:compile-in-lexenv
+ (gensym "EVAL-TMPFUN-")
+ `(lambda ()
+ ,expr)
+ lexenv)))
;;; Handle PROGN and implicit PROGN.
-(defun eval-progn-body (progn-body)
+(defun eval-progn-body (progn-body lexenv)
(unless (list-with-length-p progn-body)
(let ((*print-circle* t))
(error 'simple-program-error
(rest-i (rest i) (rest i)))
(nil)
(if rest-i ; if not last element of list
- (eval (first i))
- (return (eval (first i))))))
+ (eval-in-lexenv (first i) lexenv)
+ (return (eval-in-lexenv (first i) lexenv)))))
-;;; 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
"Evaluate the argument in a null lexical environment, returning the
result or results."
+ (eval-in-lexenv original-exp (make-null-lexenv)))
+
+;;; Pick off a few easy cases, and the various top level EVAL-WHEN
+;;; magical cases, and call %EVAL for the rest.
+(defun eval-in-lexenv (original-exp lexenv)
(declare (optimize (safety 1)))
- (let ((exp (macroexpand original-exp)))
+ ;; (aver (lexenv-simple-p lexenv))
+ (let ((exp (macroexpand original-exp lexenv)))
(typecase exp
(symbol
(ecase (info :variable :kind exp)
;; compatibility, it can be implemented with
;; DEFINE-SYMBOL-MACRO, keeping the code walkers happy.
(:alien
- (%eval original-exp))))
+ (%eval original-exp lexenv))))
(list
(let ((name (first exp))
(n-args (1- (length exp))))
(case name
- (function
+ ((function)
(unless (= n-args 1)
(error "wrong number of args to FUNCTION:~% ~S" exp))
(let ((name (second exp)))
- (if (or (atom name)
- (and (consp name)
- (eq (car name) 'setf)))
+ (if (and (legal-fun-name-p name)
+ (not (consp (let ((sb!c:*lexenv* lexenv))
+ (sb!c:lexenv-find name funs)))))
(fdefinition name)
- (%eval original-exp))))
- (quote
+ (%eval original-exp lexenv))))
+ ((quote)
(unless (= n-args 1)
(error "wrong number of args to QUOTE:~% ~S" exp))
(second exp))
(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))))))))
+ (t (return (%eval original-exp lexenv))))))))
((progn)
- (eval-progn-body (rest exp)))
+ (eval-progn-body (rest exp) lexenv))
((eval-when)
- ;; FIXME: DESTRUCTURING-BIND returns
- ;; DEFMACRO-LL-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
+ ;; 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
;; otherwise, the EVAL-WHEN form returns NIL.
(declare (ignore ct lt))
(when e
- (eval-progn-body body)))))
+ (eval-progn-body body lexenv)))))
+ ((locally)
+ (multiple-value-bind (body decls) (parse-body (rest exp) nil)
+ (let ((lexenv
+ ;; KLUDGE: Uh, yeah. I'm not anticipating
+ ;; winning any prizes for this code, which was
+ ;; written on a "let's get it to work" basis.
+ ;; These seem to be the variables that need
+ ;; bindings for PROCESS-DECLS to work
+ ;; (*FREE-FUNS* and *FREE-VARS* so that
+ ;; references to free functions and variables in
+ ;; the declarations can be noted;
+ ;; *UNDEFINED-WARNINGS* so that warnings about
+ ;; undefined things can be accumulated [and then
+ ;; thrown away, as it happens]). -- CSR, 2002-10-24
+ (let ((sb!c:*lexenv* lexenv)
+ (sb!c::*free-funs* (make-hash-table :test 'equal))
+ (sb!c::*free-vars* (make-hash-table :test 'eq))
+ (sb!c::*undefined-warnings* nil))
+ (sb!c::process-decls decls
+ nil nil
+ (sb!c::make-continuation)
+ lexenv))))
+ (eval-progn-body body lexenv))))
+ ((macrolet)
+ (destructuring-bind (definitions &rest body)
+ (rest exp)
+ ;; FIXME: shared code with FUNCALL-IN-FOOMACROLET-LEXENV
+ (declare (type list definitions))
+ (unless (= (length definitions)
+ (length (remove-duplicates definitions :key #'first)))
+ (style-warn "duplicate definitions in ~S" definitions))
+ (let ((lexenv
+ (sb!c::make-lexenv
+ :default lexenv
+ :funs (mapcar
+ (sb!c::macrolet-definitionize-fun
+ :eval
+ ;; I'm not sure that this is the correct
+ ;; LEXENV to be compiling local macros
+ ;; in...
+ lexenv)
+ definitions))))
+ (eval-in-lexenv `(locally ,@body) lexenv))))
+ ((symbol-macrolet)
+ (destructuring-bind (definitions &rest body)
+ (rest exp)
+ ;; FIXME: shared code with FUNCALL-IN-FOOMACROLET-LEXENV
+ (declare (type list definitions))
+ (unless (= (length definitions)
+ (length (remove-duplicates definitions :key #'first)))
+ (style-warn "duplicate definitions in ~S" definitions))
+ (let ((lexenv
+ (sb!c::make-lexenv
+ :default lexenv
+ :vars (mapcar
+ (sb!c::symbol-macrolet-definitionize-fun
+ :eval)
+ definitions))))
+ (eval-in-lexenv `(locally ,@body) lexenv))))
(t
(if (and (symbolp name)
(eq (info :function :kind name) :function))
(collect ((args))
- (dolist (arg (rest exp))
- (args (eval arg)))
- (apply (symbol-function name) (args)))
- (%eval original-exp))))))
+ (dolist (arg (rest exp))
+ (args (eval-in-lexenv arg lexenv)))
+ (apply (symbol-function name) (args)))
+ (%eval exp lexenv))))))
(t
exp))))
-
-(defun function-lambda-expression (fun)
- "Return (VALUES DEFINING-LAMBDA-EXPRESSION CLOSURE-P NAME), where
- DEFINING-LAMBDA-EXPRESSION is NIL if unknown, or a suitable argument
- to COMPILE otherwise, CLOSURE-P is non-NIL if the function's definition
- might have been enclosed in some non-null lexical environment, and
- NAME is some name (for debugging only) or NIL if there is no name."
- (declare (type function fun))
- (let* ((fun (%simple-fun-self fun))
- (name (%simple-fun-name fun))
- (code (sb!di::fun-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