(Gauche:Bugsから移動)
isi (2006/02/09 06:55:55 PST): キーボードからの入力を行うプログラムで、(1) gosh インタープリターから関数名をキー入力してプログラムを実行した場合、先頭で余分な空行が入力されます。(2) シェルから起動した場合は、そんなことはありません。
例:このプログラムで、
;;; input-test.scm
(define (main args)
(with-input-from-port (current-input-port)
(lambda ()
(let ((ln 0))
(port-for-each
(lambda (line)
(set! ln (+ ln 1))
(display #`",ln ---,|line|---")
(newline))
read-line))))
0)
(1) gosh インタープリターから関数起動
bash$ gosh gosh> (load "./input-test.scm") gosh> (main '()) 1 ------ <=== 起動後すぐ出力される abc 2 ---abc--- 0 gosh> (exit)
(2) シェルから起動
bash$ gosh input-test.scm abc <=== こっちは問題なし(起動後入力待ちとなる) 1 ---abc--- xyz 2 ---xyz--- bash$
gosh> (load "./input-test") #t gosh> (main '())abc 1 ---abc--- xyz 2 ---xyz--- 0 gosh> (exit)
(define my-prompter
(lambda ()
(format #t "MY-REPL: ")
(flush)))
(define my-eval
(lambda (expr env)
(let ((in (open-input-fd-port
(port-file-number (current-input-port)))))
(dynamic-wind
(lambda () #f)
(lambda ()
(with-input-from-port in
(lambda () (eval expr env))))
(lambda () (close-input-port in))))))
(read-eval-print-loop #f my-eval #f my-prompter)
Shiro(2006/02/17 19:03:54 PST): うーん、バッファリングされてるポートのfdを 別ポートでオープンするってとこにちょっと危うさを感じます。 入力がline bufferedである限りはうまくいくでしょうが。 それと、dynamic-windを一度抜けるとinがcloseされちゃいますが、 expr中で捕まえた継続に外から戻るとinがcloseされたままになります。
通常のgoshのREPL (newlineを読み飛ばすためにread-charが入ってる。123 および456がユーザによる入力)
gosh> (define *c* (let ((k (let/cc k k))) (print "yoh!") (read-char) (read-line) k)) yoh! 123 *c* gosh> (*c* *c*) yoh! 456 *c*
上記のmy-eval。2度目以降はread-lineが効かない:
MY-REPL: (define *c* (let ((k (let/cc k k))) (print "yoh!") (read-line) k)) yoh! 123 *c* MY-REPL: (*c* *c*) yoh! *c*
(define my-eval
(lambda (expr env)
(let ((sin-fd (port-file-number (standard-input-port)))
(in #f))
(dynamic-wind
(lambda () #f)
(lambda ()
(when (and in (not (port-closed? in)))
(close-input-port in))
(set! in (open-input-fd-port sin-fd))
(with-input-from-port in
(lambda ()
(print "IN-MY-EVAL:" (current-input-port))
(eval expr env))))
(lambda () (close-input-port in))))))
----
MY-REPL: (define *c* (let ((k (let/cc k k))) (print (current-input-port)) (read-line) k))
IN-MY-EVAL:#<iport #f 0x43f450>
#<iport #f 0x43f450>
123
*c*
MY-REPL: (*c* *c*)
IN-MY-EVAL:#<iport #f 0x43f228>
#<iport (stdin) 0xa2f18>
*c*
;; (1) 改行までを読み飛ばす。
(define (main args)
(define (my-prompter)
(format #t "My-REPL: ")
(flush))
;
(define (my-reader)
(let ((expr (read)))
(read-line)
expr))
;
(read-eval-print-loop my-reader #f #f my-prompter)
0)
;; (2) buffered-input-port を使う
(use gauche.uvector)
(use gauche.vport)
;;
(define (make-buffered-input-port)
(define filler
(lambda (u8vec)
(let ((line (read-line)))
(if (eof-object? line)
0
(let ((line-vec (string->u8vector (string-append line "\n"))))
(u8vector-copy! u8vec 0 line-vec)
(u8vector-length line-vec))))))
(make <buffered-input-port> :fill filler))
;;
(define (main args)
(let ((in-port (make-buffered-input-port)))
(define (my-prompter)
(format #t "My-REPL: ")
(flush))
;
(define (my-reader)
(read in-port))
;
(read-eval-print-loop my-reader #f #f my-prompter))
0)
Tag: REPL