@@ -34,7 +34,7 @@ pub enum ContractDef {
3434}
3535
3636#[ derive( Clone , Debug , PartialEq ) ]
37- pub enum FunctionDef {
37+ pub enum BlockDef {
3838 Base ( Base ) ,
3939 Array ( Array ) ,
4040}
@@ -53,25 +53,31 @@ pub struct ContractScope {
5353}
5454
5555#[ derive( Clone , Debug , PartialEq ) ]
56- pub struct FunctionScope {
56+ pub struct BlockScope {
5757 pub span : Span ,
58- pub parent : Shared < ContractScope > ,
59- pub defs : HashMap < String , FunctionDef > ,
58+ pub parent : BlockScopeParent ,
59+ pub defs : HashMap < String , BlockDef > ,
6060}
6161
6262#[ allow( dead_code) ]
6363pub enum Scope {
6464 Module ( Shared < ModuleScope > ) ,
6565 Contract ( Shared < ContractScope > ) ,
66- Function ( Shared < FunctionScope > ) ,
66+ Block ( Shared < BlockScope > ) ,
67+ }
68+
69+ #[ derive( Clone , Debug , PartialEq ) ]
70+ pub enum BlockScopeParent {
71+ Contract ( Shared < ContractScope > ) ,
72+ Block ( Shared < BlockScope > ) ,
6773}
6874
6975impl Scope {
7076 pub fn module_scope ( & self ) -> Shared < ModuleScope > {
7177 match self {
7278 Scope :: Module ( scope) => Rc :: clone ( scope) ,
7379 Scope :: Contract ( scope) => Rc :: clone ( & scope. borrow ( ) . parent ) ,
74- Scope :: Function ( scope) => Rc :: clone ( & scope. borrow ( ) . parent . borrow ( ) . parent ) ,
80+ Scope :: Block ( scope) => Rc :: clone ( & scope. borrow ( ) . contract_scope ( ) . borrow ( ) . parent ) ,
7581 }
7682 }
7783}
@@ -136,9 +142,17 @@ impl ContractScope {
136142 }
137143}
138144
139- impl FunctionScope {
140- pub fn new ( span : Span , parent : Shared < ContractScope > ) -> Shared < Self > {
141- Rc :: new ( RefCell :: new ( FunctionScope {
145+ impl BlockScope {
146+ pub fn from_contract_scope ( span : Span , parent : Shared < ContractScope > ) -> Shared < Self > {
147+ BlockScope :: new ( span, BlockScopeParent :: Contract ( parent) )
148+ }
149+
150+ pub fn from_block_scope ( span : Span , parent : Shared < BlockScope > ) -> Shared < Self > {
151+ BlockScope :: new ( span, BlockScopeParent :: Block ( parent) )
152+ }
153+
154+ pub fn new ( span : Span , parent : BlockScopeParent ) -> Shared < Self > {
155+ Rc :: new ( RefCell :: new ( BlockScope {
142156 span,
143157 parent,
144158 defs : HashMap :: new ( ) ,
@@ -147,26 +161,136 @@ impl FunctionScope {
147161
148162 #[ allow( dead_code) ]
149163 pub fn module_scope ( & self ) -> Shared < ModuleScope > {
150- Rc :: clone ( & self . parent . borrow ( ) . parent )
164+ Rc :: clone ( & self . contract_scope ( ) . borrow ( ) . parent )
151165 }
152166
167+ /// Return the contract scope and its immediate block scope child
168+ fn find_scope_boundary ( & self ) -> ( Shared < ContractScope > , Shared < BlockScope > ) {
169+ let mut parent = self . parent . clone ( ) ;
170+ let mut last_block_scope = Rc :: new ( RefCell :: new ( self . clone ( ) ) ) ;
171+ loop {
172+ parent = match parent {
173+ BlockScopeParent :: Block ( ref scope) => {
174+ last_block_scope = scope. clone ( ) ;
175+ scope. borrow ( ) . parent . clone ( )
176+ }
177+ BlockScopeParent :: Contract ( ref scope) => return ( scope. clone ( ) , last_block_scope) ,
178+ }
179+ }
180+ }
181+
182+ /// Return the contract scope that the block scope inherits from
153183 pub fn contract_scope ( & self ) -> Shared < ContractScope > {
154- Rc :: clone ( & self . parent )
184+ let ( contract_scope, _) = self . find_scope_boundary ( ) ;
185+ contract_scope
186+ }
187+
188+ /// Return the block scope that is associated with the function block
189+ pub fn function_scope ( & self ) -> Shared < BlockScope > {
190+ let ( _, function_scope) = self . find_scope_boundary ( ) ;
191+ function_scope
155192 }
156193
157194 pub fn contract_def ( & self , name : String ) -> Option < ContractDef > {
158195 self . contract_scope ( ) . borrow ( ) . def ( name)
159196 }
160197
161- pub fn def ( & self , name : String ) -> Option < FunctionDef > {
162- self . defs . get ( & name) . map ( |def| ( * def) . clone ( ) )
198+ /// Lookup definition in current or inherited block scope
199+ pub fn def ( & self , name : String ) -> Option < BlockDef > {
200+ let block_def = self . defs . get ( & name) . map ( |def| ( * def) . clone ( ) ) ;
201+ if block_def. is_none ( ) {
202+ if let BlockScopeParent :: Block ( scope) = & self . parent {
203+ scope. borrow ( ) . def ( name)
204+ } else {
205+ None
206+ }
207+ } else {
208+ block_def
209+ }
163210 }
164211
165212 pub fn add_array ( & mut self , name : String , array : Array ) {
166- self . defs . insert ( name, FunctionDef :: Array ( array) ) ;
213+ self . defs . insert ( name, BlockDef :: Array ( array) ) ;
167214 }
168215
169216 pub fn add_base ( & mut self , name : String , base : Base ) {
170- self . defs . insert ( name, FunctionDef :: Base ( base) ) ;
217+ self . defs . insert ( name, BlockDef :: Base ( base) ) ;
218+ }
219+ }
220+
221+ #[ cfg( test) ]
222+ mod tests {
223+ use crate :: namespace:: scopes:: {
224+ BlockDef ,
225+ BlockScope ,
226+ ContractScope ,
227+ ModuleScope ,
228+ } ;
229+ use crate :: namespace:: types:: Base ;
230+ use fe_parser:: span:: Span ;
231+
232+ #[ test]
233+ fn test_scope_resolution_on_first_level_block_scope ( ) {
234+ let module_scope = ModuleScope :: new ( ) ;
235+ let contract_scope = ContractScope :: new ( module_scope) ;
236+ let block_scope_1 =
237+ BlockScope :: from_contract_scope ( Span :: new ( 0 , 0 ) , contract_scope. clone ( ) ) ;
238+ assert_eq ! ( block_scope_1, block_scope_1. borrow( ) . function_scope( ) ) ;
239+ assert_eq ! ( contract_scope, block_scope_1. borrow( ) . contract_scope( ) ) ;
240+ }
241+
242+ #[ test]
243+ fn test_scope_resolution_on_second_level_block_scope ( ) {
244+ let module_scope = ModuleScope :: new ( ) ;
245+ let contract_scope = ContractScope :: new ( module_scope) ;
246+ let block_scope_1 =
247+ BlockScope :: from_contract_scope ( Span :: new ( 0 , 0 ) , contract_scope. clone ( ) ) ;
248+ let block_scope_2 = BlockScope :: from_block_scope ( Span :: new ( 0 , 0 ) , block_scope_1. clone ( ) ) ;
249+ assert_eq ! ( block_scope_1, block_scope_2. borrow( ) . function_scope( ) ) ;
250+ assert_eq ! ( contract_scope, block_scope_2. borrow( ) . contract_scope( ) ) ;
251+ }
252+
253+ #[ test]
254+ fn test_1st_level_def_lookup_on_1st_level_block_scope ( ) {
255+ let module_scope = ModuleScope :: new ( ) ;
256+ let contract_scope = ContractScope :: new ( module_scope) ;
257+ let block_scope_1 =
258+ BlockScope :: from_contract_scope ( Span :: new ( 0 , 0 ) , contract_scope. clone ( ) ) ;
259+ block_scope_1
260+ . borrow_mut ( )
261+ . add_base ( "some_thing" . to_string ( ) , Base :: Bool ) ;
262+ assert_eq ! (
263+ Some ( BlockDef :: Base ( Base :: Bool ) ) ,
264+ block_scope_1. borrow( ) . def( "some_thing" . to_string( ) )
265+ ) ;
266+ }
267+
268+ #[ test]
269+ fn test_1st_level_def_lookup_on_2nd_level_block_scope ( ) {
270+ let module_scope = ModuleScope :: new ( ) ;
271+ let contract_scope = ContractScope :: new ( module_scope) ;
272+ let block_scope_1 =
273+ BlockScope :: from_contract_scope ( Span :: new ( 0 , 0 ) , contract_scope. clone ( ) ) ;
274+ let block_scope_2 = BlockScope :: from_block_scope ( Span :: new ( 0 , 0 ) , block_scope_1. clone ( ) ) ;
275+ block_scope_1
276+ . borrow_mut ( )
277+ . add_base ( "some_thing" . to_string ( ) , Base :: Bool ) ;
278+ assert_eq ! (
279+ Some ( BlockDef :: Base ( Base :: Bool ) ) ,
280+ block_scope_2. borrow( ) . def( "some_thing" . to_string( ) )
281+ ) ;
282+ }
283+
284+ #[ test]
285+ fn test_2nd_level_def_lookup_on_1nd_level_block_scope_fails ( ) {
286+ let module_scope = ModuleScope :: new ( ) ;
287+ let contract_scope = ContractScope :: new ( module_scope) ;
288+ let block_scope_1 =
289+ BlockScope :: from_contract_scope ( Span :: new ( 0 , 0 ) , contract_scope. clone ( ) ) ;
290+ let block_scope_2 = BlockScope :: from_block_scope ( Span :: new ( 0 , 0 ) , block_scope_1. clone ( ) ) ;
291+ block_scope_2
292+ . borrow_mut ( )
293+ . add_base ( "some_thing" . to_string ( ) , Base :: Bool ) ;
294+ assert_eq ! ( None , block_scope_1. borrow( ) . def( "some_thing" . to_string( ) ) ) ;
171295 }
172296}
0 commit comments