*** empty log message ***
[bpt/guile.git] / ice-9 / debugger.scm
CommitLineData
e80e1c98
MD
1;;;; Guile Debugger
2
3;;; Copyright (C) 1999 Free Software Foundation, Inc.
4;;;
5;;; This program is free software; you can redistribute it and/or
6;;; modify it under the terms of the GNU General Public License as
7;;; published by the Free Software Foundation; either version 2, or
8;;; (at your option) any later version.
9;;;
10;;; This program is distributed in the hope that it will be useful,
11;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;; General Public License for more details.
14;;;
15;;; You should have received a copy of the GNU General Public License
16;;; along with this software; see the file COPYING. If not, write to
17;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18;;; Boston, MA 02111-1307 USA
19
8be85ef1 20(define-module (ice-9 debugger)
8b8fd2e3
MD
21 :use-module (ice-9 debug)
22 :use-module (ice-9 format)
23 :no-backtrace
24 )
daebab9e
MD
25
26(if (memq 'readline *features*)
27 (define-module (ice-9 debugger)
28 :use-module (ice-9 readline)))
29
e80e1c98 30\f
8be85ef1
MD
31(define debugger-prompt "debug> ")
32
e80e1c98
MD
33(define-public (debug)
34 (let ((stack (fluid-ref the-last-stack)))
35 (if stack
36 (let ((state (make-state stack 0)))
37 (display "This is the Guile debugger; type \"help\" for help.")
38 (newline)
39 (display "There are ")
40 (write (stack-length stack))
41 (display " frames on the stack.")
42 (newline)
43 (newline)
44 (write-state-short state)
45 (read-and-dispatch-commands state (current-input-port)))
46 (display "Nothing to debug.\n"))))
47
e385639e
MD
48(define (debugger-handler key . args)
49 (case key
50 ((exit-debugger) #f)
51 ((signal)
52 ;; Restore stack
53 (fluid-set! the-last-stack (fluid-ref before-signal-stack))
54 (apply display-error #f (current-error-port) args))
55 (else
56 (display "Internal debugger error:\n")
57 (save-stack debugger-handler)
58 (apply throw key args)))
59 (throw 'exit-debugger)) ;Pop the stack
60
e80e1c98
MD
61(define (read-and-dispatch-commands state port)
62 (catch 'exit-debugger
e385639e
MD
63 (lambda ()
64 (lazy-catch #t
65 (lambda ()
66 (with-fluids ((last-command #f))
67 (let loop ((state state))
68 (loop (read-and-dispatch-command state port)))))
69 debugger-handler))
70 (lambda args
71 *unspecified*)))
e80e1c98
MD
72
73(define (read-and-dispatch-command state port)
8be85ef1
MD
74 (if (using-readline?)
75 (set-readline-prompt! debugger-prompt)
0ea63246
MD
76 (display debugger-prompt))
77 (force-output) ;This should not be necessary...
e80e1c98
MD
78 (let ((token (read-token port)))
79 (cond ((eof-object? token)
80 (throw 'exit-debugger))
81 ((not token)
82 (discard-rest-of-line port)
83 (catch-user-errors port (lambda () (run-last-command state))))
84 (else
8b8fd2e3
MD
85 (or (catch-user-errors port
86 (lambda ()
87 (dispatch-command token command-table state port)))
88 state)))))
e80e1c98
MD
89
90(define (run-last-command state)
91 (let ((procedure (fluid-ref last-command)))
92 (if procedure
93 (procedure state))))
94
95(define (catch-user-errors port thunk)
96 (catch 'debugger-user-error
97 thunk
98 (lambda (key . objects)
99 (apply user-warning objects)
8b8fd2e3
MD
100 (discard-rest-of-line port)
101 #f)))
e80e1c98
MD
102
103(define last-command (make-fluid))
104
105(define (user-warning . objects)
106 (for-each (lambda (object)
107 (display object))
108 objects)
109 (newline))
110
111(define (user-error . objects)
112 (apply throw 'debugger-user-error objects))
113\f
114;;;; Command dispatch
115
116(define (dispatch-command string table state port)
117 (let ((value (command-table-value table string)))
118 (if value
119 (dispatch-command/value value state port)
120 (user-error "Unknown command: " string))))
121
122(define (dispatch-command/value value state port)
123 (cond ((command? value)
124 (dispatch-command/command value state port))
125 ((command-table? value)
126 (dispatch-command/table value state port))
127 ((list? value)
128 (dispatch-command/name value state port))
129 (else
130 (error "Unrecognized command-table value: " value))))
131
132(define (dispatch-command/command command state port)
133 (let ((procedure (command-procedure command))
134 (arguments ((command-parser command) port)))
135 (let ((procedure (lambda (state) (apply procedure state arguments))))
136 (warn-about-extra-args port)
137 (fluid-set! last-command procedure)
138 (procedure state))))
139
140(define (warn-about-extra-args port)
141 ;; **** modify this to show the arguments.
142 (let ((char (skip-whitespace port)))
143 (cond ((eof-object? char) #f)
144 ((char=? #\newline char) (read-char port))
145 (else
146 (user-warning "Extra arguments at end of line: "
147 (read-rest-of-line port))))))
148
149(define (dispatch-command/table table state port)
150 (let ((token (read-token port)))
151 (if (or (eof-object? token)
152 (not token))
153 (user-error "Command name too short.")
154 (dispatch-command token table state port))))
155
156(define (dispatch-command/name name state port)
157 (let ((value (lookup-command name)))
158 (cond ((not value)
159 (apply user-error "Unknown command name: " name))
160 ((command-table? value)
161 (apply user-error "Partial command name: " name))
162 (else
163 (dispatch-command/value value state port)))))
164\f
165;;;; Command definition
166
167(define (define-command name argument-template documentation procedure)
168 (let ((name (canonicalize-command-name name)))
169 (add-command name
170 (make-command name
171 (argument-template->parser argument-template)
172 documentation
173 procedure)
174 command-table)
175 name))
176
177(define (define-command-alias name1 name2)
178 (let ((name1 (canonicalize-command-name name1)))
179 (add-command name1 (canonicalize-command-name name2) command-table)
180 name1))
181\f
182(define (argument-template->parser template)
183 ;; Deliberately handles only cases that occur in "commands.scm".
184 (cond ((eq? 'tokens template)
185 (lambda (port)
186 (let loop ((tokens '()))
187 (let ((token (read-token port)))
188 (if (or (eof-object? token)
189 (not token))
190 (list (reverse! tokens))
191 (loop (cons token tokens)))))))
192 ((null? template)
193 (lambda (port)
194 '()))
195 ((and (pair? template)
196 (null? (cdr template))
197 (eq? 'object (car template)))
198 (lambda (port)
199 (list (read port))))
200 ((and (pair? template)
201 (equal? ''optional (car template))
202 (pair? (cdr template))
203 (null? (cddr template)))
204 (case (cadr template)
205 ((token)
206 (lambda (port)
207 (let ((token (read-token port)))
208 (if (or (eof-object? token)
209 (not token))
210 (list #f)
211 (list token)))))
212 ((exact-integer)
213 (lambda (port)
214 (list (parse-optional-exact-integer port))))
215 ((exact-nonnegative-integer)
216 (lambda (port)
217 (list (parse-optional-exact-nonnegative-integer port))))
218 ((object)
219 (lambda (port)
220 (list (parse-optional-object port))))
221 (else
222 (error "Malformed argument template: " template))))
223 (else
224 (error "Malformed argument template: " template))))
225
226(define (parse-optional-exact-integer port)
227 (let ((object (parse-optional-object port)))
228 (if (or (not object)
229 (and (integer? object)
230 (exact? object)))
231 object
232 (user-error "Argument not an exact integer: " object))))
233
234(define (parse-optional-exact-nonnegative-integer port)
235 (let ((object (parse-optional-object port)))
236 (if (or (not object)
237 (and (integer? object)
238 (exact? object)
239 (not (negative? object))))
240 object
241 (user-error "Argument not an exact non-negative integer: " object))))
242
243(define (parse-optional-object port)
244 (let ((terminator (skip-whitespace port)))
245 (if (or (eof-object? terminator)
246 (eq? #\newline terminator))
247 #f
248 (let ((object (read port)))
249 (if (eof-object? object)
250 #f
251 object)))))
252\f
253;;;; Command tables
254
255(define (lookup-command name)
256 (let loop ((table command-table) (strings name))
257 (let ((value (command-table-value table (car strings))))
258 (cond ((or (not value) (null? (cdr strings))) value)
259 ((command-table? value) (loop value (cdr strings)))
260 (else #f)))))
261
262(define (command-table-value table string)
263 (let ((entry (command-table-entry table string)))
264 (and entry
265 (caddr entry))))
266
267(define (command-table-entry table string)
268 (let loop ((entries (command-table-entries table)))
269 (and (not (null? entries))
270 (let ((entry (car entries)))
271 (if (and (<= (cadr entry)
272 (string-length string)
273 (string-length (car entry)))
274 (= (string-length string)
275 (match-strings (car entry) string)))
276 entry
277 (loop (cdr entries)))))))
278
279(define (match-strings s1 s2)
280 (let ((n (min (string-length s1) (string-length s2))))
281 (let loop ((i 0))
282 (cond ((= i n) i)
283 ((char=? (string-ref s1 i) (string-ref s2 i)) (loop (+ i 1)))
284 (else i)))))
285
286(define (write-command-name name)
287 (display (car name))
288 (for-each (lambda (string)
289 (write-char #\space)
290 (display string))
291 (cdr name)))
292\f
293(define (add-command name value table)
294 (let loop ((strings name) (table table))
295 (let ((entry
296 (or (let loop ((entries (command-table-entries table)))
297 (and (not (null? entries))
298 (if (string=? (car strings) (caar entries))
299 (car entries)
300 (loop (cdr entries)))))
301 (let ((entry (list (car strings) #f #f)))
302 (let ((entries
303 (let ((entries (command-table-entries table)))
304 (if (or (null? entries)
305 (string<? (car strings) (caar entries)))
306 (cons entry entries)
307 (begin
308 (let loop ((prev entries) (this (cdr entries)))
309 (if (or (null? this)
310 (string<? (car strings) (caar this)))
311 (set-cdr! prev (cons entry this))
312 (loop this (cdr this))))
313 entries)))))
314 (compute-string-abbreviations! entries)
315 (set-command-table-entries! table entries))
316 entry))))
317 (if (null? (cdr strings))
318 (set-car! (cddr entry) value)
319 (loop (cdr strings)
320 (if (command-table? (caddr entry))
321 (caddr entry)
322 (let ((table (make-command-table '())))
323 (set-car! (cddr entry) table)
324 table)))))))
325
326(define (canonicalize-command-name name)
327 (cond ((and (string? name)
328 (not (string-null? name)))
329 (list name))
330 ((let loop ((name name))
331 (and (pair? name)
332 (string? (car name))
333 (not (string-null? (car name)))
334 (or (null? (cdr name))
335 (loop (cdr name)))))
336 name)
337 (else
338 (error "Illegal command name: " name))))
339
340(define (compute-string-abbreviations! entries)
341 (let loop ((entries entries) (index 0))
342 (let ((groups '()))
343 (for-each
344 (lambda (entry)
345 (let* ((char (string-ref (car entry) index))
346 (group (assv char groups)))
347 (if group
348 (set-cdr! group (cons entry (cdr group)))
349 (set! groups
350 (cons (list char entry)
351 groups)))))
352 entries)
353 (for-each
354 (lambda (group)
355 (let ((index (+ index 1)))
356 (if (null? (cddr group))
357 (set-car! (cdadr group) index)
358 (loop (let ((entry
359 (let loop ((entries (cdr group)))
360 (and (not (null? entries))
361 (if (= index (string-length (caar entries)))
362 (car entries)
363 (loop (cdr entries)))))))
364 (if entry
365 (begin
366 (set-car! (cdr entry) index)
367 (delq entry (cdr group)))
368 (cdr group)))
369 index))))
370 groups))))
371\f
372;;;; Data structures
373
374(define command-table-rtd (make-record-type "command-table" '(entries)))
375(define make-command-table (record-constructor command-table-rtd '(entries)))
376(define command-table? (record-predicate command-table-rtd))
377(define command-table-entries (record-accessor command-table-rtd 'entries))
378(define set-command-table-entries!
379 (record-modifier command-table-rtd 'entries))
380
381(define command-rtd
382 (make-record-type "command"
383 '(name parser documentation procedure)))
384
385(define make-command
386 (record-constructor command-rtd
387 '(name parser documentation procedure)))
388
389(define command? (record-predicate command-rtd))
390(define command-name (record-accessor command-rtd 'name))
391(define command-parser (record-accessor command-rtd 'parser))
392(define command-documentation (record-accessor command-rtd 'documentation))
393(define command-procedure (record-accessor command-rtd 'procedure))
394
395(define state-rtd (make-record-type "debugger-state" '(stack index)))
396(define state? (record-predicate state-rtd))
397(define make-state (record-constructor state-rtd '(stack index)))
398(define state-stack (record-accessor state-rtd 'stack))
399(define state-index (record-accessor state-rtd 'index))
400
401(define (new-state-index state index)
402 (make-state (state-stack state) index))
403\f
404;;;; Character parsing
405
406(define (read-token port)
407 (letrec
408 ((loop
409 (lambda (chars)
410 (let ((char (peek-char port)))
411 (cond ((eof-object? char)
412 (do-eof char chars))
413 ((char=? #\newline char)
414 (do-eot chars))
415 ((char-whitespace? char)
416 (do-eot chars))
417 ((char=? #\# char)
418 (read-char port)
419 (let ((terminator (skip-comment port)))
420 (if (eof-object? char)
421 (do-eof char chars)
422 (do-eot chars))))
423 (else
424 (read-char port)
425 (loop (cons char chars)))))))
426 (do-eof
427 (lambda (eof chars)
428 (if (null? chars)
429 eof
430 (do-eot chars))))
431 (do-eot
432 (lambda (chars)
433 (if (null? chars)
434 #f
435 (list->string (reverse! chars))))))
436 (skip-whitespace port)
437 (loop '())))
438
439(define (skip-whitespace port)
440 (let ((char (peek-char port)))
441 (cond ((or (eof-object? char)
442 (char=? #\newline char))
443 char)
444 ((char-whitespace? char)
445 (read-char port)
446 (skip-whitespace port))
447 ((char=? #\# char)
448 (read-char port)
449 (skip-comment port))
450 (else char))))
451
452(define (skip-comment port)
453 (let ((char (peek-char port)))
454 (if (or (eof-object? char)
455 (char=? #\newline char))
456 char
457 (begin
458 (read-char port)
459 (skip-comment port)))))
460
461(define (read-rest-of-line port)
462 (let loop ((chars '()))
463 (let ((char (read-char port)))
464 (if (or (eof-object? char)
465 (char=? #\newline char))
466 (list->string (reverse! chars))
467 (loop (cons char chars))))))
468
469(define (discard-rest-of-line port)
470 (let loop ()
471 (if (not (let ((char (read-char port)))
472 (or (eof-object? char)
473 (char=? #\newline char))))
474 (loop))))
475\f
476;;;; Commands
477
478(define command-table (make-command-table '()))
479
480(define-command "help" 'tokens
481 "Type \"help\" followed by a command name for full documentation."
482 (lambda (state tokens)
483 (let loop ((name (if (null? tokens) '("help") tokens)))
484 (let ((value (lookup-command name)))
485 (cond ((not value)
486 (write-command-name name)
487 (display " is not a known command name.")
488 (newline))
489 ((command? value)
490 (display (command-documentation value))
491 (newline)
492 (if (equal? '("help") (command-name value))
493 (begin
494 (display "Available commands are:")
495 (newline)
496 (for-each (lambda (entry)
497 (if (not (list? (caddr entry)))
498 (begin
499 (display " ")
500 (display (car entry))
501 (newline))))
502 (command-table-entries command-table)))))
503 ((command-table? value)
504 (display "The \"")
505 (write-command-name name)
506 (display "\" command requires a subcommand.")
507 (newline)
508 (display "Available subcommands are:")
509 (newline)
510 (for-each (lambda (entry)
511 (if (not (list? (caddr entry)))
512 (begin
513 (display " ")
514 (write-command-name name)
515 (write-char #\space)
516 (display (car entry))
517 (newline))))
518 (command-table-entries value)))
519 ((list? value)
520 (loop value))
521 (else
522 (error "Unknown value from lookup-command:" value)))))
523 state))
524
525(define-command "frame" '('optional exact-nonnegative-integer)
526 "Select and print a stack frame.
527With no argument, print the selected stack frame. (See also \"info frame\").
528An argument specifies the frame to select; it must be a stack-frame number."
529 (lambda (state n)
530 (let ((state (if n (select-frame-absolute state n) state)))
531 (write-state-short state)
532 state)))
533
8b8fd2e3
MD
534(define-command "position" '()
535 "Display the position of the current expression."
536 (lambda (state)
537 (let* ((frame (stack-ref (state-stack state) (state-index state)))
538 (source (frame-source frame)))
539 (if (not source)
540 (display "No source available for this frame.")
541 (let ((position (source-position source)))
542 (if (not position)
543 (display "No position information available for this frame.")
544 (display-position position)))))
545 (newline)
546 state))
547
e80e1c98
MD
548(define-command "up" '('optional exact-integer)
549 "Move N frames up the stack. For positive numbers N, this advances
550toward the outermost frame, to higher frame numbers, to frames
551that have existed longer. N defaults to one."
552 (lambda (state n)
553 (let ((state (select-frame-relative state (or n 1))))
554 (write-state-short state)
555 state)))
556
557(define-command "down" '('optional exact-integer)
558 "Move N frames down the stack. For positive numbers N, this
559advances toward the innermost frame, to lower frame numbers, to
560frames that were created more recently. N defaults to one."
561 (lambda (state n)
562 (let ((state (select-frame-relative state (- (or n 1)))))
563 (write-state-short state)
564 state)))
565\f
0ea63246 566(define (eval-handler key . args)
318a34ee
MD
567 (let ((stack (make-stack #t eval-handler)))
568 (if (= (length args) 4)
e385639e 569 (apply display-error stack (current-error-port) args)
318a34ee
MD
570 ;; We want display-error to be the "final common pathway"
571 (catch #t
572 (lambda ()
573 (apply bad-throw key args))
574 (lambda (key . args)
e385639e 575 (apply display-error stack (current-error-port) args)))))
0ea63246
MD
576 (throw 'continue))
577
e80e1c98
MD
578(define-command "evaluate" '(object)
579 "Evaluate an expression.
580The expression must appear on the same line as the command,
581however it may be continued over multiple lines."
582 (lambda (state expression)
0ea63246
MD
583 (let ((source (frame-source (stack-ref (state-stack state)
584 (state-index state)))))
585 (if (not source)
c129a9b4 586 (display "No environment for this frame.\n")
0ea63246
MD
587 (catch 'continue
588 (lambda ()
589 (lazy-catch #t
590 (lambda ()
591 (let* ((env (memoized-environment source))
592 (value (local-eval expression env)))
593 (display ";value: ")
2834f3fe
MD
594 (write value)
595 (newline)))
0ea63246
MD
596 eval-handler))
597 (lambda args args)))
598 state)))
e80e1c98
MD
599
600(define-command "backtrace" '('optional exact-integer)
601 "Print backtrace of all stack frames, or innermost COUNT frames.
0ea63246
MD
602With a negative argument, print outermost -COUNT frames.
603If the number of frames aren't explicitly given, the debug option
604`depth' determines the maximum number of frames printed."
e80e1c98
MD
605 (lambda (state n-frames)
606 (let ((stack (state-stack state)))
607 ;; Kludge around lack of call-with-values.
608 (let ((values
609 (lambda (start end)
8be85ef1
MD
610 ;;(do ((index start (+ index 1)))
611 ;; ((= index end))
612 ;;(write-state-short* stack index))
613 ;;
614 ;; Use builtin backtrace instead:
c129a9b4
MD
615 (display-backtrace stack
616 (current-output-port)
617 (if (memq 'backwards (debug-options))
618 start
619 (- end 1))
620 (- end start))
8be85ef1 621 )))
e80e1c98 622 (let ((end (stack-length stack)))
c129a9b4
MD
623 (cond ((not n-frames) ;(>= (abs n-frames) end))
624 (values 0 (min end (cadr (memq 'depth (debug-options))))))
e80e1c98
MD
625 ((>= n-frames 0)
626 (values 0 n-frames))
627 (else
628 (values (+ end n-frames) end))))))
629 state))
630
631(define-command "quit" '()
632 "Exit the debugger."
633 (lambda (state)
634 (throw 'exit-debugger)))
635
636(define-command '("info" "frame") '()
637 "All about selected stack frame."
638 (lambda (state)
639 (write-state-long state)
640 state))
641
642(define-command '("info" "args") '()
643 "Argument variables of current stack frame."
644 (lambda (state)
645 (let ((index (state-index state)))
646 (let ((frame (stack-ref (state-stack state) index)))
8be85ef1 647 (write-frame-index-long frame)
e80e1c98
MD
648 (write-frame-args-long frame)))
649 state))
650
651(define-command-alias "f" "frame")
652(define-command-alias '("info" "f") '("info" "frame"))
653(define-command-alias "bt" "backtrace")
654(define-command-alias "where" "backtrace")
8b8fd2e3 655(define-command-alias "p" "evaluate")
e80e1c98
MD
656(define-command-alias '("info" "stack") "backtrace")
657\f
658;;;; Command Support
659
8be85ef1 660(define (select-frame-absolute state number)
e80e1c98 661 (new-state-index state
8be85ef1
MD
662 (frame-number->index
663 (let ((end (stack-length (state-stack state))))
664 (if (>= number end)
665 (- end 1)
666 number))
667 (state-stack state))))
e80e1c98
MD
668
669(define (select-frame-relative state delta)
670 (new-state-index state
671 (let ((index (+ (state-index state) delta))
672 (end (stack-length (state-stack state))))
673 (cond ((< index 0) 0)
674 ((>= index end) (- end 1))
675 (else index)))))
676
677(define (write-state-short state)
678 (display "Frame ")
679 (write-state-short* (state-stack state) (state-index state)))
680
681(define (write-state-short* stack index)
8be85ef1 682 (write-frame-index-short stack index)
e80e1c98
MD
683 (write-char #\space)
684 (write-frame-short (stack-ref stack index))
685 (newline))
686
8be85ef1
MD
687(define (write-frame-index-short stack index)
688 (let ((s (number->string (frame-number (stack-ref stack index)))))
e80e1c98
MD
689 (display s)
690 (write-char #\:)
691 (write-chars #\space (- 4 (string-length s)))))
692
693(define (write-frame-short frame)
694 (if (frame-procedure? frame)
695 (write-frame-short/application frame)
696 (write-frame-short/expression frame)))
697
698(define (write-frame-short/application frame)
699 (write-char #\[)
700 (write (let ((procedure (frame-procedure frame)))
701 (or (and (procedure? procedure)
702 (procedure-name procedure))
703 procedure)))
704 (if (frame-evaluating-args? frame)
705 (display " ...")
706 (begin
707 (for-each (lambda (argument)
708 (write-char #\space)
709 (write argument))
710 (frame-arguments frame))
711 (write-char #\]))))
712
713;;; Use builtin function instead:
0ea63246
MD
714(set! write-frame-short/application
715 (lambda (frame)
716 (display-application frame (current-output-port) 12)))
e80e1c98
MD
717
718(define (write-frame-short/expression frame)
719 (write (let* ((source (frame-source frame))
720 (copy (source-property source 'copy)))
721 (if (pair? copy)
722 copy
723 (unmemoize source)))))
724\f
725(define (write-state-long state)
726 (let ((index (state-index state)))
727 (let ((frame (stack-ref (state-stack state) index)))
8be85ef1 728 (write-frame-index-long frame)
e80e1c98
MD
729 (write-frame-long frame))))
730
8be85ef1 731(define (write-frame-index-long frame)
e80e1c98 732 (display "Stack frame: ")
8be85ef1 733 (write (frame-number frame))
e80e1c98
MD
734 (if (frame-real? frame)
735 (display " (real)"))
736 (newline))
737
738(define (write-frame-long frame)
739 (if (frame-procedure? frame)
740 (write-frame-long/application frame)
741 (write-frame-long/expression frame)))
742
743(define (write-frame-long/application frame)
744 (display "This frame is an application.")
745 (newline)
0ea63246
MD
746 (if (frame-source frame)
747 (begin
748 (display "The corresponding expression is:")
749 (newline)
750 (display-source frame)
751 (newline)))
e80e1c98
MD
752 (display "The procedure being applied is: ")
753 (write (let ((procedure (frame-procedure frame)))
754 (or (and (procedure? procedure)
755 (procedure-name procedure))
756 procedure)))
757 (newline)
758 (display "The procedure's arguments are")
759 (if (frame-evaluating-args? frame)
760 (display " being evaluated.")
761 (begin
762 (display ": ")
763 (write (frame-arguments frame))))
764 (newline))
765
0ea63246 766(define (display-source frame)
8b8fd2e3
MD
767 (let* ((source (frame-source frame))
768 (copy (source-property source 'copy)))
769 (cond ((source-position source)
770 => (lambda (p) (display-position p) (display ":\n"))))
771 (display " ")
772 (write (or copy (unmemoize source)))))
773
774(define (source-position source)
775 (let ((fname (source-property source 'filename))
776 (line (source-property source 'line))
777 (column (source-property source 'column)))
778 (and fname
779 (list fname line column))))
780
781(define (display-position pos)
782 (format #t "~A:~D:~D" (car pos) (+ 1 (cadr pos)) (+ 1 (caddr pos))))
0ea63246
MD
783
784(define (write-frame-long/expression frame)
785 (display "This frame is an evaluation.")
786 (newline)
787 (display "The expression being evaluated is:")
788 (newline)
789 (display-source frame)
e80e1c98
MD
790 (newline))
791
792(define (write-frame-args-long frame)
793 (if (frame-procedure? frame)
794 (let ((arguments (frame-arguments frame)))
795 (let ((n (length arguments)))
796 (display "This frame has ")
797 (write n)
798 (display " argument")
799 (if (not (= n 1))
800 (display "s"))
801 (write-char (if (null? arguments) #\. #\:))
802 (newline))
803 (for-each (lambda (argument)
804 (display " ")
805 (write argument)
806 (newline))
807 arguments))
808 (begin
809 (display "This frame is an evaluation frame; it has no arguments.")
810 (newline))))
811
812(define (write-chars char n)
813 (do ((i 0 (+ i 1)))
814 ((>= i n))
815 (write-char char)))