a2f2a6f846565d2c3a1bb0d87f4b58628b29c3c9
[bpt/guile.git] / module / system / repl / command.scm
1 ;;; Repl commands
2
3 ;; Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
4
5 ;; This library is free software; you can redistribute it and/or
6 ;; modify it under the terms of the GNU Lesser General Public
7 ;; License as published by the Free Software Foundation; either
8 ;; version 3 of the License, or (at your option) any later version.
9 ;;
10 ;; This library 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 ;; Lesser General Public License for more details.
14 ;;
15 ;; You should have received a copy of the GNU Lesser General Public
16 ;; License along with this library; if not, write to the Free Software
17 ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 ;; 02110-1301 USA
19
20 ;;; Code:
21
22 (define-module (system repl command)
23 #:use-module (system base syntax)
24 #:use-module (system base pmatch)
25 #:use-module (system base compile)
26 #:use-module (system repl common)
27 #:use-module (system repl debug)
28 #:use-module (system vm objcode)
29 #:use-module (system vm program)
30 #:use-module (system vm trap-state)
31 #:use-module (system vm vm)
32 #:use-module ((system vm frame) #:select (frame-return-values))
33 #:autoload (system base language) (lookup-language language-reader)
34 #:autoload (system vm trace) (call-with-trace)
35 #:use-module (ice-9 format)
36 #:use-module (ice-9 session)
37 #:use-module (ice-9 documentation)
38 #:use-module (ice-9 and-let-star)
39 #:use-module (ice-9 rdelim)
40 #:use-module (ice-9 control)
41 #:use-module ((ice-9 pretty-print) #:select ((pretty-print . pp)))
42 #:use-module ((system vm inspect) #:select ((inspect . %inspect)))
43 #:use-module (statprof)
44 #:export (meta-command define-meta-command))
45
46 \f
47 ;;;
48 ;;; Meta command interface
49 ;;;
50
51 (define *command-table*
52 '((help (help h) (show) (apropos a) (describe d))
53 (module (module m) (import use) (load l) (reload re) (binding b) (in))
54 (language (language L))
55 (compile (compile c) (compile-file cc)
56 (disassemble x) (disassemble-file xx))
57 (profile (time t) (profile pr) (trace tr))
58 (debug (backtrace bt) (up) (down) (frame fr)
59 (procedure proc) (locals) (error-message error)
60 (break br bp) (break-at-source break-at bs)
61 (step s) (step-instruction si)
62 (next n) (next-instruction ni)
63 (finish)
64 (tracepoint tp)
65 (traps) (delete del) (disable) (enable)
66 (registers regs))
67 (inspect (inspect i) (pretty-print pp))
68 (system (gc) (statistics stat) (option o)
69 (quit q continue cont))))
70
71 (define *show-table*
72 '((show (warranty w) (copying c) (version v))))
73
74 (define (group-name g) (car g))
75 (define (group-commands g) (cdr g))
76
77 (define *command-infos* (make-hash-table))
78 (define (command-name c) (car c))
79 (define (command-abbrevs c) (cdr c))
80 (define (command-info c) (hashq-ref *command-infos* (command-name c)))
81 (define (command-procedure c) (command-info-procedure (command-info c)))
82 (define (command-doc c) (procedure-documentation (command-procedure c)))
83
84 (define (make-command-info proc arguments-reader)
85 (cons proc arguments-reader))
86
87 (define (command-info-procedure info)
88 (car info))
89
90 (define (command-info-arguments-reader info)
91 (cdr info))
92
93 (define (command-usage c)
94 (let ((doc (command-doc c)))
95 (substring doc 0 (string-index doc #\newline))))
96
97 (define (command-summary c)
98 (let* ((doc (command-doc c))
99 (start (1+ (string-index doc #\newline))))
100 (cond ((string-index doc #\newline start)
101 => (lambda (end) (substring doc start end)))
102 (else (substring doc start)))))
103
104 (define (lookup-group name)
105 (assq name *command-table*))
106
107 (define* (lookup-command key #:optional (table *command-table*))
108 (let loop ((groups table) (commands '()))
109 (cond ((and (null? groups) (null? commands)) #f)
110 ((null? commands)
111 (loop (cdr groups) (cdar groups)))
112 ((memq key (car commands)) (car commands))
113 (else (loop groups (cdr commands))))))
114
115 (define* (display-group group #:optional (abbrev? #t))
116 (format #t "~:(~A~) Commands~:[~; [abbrev]~]:~2%" (group-name group) abbrev?)
117 (for-each (lambda (c)
118 (display-summary (command-usage c)
119 (if abbrev? (command-abbrevs c) '())
120 (command-summary c)))
121 (group-commands group))
122 (newline))
123
124 (define (display-command command)
125 (display "Usage: ")
126 (display (command-doc command))
127 (newline))
128
129 (define (display-summary usage abbrevs summary)
130 (let* ((usage-len (string-length usage))
131 (abbrevs (if (pair? abbrevs)
132 (format #f "[,~A~{ ,~A~}]" (car abbrevs) (cdr abbrevs))
133 ""))
134 (abbrevs-len (string-length abbrevs)))
135 (format #t " ,~A~A~A - ~A\n"
136 usage
137 (cond
138 ((> abbrevs-len 32)
139 (error "abbrevs too long" abbrevs))
140 ((> (+ usage-len abbrevs-len) 32)
141 (format #f "~%~v_" (+ 2 (- 32 abbrevs-len))))
142 (else
143 (format #f "~v_" (- 32 abbrevs-len usage-len))))
144 abbrevs
145 summary)))
146
147 (define (read-command repl)
148 (catch #t
149 (lambda () (read))
150 (lambda (key . args)
151 (pmatch args
152 ((,subr ,msg ,args . ,rest)
153 (format #t "Throw to key `~a' while reading command:\n" key)
154 (display-error #f (current-output-port) subr msg args rest))
155 (else
156 (format #t "Throw to key `~a' with args `~s' while reading command.\n"
157 key args)))
158 (force-output)
159 *unspecified*)))
160
161 (define (read-command-arguments c repl)
162 ((command-info-arguments-reader (command-info c)) repl))
163
164 (define (meta-command repl)
165 (let ((command (read-command repl)))
166 (cond
167 ((eq? command *unspecified*)) ; read error, already signalled; pass.
168 ((not (symbol? command))
169 (format #t "Meta-command not a symbol: ~s~%" command))
170 ((lookup-command command)
171 => (lambda (c)
172 (and=> (read-command-arguments c repl)
173 (lambda (args) (apply (command-procedure c) repl args)))))
174 (else
175 (format #t "Unknown meta command: ~A~%" command)))))
176
177 (define (add-meta-command! name category proc argument-reader)
178 (hashq-set! *command-infos* name (make-command-info proc argument-reader))
179 (if category
180 (let ((entry (assq category *command-table*)))
181 (if entry
182 (set-cdr! entry (append (cdr entry) (list (list name))))
183 (set! *command-table*
184 (append *command-table*
185 (list (list category (list name)))))))))
186
187 (define-syntax define-meta-command
188 (syntax-rules ()
189 ((_ ((name category) repl (expression0 ...) . datums) docstring b0 b1 ...)
190 (add-meta-command!
191 'name
192 'category
193 (lambda* (repl expression0 ... . datums)
194 docstring
195 b0 b1 ...)
196 (lambda (repl)
197 (define (handle-read-error form-name key args)
198 (pmatch args
199 ((,subr ,msg ,args . ,rest)
200 (format #t "Throw to key `~a' while reading ~@[argument `~A' of ~]command `~A':\n"
201 key form-name 'name)
202 (display-error #f (current-output-port) subr msg args rest))
203 (else
204 (format #t "Throw to key `~a' with args `~s' while reading ~@[ argument `~A' of ~]command `~A'.\n"
205 key args form-name 'name)))
206 (abort))
207 (% (let* ((expression0
208 (catch #t
209 (lambda ()
210 (repl-reader
211 ""
212 (lambda* (#:optional (port (current-input-port)))
213 ((language-reader (repl-language repl))
214 port (current-module)))))
215 (lambda (k . args)
216 (handle-read-error 'expression0 k args))))
217 ...)
218 (append
219 (list expression0 ...)
220 (catch #t
221 (lambda ()
222 (let ((port (open-input-string (read-line))))
223 (let lp ((out '()))
224 (let ((x (read port)))
225 (if (eof-object? x)
226 (reverse out)
227 (lp (cons x out)))))))
228 (lambda (k . args)
229 (handle-read-error #f k args)))))
230 (lambda (k) #f))))) ; the abort handler
231
232 ((_ ((name category) repl . datums) docstring b0 b1 ...)
233 (define-meta-command ((name category) repl () . datums)
234 docstring b0 b1 ...))
235
236 ((_ (name repl (expression0 ...) . datums) docstring b0 b1 ...)
237 (define-meta-command ((name #f) repl (expression0 ...) . datums)
238 docstring b0 b1 ...))
239
240 ((_ (name repl . datums) docstring b0 b1 ...)
241 (define-meta-command ((name #f) repl () . datums)
242 docstring b0 b1 ...))))
243
244
245 \f
246 ;;;
247 ;;; Help commands
248 ;;;
249
250 (define-meta-command (help repl . args)
251 "help [all | GROUP | [-c] COMMAND]
252 Show help.
253
254 With one argument, tries to look up the argument as a group name, giving
255 help on that group if successful. Otherwise tries to look up the
256 argument as a command, giving help on the command.
257
258 If there is a command whose name is also a group name, use the ,help
259 -c COMMAND form to give help on the command instead of the group.
260
261 Without any argument, a list of help commands and command groups
262 are displayed."
263 (pmatch args
264 (()
265 (display-group (lookup-group 'help))
266 (display "Command Groups:\n\n")
267 (display-summary "help all" #f "List all commands")
268 (for-each (lambda (g)
269 (let* ((name (symbol->string (group-name g)))
270 (usage (string-append "help " name))
271 (header (string-append "List " name " commands")))
272 (display-summary usage #f header)))
273 (cdr *command-table*))
274 (newline)
275 (display
276 "Type `,help -c COMMAND' to show documentation of a particular command.")
277 (newline))
278 ((all)
279 (for-each display-group *command-table*))
280 ((,group) (guard (lookup-group group))
281 (display-group (lookup-group group)))
282 ((,command) (guard (lookup-command command))
283 (display-command (lookup-command command)))
284 ((-c ,command) (guard (lookup-command command))
285 (display-command (lookup-command command)))
286 ((,command)
287 (format #t "Unknown command or group: ~A~%" command))
288 ((-c ,command)
289 (format #t "Unknown command: ~A~%" command))
290 (else
291 (format #t "Bad arguments: ~A~%" args))))
292
293 (define-meta-command (show repl . args)
294 "show [TOPIC]
295 Gives information about Guile.
296
297 With one argument, tries to show a particular piece of information;
298
299 currently supported topics are `warranty' (or `w'), `copying' (or `c'),
300 and `version' (or `v').
301
302 Without any argument, a list of topics is displayed."
303 (pmatch args
304 (()
305 (display-group (car *show-table*) #f)
306 (newline))
307 ((,topic) (guard (lookup-command topic *show-table*))
308 ((command-procedure (lookup-command topic *show-table*)) repl))
309 ((,command)
310 (format #t "Unknown topic: ~A~%" command))
311 (else
312 (format #t "Bad arguments: ~A~%" args))))
313
314 ;;; `warranty', `copying' and `version' are "hidden" meta-commands, only
315 ;;; accessible via `show'. They have an entry in *command-infos* but not
316 ;;; in *command-table*.
317
318 (define-meta-command (warranty repl)
319 "show warranty
320 Details on the lack of warranty."
321 (display *warranty*)
322 (newline))
323
324 (define-meta-command (copying repl)
325 "show copying
326 Show the LGPLv3."
327 (display *copying*)
328 (newline))
329
330 (define-meta-command (version repl)
331 "show version
332 Version information."
333 (display *version*)
334 (newline))
335
336 (define-meta-command (apropos repl regexp)
337 "apropos REGEXP
338 Find bindings/modules/packages."
339 (apropos (->string regexp)))
340
341 (define-meta-command (describe repl (form))
342 "describe OBJ
343 Show description/documentation."
344 (display (object-documentation (repl-eval repl (repl-parse repl form))))
345 (newline))
346
347 (define-meta-command (option repl . args)
348 "option [KEY VALUE]
349 List/show/set options."
350 (pmatch args
351 (()
352 (for-each (lambda (spec)
353 (format #t " ~A~24t~A\n" (car spec) (cadr spec)))
354 (repl-options repl)))
355 ((,key)
356 (display (repl-option-ref repl key))
357 (newline))
358 ((,key ,val)
359 (repl-option-set! repl key val))))
360
361 (define-meta-command (quit repl)
362 "quit
363 Quit this session."
364 (throw 'quit))
365
366 \f
367 ;;;
368 ;;; Module commands
369 ;;;
370
371 (define-meta-command (module repl . args)
372 "module [MODULE]
373 Change modules / Show current module."
374 (pmatch args
375 (() (puts (module-name (current-module))))
376 ((,mod-name) (guard (list? mod-name))
377 (set-current-module (resolve-module mod-name)))
378 (,mod-name (set-current-module (resolve-module mod-name)))))
379
380 (define-meta-command (import repl . args)
381 "import [MODULE ...]
382 Import modules / List those imported."
383 (let ()
384 (define (use name)
385 (let ((mod (resolve-interface name)))
386 (if mod
387 (module-use! (current-module) mod)
388 (format #t "No such module: ~A~%" name))))
389 (if (null? args)
390 (for-each puts (map module-name (module-uses (current-module))))
391 (for-each use args))))
392
393 (define-meta-command (load repl file)
394 "load FILE
395 Load a file in the current module."
396 (load (->string file)))
397
398 (define-meta-command (reload repl . args)
399 "reload [MODULE]
400 Reload the given module, or the current module if none was given."
401 (pmatch args
402 (() (reload-module (current-module)))
403 ((,mod-name) (guard (list? mod-name))
404 (reload-module (resolve-module mod-name)))
405 (,mod-name (reload-module (resolve-module mod-name)))))
406
407 (define-meta-command (binding repl)
408 "binding
409 List current bindings."
410 (module-for-each (lambda (k v) (format #t "~23A ~A\n" k v))
411 (current-module)))
412
413 (define-meta-command (in repl module command-or-expression . args)
414 "in MODULE COMMAND-OR-EXPRESSION
415 Evaluate an expression or command in the context of module."
416 (let ((m (resolve-module module #:ensure #f)))
417 (if m
418 (pmatch command-or-expression
419 (('unquote ,command) (guard (lookup-command command))
420 (save-module-excursion
421 (lambda ()
422 (set-current-module m)
423 (apply (command-procedure (lookup-command command)) repl args))))
424 (,expression
425 (guard (null? args))
426 (repl-print repl (eval expression m)))
427 (else
428 (format #t "Invalid arguments to `in': expected a single expression or a command.\n")))
429 (format #t "No such module: ~s\n" module))))
430
431 \f
432 ;;;
433 ;;; Language commands
434 ;;;
435
436 (define-meta-command (language repl name)
437 "language LANGUAGE
438 Change languages."
439 (let ((lang (lookup-language name))
440 (cur (repl-language repl)))
441 (format #t "Happy hacking with ~a! To switch back, type `,L ~a'.\n"
442 (language-title lang) (language-name cur))
443 (set! (repl-language repl) lang)))
444
445 \f
446 ;;;
447 ;;; Compile commands
448 ;;;
449
450 (define-meta-command (compile repl (form))
451 "compile EXP
452 Generate compiled code."
453 (let ((x (repl-compile repl (repl-parse repl form))))
454 (cond ((objcode? x) (guile:disassemble x))
455 (else (repl-print repl x)))))
456
457 (define-meta-command (compile-file repl file . opts)
458 "compile-file FILE
459 Compile a file."
460 (compile-file (->string file) #:opts opts))
461
462 (define (guile:disassemble x)
463 ((@ (language assembly disassemble) disassemble) x))
464
465 (define-meta-command (disassemble repl (form))
466 "disassemble EXP
467 Disassemble a compiled procedure."
468 (let ((obj (repl-eval repl (repl-parse repl form))))
469 (if (or (program? obj) (objcode? obj))
470 (guile:disassemble obj)
471 (format #t "Argument to ,disassemble not a procedure or objcode: ~a~%"
472 obj))))
473
474 (define-meta-command (disassemble-file repl file)
475 "disassemble-file FILE
476 Disassemble a file."
477 (guile:disassemble (load-objcode (->string file))))
478
479 \f
480 ;;;
481 ;;; Profile commands
482 ;;;
483
484 (define-meta-command (time repl (form))
485 "time EXP
486 Time execution."
487 (let* ((gc-start (gc-run-time))
488 (real-start (get-internal-real-time))
489 (run-start (get-internal-run-time))
490 (result (repl-eval repl (repl-parse repl form)))
491 (run-end (get-internal-run-time))
492 (real-end (get-internal-real-time))
493 (gc-end (gc-run-time)))
494 (define (diff start end)
495 (/ (- end start) 1.0 internal-time-units-per-second))
496 (repl-print repl result)
497 (format #t ";; ~,6Fs real time, ~,6Fs run time. ~,6Fs spent in GC.\n"
498 (diff real-start real-end)
499 (diff run-start run-end)
500 (diff gc-start gc-end))
501 result))
502
503 (define-meta-command (profile repl (form) . opts)
504 "profile EXP
505 Profile execution."
506 ;; FIXME opts
507 (apply statprof
508 (repl-prepare-eval-thunk repl (repl-parse repl form))
509 opts))
510
511 (define-meta-command (trace repl (form) . opts)
512 "trace EXP
513 Trace execution."
514 ;; FIXME: doc options, or somehow deal with them better
515 (apply call-with-trace
516 (repl-prepare-eval-thunk repl (repl-parse repl form))
517 opts))
518
519 \f
520 ;;;
521 ;;; Debug commands
522 ;;;
523
524 (define-syntax define-stack-command
525 (lambda (x)
526 (syntax-case x ()
527 ((_ (name repl . args) docstring body body* ...)
528 #`(define-meta-command (name repl . args)
529 docstring
530 (let ((debug (repl-debug repl)))
531 (if debug
532 (letrec-syntax
533 ((#,(datum->syntax #'repl 'frames)
534 (identifier-syntax (debug-frames debug)))
535 (#,(datum->syntax #'repl 'message)
536 (identifier-syntax (debug-error-message debug)))
537 (#,(datum->syntax #'repl 'for-trap?)
538 (identifier-syntax (debug-for-trap? debug)))
539 (#,(datum->syntax #'repl 'index)
540 (identifier-syntax
541 (id (debug-index debug))
542 ((set! id exp) (set! (debug-index debug) exp))))
543 (#,(datum->syntax #'repl 'cur)
544 (identifier-syntax
545 (vector-ref #,(datum->syntax #'repl 'frames)
546 #,(datum->syntax #'repl 'index)))))
547 body body* ...)
548 (format #t "Nothing to debug.~%"))))))))
549
550 (define-stack-command (backtrace repl #:optional count
551 #:key (width (terminal-width)) full?)
552 "backtrace [COUNT] [#:width W] [#:full? F]
553 Print a backtrace.
554
555 Print a backtrace of all stack frames, or innermost COUNT frames.
556 If COUNT is negative, the last COUNT frames will be shown."
557 (print-frames frames
558 #:count count
559 #:width width
560 #:full? full?
561 #:for-trap? for-trap?))
562
563 (define-stack-command (up repl #:optional (count 1))
564 "up [COUNT]
565 Select a calling stack frame.
566
567 Select and print stack frames that called this one.
568 An argument says how many frames up to go."
569 (cond
570 ((or (not (integer? count)) (<= count 0))
571 (format #t "Invalid argument to `up': expected a positive integer for COUNT.~%"))
572 ((>= (+ count index) (vector-length frames))
573 (cond
574 ((= index (1- (vector-length frames)))
575 (format #t "Already at outermost frame.\n"))
576 (else
577 (set! index (1- (vector-length frames)))
578 (print-frame cur #:index index
579 #:next-source? (and (zero? index) for-trap?)))))
580 (else
581 (set! index (+ count index))
582 (print-frame cur #:index index
583 #:next-source? (and (zero? index) for-trap?)))))
584
585 (define-stack-command (down repl #:optional (count 1))
586 "down [COUNT]
587 Select a called stack frame.
588
589 Select and print stack frames called by this one.
590 An argument says how many frames down to go."
591 (cond
592 ((or (not (integer? count)) (<= count 0))
593 (format #t "Invalid argument to `down': expected a positive integer for COUNT.~%"))
594 ((< (- index count) 0)
595 (cond
596 ((zero? index)
597 (format #t "Already at innermost frame.\n"))
598 (else
599 (set! index 0)
600 (print-frame cur #:index index #:next-source? for-trap?))))
601 (else
602 (set! index (- index count))
603 (print-frame cur #:index index
604 #:next-source? (and (zero? index) for-trap?)))))
605
606 (define-stack-command (frame repl #:optional idx)
607 "frame [IDX]
608 Show a frame.
609
610 Show the selected frame.
611 With an argument, select a frame by index, then show it."
612 (cond
613 (idx
614 (cond
615 ((or (not (integer? idx)) (< idx 0))
616 (format #t "Invalid argument to `frame': expected a non-negative integer for IDX.~%"))
617 ((< idx (vector-length frames))
618 (set! index idx)
619 (print-frame cur #:index index
620 #:next-source? (and (zero? index) for-trap?)))
621 (else
622 (format #t "No such frame.~%"))))
623 (else (print-frame cur #:index index
624 #:next-source? (and (zero? index) for-trap?)))))
625
626 (define-stack-command (procedure repl)
627 "procedure
628 Print the procedure for the selected frame."
629 (repl-print repl (frame-procedure cur)))
630
631 (define-stack-command (locals repl #:key (width (terminal-width)))
632 "locals
633 Show local variables.
634
635 Show locally-bound variables in the selected frame."
636 (print-locals cur #:width width))
637
638 (define-stack-command (error-message repl)
639 "error-message
640 Show error message.
641
642 Display the message associated with the error that started the current
643 debugging REPL."
644 (format #t "~a~%" (if (string? message) message "No error message")))
645
646 (define-meta-command (break repl (form))
647 "break PROCEDURE
648 Break on calls to PROCEDURE.
649
650 Starts a recursive prompt when PROCEDURE is called."
651 (let ((proc (repl-eval repl (repl-parse repl form))))
652 (if (not (procedure? proc))
653 (error "Not a procedure: ~a" proc)
654 (let ((idx (add-trap-at-procedure-call! proc)))
655 (format #t "Trap ~a: ~a.~%" idx (trap-name idx))))))
656
657 (define-meta-command (break-at-source repl file line)
658 "break-at-source FILE LINE
659 Break when control reaches the given source location.
660
661 Starts a recursive prompt when control reaches line LINE of file FILE.
662 Note that the given source location must be inside a procedure."
663 (let ((file (if (symbol? file) (symbol->string file) file)))
664 (let ((idx (add-trap-at-source-location! file line)))
665 (format #t "Trap ~a: ~a.~%" idx (trap-name idx)))))
666
667 (define (repl-pop-continuation-resumer repl msg)
668 ;; Capture the dynamic environment with this prompt thing. The
669 ;; result is a procedure that takes a frame.
670 (% (call-with-values
671 (lambda ()
672 (abort
673 (lambda (k)
674 ;; Call frame->stack-vector before reinstating the
675 ;; continuation, so that we catch the %stacks fluid at
676 ;; the time of capture.
677 (lambda (frame)
678 (k frame
679 (frame->stack-vector
680 (frame-previous frame)))))))
681 (lambda (from stack)
682 (format #t "~a~%" msg)
683 (let ((vals (frame-return-values from)))
684 (if (null? vals)
685 (format #t "No return values.~%")
686 (begin
687 (format #t "Return values:~%")
688 (for-each (lambda (x) (repl-print repl x)) vals))))
689 ((module-ref (resolve-interface '(system repl repl)) 'start-repl)
690 #:debug (make-debug stack 0 msg #t))))))
691
692 (define-stack-command (finish repl)
693 "finish
694 Run until the current frame finishes.
695
696 Resume execution, breaking when the current frame finishes."
697 (let ((handler (repl-pop-continuation-resumer
698 repl (format #f "Return from ~a" cur))))
699 (add-ephemeral-trap-at-frame-finish! cur handler)
700 (throw 'quit)))
701
702 (define (repl-next-resumer msg)
703 ;; Capture the dynamic environment with this prompt thing. The
704 ;; result is a procedure that takes a frame.
705 (% (let ((stack (abort
706 (lambda (k)
707 ;; Call frame->stack-vector before reinstating the
708 ;; continuation, so that we catch the %stacks fluid
709 ;; at the time of capture.
710 (lambda (frame)
711 (k (frame->stack-vector frame)))))))
712 (format #t "~a~%" msg)
713 ((module-ref (resolve-interface '(system repl repl)) 'start-repl)
714 #:debug (make-debug stack 0 msg #t)))))
715
716 (define-stack-command (step repl)
717 "step
718 Step until control reaches a different source location.
719
720 Step until control reaches a different source location."
721 (let ((msg (format #f "Step into ~a" cur)))
722 (add-ephemeral-stepping-trap! cur (repl-next-resumer msg)
723 #:into? #t #:instruction? #f)
724 (throw 'quit)))
725
726 (define-stack-command (step-instruction repl)
727 "step-instruction
728 Step until control reaches a different instruction.
729
730 Step until control reaches a different VM instruction."
731 (let ((msg (format #f "Step into ~a" cur)))
732 (add-ephemeral-stepping-trap! cur (repl-next-resumer msg)
733 #:into? #t #:instruction? #t)
734 (throw 'quit)))
735
736 (define-stack-command (next repl)
737 "next
738 Step until control reaches a different source location in the current frame.
739
740 Step until control reaches a different source location in the current frame."
741 (let ((msg (format #f "Step into ~a" cur)))
742 (add-ephemeral-stepping-trap! cur (repl-next-resumer msg)
743 #:into? #f #:instruction? #f)
744 (throw 'quit)))
745
746 (define-stack-command (next-instruction repl)
747 "next-instruction
748 Step until control reaches a different instruction in the current frame.
749
750 Step until control reaches a different VM instruction in the current frame."
751 (let ((msg (format #f "Step into ~a" cur)))
752 (add-ephemeral-stepping-trap! cur (repl-next-resumer msg)
753 #:into? #f #:instruction? #t)
754 (throw 'quit)))
755
756 (define-meta-command (tracepoint repl (form))
757 "tracepoint PROCEDURE
758 Add a tracepoint to PROCEDURE.
759
760 A tracepoint will print out the procedure and its arguments, when it is
761 called, and its return value(s) when it returns."
762 (let ((proc (repl-eval repl (repl-parse repl form))))
763 (if (not (procedure? proc))
764 (error "Not a procedure: ~a" proc)
765 (let ((idx (add-trace-at-procedure-call! proc)))
766 (format #t "Trap ~a: ~a.~%" idx (trap-name idx))))))
767
768 (define-meta-command (traps repl)
769 "traps
770 Show the set of currently attached traps.
771
772 Show the set of currently attached traps (breakpoints and tracepoints)."
773 (let ((traps (list-traps)))
774 (if (null? traps)
775 (format #t "No traps set.~%")
776 (for-each (lambda (idx)
777 (format #t " ~a: ~a~a~%"
778 idx (trap-name idx)
779 (if (trap-enabled? idx) "" " (disabled)")))
780 traps))))
781
782 (define-meta-command (delete repl idx)
783 "delete IDX
784 Delete a trap.
785
786 Delete a trap."
787 (if (not (integer? idx))
788 (error "expected a trap index (a non-negative integer)" idx)
789 (delete-trap! idx)))
790
791 (define-meta-command (disable repl idx)
792 "disable IDX
793 Disable a trap.
794
795 Disable a trap."
796 (if (not (integer? idx))
797 (error "expected a trap index (a non-negative integer)" idx)
798 (disable-trap! idx)))
799
800 (define-meta-command (enable repl idx)
801 "enable IDX
802 Enable a trap.
803
804 Enable a trap."
805 (if (not (integer? idx))
806 (error "expected a trap index (a non-negative integer)" idx)
807 (enable-trap! idx)))
808
809 (define-stack-command (registers repl)
810 "registers
811 Print registers.
812
813 Print the registers of the current frame."
814 (print-registers cur))
815
816 (define-meta-command (width repl #:optional x)
817 "width [X]
818 Set debug output width.
819
820 Set the number of screen columns in the output from `backtrace' and
821 `locals'."
822 (terminal-width x)
823 (format #t "Set screen width to ~a columns.~%" (terminal-width)))
824
825
826 \f
827 ;;;
828 ;;; Inspection commands
829 ;;;
830
831 (define-meta-command (inspect repl (form))
832 "inspect EXP
833 Inspect the result(s) of evaluating EXP."
834 (call-with-values (repl-prepare-eval-thunk repl (repl-parse repl form))
835 (lambda args
836 (for-each %inspect args))))
837
838 (define-meta-command (pretty-print repl (form))
839 "pretty-print EXP
840 Pretty-print the result(s) of evaluating EXP."
841 (call-with-values (repl-prepare-eval-thunk repl (repl-parse repl form))
842 (lambda args
843 (for-each
844 (lambda (x)
845 (run-hook before-print-hook x)
846 (pp x))
847 args))))
848
849 \f
850 ;;;
851 ;;; System commands
852 ;;;
853
854 (define-meta-command (gc repl)
855 "gc
856 Garbage collection."
857 (gc))
858
859 (define-meta-command (statistics repl)
860 "statistics
861 Display statistics."
862 (let ((this-tms (times))
863 (this-gcs (gc-stats))
864 (last-tms (repl-tm-stats repl))
865 (last-gcs (repl-gc-stats repl)))
866 ;; GC times
867 (let ((this-times (assq-ref this-gcs 'gc-times))
868 (last-times (assq-ref last-gcs 'gc-times)))
869 (display-diff-stat "GC times:" #t this-times last-times "times")
870 (newline))
871 ;; Memory size
872 (let ((this-heap (assq-ref this-gcs 'heap-size))
873 (this-free (assq-ref this-gcs 'heap-free-size)))
874 (display-stat-title "Memory size:" "current" "limit")
875 (display-stat "heap" #f (- this-heap this-free) this-heap "bytes")
876 (newline))
877 ;; Cells collected
878 (let ((this-alloc (assq-ref this-gcs 'heap-total-allocated))
879 (last-alloc (assq-ref last-gcs 'heap-total-allocated)))
880 (display-stat-title "Bytes allocated:" "diff" "total")
881 (display-diff-stat "allocated" #f this-alloc last-alloc "bytes")
882 (newline))
883 ;; GC time taken
884 (let ((this-total (assq-ref this-gcs 'gc-time-taken))
885 (last-total (assq-ref last-gcs 'gc-time-taken)))
886 (display-stat-title "GC time taken:" "diff" "total")
887 (display-time-stat "total" this-total last-total)
888 (newline))
889 ;; Process time spent
890 (let ((this-utime (tms:utime this-tms))
891 (last-utime (tms:utime last-tms))
892 (this-stime (tms:stime this-tms))
893 (last-stime (tms:stime last-tms))
894 (this-cutime (tms:cutime this-tms))
895 (last-cutime (tms:cutime last-tms))
896 (this-cstime (tms:cstime this-tms))
897 (last-cstime (tms:cstime last-tms)))
898 (display-stat-title "Process time spent:" "diff" "total")
899 (display-time-stat "user" this-utime last-utime)
900 (display-time-stat "system" this-stime last-stime)
901 (display-time-stat "child user" this-cutime last-cutime)
902 (display-time-stat "child system" this-cstime last-cstime)
903 (newline))
904 ;; Save statistics
905 ;; Save statistics
906 (set! (repl-tm-stats repl) this-tms)
907 (set! (repl-gc-stats repl) this-gcs)))
908
909 (define (display-stat title flag field1 field2 unit)
910 (let ((fmt (format #f "~~20~AA ~~10@A /~~10@A ~~A~~%" (if flag "" "@"))))
911 (format #t fmt title field1 field2 unit)))
912
913 (define (display-stat-title title field1 field2)
914 (display-stat title #t field1 field2 ""))
915
916 (define (display-diff-stat title flag this last unit)
917 (display-stat title flag (- this last) this unit))
918
919 (define (display-time-stat title this last)
920 (define (conv num)
921 (format #f "~10,2F" (exact->inexact (/ num internal-time-units-per-second))))
922 (display-stat title #f (conv (- this last)) (conv this) "s"))
923
924 (define (display-mips-stat title this-time this-clock last-time last-clock)
925 (define (mips time clock)
926 (if (= time 0) "----" (format #f "~10,2F" (/ clock time 1000000.0))))
927 (display-stat title #f
928 (mips (- this-time last-time) (- this-clock last-clock))
929 (mips this-time this-clock) "mips"))