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