void ProduceStringLiteral() { while (Peek() != '"' && !IsAtEnd()) { if (Peek() == '\n') { _line++; } Consume(); } if (IsAtEnd()) { Lox.StaticError(_line, "Unterminated string."); return; } Consume(); var length = _currentCharacter - _startOfNextLexeme; var literal = Source.Substring(_startOfNextLexeme + 1, length - 2); ProduceToken(TokenType.String, literal); }
void ScanToken() { var character = Consume(); switch (character) { case '(': ProduceToken(TokenType.LeftParen); break; case ')': ProduceToken(TokenType.RightParen); break; case '{': ProduceToken(TokenType.LeftBrace); break; case '}': ProduceToken(TokenType.RightBrace); break; case ',': ProduceToken(TokenType.Comma); break; case '.': ProduceToken(TokenType.Dot); break; case '-': ProduceToken(TokenType.Minus); break; case '+': ProduceToken(TokenType.Plus); break; case ';': ProduceToken(TokenType.SemiColon); break; case '*': ProduceToken(TokenType.Star); break; case '!': ProduceToken(MaybeConsume('=') ? TokenType.BangEqual : TokenType.Bang); break; case '=': ProduceToken(MaybeConsume('=') ? TokenType.EqualEqual : TokenType.Equal); break; case '<': ProduceToken(MaybeConsume('=') ? TokenType.LessEqual : TokenType.Less); break; case '>': ProduceToken(MaybeConsume('=') ? TokenType.GreaterEqual : TokenType.Greater); break; case '/': if (MaybeConsume('/')) { while (Peek() != '\n' && !IsAtEnd()) { Consume(); } } else { ProduceToken(TokenType.Slash); } break; case '"': ProduceStringLiteral(); break; case char digit when char.IsDigit(digit): ProduceNumericLiteral(); break; case char alpha when char.IsLetter(alpha): ProduceIdentifier(); break; case ' ': case '\t': case '\r': break; case '\n': _line++; break; default: Lox.StaticError(_line, $"Unexpected character '{character}'."); break; } }
Exception CreateStaticError(Token badToken, string message) { Lox.StaticError(badToken.Line, $"At '{badToken.Lexeme}'. {message}"); return(new LoxStaticErrorException(badToken, message)); }