repl.scm refactor
[bpt/guile.git] / module / system / repl / repl.scm
CommitLineData
17e90c5e
KN
1;;; Read-Eval-Print Loop
2
eaba53b7 3;; Copyright (C) 2001, 2009, 2010, 2011 Free Software Foundation, Inc.
17e90c5e 4
eb721799
AW
5;; This library is free software; you can redistribute it and/or
6;; modify it under the terms of the GNU Lesser General Public
7;; License as published by the Free Software Foundation; either
8;; version 3 of the License, or (at your option) any later version.
17e90c5e 9;;
eb721799 10;; This library is distributed in the hope that it will be useful,
17e90c5e 11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
eb721799
AW
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;; Lesser General Public License for more details.
17e90c5e 14;;
eb721799
AW
15;; You should have received a copy of the GNU Lesser General Public
16;; License along with this library; if not, write to the Free Software
17;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18;; 02110-1301 USA
17e90c5e
KN
19
20;;; Code:
21
22(define-module (system repl repl)
8239263f 23 #:use-module (system base syntax)
1a1a10d3
AW
24 #:use-module (system base pmatch)
25 #:use-module (system base compile)
26 #:use-module (system base language)
33df2ec7
AW
27 #:use-module (system vm vm)
28 #:use-module (system repl error-handling)
1a1a10d3
AW
29 #:use-module (system repl common)
30 #:use-module (system repl command)
3ae78d95
AW
31 #:use-module (ice-9 control)
32 #:export (start-repl run-repl))
17e90c5e 33
33df2ec7
AW
34\f
35
36;;;
37;;; Meta commands
38;;;
39
3a6f6678
AW
40(define meta-command-token (cons 'meta 'command))
41
4b2afc62 42(define (meta-reader read env)
c372cd74
AW
43 (lambda* (#:optional (port (current-input-port)))
44 (with-input-from-port port
45 (lambda ()
859e58ae 46 (let ((ch (flush-leading-whitespace)))
c372cd74
AW
47 (cond ((eof-object? ch)
48 ;; EOF objects are not buffered. It's quite possible
49 ;; to peek an EOF then read something else. It's
50 ;; strange but it's how it works.
51 ch)
52 ((eqv? ch #\,)
53 (read-char port)
54 meta-command-token)
55 (else (read port env))))))))
3a6f6678 56
dcb7c7dd
AW
57(define (flush-all-input)
58 (if (and (char-ready?)
59 (not (eof-object? (peek-char))))
60 (begin
61 (read-char)
62 (flush-all-input))))
63
3a6f6678
AW
64;; repl-reader is a function defined in boot-9.scm, and is replaced by
65;; something else if readline has been activated. much of this hoopla is
66;; to be able to re-use the existing readline machinery.
b93c34c0
AW
67;;
68;; Catches read errors, returning *unspecified* in that case.
3a6f6678 69(define (prompting-meta-read repl)
33df2ec7
AW
70 (catch #t
71 (lambda ()
72 (repl-reader (lambda () (repl-prompt repl))
73 (meta-reader (language-reader (repl-language repl))
74 (current-module))))
75 (lambda (key . args)
76 (case key
77 ((quit)
78 (apply throw key args))
79 (else
eaba53b7
AW
80 (format (current-output-port) "While reading expression:\n")
81 (print-exception (current-output-port) #f key args)
dcb7c7dd 82 (flush-all-input)
33df2ec7 83 *unspecified*)))))
67c4505e 84
652f48c0
AW
85\f
86
87;;;
88;;; The repl
89;;;
90
33df2ec7
AW
91(define* (start-repl #:optional (lang (current-language)) #:key debug)
92 (run-repl (make-repl lang debug)))
93
ffe911f7
AW
94;; (put 'abort-on-error 'scheme-indent-function 1)
95(define-syntax abort-on-error
96 (syntax-rules ()
97 ((_ string exp)
98 (catch #t
99 (lambda () exp)
100 (lambda (key . args)
101 (format #t "While ~A:~%" string)
eaba53b7 102 (print-exception (current-output-port) #f key args)
ffe911f7
AW
103 (abort))))))
104
33df2ec7 105(define (run-repl repl)
52738540
AW
106 (define (with-stack-and-prompt thunk)
107 (call-with-prompt (default-prompt-tag)
108 (lambda () (start-stack #t (thunk)))
109 (lambda (k proc)
110 (with-stack-and-prompt (lambda () (proc k))))))
111
3ae78d95
AW
112 (% (with-fluids ((*repl-stack*
113 (cons repl (or (fluid-ref *repl-stack*) '()))))
114 (if (null? (cdr (fluid-ref *repl-stack*)))
115 (repl-welcome repl))
116 (let prompt-loop ()
117 (let ((exp (prompting-meta-read repl)))
118 (cond
119 ((eqv? exp *unspecified*)) ; read error, pass
120 ((eq? exp meta-command-token)
5bc97ad5
AW
121 (catch #t
122 (lambda ()
123 (meta-command repl))
3ae78d95 124 (lambda (k . args)
5bc97ad5
AW
125 (if (eq? k 'quit)
126 (abort args)
127 (begin
a627100b 128 (format #t "While executing meta-command:~%")
eaba53b7 129 (print-exception (current-output-port) #f k args))))))
3ae78d95
AW
130 ((eof-object? exp)
131 (newline)
132 (abort '()))
133 (else
134 ;; since the input port is line-buffered, consume up to the
135 ;; newline
136 (flush-to-newline)
137 (call-with-error-handling
138 (lambda ()
139 (catch 'quit
140 (lambda ()
141 (call-with-values
142 (lambda ()
ffe911f7
AW
143 (% (let ((thunk
144 (abort-on-error "compiling expression"
145 (repl-prepare-eval-thunk
146 repl
147 (abort-on-error "parsing expression"
148 (repl-parse repl exp))))))
149 (run-hook before-eval-hook exp)
150 (with-error-handling
52738540 151 (with-stack-and-prompt thunk)))
ffe911f7 152 (lambda (k) (values))))
3ae78d95
AW
153 (lambda l
154 (for-each (lambda (v)
155 (repl-print repl v))
156 l))))
157 (lambda (k . args)
b0e556d4
AW
158 (abort args))))
159 #:trap-handler 'disabled)))
859e58ae 160 (flush-to-newline) ;; consume trailing whitespace
3ae78d95 161 (prompt-loop))))
33df2ec7 162 (lambda (k status)
3ae78d95 163 status)))
17e90c5e 164
859e58ae
AW
165;; Returns first non-whitespace char.
166(define (flush-leading-whitespace)
167 (let ((ch (peek-char)))
168 (cond ((eof-object? ch) ch)
169 ((char-whitespace? ch) (read-char) (flush-leading-whitespace))
170 (else ch))))
0d646345
AW
171
172(define (flush-to-newline)
173 (if (char-ready?)
174 (let ((ch (peek-char)))
175 (if (and (not (eof-object? ch)) (char-whitespace? ch))
176 (begin
177 (read-char)
178 (if (not (char=? ch #\newline))
179 (flush-to-newline)))))))