diff --git a/collects/tests/xrepl/xrepl.rkt b/collects/tests/xrepl/xrepl.rkt index c86b744198..1af636c0f6 100644 --- a/collects/tests/xrepl/xrepl.rkt +++ b/collects/tests/xrepl/xrepl.rkt @@ -87,6 +87,9 @@ 4 -> «(list ^ ^^ ^^^ ^^^^)» '(4 3 2 1) + -> «(collect-garbage)» + -> «^» + ; ^: saved value #1 was garbage-collected [,bt for context] -> «(module foo racket (define x 123))» -> «,en foo» 'foo> «x» diff --git a/collects/xrepl/saved-values.rkt b/collects/xrepl/saved-values.rkt index 55bff1a83f..67d85747c4 100644 --- a/collects/xrepl/saved-values.rkt +++ b/collects/xrepl/saved-values.rkt @@ -49,7 +49,12 @@ [else (err "unknown name pattern for a saved-value reference")])) (unless (pair? saved) (err "no saved values, yet")) (when (n . > . (length saved)) (err "no ~a saved values, yet" n)) - #`'#,(list-ref saved (sub1 n))) + ;; the values are either `#f', or a weak box holding the value + (define r + (let ([b (list-ref saved (sub1 n))]) + (and b (or (weak-box-value b) + (err "saved value #~a was garbage-collected" n))))) + #`'#,r) (syntax-case stx (set!) [(set! id . xs) (raise-syntax-error 'set! "cannot set history reference")] [(id . xs) (datum->syntax stx (cons (ref #'id) #'xs) stx)] diff --git a/collects/xrepl/xrepl.rkt b/collects/xrepl/xrepl.rkt index 84aa27a0dc..263d3f47fa 100644 --- a/collects/xrepl/xrepl.rkt +++ b/collects/xrepl/xrepl.rkt @@ -1198,7 +1198,8 @@ ;; saved interaction values (can be #f to disable saving) (define saved-values (make-parameter '())) (define (save-values! xs) - (let ([xs (filter (λ (x) (not (void? x))) xs)]) ; don't save void values + (let* ([xs (filter (λ (x) (not (void? x))) xs)] ; don't save void values + [xs (map (λ (x) (and x (make-weak-box x))) xs)]) ; save weakly (unless (null? xs) ;; the order is last, 2nd-to-last, ..., same from prev interactions ;; the idea is that `^', `^^', etc refer to the values as displayed diff --git a/collects/xrepl/xrepl.scrbl b/collects/xrepl/xrepl.scrbl index afcf299d25..dd3f5493de 100644 --- a/collects/xrepl/xrepl.scrbl +++ b/collects/xrepl/xrepl.scrbl @@ -451,9 +451,19 @@ The rationale for this is that @racketidfont{^} always refers to the last @emph{printed} result, @racketidfont{^^} to the one before that, etc. -These bindings are made available only if they are not already defined, -and if they are not modified. This means that if you have code that -uses these names, it will continue to work as usual. +The bindings are made available only if they are not already defined. +This means that if you have code that uses these names, it will continue +to work as usual. + +The bindings are identifier macros that expand to the literal saved +values; so referring to a saved value that is missing (because not +enough values were shown) raises a syntax error. In addition, the +values are held in a @tech{weak reference}, so they can disappear after +a garbage-collection. + +Note that this facility can be used to ``transfer'' values from one +namespace to another---but beware of struct values that might come from +a different instantiation of a module. @; --------------------------------------------------------------------- @section{Hacking XREPL}