summaryrefslogtreecommitdiff
path: root/module/system/repl/command.scm
diff options
context:
space:
mode:
Diffstat (limited to 'module/system/repl/command.scm')
-rw-r--r--module/system/repl/command.scm502
1 files changed, 502 insertions, 0 deletions
diff --git a/module/system/repl/command.scm b/module/system/repl/command.scm
new file mode 100644
index 000000000..a99e1bae9
--- /dev/null
+++ b/module/system/repl/command.scm
@@ -0,0 +1,502 @@
+;;; Repl commands
+
+;; Copyright (C) 2001, 2009 Free Software Foundation, Inc.
+
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 3 of the License, or (at your option) any later version.
+;;
+;; This library is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301 USA
+
+;;; Code:
+
+(define-module (system repl command)
+ #:use-module (system base syntax)
+ #:use-module (system base pmatch)
+ #:use-module (system base compile)
+ #:use-module (system repl common)
+ #:use-module (system vm objcode)
+ #:use-module (system vm program)
+ #:use-module (system vm vm)
+ #:autoload (system base language) (lookup-language language-reader)
+ #:autoload (system vm debug) (vm-debugger vm-backtrace)
+ #:autoload (system vm trace) (vm-trace vm-trace-on vm-trace-off)
+ #:autoload (system vm profile) (vm-profile)
+ #:use-module (ice-9 format)
+ #:use-module (ice-9 session)
+ #:use-module (ice-9 documentation)
+ #:use-module (ice-9 and-let-star)
+ #:use-module (ice-9 rdelim)
+ #:export (meta-command))
+
+
+;;;
+;;; Meta command interface
+;;;
+
+(define *command-table*
+ '((help (help h) (apropos a) (describe d) (option o) (quit q))
+ (module (module m) (import i) (load l) (binding b))
+ (language (language L))
+ (compile (compile c) (compile-file cc)
+ (disassemble x) (disassemble-file xx))
+ (profile (time t) (profile pr))
+ (debug (backtrace bt) (debugger db) (trace tr) (step st))
+ (system (gc) (statistics stat))))
+
+(define (group-name g) (car g))
+(define (group-commands g) (cdr g))
+
+;; Hack, until core can be extended.
+(define procedure-documentation
+ (let ((old-definition procedure-documentation))
+ (lambda (p)
+ (if (program? p)
+ (program-documentation p)
+ (old-definition p)))))
+
+(define *command-module* (current-module))
+(define (command-name c) (car c))
+(define (command-abbrev c) (if (null? (cdr c)) #f (cadr c)))
+(define (command-procedure c) (module-ref *command-module* (command-name c)))
+(define (command-doc c) (procedure-documentation (command-procedure c)))
+
+(define (command-usage c)
+ (let ((doc (command-doc c)))
+ (substring doc 0 (string-index doc #\newline))))
+
+(define (command-summary c)
+ (let* ((doc (command-doc c))
+ (start (1+ (string-index doc #\newline))))
+ (cond ((string-index doc #\newline start)
+ => (lambda (end) (substring doc start end)))
+ (else (substring doc start)))))
+
+(define (lookup-group name)
+ (assq name *command-table*))
+
+(define (lookup-command key)
+ (let loop ((groups *command-table*) (commands '()))
+ (cond ((and (null? groups) (null? commands)) #f)
+ ((null? commands)
+ (loop (cdr groups) (cdar groups)))
+ ((memq key (car commands)) (car commands))
+ (else (loop groups (cdr commands))))))
+
+(define (display-group group . opts)
+ (format #t "~:(~A~) Commands [abbrev]:~2%" (group-name group))
+ (for-each (lambda (c)
+ (display-summary (command-usage c)
+ (command-abbrev c)
+ (command-summary c)))
+ (group-commands group))
+ (newline))
+
+(define (display-command command)
+ (display "Usage: ")
+ (display (command-doc command))
+ (newline))
+
+(define (display-summary usage abbrev summary)
+ (let ((abbrev (if abbrev (format #f "[,~A]" abbrev) "")))
+ (format #t " ,~24A ~8@A - ~A\n" usage abbrev summary)))
+
+(define (read-datum repl)
+ (read))
+
+(define read-line
+ (let ((orig-read-line read-line))
+ (lambda (repl)
+ (orig-read-line))))
+
+(define (meta-command repl)
+ (let ((command (read-datum repl)))
+ (if (not (symbol? command))
+ (user-error "Meta-command not a symbol: ~s" command))
+ (let ((c (lookup-command command)))
+ (if c
+ ((command-procedure c) repl)
+ (user-error "Unknown meta command: ~A" command)))))
+
+(define-syntax define-meta-command
+ (syntax-rules ()
+ ((_ (name repl (expression0 ...) . datums) docstring b0 b1 ...)
+ (define (name repl)
+ docstring
+ (let* ((expression0
+ (with-fluid* current-reader
+ (language-reader (repl-language repl))
+ (lambda () (repl-reader ""))))
+ ...)
+ (apply (lambda datums b0 b1 ...)
+ (let ((port (open-input-string (read-line repl))))
+ (let lp ((out '()))
+ (let ((x (read port)))
+ (if (eof-object? x)
+ (reverse out)
+ (lp (cons x out))))))))))
+ ((_ (name repl . datums) docstring b0 b1 ...)
+ (define-meta-command (name repl () . datums)
+ docstring b0 b1 ...))))
+
+
+
+;;;
+;;; Help commands
+;;;
+
+(define-meta-command (help repl . args)
+ "help
+help GROUP
+help [-c] COMMAND
+
+Gives help on the meta-commands available at the REPL.
+
+With one argument, tries to look up the argument as a group name, giving
+help on that group if successful. Otherwise tries to look up the
+argument as a command, giving help on the command.
+
+If there is a command whose name is also a group name, use the ,help
+-c COMMAND form to give help on the command instead of the group.
+
+Without any argument, a list of help commands and command groups
+are displayed."
+ (pmatch args
+ (()
+ (display-group (lookup-group 'help))
+ (display "Command Groups:\n\n")
+ (display-summary "help all" #f "List all commands")
+ (for-each (lambda (g)
+ (let* ((name (symbol->string (group-name g)))
+ (usage (string-append "help " name))
+ (header (string-append "List " name " commands")))
+ (display-summary usage #f header)))
+ (cdr *command-table*))
+ (newline)
+ (display "Type `,COMMAND -h' to show documentation of each command.")
+ (newline))
+ ((all)
+ (for-each display-group *command-table*))
+ ((,group) (guard (lookup-group group))
+ (display-group (lookup-group group)))
+ ((,command) (guard (lookup-command command))
+ (display-command (lookup-command command)))
+ ((-c ,command) (guard (lookup-command command))
+ (display-command (lookup-command command)))
+ ((,command)
+ (user-error "Unknown command or group: ~A" command))
+ ((-c ,command)
+ (user-error "Unknown command: ~A" command))
+ (else
+ (user-error "Bad arguments: ~A" args))))
+
+(define guile:apropos apropos)
+(define-meta-command (apropos repl regexp)
+ "apropos REGEXP
+Find bindings/modules/packages."
+ (guile:apropos (->string regexp)))
+
+(define-meta-command (describe repl (form))
+ "describe OBJ
+Show description/documentation."
+ (display (object-documentation (repl-eval repl (repl-parse repl form))))
+ (newline))
+
+(define-meta-command (option repl . args)
+ "option [KEY VALUE]
+List/show/set options."
+ (pmatch args
+ (()
+ (for-each (lambda (key+val)
+ (format #t "~A\t~A\n" (car key+val) (cdr key+val)))
+ (repl-options repl)))
+ ((,key)
+ (display (repl-option-ref repl key))
+ (newline))
+ ((,key ,val)
+ (repl-option-set! repl key val)
+ (case key
+ ((trace)
+ (let ((vm (repl-vm repl)))
+ (if val
+ (apply vm-trace-on vm val)
+ (vm-trace-off vm))))))))
+
+(define-meta-command (quit repl)
+ "quit
+Quit this session."
+ (throw 'quit))
+
+
+;;;
+;;; Module commands
+;;;
+
+(define-meta-command (module repl . args)
+ "module [MODULE]
+Change modules / Show current module."
+ (pmatch args
+ (() (puts (module-name (current-module))))
+ ((,mod-name) (guard (list? mod-name))
+ (set-current-module (resolve-module mod-name)))
+ (,mod-name (set-current-module (resolve-module mod-name)))))
+
+(define-meta-command (import repl . args)
+ "import [MODULE ...]
+Import modules / List those imported."
+ (let ()
+ (define (use name)
+ (let ((mod (resolve-interface name)))
+ (if mod
+ (module-use! (current-module) mod)
+ (user-error "No such module: ~A" name))))
+ (if (null? args)
+ (for-each puts (map module-name (module-uses (current-module))))
+ (for-each use args))))
+
+(define-meta-command (load repl file . opts)
+ "load FILE
+Load a file in the current module.
+
+ -f Load source file (see `compile')"
+ (let* ((file (->string file))
+ (objcode (if (memq #:f opts)
+ (apply load-source-file file opts)
+ (apply load-file file opts))))
+ (vm-load (repl-vm repl) objcode)))
+
+(define-meta-command (binding repl)
+ "binding
+List current bindings."
+ (module-for-each (lambda (k v) (format #t "~23A ~A\n" k v))
+ (current-module)))
+
+
+;;;
+;;; Language commands
+;;;
+
+(define-meta-command (language repl name)
+ "language LANGUAGE
+Change languages."
+ (set! (repl-language repl) (lookup-language name))
+ (repl-welcome repl))
+
+
+;;;
+;;; Compile commands
+;;;
+
+(define-meta-command (compile repl (form) . opts)
+ "compile FORM
+Generate compiled code.
+
+ -e Stop after expanding syntax/macro
+ -t Stop after translating into GHIL
+ -c Stop after generating GLIL
+
+ -O Enable optimization
+ -D Add debug information"
+ (let ((x (apply repl-compile repl (repl-parse repl form) opts)))
+ (cond ((objcode? x) (guile:disassemble x))
+ (else (repl-print repl x)))))
+
+(define guile:compile-file compile-file)
+(define-meta-command (compile-file repl file . opts)
+ "compile-file FILE
+Compile a file."
+ (guile:compile-file (->string file) #:opts opts))
+
+(define (guile:disassemble x)
+ ((@ (language assembly disassemble) disassemble) x))
+
+(define-meta-command (disassemble repl (form))
+ "disassemble PROGRAM
+Disassemble a program."
+ (guile:disassemble (repl-eval repl (repl-parse repl form))))
+
+(define-meta-command (disassemble-file repl file)
+ "disassemble-file FILE
+Disassemble a file."
+ (guile:disassemble (load-objcode (->string file))))
+
+
+;;;
+;;; Profile commands
+;;;
+
+(define-meta-command (time repl (form))
+ "time FORM
+Time execution."
+ (let* ((vms-start (vm-stats (repl-vm repl)))
+ (gc-start (gc-run-time))
+ (tms-start (times))
+ (result (repl-eval repl (repl-parse repl form)))
+ (tms-end (times))
+ (gc-end (gc-run-time))
+ (vms-end (vm-stats (repl-vm repl))))
+ (define (get proc start end)
+ (exact->inexact (/ (- (proc end) (proc start)) internal-time-units-per-second)))
+ (repl-print repl result)
+ (display "clock utime stime cutime cstime gctime\n")
+ (format #t "~5,2F ~5,2F ~5,2F ~6,2F ~6,2F ~6,2F\n"
+ (get tms:clock tms-start tms-end)
+ (get tms:utime tms-start tms-end)
+ (get tms:stime tms-start tms-end)
+ (get tms:cutime tms-start tms-end)
+ (get tms:cstime tms-start tms-end)
+ (get identity gc-start gc-end))
+ result))
+
+(define-meta-command (profile repl form . opts)
+ "profile FORM
+Profile execution."
+ (apply vm-profile
+ (repl-vm repl)
+ (repl-compile repl (repl-parse repl form))
+ opts))
+
+
+;;;
+;;; Debug commands
+;;;
+
+(define-meta-command (backtrace repl)
+ "backtrace
+Display backtrace."
+ (vm-backtrace (repl-vm repl)))
+
+(define-meta-command (debugger repl)
+ "debugger
+Start debugger."
+ (vm-debugger (repl-vm repl)))
+
+(define-meta-command (trace repl form . opts)
+ "trace FORM
+Trace execution.
+
+ -s Display stack
+ -l Display local variables
+ -b Bytecode level trace"
+ (apply vm-trace (repl-vm repl)
+ (repl-compile repl (repl-parse repl form))
+ opts))
+
+(define-meta-command (step repl)
+ "step FORM
+Step execution."
+ (display "Not implemented yet\n"))
+
+
+;;;
+;;; System commands
+;;;
+
+(define guile:gc gc)
+(define-meta-command (gc repl)
+ "gc
+Garbage collection."
+ (guile:gc))
+
+(define-meta-command (statistics repl)
+ "statistics
+Display statistics."
+ (let ((this-tms (times))
+ (this-vms (vm-stats (repl-vm repl)))
+ (this-gcs (gc-stats))
+ (last-tms (repl-tm-stats repl))
+ (last-vms (repl-vm-stats repl))
+ (last-gcs (repl-gc-stats repl)))
+ ;; GC times
+ (let ((this-times (assq-ref this-gcs 'gc-times))
+ (last-times (assq-ref last-gcs 'gc-times)))
+ (display-diff-stat "GC times:" #t this-times last-times "times")
+ (newline))
+ ;; Memory size
+ (let ((this-cells (assq-ref this-gcs 'cells-allocated))
+ (this-heap (assq-ref this-gcs 'cell-heap-size))
+ (this-bytes (assq-ref this-gcs 'bytes-malloced))
+ (this-malloc (assq-ref this-gcs 'gc-malloc-threshold)))
+ (display-stat-title "Memory size:" "current" "limit")
+ (display-stat "heap" #f this-cells this-heap "cells")
+ (display-stat "malloc" #f this-bytes this-malloc "bytes")
+ (newline))
+ ;; Cells collected
+ (let ((this-marked (assq-ref this-gcs 'cells-marked))
+ (last-marked (assq-ref last-gcs 'cells-marked))
+ (this-swept (assq-ref this-gcs 'cells-swept))
+ (last-swept (assq-ref last-gcs 'cells-swept)))
+ (display-stat-title "Cells collected:" "diff" "total")
+ (display-diff-stat "marked" #f this-marked last-marked "cells")
+ (display-diff-stat "swept" #f this-swept last-swept "cells")
+ (newline))
+ ;; GC time taken
+ (let ((this-mark (assq-ref this-gcs 'gc-mark-time-taken))
+ (last-mark (assq-ref last-gcs 'gc-mark-time-taken))
+ (this-total (assq-ref this-gcs 'gc-time-taken))
+ (last-total (assq-ref last-gcs 'gc-time-taken)))
+ (display-stat-title "GC time taken:" "diff" "total")
+ (display-time-stat "mark" this-mark last-mark)
+ (display-time-stat "total" this-total last-total)
+ (newline))
+ ;; Process time spent
+ (let ((this-utime (tms:utime this-tms))
+ (last-utime (tms:utime last-tms))
+ (this-stime (tms:stime this-tms))
+ (last-stime (tms:stime last-tms))
+ (this-cutime (tms:cutime this-tms))
+ (last-cutime (tms:cutime last-tms))
+ (this-cstime (tms:cstime this-tms))
+ (last-cstime (tms:cstime last-tms)))
+ (display-stat-title "Process time spent:" "diff" "total")
+ (display-time-stat "user" this-utime last-utime)
+ (display-time-stat "system" this-stime last-stime)
+ (display-time-stat "child user" this-cutime last-cutime)
+ (display-time-stat "child system" this-cstime last-cstime)
+ (newline))
+ ;; VM statistics
+ (let ((this-time (vms:time this-vms))
+ (last-time (vms:time last-vms))
+ (this-clock (vms:clock this-vms))
+ (last-clock (vms:clock last-vms)))
+ (display-stat-title "VM statistics:" "diff" "total")
+ (display-time-stat "time spent" this-time last-time)
+ (display-diff-stat "bogoclock" #f this-clock last-clock "clock")
+ (display-mips-stat "bogomips" this-time this-clock last-time last-clock)
+ (newline))
+ ;; Save statistics
+ ;; Save statistics
+ (set! (repl-tm-stats repl) this-tms)
+ (set! (repl-vm-stats repl) this-vms)
+ (set! (repl-gc-stats repl) this-gcs)))
+
+(define (display-stat title flag field1 field2 unit)
+ (let ((str (format #f "~~20~AA ~~10@A /~~10@A ~~A~~%" (if flag "" "@"))))
+ (format #t str title field1 field2 unit)))
+
+(define (display-stat-title title field1 field2)
+ (display-stat title #t field1 field2 ""))
+
+(define (display-diff-stat title flag this last unit)
+ (display-stat title flag (- this last) this unit))
+
+(define (display-time-stat title this last)
+ (define (conv num)
+ (format #f "~10,2F" (exact->inexact (/ num internal-time-units-per-second))))
+ (display-stat title #f (conv (- this last)) (conv this) "s"))
+
+(define (display-mips-stat title this-time this-clock last-time last-clock)
+ (define (mips time clock)
+ (if (= time 0) "----" (format #f "~10,2F" (/ clock time 1000000.0))))
+ (display-stat title #f
+ (mips (- this-time last-time) (- this-clock last-clock))
+ (mips this-time this-clock) "mips"))