(%record %symbol name +unbound+ +unbound+ '() '() false false-procedure
'() '() '() '() '() '() '() '() '()))
\f
+;;;; Special bindings stack.
+
+(define *specpdl* '())
+
+(define-integrable (%specbind vars inits thunk)
+ (let ((saved-specpdl *specpdl*))
+ (%wind-one! (cons (cons vars inits) *specpdl*))
+ (let ((value (thunk)))
+ (%unwind! saved-specpdl)
+ value)))
+
+(define-integrable (%wind! saved-state)
+ (cond ((eq? saved-state *specpdl*) unspecific)
+ ((null? saved-state)
+ (error "Cannot wind to saved-state!" saved-state))
+ (else
+ ;; Wind up to previous state.
+ (%wind! (cdr saved-state))
+ ;; Wind up this state.
+ (%wind-one! saved-state)
+ unspecific)))
+
+(define (%wind-one! saved-state)
+ (let loop ((vars (car (car saved-state)))
+ (vals (cdr (car saved-state))))
+ (if (pair? vars)
+ (let ((var (car vars))
+ (val (car vals)))
+ (set-car! vals (%symbol-value-no-error var))
+ (if (eq? val +unbound+)
+ (%set-symbol-unbound! var)
+ (%set-symbol-value! var val))
+ (loop (cdr vars) (cdr vals)))))
+ (set! *specpdl* saved-state))
+
+(define (%unwind! saved-state)
+ (cond ((eq? *specpdl* saved-state) unspecific)
+ ((null? *specpdl*)
+ (error "Unwound past saved state!" saved-state))
+ (else
+ ;; Unwind this state.
+ (let loop ((vars (car (car *specpdl*)))
+ (vals (cdr (car *specpdl*))))
+ (if (pair? vars)
+ (let ((var (car vars))
+ (val (car vals)))
+ (set-car! vals (%symbol-value-no-error var))
+ (if (eq? val +unbound+)
+ (%set-symbol-unbound! var)
+ (%set-symbol-value! var val))
+ (loop (cdr vars) (cdr vals)))))
+ (set! *specpdl* (cdr *specpdl*))
+ ;; Unwind previous states.
+ (%unwind! saved-state)
+ unspecific)))
+\f
;;;; Exported definitions
(declare (integrate-operator %symbol?))
;; Assume it's the empty list.
(error:%signal Qsetting-constant (list '()))))
+(declare (integrate-operator %symbol-value-no-error))
+(define (%symbol-value-no-error symbol)
+ (if (%%symbol? symbol)
+ (let ((%value (%symbol/value symbol)))
+ (cond ((eq? %value +not-global+)
+ (if ((%symbol/bound? symbol))
+ ((%symbol/get-value symbol))
+ +unbound+))
+ (else %value)))
+ ;; Assume it's the empty list.
+ '()))
+
(declare (integrate-operator %symbol-value))
(define (%symbol-value symbol)
(if (%%symbol? symbol)
(cons (%car elt) vars)
(cons (%eval (%car (%cdr elt))) inits)))))))
-(define (%specbind vars inits thunk)
- (let ((current-buffer (%current-buffer))
- (+unbound+ "unbound"))
- (let ((exchange!
- (lambda ()
- ;; When rewinding, (%current-buffer) may not be the same as
- ;; current-buffer, so set it before establishing bindings and
- ;; restore it afterwards.
- (let ((old-buffer (%current-buffer)))
- (%set-current-buffer! current-buffer)
- (let loop ((syms vars)
- (vals inits))
- (if (pair? syms)
- (let* ((symbol (car syms))
- (new-value (car vals))
- (old-value (if (%symbol-bound? symbol)
- (%symbol-value symbol)
- +unbound+)))
- (if (eq? new-value +unbound+)
- (%set-symbol-unbound! symbol)
- (%set-symbol-value! symbol new-value))
- (set-car! vals old-value)
- (loop (cdr syms) (cdr vals)))))
- (%set-current-buffer! old-buffer))
- unspecific)))
- (dynamic-wind
- exchange!
- thunk
- exchange!))))
-
(DEFUN (el:while "e test . body)
"(while TEST BODY...) if TEST yields non-NIL, execute the BODY forms and repeat."
(let loop ()
(%catch (%eval tag) (lambda () (%progn body))))
(define (%catch tag thunk)
- (call-with-current-continuation
- (lambda (exit)
- (bind-condition-handler
- (list condition-type:%throw)
- (lambda (condition)
- (if (eq? (access-condition condition 'TAG) tag)
- (exit (access-condition condition 'VALUE))))
- thunk))))
+ (let ((saved-specpdl *specpdl*))
+ (call-with-current-continuation
+ (lambda (exit)
+ (bind-condition-handler
+ (list condition-type:%throw)
+ (lambda (condition)
+ (if (eq? (access-condition condition 'TAG) tag)
+ (begin
+ (%unwind! saved-specpdl)
+ (exit (access-condition condition 'VALUE)))))
+ thunk)))))
(DEFUN (el:throw tag value)
"(throw TAG VALUE): throw to the catch for TAG and return VALUE from it.
(lambda () (%progn unwindforms))))
(define (%unwind-protect protected-thunk unwind-thunk)
- (dynamic-wind
- (lambda () unspecific)
- protected-thunk
- unwind-thunk))
+ (let (;;(inside-specpdl *specpdl*)
+ (outside-specpdl))
+ (dynamic-wind
+ (lambda ()
+ (set! outside-specpdl *specpdl*)
+ ;; Let whoever caught the cc worry about saving the dynamic state!
+ ;;(%wind! inside-specpdl)
+ ;;(set! inside-specpdl)
+ unspecific)
+ protected-thunk
+ (lambda ()
+ ;;(set! inside-specpdl *specpdl*)
+ (%unwind! outside-specpdl)
+ (set! outside-specpdl)
+ (unwind-thunk)
+ unspecific))))
(define condition-type:%signal
(make-condition-type 'EL:SIGNAL () '(NAME DATA)
with VAR bound to (SIGNALED-CONDITIONS . SIGNAL-DATA).
The value of the last BODY form is returned from the condition-case.
See SIGNAL for more info."
- (call-with-current-continuation
- (lambda (exit)
- (bind-condition-handler
- (list condition-type:%signal)
- (lambda (condition)
- (let ((generalizations (%get (access-condition condition 'NAME)
- Qerror-conditions)))
- (let loop ((handlers handlers))
- (cond ((null? handlers) false)
- ((memq (caar handlers) generalizations)
- (exit (if (null? var)
- (%progn (CHECK-LIST (cdar handlers)))
- (%specbind
- (list var)
- (list (cons
- (access-condition condition 'NAME)
- (access-condition condition 'DATA)))
- (lambda ()
- (%progn (CHECK-LIST (cdar handlers))))))))
- (else (loop (cdr handlers)))))))
- (lambda ()
- (%eval bodyform))))))
+ (let ((saved-specpdl *specpdl*))
+ (call-with-current-continuation
+ (lambda (exit)
+ (bind-condition-handler
+ (list condition-type:%signal)
+ (lambda (condition)
+ (let ((generalizations (%get (access-condition condition 'NAME)
+ Qerror-conditions)))
+ (let loop ((handlers handlers))
+ (cond ((null? handlers) false)
+ ((memq (caar handlers) generalizations)
+ (%unwind! saved-specpdl)
+ (exit (if (null? var)
+ (%progn (CHECK-LIST (cdar handlers)))
+ (%specbind
+ (list var)
+ (list (cons
+ (access-condition condition 'NAME)
+ (access-condition condition 'DATA)))
+ (lambda ()
+ (%progn (CHECK-LIST (cdar handlers))))))))
+ (else (loop (cdr handlers)))))))
+ (lambda ()
+ (%eval bodyform)))))))
(DEFUN (el:signal name data)
"Signal an error. Args are SIGNAL-NAME, and associated DATA.
"an alist of Emacs Lisp symbols and values, or the Emacs Lisp symbol \"t\""))
(loop autoload-queue)))))
- (let ((outside-queue)
+ (let ((outside-specpdl)
+ (outside-queue)
+ ;;(inside-specpdl *specpdl*)
(inside-queue Qt))
(dynamic-wind
(lambda ()
+ (set! outside-specpdl *specpdl*)
+ ;; Let whoever caught the cc worry about saving the dynamic state!
+ ;;(%wind! inside-specpdl)
+ ;;(set! *specpdl* inside-specpdl)
+ ;;(set! inside-specpdl)
+ ;; Don't make them worry about the autoload-queue!
(set! outside-queue autoload-queue)
(set! autoload-queue inside-queue)
(set! inside-queue)
(set! inside-queue autoload-queue)
(set! autoload-queue outside-queue)
(set! outside-queue)
+ ;;(set! inside-specpdl *specpdl*)
+ (%unwind! outside-specpdl)
+ (set! outside-specpdl)
unspecific))))
(DEFUN (el:eval form)