positions introduced

This commit is contained in:
Timon Ringwald 2022-05-23 12:59:35 +02:00
parent 9c3d038fcd
commit 40d00d9244
4 changed files with 69 additions and 5 deletions

6
pos_rune.go Normal file
View File

@ -0,0 +1,6 @@
package bufr
type posRune struct {
Rune rune
Pos Position
}

17
position.go Normal file
View File

@ -0,0 +1,17 @@
package bufr
type Position struct {
Index int
Line int
Column int
}
func (p *Position) Advance(rn rune) {
p.Index++
if rn == '\n' {
p.Line++
p.Column = 0
} else {
p.Column++
}
}

View File

@ -9,22 +9,36 @@ import (
) )
type Reader struct { type Reader struct {
buf *dstruct.Stack[rune] buf *dstruct.Stack[posRune]
src *bufio.Reader src *bufio.Reader
pos *Position
} }
func NewReader(r io.Reader) *Reader { func NewReader(r io.Reader) *Reader {
return &Reader{ return &Reader{
buf: new(dstruct.Stack[rune]), buf: new(dstruct.Stack[posRune]),
src: bufio.NewReader(r), src: bufio.NewReader(r),
pos: &Position{},
} }
} }
func (r *Reader) psrn(rn rune) posRune {
return posRune{
Rune: rn,
Pos: *r.pos,
}
}
func (r *Reader) Pos() (index, line, column int) {
return r.pos.Index, r.pos.Line, r.pos.Column
}
// Rune returns the next rune in r // Rune returns the next rune in r
func (r *Reader) Rune() (rune, error) { func (r *Reader) Rune() (rune, error) {
rn, _, err := r.src.ReadRune() rn, _, err := r.src.ReadRune()
if err == nil { if err == nil {
r.buf.Push(rn) r.buf.Push(r.psrn(rn))
r.pos.Advance(rn)
} }
return rn, err return rn, err
} }
@ -38,9 +52,12 @@ func (r *Reader) UnreadRune() error {
} }
if err := r.src.UnreadRune(); err == nil { if err := r.src.UnreadRune(); err == nil {
r.buf.Pop() rn := r.buf.Pop()
*r.pos = rn.Pos
} else { } else {
r.src = prependRune(r.buf.Pop(), r.src) rn := r.buf.Pop()
*r.pos = rn.Pos
r.src = prependRune(rn.Rune, r.src)
} }
return nil return nil

24
reader_test.go Normal file
View File

@ -0,0 +1,24 @@
package bufr
import (
"fmt"
"strings"
"testing"
)
func TestPos(t *testing.T) {
r := NewReader(strings.NewReader("hello world\nsecond line"))
unread := false
for rn, err := r.Rune(); err == nil; rn, err = r.Rune() {
index, line, col := r.Pos()
fmt.Println(string(rn), index, line, col)
if !unread && rn == '\n' {
for i := 0; i < 5; i++ {
r.UnreadRune()
}
unread = true
}
}
}