diff --git a/src/main.rs b/src/main.rs index 66129a9..5717056 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,8 @@ mod scanner; mod token; mod token_type; mod expr; +mod astprinter; +mod parser; use crate::rlox_interpreter::RLoxInterpreter; @@ -34,4 +36,4 @@ fn main() { // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // Pause : -// http://www.craftinginterpreters.com/representing-code.html#working-with-trees +// http://www.craftinginterpreters.com/parsing-expressions.html implémentation de comparison diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..d2e0488 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,215 @@ +use crate::expr::{Binary, Expr, Grouping, Unary}; +use crate::expr::Literal::{LiteralBool, LiteralNumber, LiteralString}; +use crate::token::Token; +use crate::token_type::TokenType; + +pub struct Parser { + tokens: Vec, + current: usize +} + +pub struct ParseError { + message: String +} + +impl Parser { + pub fn new( t_init: Vec) -> Self { + Parser { + tokens: t_init, + current: 0 + } + } + + fn match_token( &mut self, token_type_list: &[TokenType] ) -> bool { + for token_type in token_type_list { + if self.check(token_type) { + self.advance(); + return true; + } + } + + return false; + } + + fn check(&self, token_type: &TokenType) -> bool { + if self.is_at_end() { + return false; + } + + return self.peek().token_type==*token_type; + } + + fn advance(&mut self) -> Token { + if !self.is_at_end() { + self.current += 1; + } + return self.previous(); + } + + fn is_at_end(&self) -> bool { + return self.peek().token_type==TokenType::Eof; + } + + fn peek(&self) -> Token { + return self.tokens[self.current].clone(); + } + + fn previous(&self) -> Token { + return self.tokens[self.current - 1].clone(); + } + + fn consume(&mut self, token_type: &TokenType, message: String) -> Result<(), ParseError> { + if self.check(token_type) { + self.advance(); + return Ok(()); + } + + Err(ParseError { + message + }) + } + + fn synchronise(&mut self) { + self.advance(); + + while !self.is_at_end() { + if self.previous().token_type == TokenType::Semicolon { + return; + } + + match self.peek().token_type { + TokenType::Class => return, + TokenType::Fun => return, + TokenType::Var => return, + TokenType::For => return, + TokenType::If => return, + TokenType::While => return, + TokenType::Print => return, + TokenType::Return => return, + _ => (), + } + + self.advance(); + } + } + + fn expression(&mut self) -> Result { + self.equality() + } + + fn equality(&mut self) -> Result { + let mut expr: Expr = self.comparison()?; + + while self.match_token( &[TokenType::BangEqual, TokenType::EqualEqual]) { + let operator: Token = self.previous(); + let right: Expr = self.comparison()?; + expr = Expr::BinaryExpr(Binary{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + return Ok(expr); + } + + fn comparison(&mut self) -> Result { + let mut expr = self.term()?; + + while self.match_token(&[TokenType::Greater, TokenType::GreaterEqual, TokenType::Less, TokenType::LessEqual]) { + let operator = self.previous(); + let right = self.term()?; + expr = Expr::BinaryExpr(Binary{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + return Ok(expr); + } + + fn term(&mut self) -> Result { + let mut expr = self.factor()?; + + while self.match_token(&[TokenType::Minus, TokenType::Plus]) { + let operator = self.previous(); + let right = self.factor()?; + expr = Expr::BinaryExpr(Binary{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + return Ok(expr); + } + + fn factor(&mut self) -> Result { + let mut expr = self.unary()?; + + while self.match_token(&[TokenType::Star, TokenType::Slash]) { + let operator = self.previous(); + let right = self.unary()?; + expr = Expr::BinaryExpr(Binary{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + return Ok(expr); + } + + fn unary(&mut self) -> Result { + if self.match_token(&[TokenType::Bang, TokenType::Minus]) { + let operator = self.previous(); + let right = self.unary()?; + return Ok(Expr::UnaryExpr(Unary { + operator, + right: Box::new(right) + })); + } + + self.primary() + } + + fn primary(&mut self) -> Result { + if self.match_token(&[TokenType::False]) { + return Ok(Expr::LiteralExpr(LiteralBool(false))); + } + if self.match_token(&[TokenType::True]) { + return Ok(Expr::LiteralExpr(LiteralBool(true))); + } + if self.match_token(&[TokenType::Nil]) { + return Ok(Expr::LiteralExpr(LiteralBool(false))); + } + if self.match_token(&[TokenType::Number]) { + return Ok(Expr::LiteralExpr(LiteralNumber(self.previous().literal.parse::().unwrap()))); + } + if self.match_token(&[TokenType::String]) { + return Ok(Expr::LiteralExpr(LiteralString(self.previous().literal))); + } + if self.match_token(&[TokenType::LeftParen]) { + let expr = self.expression()?; + self.consume(&TokenType::RightParen, String::from("Expect ')' after expression."))?; + return Ok(Expr::GroupingExpr(Grouping { + expression: Box::new(expr) + })); + } else { + Err(ParseError { + message: String::from("Unexpected token : expression expected.") + }) + } + } + + pub fn parse(&mut self) -> Option { + match self.expression() { + Ok(expr) => Some(expr), + Err(error) => { + println!("Error while parsing expression : {}",error.message); + None + } + } + } +} \ No newline at end of file diff --git a/src/rlox_interpreter.rs b/src/rlox_interpreter.rs index 850cfcb..f4bc270 100644 --- a/src/rlox_interpreter.rs +++ b/src/rlox_interpreter.rs @@ -1,6 +1,9 @@ use std::{fs, io}; use crate::EX_OK; use std::io::Write; +use crate::astprinter::ASTPrinter; +use crate::expr::ExprVisitor; +use crate::parser::Parser; use crate::scanner::Scanner; @@ -40,15 +43,15 @@ impl RLoxInterpreter { fn run(&self, src: String) -> i32 { let mut scanner = Scanner::new( src ); - scanner.scan_tokens(); - let mut current_line = 0; - for t in scanner.tokens { - if t.line!=current_line { - current_line = t.line; - println!("-- line {} --------------------", current_line); - } - println!("{}\t{}\t{}", t.token_type, t.lexeme, t.literal); + + let mut parser = Parser::new( scanner.tokens ); + match parser.parse() { + Some(expr) => { + let printer = ASTPrinter; + printer.visit_expr(&expr); + }, + None => println!("An error occurred while parsing expression.") } EX_OK diff --git a/src/token.rs b/src/token.rs index deecce1..0917303 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,6 +1,6 @@ use crate::token_type::TokenType; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Token { pub token_type: TokenType, pub lexeme: String,