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(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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/expr.rs
46
src/expr.rs
@@ -10,6 +10,7 @@ pub struct Grouping {
|
||||
pub expression: Box<Expr>,
|
||||
}
|
||||
|
||||
#[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<T> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<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::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 <sysexits.h>
|
||||
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<String> = 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
|
||||
|
||||
Reference in New Issue
Block a user