@@ -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) ]
84104mod 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