2020-11-23 02:00:02 +01:00
|
|
|
use crate::errors::{Error, ErrorKind};
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum TokenKind {
|
|
|
|
// Single-character tokens.
|
|
|
|
LeftParen,
|
|
|
|
RightParen,
|
|
|
|
LeftBrace,
|
|
|
|
RightBrace,
|
|
|
|
Comma,
|
|
|
|
Dot,
|
|
|
|
Minus,
|
|
|
|
Plus,
|
|
|
|
Semicolon,
|
|
|
|
Slash,
|
|
|
|
Star,
|
|
|
|
|
|
|
|
// One or two character tokens.
|
|
|
|
Bang,
|
|
|
|
BangEqual,
|
|
|
|
Equal,
|
|
|
|
EqualEqual,
|
|
|
|
Greater,
|
|
|
|
GreaterEqual,
|
|
|
|
Less,
|
|
|
|
LessEqual,
|
|
|
|
|
|
|
|
// Literals.
|
|
|
|
Identifier,
|
|
|
|
String,
|
|
|
|
Number,
|
|
|
|
|
|
|
|
// Keywords.
|
|
|
|
And,
|
|
|
|
Class,
|
|
|
|
Else,
|
|
|
|
False,
|
|
|
|
Fun,
|
|
|
|
For,
|
|
|
|
If,
|
|
|
|
Nil,
|
|
|
|
Or,
|
|
|
|
Print,
|
|
|
|
Return,
|
|
|
|
Super,
|
|
|
|
This,
|
|
|
|
True,
|
|
|
|
Var,
|
|
|
|
While,
|
|
|
|
|
|
|
|
// Special things
|
|
|
|
Eof,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Token<'a> {
|
|
|
|
kind: TokenKind,
|
2020-11-27 17:55:38 +01:00
|
|
|
lexeme: &'a [char],
|
2020-11-23 02:00:02 +01:00
|
|
|
// literal: Object, // TODO(tazjin): Uhh?
|
|
|
|
line: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Scanner<'a> {
|
2020-11-27 17:55:38 +01:00
|
|
|
source: &'a [char],
|
2020-11-23 02:00:02 +01:00
|
|
|
tokens: Vec<Token<'a>>,
|
|
|
|
errors: Vec<Error>,
|
|
|
|
start: usize, // offset of first character in current lexeme
|
|
|
|
current: usize, // current offset into source
|
|
|
|
line: usize, // current line in source
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Scanner<'a> {
|
|
|
|
fn is_at_end(&self) -> bool {
|
|
|
|
return self.current >= self.source.len();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn advance(&mut self) -> char {
|
|
|
|
self.current += 1;
|
2020-11-27 17:55:38 +01:00
|
|
|
self.source[self.current-1]
|
2020-11-23 02:00:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn add_token(&mut self, kind: TokenKind) {
|
|
|
|
let lexeme = &self.source[self.start..self.current];
|
|
|
|
self.tokens.push(Token {
|
|
|
|
kind,
|
|
|
|
lexeme,
|
|
|
|
line: self.line,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn scan_token(&mut self) {
|
|
|
|
match self.advance() {
|
|
|
|
'(' => self.add_token(TokenKind::LeftParen),
|
|
|
|
')' => self.add_token(TokenKind::RightParen),
|
|
|
|
'{' => self.add_token(TokenKind::LeftBrace),
|
|
|
|
'}' => self.add_token(TokenKind::RightBrace),
|
|
|
|
',' => self.add_token(TokenKind::Comma),
|
|
|
|
'.' => self.add_token(TokenKind::Dot),
|
|
|
|
'-' => self.add_token(TokenKind::Minus),
|
|
|
|
'+' => self.add_token(TokenKind::Plus),
|
|
|
|
';' => self.add_token(TokenKind::Semicolon),
|
|
|
|
'*' => self.add_token(TokenKind::Star),
|
|
|
|
|
|
|
|
unexpected => self.errors.push(Error {
|
|
|
|
line: self.line,
|
|
|
|
kind: ErrorKind::UnexpectedChar(unexpected),
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
fn scan_tokens(mut self) -> Vec<Token<'a>> {
|
|
|
|
while !self.is_at_end() {
|
|
|
|
self.start = self.current;
|
|
|
|
self.scan_token();
|
|
|
|
}
|
|
|
|
|
|
|
|
return self.tokens;
|
|
|
|
}
|
|
|
|
}
|