diff --git a/src/astprinter.rs b/src/astprinter.rs index 4e9e824..0eb9fff 100644 --- a/src/astprinter.rs +++ b/src/astprinter.rs @@ -1,4 +1,4 @@ -use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary, VisitableExpr}; +use crate::expr::{Binary, Expr, ExprVisitor, Grouping, Literal, Unary}; pub struct ASTPrinter { pub(crate) depth: u32 @@ -10,18 +10,18 @@ impl ASTPrinter { } } -impl ExprVisitor for ASTPrinter { +impl ExprVisitor<()> for ASTPrinter { fn visit_binary(&mut self, b: &Binary) { println!("{}BINARY",self.ast_tab()); println!("{}op='{}'", self.ast_tab(), b.operator.lexeme); println!("{}left=(", self.ast_tab()); self.depth+=1; - b.left.accept(self); + self.visit_expr(&*b.left); self.depth-=1; println!("{})", self.ast_tab()); println!("{}right=(", self.ast_tab()); self.depth+=1; - b.right.accept(self); + self.visit_expr(&*b.right); self.depth-=1; println!("{})", self.ast_tab()); } @@ -29,7 +29,7 @@ impl ExprVisitor for ASTPrinter { fn visit_grouping(&mut self, g: &Grouping) { println!("{}GROUPING(", self.ast_tab()); self.depth+=1; - g.expression.accept(self); + self.visit_expr(&*g.expression); self.depth-=1; print!(") "); } @@ -46,17 +46,17 @@ impl ExprVisitor for ASTPrinter { fn visit_unary(&mut self, u: &Unary) { println!("{}UNARY(op='{}'", self.ast_tab(), u.operator.lexeme); self.depth+=1; - u.right.accept(self); + self.visit_expr(&*u.right); self.depth-=1; print!(") "); } fn visit_expr(&mut self, e: &Expr) { match e { - Expr::BinaryExpr(b) => { b.accept(self); } - Expr::GroupingExpr(g) => { g.accept(self); } - Expr::LiteralExpr(l) => { l.accept(self); } - Expr::UnaryExpr(u) => { u.accept(self); } + Expr::BinaryExpr(b) => { self.visit_binary(b); } + Expr::GroupingExpr(g) => { self.visit_grouping(g); } + Expr::LiteralExpr(l) => { self.visit_literal(l); } + Expr::UnaryExpr(u) => { self.visit_unary(u); } } } } \ No newline at end of file diff --git a/src/expr.rs b/src/expr.rs index 8827404..db49f7b 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -10,6 +10,7 @@ pub struct Grouping { pub expression: Box, } +#[derive(Clone)] pub enum Literal { LiteralNumber(f64), LiteralString(String), @@ -29,44 +30,11 @@ pub enum Expr { UnaryExpr(Unary), } -pub trait ExprVisitor { - fn visit_binary(&mut self, b: &Binary); - fn visit_grouping(&mut self, g: &Grouping); - fn visit_literal(&mut self, l: &Literal); - fn visit_unary(&mut self, u: &Unary); - fn visit_expr(&mut self, e: &Expr); +pub trait ExprVisitor { + fn visit_binary(&mut self, b: &Binary) -> T; + fn visit_grouping(&mut self, g: &Grouping) -> T; + fn visit_literal(&mut self, l: &Literal) ->T; + fn visit_unary(&mut self, u: &Unary) -> T; + fn visit_expr(&mut self, e: &Expr) -> T; } -pub trait VisitableExpr { - fn accept(&self, visitor: &mut impl ExprVisitor); -} - -impl VisitableExpr for Binary { - fn accept(&self, visitor: &mut impl ExprVisitor) { - visitor.visit_binary(self); - } -} - -impl VisitableExpr for Grouping { - fn accept(&self, visitor: &mut impl ExprVisitor) { - visitor.visit_grouping(self); - } -} - -impl VisitableExpr for Literal { - fn accept(&self, visitor: &mut impl ExprVisitor) { - visitor.visit_literal(self); - } -} - -impl VisitableExpr for Unary { - fn accept(&self, visitor: &mut impl ExprVisitor) { - visitor.visit_unary(self); - } -} - -impl VisitableExpr for Expr { - fn accept(&self, visitor: &mut impl ExprVisitor) { - visitor.visit_expr(self); - } -} diff --git a/src/interpreter.rs b/src/interpreter.rs index 3bd3a1b..3534c50 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,2 +1,148 @@ +use crate::expr::Expr::UnaryExpr; +use crate::expr::Expr::LiteralExpr; +use crate::expr::Expr::GroupingExpr; +use crate::expr::Expr::BinaryExpr; +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::token_type::TokenType; + pub struct Interpreter; +pub struct RuntimeError { + pub(crate) message: String +} + +fn is_truthy(l : &Literal) -> bool { + match l { + LiteralNil => false, + LiteralBool(b) => *b, + _ => true + } +} + +fn is_equal(a: &Literal, b: &Literal) -> bool { + match a { + LiteralNil => { + match b { + LiteralNil => true, + _ => false + } + } + LiteralBool(b_a) => { + match b { + LiteralBool(b_b) => b_a==b_b, + _ => false + } + } + LiteralString( s_a) => { + match b { + LiteralString( s_b) => s_a==s_b, + _ => false + } + } + LiteralNumber( n_a ) => { + match b { + LiteralNumber(n_b) => n_a==n_b, + _ => false + } + } + } +} + +fn is_greater(a: &Literal, b: &Literal) -> bool { + match a { + LiteralNil => false, + LiteralBool(_) => false, + LiteralString( s_a) => { + match b { + LiteralString( s_b) => s_a>s_b, + _ => false + } + } + LiteralNumber( n_a ) => { + match b { + LiteralNumber(n_b) => n_a>n_b, + _ => false + } + } + } +} + +impl ExprVisitor> for Interpreter { + fn visit_binary(&mut self, b: &Binary) -> Result { + let left = self.visit_expr(&*b.left)?; + let right = self.visit_expr(&*b.right)?; + match b.operator.token_type { + TokenType::Minus => { + match (left, right) { + (LiteralNumber(l), LiteralNumber(r)) => Ok(LiteralNumber(l-r)), + _ => Err(RuntimeError { message: String::from("On ne peut soustraire que des nombres.")}) + } + } + TokenType::Plus => { + match (left, right) { + (LiteralNumber(l), LiteralNumber(r)) => Ok(LiteralNumber(l+r)), + (LiteralString(l), LiteralString(r)) => Ok(LiteralString(l+ &*r)), + _ => Err(RuntimeError { message: String::from("On ne peut ajouter que des nombres ou des chaines.")}) + } + } + TokenType::Slash => { + match (left, right) { + (LiteralNumber(l), LiteralNumber(r)) => { if r>0.0 { Ok(LiteralNumber(l/r)) } else { Err(RuntimeError { message: String::from("Division par zéro")}) } } + _ => Err(RuntimeError { message: String::from("On ne peut diviser que des nombres.")}) + } + } + TokenType::Star => { + match (left, right) { + (LiteralNumber(l), LiteralNumber(r)) => Ok(LiteralNumber(l * r)), + _ => Err(RuntimeError { message: String::from("On ne peut multiplier que des nombres.") }) + } + } + TokenType::BangEqual => { Ok(LiteralBool(!is_equal(&left, &right))) } + TokenType::Equal => { Ok(LiteralBool(is_equal(&left, &right))) } + TokenType::EqualEqual => { Err(RuntimeError { message: String::from("Pas encore implémenté.") }) } + TokenType::Greater => { Ok(LiteralBool(is_greater(&left, &right))) } + TokenType::GreaterEqual => { Ok(LiteralBool(is_greater(&left, &right) || is_equal(&left, &right))) } + TokenType::Less => { Ok(LiteralBool(!is_greater(&left, &right))) } + TokenType::LessEqual => { Ok(LiteralBool(!is_greater(&left, &right) && !is_equal(&left, &right))) } + TokenType::And => { Err(RuntimeError { message: String::from("Pas encore implémenté.") }) } + TokenType::Or => { Err(RuntimeError { message: String::from("Pas encore implémenté.") }) } + _ => { panic!("Parsing error") } + } + + } + + fn visit_grouping(&mut self, g: &Grouping) -> Result { + Ok(self.visit_expr(&*g.expression)?) + } + + fn visit_literal(&mut self, l: &Literal) -> Result { + Ok(l.clone()) + } + + fn visit_unary(&mut self, u: &Unary) -> Result { + let right = self.visit_expr(&*u.right)?; + match u.operator.token_type { + TokenType::Minus => { match right { + LiteralNumber(f) => { Ok(Literal::LiteralNumber(-f)) } + LiteralBool(b) => { Ok(LiteralBool(!b)) } + LiteralNil => { Ok(Literal::LiteralNil) } + LiteralString(_) => { Err(RuntimeError { message: String::from("On ne peut pas utiliser la négation unaire sur une chaine.")}) } + }} + TokenType::Bang => { Ok(LiteralBool(is_truthy(&right))) } + _ => panic!("Parsing error") + } + } + + 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)?) } + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b7983f4..233d66b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ use std::{env, fs, io}; use std::io::Write; use std::process; use crate::astprinter::ASTPrinter; -use crate::expr::ExprVisitor; +use crate::expr::{ExprVisitor, Literal}; +use crate::interpreter::Interpreter; use crate::parser::Parser; mod interpreter; @@ -17,8 +18,9 @@ use crate::scanner::Scanner; // 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; fn main() { let args: Vec = env::args().collect(); @@ -63,17 +65,32 @@ pub fn run_prompt() -> i32 { } fn run(src: String) -> i32 { + println!("Scanner"); let mut scanner = Scanner::new( src ); scanner.scan_tokens(); + println!("Parser"); let mut parser = Parser::new( scanner.tokens ); match parser.parse() { Some(expr) => { + println!("AST"); let mut printer = ASTPrinter { depth: 0 }; printer.visit_expr(&expr); + println!("Interpretation"); + let mut interpreter = Interpreter; + let result = interpreter.visit_expr(&expr); + match result { + Ok(r) => { match r { + Literal::LiteralNumber(f) => { println!("Resultat numérique = {}", f); } + Literal::LiteralString(s) => { println!("Résultat chaîne = {}", s); } + Literal::LiteralBool(b) => { println!("Résultat booléen = {}", b); } + Literal::LiteralNil => { println!("Résultat nul")} + }} + Err(e) => { println!("Erreur d'exécution : {}", e.message); return EX_EXECERR; } + } println!(); }, - None => println!("An error occurred while parsing expression.") + None => { println!("An error occurred while parsing expression."); return EX_DATAERR; } } EX_OK @@ -84,4 +101,4 @@ fn run(src: String) -> i32 { // https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust // Pause : -// http://www.craftinginterpreters.com/parsing-expressions.html implémentation de comparison +// http://www.craftinginterpreters.com/statements-and-state.html