package bufr import ( "bufio" "io" "strings" "git.milar.in/milarin/ds" ) type Reader struct { buf ds.Stack[posRune] src *bufio.Reader pos *Position } func New(r io.Reader) *Reader { return &Reader{ buf: ds.NewArrayStack[posRune](), src: bufio.NewReader(r), pos: &Position{Index: 0, Line: 1, Column: 1}, } } func NewFromString(str string) *Reader { return New(strings.NewReader(str)) } func (r *Reader) psrn(rn rune) posRune { return posRune{ Rune: rn, Pos: *r.pos, } } func (r *Reader) Pos() Position { return *r.pos } // Rune returns the next rune in r func (r *Reader) Rune() (rune, error) { rn, _, err := r.src.ReadRune() if err == nil { r.buf.Push(r.psrn(rn)) r.pos.Advance(rn) } return rn, err } func (r *Reader) Buffered() int { return r.src.Buffered() } // PeekRune returns the next rune in r without advancing reader position. // The next read will return the same rune again. func (r *Reader) PeekRune() (rune, error) { rn, err := r.Rune() if err != nil { return 0, err } if err := r.UnreadRune(); err != nil { return 0, err } return rn, nil } // String returns the next len runes in r as a string. // If an error occurs, both the already read string and the error will be returned func (r *Reader) String(len int) (string, error) { str := "" for i := 0; i < len; i++ { rn, err := r.Rune() if err != nil { return str, err } str += string(rn) } return str, nil } // UnreadRune unreads the last rune. // The next read will include the unread rune. // It returns ErrNothingToUnread if there wasn't any read yet func (r *Reader) UnreadRune() error { if r.buf.Empty() { return ErrNothingToUnread.New() } if err := r.src.UnreadRune(); err == nil { rn := r.buf.Pop() *r.pos = rn.Pos } else { rn := r.buf.Pop() *r.pos = rn.Pos r.src = prependRune(rn.Rune, r.src) } return nil } // UnreadString calls UnreadRune for each rune in str + one addtional rune for the separator rune // The actual runes in str are irrelevant. // Only the rune count of str determines the amount of UnreadRune calls. // The first error occured will be returned immediately. func (r *Reader) UnreadString(str string) error { for range str { err := r.UnreadRune() if err != nil { return err } } return r.UnreadRune() } // UnreadRunes calls UnreadRune n times func (r *Reader) UnreadRunes(n int) error { for i := 0; i < n; i++ { err := r.UnreadRune() if err != nil { return err } } return nil } // StringWhile reads runes and calls all functions for each one. // It returns all runes as a string for which any function returned true. // It stops when all functions returned false or an error occured. // The rune for which that function returned false will not be unread. func (r *Reader) StringWhile(f ...RuneFunc) (string, error) { s := new(strings.Builder) var rn rune var err error for rn, err = r.Rune(); err == nil && findFirstTrue(rn, f); rn, err = r.Rune() { s.WriteRune(rn) } return s.String(), err } // PeekStringWhile acts as StringWhile but does not advance reader position func (r *Reader) PeekStringWhile(f ...RuneFunc) (string, error) { str, err := r.StringWhile(f...) if err != nil { return "", err } if err := r.UnreadString(str); err != nil { return "", err } return str, nil } // StringUntil reads runes and calls all functions for each one. // It returns all runes as a string for which all functions returned true. // It stops when any function returns false or an error occured. // The rune for which that function returned false will not be unread. func (r *Reader) StringUntil(f ...RuneFunc) (string, error) { return r.StringWhile(func(rn rune) bool { return !findFirstTrue(rn, f) }) } // PeekStringUntil acts as StringUntil but does not advance reader position func (r *Reader) PeekStringUntil(f ...RuneFunc) (string, error) { str, err := r.StringUntil(f...) if err != nil { return "", err } if err := r.UnreadString(str); err != nil { return "", err } return str, nil } // SkipUntil acts as StringUntil but discards the string // The rune for which that function returned false will be unread. func (r *Reader) SkipUntil(f ...RuneFunc) error { _, err := r.StringUntil(f...) if err != nil { return err } return r.UnreadRune() } // SkipWhile acts as StringWhile but discards the string. // The rune for which that function returned false will be unread. func (r *Reader) SkipWhile(f ...RuneFunc) error { _, err := r.StringWhile(f...) if err != nil { return err } return r.UnreadRune() } // ExpectRune returns true if any function returns true for the next rune read from r func (r *Reader) ExpectRune(f ...RuneFunc) (bool, error) { rn, err := r.Rune() if err != nil { return false, err } return findFirstTrue(rn, f), nil } // ExpectString calls ExpectRune for each rune in str successively. // If the expected string was not found, all read runes will be unread func (r *Reader) ExpectString(str string) (bool, error) { read := 0 for _, rn := range str { ok, err := r.ExpectRune(Is(rn)) if err != nil { return false, err } read++ if !ok { if err := r.UnreadRunes(read); err != nil { return false, err } return false, nil } } return true, nil } // ExpectOneOfString calls ExpectString for each string successively // and returns the string which first matched. // The returned string will not be unread. // If no string matches, ErrNoMatchFound is returned func (r *Reader) ExpectOneOfString(str ...string) (string, error) { for _, s := range str { ok, err := r.ExpectString(s) if err != nil { return "", err } if ok { return s, nil } } return "", ErrNoMatchFound.New() } // Commit clears the internal buffer and therefore removes all data which were already read. // After calling Commit any unreads will return ErrNothingToUnread until another read occured. func (r *Reader) Commit() { r.buf.Clear() }