105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
package lexer
|
|
|
|
// PeekingLexer supports arbitrary lookahead as well as cloning.
|
|
type PeekingLexer struct {
|
|
rawCursor RawCursor
|
|
cursor int
|
|
eof Token
|
|
tokens []Token
|
|
elide map[TokenType]bool
|
|
}
|
|
|
|
// RawCursor index in the token stream.
|
|
type RawCursor int
|
|
|
|
var _ Lexer = &PeekingLexer{}
|
|
|
|
// Upgrade a Lexer to a PeekingLexer with arbitrary lookahead.
|
|
//
|
|
// "elide" is a slice of token types to elide from processing.
|
|
func Upgrade(lex Lexer, elide ...TokenType) (*PeekingLexer, error) {
|
|
r := &PeekingLexer{
|
|
elide: make(map[TokenType]bool, len(elide)),
|
|
}
|
|
for _, rn := range elide {
|
|
r.elide[rn] = true
|
|
}
|
|
for {
|
|
t, err := lex.Next()
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
if t.EOF() {
|
|
r.eof = t
|
|
break
|
|
}
|
|
r.tokens = append(r.tokens, t)
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// Range returns the slice of tokens between the two cursor points.
|
|
func (p *PeekingLexer) Range(rawStart, rawEnd RawCursor) []Token {
|
|
return p.tokens[rawStart:rawEnd]
|
|
}
|
|
|
|
// Cursor position in tokens, excluding elided tokens.
|
|
func (p *PeekingLexer) Cursor() int {
|
|
return p.cursor
|
|
}
|
|
|
|
// RawCursor position in tokens, including elided tokens.
|
|
func (p *PeekingLexer) RawCursor() RawCursor {
|
|
return p.rawCursor
|
|
}
|
|
|
|
// Next consumes and returns the next token.
|
|
func (p *PeekingLexer) Next() (Token, error) {
|
|
for int(p.rawCursor) < len(p.tokens) {
|
|
t := p.tokens[p.rawCursor]
|
|
p.rawCursor++
|
|
if p.elide[t.Type] {
|
|
continue
|
|
}
|
|
p.cursor++
|
|
return p.tokens[p.rawCursor-1], nil
|
|
}
|
|
return p.eof, nil
|
|
}
|
|
|
|
// Peek ahead at the n+1 token. eg. Peek(0) will peek at the next token.
|
|
func (p *PeekingLexer) Peek(n int) (Token, error) {
|
|
for i := int(p.rawCursor); i < len(p.tokens); i++ {
|
|
t := p.tokens[i]
|
|
if p.elide[t.Type] {
|
|
continue
|
|
}
|
|
if n == 0 {
|
|
return t, nil
|
|
}
|
|
n--
|
|
}
|
|
return p.eof, nil
|
|
}
|
|
|
|
// RawPeek peeks ahead at the raw token n+1. eg. RawPeek(0) will peek at the next token.
|
|
//
|
|
// Unlike Peek, this will include elided tokens.
|
|
func (p *PeekingLexer) RawPeek(n int) (Token, error) {
|
|
for i := int(p.rawCursor); i < len(p.tokens); i++ {
|
|
t := p.tokens[i]
|
|
if n == 0 {
|
|
return t, nil
|
|
}
|
|
n--
|
|
}
|
|
return p.eof, nil
|
|
}
|
|
|
|
// Clone creates a clone of this PeekingLexer at its current token.
|
|
//
|
|
// The parent and clone are completely independent.
|
|
func (p *PeekingLexer) Clone() *PeekingLexer {
|
|
clone := *p
|
|
return &clone
|
|
}
|