Finalisation de l'interpreteur d'expressions.
This commit is contained in:
@@ -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 struct ASTPrinter {
|
||||||
pub(crate) depth: u32
|
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) {
|
fn visit_binary(&mut self, b: &Binary) {
|
||||||
println!("{}BINARY",self.ast_tab());
|
println!("{}BINARY",self.ast_tab());
|
||||||
println!("{}op='{}'", self.ast_tab(), b.operator.lexeme);
|
println!("{}op='{}'", self.ast_tab(), b.operator.lexeme);
|
||||||
println!("{}left=(", self.ast_tab());
|
println!("{}left=(", self.ast_tab());
|
||||||
self.depth+=1;
|
self.depth+=1;
|
||||||
b.left.accept(self);
|
self.visit_expr(&*b.left);
|
||||||
self.depth-=1;
|
self.depth-=1;
|
||||||
println!("{})", self.ast_tab());
|
println!("{})", self.ast_tab());
|
||||||
println!("{}right=(", self.ast_tab());
|
println!("{}right=(", self.ast_tab());
|
||||||
self.depth+=1;
|
self.depth+=1;
|
||||||
b.right.accept(self);
|
self.visit_expr(&*b.right);
|
||||||
self.depth-=1;
|
self.depth-=1;
|
||||||
println!("{})", self.ast_tab());
|
println!("{})", self.ast_tab());
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ impl ExprVisitor for ASTPrinter {
|
|||||||
fn visit_grouping(&mut self, g: &Grouping) {
|
fn visit_grouping(&mut self, g: &Grouping) {
|
||||||
println!("{}GROUPING(", self.ast_tab());
|
println!("{}GROUPING(", self.ast_tab());
|
||||||
self.depth+=1;
|
self.depth+=1;
|
||||||
g.expression.accept(self);
|
self.visit_expr(&*g.expression);
|
||||||
self.depth-=1;
|
self.depth-=1;
|
||||||
print!(") ");
|
print!(") ");
|
||||||
}
|
}
|
||||||
@@ -46,17 +46,17 @@ impl ExprVisitor for ASTPrinter {
|
|||||||
fn visit_unary(&mut self, u: &Unary) {
|
fn visit_unary(&mut self, u: &Unary) {
|
||||||
println!("{}UNARY(op='{}'", self.ast_tab(), u.operator.lexeme);
|
println!("{}UNARY(op='{}'", self.ast_tab(), u.operator.lexeme);
|
||||||
self.depth+=1;
|
self.depth+=1;
|
||||||
u.right.accept(self);
|
self.visit_expr(&*u.right);
|
||||||
self.depth-=1;
|
self.depth-=1;
|
||||||
print!(") ");
|
print!(") ");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_expr(&mut self, e: &Expr) {
|
fn visit_expr(&mut self, e: &Expr) {
|
||||||
match e {
|
match e {
|
||||||
Expr::BinaryExpr(b) => { b.accept(self); }
|
Expr::BinaryExpr(b) => { self.visit_binary(b); }
|
||||||
Expr::GroupingExpr(g) => { g.accept(self); }
|
Expr::GroupingExpr(g) => { self.visit_grouping(g); }
|
||||||
Expr::LiteralExpr(l) => { l.accept(self); }
|
Expr::LiteralExpr(l) => { self.visit_literal(l); }
|
||||||
Expr::UnaryExpr(u) => { u.accept(self); }
|
Expr::UnaryExpr(u) => { self.visit_unary(u); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
46
src/expr.rs
46
src/expr.rs
@@ -10,6 +10,7 @@ pub struct Grouping {
|
|||||||
pub expression: Box<Expr>,
|
pub expression: Box<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
LiteralNumber(f64),
|
LiteralNumber(f64),
|
||||||
LiteralString(String),
|
LiteralString(String),
|
||||||
@@ -29,44 +30,11 @@ pub enum Expr {
|
|||||||
UnaryExpr(Unary),
|
UnaryExpr(Unary),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ExprVisitor {
|
pub trait ExprVisitor<T> {
|
||||||
fn visit_binary(&mut self, b: &Binary);
|
fn visit_binary(&mut self, b: &Binary) -> T;
|
||||||
fn visit_grouping(&mut self, g: &Grouping);
|
fn visit_grouping(&mut self, g: &Grouping) -> T;
|
||||||
fn visit_literal(&mut self, l: &Literal);
|
fn visit_literal(&mut self, l: &Literal) ->T;
|
||||||
fn visit_unary(&mut self, u: &Unary);
|
fn visit_unary(&mut self, u: &Unary) -> T;
|
||||||
fn visit_expr(&mut self, e: &Expr);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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 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<Result<Literal, RuntimeError>> for Interpreter {
|
||||||
|
fn visit_binary(&mut self, b: &Binary) -> Result<Literal, RuntimeError> {
|
||||||
|
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<Literal, RuntimeError> {
|
||||||
|
Ok(self.visit_expr(&*g.expression)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_literal(&mut self, l: &Literal) -> Result<Literal, RuntimeError> {
|
||||||
|
Ok(l.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_unary(&mut self, u: &Unary) -> Result<Literal, RuntimeError> {
|
||||||
|
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<Literal, RuntimeError> {
|
||||||
|
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)?) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/main.rs
25
src/main.rs
@@ -2,7 +2,8 @@ use std::{env, fs, io};
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process;
|
use std::process;
|
||||||
use crate::astprinter::ASTPrinter;
|
use crate::astprinter::ASTPrinter;
|
||||||
use crate::expr::ExprVisitor;
|
use crate::expr::{ExprVisitor, Literal};
|
||||||
|
use crate::interpreter::Interpreter;
|
||||||
use crate::parser::Parser;
|
use crate::parser::Parser;
|
||||||
|
|
||||||
mod interpreter;
|
mod interpreter;
|
||||||
@@ -17,8 +18,9 @@ use crate::scanner::Scanner;
|
|||||||
|
|
||||||
// Exit codes from #include <sysexits.h>
|
// Exit codes from #include <sysexits.h>
|
||||||
const EX_OK: i32 = 0;
|
const EX_OK: i32 = 0;
|
||||||
//const EX_DATAERR: i32 = 65;
|
const EX_DATAERR: i32 = 65;
|
||||||
const EX_USAGE : i32 = 66;
|
const EX_USAGE : i32 = 66;
|
||||||
|
const EX_EXECERR: i32 = 70;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
@@ -63,17 +65,32 @@ pub fn run_prompt() -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(src: String) -> i32 {
|
fn run(src: String) -> i32 {
|
||||||
|
println!("Scanner");
|
||||||
let mut scanner = Scanner::new( src );
|
let mut scanner = Scanner::new( src );
|
||||||
scanner.scan_tokens();
|
scanner.scan_tokens();
|
||||||
|
|
||||||
|
println!("Parser");
|
||||||
let mut parser = Parser::new( scanner.tokens );
|
let mut parser = Parser::new( scanner.tokens );
|
||||||
match parser.parse() {
|
match parser.parse() {
|
||||||
Some(expr) => {
|
Some(expr) => {
|
||||||
|
println!("AST");
|
||||||
let mut printer = ASTPrinter { depth: 0 };
|
let mut printer = ASTPrinter { depth: 0 };
|
||||||
printer.visit_expr(&expr);
|
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!();
|
println!();
|
||||||
},
|
},
|
||||||
None => println!("An error occurred while parsing expression.")
|
None => { println!("An error occurred while parsing expression."); return EX_DATAERR; }
|
||||||
}
|
}
|
||||||
|
|
||||||
EX_OK
|
EX_OK
|
||||||
@@ -84,4 +101,4 @@ fn run(src: String) -> i32 {
|
|||||||
// https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust
|
// https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust
|
||||||
|
|
||||||
// Pause :
|
// Pause :
|
||||||
// http://www.craftinginterpreters.com/parsing-expressions.html implémentation de comparison
|
// http://www.craftinginterpreters.com/statements-and-state.html
|
||||||
|
|||||||
Reference in New Issue
Block a user