From 6bf255668ad8dcc5f09d7765eb3b63c9bed11492 Mon Sep 17 00:00:00 2001 From: Giulio Agostini Date: Sat, 11 Jul 2026 18:07:07 +0200 Subject: [PATCH] wip: i dont rembemer --- examples/test_closure.lox | 15 ++ src/backend/environment.rs | 35 +++-- src/backend/interpreter.rs | 8 +- src/common/base_value.rs | 5 +- src/common/lox_result.rs | 6 +- src/frontend/mod.rs | 1 + src/frontend/parser.rs | 8 +- src/frontend/variable_resolution.rs | 204 ++++++++++++++++++++++++++++ 8 files changed, 253 insertions(+), 29 deletions(-) create mode 100644 src/frontend/variable_resolution.rs diff --git a/examples/test_closure.lox b/examples/test_closure.lox index 2e288c0..719f093 100644 --- a/examples/test_closure.lox +++ b/examples/test_closure.lox @@ -10,3 +10,18 @@ end internal := closure(); internal(); + +a := "Global"; +b := a; +c := b; +c = b = a; +d := c = b = a; +do + showA :: fn() do + print a; + end + + showA(); + a := "Local"; + showA(); +end diff --git a/src/backend/environment.rs b/src/backend/environment.rs index 97166ec..6b4f9cd 100644 --- a/src/backend/environment.rs +++ b/src/backend/environment.rs @@ -1,34 +1,45 @@ -use std::collections::HashMap; - use crate::{ - common::{ - base_value::BaseValue, - lox_result::{runtime_error, LoxResult}, - }, + common::lox_result::{runtime_error, LoxResult}, frontend::source_registry::SourceSlice, }; +use std::collections::HashMap; +use std::fmt::Debug; + +pub type Environment = HashMap; #[derive(Debug, Clone, PartialEq)] -pub struct EnvironmentStack { - stack: Vec>, +pub struct EnvironmentStack { + stack: Vec>, } -impl EnvironmentStack { +impl EnvironmentStack { pub fn new() -> Self { EnvironmentStack { stack: vec![HashMap::new()], } } + pub fn is_empty(&self) -> bool { + self.stack.is_empty() + } + pub fn push_new_scope(&mut self) { self.stack.push(HashMap::new()); } + pub fn push_existing_scope(&mut self, scope: HashMap) { + self.stack.push(scope); + } + pub fn pop_scope(&mut self) { self.stack.pop(); } - pub fn get(&self, name: &str) -> LoxResult { + pub fn clone_last_scope(&mut self) -> HashMap { + self.stack.last().unwrap().clone() + } + + pub fn get(&self, name: &str) -> LoxResult { let size = self.stack.len(); for i in (0..size).rev() { @@ -42,12 +53,12 @@ impl EnvironmentStack { ) } - pub fn declare(&mut self, name: String, value: BaseValue) -> LoxResult { + pub fn declare(&mut self, name: String, value: T) -> LoxResult { self.stack.last_mut().unwrap().insert(name, value.clone()); Ok(value) } - pub fn set(&mut self, name: String, value: BaseValue) -> LoxResult { + pub fn set(&mut self, name: String, value: T) -> LoxResult { let size = self.stack.len(); for i in (0..size).rev() { diff --git a/src/backend/interpreter.rs b/src/backend/interpreter.rs index 360d8ec..4c608f5 100644 --- a/src/backend/interpreter.rs +++ b/src/backend/interpreter.rs @@ -10,14 +10,14 @@ use crate::{ use std::fmt::{Debug, Display}; pub struct Interpreter { - enviorment: EnvironmentStack, + enviorment: EnvironmentStack, } pub trait EvaluateInterpreter { fn evaluate(&mut self, stmt: T) -> LoxResult; } -impl<'a, R: AstNodeKind + Clone + Debug + Display> EvaluateInterpreter> for Interpreter +impl EvaluateInterpreter> for Interpreter where Interpreter: EvaluateInterpreter, { @@ -36,8 +36,6 @@ impl EvaluateInterpreter for Interpreter { Expr::Literal { value } => match value { BaseValue::Function(mut func) => { func.closure = Some(self.enviorment.clone()); - println!("Closure created"); - println!("current enviorment: {:?}", self.enviorment); Ok(BaseValue::Function(func)) } _ => Ok(value), @@ -128,9 +126,7 @@ impl Interpreter { match function { BaseValue::NativeFunction(func) => Ok((func.function)(&evaluated_arguments)), BaseValue::Function(func) => { - // Save the current environment let saved_env = self.enviorment.clone(); - // If the function captured a closure, use it as the base environment if let Some(closure_env) = func.closure { self.enviorment = closure_env; diff --git a/src/common/base_value.rs b/src/common/base_value.rs index 6eb2976..1929a4d 100644 --- a/src/common/base_value.rs +++ b/src/common/base_value.rs @@ -2,6 +2,7 @@ use core::fmt; use std::fmt::Display; use std::ops::{Add, Div, Mul, Not, Rem, Sub}; +use crate::backend::environment::Environment; use crate::common::lox_result::{runtime_error, LoxResult}; use crate::{ backend::environment::EnvironmentStack, @@ -312,7 +313,7 @@ pub struct LoxFunction { pub parameters: Vec<(String, String)>, pub return_type: Option, pub body: AstNode, - pub closure: Option, + pub closure: Option>, pub guard: Option>, } @@ -320,7 +321,7 @@ impl LoxFunction { pub fn new( parameters: Vec<(String, String)>, body: AstNode, - closure: Option, + closure: Option>, guard: Option>, ) -> Self { LoxFunction { diff --git a/src/common/lox_result.rs b/src/common/lox_result.rs index dce78e0..63327b4 100644 --- a/src/common/lox_result.rs +++ b/src/common/lox_result.rs @@ -106,11 +106,7 @@ impl LoxError { LoxError::ParseError { source_slice, .. } => Some(source_slice.clone()), LoxError::IoError { .. } => None, LoxError::TypeMismatch { source_slice, .. } => Some(source_slice.clone()), - LoxError::Return { - value, - return_label, - .. - } => None, + LoxError::Return { .. } => None, } } diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 732ebff..9d25663 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -2,3 +2,4 @@ pub mod lexer; pub mod parser; pub mod source_registry; pub mod tokens; +pub mod variable_resolution; diff --git a/src/frontend/parser.rs b/src/frontend/parser.rs index 29e8dad..185502a 100644 --- a/src/frontend/parser.rs +++ b/src/frontend/parser.rs @@ -205,6 +205,10 @@ impl Parser { let mut _type_annotation = BaseValue::Nil; self.consume(TokenType::Colon, "Expect column")?; + if self.peek().token_type == TokenType::Identifier { + // TODO manage type annotation + self.consume(TokenType::Identifier, "Expect type name.")?; + } match self.peek().token_type { TokenType::Equal | TokenType::Identifier => { @@ -374,11 +378,7 @@ impl Parser { while self.peek().token_type != TokenType::EndBlock && !self.is_at_end() { let stmt = self.statement(label.clone())?; - let should_break = matches!(stmt.node, Stmt::Expression { .. }); statements.push(stmt); - if should_break { - break; - } } let end_token = self.consume(TokenType::EndBlock, "Expect 'end' after block.")?; let end_slice = end_token.source_slice.clone(); diff --git a/src/frontend/variable_resolution.rs b/src/frontend/variable_resolution.rs new file mode 100644 index 0000000..1c9d515 --- /dev/null +++ b/src/frontend/variable_resolution.rs @@ -0,0 +1,204 @@ +use crate::{ + backend::environment::EnvironmentStack, + common::{ + ast::{AstNode, AstNodeKind, Expr, Stmt}, + lox_result::{runtime_error, LoxError, LoxResult}, + }, + frontend::source_registry::SourceSlice, +}; + +use std::fmt::{Debug, Display}; +struct Resolver { + scopes: EnvironmentStack, +} + +impl Resolver { + pub fn new() -> Self { + Resolver { + scopes: EnvironmentStack::new(), + } + } + + fn declare(&mut self, name: &String) { + if self.scopes.is_empty() { + return; + } + let _ = self.scopes.set(name.clone(), false); + } + + fn define(&mut self, name: &String) { + if self.scopes.is_empty() { + return; + } + let _ = self.scopes.set(name.clone(), true); + } +} + +pub trait StaticAnalyzer { + fn resolve(&mut self, node: &T) -> LoxResult; +} + +impl StaticAnalyzer> for Resolver +where + Resolver: StaticAnalyzer, +{ + fn resolve(&mut self, node: &AstNode) -> LoxResult { + self.resolve(&node.node) + } +} + +impl StaticAnalyzer for Resolver { + fn resolve(&mut self, node: &Stmt) -> LoxResult { + match node { + Stmt::Expression { expression, .. } => { + // Visit the expression + self.resolve(expression.as_ref()) + } + Stmt::Print { expression, .. } => { + // Visit the expression + self.resolve(expression.as_ref()) + } + Stmt::VarDeclaration { + initializer, name, .. + } => { + self.declare(name); + // Visit the initializer if present + if let Some(init) = initializer { + self.resolve(init.as_ref())?; + } + self.define(name); + Ok(true) + } + Stmt::VarAssigment { value, name, .. } => { + match self.scopes.get(name) { + Ok(true) => (), + Ok(false) => { + return Err(LoxError::RuntimeError { + source_slice: SourceSlice::default(), + message: "Cant read loac variable in it own lintilizer".to_string(), + }) + } + Err(err) => return Err(err), + } + self.resolve(value.as_ref()) + } + Stmt::Return { expression, .. } => { + // Visit the return expression + self.resolve(expression.as_ref()) + } + Stmt::Block { statements, .. } => { + self.scopes.push_new_scope(); + // Visit all statements in the block + for stmt in statements.iter() { + self.resolve(stmt)?; + } + self.scopes.pop_scope(); + Ok(true) + } + Stmt::If { + condition, + then_branch, + elif_branch, + else_branch, + .. + } => { + // Visit the condition + self.resolve(condition.as_ref())?; + + // Visit the then branch + self.resolve(then_branch.as_ref())?; + + // Visit all elif branches + for (elif_condition, elif_stmt) in elif_branch.iter() { + self.resolve(elif_condition.as_ref())?; + self.resolve(elif_stmt.as_ref())?; + } + + // Visit the else branch if present + if let Some(else_stmt) = else_branch { + self.resolve(else_stmt.as_ref())?; + } + + Ok(true) + } + Stmt::While { + condition, body, .. + } => { + // Visit the condition + self.resolve(condition.as_ref())?; + + // Visit the body + self.resolve(body.as_ref())?; + Ok(true) + } + Stmt::For { + variable, + condition, + increment, + body, + .. + } => { + // Visit the variable initialization + self.resolve(variable.as_ref())?; + + // Visit the condition + self.resolve(condition.as_ref())?; + + // Visit the increment + self.resolve(increment.as_ref())?; + + // Visit the body + self.resolve(body.as_ref())?; + Ok(true) + } + } + } +} + +impl StaticAnalyzer for Resolver { + fn resolve(&mut self, node: &Expr) -> LoxResult { + match node { + Expr::Literal { .. } => { + // Leaf node - no children to visit + Ok(true) + } + Expr::Binary { left, right, .. } => { + // Visit left operand + self.resolve(left.as_ref())?; + + // Visit right operand + self.resolve(right.as_ref()) + } + Expr::Unary { operand, .. } => { + // Visit the operand + self.resolve(operand.as_ref()) + } + Expr::Grouping { expression } => { + // Visit the grouped expression + self.resolve(expression.as_ref()) + } + Expr::Identifier { name, .. } => { + if !self.scopes.is_empty() && self.scopes.get(name).is_ok() { + return Err(LoxError::ParseError { + source_slice: SourceSlice::default(), + message: "Cant read local varialbe in it own initializer".to_string(), + }); + } + Ok(true) + } + Expr::Call { + callee, arguments, .. + } => { + // Visit the callee + self.resolve(callee.as_ref())?; + + // Visit all arguments + for arg in arguments.iter() { + self.resolve(arg)?; + } + + Ok(true) + } + } + } +}