(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