From f1a130cb94a5084234c52f8216dc49a37bf658be Mon Sep 17 00:00:00 2001 From: oliveira Date: Sun, 11 Aug 2024 11:17:11 -0300 Subject: [PATCH] fix environment enclosing --- src/environment.rs | 40 ++++- src/interpreter.rs | 414 ++++++++++++++++++--------------------------- src/main.rs | 11 +- 3 files changed, 199 insertions(+), 266 deletions(-) diff --git a/src/environment.rs b/src/environment.rs index a22c2a0..3a274a5 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -3,33 +3,59 @@ use std::collections::HashMap; type Value = Option; -#[derive(Clone)] pub struct Environment<'a> { values: HashMap<&'a str, Value>, - pub enclosing: Option>>, + pub parent: Box>>, } impl<'a> Environment<'a> { - pub fn new(enclosing: Option>>) -> Self { + pub fn new(parent: Option>) -> Self { Self { - enclosing, + parent: Box::new(parent), values: HashMap::new(), } } - pub fn empty() -> Self { + pub fn head() -> Self { Self::new(None) } - pub fn with_enclosing(enclosing: Environment<'a>) -> Self { - Self::new(Some(Box::new(enclosing))) + pub fn block(parent: Environment<'a>) -> Self { + Self::new(Some(parent)) + } + + pub fn get_parent(self) -> Environment<'a> { + self.parent.unwrap() } pub fn define(&mut self, name: &'a str, value: Option) -> Option { self.values.insert(name, value) } + pub fn define_deep(&mut self, name: &'a str, value: Option) -> Option { + match self.define(name, value.clone()) { + Some(v) => Some(v), + None => match *self.parent { + Some(ref mut parent) => parent.define(name, value), + None => None, + }, + } + } + pub fn get(&self, name: &'a str) -> Option<&Value> { self.values.get(&name) } + + pub fn get_deep(&self, name: &'a str) -> Option<&Value> { + let mut variable = self.get(name); + + if variable.is_none() { + variable = match *self.parent { + Some(ref parent) => parent.get(name), + None => None, + }; + } + + variable + } } diff --git a/src/interpreter.rs b/src/interpreter.rs index ca3079a..1b9cfc5 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -3,284 +3,200 @@ use crate::{ environment::Environment, lexer::{Token, TokenType}, }; -use std::ops::Deref; -pub type InterpreterResult<'a, T> = std::result::Result>; +pub type InterpreterResult<'a> = std::result::Result, InterpreterError<'a>>; -#[derive(Debug, Clone)] -pub struct InterpreterError<'a> { - pub token: Token<'a>, - pub message: &'a str, -} +pub fn run(statements: Vec) { + let mut env = Environment::head(); -pub struct Interpreter<'a> { - environment: Environment<'a>, - statements: Vec>, + for statement in statements { + env = execute(statement, env).unwrap(); + } } -fn is_truthy(literal: &Literal) -> bool { - match literal { - Literal::Nil => false, - Literal::Boolean(b) => *b, - _ => true, +fn execute<'a>( + statement: Statement<'a>, + env: Environment<'a>, +) -> Result, InterpreterError<'a>> { + match statement { + Statement::Expression(expr) => execute_expression(expr, env), + Statement::Print(expr) => execute_print(expr, env), + Statement::Var { name, expression } => execute_var(name, expression, env), + Statement::Block(statements) => execute_block(statements, env), + Statement::If { + condition, + then, + otherwise, + } => execute_if(condition, then, otherwise, env), + Statement::While { condition, body } => execute_while(condition, body, env), } } -impl<'a> Interpreter<'a> { - pub fn new(statements: Vec>) -> Self { - Self { - environment: Environment::empty(), - statements, - } - } +fn evaluate_unary<'a>( + operator: Token<'a>, + right: Box>, + env: Environment<'a>, +) -> Result<(Literal, Environment<'a>), InterpreterError<'a>> { + let (right, env) = evaluate(*right, env)?; + + let value = match operator.kind { + TokenType::Minus => match right { + Literal::Integer(n) => Literal::Integer(-n), + Literal::Float(n) => Literal::Float(-n), + _ => panic!("Unary minus can only be applied to numbers"), + }, + TokenType::Bang => Literal::Boolean(!is_truthy(right)), + _ => unreachable!(), + }; + + Ok((value, env)) +} - pub fn interpret(&mut self) -> Result<(), InterpreterError<'a>> { - // todo: how to remove that clone - for statement in &self.statements.clone() { - self.execute(statement)?; +fn evaluate_binary<'a>( + _left: Box, + _operator: &Token, + _right: Box, +) -> Result> { + Ok(Literal::Integer(1)) +} + +fn evaluate_var<'a>() { + todo!() +} + +fn evaluate<'a>( + expression: Expression<'a>, + env: Environment<'a>, +) -> Result<(Literal, Environment<'a>), InterpreterError<'a>> { + match expression { + Expression::Literal(l) => Ok((l.clone(), env)), + Expression::Grouping(literal) => evaluate(*literal, env), + Expression::Unary { operator, right } => evaluate_unary(operator, right, env), + Expression::Binary { + left, + operator, + right, + } => evaluate_binary(left, &operator, right).map(|_| (Literal::Nil, env)), + Expression::Variable(token) => { + let value = env.get_deep(token.lexeme).unwrap().clone(); + Ok((value.unwrap(), env)) } + Expression::Assign(token, value) => { + let (value, mut env) = evaluate(*value, env)?; - Ok(()) - } + env.define_deep(token.lexeme, Some(value.clone())); - pub fn execute(&mut self, statement: &Statement<'a>) -> Result<(), InterpreterError<'a>> { - match statement { - Statement::Expression(expression) => self.evaluate(expression).map(|_| ()), - Statement::Print(expression) => { - // maybe something else - let value = self.evaluate(expression)?; - - println!("{}", value); - - Ok(()) - } - Statement::Var { name, expression } => { - match expression { - Some(expr) => { - let value = self.evaluate(expr)?; - self.environment.define(name.lexeme, Some(value)); - } - None => { - self.environment.define(name.lexeme, None); - } - }; - - Ok(()) - } - Statement::Block(statements) => { - let block_env = Environment::with_enclosing(self.environment.clone()); - self.execute_block(statements, block_env)?; - - Ok(()) - } - Statement::If { - condition, - then, - otherwise, - } => { - let condition = self.evaluate(condition)?; - - if is_truthy(&condition) { - self.execute(then)?; - } else if let Some(s) = otherwise.deref() { - self.execute(s)?; - } - - Ok(()) - } - Statement::While { condition, body } => { - while is_truthy(&self.evaluate(condition)?) { - self.execute(body)?; - } - - Ok(()) - } + Ok((value, env)) + } + Expression::Logical { + left, + operator, + right, + } => { + todo!() } } +} + +fn execute_expression<'a>( + expression: Expression<'a>, + env: Environment<'a>, +) -> InterpreterResult<'a> { + evaluate(expression, env).map(|(_, env)| env) +} - pub fn execute_block( - &mut self, - statements: &Vec>, - env: Environment<'a>, - ) -> Result<(), InterpreterError<'a>> { - let prev = self.environment.clone(); +fn execute_print<'a>(expression: Expression<'a>, env: Environment<'a>) -> InterpreterResult<'a> { + let (value, env) = evaluate(expression, env)?; - // Change the environment temporarly for this block's execution - self.environment = env; + println!("{}", value); + + Ok(env) +} - for statement in statements { - let result = self.execute(statement); +fn execute_var<'a>( + name: Token<'a>, + expression: Option>, + mut env: Environment<'a>, +) -> Result, InterpreterError<'a>> { + match expression { + None => { + env.define(name.lexeme, None); - if result.is_err() { - self.environment = prev; - return result; - } + Ok(env) } + Some(expr) => { + let (value, mut env) = evaluate(expr, env)?; - self.environment = prev; + env.define(name.lexeme, Some(value)); - Ok(()) + Ok(env) + } } +} - pub fn error(token: Token<'a>, message: &'a str) -> Result> { - Err(InterpreterError { token, message }) +fn execute_block<'a>( + statements: Vec>, + env: Environment<'a>, +) -> InterpreterResult<'a> { + // Here we 'borrow' the environment and create a new one with the block as the parent + // as soon as the block is done executing, + // we return the parent environment and the block is dropped + let mut block_env = Environment::block(env); + + for statement in statements { + block_env = execute(statement, block_env)?; } - pub fn evaluate(&mut self, expr: &Expression<'a>) -> Result> { - match expr { - Expression::Literal(l) => Ok(l.clone()), - Expression::Grouping(literal) => self.evaluate(&literal), - Expression::Unary { operator, right } => self.evaluate_unary(operator, right), - Expression::Binary { - left, - operator, - right, - } => self.evaluate_binary(left, &operator, right), - Expression::Variable(token) => { - let mut variable = self.environment.get(token.lexeme); - - if variable.is_none() { - variable = self - .environment - .enclosing - .as_mut() - .map(|env| env.get(token.lexeme)) - .flatten(); - } - - match variable { - Some(value) => value.clone().map_or_else(|| Ok(Literal::Nil), Ok), - None => Self::error(token.clone(), "Undefined variable"), - } - } - Expression::Assign(token, value) => { - let value = self.evaluate(value)?.clone(); - - let mut was_defined = self.environment.define(token.lexeme, Some(value.clone())); - - if was_defined.is_none() { - was_defined = self - .environment - .enclosing - .as_mut() - .map(|env| env.define(token.lexeme, Some(value.clone()))) - .flatten(); - } - - if was_defined.is_none() { - return Self::error(token.clone(), "Undefined variable"); - } - - Ok(value) - } - Expression::Logical { - left, - operator, - right, - } => match operator.kind { - TokenType::Or => { - let left_value = self.evaluate(left)?; - - if is_truthy(&left_value) { - return Ok(left_value); - } - - Ok(self.evaluate(right)?) - } - TokenType::And => { - let left_value = self.evaluate(left)?; - - if !is_truthy(&left_value) { - return Ok(left_value); - } - - Ok(self.evaluate(right)?) - } - _ => unreachable!(), - }, - } + Ok(block_env.get_parent()) +} + +fn execute_if<'a>( + condition: Expression<'a>, + then: Box>, + otherwise: Box>>, + env: Environment<'a>, +) -> InterpreterResult<'a> { + let (value, mut env) = evaluate(condition, env)?; + + if is_truthy(value) { + env = execute(*then, env)?; + } else if let Some(e) = *otherwise { + env = execute(e, env)?; } - pub fn evaluate_unary( - &mut self, - operator: &Token<'a>, - right: &Expression<'a>, - ) -> InterpreterResult<'a, Literal> { - let value = self.evaluate(&right)?; - - match operator.kind { - TokenType::Bang => Ok(Literal::Boolean(!is_truthy(&value))), - TokenType::Minus => match value { - Literal::Integer(i) => Ok(Literal::Integer(-i)), - Literal::Float(f) => Ok(Literal::Float(-f)), - _ => Self::error(operator.clone(), "Operand must be a number"), - }, - _ => unreachable!(), + Ok(env) +} + +fn execute_while<'a>( + condition: Expression<'a>, + body: Box>, + mut env: Environment<'a>, +) -> InterpreterResult<'a> { + loop { + let (val, env_) = evaluate(condition.clone(), env)?; + + env = env_; + + if !is_truthy(val) { + break; } + + env = execute(*body.clone(), env)?; } - fn evaluate_binary( - &mut self, - left: &Expression<'a>, - operator: &Token<'a>, - right: &Expression<'a>, - ) -> InterpreterResult<'a, Literal> { - let left = self.evaluate(&left)?; - let right = self.evaluate(&right)?; - - match (operator.kind, left, right) { - (TokenType::Plus, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Integer(left + right)) - } - (TokenType::Plus, Literal::String(mut left), Literal::String(right)) => { - left.push_str(right.as_str()); - Ok(Literal::String(left)) - } - (TokenType::Minus, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Integer(left - right)) - } - (TokenType::Minus, Literal::Float(left), Literal::Float(right)) => { - Ok(Literal::Float(left - right)) - } - (TokenType::Greater, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Boolean(left > right)) - } - (TokenType::GreaterEqual, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Boolean(left >= right)) - } - (TokenType::Less, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Boolean(left < right)) - } - (TokenType::LessEqual, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Boolean(left <= right)) - } - (TokenType::Slash, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Integer(left / right)) - } - (TokenType::Slash, Literal::Float(left), Literal::Float(right)) => { - Ok(Literal::Float(left / right)) - } - (TokenType::Star, Literal::Integer(left), Literal::Integer(right)) => { - Ok(Literal::Integer(left * right)) - } - (TokenType::Star, Literal::Float(left), Literal::Float(right)) => { - Ok(Literal::Float(left * right)) - } - ( - TokenType::Greater - | TokenType::GreaterEqual - | TokenType::Less - | TokenType::LessEqual - | TokenType::Minus - | TokenType::Plus - | TokenType::Slash - | TokenType::Star, - _, - _, - ) => Self::error(operator.clone(), "Operands must be numbers"), - (TokenType::EqualEqual, left, right) => Ok(Literal::Boolean(left.eq(&right))), - (TokenType::BangEqual, left, right) => Ok(Literal::Boolean(!left.eq(&right))), - _ => unreachable!(), - } + Ok(env) +} + +fn is_truthy(value: Literal) -> bool { + match value { + Literal::Boolean(v) => v, + Literal::Nil => false, + _ => true, } } + +#[derive(Debug, Clone)] +pub struct InterpreterError<'a> { + pub token: Token<'a>, + pub message: &'a str, +} diff --git a/src/main.rs b/src/main.rs index 9b15989..2a0b2b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ mod lox; mod parser; use clap::Parser as ArgsParser; -use interpreter::Interpreter; use lexer::Token; use std::path::PathBuf; @@ -28,13 +27,5 @@ fn main() { let expression = parser.parse().unwrap(); - let mut interpreter = Interpreter::new(expression); - - let result = interpreter.interpret(); - - if result.is_err() { - let error = result.unwrap_err(); - println!("{:?}", error); - std::process::exit(65); - } + interpreter::run(expression); }