📄 debugger.scm
字号:
(define state? (record-predicate state-rtd))(define make-state (record-constructor state-rtd '(stack index)))(define state-stack (record-accessor state-rtd 'stack))(define state-index (record-accessor state-rtd 'index))(define (new-state-index state index) (make-state (state-stack state) index));;;; Character parsing(define (read-token port) (letrec ((loop (lambda (chars) (let ((char (peek-char port))) (cond ((eof-object? char) (do-eof char chars)) ((char=? #\newline char) (do-eot chars)) ((char-whitespace? char) (do-eot chars)) ((char=? #\# char) (read-char port) (let ((terminator (skip-comment port))) (if (eof-object? char) (do-eof char chars) (do-eot chars)))) (else (read-char port) (loop (cons char chars))))))) (do-eof (lambda (eof chars) (if (null? chars) eof (do-eot chars)))) (do-eot (lambda (chars) (if (null? chars) #f (list->string (reverse! chars)))))) (skip-whitespace port) (loop '())))(define (skip-whitespace port) (let ((char (peek-char port))) (cond ((or (eof-object? char) (char=? #\newline char)) char) ((char-whitespace? char) (read-char port) (skip-whitespace port)) ((char=? #\# char) (read-char port) (skip-comment port)) (else char))))(define (skip-comment port) (let ((char (peek-char port))) (if (or (eof-object? char) (char=? #\newline char)) char (begin (read-char port) (skip-comment port)))))(define (read-rest-of-line port) (let loop ((chars '())) (let ((char (read-char port))) (if (or (eof-object? char) (char=? #\newline char)) (list->string (reverse! chars)) (loop (cons char chars))))))(define (discard-rest-of-line port) (let loop () (if (not (let ((char (read-char port))) (or (eof-object? char) (char=? #\newline char)))) (loop))));;;; Commands(define command-table (make-command-table '()))(define-command "help" 'tokens "Type \"help\" followed by a command name for full documentation." (lambda (state tokens) (let loop ((name (if (null? tokens) '("help") tokens))) (let ((value (lookup-command name))) (cond ((not value) (write-command-name name) (display " is not a known command name.") (newline)) ((command? value) (display (command-documentation value)) (newline) (if (equal? '("help") (command-name value)) (begin (display "Available commands are:") (newline) (for-each (lambda (entry) (if (not (list? (caddr entry))) (begin (display " ") (display (car entry)) (newline)))) (command-table-entries command-table))))) ((command-table? value) (display "The \"") (write-command-name name) (display "\" command requires a subcommand.") (newline) (display "Available subcommands are:") (newline) (for-each (lambda (entry) (if (not (list? (caddr entry))) (begin (display " ") (write-command-name name) (write-char #\space) (display (car entry)) (newline)))) (command-table-entries value))) ((list? value) (loop value)) (else (error "Unknown value from lookup-command:" value))))) state))(define-command "frame" '('optional exact-nonnegative-integer) "Select and print a stack frame.With no argument, print the selected stack frame. (See also \"info frame\").An argument specifies the frame to select; it must be a stack-frame number." (lambda (state n) (let ((state (if n (select-frame-absolute state n) state))) (write-state-short state) state)))(define-command "position" '() "Display the position of the current expression." (lambda (state) (let* ((frame (stack-ref (state-stack state) (state-index state))) (source (frame-source frame))) (if (not source) (display "No source available for this frame.") (let ((position (source-position source))) (if (not position) (display "No position information available for this frame.") (display-position position))))) (newline) state))(define-command "up" '('optional exact-integer) "Move N frames up the stack. For positive numbers N, this advancestoward the outermost frame, to higher frame numbers, to framesthat have existed longer. N defaults to one." (lambda (state n) (let ((state (select-frame-relative state (or n 1)))) (write-state-short state) state)))(define-command "down" '('optional exact-integer) "Move N frames down the stack. For positive numbers N, thisadvances toward the innermost frame, to lower frame numbers, toframes that were created more recently. N defaults to one." (lambda (state n) (let ((state (select-frame-relative state (- (or n 1))))) (write-state-short state) state)))(define (eval-handler key . args) (let ((stack (make-stack #t eval-handler))) (if (= (length args) 4) (apply display-error stack (current-error-port) args) ;; We want display-error to be the "final common pathway" (catch #t (lambda () (apply bad-throw key args)) (lambda (key . args) (apply display-error stack (current-error-port) args))))) (throw 'continue))(define-command "evaluate" '(object) "Evaluate an expression.The expression must appear on the same line as the command,however it may be continued over multiple lines." (lambda (state expression) (let ((source (frame-source (stack-ref (state-stack state) (state-index state))))) (if (not source) (display "No environment for this frame.\n") (catch 'continue (lambda () (lazy-catch #t (lambda () (let* ((env (memoized-environment source)) (value (local-eval expression env))) (display ";value: ") (write value) (newline))) eval-handler)) (lambda args args))) state)))(define-command "backtrace" '('optional exact-integer) "Print backtrace of all stack frames, or innermost COUNT frames.With a negative argument, print outermost -COUNT frames.If the number of frames aren't explicitly given, the debug option`depth' determines the maximum number of frames printed." (lambda (state n-frames) (let ((stack (state-stack state))) ;; Kludge around lack of call-with-values. (let ((values (lambda (start end) ;;(do ((index start (+ index 1))) ;; ((= index end)) ;;(write-state-short* stack index)) ;; ;; Use builtin backtrace instead: (display-backtrace stack (current-output-port) (if (memq 'backwards (debug-options)) start (- end 1)) (- end start)) ))) (let ((end (stack-length stack))) (cond ((not n-frames) ;(>= (abs n-frames) end)) (values 0 (min end (cadr (memq 'depth (debug-options)))))) ((>= n-frames 0) (values 0 n-frames)) (else (values (+ end n-frames) end)))))) state))(define-command "quit" '() "Exit the debugger." (lambda (state) (throw 'exit-debugger)))(define-command '("info" "frame") '() "All about selected stack frame." (lambda (state) (write-state-long state) state))(define-command '("info" "args") '() "Argument variables of current stack frame." (lambda (state) (let ((index (state-index state))) (let ((frame (stack-ref (state-stack state) index))) (write-frame-index-long frame) (write-frame-args-long frame))) state))(define-command-alias "f" "frame")(define-command-alias '("info" "f") '("info" "frame"))(define-command-alias "bt" "backtrace")(define-command-alias "where" "backtrace")(define-command-alias "p" "evaluate")(define-command-alias '("info" "stack") "backtrace");;;; Command Support(define (select-frame-absolute state number) (new-state-index state (frame-number->index (let ((end (stack-length (state-stack state)))) (if (>= number end) (- end 1) number)) (state-stack state))))(define (select-frame-relative state delta) (new-state-index state (let ((index (+ (state-index state) delta)) (end (stack-length (state-stack state)))) (cond ((< index 0) 0) ((>= index end) (- end 1)) (else index)))))(define (write-state-short state) (display "Frame ") (write-state-short* (state-stack state) (state-index state)))(define (write-state-short* stack index) (write-frame-index-short stack index) (write-char #\space) (write-frame-short (stack-ref stack index)) (newline))(define (write-frame-index-short stack index) (let ((s (number->string (frame-number (stack-ref stack index))))) (display s) (write-char #\:) (write-chars #\space (- 4 (string-length s)))))(define (write-frame-short frame) (if (frame-procedure? frame) (write-frame-short/application frame) (write-frame-short/expression frame)))(define (write-frame-short/application frame) (write-char #\[) (write (let ((procedure (frame-procedure frame))) (or (and (procedure? procedure) (procedure-name procedure)) procedure))) (if (frame-evaluating-args? frame) (display " ...") (begin (for-each (lambda (argument) (write-char #\space) (write argument)) (frame-arguments frame)) (write-char #\]))));;; Use builtin function instead:(set! write-frame-short/application (lambda (frame) (display-application frame (current-output-port) 12)))(define (write-frame-short/expression frame) (write (let* ((source (frame-source frame)) (copy (source-property source 'copy))) (if (pair? copy) copy (unmemoize source)))))(define (write-state-long state) (let ((index (state-index state))) (let ((frame (stack-ref (state-stack state) index))) (write-frame-index-long frame) (write-frame-long frame))))(define (write-frame-index-long frame) (display "Stack frame: ") (write (frame-number frame)) (if (frame-real? frame) (display " (real)")) (newline))(define (write-frame-long frame) (if (frame-procedure? frame) (write-frame-long/application frame) (write-frame-long/expression frame)))(define (write-frame-long/application frame) (display "This frame is an application.") (newline) (if (frame-source frame) (begin (display "The corresponding expression is:") (newline) (display-source frame) (newline))) (display "The procedure being applied is: ") (write (let ((procedure (frame-procedure frame))) (or (and (procedure? procedure) (procedure-name procedure)) procedure))) (newline) (display "The procedure's arguments are") (if (frame-evaluating-args? frame) (display " being evaluated.") (begin (display ": ") (write (frame-arguments frame)))) (newline))(define (display-source frame) (let* ((source (frame-source frame)) (copy (source-property source 'copy))) (cond ((source-position source) => (lambda (p) (display-position p) (display ":\n")))) (display " ") (write (or copy (unmemoize source)))))(define (source-position source) (let ((fname (source-property source 'filename)) (line (source-property source 'line)) (column (source-property source 'column))) (and fname (list fname line column))))(define (display-position pos) (format #t "~A:~D:~D" (car pos) (+ 1 (cadr pos)) (+ 1 (caddr pos))))(define (write-frame-long/expression frame) (display "This frame is an evaluation.") (newline) (display "The expression being evaluated is:") (newline) (display-source frame) (newline))(define (write-frame-args-long frame) (if (frame-procedure? frame) (let ((arguments (frame-arguments frame))) (let ((n (length arguments))) (display "This frame has ") (write n) (display " argument") (if (not (= n 1)) (display "s")) (write-char (if (null? arguments) #\. #\:)) (newline)) (for-each (lambda (argument) (display " ") (write argument) (newline)) arguments)) (begin (display "This frame is an evaluation frame; it has no arguments.") (newline))))(define (write-chars char n) (do ((i 0 (+ i 1))) ((>= i n)) (write-char char)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -