Skip to content

Commit 6cae059

Browse files
committed
[fix] New implementation for the 'lookup_variable' function
1 parent d07ecfd commit 6cae059

1 file changed

Lines changed: 81 additions & 27 deletions

File tree

src/environment/environment.rs

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ impl<A: Clone> Scope<A> {
2828
return ();
2929
}
3030

31-
fn lookup(&self, var: &Name) -> Option<&A> {
31+
fn lookup_var(&self, var: &Name) -> Option<&A> {
3232
self.variables.get(var)
3333
}
34+
35+
fn lookup_function(&self, name: &Name) -> Option<&Function> {
36+
self.functions.get(name)
37+
}
3438
}
3539

3640
#[derive(Clone)]
@@ -51,20 +55,36 @@ impl<A: Clone> Environment<A> {
5155
match self.stack.front_mut() {
5256
None => self.globals.map_variable(var, value),
5357
Some(top) => top.map_variable(var, value),
54-
};
55-
return ();
58+
}
5659
}
5760

5861
pub fn map_function(&mut self, function: Function) -> () {
59-
self.globals.map_function(function);
60-
return ();
62+
match self.stack.front_mut() {
63+
None => self.globals.map_function(function),
64+
Some(top) => top.map_function(function),
65+
}
6166
}
6267

6368
pub fn lookup(&self, var: &Name) -> Option<&A> {
64-
match self.stack.front() {
65-
None => self.globals.lookup(var),
66-
Some(top) => top.lookup(var),
69+
// First check local scopes in order
70+
for scope in self.stack.iter() {
71+
if let Some(value) = scope.lookup_var(var) {
72+
return Some(value);
73+
}
74+
}
75+
// Then check global scope
76+
self.globals.lookup_var(var)
77+
}
78+
79+
pub fn lookup_function(&self, name: &Name) -> Option<&Function> {
80+
// First check local scopes in order
81+
for scope in self.stack.iter() {
82+
if let Some(func) = scope.lookup_function(name) {
83+
return Some(func);
84+
}
6785
}
86+
// Then check global scope
87+
self.globals.lookup_function(name)
6888
}
6989

7090
pub fn scoped_function(&self) -> bool {
@@ -82,37 +102,71 @@ impl<A: Clone> Environment<A> {
82102

83103
#[cfg(test)]
84104
mod tests {
85-
use crate::environment::environment::{Environment, Scope};
105+
use super::*;
86106

87107
#[test]
88-
fn eval_map_and_lookup_var() {
89-
let mut s: Scope<i32> = Scope::new();
108+
fn test_variable_scoping() {
109+
let mut env: Environment<i32> = Environment::new();
110+
111+
// Test global scope
112+
env.map_variable("x".to_string(), 32);
113+
assert_eq!(Some(&32), env.lookup(&"x".to_string()));
90114

91-
s.map_variable("x".to_string(), 32);
92-
s.map_variable("y".to_string(), 23);
115+
// Test nested scopes
116+
env.push(); // scope 1
117+
env.map_variable("y".to_string(), 23);
118+
env.map_variable("x".to_string(), 55); // shadows global x
119+
120+
env.push(); // scope 2
121+
env.map_variable("z".to_string(), 44);
93122

94-
assert_eq!(Some(32), s.lookup(&"x".to_string()).copied());
95-
assert_eq!(Some(23), s.lookup(&"y".to_string()).copied());
123+
// Variables from all scopes should be accessible
124+
assert_eq!(Some(&55), env.lookup(&"x".to_string())); // from scope 1
125+
assert_eq!(Some(&23), env.lookup(&"y".to_string())); // from scope 1
126+
assert_eq!(Some(&44), env.lookup(&"z".to_string())); // from scope 2
127+
128+
// Pop scope 2
129+
env.pop();
130+
assert_eq!(Some(&55), env.lookup(&"x".to_string())); // still in scope 1
131+
assert_eq!(Some(&23), env.lookup(&"y".to_string())); // still in scope 1
132+
assert_eq!(None, env.lookup(&"z".to_string())); // z is gone
133+
134+
// Pop scope 1
135+
env.pop();
136+
assert_eq!(Some(&32), env.lookup(&"x".to_string())); // back to global x
137+
assert_eq!(None, env.lookup(&"y".to_string())); // y is gone
96138
}
97139

98140
#[test]
99-
fn eval_environment() {
141+
fn test_function_scoping() {
100142
let mut env: Environment<i32> = Environment::new();
143+
144+
let global_func = Function {
145+
name: "global".to_string(),
146+
kind: None,
147+
params: None,
148+
body: None,
149+
};
101150

102-
env.map_variable("x".to_string(), 32);
103-
104-
env.push();
151+
let local_func = Function {
152+
name: "local".to_string(),
153+
kind: None,
154+
params: None,
155+
body: None,
156+
};
105157

106-
env.map_variable("x".to_string(), 55);
107-
env.map_variable("y".to_string(), 23);
158+
// Test function scoping
159+
env.map_function(global_func.clone());
160+
assert!(env.lookup_function(&"global".to_string()).is_some());
108161

109-
assert_eq!(Some(55), env.lookup(&"x".to_string()).copied());
110-
assert_eq!(Some(23), env.lookup(&"y".to_string()).copied());
111-
assert_eq!(None, env.lookup(&"a".to_string()).copied());
162+
env.push();
163+
env.map_function(local_func.clone());
164+
165+
assert!(env.lookup_function(&"global".to_string()).is_some()); // can see global
166+
assert!(env.lookup_function(&"local".to_string()).is_some()); // can see local
112167

113168
env.pop();
114-
115-
assert_eq!(Some(32), env.lookup(&"x".to_string()).copied());
116-
assert_eq!(None, env.lookup(&"y".to_string()).copied());
169+
assert!(env.lookup_function(&"global".to_string()).is_some()); // global still visible
170+
assert!(env.lookup_function(&"local".to_string()).is_none()); // local gone
117171
}
118172
}

0 commit comments

Comments
 (0)