File: stack-checkpoint.rkt

package info (click to toggle)
racket-mode 20250711~git.8a80578-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,024 kB
  • sloc: lisp: 17,215; makefile: 106
file content (52 lines) | stat: -rw-r--r-- 1,959 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
;; Copyright (c) 2013-2022 by Greg Hendershott.
;; SPDX-License-Identifier: GPL-3.0-or-later

#lang racket/base

(require racket/list
         racket/match
         syntax/parse/define)

(provide with-stack-checkpoint
         continuation-mark-set->trimmed-context)

;;; Inspired by drracket/private/stack-checkpoint.rkt.

;; Run a thunk, and if an exception is raised, make it possible to
;; trim the stack so that the surrounding context is hidden
(define checkpoints (make-weak-hasheq))
(define (call-with-stack-checkpoint thunk)
  (define checkpoint #f)
  (call-with-exception-handler
   (λ (exn)
     (when checkpoint ; just in case there's an exception before it's set
       (define key (if (exn? exn) (exn-continuation-marks exn) exn))
       (unless (hash-has-key? checkpoints key)
         (hash-set! checkpoints key checkpoint)))
     exn)
   (λ ()
     (set! checkpoint (current-continuation-marks))
     (thunk))))

(define-simple-macro (with-stack-checkpoint e:expr ...+)
  (call-with-stack-checkpoint (λ () e ...)))

;; Like continuation-mark-set->context, but trims any tail registered
;; as a checkpoint, as well as removing items lacking srcloc.
(define (continuation-mark-set->trimmed-context cms)
  (define stack (continuation-mark-set->context cms))
  (filter
   cdr ;only non-#f srcloc
   (match (hash-ref checkpoints cms #f)
     [(? continuation-mark-set? v)
      (define checkpoint (continuation-mark-set->context v))
      ;; To drop the common tail, reverse both and use drop-common-prefix.
      (define-values (trimmed _) (drop-common-prefix (reverse stack)
                                                     (reverse checkpoint)))
      (match trimmed
        ;; The mark for call-with-stack-checkpoint is the head; ignore
        ;; it. Reverse the remainder back to stack order.
        [(cons _ xs) (reverse xs)]
        ;; Can happen with Racket < 7.0 and debugger REPL.
        [_           '()])]
     [#f stack])))