@@ -31,32 +31,58 @@ impl Lifetime {
31
31
}
32
32
33
33
/// Represents a structure that is used to map Lua variables to registers, and to keep
34
- /// track of their lifetimes. Each Lua file has its own register map.
34
+ /// track of their lifetimes. Each Lua module has its own register map.
35
35
pub struct RegisterMap < ' a > {
36
36
lifetimes : Vec < Lifetime > ,
37
- reg_map : HashMap < & ' a str , usize > ,
37
+ reg_maps : Vec < HashMap < & ' a str , usize > > ,
38
38
}
39
39
40
40
impl < ' a > RegisterMap < ' a > {
41
41
pub fn new ( ) -> RegisterMap < ' a > {
42
42
RegisterMap {
43
43
lifetimes : vec ! [ ] ,
44
- reg_map : HashMap :: new ( ) ,
44
+ // the first map holds the variables of the module
45
+ reg_maps : vec ! [ HashMap :: new( ) ] ,
45
46
}
46
47
}
47
48
48
- /// Creates and returns a new register, whose lifetime begins from self.current_instr.
49
+ /// Pushes a new map of registers. All new registers will be allocated in the newly
50
+ /// created map.
51
+ pub fn push_scope ( & mut self ) {
52
+ self . reg_maps . push ( HashMap :: new ( ) ) ;
53
+ }
54
+
55
+ /// Pops the last map of registers.
56
+ pub fn pop_scope ( & mut self ) {
57
+ self . reg_maps . pop ( ) ;
58
+ }
59
+
60
+ /// Creates and returns a new register.
49
61
pub fn get_new_reg ( & mut self ) -> usize {
50
62
let lifetime = Lifetime :: new ( self . lifetimes . len ( ) ) ;
51
63
self . lifetimes . push ( lifetime) ;
52
64
self . lifetimes . len ( ) - 1
53
65
}
54
66
55
- /// Get the register of <name>, or create it if it doesn't exist.
67
+ /// Creates a mapping between <name> and a newly created register.
68
+ pub fn create_reg ( & mut self , name : & ' a str ) -> usize {
69
+ let reg = self . get_new_reg ( ) ;
70
+ self . set_reg ( name, reg) ;
71
+ reg
72
+ }
73
+
74
+ /// Get the register of <name>.
56
75
pub fn get_reg ( & mut self , name : & ' a str ) -> usize {
57
76
let lifetimes = & mut self . lifetimes ;
58
- * self
59
- . reg_map
77
+ for map in self . reg_maps [ 1 ..] . iter ( ) . rev ( ) {
78
+ if let Some ( & reg) = map. get ( name) {
79
+ return reg;
80
+ }
81
+ }
82
+ // In lua, if a variable is queried, but isn't in scope, a Nil is returned instead
83
+ // If none of the maps have a definition for <name> that means we have to define
84
+ // it ourselves in the map of the module (the first map in <reg_maps>).
85
+ * self . reg_maps [ 0 ]
60
86
. entry ( name)
61
87
. and_modify ( |reg| {
62
88
let len = lifetimes. len ( ) ;
@@ -71,7 +97,7 @@ impl<'a> RegisterMap<'a> {
71
97
72
98
/// Set the register of <name> to <reg>.
73
99
pub fn set_reg ( & mut self , name : & ' a str , reg : usize ) {
74
- self . reg_map . insert ( name, reg) ;
100
+ self . reg_maps . last_mut ( ) . unwrap ( ) . insert ( name, reg) ;
75
101
}
76
102
77
103
/// Get the total number of registers that were needed.
@@ -98,17 +124,34 @@ mod tests {
98
124
}
99
125
100
126
#[ test]
101
- fn get_reg_correctly_maps_strings_to_registers ( ) {
127
+ fn correctly_maps_strings_to_registers ( ) {
102
128
let mut rm = RegisterMap :: new ( ) ;
103
129
// create a new register
104
130
assert_eq ! ( rm. get_new_reg( ) , 0 ) ;
105
131
// create a mapping
132
+ assert_eq ! ( rm. create_reg( "foo" ) , 1 ) ;
133
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "foo" ) . unwrap( ) , 1 ) ;
106
134
assert_eq ! ( rm. get_reg( "foo" ) , 1 ) ;
107
- assert_eq ! ( * rm. reg_map. get( "foo" ) . unwrap( ) , 1 ) ;
135
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "foo" ) . unwrap( ) , 1 ) ;
136
+ assert_eq ! ( rm. get_reg( "bar" ) , 2 ) ;
137
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "bar" ) . unwrap( ) , 2 ) ;
138
+ // create a new scope in which we define another foo
139
+ rm. push_scope ( ) ;
140
+ assert_eq ! ( rm. create_reg( "foo" ) , 3 ) ;
141
+ assert_eq ! ( * rm. reg_maps[ 1 ] . get( "foo" ) . unwrap( ) , 3 ) ;
142
+ assert_eq ! ( rm. get_reg( "foo" ) , 3 ) ;
143
+ assert_eq ! ( * rm. reg_maps[ 1 ] . get( "foo" ) . unwrap( ) , 3 ) ;
144
+ assert_eq ! ( rm. get_reg( "bar" ) , 2 ) ;
145
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "bar" ) . unwrap( ) , 2 ) ;
146
+ assert ! ( rm. reg_maps[ 1 ] . get( "bar" ) . is_none( ) ) ;
147
+ rm. pop_scope ( ) ;
148
+ // pop the scope and query foo and bar again to check if they have the same values
108
149
assert_eq ! ( rm. get_reg( "foo" ) , 1 ) ;
109
- assert_eq ! ( * rm. reg_map. get( "foo" ) . unwrap( ) , 1 ) ;
150
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "foo" ) . unwrap( ) , 1 ) ;
151
+ assert_eq ! ( rm. get_reg( "bar" ) , 2 ) ;
152
+ assert_eq ! ( * rm. reg_maps[ 0 ] . get( "bar" ) . unwrap( ) , 2 ) ;
110
153
// test total number of registers created
111
- assert_eq ! ( rm. reg_count( ) , 2 ) ;
154
+ assert_eq ! ( rm. reg_count( ) , 4 ) ;
112
155
}
113
156
114
157
#[ test]
@@ -117,12 +160,30 @@ mod tests {
117
160
let reg1 = rm. get_new_reg ( ) ;
118
161
assert_eq ! ( rm. lifetimes[ reg1] . 0 , 0 ) ;
119
162
assert_eq ! ( rm. lifetimes[ reg1] . 1 , 1 ) ;
120
- let reg2 = rm. get_reg ( "reg" ) ;
163
+ let reg2 = rm. create_reg ( "reg" ) ;
121
164
assert_eq ! ( rm. lifetimes[ reg2] . 0 , 1 ) ;
122
165
assert_eq ! ( rm. lifetimes[ reg2] . 1 , 2 ) ;
123
166
rm. get_reg ( "reg" ) ;
124
167
assert_eq ! ( rm. lifetimes[ reg2] . 0 , 1 ) ;
125
168
assert_eq ! ( rm. lifetimes[ reg2] . 1 , 3 ) ;
126
- assert_eq ! ( rm. reg_count( ) , 2 ) ;
169
+ rm. push_scope ( ) ;
170
+ let reg3 = rm. create_reg ( "reg3" ) ;
171
+ rm. pop_scope ( ) ;
172
+ assert_eq ! ( rm. lifetimes[ reg3] . 0 , 2 ) ;
173
+ assert_eq ! ( rm. lifetimes[ reg3] . 1 , 3 ) ;
174
+ assert_eq ! ( rm. reg_count( ) , 3 ) ;
175
+ }
176
+
177
+ #[ test]
178
+ fn registers_are_retrieved_in_the_correct_order ( ) {
179
+ let mut rm = RegisterMap :: new ( ) ;
180
+ for i in 0 ..3 {
181
+ rm. push_scope ( ) ;
182
+ rm. create_reg ( "foo" ) ;
183
+ }
184
+ for i in 0 ..3 {
185
+ assert_eq ! ( rm. get_reg( "foo" ) , 2 - i) ;
186
+ rm. pop_scope ( ) ;
187
+ }
127
188
}
128
189
}
0 commit comments