@@ -21,7 +21,13 @@ fn check_lvalue(expr: &ast::Expr) -> Result<(), Error> {
2121 }
2222}
2323
24- type VarTable = HashMap < String , String > ;
24+ #[ derive( Clone ) ]
25+ struct VarEntry {
26+ name : String ,
27+ in_current_scope : bool ,
28+ }
29+
30+ type VarTable = HashMap < String , VarEntry > ;
2531struct VariableResolution {
2632 var_table : VarTable ,
2733 var_index : i32 ,
@@ -36,23 +42,30 @@ impl VariableResolution {
3642 }
3743
3844 /// Resolve a variable name that has already been mangled
39- fn resolve_var_name ( & self , name : & Identifier ) -> Result < & String , Error > {
40- let new_name = self . var_table . get ( name. val ( ) ) ;
41- new_name . ok_or ( format ! ( "Could not find identifier {}" , name. val( ) ) )
45+ fn resolve_var_name ( & self , name : & Identifier ) -> Result < & VarEntry , Error > {
46+ let new_entry = self . var_table . get ( name. val ( ) ) ;
47+ new_entry . ok_or ( format ! ( "Could not find identifier {}" , name. val( ) ) )
4248 }
4349
4450 /// Return a globally unique variable name to avoid collisions in ASM
4551 fn record_var_name ( & mut self , name : & Identifier ) -> Result < Identifier , Error > {
4652 let orig_name = name. val ( ) ;
4753 let new_name = self . var_table . get ( orig_name) ;
48- if let Some ( name) = new_name {
49- return Err ( format ! ( "Variable {} already defined" , name) ) ;
54+ // If we find the variable in this scope, fail for a redeclaration
55+ if let Some ( name) = new_name
56+ && name. in_current_scope
57+ {
58+ return Err ( format ! ( "Variable {} already defined" , name. name) ) ;
5059 }
5160 let new_name = format ! ( "{}.{}" , orig_name, self . var_index) ;
5261 self . var_index += 1 ;
53- self
54- . var_table
55- . insert ( orig_name. to_string ( ) , new_name. clone ( ) ) ;
62+ self . var_table . insert (
63+ orig_name. to_string ( ) ,
64+ VarEntry {
65+ name : new_name. clone ( ) ,
66+ in_current_scope : true ,
67+ } ,
68+ ) ;
5669 Ok ( Identifier :: new ( & new_name) )
5770 }
5871
@@ -71,7 +84,7 @@ impl VariableResolution {
7184 }
7285 ast:: Expr :: Var ( identifier) => {
7386 let new_name = self . resolve_var_name ( & identifier) ?;
74- * identifier = Identifier :: new ( new_name) ;
87+ * identifier = Identifier :: new ( & new_name. name ) ;
7588 Ok ( ( ) )
7689 }
7790 ast:: Expr :: Conditional {
@@ -101,9 +114,25 @@ impl VariableResolution {
101114 }
102115 Ok ( ( ) )
103116 }
104- ast:: Stmt :: Compound ( block) => todo ! ( ) ,
117+ ast:: Stmt :: Compound ( block) => {
118+ // We're entering a new block so adjust name resolution by backing up
119+ // the current var table and using a new one with in_current_scope set to false
120+ let old_table = self . var_table . clone ( ) ;
121+
122+ // Note that the vars are not in the current scope
123+ self . var_table . iter_mut ( ) . for_each ( |( _, v) | {
124+ v. in_current_scope = false ;
125+ } ) ;
126+ for block_item in & mut block. items {
127+ self . resolve_in_block ( block_item) ?;
128+ }
129+ // Restore the old table as we leave the scope
130+ self . var_table = old_table;
131+ Ok ( ( ) )
132+ }
105133 }
106134 }
135+
107136 fn resolve_in_block ( & mut self , block : & mut ast:: BlockItem ) -> Result < ( ) , Error > {
108137 match block {
109138 ast:: BlockItem :: Declaration ( identifier, expr) => {
@@ -290,4 +319,50 @@ Program(
290319
291320 Ok ( ( ) )
292321 }
322+
323+ #[ test]
324+ fn resolve_compound ( ) {
325+ let main = r#"
326+ int main(void) {
327+ int x = 0;
328+ int outer = 0;
329+ {
330+ int y = x + 1;
331+ int x = y + 2;
332+ {
333+ int z = x + 1;
334+ int x = z + 2;
335+ outer = x;
336+ }
337+ }
338+ {
339+ int x = outer;
340+ return x;
341+ }
342+ }
343+ "# ;
344+
345+ let expected = r#"
346+ Program(
347+ Function main() {
348+ Declaration(x.0, $0);
349+ Declaration(outer.1, $0);
350+ Block (
351+ Declaration(y.2, Plus($x.0, $1));
352+ Declaration(x.3, Plus($y.2, $2));
353+ Block (
354+ Declaration(z.4, Plus($x.3, $1));
355+ Declaration(x.5, Plus($z.4, $2));
356+ =($outer.1, $x.5);
357+ )
358+ )
359+ Block (
360+ Declaration(x.6, $outer.1);
361+ return $x.6;
362+ )
363+ }
364+ )
365+ "# ;
366+ assert_has_pretty_print_after_semantics ( main, expected) ;
367+ }
293368}
0 commit comments