1package lexer
2
3// PeekingLexer supports arbitrary lookahead as well as cloning.
4type PeekingLexer struct {
5	cursor int
6	eof    Token
7	tokens []Token
8}
9
10// Upgrade a Lexer to a PeekingLexer with arbitrary lookahead.
11func Upgrade(lex Lexer) (*PeekingLexer, error) {
12	r := &PeekingLexer{}
13	for {
14		t, err := lex.Next()
15		if err != nil {
16			return nil, err
17		}
18		if t.EOF() {
19			r.eof = t
20			break
21		}
22		r.tokens = append(r.tokens, t)
23	}
24	return r, nil
25}
26
27// Cursor position in tokens.
28func (p *PeekingLexer) Cursor() int {
29	return p.cursor
30}
31
32// Next consumes and returns the next token.
33func (p *PeekingLexer) Next() (Token, error) {
34	if p.cursor >= len(p.tokens) {
35		return p.eof, nil
36	}
37	p.cursor++
38	return p.tokens[p.cursor-1], nil
39}
40
41// Peek ahead at the n+1 token. ie. Peek(0) will peek at the next token.
42func (p *PeekingLexer) Peek(n int) (Token, error) {
43	i := p.cursor + n
44	if i >= len(p.tokens) {
45		return p.eof, nil
46	}
47	return p.tokens[i], nil
48}
49
50// Clone creates a clone of this PeekingLexer at its current token.
51//
52// The parent and clone are completely independent.
53func (p *PeekingLexer) Clone() *PeekingLexer {
54	clone := *p
55	return &clone
56}
57