crafting-interpreters/golox/internal/runner/scanner.go

80 lines
1.2 KiB
Go

package runner
type Scanner struct {
source string
// State.
tokens []Token
start int
current int
line int
}
func NewScanner(source string) *Scanner {
return &Scanner{
source: source,
tokens: []Token{},
start: 0,
current: 0,
line: 1,
}
}
func (s *Scanner) ScanTokens() []Token {
for !s.isAtEnd() {
s.start = s.current
s.scanToken()
}
s.tokens = append(s.tokens, NewToken(EOF, "", nil, s.line))
return s.tokens
}
func (s *Scanner) scanToken() {
c := s.advance()
switch c {
case '(':
s.addToken(LPAREN)
case ')':
s.addToken(RPAREN)
case '{':
s.addToken(LBRACE)
case '}':
s.addToken(RBRACE)
case ',':
s.addToken(COMMA)
case '.':
s.addToken(DOT)
case '-':
s.addToken(MINUS)
case '+':
s.addToken(PLUS)
case ';':
s.addToken(SEMI)
case '*':
s.addToken(STAR)
}
}
func (s *Scanner) advance() byte {
idx := s.current
s.current += 1
return s.source[idx]
}
func (s *Scanner) addToken(typ TokenType) {
s.addTokenWithLiteral(typ, nil)
}
func (s *Scanner) addTokenWithLiteral(typ TokenType, literal interface{}) {
lexme := s.source[s.start:s.current]
s.tokens = append(
s.tokens,
NewToken(typ, lexme, literal, s.line),
)
}
func (s *Scanner) isAtEnd() bool {
return s.current >= len(s.source)
}