;;; 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))
;; 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 ARG-COUNT-ERROR
;; instead of PROGRAM-ERROR when there's something wrong
;; 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))))
\f