GoLexer/scanner.go
2025-02-19 23:25:55 +00:00

74 lines
1.1 KiB
Go

package main
type Scanner struct {
source string
cursor int
}
func (s *Scanner) Consume() Token {
if s.cursor >= len(s.source) {
return Token{kind: "eof", lexeme: "EOF"}
}
s.readWhile(isWhitespace)
next := s.peek()
if isDigit(next) {
lexeme := s.readWhile(isDigit)
return Token{kind: "number", lexeme: lexeme}
}
kind, ok := kinds[next]
if ok {
lexeme := s.read()
return Token{kind: kind, lexeme: string(lexeme)}
}
lexeme := s.readWhile(notWhitespace)
return Token{kind: "unknown", lexeme: lexeme}
}
func (s *Scanner) peek() rune {
if s.cursor >= len(s.source) {
return 0
}
return rune(s.source[s.cursor])
}
func (s *Scanner) read() rune {
c := rune(s.source[s.cursor])
s.cursor += 1
return c
}
func (s *Scanner) readWhile(predicate func(rune) bool) string {
lexeme := ""
c := s.peek()
for s.cursor < len(s.source) && predicate(c) {
lexeme += string(s.read())
c = s.peek()
}
return lexeme
}
func isWhitespace(c rune) bool {
return c == ' ' || c == '\t' || c == '\n'
}
func notWhitespace(c rune) bool {
return !isWhitespace(c)
}
func isDigit(c rune) bool {
return '0' <= c && c <= '9'
}