From e72a52d885b34f42426a1576a4c4a4ddeffe451e Mon Sep 17 00:00:00 2001 From: Manu Date: Sat, 11 Oct 2025 23:39:25 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20des=20If,=20des=20op=C3=A9rateurs=20log?= =?UTF-8?q?iques=20et=20des=20boucles=20While?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- essai.lox | 5 ++++ src/astprinter.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++-- src/expr.rs | 9 ++++++ src/interpreter.rs | 51 +++++++++++++++++++++++++++------ src/main.rs | 2 +- src/parser.rs | 71 +++++++++++++++++++++++++++++++++++++++++++--- src/stmt.rs | 17 +++++++++++ 7 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 essai.lox diff --git a/essai.lox b/essai.lox new file mode 100644 index 0000000..475bef7 --- /dev/null +++ b/essai.lox @@ -0,0 +1,5 @@ +var l=3; +while(l>0) { + print l; + l = l-1; +} \ No newline at end of file diff --git a/src/astprinter.rs b/src/astprinter.rs index 1056b19..d4ea41d 100644 --- a/src/astprinter.rs +++ b/src/astprinter.rs @@ -1,5 +1,5 @@ -use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; -use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement}; +use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable, Logical}; +use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement, IfStatement, WhileStatement}; pub struct ASTPrinter { pub(crate) depth: u32 @@ -60,6 +60,7 @@ impl ExprVisitor<()> for ASTPrinter { Expr::UnaryExpr(u) => { self.visit_unary(u); } Expr::VariableExpr(v) => { self.visit_variable(v); } Expr::AssignExpr(a) => { self.visit_assign(a); } + Expr::LogicalExpr(l) => { self.visit_logical(l); } } } @@ -74,6 +75,21 @@ impl ExprVisitor<()> for ASTPrinter { self.depth-=1; print!(") "); } + + fn visit_logical(&mut self, l: &Logical) { + println!("{}LOGICAL",self.ast_tab()); + println!("{}op='{}'", self.ast_tab(), l.operator.lexeme); + println!("{}left=(", self.ast_tab()); + self.depth+=1; + self.visit_expr(&*l.left); + self.depth-=1; + println!("{})", self.ast_tab()); + println!("{}right=(", self.ast_tab()); + self.depth+=1; + self.visit_expr(&*l.right); + self.depth-=1; + println!("{})", self.ast_tab()); + } } impl StatementVisitor<()> for ASTPrinter { @@ -117,12 +133,63 @@ impl StatementVisitor<()> for ASTPrinter { print!(") "); } + fn visit_if_stmt(&mut self, i: &IfStatement) -> () { + println!("{} IF_STMT(", self.ast_tab()); + self.depth+=1; + + println!("{} IF_EXPR(", self.ast_tab()); + self.depth+=1; + self.visit_expr(&i.expr); + self.depth-=1; + println!("{} )", self.ast_tab()); + + println!("{} IF_THEN(", self.ast_tab()); + self.depth+=1; + self.visit_stmt(&i.statement_then); + self.depth-=1; + println!("{} )", self.ast_tab()); + + match i.statement_else.clone() { + Some(s) => { + println!("{} IF_ELSE(", self.ast_tab()); + self.depth+=1; + self.visit_stmt(&s); + self.depth-=1; + println!("{} )", self.ast_tab()); + } + None => {} + } + + self.depth-=1; + print!(") "); + } + fn visit_stmt(&mut self, s: &Statement) -> () { match s { Statement::Expression(e) => { self.visit_expr_stmt(&e) } Statement::Print(p) => { self.visit_print(&p) } Statement::Var(v) => { self.visit_var_stmt(&v) } Statement::Block(b) => { self.visit_block_stmt(&b) } + Statement::If(i) => { self.visit_if_stmt(&i) } + Statement::While(w) => { self.visit_while_stmt(&w) } } } + + fn visit_while_stmt(&mut self, w: &WhileStatement) -> () { + println!("{} WHILE_STMT(", self.ast_tab()); + self.depth+=1; + + println!("{} WHILE_COND(", self.ast_tab()); + self.depth+=1; + self.visit_expr(&w.condition); + self.depth-=1; + println!("{} )", self.ast_tab()); + + println!("{} WHILE_BODY(", self.ast_tab()); + self.depth+=1; + self.visit_stmt(&w.body); + self.depth-=1; + println!("{} )", self.ast_tab()); + + } } \ No newline at end of file diff --git a/src/expr.rs b/src/expr.rs index 1542b72..86af49f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -37,11 +37,19 @@ pub struct Variable { pub name: Token, } +#[derive(Clone)] +pub struct Logical { + pub left: Box, + pub operator: Token, + pub right: Box, +} + #[derive(Clone)] pub enum Expr { BinaryExpr(Binary), GroupingExpr(Grouping), LiteralExpr(Literal), + LogicalExpr(Logical), UnaryExpr(Unary), VariableExpr(Variable), AssignExpr(Assign), @@ -55,5 +63,6 @@ pub trait ExprVisitor { fn visit_expr(&mut self, e: &Expr) -> T; fn visit_variable(&mut self, v: &Variable) -> T; fn visit_assign(&mut self, a: &Assign) -> T; + fn visit_logical(&mut self, l: &Logical) -> T; } diff --git a/src/interpreter.rs b/src/interpreter.rs index 684fc9b..9d9051a 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -3,8 +3,8 @@ use crate::expr::Literal::LiteralString; use crate::expr::Literal::LiteralNumber; use crate::expr::Literal::LiteralBool; use crate::expr::Literal::LiteralNil; -use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; -use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement}; +use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable, Logical}; +use crate::stmt::{BlockStatement, ExpressionStatement, IfStatement, PrintStatement, Statement, StatementVisitor, VarStatement, WhileStatement}; use crate::token_type::TokenType; pub struct Interpreter { @@ -18,15 +18,16 @@ impl Interpreter { } } - fn execute_block( &mut self, statements: &Vec, env: &Environment ) { - let previous = self.environment.clone(); + fn execute_block( &mut self, statements: &Vec ) { + let new_env = Environment::new(Some(Box::new(self.environment.clone()))); + self.environment = new_env; - self.environment = (*env).clone(); for s in statements { self.visit_stmt(s); } - self.environment = previous; + let old_env = self.environment.clone().enclosing.unwrap(); + self.environment = *old_env; } } @@ -132,7 +133,23 @@ impl ExprVisitor> for Interpreter { TokenType::Or => { Err(RuntimeError { message: String::from("Pas encore implémenté.") }) } _ => { panic!("Parsing error") } } + } + fn visit_logical(&mut self, l: &Logical) -> Result { + let left = self.visit_expr(&*l.left)?; + if l.operator.token_type==TokenType::Or { + if is_truthy(&left) { + Ok(left) + } else { + Ok(self.visit_expr(&*l.right)?) + } + } else { + if !is_truthy(&left) { + Ok(left) + } else { + Ok(self.visit_expr(&*l.right)?) + } + } } fn visit_grouping(&mut self, g: &Grouping) -> Result { @@ -165,6 +182,7 @@ impl ExprVisitor> for Interpreter { Expr::UnaryExpr(u) => { Ok(self.visit_unary(&u)?) } Expr::VariableExpr(v) => { Ok(self.visit_variable(&v)?) } Expr::AssignExpr(a) => { Ok(self.visit_assign(&a)?) } + Expr::LogicalExpr(l) => { Ok(self.visit_logical(&l)?) } } } @@ -187,6 +205,8 @@ impl StatementVisitor<()> for Interpreter { Statement::Print(p) => { self.visit_print(p); } Statement::Var(v) => { self.visit_var_stmt(v); } Statement::Block(b) => { self.visit_block_stmt(b); } + Statement::If(b) => { self.visit_if_stmt(b); } + Statement::While(w) => { self.visit_while_stmt(w); } } } @@ -217,9 +237,24 @@ impl StatementVisitor<()> for Interpreter { } fn visit_block_stmt(&mut self, b: &BlockStatement) { - let mut new_env = Environment::new(Some(Box::new(self.environment.clone()))); + self.execute_block(&b.statements ); + } - self.execute_block(&b.statements, &new_env ); + fn visit_if_stmt(&mut self, i: &IfStatement) { + if is_truthy( &&self.visit_expr(&i.expr).unwrap()) { + self.visit_stmt(& i.statement_then); + } else { + match &i.statement_else { + Some(stmt_else) => { self.visit_stmt(stmt_else); } + None => {} + } + } + } + + fn visit_while_stmt(&mut self, w: &WhileStatement) -> () { + while is_truthy( &&self.visit_expr(&w.condition).unwrap()) { + self.visit_stmt(& w.body); + } } } diff --git a/src/main.rs b/src/main.rs index 27d3792..5c280de 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,4 +95,4 @@ fn run(src: String) -> i32 { // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // Pause : -// http://www.craftinginterpreters.com/control-flow.html +// https://www.craftinginterpreters.com/control-flow.html#for-loops diff --git a/src/parser.rs b/src/parser.rs index 9852df2..e737f09 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,9 @@ -use crate::expr::{Assign, Binary, Expr, Grouping, Unary, Variable}; +use crate::expr::{Assign, Binary, Expr, Grouping, Unary, Variable, Logical}; +use crate::expr::Expr::LogicalExpr; use crate::expr::Literal::{LiteralBool, LiteralNumber, LiteralString}; use crate::token::Token; use crate::token_type::TokenType; -use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, VarStatement}; +use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, VarStatement, IfStatement, WhileStatement}; pub struct Parser { tokens: Vec, @@ -96,8 +97,40 @@ impl Parser { self.assignment() } + fn or(&mut self) -> Result { + let mut expr = self.and()?; + + while self.match_token(&[TokenType::Or]) { + let operator = self.previous(); + let right = self.and()?; + expr = Expr::LogicalExpr(Logical{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + Ok(expr) + } + + fn and(&mut self) -> Result { + let mut expr = self.equality()?; + + while self.match_token(&[TokenType::And]) { + let operator = self.previous(); + let right = self.equality()?; + expr = Expr::LogicalExpr(Logical{ + left: Box::new(expr), + operator, + right: Box::new(right) + }); + } + + Ok(expr) + } + fn assignment(&mut self) -> Result { - let expr = self.equality()?; + let expr = self.or()?; if self.match_token(&[TokenType::Equal]) { let value = Box::new(self.assignment()?); // l'assignation a une associativité par la droite @@ -126,7 +159,7 @@ impl Parser { }); } - return Ok(expr); + Ok(expr) } fn comparison(&mut self) -> Result { @@ -224,10 +257,18 @@ impl Parser { } fn statement(&mut self) -> Result { + if self.match_token(&[TokenType::If]) { + return self.if_statement(); + } + if self.match_token(&[TokenType::Print]) { return self.print_statement(); } + if self.match_token(&[TokenType::While]) { + return self.while_statement(); + } + if self.match_token(&[TokenType::LeftBrace]) { return self.block_statement(); } @@ -257,6 +298,28 @@ impl Parser { } } + fn while_statement(&mut self) -> Result { + self.consume(&TokenType::LeftParen, String::from("( attendu"))?; + let condition = self.expression()?; + self.consume(&TokenType::RightParen, String::from(") attendu"))?; + let body = self.statement()?; + + Ok(Statement::While(WhileStatement{ condition, body: Box::new(body) })) + } + + fn if_statement(&mut self) -> Result { + self.consume(&TokenType::LeftParen, String::from("( attendu"))?; + let expr = self.expression()?; + self.consume(&TokenType::RightParen, String::from(") attendu"))?; + let then_stmt = self.statement()?; + if self.match_token(&[TokenType::Else]) { + let else_stmt = self.statement()?; + Ok(Statement::If(IfStatement{ expr, statement_then: Box::new(then_stmt), statement_else: Some(Box::new(else_stmt))})) + } else { + Ok(Statement::If(IfStatement{ expr, statement_then: Box::new(then_stmt), statement_else: None})) + } + } + fn expr_statement(&mut self) -> Result { match self.expression() { Ok(e) => { diff --git a/src/stmt.rs b/src/stmt.rs index 6d05a21..5ffe1c8 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -7,6 +7,8 @@ pub enum Statement { Print(PrintStatement), Var(VarStatement), Block(BlockStatement), + If(IfStatement), + While(WhileStatement), } #[derive(Clone)] @@ -30,6 +32,19 @@ pub struct BlockStatement { pub statements: Vec, } +#[derive(Clone)] +pub struct IfStatement { + pub expr: Expr, + pub statement_then: Box, + pub statement_else: Option>, +} + +#[derive(Clone)] +pub struct WhileStatement { + pub condition: Expr, + pub body: Box, +} + impl BlockStatement { pub fn new( statements: Vec ) -> Self { BlockStatement { @@ -44,4 +59,6 @@ pub trait StatementVisitor { fn visit_print(&mut self, p: &PrintStatement) -> T; fn visit_var_stmt(&mut self, v: &VarStatement) -> T; fn visit_block_stmt(&mut self, b: &BlockStatement) -> T; + fn visit_if_stmt(&mut self, i: &IfStatement) -> T; + fn visit_while_stmt(&mut self, w: &WhileStatement) -> T; }