scm-style-repl.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. ;;;; Copyright (C) 1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010
  2. ;;;; Free Software Foundation, Inc.
  3. ;;;;
  4. ;;;; This library is free software; you can redistribute it and/or
  5. ;;;; modify it under the terms of the GNU Lesser General Public
  6. ;;;; License as published by the Free Software Foundation; either
  7. ;;;; version 3 of the License, or (at your option) any later version.
  8. ;;;;
  9. ;;;; This library is distributed in the hope that it will be useful,
  10. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;;; Lesser General Public License for more details.
  13. ;;;;
  14. ;;;; You should have received a copy of the GNU Lesser General Public
  15. ;;;; License along with this library; if not, write to the Free Software
  16. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;;;
  18. (define-module (ice-9 scm-style-repl)
  19. #:use-module (ice-9 save-stack)
  20. #:export (scm-repl-silent
  21. scm-repl-print-unspecified
  22. scm-repl-verbose
  23. scm-repl-prompt)
  24. ;; #:replace, as with deprecated code enabled these will be in the root env
  25. #:replace (assert-repl-silence
  26. assert-repl-print-unspecified
  27. assert-repl-verbosity
  28. default-pre-unwind-handler
  29. bad-throw
  30. error-catching-loop
  31. error-catching-repl
  32. scm-style-repl
  33. handle-system-error))
  34. (define scm-repl-silent #f)
  35. (define (assert-repl-silence v) (set! scm-repl-silent v))
  36. (define scm-repl-print-unspecified #f)
  37. (define (assert-repl-print-unspecified v) (set! scm-repl-print-unspecified v))
  38. (define scm-repl-verbose #f)
  39. (define (assert-repl-verbosity v) (set! scm-repl-verbose v))
  40. (define scm-repl-prompt "guile> ")
  41. ;; bad-throw is the hook that is called upon a throw to a an unhandled
  42. ;; key (unless the throw has four arguments, in which case
  43. ;; it's usually interpreted as an error throw.)
  44. ;; If the key has a default handler (a throw-handler-default property),
  45. ;; it is applied to the throw.
  46. ;;
  47. (define (bad-throw key . args)
  48. (let ((default (symbol-property key 'throw-handler-default)))
  49. (or (and default (apply default key args))
  50. (apply error "unhandled-exception:" key args))))
  51. (define (default-pre-unwind-handler key . args)
  52. ;; Narrow by two more frames: this one, and the throw handler.
  53. (save-stack 2)
  54. (apply throw key args))
  55. (define has-shown-debugger-hint? #f)
  56. (define (error-catching-loop thunk)
  57. (let ((status #f)
  58. (interactive #t))
  59. (define (loop first)
  60. (let ((next
  61. (catch #t
  62. (lambda ()
  63. (call-with-unblocked-asyncs
  64. (lambda ()
  65. (first)
  66. ;; This line is needed because mark
  67. ;; doesn't do closures quite right.
  68. ;; Unreferenced locals should be
  69. ;; collected.
  70. (set! first #f)
  71. (let loop ((v (thunk)))
  72. (loop (thunk)))
  73. #f)))
  74. (lambda (key . args)
  75. (case key
  76. ((quit)
  77. (set! status args)
  78. #f)
  79. ((switch-repl)
  80. (apply throw 'switch-repl args))
  81. ((abort)
  82. ;; This is one of the closures that require
  83. ;; (set! first #f) above
  84. ;;
  85. (lambda ()
  86. (run-hook abort-hook)
  87. (force-output (current-output-port))
  88. (display "ABORT: " (current-error-port))
  89. (write args (current-error-port))
  90. (newline (current-error-port))
  91. (if interactive
  92. (begin
  93. (if (and
  94. (not has-shown-debugger-hint?)
  95. (not (memq 'backtrace
  96. (debug-options-interface)))
  97. (stack? (fluid-ref the-last-stack)))
  98. (begin
  99. (newline (current-error-port))
  100. (display
  101. "Type \"(backtrace)\" to get more information or \"(debug)\" to enter the debugger.\n"
  102. (current-error-port))
  103. (set! has-shown-debugger-hint? #t)))
  104. (force-output (current-error-port)))
  105. (begin
  106. (primitive-exit 1)))
  107. (set! stack-saved? #f)))
  108. (else
  109. ;; This is the other cons-leak closure...
  110. (lambda ()
  111. (cond ((= (length args) 4)
  112. (apply handle-system-error key args))
  113. (else
  114. (apply bad-throw key args)))))))
  115. default-pre-unwind-handler)))
  116. (if next (loop next) status)))
  117. (set! ensure-batch-mode! (lambda ()
  118. (set! interactive #f)
  119. (restore-signals)))
  120. (set! batch-mode? (lambda () (not interactive)))
  121. (call-with-blocked-asyncs
  122. (lambda () (loop (lambda () #t))))))
  123. (define (error-catching-repl r e p)
  124. (error-catching-loop
  125. (lambda ()
  126. (call-with-values (lambda () (e (r)))
  127. (lambda the-values (for-each p the-values))))))
  128. (define (scm-style-repl)
  129. (letrec (
  130. (start-gc-rt #f)
  131. (start-rt #f)
  132. (repl-report-start-timing (lambda ()
  133. (set! start-gc-rt (gc-run-time))
  134. (set! start-rt (get-internal-run-time))))
  135. (repl-report (lambda ()
  136. (display ";;; ")
  137. (display (inexact->exact
  138. (* 1000 (/ (- (get-internal-run-time) start-rt)
  139. internal-time-units-per-second))))
  140. (display " msec (")
  141. (display (inexact->exact
  142. (* 1000 (/ (- (gc-run-time) start-gc-rt)
  143. internal-time-units-per-second))))
  144. (display " msec in gc)\n")))
  145. (consume-trailing-whitespace
  146. (lambda ()
  147. (let ((ch (peek-char)))
  148. (cond
  149. ((eof-object? ch))
  150. ((or (char=? ch #\space) (char=? ch #\tab))
  151. (read-char)
  152. (consume-trailing-whitespace))
  153. ((char=? ch #\newline)
  154. (read-char))))))
  155. (-read (lambda ()
  156. (let ((val
  157. (let ((prompt (cond ((string? scm-repl-prompt)
  158. scm-repl-prompt)
  159. ((thunk? scm-repl-prompt)
  160. (scm-repl-prompt))
  161. (scm-repl-prompt "> ")
  162. (else ""))))
  163. (repl-reader prompt))))
  164. ;; As described in R4RS, the READ procedure updates the
  165. ;; port to point to the first character past the end of
  166. ;; the external representation of the object. This
  167. ;; means that it doesn't consume the newline typically
  168. ;; found after an expression. This means that, when
  169. ;; debugging Guile with GDB, GDB gets the newline, which
  170. ;; it often interprets as a "continue" command, making
  171. ;; breakpoints kind of useless. So, consume any
  172. ;; trailing newline here, as well as any whitespace
  173. ;; before it.
  174. ;; But not if EOF, for control-D.
  175. (if (not (eof-object? val))
  176. (consume-trailing-whitespace))
  177. (run-hook after-read-hook)
  178. (if (eof-object? val)
  179. (begin
  180. (repl-report-start-timing)
  181. (if scm-repl-verbose
  182. (begin
  183. (newline)
  184. (display ";;; EOF -- quitting")
  185. (newline)))
  186. (quit 0)))
  187. val)))
  188. (-eval (lambda (sourc)
  189. (repl-report-start-timing)
  190. (run-hook before-eval-hook sourc)
  191. (let ((val (start-stack 'repl-stack
  192. ;; If you change this procedure
  193. ;; (primitive-eval), please also
  194. ;; modify the repl-stack case in
  195. ;; save-stack so that stack cutting
  196. ;; continues to work.
  197. (primitive-eval sourc))))
  198. (run-hook after-eval-hook sourc)
  199. val)))
  200. (-print (let ((maybe-print (lambda (result)
  201. (if (or scm-repl-print-unspecified
  202. (not (unspecified? result)))
  203. (begin
  204. (write result)
  205. (newline))))))
  206. (lambda (result)
  207. (if (not scm-repl-silent)
  208. (begin
  209. (run-hook before-print-hook result)
  210. (maybe-print result)
  211. (run-hook after-print-hook result)
  212. (if scm-repl-verbose
  213. (repl-report))
  214. (force-output))))))
  215. (-quit (lambda (args)
  216. (if scm-repl-verbose
  217. (begin
  218. (display ";;; QUIT executed, repl exitting")
  219. (newline)
  220. (repl-report)))
  221. args)))
  222. (let ((status (error-catching-repl -read
  223. -eval
  224. -print)))
  225. (-quit status))))
  226. (define (handle-system-error key . args)
  227. (let ((cep (current-error-port)))
  228. (cond ((not (stack? (fluid-ref the-last-stack))))
  229. ((memq 'backtrace (debug-options-interface))
  230. (let ((highlights (if (or (eq? key 'wrong-type-arg)
  231. (eq? key 'out-of-range))
  232. (list-ref args 3)
  233. '())))
  234. (run-hook before-backtrace-hook)
  235. (newline cep)
  236. (display "Backtrace:\n")
  237. (display-backtrace (fluid-ref the-last-stack) cep
  238. #f #f highlights)
  239. (newline cep)
  240. (run-hook after-backtrace-hook))))
  241. (run-hook before-error-hook)
  242. (apply display-error (fluid-ref the-last-stack) cep args)
  243. (run-hook after-error-hook)
  244. (force-output cep)
  245. (throw 'abort key)))