From 6ed3e4c68ca718a5bc1ad9750e4865c36314c2da Mon Sep 17 00:00:00 2001 From: Emmanuel BERNAT Date: Wed, 12 Jun 2024 22:15:26 +0200 Subject: [PATCH] Blocs d'instructions --- src/astprinter.rs | 21 ++++++++++++++++++++- src/environment.rs | 19 ++++++++++++++++--- src/interpreter.rs | 34 +++++++++++++++++++++++++++++----- src/main.rs | 20 ++++++-------------- src/parser.rs | 24 ++++++++++++++++++++---- src/stmt.rs | 16 ++++++++++++++++ 6 files changed, 107 insertions(+), 27 deletions(-) diff --git a/src/astprinter.rs b/src/astprinter.rs index 5da275f..1056b19 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::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; +use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement}; pub struct ASTPrinter { pub(crate) depth: u32 @@ -106,4 +106,23 @@ impl StatementVisitor<()> for ASTPrinter { self.depth-=1; print!(") "); } + + fn visit_block_stmt(&mut self, b: &BlockStatement) -> () { + println!("{} BLOCK_STMT(", self.ast_tab()); + self.depth+=1; + for s in &b.statements { + self.visit_stmt(s); + } + 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) } + } + } } \ No newline at end of file diff --git a/src/environment.rs b/src/environment.rs index 6f8766d..e37805d 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -2,14 +2,17 @@ use std::collections::HashMap; use crate::expr::Literal; use crate::interpreter::RuntimeError; +#[derive(Clone)] pub struct Environment { pub values: HashMap, + pub enclosing: Option>, } impl Environment { pub fn new() -> Self { Environment { - values : HashMap::new() + values : HashMap::new(), + enclosing: None, } } @@ -20,7 +23,13 @@ impl Environment { pub fn get(&self, name: &String) -> Result { match self.values.get(name) { Some(s) => { Ok(s.clone()) } , - None => { Err(RuntimeError { message: format!("Variable {} non définie", name) } ) } + None => { + if let Some(encl) = &self.enclosing { + encl.get(name) + } else { + Err(RuntimeError { message: format!("Variable {} non définie", name) } ) + } + } } } @@ -29,7 +38,11 @@ impl Environment { self.values.insert(name, value); Ok(()) } else { - Err(RuntimeError { message: String::from("Undefined variable")}) + if let Some(encl) = &mut self.enclosing { + encl.assign(name, value) + } else { + Err(RuntimeError { message: format!("Variable {} non définie", name) } ) + } } } } \ No newline at end of file diff --git a/src/interpreter.rs b/src/interpreter.rs index b406cb6..f188de8 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -4,7 +4,7 @@ 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::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; +use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement}; use crate::token_type::TokenType; pub struct Interpreter { @@ -17,6 +17,17 @@ impl Interpreter { environment: Environment::new() } } + + fn execute_block( &mut self, statements: &Vec, env: &Environment ) { + let previous = self.environment.clone(); + + self.environment = (*env).clone(); + for s in statements { + self.visit_stmt(s); + } + + self.environment = previous; + } } #[derive(Debug)] @@ -157,19 +168,28 @@ impl ExprVisitor> for Interpreter { } } + fn visit_variable(&mut self, v: &Variable) -> Result { + self.environment.get(&v.name.literal) + } + fn visit_assign(&mut self, a: &Assign) -> Result { let value = self.visit_expr(&a.value)?; self.environment.assign(a.name.literal.clone(), value.clone())?; Ok(value) } - - fn visit_variable(&mut self, v: &Variable) -> Result { - self.environment.get(&v.name.literal) - } } impl StatementVisitor<()> for Interpreter { + 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); } + } + } + fn visit_expr_stmt(&mut self, e: &ExpressionStatement) { self.visit_expr(&e.expr).expect("Erreur pendant l'évaluation de l'expression."); } @@ -195,6 +215,10 @@ impl StatementVisitor<()> for Interpreter { None => {} } } + + fn visit_block_stmt(&mut self, b: &BlockStatement) { + self.execute_block(&b.statements, &Environment::new() ); + } } diff --git a/src/main.rs b/src/main.rs index b6106a2..0a3cae2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ mod stmt; mod environment; use crate::scanner::Scanner; -use crate::stmt::{Statement, StatementVisitor}; +use crate::stmt::StatementVisitor; // Exit codes from #include const EX_OK: i32 = 0; @@ -77,22 +77,14 @@ fn run(src: String) -> i32 { println!("AST"); let mut printer = ASTPrinter { depth: 0 }; - for s in program.clone() { - match s { - Statement::Expression(e) => { printer.visit_expr_stmt(&e) } - Statement::Print(p) => { printer.visit_print(&p) } - Statement::Var(v) => { printer.visit_var_stmt(&v) } - } + for s in &program { + printer.visit_stmt(s); } println!("Interpretation"); let mut interpreter = Interpreter::new(); - for s in program { - match s { - Statement::Expression(e) => { interpreter.visit_expr_stmt(&e) } - Statement::Print(p) => { interpreter.visit_print(&p) } - Statement::Var(v) => { interpreter.visit_var_stmt(&v) } - } + for s in &program { + interpreter.visit_stmt(s); } EX_OK @@ -103,4 +95,4 @@ fn run(src: String) -> i32 { // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // Pause : -// http://www.craftinginterpreters.com/statements-and-state.html#assignment +// http://www.craftinginterpreters.com/statements-and-state.html#block-syntax-and-semantics (visiteur du block statement dans l'interpréteur) diff --git a/src/parser.rs b/src/parser.rs index 059301c..9852df2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2,7 +2,7 @@ use crate::expr::{Assign, Binary, Expr, Grouping, Unary, Variable}; use crate::expr::Literal::{LiteralBool, LiteralNumber, LiteralString}; use crate::token::Token; use crate::token_type::TokenType; -use crate::stmt::{ExpressionStatement, PrintStatement, Statement, VarStatement}; +use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, VarStatement}; pub struct Parser { tokens: Vec, @@ -225,10 +225,26 @@ impl Parser { fn statement(&mut self) -> Result { if self.match_token(&[TokenType::Print]) { - self.print_statement() - } else { - self.expr_statement() + return self.print_statement(); } + + if self.match_token(&[TokenType::LeftBrace]) { + return self.block_statement(); + } + + self.expr_statement() + } + + fn block_statement(&mut self) -> Result { + let mut statements: Vec = Vec::new(); + + while !self.check(&TokenType::RightBrace) && !self.is_at_end() { + statements.push(self.declaration()?); + } + + self.consume(&TokenType::RightBrace, String::from("Expect '}' after block"))?; + + Ok(Statement::Block(BlockStatement::new(statements))) } fn print_statement(&mut self) -> Result { diff --git a/src/stmt.rs b/src/stmt.rs index ffba0c6..6d05a21 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -6,6 +6,7 @@ pub enum Statement { Expression(ExpressionStatement), Print(PrintStatement), Var(VarStatement), + Block(BlockStatement), } #[derive(Clone)] @@ -24,8 +25,23 @@ pub struct VarStatement { pub initializer: Option } +#[derive(Clone)] +pub struct BlockStatement { + pub statements: Vec, +} + +impl BlockStatement { + pub fn new( statements: Vec ) -> Self { + BlockStatement { + statements + } + } +} + pub trait StatementVisitor { + fn visit_stmt(&mut self, s: &Statement) -> T; fn visit_expr_stmt(&mut self, e: &ExpressionStatement) -> 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; }