From e121ba216021140ec8fa7c77a621313353c0da20 Mon Sep 17 00:00:00 2001 From: Emmanuel BERNAT Date: Mon, 3 Jun 2024 08:04:53 +0200 Subject: [PATCH] =?UTF-8?q?Variables=20globales=20(d=C3=A9claration,=20aff?= =?UTF-8?q?ectation=20avec=20une=20expression=20et=20=C3=A9valuation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/astprinter.rs | 23 +++++++++++++-- src/environment.rs | 26 +++++++++++++++++ src/expr.rs | 7 +++++ src/interpreter.rs | 39 ++++++++++++++++++++++---- src/main.rs | 10 ++++--- src/parser.rs | 70 +++++++++++++++++++++++++++++++++------------- src/stmt.rs | 11 +++++++- 7 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 src/environment.rs diff --git a/src/astprinter.rs b/src/astprinter.rs index e1944c5..6024e95 100644 --- a/src/astprinter.rs +++ b/src/astprinter.rs @@ -1,5 +1,5 @@ -use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary}; -use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor}; +use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; +use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; pub struct ASTPrinter { pub(crate) depth: u32 @@ -58,8 +58,13 @@ impl ExprVisitor<()> for ASTPrinter { Expr::GroupingExpr(g) => { self.visit_grouping(g); } Expr::LiteralExpr(l) => { self.visit_literal(l); } Expr::UnaryExpr(u) => { self.visit_unary(u); } + Expr::VariableExpr(v) => { self.visit_variable(v); } } } + + fn visit_variable(&mut self, v: &Variable) -> () { + println!("{}VARIABLE(name={})", self.ast_tab(), v.name.literal); + } } impl StatementVisitor<()> for ASTPrinter { @@ -78,4 +83,18 @@ impl StatementVisitor<()> for ASTPrinter { self.depth-=1; print!(") "); } + + fn visit_var_stmt(&mut self, v: &VarStatement) -> () { + println!("{} VAR_STMT(", self.ast_tab()); + self.depth+=1; + println!("variable name = {}",&v.token.literal); + print!("variable initializer = "); + match &v.initializer { + Some(v) => { self.visit_expr(&v) } + None => {} + } + + self.depth-=1; + print!(") "); + } } \ No newline at end of file diff --git a/src/environment.rs b/src/environment.rs new file mode 100644 index 0000000..7b761fa --- /dev/null +++ b/src/environment.rs @@ -0,0 +1,26 @@ +use std::collections::HashMap; +use crate::expr::Literal; +use crate::interpreter::RuntimeError; + +pub struct Environment { + pub values: HashMap, +} + +impl Environment { + pub fn new() -> Self { + Environment { + values : HashMap::new() + } + } + + pub fn define(&mut self, name: String, value: Literal) { + self.values.insert(name, value); + } + + 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) } ) } + } + } +} \ No newline at end of file diff --git a/src/expr.rs b/src/expr.rs index f312571..6d6f8a0 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -26,12 +26,18 @@ pub struct Unary { pub right: Box, } +#[derive(Clone)] +pub struct Variable { + pub name: Token, +} + #[derive(Clone)] pub enum Expr { BinaryExpr(Binary), GroupingExpr(Grouping), LiteralExpr(Literal), UnaryExpr(Unary), + VariableExpr(Variable), } pub trait ExprVisitor { @@ -40,5 +46,6 @@ pub trait ExprVisitor { fn visit_literal(&mut self, l: &Literal) ->T; fn visit_unary(&mut self, u: &Unary) -> T; fn visit_expr(&mut self, e: &Expr) -> T; + fn visit_variable(&mut self, v: &Variable) -> T; } diff --git a/src/interpreter.rs b/src/interpreter.rs index 1ab3718..871ea6c 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,16 +1,28 @@ +use crate::environment::Environment; use crate::expr::Expr::UnaryExpr; use crate::expr::Expr::LiteralExpr; use crate::expr::Expr::GroupingExpr; use crate::expr::Expr::BinaryExpr; +use crate::expr::Expr::VariableExpr; use crate::expr::Literal::LiteralString; use crate::expr::Literal::LiteralNumber; use crate::expr::Literal::LiteralBool; use crate::expr::Literal::LiteralNil; -use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary}; -use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor}; +use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; +use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; use crate::token_type::TokenType; -pub struct Interpreter; +pub struct Interpreter { + environment: Environment, +} + +impl Interpreter { + pub fn new() -> Self { + Interpreter { + environment: Environment::new() + } + } +} #[derive(Debug)] pub struct RuntimeError { @@ -145,18 +157,23 @@ impl ExprVisitor> for Interpreter { GroupingExpr(g) => { Ok(self.visit_grouping(&g)?) } LiteralExpr(l) => { Ok(self.visit_literal(&l)?) } UnaryExpr(u) => { Ok(self.visit_unary(&u)?) } + VariableExpr(v) => { Ok(self.visit_variable(&v)? )} } } + + fn visit_variable(&mut self, v: &Variable) -> Result { + self.environment.get(&v.name.literal) + } } impl StatementVisitor<()> for Interpreter { - fn visit_expr_stmt(&mut self, e: &ExpressionStatement) -> () { + fn visit_expr_stmt(&mut self, e: &ExpressionStatement) { self.visit_expr(&e.expr).expect("Erreur pendant l'évaluation de l'expression."); } - fn visit_print(&mut self, p: &PrintStatement) -> () { + fn visit_print(&mut self, p: &PrintStatement) { match self.visit_expr(&p.expr) { - Ok(lit) => match (lit) { + Ok(lit) => match lit { Literal::LiteralNumber(f) => { println!("{}", f); } Literal::LiteralString(s) => { println!("{}", s); } Literal::LiteralBool(b) => { println!("{}", b); } @@ -165,6 +182,16 @@ impl StatementVisitor<()> for Interpreter { Err(e) => panic!("{}", e.message) } } + + fn visit_var_stmt(&mut self, v: &VarStatement) { + match &v.initializer { + Some(e) => { + let value = self.visit_expr(&e).unwrap(); + self.environment.define(v.token.literal.clone(), value); + } + None => {} + } + } } diff --git a/src/main.rs b/src/main.rs index aa39089..aff00d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,6 @@ use std::{env, fs, io}; use std::io::Write; use std::process; use crate::astprinter::ASTPrinter; -use crate::expr::ExprVisitor; use crate::interpreter::Interpreter; use crate::parser::Parser; @@ -14,15 +13,16 @@ mod expr; mod astprinter; mod parser; mod stmt; +mod environment; use crate::scanner::Scanner; use crate::stmt::{Statement, StatementVisitor}; // Exit codes from #include const EX_OK: i32 = 0; -const EX_DATAERR: i32 = 65; +//const EX_DATAERR: i32 = 65; const EX_USAGE : i32 = 66; -const EX_EXECERR: i32 = 70; +//const EX_EXECERR: i32 = 70; fn main() { let args: Vec = env::args().collect(); @@ -81,15 +81,17 @@ fn run(src: String) -> i32 { 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) } } } println!("Interpretation"); - let mut interpreter = Interpreter; + 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) } } } diff --git a/src/parser.rs b/src/parser.rs index 7c49a01..3f7af2e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,8 @@ -use crate::expr::{Binary, Expr, Grouping, Unary}; +use crate::expr::{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}; +use crate::stmt::{ExpressionStatement, PrintStatement, Statement, VarStatement}; pub struct Parser { tokens: Vec, @@ -60,15 +60,12 @@ impl Parser { return self.tokens[self.current - 1].clone(); } - fn consume(&mut self, token_type: &TokenType, message: String) -> Result<(), ParseError> { + fn consume(&mut self, token_type: &TokenType, message: String) -> Result { if self.check(token_type) { - self.advance(); - return Ok(()); + Ok(self.advance()) + } else { + Err(ParseError { message }) } - - Err(ParseError { - message - }) } fn synchronise(&mut self) { @@ -192,6 +189,10 @@ impl Parser { if self.match_token(&[TokenType::String]) { return Ok(Expr::LiteralExpr(LiteralString(self.previous().literal))); } + if self.match_token(&[TokenType::Identifier]) { + return Ok(Expr::VariableExpr(Variable { name: self.previous() } )); + } + if self.match_token(&[TokenType::LeftParen]) { let expr = self.expression()?; self.consume(&TokenType::RightParen, String::from("Expect ')' after expression."))?; @@ -205,7 +206,7 @@ impl Parser { } } - fn statement(&mut self) -> Statement { + fn statement(&mut self) -> Result { if self.match_token(&[TokenType::Print]) { self.print_statement() } else { @@ -213,22 +214,53 @@ impl Parser { } } - fn print_statement(&mut self) -> Statement { - let e = self.expression().unwrap(); - self.consume(&TokenType::Semicolon, String::from("; attendu")).unwrap(); - Statement::Print(PrintStatement{ expr: e }) + fn print_statement(&mut self) -> Result { + match self.expression() { + Ok(e) => { + self.consume(&TokenType::Semicolon, String::from("; attendu"))?; + Ok(Statement::Print(PrintStatement{ expr: e })) + } + Err(e ) => { Err(e) } + } } - fn expr_statement(&mut self) -> Statement { - let e = self.expression().unwrap(); - self.consume(&TokenType::Semicolon, String::from("; attendu")).unwrap(); - Statement::Expression(ExpressionStatement{ expr: e }) + fn expr_statement(&mut self) -> Result { + match self.expression() { + Ok(e) => { + self.consume(&TokenType::Semicolon, String::from("; attendu"))?; + Ok(Statement::Expression(ExpressionStatement{ expr: e })) + } + Err(e ) => { Err(e) } + } + } + + fn declaration(&mut self) -> Result { + if self.match_token(&[TokenType::Var]) { + self.var_declaration() + } else { + self.statement() + } + } + + fn var_declaration(&mut self) -> Result { + let name = self.consume(&TokenType::Identifier, String::from("nom de variable attendu"))?; + + let mut initializer: Option = None; + if self.match_token(&[TokenType::Equal]) { + initializer = Some(self.expression()?); + } + + self.consume(&TokenType::Semicolon, String::from("; attendu"))?; + Ok(Statement::Var(VarStatement{ token: name, initializer })) } pub fn parse(&mut self) -> Vec { let mut statements= Vec::new(); while !self.is_at_end() { - statements.push(self.statement()); + match self.declaration() { + Ok(stmt) => statements.push(stmt), + Err(_e) => self.synchronise(), + } } statements diff --git a/src/stmt.rs b/src/stmt.rs index 304c023..ffba0c6 100644 --- a/src/stmt.rs +++ b/src/stmt.rs @@ -1,9 +1,11 @@ use crate::expr::Expr; +use crate::token::Token; #[derive(Clone)] pub enum Statement { Expression(ExpressionStatement), - Print(PrintStatement) + Print(PrintStatement), + Var(VarStatement), } #[derive(Clone)] @@ -16,7 +18,14 @@ pub struct PrintStatement { pub expr: Expr } +#[derive(Clone)] +pub struct VarStatement { + pub token: Token, + pub initializer: Option +} + pub trait StatementVisitor { 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; }