session.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. ;;;; Copyright (C) 1997, 2000 Free Software Foundation, Inc.
  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
  15. ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. ;;;; Boston, MA 02111-1307 USA
  17. ;;;;
  18. (define-module (ice-9 session)
  19. :use-module (ice-9 documentation)
  20. :use-module (ice-9 regex)
  21. )
  22. ;;; Documentation
  23. ;;;
  24. (define-public help
  25. (procedure->syntax
  26. (lambda (exp env)
  27. "(help [NAME])
  28. Prints useful information. Try `(help)'."
  29. (cond ((not (= (length exp) 2))
  30. (help-usage))
  31. ((not (feature? 'regex))
  32. (display "`help' depends on the `regex' feature.
  33. You don't seem to have regular expressions installed.\n"))
  34. (else
  35. (let ((name (cadr exp)))
  36. (cond ((symbol? name)
  37. (help-doc name
  38. (string-append "^"
  39. (regexp-quote
  40. (symbol->string name))
  41. "$")))
  42. ((string? name)
  43. (help-doc name name))
  44. ((and (list? name)
  45. (= (length name) 2)
  46. (eq? (car name) 'unquote))
  47. (let ((doc (object-documentation (local-eval (cadr name)
  48. env))))
  49. (if (not doc)
  50. (simple-format #t "No documentation found for ~S\n"
  51. (cadr name))
  52. (write-line doc))))
  53. (else
  54. (help-usage)))
  55. *unspecified*))))))
  56. (define (help-doc term regexp)
  57. (let ((entries (apropos-fold (lambda (module name object data)
  58. (cons (list module
  59. name
  60. (object-documentation object))
  61. data))
  62. '()
  63. regexp
  64. apropos-fold-exported))
  65. (module car)
  66. (name cadr)
  67. (doc caddr))
  68. (if (null? entries)
  69. ;; no matches
  70. (begin
  71. (display "Did not find any object ")
  72. (simple-format #t
  73. (if (symbol? term)
  74. "named `~A'\n"
  75. "matching regexp \"~A\"\n")
  76. term))
  77. (let ((first? #t))
  78. (if (or-map doc entries)
  79. ;; entries with documentation
  80. (for-each (lambda (entry)
  81. ;; *fixme*: Use `describe' when we have GOOPS?
  82. (if (doc entry)
  83. (begin
  84. (if first?
  85. (set! first? #f)
  86. (newline))
  87. (simple-format #t "~S: ~S\n~A\n"
  88. (module-name (module entry))
  89. (name entry)
  90. (doc entry)))))
  91. entries))
  92. (if (or-map (lambda (x) (not (doc x))) entries)
  93. ;; entries without documentation
  94. (begin
  95. (if (not first?)
  96. (display "\nNo documentation found for:\n"))
  97. (for-each (lambda (entry)
  98. (if (not (doc entry))
  99. (simple-format #t "~S: ~S\n"
  100. (module-name (module entry))
  101. (name entry))))
  102. entries)))))))
  103. (define (help-usage)
  104. (display "Usage: (help NAME) gives documentation about objects named NAME (a symbol)
  105. (help REGEXP) ditto for objects with names matching REGEXP (a string)
  106. (help ,EXPR) gives documentation for object returned by EXPR
  107. (help) gives this text
  108. `help' searches among bindings exported from loaded modules, while
  109. `apropos' searches among bindings visible from the \"current\" module.
  110. Examples: (help help)
  111. (help cons)
  112. (help \"output-string\")
  113. Other useful sources of helpful information:
  114. (apropos STRING)
  115. (arity PROCEDURE)
  116. (name PROCEDURE-OR-MACRO)
  117. (source PROCEDURE-OR-MACRO)
  118. Tools:
  119. (backtrace) ;show backtrace from last error
  120. (debug) ;enter the debugger
  121. (trace [PROCEDURE]) ;trace procedure (no arg => show)
  122. (untrace [PROCEDURE]) ;untrace (no arg => untrace all)
  123. (OPTIONSET-options 'full) ;display option information
  124. (OPTIONSET-enable 'OPTION)
  125. (OPTIONSET-disable 'OPTION)
  126. (OPTIONSET-set! OPTION VALUE)
  127. where OPTIONSET is one of debug, read, eval, print
  128. "))
  129. ;;; {Apropos}
  130. ;;;
  131. ;;; Author: Roland Orre <orre@nada.kth.se>
  132. ;;;
  133. (define (id x) x)
  134. (define-public (apropos rgx . options)
  135. "Search for bindings: apropos regexp {options= 'full 'shadow 'value}"
  136. (if (zero? (string-length rgx))
  137. "Empty string not allowed"
  138. (let* ((match (make-regexp rgx))
  139. (modules (cons (current-module)
  140. (module-uses (current-module))))
  141. (separator #\tab)
  142. (shadow (member 'shadow options))
  143. (value (member 'value options)))
  144. (cond ((member 'full options)
  145. (set! shadow #t)
  146. (set! value #t)))
  147. (for-each
  148. (lambda (module)
  149. (let* ((builtin (or (eq? module the-scm-module)
  150. (eq? module the-root-module)))
  151. (name (module-name module))
  152. (obarrays (if builtin
  153. (list (builtin-weak-bindings)
  154. (builtin-bindings))
  155. (list (module-obarray module))))
  156. (get-refs (if builtin
  157. (list id id)
  158. (list variable-ref)))
  159. )
  160. (for-each
  161. (lambda (obarray get-ref)
  162. (array-for-each
  163. (lambda (oblist)
  164. (for-each
  165. (lambda (x)
  166. (cond ((regexp-exec match (car x))
  167. (display name)
  168. (display ": ")
  169. (display (car x))
  170. (cond ((procedure? (get-ref (cdr x)))
  171. (display separator)
  172. (display (get-ref (cdr x))))
  173. (value
  174. (display separator)
  175. (display (get-ref (cdr x)))))
  176. (if (and shadow
  177. (not (eq? (module-ref module
  178. (car x))
  179. (module-ref (current-module)
  180. (car x)))))
  181. (display " shadowed"))
  182. (newline)
  183. )))
  184. oblist))
  185. obarray))
  186. obarrays get-refs)))
  187. modules))))
  188. (define-public (apropos-internal rgx)
  189. "Return a list of accessible variable names."
  190. (apropos-fold (lambda (module name var data)
  191. (cons name data))
  192. '()
  193. rgx
  194. (apropos-fold-accessible (current-module))))
  195. (define-public (apropos-fold proc init rgx folder)
  196. "Folds PROCEDURE over bindings matching third arg REGEXP.
  197. Result is
  198. (PROCEDURE MODULE1 NAME1 VALUE1
  199. (PROCEDURE MODULE2 NAME2 VALUE2
  200. ...
  201. (PROCEDURE MODULEn NAMEn VALUEn INIT)))
  202. where INIT is the second arg to `apropos-fold'.
  203. Fourth arg FOLDER is one of
  204. (apropos-fold-accessible MODULE) ;fold over bindings accessible in MODULE
  205. apropos-fold-exported ;fold over all exported bindings
  206. apropos-fold-all ;fold over all bindings"
  207. (let ((match (make-regexp rgx))
  208. (recorded (make-vector 61 '())))
  209. (let ((fold-module
  210. (lambda (module data)
  211. (let* ((obarray-filter
  212. (lambda (name val data)
  213. (if (and (regexp-exec match name)
  214. (not (hashq-get-handle recorded name)))
  215. (begin
  216. (hashq-set! recorded name #t)
  217. (proc module name val data))
  218. data)))
  219. (module-filter
  220. (lambda (name var data)
  221. (obarray-filter name (variable-ref var) data))))
  222. (cond ((or (eq? module the-scm-module)
  223. (eq? module the-root-module))
  224. (hash-fold obarray-filter
  225. (hash-fold obarray-filter
  226. data
  227. (builtin-bindings))
  228. (builtin-weak-bindings)))
  229. (module (hash-fold module-filter
  230. data
  231. (module-obarray module)))
  232. (else data))))))
  233. (folder fold-module init))))
  234. (define (make-fold-modules init-thunk traverse extract)
  235. "Return procedure capable of traversing a forest of modules.
  236. The forest traversed is the image of the forest generated by root
  237. modules returned by INIT-THUNK and the generator TRAVERSE.
  238. It is an image under the mapping EXTRACT."
  239. (lambda (fold-module init)
  240. (let* ((table (make-hash-table 31))
  241. (first? (lambda (obj)
  242. (let* ((handle (hash-create-handle! table obj #t))
  243. (first? (cdr handle)))
  244. (set-cdr! handle #f)
  245. first?))))
  246. (let rec ((data init)
  247. (modules (init-thunk)))
  248. (do ((modules modules (cdr modules))
  249. (data data (if (first? (car modules))
  250. (rec (fold-module (extract (car modules)) data)
  251. (traverse (car modules)))
  252. data)))
  253. ((null? modules) data))))))
  254. (define-public (apropos-fold-accessible module)
  255. (make-fold-modules (lambda () (list module))
  256. module-uses
  257. (lambda (x) x)))
  258. (define (root-modules)
  259. (cons the-root-module
  260. (submodules (nested-ref the-root-module '(app modules)))))
  261. (define (submodules m)
  262. (hash-fold (lambda (name var data)
  263. (let ((obj (variable-ref var)))
  264. (if (and (module? obj)
  265. (eq? (module-kind obj) 'directory))
  266. (cons obj data)
  267. data)))
  268. '()
  269. (module-obarray m)))
  270. (define-public apropos-fold-exported
  271. (make-fold-modules root-modules submodules module-public-interface))
  272. (define-public apropos-fold-all
  273. (make-fold-modules root-modules submodules (lambda (x) x)))
  274. (define-public (source obj)
  275. (cond ((procedure? obj) (procedure-source obj))
  276. ((macro? obj) (procedure-source (macro-transformer obj)))
  277. (else #f)))
  278. (define-public (arity obj)
  279. (let ((arity (procedure-property obj 'arity)))
  280. (display (car arity))
  281. (cond ((caddr arity)
  282. (display " or more"))
  283. ((not (zero? (cadr arity)))
  284. (display " required and ")
  285. (display (cadr arity))
  286. (display " optional")))
  287. (if (and (not (caddr arity))
  288. (= (car arity) 1)
  289. (<= (cadr arity) 1))
  290. (display " argument")
  291. (display " arguments"))
  292. (if (closure? obj)
  293. (let ((formals (cadr (procedure-source obj))))
  294. (if (pair? formals)
  295. (begin
  296. (display ": `")
  297. (display (car formals))
  298. (let loop ((ls (cdr formals)))
  299. (cond ((null? ls)
  300. (display #\'))
  301. ((not (pair? ls))
  302. (display "', the rest in `")
  303. (display ls)
  304. (display #\'))
  305. (else
  306. (if (pair? (cdr ls))
  307. (display "', `")
  308. (display "' and `"))
  309. (display (car ls))
  310. (loop (cdr ls))))))
  311. (begin
  312. (display " in `")
  313. (display formals)
  314. (display #\')))))
  315. (display ".\n")))
  316. (define-public system-module
  317. (procedure->syntax
  318. (lambda (exp env)
  319. (let* ((m (nested-ref the-root-module
  320. (append '(app modules) (cadr exp)))))
  321. (if (not m)
  322. (error "Couldn't find any module named" (cadr exp)))
  323. (let ((s (not (procedure-property (module-eval-closure m)
  324. 'system-module))))
  325. (set-system-module! m s)
  326. (string-append "Module " (symbol->string (module-name m))
  327. " is now a " (if s "system" "user") " module."))))))