diff --git a/src/astprinter.rs b/src/astprinter.rs index 6024e95..5da275f 100644 --- a/src/astprinter.rs +++ b/src/astprinter.rs @@ -1,4 +1,4 @@ -use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; +use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; pub struct ASTPrinter { @@ -59,12 +59,21 @@ impl ExprVisitor<()> for ASTPrinter { Expr::LiteralExpr(l) => { self.visit_literal(l); } Expr::UnaryExpr(u) => { self.visit_unary(u); } Expr::VariableExpr(v) => { self.visit_variable(v); } + Expr::AssignExpr(a) => { self.visit_assign(a); } } } fn visit_variable(&mut self, v: &Variable) -> () { println!("{}VARIABLE(name={})", self.ast_tab(), v.name.literal); } + + fn visit_assign(&mut self, a: &Assign) -> () { + println!("{}ASSIGN(var={}", self.ast_tab(), a.name); + self.depth+=1; + self.visit_expr(&a.value); + self.depth-=1; + print!(") "); + } } impl StatementVisitor<()> for ASTPrinter { diff --git a/src/environment.rs b/src/environment.rs index 7b761fa..6f8766d 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -23,4 +23,13 @@ impl Environment { None => { Err(RuntimeError { message: format!("Variable {} non définie", name) } ) } } } + + pub fn assign(&mut self, name: String, value: Literal) -> Result<(), RuntimeError> { + if self.values.contains_key(&name) { + self.values.insert(name, value); + Ok(()) + } else { + Err(RuntimeError { message: String::from("Undefined variable")}) + } + } } \ No newline at end of file diff --git a/src/expr.rs b/src/expr.rs index 6d6f8a0..1542b72 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1,5 +1,11 @@ use crate::token::Token; +#[derive(Clone)] +pub struct Assign { + pub name: Token, + pub value: Box, +} + #[derive(Clone)] pub struct Binary { pub left: Box, @@ -38,6 +44,7 @@ pub enum Expr { LiteralExpr(Literal), UnaryExpr(Unary), VariableExpr(Variable), + AssignExpr(Assign), } pub trait ExprVisitor { @@ -47,5 +54,6 @@ pub trait ExprVisitor { fn visit_unary(&mut self, u: &Unary) -> 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; } diff --git a/src/interpreter.rs b/src/interpreter.rs index 871ea6c..b406cb6 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,14 +1,9 @@ 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, Variable}; +use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable}; use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement}; use crate::token_type::TokenType; @@ -153,14 +148,22 @@ impl ExprVisitor> for Interpreter { fn visit_expr(&mut self, e: &Expr) -> Result { match e { - BinaryExpr(b) => { Ok(self.visit_binary(&b)?) } - 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)? )} + Expr::BinaryExpr(b) => { Ok(self.visit_binary(&b)?) } + Expr::GroupingExpr(g) => { Ok(self.visit_grouping(&g)?) } + Expr::LiteralExpr(l) => { Ok(self.visit_literal(&l)?) } + Expr::UnaryExpr(u) => { Ok(self.visit_unary(&u)?) } + Expr::VariableExpr(v) => { Ok(self.visit_variable(&v)?) } + Expr::AssignExpr(a) => { Ok(self.visit_assign(&a)?) } } } + 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) } diff --git a/src/main.rs b/src/main.rs index aff00d7..b6106a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,4 +103,4 @@ fn run(src: String) -> i32 { // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // Pause : -// http://www.craftinginterpreters.com/statements-and-state.html#global-variables +// http://www.craftinginterpreters.com/statements-and-state.html#assignment diff --git a/src/parser.rs b/src/parser.rs index 3f7af2e..059301c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,4 @@ -use crate::expr::{Binary, Expr, Grouping, Unary, Variable}; +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; @@ -92,11 +92,28 @@ impl Parser { } } - fn expression(&mut self) -> Result { - self.equality() + fn expression(&mut self) -> Result { + self.assignment() } - fn equality(&mut self) -> Result { + fn assignment(&mut self) -> Result { + let expr = self.equality()?; + + if self.match_token(&[TokenType::Equal]) { + let value = Box::new(self.assignment()?); // l'assignation a une associativité par la droite + + match expr { + Expr::VariableExpr(v) => { + Ok( Expr::AssignExpr(Assign { name: v.name, value })) + } + _ => Err(ParseError { message: String::from("Invalid assignment target") }) + } + } else { + Ok(expr) + } + } + + fn equality(&mut self) -> Result { let mut expr: Expr = self.comparison()?; while self.match_token( &[TokenType::BangEqual, TokenType::EqualEqual]) { @@ -112,7 +129,7 @@ impl Parser { return Ok(expr); } - fn comparison(&mut self) -> Result { + fn comparison(&mut self) -> Result { let mut expr = self.term()?; while self.match_token(&[TokenType::Greater, TokenType::GreaterEqual, TokenType::Less, TokenType::LessEqual]) {