diff --git a/src/main.rs b/src/main.rs index 5334a02..d4f317e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,29 @@ +mod parser; mod tokenizer; -use std::{env, error::Error, fs}; +use std::{env, error::Error, fs, process}; + +fn compile_file(path: String) -> Result<(), Box> { + let source = fs::read_to_string(path.clone())?; + + // TODO: basename + let tokenizer = tokenizer::Tokenizer::new(path, source); + let tokens = tokenizer.tokenize()?; + let parser = parser::Parser::new(tokens); + + println!("{:#?}", parser.parse()); + + Ok(()) +} fn main() -> Result<(), Box> { let mut args = env::args(); let path = args.nth(1).unwrap(); - let source = fs::read_to_string(path.clone())?; - - // TODO: basename - let tokenizer = tokenizer::Tokenizer::new(path, source); - println!("{:#?}", tokenizer.tokenize()?); + if let Err(err) = compile_file(path) { + eprintln!("{}", err); + process::exit(1); + } Ok(()) } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..13ed650 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,176 @@ +use crate::tokenizer::{MotError, Token, TokenType, error}; + +#[derive(Debug, Clone)] +pub enum Expr { + Binary { + left: Box, + op: Token, + right: Box, + }, + Grouping(Box), + Literal(Token), + Unary { + op: Token, + right: Box, + }, +} + +pub struct Parser { + tokens: Vec, + current: usize, +} + +impl Parser { + pub fn new(tokens: Vec) -> Parser { + Parser { tokens, current: 0 } + } + + pub fn parse(mut self) -> Result { + self.expression() + } + + // TODO: synchronization after parse error + + fn expression(&mut self) -> Result { + self.equality() + } + + fn equality(&mut self) -> Result { + let mut expr = self.comparison()?; + + while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) { + let op = self.previous().clone(); + let right = self.comparison()?; + expr = Expr::Binary { + left: Box::new(expr), + op, + right: Box::new(right), + } + } + + Ok(expr) + } + + fn comparison(&mut self) -> Result { + let mut expr = self.term()?; + + while self.match_token(&[ + TokenType::Greater, + TokenType::GreaterEqual, + TokenType::LessEqual, + TokenType::Less, + ]) { + let op = self.previous().clone(); + let right = self.term()?; + expr = Expr::Binary { + left: Box::new(expr), + op, + right: Box::new(right), + } + } + + Ok(expr) + } + + fn term(&mut self) -> Result { + let mut expr = self.factor()?; + + while self.match_token(&[TokenType::Plus, TokenType::Minus, TokenType::Xor]) { + let op = self.previous().clone(); + let right = self.factor()?; + expr = Expr::Binary { + left: Box::new(expr), + op, + right: Box::new(right), + } + } + + Ok(expr) + } + + fn factor(&mut self) -> Result { + let mut expr = self.unary()?; + + while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Mod]) { + let op = self.previous().clone(); + let right = self.unary()?; + expr = Expr::Binary { + left: Box::new(expr), + op, + right: Box::new(right), + } + } + + Ok(expr) + } + + fn unary(&mut self) -> Result { + if self.match_token(&[TokenType::Bang, TokenType::Minus]) { + let op = self.previous().clone(); + let right = self.unary()?; + return Ok(Expr::Unary { + op, + right: Box::new(right), + }); + } + + self.primary() + } + + fn primary(&mut self) -> Result { + if self.match_token(&[TokenType::Number, TokenType::String]) { + Ok(Expr::Literal(self.previous().clone())) + } else if self.match_token(&[TokenType::LeftParen]) { + let expr = self.expression()?; + self.consume(TokenType::RightParen, "expected ')' after expression")?; + Ok(Expr::Grouping(Box::new(expr))) + } else { + error!(self.peek().loc, "expected expression") + } + } + + fn consume(&mut self, token_type: TokenType, message: &str) -> Result { + if self.check(&token_type) { + Ok(self.advance().clone()) + } else { + error!(self.previous().loc, format!("{}", message)) + } + } + + fn match_token(&mut self, token_types: &[TokenType]) -> bool { + for x in token_types { + if self.check(x) { + self.advance(); + return true; + } + } + false + } + + fn check(&self, token_type: &TokenType) -> bool { + if self.eof() { + false + } else { + self.peek().token_type == *token_type + } + } + + fn advance(&mut self) -> &Token { + if !self.eof() { + self.current += 1; + } + self.previous() + } + + fn peek(&self) -> &Token { + &self.tokens[self.current] + } + + fn previous(&self) -> &Token { + &self.tokens[self.current - 1] + } + + fn eof(&self) -> bool { + self.peek().token_type == TokenType::Eof + } +} diff --git a/src/tokenizer.rs b/src/tokenizer.rs index c2617e6..49086bf 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -183,7 +183,7 @@ impl Tokenizer { while !self.eof() && self.peek() != '"' { if self.peek() == '\n' { self.loc.line += 1; - self.loc.column = 0; + self.loc.column = 1; } self.advance(); } @@ -198,10 +198,10 @@ impl Tokenizer { ' ' | '\t' | '\r' => {} '\n' => { self.loc.line += 1; - self.loc.column = 0; + self.loc.column = 1; } '0'..='9' => self.scan_number(), - 'A'..='z' => self.scan_identifier(), + 'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(), _ => return error!(self.loc, "unexpected character"), } Ok(())