Untitled
rust
a month ago
6.0 kB
6
Indexable
Never
pub mod scanner { #[derive(Debug, PartialEq, Clone)] pub enum TokenType { // single-character tokens LeftParen, RightParen, Comma, Dot, SemiColon, Plus, Minus, Star, Slash, // one or two character tokens Bang, BangEqual, Equal, EqualEqual, Greater, GreaterEqual, Less, LessEqual, // literals Identifier, String, Number, // keywords Print, Let, // other EOF, } #[derive(Debug, PartialEq, Clone)] pub enum Literal { String(String), Number(f64), Boolean(bool), Nil, None, } #[derive(Debug, PartialEq, Clone)] pub struct Token { pub token_type: TokenType, pub lexeme: String, pub literal: Literal, pub line: u32, } impl Token { pub fn new(token_type: TokenType, lexeme: String, literal: Literal, line: u32) -> Token { Token { token_type, lexeme, literal, line, } } } #[derive(Debug, PartialEq, Clone)] pub struct Scanner { source: String, tokens: Vec<Token>, start: usize, current: usize, line: u32, } impl Scanner { fn is_at_end(&mut self) -> bool { self.current >= self.source.len() } fn advance(&mut self) -> char { self.current += 1; self.source.chars().nth(self.current - 1).unwrap() } fn peek(&mut self) -> char { if self.is_at_end() { return '\0'; } self.source.chars().nth(self.current).unwrap() } fn peek_next(&mut self) -> char { if self.current + 1 >= self.source.len() { return '\0'; } self.source.chars().nth(self.current + 1).unwrap() } fn previous(&mut self) -> char { self.source.chars().nth(self.current - 1).unwrap() } fn skip_whitespace(&mut self) { loop { let c = self.peek(); match c { ' ' | '\r' | '\t' => { self.advance(); } '\n' => { self.line += 1; self.advance(); } '/' => { if self.peek_next() == '/' { // A comment goes until the end of the line. while self.peek() != '\n' && !self.is_at_end() { self.advance(); } } else { return; } } _ => return, } } } } impl Scanner { fn add_token(&mut self, token_type: TokenType) { let text = self.source[self.start..self.current].to_string(); self.tokens .push(Token::new(token_type, text, Literal::None, self.line)); } fn add_token_literal(&mut self, token_type: TokenType, literal: Literal) { let text = self.source[self.start..self.current].to_string(); self.tokens .push(Token::new(token_type, text, literal, self.line)); } fn number(&mut self) { while self.peek().is_numeric() { self.advance(); } // Look for a fractional part. if self.peek() == '.' && self.peek_next().is_numeric() { // Consume the "." self.advance(); while self.peek().is_numeric() { self.advance(); } } let number = self.source[self.start..self.current] .parse::<f64>() .unwrap(); self.add_token_literal(TokenType::Number, Literal::Number(number)); } fn scan_token(&mut self) { self.skip_whitespace(); self.start = self.current; let c = self.advance(); match c { '(' => self.add_token(TokenType::LeftParen), ')' => self.add_token(TokenType::RightParen), ',' => self.add_token(TokenType::Comma), '.' => self.add_token(TokenType::Dot), ';' => self.add_token(TokenType::SemiColon), '+' => self.add_token(TokenType::Plus), '-' => self.add_token(TokenType::Minus), '*' => self.add_token(TokenType::Star), '/' => self.add_token(TokenType::Slash), _ => { if c.is_numeric() { self.number(); return; } println!("Unexpected character: {}", c); } } } } impl Scanner { pub fn new(source: String) -> Scanner { Scanner { source, tokens: Vec::new(), start: 0, current: 0, line: 1, } } pub fn scan_tokens(&mut self) -> Vec<Token> { println!("Scanning: {:?}", self.source); while !self.is_at_end() { self.scan_token(); } return self.tokens.clone(); } } } fn main() { //read src/test.script let source = std::fs::read_to_string("src/test.script").expect("Something went wrong reading the file"); let mut scanner = scanner::Scanner::new(source); let tokens = scanner.scan_tokens(); for token in tokens { println!("{:?}", token); } }