Blocs d'instructions

This commit is contained in:
2024-06-12 22:15:26 +02:00
parent 897a6c4c13
commit 6ed3e4c68c
6 changed files with 107 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable};
use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement};
use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement};
pub struct ASTPrinter {
pub(crate) depth: u32
@@ -106,4 +106,23 @@ impl StatementVisitor<()> for ASTPrinter {
self.depth-=1;
print!(") ");
}
fn visit_block_stmt(&mut self, b: &BlockStatement) -> () {
println!("{} BLOCK_STMT(", self.ast_tab());
self.depth+=1;
for s in &b.statements {
self.visit_stmt(s);
}
self.depth-=1;
print!(") ");
}
fn visit_stmt(&mut self, s: &Statement) -> () {
match s {
Statement::Expression(e) => { self.visit_expr_stmt(&e) }
Statement::Print(p) => { self.visit_print(&p) }
Statement::Var(v) => { self.visit_var_stmt(&v) }
Statement::Block(b) => { self.visit_block_stmt(&b) }
}
}
}

View File

@@ -2,14 +2,17 @@ use std::collections::HashMap;
use crate::expr::Literal;
use crate::interpreter::RuntimeError;
#[derive(Clone)]
pub struct Environment {
pub values: HashMap<String, Literal>,
pub enclosing: Option<Box<Environment>>,
}
impl Environment {
pub fn new() -> Self {
Environment {
values : HashMap::new()
values : HashMap::new(),
enclosing: None,
}
}
@@ -20,7 +23,13 @@ impl Environment {
pub fn get(&self, name: &String) -> Result<Literal, RuntimeError> {
match self.values.get(name) {
Some(s) => { Ok(s.clone()) } ,
None => { Err(RuntimeError { message: format!("Variable {} non définie", name) } ) }
None => {
if let Some(encl) = &self.enclosing {
encl.get(name)
} else {
Err(RuntimeError { message: format!("Variable {} non définie", name) } )
}
}
}
}
@@ -29,7 +38,11 @@ impl Environment {
self.values.insert(name, value);
Ok(())
} else {
Err(RuntimeError { message: String::from("Undefined variable")})
if let Some(encl) = &mut self.enclosing {
encl.assign(name, value)
} else {
Err(RuntimeError { message: format!("Variable {} non définie", name) } )
}
}
}
}

View File

@@ -4,7 +4,7 @@ use crate::expr::Literal::LiteralNumber;
use crate::expr::Literal::LiteralBool;
use crate::expr::Literal::LiteralNil;
use crate::expr::{Assign, Binary, Expr, ExprVisitor, Grouping, Literal, Unary, Variable};
use crate::stmt::{ExpressionStatement, PrintStatement, StatementVisitor, VarStatement};
use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, StatementVisitor, VarStatement};
use crate::token_type::TokenType;
pub struct Interpreter {
@@ -17,6 +17,17 @@ impl Interpreter {
environment: Environment::new()
}
}
fn execute_block( &mut self, statements: &Vec<Statement>, env: &Environment ) {
let previous = self.environment.clone();
self.environment = (*env).clone();
for s in statements {
self.visit_stmt(s);
}
self.environment = previous;
}
}
#[derive(Debug)]
@@ -157,19 +168,28 @@ impl ExprVisitor<Result<Literal, RuntimeError>> for Interpreter {
}
}
fn visit_variable(&mut self, v: &Variable) -> Result<Literal, RuntimeError> {
self.environment.get(&v.name.literal)
}
fn visit_assign(&mut self, a: &Assign) -> Result<Literal, RuntimeError> {
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<Literal, RuntimeError> {
self.environment.get(&v.name.literal)
}
}
impl StatementVisitor<()> for Interpreter {
fn visit_stmt(&mut self, s: &Statement) {
match s {
Statement::Expression(e) => { self.visit_expr_stmt(e); }
Statement::Print(p) => { self.visit_print(p); }
Statement::Var(v) => { self.visit_var_stmt(v); }
Statement::Block(b) => { self.visit_block_stmt(b); }
}
}
fn visit_expr_stmt(&mut self, e: &ExpressionStatement) {
self.visit_expr(&e.expr).expect("Erreur pendant l'évaluation de l'expression.");
}
@@ -195,6 +215,10 @@ impl StatementVisitor<()> for Interpreter {
None => {}
}
}
fn visit_block_stmt(&mut self, b: &BlockStatement) {
self.execute_block(&b.statements, &Environment::new() );
}
}

View File

@@ -16,7 +16,7 @@ mod stmt;
mod environment;
use crate::scanner::Scanner;
use crate::stmt::{Statement, StatementVisitor};
use crate::stmt::StatementVisitor;
// Exit codes from #include <sysexits.h>
const EX_OK: i32 = 0;
@@ -77,22 +77,14 @@ fn run(src: String) -> i32 {
println!("AST");
let mut printer = ASTPrinter { depth: 0 };
for s in program.clone() {
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) }
}
for s in &program {
printer.visit_stmt(s);
}
println!("Interpretation");
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) }
}
for s in &program {
interpreter.visit_stmt(s);
}
EX_OK
@@ -103,4 +95,4 @@ fn run(src: String) -> i32 {
// https://github.com/munificent/craftinginterpreters/wiki/Lox-implementations#rust
// Pause :
// http://www.craftinginterpreters.com/statements-and-state.html#assignment
// http://www.craftinginterpreters.com/statements-and-state.html#block-syntax-and-semantics (visiteur du block statement dans l'interpréteur)

View File

@@ -2,7 +2,7 @@ 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;
use crate::stmt::{ExpressionStatement, PrintStatement, Statement, VarStatement};
use crate::stmt::{BlockStatement, ExpressionStatement, PrintStatement, Statement, VarStatement};
pub struct Parser {
tokens: Vec<Token>,
@@ -225,10 +225,26 @@ impl Parser {
fn statement(&mut self) -> Result<Statement, ParseError> {
if self.match_token(&[TokenType::Print]) {
self.print_statement()
} else {
return self.print_statement();
}
if self.match_token(&[TokenType::LeftBrace]) {
return self.block_statement();
}
self.expr_statement()
}
fn block_statement(&mut self) -> Result<Statement, ParseError> {
let mut statements: Vec<Statement> = Vec::new();
while !self.check(&TokenType::RightBrace) && !self.is_at_end() {
statements.push(self.declaration()?);
}
self.consume(&TokenType::RightBrace, String::from("Expect '}' after block"))?;
Ok(Statement::Block(BlockStatement::new(statements)))
}
fn print_statement(&mut self) -> Result<Statement, ParseError> {

View File

@@ -6,6 +6,7 @@ pub enum Statement {
Expression(ExpressionStatement),
Print(PrintStatement),
Var(VarStatement),
Block(BlockStatement),
}
#[derive(Clone)]
@@ -24,8 +25,23 @@ pub struct VarStatement {
pub initializer: Option<Expr>
}
#[derive(Clone)]
pub struct BlockStatement {
pub statements: Vec<Statement>,
}
impl BlockStatement {
pub fn new( statements: Vec<Statement> ) -> Self {
BlockStatement {
statements
}
}
}
pub trait StatementVisitor<T> {
fn visit_stmt(&mut self, s: &Statement) -> T;
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;
fn visit_block_stmt(&mut self, b: &BlockStatement) -> T;
}