Untitled
unknown
rust
2 years ago
6.0 kB
17
Indexable
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);
}
}
Editor is loading...