Refactor environment to use stack-based scoping
The commit rewrites the environment to use a stack of hash maps for managing variable scopes. This replaces the old parent-reference approach with a simpler and more efficient stack-based model. Key changes: - Rename Environment to EnvironmentStack - Store scopes in a Vec of HashMaps - Add push/pop scope operations for block handling - Update interpreter to properly manage scope lifetimes - Clean up error handling with helper functions
This commit is contained in:
+50
-80
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
backend::environment::Environment,
|
||||
backend::environment::EnvironmentStack,
|
||||
frontend::{
|
||||
ast::{AstNode, AstNodeKind, Expr, Stmt},
|
||||
source_registry::SourceSlice,
|
||||
@@ -8,7 +8,7 @@ use crate::{
|
||||
result::{LoxError, LoxResult},
|
||||
};
|
||||
use std::{
|
||||
fmt::{format, Debug, Display},
|
||||
fmt::{Debug, Display},
|
||||
ops::{Add, Div, Mul, Neg, Not, Rem, Sub},
|
||||
};
|
||||
|
||||
@@ -169,59 +169,17 @@ impl From<LiteralValue> for bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Interpreter<'a> {
|
||||
enviorment: &'a mut Environment<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Interpreter<'a> {
|
||||
pub fn new(env: &'a mut Environment<'a>) -> Self {
|
||||
Self { enviorment: env }
|
||||
}
|
||||
|
||||
fn interpret_binary(
|
||||
&mut self,
|
||||
left: AstNode<Expr>,
|
||||
operator: TokenType,
|
||||
right: AstNode<Expr>,
|
||||
source_slice: SourceSlice,
|
||||
) -> LoxResult<LiteralValue> {
|
||||
let left_value = self.interpret(left)?;
|
||||
let right_value = self.interpret(right)?;
|
||||
match operator {
|
||||
TokenType::Minus => left_value - right_value,
|
||||
TokenType::Plus => left_value.add_with_source(right_value, source_slice.clone()),
|
||||
TokenType::Slash => left_value / right_value,
|
||||
TokenType::Star => left_value * right_value,
|
||||
TokenType::EqualEqual => Ok(LiteralValue::Boolean(left_value == right_value)),
|
||||
TokenType::BangEqual => Ok(LiteralValue::Boolean(left_value != right_value)),
|
||||
TokenType::Greater => Ok(LiteralValue::Boolean(left_value > right_value)),
|
||||
TokenType::GreaterEqual => Ok(LiteralValue::Boolean(left_value >= right_value)),
|
||||
TokenType::Less => Ok(LiteralValue::Boolean(left_value < right_value)),
|
||||
TokenType::LessEqual => Ok(LiteralValue::Boolean(left_value <= right_value)),
|
||||
TokenType::Percent => left_value % right_value,
|
||||
|
||||
TokenType::And => Ok(LiteralValue::Boolean(
|
||||
left_value.is_truthy() && right_value.is_truthy(),
|
||||
)),
|
||||
TokenType::Or => Ok(LiteralValue::Boolean(
|
||||
left_value.is_truthy() || right_value.is_truthy(),
|
||||
)),
|
||||
_ => Err(LoxError::RuntimeError {
|
||||
source_slice: SourceSlice::default(), // todo change this to the actual source slice
|
||||
message: format!("Unsupported binary operator {}", operator),
|
||||
}),
|
||||
}
|
||||
}
|
||||
pub struct Interpreter {
|
||||
enviorment: EnvironmentStack,
|
||||
}
|
||||
|
||||
pub trait EvaluateInterpreter<T> {
|
||||
fn interpret(&mut self, stmt: T) -> LoxResult<LiteralValue>;
|
||||
}
|
||||
|
||||
impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter<AstNode<R>>
|
||||
for Interpreter<'a>
|
||||
impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter<AstNode<R>> for Interpreter
|
||||
where
|
||||
Interpreter<'a>: EvaluateInterpreter<R>,
|
||||
Interpreter: EvaluateInterpreter<R>,
|
||||
{
|
||||
fn interpret(&mut self, stmt: AstNode<R>) -> LoxResult<LiteralValue> {
|
||||
match self.interpret(stmt.node.clone()) {
|
||||
@@ -235,7 +193,7 @@ where
|
||||
}
|
||||
|
||||
// Direct Expr evaluation to avoid infinite recursion
|
||||
impl<'a> EvaluateInterpreter<Expr> for Interpreter<'a> {
|
||||
impl EvaluateInterpreter<Expr> for Interpreter {
|
||||
fn interpret(&mut self, expr: Expr) -> LoxResult<LiteralValue> {
|
||||
match expr {
|
||||
Expr::Literal { value } => Ok(value),
|
||||
@@ -258,7 +216,7 @@ impl<'a> EvaluateInterpreter<Expr> for Interpreter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> EvaluateInterpreter<AstNode<Stmt>> for Interpreter<'a> {
|
||||
impl EvaluateInterpreter<AstNode<Stmt>> for Interpreter {
|
||||
fn interpret(&mut self, node: AstNode<Stmt>) -> LoxResult<LiteralValue> {
|
||||
let stmt = node.node;
|
||||
let _source_slice = node.source_slice;
|
||||
@@ -266,7 +224,13 @@ impl<'a> EvaluateInterpreter<AstNode<Stmt>> for Interpreter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Interpreter<'a> {
|
||||
impl Interpreter {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enviorment: EnvironmentStack::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_binary(
|
||||
&mut self,
|
||||
left: LiteralValue,
|
||||
@@ -311,30 +275,7 @@ impl<'a> Interpreter<'a> {
|
||||
println!("print interpreter: \t{}", value);
|
||||
Ok(LiteralValue::Nil)
|
||||
}
|
||||
Stmt::Block { statements } => {
|
||||
let (elements, final_expr) = match statements.split_last() {
|
||||
Some((stmt, body)) => match &stmt.node {
|
||||
Stmt::Expression { expression } => (body, Some(expression)),
|
||||
Stmt::Return { expression } => (body, Some(expression)),
|
||||
_ => (statements.as_slice(), None),
|
||||
},
|
||||
|
||||
None => {
|
||||
(&[][..], None) // Blocco vuoto
|
||||
}
|
||||
};
|
||||
|
||||
// Ora elements è sempre disponibile
|
||||
for statement in elements.iter() {
|
||||
self.interpret((*statement).clone())?;
|
||||
}
|
||||
|
||||
// Gestisci l'espressione finale se presente
|
||||
match final_expr {
|
||||
Some(expr) => self.interpret(*expr.clone()),
|
||||
None => Ok(LiteralValue::Nil),
|
||||
}
|
||||
}
|
||||
Stmt::Block { statements } => self.evaluate_block(*statements),
|
||||
Stmt::Stmt { expression } => self.interpret(*expression.clone()),
|
||||
Stmt::Return { expression } => self.interpret(*expression),
|
||||
Stmt::Var { name, initializer } => {
|
||||
@@ -396,11 +337,40 @@ impl<'a> Interpreter<'a> {
|
||||
}
|
||||
Ok(LiteralValue::Nil)
|
||||
}
|
||||
Stmt::For {
|
||||
variable,
|
||||
iterable,
|
||||
body,
|
||||
} => todo!(),
|
||||
Stmt::For { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_block(&mut self, statements: Vec<AstNode<Stmt>>) -> LoxResult<LiteralValue> {
|
||||
self.enviorment.push_new_scope();
|
||||
let (elements, final_expr) = match statements.split_last() {
|
||||
Some((stmt, body)) => match &stmt.node {
|
||||
Stmt::Expression { expression } => (body, Some(expression)),
|
||||
Stmt::Return { expression } => (body, Some(expression)),
|
||||
_ => (statements.as_slice(), None),
|
||||
},
|
||||
|
||||
None => {
|
||||
(&[][..], None) // Blocco vuoto
|
||||
}
|
||||
};
|
||||
|
||||
// Ora elements è sempre disponibile
|
||||
for statement in elements.iter() {
|
||||
self.interpret((*statement).clone())?;
|
||||
}
|
||||
|
||||
// Gestisci l'espressione finale se presente
|
||||
match final_expr {
|
||||
Some(expr) => {
|
||||
let res = self.interpret(*expr.clone());
|
||||
self.enviorment.pop_scope();
|
||||
res
|
||||
}
|
||||
None => {
|
||||
self.enviorment.pop_scope();
|
||||
Ok(LiteralValue::Nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user