123 lines
4.2 KiB
Scheme
123 lines
4.2 KiB
Scheme
;;; Ikarus Scheme -- A compiler for R6RS Scheme.
|
|
;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum
|
|
;;;
|
|
;;; This program is free software: you can redistribute it and/or modify
|
|
;;; it under the terms of the GNU General Public License version 3 as
|
|
;;; published by the Free Software Foundation.
|
|
;;;
|
|
;;; This program is distributed in the hope that it will be useful, but
|
|
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
;;; General Public License for more details.
|
|
;;;
|
|
;;; You should have received a copy of the GNU General Public License
|
|
;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#|procedure:new-cafe
|
|
synopsis:
|
|
(new-cafe [eval])
|
|
description:
|
|
The procedure new-cafe starts a new read-eval-print loop inside
|
|
the current cafe (if one exists). It prompts the user for an
|
|
expression, evaluates it, prints the result back, and repeats the
|
|
process. If new-cafe is called with an argument, eval, then that
|
|
argument must be a procedure that takes a single argument. The
|
|
eval procedure will be used to evaluate the expressions.
|
|
|
|
Every time a new cafe is started, the prompt is changed to reflect
|
|
the depth of the current cafe (i.e. how many eof objects is takes
|
|
to exit the outermost cafe).
|
|
|
|
Input and output performed by the cafe can be changed by the
|
|
console-input-port and console-output-port parameters.
|
|
|
|
If an die occurs during reading, evaluating, or printing an
|
|
expression, then the die is printed to the error-port and the
|
|
operations of the cafe resume as normal.|#
|
|
#|FIXME:new-cafe
|
|
Be specific about what the error-port is |#
|
|
|
|
(library (ikarus cafe)
|
|
(export new-cafe)
|
|
(import
|
|
(only (rnrs) with-exception-handler)
|
|
(except (ikarus) new-cafe))
|
|
|
|
(define eval-depth 0)
|
|
|
|
(define display-prompt
|
|
(lambda (i)
|
|
(if (fx= i eval-depth)
|
|
(display " " (console-output-port))
|
|
(begin
|
|
(display ">" (console-output-port))
|
|
(display-prompt (fx+ i 1))))))
|
|
|
|
(define my-read
|
|
(lambda (k)
|
|
(parameterize ([interrupt-handler
|
|
(lambda ()
|
|
(flush-output-port (console-output-port))
|
|
(reset-input-port! (console-input-port))
|
|
(newline (console-output-port))
|
|
(k))])
|
|
(read (console-input-port)))))
|
|
|
|
(define wait
|
|
(lambda (eval-proc escape-k)
|
|
(call/cc
|
|
(lambda (k)
|
|
(with-exception-handler
|
|
(lambda (con)
|
|
(reset-input-port! (console-input-port))
|
|
(k (void)))
|
|
(lambda ()
|
|
(with-exception-handler
|
|
(lambda (con)
|
|
(flush-output-port (console-output-port))
|
|
(display "Unhandled exception\n" (console-error-port))
|
|
(print-condition con (console-error-port))
|
|
(when (interrupted-condition? con)
|
|
(raise-continuable con)))
|
|
(lambda ()
|
|
(display-prompt 0)
|
|
(let ([x (my-read k)])
|
|
(cond
|
|
[(eof-object? x)
|
|
(newline (console-output-port))
|
|
(escape-k (void))]
|
|
[else
|
|
(call-with-values
|
|
(lambda () (eval-proc x))
|
|
(lambda v*
|
|
(unless (andmap (lambda (v) (eq? v (void))) v*)
|
|
(for-each
|
|
(lambda (v)
|
|
(pretty-print v (console-output-port)))
|
|
v*))))]))))))))
|
|
(wait eval-proc escape-k)))
|
|
|
|
(define do-new-cafe
|
|
(lambda (eval-proc)
|
|
(dynamic-wind
|
|
(lambda () (set! eval-depth (fxadd1 eval-depth)))
|
|
(lambda ()
|
|
(call/cc
|
|
(lambda (k)
|
|
(wait eval-proc k))))
|
|
(lambda () (set! eval-depth (fxsub1 eval-depth))))))
|
|
|
|
(define default-cafe-eval
|
|
(lambda (x)
|
|
(eval x (interaction-environment))))
|
|
|
|
(define new-cafe
|
|
(case-lambda
|
|
[() (do-new-cafe default-cafe-eval)]
|
|
[(p)
|
|
(unless (procedure? p)
|
|
(die 'new-cafe "not a procedure" p))
|
|
(do-new-cafe p)]))
|
|
)
|
|
|