1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
package parse
import (
"io"
)
var nullBuffer = []byte{0}
// Input is a buffered reader that allows peeking forward and shifting, taking an io.Input.
// It keeps data in-memory until Free, taking a byte length, is called to move beyond the data.
type Input struct {
buf []byte
pos int // index in buf
start int // index in buf
err error
restore func()
}
// NewInput returns a new Input for a given io.Input and uses io.ReadAll to read it into a byte slice.
// If the io.Input implements Bytes, that is used instead. It will append a NULL at the end of the buffer.
func NewInput(r io.Reader) *Input {
var b []byte
if r != nil {
if buffer, ok := r.(interface {
Bytes() []byte
}); ok {
b = buffer.Bytes()
} else {
var err error
b, err = io.ReadAll(r)
if err != nil {
return &Input{
buf: nullBuffer,
err: err,
}
}
}
}
return NewInputBytes(b)
}
// NewInputString returns a new Input for a given string and appends NULL at the end.
func NewInputString(s string) *Input {
return NewInputBytes([]byte(s))
}
// NewInputBytes returns a new Input for a given byte slice and appends NULL at the end.
// To avoid reallocation, make sure the capacity has room for one more byte.
func NewInputBytes(b []byte) *Input {
z := &Input{
buf: b,
}
n := len(b)
if n == 0 {
z.buf = nullBuffer
} else {
// Append NULL to buffer, but try to avoid reallocation
if cap(b) > n {
// Overwrite next byte but restore when done
b = b[:n+1]
c := b[n]
b[n] = 0
z.buf = b
z.restore = func() {
b[n] = c
}
} else {
z.buf = append(b, 0)
}
}
return z
}
// Restore restores the replaced byte past the end of the buffer by NULL.
func (z *Input) Restore() {
if z.restore != nil {
z.restore()
z.restore = nil
}
}
// Err returns the error returned from io.Input or io.EOF when the end has been reached.
func (z *Input) Err() error {
return z.PeekErr(0)
}
// PeekErr returns the error at position pos. When pos is zero, this is the same as calling Err().
func (z *Input) PeekErr(pos int) error {
if z.err != nil {
return z.err
} else if len(z.buf)-1 <= z.pos+pos {
return io.EOF
}
return nil
}
// Peek returns the ith byte relative to the end position.
// Peek returns 0 when an error has occurred, Err returns the erroz.
func (z *Input) Peek(pos int) byte {
pos += z.pos
return z.buf[pos]
}
// PeekRune returns the rune and rune length of the ith byte relative to the end position.
func (z *Input) PeekRune(pos int) (rune, int) {
// from unicode/utf8
c := z.Peek(pos)
if c < 0xC0 || len(z.buf)-1-z.pos < 2 {
return rune(c), 1
} else if c < 0xE0 || len(z.buf)-1-z.pos < 3 {
return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2
} else if c < 0xF0 || len(z.buf)-1-z.pos < 4 {
return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3
}
return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4
}
// Move advances the position.
func (z *Input) Move(n int) {
z.pos += n
}
// MoveRune advances the position by the length of the current rune.
func (z *Input) MoveRune() {
c := z.Peek(0)
if c < 0xC0 || len(z.buf)-1-z.pos < 2 {
z.pos++
} else if c < 0xE0 || len(z.buf)-1-z.pos < 3 {
z.pos += 2
} else if c < 0xF0 || len(z.buf)-1-z.pos < 4 {
z.pos += 3
} else {
z.pos += 4
}
}
// Pos returns a mark to which can be rewinded.
func (z *Input) Pos() int {
return z.pos - z.start
}
// Rewind rewinds the position to the given position.
func (z *Input) Rewind(pos int) {
z.pos = z.start + pos
}
// Lexeme returns the bytes of the current selection.
func (z *Input) Lexeme() []byte {
return z.buf[z.start:z.pos:z.pos]
}
// Skip collapses the position to the end of the selection.
func (z *Input) Skip() {
z.start = z.pos
}
// Shift returns the bytes of the current selection and collapses the position to the end of the selection.
func (z *Input) Shift() []byte {
b := z.buf[z.start:z.pos:z.pos]
z.start = z.pos
return b
}
// Offset returns the character position in the buffez.
func (z *Input) Offset() int {
return z.pos
}
// Bytes returns the underlying buffez.
func (z *Input) Bytes() []byte {
return z.buf[: len(z.buf)-1 : len(z.buf)-1]
}
// Len returns the length of the underlying buffez.
func (z *Input) Len() int {
return len(z.buf) - 1
}
// Reset resets position to the underlying buffez.
func (z *Input) Reset() {
z.start = 0
z.pos = 0
}
|