[gambit-list] Seekable String Ports

Taylor Venable taylor at metasyntax.net
Thu Jun 11 23:11:30 EDT 2009

Is there any way to seek through string ports?  When I try to use
input-port-byte-position I get this:

> (call-with-input-string "asdf" (either (char/exactly #\c) (char/exactly #\s)))
*** ERROR IN #<procedure #10>, "tcv-gambit-parse.scm"@66.20 -- (Argument 1) Device INPUT PORT expected
(input-port-byte-position '#<input-port #11 (string)>)

(I'm doubtful that input-port-byte-position would be what I want
anyway if the string included characters that weren't encoded as
single bytes, but that's a digression.)

I'm trying to write a parser combinator library, and part of that
entails some rewinding of streams for ordered-choice operations (as
illustrated above).  A potential alternative would be to duplicate the
port's contents and use a different port for each alternative, but I
am not aware of any API to do this either.  Any ideas on how to
accomplish this objective?  I need something that works for at least
string ports and device ports.

My current code, for background:

(define char/exactly
  (lambda (c)
    (lambda (stream)
      (let ((char (read-char stream)))
        (cond ((eof-object? char) #f)
              ((not (char=? char c)) #f)
              (else char))))))

(define either
  (lambda combinators
    (lambda (stream)
      (let loop ((c combinators))
        (cond ((null? c) #f)
              ((apply (car c) (list stream)) #t)
              (else (loop (cdr c))))))))

As defined here, the either function will not undo the changes done by
char/exactly (in the example above), thus each choice will advance the
stream by one character.  We could work around it here by using
peek-char rather than read-char but that wouldn't scale to when either
is used on functions that read large chunks of data before failing.

Thanks for any ideas,

Taylor Christopher Venable

More information about the Gambit-list mailing list