scm-style-repl.scm 12 KB

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