Update copyright.
[bpt/guile.git] / ice-9 / session.scm
CommitLineData
13ae9151 1;;;; Copyright (C) 1997, 2000 Free Software Foundation, Inc.
0e81dabd
MD
2;;;;
3;;;; This program is free software; you can redistribute it and/or modify
4;;;; it under the terms of the GNU General Public License as published by
5;;;; the Free Software Foundation; either version 2, or (at your option)
6;;;; any later version.
7;;;;
8;;;; This program is distributed in the hope that it will be useful,
9;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
10;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11;;;; GNU General Public License for more details.
12;;;;
13;;;; You should have received a copy of the GNU General Public License
14;;;; along with this software; see the file COPYING. If not, write to
c6e23ea2
JB
15;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16;;;; Boston, MA 02111-1307 USA
0e81dabd
MD
17;;;;
18\f
19
bbefd480 20(define-module (ice-9 session)
3bdca000 21 :use-module (ice-9 documentation)
3510b484 22 :use-module (ice-9 regex)
3bdca000 23 )
0e81dabd
MD
24
25\f
26
13ae9151
MD
27;;; Documentation
28;;;
29(define-public help
30 (procedure->syntax
31 (lambda (exp env)
32 "(help [NAME])
33Prints useful information. Try `(help)'."
9f0eee46
MD
34 (cond ((not (= (length exp) 2))
35 (help-usage))
36 ((not (feature? 'regex))
37 (display "`help' depends on the `regex' feature.
38You don't seem to have regular expressions installed.\n"))
39 (else
40 (let ((name (cadr exp)))
41 (cond ((symbol? name)
42 (help-doc name
43 (string-append "^"
3510b484
MD
44 (regexp-quote
45 (symbol->string name))
9f0eee46
MD
46 "$")))
47 ((string? name)
48 (help-doc name name))
49 ((and (list? name)
50 (= (length name) 2)
51 (eq? (car name) 'unquote))
52 (let ((doc (object-documentation (local-eval (cadr name)
53 env))))
54 (if (not doc)
55 (simple-format #t "No documentation found for ~S\n"
56 (cadr name))
57 (write-line doc))))
58 (else
59 (help-usage)))
60 *unspecified*))))))
13ae9151 61
3bdca000
MD
62(define (help-doc term regexp)
63 (let ((entries (apropos-fold (lambda (module name object data)
64 (cons (list module
65 name
db611983
NJ
66 (object-documentation object)
67 (cond ((closure? object)
68 "a procedure")
69 ((procedure? object)
70 "a primitive procedure")
71 (else
72 "an object")))
3bdca000
MD
73 data))
74 '()
75 regexp
76 apropos-fold-exported))
77 (module car)
78 (name cadr)
db611983
NJ
79 (doc caddr)
80 (type cadddr))
3bdca000
MD
81 (if (null? entries)
82 ;; no matches
83 (begin
84 (display "Did not find any object ")
85 (simple-format #t
86 (if (symbol? term)
87 "named `~A'\n"
88 "matching regexp \"~A\"\n")
89 term))
db611983
NJ
90 (let ((first? #t)
91 (undocumented-entries '())
92 (documented-entries '())
93 (documentations '()))
94
95 (for-each (lambda (entry)
96 (let ((entry-summary (simple-format #f
97 "~S: ~S\n"
98 (module-name (module entry))
99 (name entry))))
100 (if (doc entry)
101 (begin
102 (set! documented-entries
103 (cons entry-summary documented-entries))
104 ;; *fixme*: Use `describe' when we have GOOPS?
105 (set! documentations
106 (cons (simple-format #f
107 "`~S' is ~A in the ~S module.\n\n~A\n"
108 (name entry)
109 (type entry)
110 (module-name (module entry))
111 (doc entry))
112 documentations)))
113 (set! undocumented-entries
114 (cons entry-summary undocumented-entries)))))
115 entries)
116
117 (if (and (not (null? documented-entries))
118 (or (> (length documented-entries) 1)
119 (not (null? undocumented-entries))))
120 (begin
121 (display "Documentation found for:\n")
122 (for-each (lambda (entry) (display entry)) documented-entries)
123 (set! first? #f)))
124
125 (for-each (lambda (entry)
126 (if first?
127 (set! first? #f)
128 (newline))
129 (display entry))
130 documentations)
131
132 (if (not (null? undocumented-entries))
3bdca000 133 (begin
db611983
NJ
134 (if first?
135 (set! first? #f)
136 (newline))
137 (display "No documentation found for:\n")
138 (for-each (lambda (entry) (display entry)) undocumented-entries)))))))
3bdca000 139
13ae9151 140(define (help-usage)
3bdca000
MD
141 (display "Usage: (help NAME) gives documentation about objects named NAME (a symbol)
142 (help REGEXP) ditto for objects with names matching REGEXP (a string)
d1c50f73 143 (help ,EXPR) gives documentation for object returned by EXPR
13ae9151
MD
144 (help) gives this text
145
3bdca000
MD
146`help' searches among bindings exported from loaded modules, while
147`apropos' searches among bindings visible from the \"current\" module.
148
2f52380c
MD
149Examples: (help help)
150 (help cons)
3bdca000 151 (help \"output-string\")
13ae9151
MD
152
153Other useful sources of helpful information:
154
155(apropos STRING)
156(arity PROCEDURE)
157(name PROCEDURE-OR-MACRO)
158(source PROCEDURE-OR-MACRO)
159
160Tools:
161
2f52380c
MD
162(backtrace) ;show backtrace from last error
163(debug) ;enter the debugger
164(trace [PROCEDURE]) ;trace procedure (no arg => show)
165(untrace [PROCEDURE]) ;untrace (no arg => untrace all)
13ae9151
MD
166
167(OPTIONSET-options 'full) ;display option information
168(OPTIONSET-enable 'OPTION)
169(OPTIONSET-disable 'OPTION)
170(OPTIONSET-set! OPTION VALUE)
171
172where OPTIONSET is one of debug, read, eval, print
173
174"))
175
0e81dabd
MD
176;;; {Apropos}
177;;;
178;;; Author: Roland Orre <orre@nada.kth.se>
179;;;
180
181(define (id x) x)
182
0e81dabd
MD
183(define-public (apropos rgx . options)
184 "Search for bindings: apropos regexp {options= 'full 'shadow 'value}"
185 (if (zero? (string-length rgx))
186 "Empty string not allowed"
4f161c5c 187 (let* ((match (make-regexp rgx))
0e81dabd
MD
188 (modules (cons (current-module)
189 (module-uses (current-module))))
190 (separator #\tab)
191 (shadow (member 'shadow options))
192 (value (member 'value options)))
193 (cond ((member 'full options)
194 (set! shadow #t)
195 (set! value #t)))
196 (for-each
197 (lambda (module)
198 (let* ((builtin (or (eq? module the-scm-module)
199 (eq? module the-root-module)))
200 (name (module-name module))
10764e3c
DH
201 (obarray (if builtin
202 (builtin-bindings)
203 (module-obarray module)))
204 (get-ref (if builtin
205 id
206 variable-ref)))
207 (array-for-each
208 (lambda (oblist)
209 (for-each
210 (lambda (x)
211 (cond ((regexp-exec match (symbol->string (car x)))
212 (display name)
213 (display ": ")
214 (display (car x))
215 (cond ((procedure? (get-ref (cdr x)))
216 (display separator)
217 (display (get-ref (cdr x))))
218 (value
219 (display separator)
220 (display (get-ref (cdr x)))))
221 (if (and shadow
222 (not (eq? (module-ref module
223 (car x))
224 (module-ref (current-module)
225 (car x)))))
226 (display " shadowed"))
227 (newline)
228 )))
229 oblist))
230 obarray)))
0e81dabd 231 modules))))
68aed3ea
MD
232
233(define-public (apropos-internal rgx)
234 "Return a list of accessible variable names."
3bdca000
MD
235 (apropos-fold (lambda (module name var data)
236 (cons name data))
237 '()
238 rgx
239 (apropos-fold-accessible (current-module))))
240
241(define-public (apropos-fold proc init rgx folder)
242 "Folds PROCEDURE over bindings matching third arg REGEXP.
243
244Result is
245
246 (PROCEDURE MODULE1 NAME1 VALUE1
247 (PROCEDURE MODULE2 NAME2 VALUE2
248 ...
249 (PROCEDURE MODULEn NAMEn VALUEn INIT)))
250
251where INIT is the second arg to `apropos-fold'.
252
253Fourth arg FOLDER is one of
254
255 (apropos-fold-accessible MODULE) ;fold over bindings accessible in MODULE
256 apropos-fold-exported ;fold over all exported bindings
257 apropos-fold-all ;fold over all bindings"
258 (let ((match (make-regexp rgx))
259 (recorded (make-vector 61 '())))
260 (let ((fold-module
261 (lambda (module data)
262 (let* ((obarray-filter
263 (lambda (name val data)
4adc3028 264 (if (and (regexp-exec match (symbol->string name))
3bdca000
MD
265 (not (hashq-get-handle recorded name)))
266 (begin
267 (hashq-set! recorded name #t)
268 (proc module name val data))
269 data)))
270 (module-filter
271 (lambda (name var data)
272 (obarray-filter name (variable-ref var) data))))
273 (cond ((or (eq? module the-scm-module)
274 (eq? module the-root-module))
275 (hash-fold obarray-filter
b52e071b
DH
276 data
277 (builtin-bindings)))
3bdca000
MD
278 (module (hash-fold module-filter
279 data
280 (module-obarray module)))
281 (else data))))))
282 (folder fold-module init))))
283
284(define (make-fold-modules init-thunk traverse extract)
285 "Return procedure capable of traversing a forest of modules.
286The forest traversed is the image of the forest generated by root
287modules returned by INIT-THUNK and the generator TRAVERSE.
288It is an image under the mapping EXTRACT."
289 (lambda (fold-module init)
9aec4751
MD
290 (let* ((table (make-hash-table 31))
291 (first? (lambda (obj)
8d627248
MD
292 (let* ((handle (hash-create-handle! table obj #t))
293 (first? (cdr handle)))
294 (set-cdr! handle #f)
295 first?))))
9aec4751
MD
296 (let rec ((data init)
297 (modules (init-thunk)))
298 (do ((modules modules (cdr modules))
299 (data data (if (first? (car modules))
300 (rec (fold-module (extract (car modules)) data)
301 (traverse (car modules)))
302 data)))
303 ((null? modules) data))))))
3bdca000
MD
304
305(define-public (apropos-fold-accessible module)
306 (make-fold-modules (lambda () (list module))
307 module-uses
308 (lambda (x) x)))
309
310(define (root-modules)
311 (cons the-root-module
312 (submodules (nested-ref the-root-module '(app modules)))))
313
314(define (submodules m)
315 (hash-fold (lambda (name var data)
316 (let ((obj (variable-ref var)))
317 (if (and (module? obj)
318 (eq? (module-kind obj) 'directory))
319 (cons obj data)
320 data)))
321 '()
322 (module-obarray m)))
323
324(define-public apropos-fold-exported
325 (make-fold-modules root-modules submodules module-public-interface))
326
327(define-public apropos-fold-all
328 (make-fold-modules root-modules submodules (lambda (x) x)))
7cfae7e6
MD
329
330(define-public (source obj)
331 (cond ((procedure? obj) (procedure-source obj))
332 ((macro? obj) (procedure-source (macro-transformer obj)))
333 (else #f)))
4a9f464e
MD
334
335(define-public (arity obj)
336 (let ((arity (procedure-property obj 'arity)))
337 (display (car arity))
338 (cond ((caddr arity)
339 (display " or more"))
340 ((not (zero? (cadr arity)))
341 (display " required and ")
342 (display (cadr arity))
343 (display " optional")))
344 (if (and (not (caddr arity))
345 (= (car arity) 1)
346 (<= (cadr arity) 1))
347 (display " argument")
348 (display " arguments"))
349 (if (closure? obj)
350 (let ((formals (cadr (procedure-source obj))))
351 (if (pair? formals)
352 (begin
353 (display ": `")
354 (display (car formals))
355 (let loop ((ls (cdr formals)))
356 (cond ((null? ls)
357 (display #\'))
358 ((not (pair? ls))
359 (display "', the rest in `")
360 (display ls)
361 (display #\'))
362 (else
363 (if (pair? (cdr ls))
364 (display "', `")
365 (display "' and `"))
366 (display (car ls))
367 (loop (cdr ls))))))
368 (begin
369 (display " in `")
370 (display formals)
371 (display #\')))))
372 (display ".\n")))
6ae34994
MD
373
374(define-public system-module
375 (procedure->syntax
376 (lambda (exp env)
377 (let* ((m (nested-ref the-root-module
378 (append '(app modules) (cadr exp)))))
379 (if (not m)
380 (error "Couldn't find any module named" (cadr exp)))
381 (let ((s (not (procedure-property (module-eval-closure m)
382 'system-module))))
383 (set-system-module! m s)
384 (string-append "Module " (symbol->string (module-name m))
385 " is now a " (if s "system" "user") " module."))))))