Skip to content

Commit d488d84

Browse files
Fix: propagate outer functions to new_env for recursion support
Previously, new_env was not receiving functions from the outer environment, which caused external functions to be inaccessible inside function bodies. This also broke recursion, since the function itself wasn't visible in its own scope. This commit ensures that external functions are copied into new_env, allowing function bodies to reference both external and self-defined functions.
1 parent 3135447 commit d488d84

2 files changed

Lines changed: 40 additions & 4 deletions

File tree

src/environment/environment.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,33 @@ impl<A: Clone> Scope<A> {
5252

5353
#[derive(Clone)]
5454
pub struct Environment<A> {
55+
pub current_func: String,
5556
pub globals: Scope<A>,
5657
pub stack: LinkedList<Scope<A>>,
5758
}
5859

5960
impl<A: Clone> Environment<A> {
6061
pub fn new() -> Environment<A> {
6162
Environment {
63+
current_func: String::new(),
6264
globals: Scope::new(),
6365
stack: LinkedList::new(),
6466
}
6567
}
6668

69+
pub fn get_current_func(&self) -> String {
70+
return self.current_func.clone();
71+
}
72+
73+
pub fn set_current_func(&mut self, func_name: &str) {
74+
self.current_func = func_name.to_string();
75+
}
76+
77+
pub fn set_global_functions(&mut self, global_functions: HashMap<Name, Function>) {
78+
self.globals.functions = global_functions;
79+
}
80+
81+
6782
pub fn map_variable(&mut self, var: Name, mutable: bool, value: A) -> () {
6883
match self.stack.front_mut() {
6984
None => self.globals.map_variable(var, mutable, value),
@@ -142,9 +157,22 @@ impl<A: Clone> Environment<A> {
142157
vars.push((name.clone(), value.clone()));
143158
}
144159
}
145-
146160
vars
147161
}
162+
163+
// The type checker ensures that each function is defined only once
164+
pub fn get_all_functions(&self) -> HashMap<Name,Function> {
165+
let mut all_functions = HashMap::new();
166+
for (name, func) in &self.globals.functions {
167+
all_functions.insert(name.clone(), func.clone());
168+
}
169+
for scope in self.stack.iter() {
170+
for (name, func) in &scope.functions {
171+
all_functions.insert(name.clone(), func.clone());
172+
}
173+
}
174+
all_functions
175+
}
148176
}
149177

150178
#[cfg(test)]

src/interpreter/expression_eval.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::statement_execute::Computation;
2-
use crate::environment::environment::Environment;
2+
use crate::environment::environment::{Environment, Scope};
33
use crate::ir::ast::{Expression, Name};
44

55
#[derive(Debug, PartialEq, Clone)]
@@ -398,7 +398,13 @@ pub fn eval_function_call(
398398
));
399399
}
400400

401-
new_env.push();
401+
// new_env.push(); <- Removed the push; parameters are now mapped directly to the global scope
402+
//In this new environment, external functions and actual parameters are regarded as globally accessible
403+
//This is justified, since their visibility extends across the entire function body
404+
new_env.set_current_func(&name);
405+
// Functions from the outer environment must be propagated to new_env to ensure access to external functions within the function body.
406+
// This also allows the function to reference itself, which enables recursion
407+
new_env.set_global_functions(env.get_all_functions());
402408

403409
for (formal, actual) in function_definition.params.iter().zip(args.iter()) {
404410
let value = match eval(actual.clone(), env)? {
@@ -410,9 +416,11 @@ pub fn eval_function_call(
410416
new_env.map_variable(formal.argument_name.clone(), false, value);
411417
}
412418

419+
420+
413421
// Execute the body of the function.
414422
match super::statement_execute::execute(
415-
*function_definition.body.as_ref().unwrap().clone(),
423+
*function_definition.body.as_ref().unwrap().clone(), //Push occurs here, because function body is a Statement::Block
416424
&new_env,
417425
) {
418426
Ok(Computation::Continue(_)) => Err("Function did not return a value".to_string()),

0 commit comments

Comments
 (0)