package lox type Lexer struct { start int current int line int column int source []rune tokens []Token } func (lexer Lexer) lex() { for !lexer.eof() { lexer.start = lexer.current c := lexer.advance() switch c { case '(': lexer.addToken(LeftParen) case ')': lexer.addToken(RightParen) case '{': lexer.addToken(LeftBrace) case '}': lexer.addToken(RightBrace) case ',': lexer.addToken(Comma) case '.': lexer.addToken(Dot) case '-': lexer.addToken(Minus) case '+': lexer.addToken(Plus) case ';': lexer.addToken(Semicolon) case '*': lexer.addToken(Star) case '!': if lexer.match('=') { lexer.addToken(BangEqual) } else { lexer.addToken(Bang) } case '=': if lexer.match('=') { lexer.addToken(EqualEqual) } else { lexer.addToken(Equal) } case '<': if lexer.match('=') { lexer.addToken(LessEqual) } else { lexer.addToken(Less) } case '>': if lexer.match('=') { lexer.addToken(GreaterEqual) } else { lexer.addToken(Greater) } case '/': if lexer.match('/') { for lexer.peek() != '\n' && !lexer.eof() { lexer.advance() } } else { lexer.addToken(Slash) } case ' ', '\r', '\t': // Ignore whitespace continue case '\n': lexer.line++ lexer.column = 0 case '"': for lexer.peek() != '"' && !lexer.eof() { if lexer.peek() == '\n' { lexer.line++ lexer.column-- } lexer.advance() } // if lexer.eof() { // // Add error (unterminated string) // } // Consume the terminating " lexer.advance() //value := lexer.source[lexer.start+1 : lexer.current-1] //lexer.addToken(String, value) } } lexer.addToken(Eof) } func (s *Lexer) addToken(tt TokenType) { s.tokens = append(s.tokens, *makeToken(tt, "", nil, s.line, s.column)) } // eof returns true if the read pointer has reached the end of the source file func (s Lexer) eof() bool { return s.current >= len(s.source) } // peek looks one rune ahead without advancing the cursor func (s Lexer) peek() rune { if s.eof() { return '\u0004' // emit end of file character } return s.source[s.current] } // advance increments the read pointer and returns the rune at that position func (s *Lexer) advance() rune { r := s.source[s.current] s.current++ s.column++ return r } // match tried to match a single rune and advances the read pointer if it does. func (s *Lexer) match(expected rune) bool { if s.eof() { return false } if s.source[s.current] != expected { return false } s.current++ s.column++ return true } func newLexer(source string) *Lexer { return &Lexer{line: 1, column: 0, source: []rune(source)} }