Ajout des If, des opérateurs logiques et des boucles While

This commit is contained in:
2025-10-11 23:39:25 +02:00
parent bba863687d
commit e72a52d885
7 changed files with 211 additions and 15 deletions

5
essai.lox Normal file
View File

@@ -0,0 +1,5 @@
var l=3;
while(l>0) {
print l;
l = l-1;
}

View File

@@ -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());
}
}

View File

@@ -37,11 +37,19 @@ pub struct Variable {
pub name: Token,
}
#[derive(Clone)]
pub struct Logical {
pub left: Box<Expr>,
pub operator: Token,
pub right: Box<Expr>,
}
#[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<T> {
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;
}

View File

@@ -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<Statement>, env: &Environment ) {
let previous = self.environment.clone();
fn execute_block( &mut self, statements: &Vec<Statement> ) {
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<Result<Literal, RuntimeError>> for Interpreter {
TokenType::Or => { Err(RuntimeError { message: String::from("Pas encore implémenté.") }) }
_ => { panic!("Parsing error") }
}
}
fn visit_logical(&mut self, l: &Logical) -> Result<Literal, RuntimeError> {
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<Literal, RuntimeError> {
@@ -165,6 +182,7 @@ impl ExprVisitor<Result<Literal, RuntimeError>> 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);
}
}
}

View File

@@ -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

View File

@@ -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<Token>,
@@ -96,8 +97,40 @@ impl Parser {
self.assignment()
}
fn or(&mut self) -> Result<Expr, ParseError> {
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<Expr, ParseError> {
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<Expr, ParseError> {
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<Expr, ParseError> {
@@ -224,10 +257,18 @@ impl Parser {
}
fn statement(&mut self) -> Result<Statement, ParseError> {
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<Statement, ParseError> {
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<Statement, ParseError> {
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<Statement, ParseError> {
match self.expression() {
Ok(e) => {

View File

@@ -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<Statement>,
}
#[derive(Clone)]
pub struct IfStatement {
pub expr: Expr,
pub statement_then: Box<Statement>,
pub statement_else: Option<Box<Statement>>,
}
#[derive(Clone)]
pub struct WhileStatement {
pub condition: Expr,
pub body: Box<Statement>,
}
impl BlockStatement {
pub fn new( statements: Vec<Statement> ) -> Self {
BlockStatement {
@@ -44,4 +59,6 @@ pub trait StatementVisitor<T> {
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;
}