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