213 lines
5.8 KiB
Scheme
213 lines
5.8 KiB
Scheme
|
;;; -*-Scheme-*-
|
||
|
;;;
|
||
|
;;; A simple debugger (improvements by Thomas M. Breuel <tmb@ai.mit.edu>).
|
||
|
|
||
|
(define (backtrace . args)
|
||
|
(if (> (length args) 1)
|
||
|
(error 'backtrace "too many arguments"))
|
||
|
(if (not (null? args))
|
||
|
(if (not (eq? (type (car args)) 'control-point))
|
||
|
(error 'backtrace "argument must be a control point")))
|
||
|
(let ((trace (apply backtrace-list args)))
|
||
|
(if (null? args)
|
||
|
(set! trace (cdddr trace)))
|
||
|
(show-backtrace trace 0 999999)))
|
||
|
|
||
|
(define (show-backtrace trace start-frame end-frame)
|
||
|
(define (rjust n x)
|
||
|
(let* ((y (string-append (make-string n #\space) x))
|
||
|
(l (string-length y)))
|
||
|
(substring y (- l n) l)))
|
||
|
(let ((maxlen 28))
|
||
|
(let loop ((frames (list-tail trace start-frame)) (num start-frame))
|
||
|
(if (or (null? frames) (>= num end-frame)) #v
|
||
|
(let ((frame (car frames)))
|
||
|
(let* ((func
|
||
|
(format #f "~s" (vector-ref frame 0)))
|
||
|
(indent
|
||
|
(- maxlen (+ 5 (string-length func)))))
|
||
|
(display (rjust 4 (number->string num)))
|
||
|
(display " ")
|
||
|
(display func)
|
||
|
(if (negative? indent)
|
||
|
(begin
|
||
|
(newline)
|
||
|
(set! indent maxlen)))
|
||
|
(do ((i indent (1- i)))
|
||
|
((> 0 i))
|
||
|
(display " ")))
|
||
|
(fluid-let
|
||
|
((print-depth 2)
|
||
|
(print-length 3))
|
||
|
(display (vector-ref frame 1)))
|
||
|
(newline))
|
||
|
(loop (cdr frames) (1+ num))))))
|
||
|
|
||
|
(define (show-environment env)
|
||
|
(fluid-let
|
||
|
((print-length 2)
|
||
|
(print-depth 2))
|
||
|
(do ((f (environment->list env) (cdr f)))
|
||
|
((null? f))
|
||
|
(do ((b (car f) (cdr b)))
|
||
|
((null? b))
|
||
|
(format #t "~s\t~s~%" (caar b) (cdar b)))
|
||
|
(print '-------)))
|
||
|
#v)
|
||
|
|
||
|
(define inspect)
|
||
|
|
||
|
(let ((frame)
|
||
|
(trace)
|
||
|
(help-text
|
||
|
'("q -- quit inspector"
|
||
|
"f -- print current frame"
|
||
|
"u -- go up one frame"
|
||
|
"d -- go down one frame"
|
||
|
"^ -- go to top frame"
|
||
|
"$ -- go to bottom frame"
|
||
|
"g <n> -- goto to n-th frame"
|
||
|
"e -- eval expressions in environment"
|
||
|
"p -- pretty-print procedure"
|
||
|
"v -- show environment"
|
||
|
"<n> -- pretty-print n-th argument"
|
||
|
"b -- show backtrace starting at current frame"
|
||
|
"t -- show top of bracktrace starting at current frame"
|
||
|
"z -- show and move top of backtrace starting at current frame"
|
||
|
"o -- obarray information")))
|
||
|
|
||
|
(define (inspect-command-loop)
|
||
|
(let ((input) (done #f))
|
||
|
(display "inspect> ")
|
||
|
(set! input (read))
|
||
|
(case input
|
||
|
(q
|
||
|
(set! done #t))
|
||
|
(?
|
||
|
(for-each
|
||
|
(lambda (msg)
|
||
|
(display msg)
|
||
|
(newline))
|
||
|
help-text))
|
||
|
(f
|
||
|
(print-frame))
|
||
|
(^
|
||
|
(set! frame 0)
|
||
|
(print-frame))
|
||
|
($
|
||
|
(set! frame (1- (length trace)))
|
||
|
(print-frame))
|
||
|
(u
|
||
|
(if (zero? frame)
|
||
|
(format #t "Already on top frame.~%")
|
||
|
(set! frame (1- frame))
|
||
|
(print-frame)))
|
||
|
(d
|
||
|
(if (= frame (1- (length trace)))
|
||
|
(format #t "Already on bottom frame.~%")
|
||
|
(set! frame (1+ frame))
|
||
|
(print-frame)))
|
||
|
(g
|
||
|
(set! input (read))
|
||
|
(if (integer? input)
|
||
|
(set! frame
|
||
|
(cond ((negative? input) 0)
|
||
|
((>= input (length trace)) (1- (length trace)))
|
||
|
(else input)))
|
||
|
(format #t "Frame number must be an integer.~%")))
|
||
|
(v
|
||
|
(show-environment (vector-ref (list-ref trace frame) 2)))
|
||
|
(e
|
||
|
(format #t "Type ^D to return to Inspector.~%")
|
||
|
(let loop ()
|
||
|
(display "eval> ")
|
||
|
(set! input (read))
|
||
|
(if (not (eof-object? input))
|
||
|
(begin
|
||
|
(write (eval input
|
||
|
(vector-ref (list-ref trace frame) 2)))
|
||
|
(newline)
|
||
|
(loop))))
|
||
|
(newline))
|
||
|
(p
|
||
|
(pp (vector-ref (list-ref trace frame) 0))
|
||
|
(newline))
|
||
|
(z
|
||
|
(show-backtrace trace frame (+ frame 10))
|
||
|
(set! frame (+ frame 9))
|
||
|
(if (>= frame (length trace)) (set! frame (1- (length trace)))))
|
||
|
(t
|
||
|
(show-backtrace trace frame (+ frame 10)))
|
||
|
(b
|
||
|
(show-backtrace trace frame 999999))
|
||
|
(o
|
||
|
(let ((l (map length (oblist))))
|
||
|
(let ((n 0))
|
||
|
(for-each (lambda (x) (set! n (+ x n))) l)
|
||
|
(format #t "~s symbols " n)
|
||
|
(format #t "(maximum bucket: ~s).~%" (apply max l)))))
|
||
|
(else
|
||
|
(cond
|
||
|
((integer? input)
|
||
|
(let ((args (vector-ref (list-ref trace frame) 1)))
|
||
|
(if (or (< input 1) (> input (length args)))
|
||
|
(format #t "No such argument.~%")
|
||
|
(pp (list-ref args (1- input)))
|
||
|
(newline))))
|
||
|
((eof-object? input)
|
||
|
(set! done #t))
|
||
|
(else
|
||
|
(format #t "Invalid command. Type ? for help.~%")))))
|
||
|
(if (not done)
|
||
|
(inspect-command-loop))))
|
||
|
|
||
|
(define (print-frame)
|
||
|
(format #t "~%Frame ~s of ~s:~%~%" frame (1- (length trace)))
|
||
|
(let* ((f (list-ref trace frame)) (args (vector-ref f 1)))
|
||
|
(format #t "Procedure: ~s~%" (vector-ref f 0))
|
||
|
(format #t "Environment: ~s~%" (vector-ref f 2))
|
||
|
(if (null? args)
|
||
|
(format #t "No arguments.~%")
|
||
|
(fluid-let
|
||
|
((print-depth 2)
|
||
|
(print-length 3))
|
||
|
(do ((i 1 (1+ i)) (args args (cdr args))) ((null? args))
|
||
|
(format #t "Argument ~s: ~s~%" i (car args))))))
|
||
|
(newline))
|
||
|
|
||
|
(define (find-frame proc)
|
||
|
(let loop ((l trace) (i 0))
|
||
|
(cond ((null? l) -1)
|
||
|
((eq? (vector-ref (car l) 0) proc) i)
|
||
|
(else (loop (cdr l) (1+ i))))))
|
||
|
|
||
|
(set! inspect
|
||
|
(lambda ()
|
||
|
(set! trace (backtrace-list))
|
||
|
(set! trace (cddr trace))
|
||
|
(do ((t trace (cdr t)) (f 1 (1+ f))) ((null? t))
|
||
|
(if (not (null? (vector-ref (car t) 1)))
|
||
|
(let ((last (last-pair (vector-ref (car t) 1))))
|
||
|
(if (not (null? (cdr last)))
|
||
|
(begin
|
||
|
(format #t
|
||
|
"[inspector: fixing improper arglist in frame ~s]~%" f)
|
||
|
(set-cdr! last (cons (cdr last) '())))))))
|
||
|
(set! frame (find-frame error-handler))
|
||
|
(if (negative? frame)
|
||
|
(set! frame 0))
|
||
|
(format #t "Inspector (type ? for help):~%")
|
||
|
(let loop ()
|
||
|
(if (call-with-current-continuation
|
||
|
(lambda (control-point)
|
||
|
(push-frame control-point)
|
||
|
(inspect-command-loop)
|
||
|
#f))
|
||
|
(begin
|
||
|
(pop-frame)
|
||
|
(loop))))
|
||
|
(newline)
|
||
|
(pop-frame)
|
||
|
(let ((next-frame (car rep-frames)))
|
||
|
(next-frame #t)))))
|