Gauche:対話環境での入出力

Gauche:対話環境での入出力

gosh対話環境でキーボード入力する関数を起動すると先頭で余分な改行が入力される

(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$

理由

改善案

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


Last modified : 2013/04/25 09:40:14 UTC