1
1
use std:: cell:: RefCell ;
2
- use std:: fmt:: Display ;
2
+ use std:: fmt:: { Display , Formatter } ;
3
3
use std:: { collections:: HashMap , rc:: Rc } ;
4
4
5
5
use crate :: lox:: entities:: expr:: { ExprFunction , ExprKind } ;
@@ -19,10 +19,36 @@ use log::trace;
19
19
use loxrs_env:: Scope ;
20
20
use loxrs_types:: { LoxErr , Result } ;
21
21
22
+ #[ derive( Default , Debug , Clone , PartialEq ) ]
23
+ enum VarStatus {
24
+ #[ default]
25
+ Declared ,
26
+ Defined ,
27
+ Assigned ,
28
+ }
29
+
30
+ impl Display for VarStatus {
31
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
32
+ write ! (
33
+ f,
34
+ "{}" ,
35
+ match self {
36
+ Self :: Declared => "declared" ,
37
+ Self :: Defined => "defined" ,
38
+ Self :: Assigned => "assigned" ,
39
+ }
40
+ )
41
+ }
42
+ }
43
+
22
44
#[ derive( Debug ) ]
23
45
pub struct Resolver {
24
46
interpreter : Rc < RefCell < Interpreter > > ,
25
- stack : Vec < HashMap < String , bool > > ,
47
+ // TODO here this needs to be changed into an enum
48
+ // and on `assign` it needs to be set to assigned
49
+ // when we pop a scope, any unassigned vars should be
50
+ // an error
51
+ stack : Vec < HashMap < String , VarStatus > > ,
26
52
curr_function : FuncType ,
27
53
}
28
54
@@ -65,10 +91,11 @@ impl Resolver {
65
91
for param in & stmt. def . params {
66
92
self . declare ( param) ?;
67
93
self . define ( param) ?;
94
+ self . assign ( param) ?;
68
95
}
69
96
self . resolve_stmt ( & Stmt :: Block ( stmt. def . body . to_owned ( ) ) ) ?;
70
97
71
- self . end_scope ( ) ;
98
+ self . end_scope ( ) ? ;
72
99
73
100
self . curr_function = prev_function_type;
74
101
Ok ( None )
@@ -86,15 +113,47 @@ impl Resolver {
86
113
} ) ;
87
114
}
88
115
89
- last. insert ( name. extract_identifier_str ( ) ?. to_owned ( ) , false ) ;
116
+ last. insert (
117
+ name. extract_identifier_str ( ) ?. to_owned ( ) ,
118
+ VarStatus :: default ( ) ,
119
+ ) ;
90
120
}
91
121
92
122
Ok ( None )
93
123
}
94
124
95
125
fn define ( & mut self , name : & Token ) -> Result < Option < Value > > {
126
+ let var_name = name. extract_identifier_str ( ) ?;
96
127
if let Some ( last) = self . stack . last_mut ( ) {
97
- last. insert ( name. extract_identifier_str ( ) ?. to_owned ( ) , true ) ;
128
+ if !last. contains_key ( var_name) {
129
+ return Err ( LoxErr :: Resolve {
130
+ message : format ! ( "Can't define local variable {} before it is declared\n at line: {}, col: {}" ,
131
+ var_name, name. line,
132
+ name. column) ,
133
+ } ) ;
134
+ }
135
+ last. insert (
136
+ name. extract_identifier_str ( ) ?. to_owned ( ) ,
137
+ VarStatus :: Defined ,
138
+ ) ;
139
+ }
140
+
141
+ Ok ( None )
142
+ }
143
+
144
+ fn assign ( & mut self , name : & Token ) -> Result < Option < Value > > {
145
+ let var_name = name. extract_identifier_str ( ) ?;
146
+ if let Some ( last) = self . stack . last_mut ( ) {
147
+ if !last
148
+ . get ( var_name)
149
+ . is_some_and ( |el| * el == VarStatus :: Defined )
150
+ {
151
+ return Err ( LoxErr :: Resolve {
152
+ message : format ! ( "Can't assign local variable {} before it is defined\n at line: {}, col: {}" , var_name, name. line,
153
+ name. column) ,
154
+ } ) ;
155
+ }
156
+ last. insert ( var_name. to_owned ( ) , VarStatus :: Assigned ) ;
98
157
}
99
158
100
159
Ok ( None )
@@ -104,8 +163,17 @@ impl Resolver {
104
163
self . stack . push ( HashMap :: new ( ) ) ;
105
164
}
106
165
107
- fn end_scope ( & mut self ) {
108
- self . stack . pop ( ) ;
166
+ fn end_scope ( & mut self ) -> Result < Option < Value > > {
167
+ if let Some ( stack) = self . stack . pop ( ) {
168
+ for ( k, v) in stack {
169
+ if v != VarStatus :: Assigned {
170
+ return Err ( LoxErr :: Resolve {
171
+ message : format ! ( "Variable `{}` not assigned" , k) ,
172
+ } ) ;
173
+ }
174
+ }
175
+ }
176
+ Ok ( None )
109
177
}
110
178
111
179
pub fn resolve ( & mut self , stmts : & Vec < Stmt > ) -> Result < Option < Value > > {
@@ -125,9 +193,9 @@ impl Resolver {
125
193
Ok ( None )
126
194
}
127
195
128
- fn resolve_local ( & self , expr : & Expr , name : & str ) -> Result < Option < Value > > {
196
+ fn resolve_local ( & mut self , expr : & Expr , name : & str , assign : bool ) -> Result < Option < Value > > {
129
197
trace ! ( "resolving to locals: {} with stack: {}" , expr, self , ) ;
130
- for ( idx, scope) in self . stack . iter ( ) . rev ( ) . enumerate ( ) {
198
+ for ( idx, scope) in self . stack . iter_mut ( ) . rev ( ) . enumerate ( ) {
131
199
trace ! (
132
200
"searching for {} within stack no: {} and curr stack: {:?}" ,
133
201
expr,
@@ -137,6 +205,10 @@ impl Resolver {
137
205
if scope. contains_key ( name) {
138
206
trace ! ( "found! resolving {} within stack no.: {}" , expr, idx, ) ;
139
207
self . interpreter . as_ref ( ) . borrow_mut ( ) . resolve ( expr, idx) ;
208
+ if assign {
209
+ trace ! ( "Also setting {} to assigned" , name) ;
210
+ scope. insert ( name. to_owned ( ) , VarStatus :: Assigned ) ;
211
+ }
140
212
return Ok ( None ) ;
141
213
}
142
214
}
@@ -189,6 +261,10 @@ impl StmtVisitor for Resolver {
189
261
self . declare ( & var. token ) ?;
190
262
if let Some ( expr) = & var. expr {
191
263
self . resolve_expr ( expr) ?;
264
+ self . define ( & var. token ) ?;
265
+ self . assign ( & var. token ) ?;
266
+
267
+ return Ok ( None ) ;
192
268
}
193
269
194
270
self . define ( & var. token ) ?;
@@ -198,6 +274,7 @@ impl StmtVisitor for Resolver {
198
274
fn fun_stmt ( & mut self , stmt : & StmtFun ) -> Result < Option < Value > > {
199
275
self . declare ( & stmt. name ) ?;
200
276
self . define ( & stmt. name ) ?;
277
+ self . assign ( & stmt. name ) ?;
201
278
self . resolve_fun_stmt ( stmt)
202
279
}
203
280
@@ -217,7 +294,7 @@ impl StmtVisitor for Resolver {
217
294
self . resolve ( & block. stmts ) ?;
218
295
219
296
trace ! ( "done traversing block! ejecting scope... {}" , & self ) ;
220
- self . end_scope ( ) ;
297
+ self . end_scope ( ) ? ;
221
298
222
299
Ok ( None )
223
300
}
@@ -248,13 +325,14 @@ impl ExprVisitor<Option<Value>> for Resolver {
248
325
for param in & def. params {
249
326
self . declare ( param) ?;
250
327
self . define ( param) ?;
328
+ self . assign ( param) ?;
251
329
}
252
330
253
331
self . resolve_stmt ( & Stmt :: Block ( StmtBlock {
254
332
stmts : def. body . stmts . to_owned ( ) ,
255
333
} ) ) ?;
256
334
257
- self . end_scope ( ) ;
335
+ self . end_scope ( ) ? ;
258
336
259
337
self . curr_function = prev_function_type;
260
338
Ok ( None )
@@ -280,14 +358,14 @@ impl ExprVisitor<Option<Value>> for Resolver {
280
358
self . resolve_expr ( & expression. expression )
281
359
}
282
360
283
- fn var ( & self , expression : & Expr ) -> Result < Option < Value > > {
361
+ fn var ( & mut self , expression : & Expr ) -> Result < Option < Value > > {
284
362
if let ExprKind :: Var ( var) = & expression. kind {
285
363
trace ! ( "var expr: {}" , var) ;
286
364
let name = var. extract_identifier_str ( ) ?;
287
365
if self
288
366
. stack
289
367
. last ( )
290
- . is_some_and ( |last| last. get ( name) . is_some_and ( |el| ! * el) )
368
+ . is_some_and ( |last| last. get ( name) . is_some_and ( |el| * el == VarStatus :: Declared ) )
291
369
{
292
370
return Err ( LoxErr :: Resolve {
293
371
message : format ! ( "Can't read local variable {} from its own initalizer\n at line: {}, col: {}" , name, var. line,
@@ -296,7 +374,7 @@ impl ExprVisitor<Option<Value>> for Resolver {
296
374
}
297
375
298
376
trace ! ( "resolving to locals from var expr: {}" , var) ;
299
- self . resolve_local ( expression, name) ?;
377
+ self . resolve_local ( expression, name, false ) ?;
300
378
return Ok ( None ) ;
301
379
}
302
380
@@ -334,7 +412,8 @@ impl ExprVisitor<Option<Value>> for Resolver {
334
412
expr_assign. name,
335
413
expr
336
414
) ;
337
- return self . resolve_local ( expr, expr_assign. name . extract_identifier_str ( ) ?) ;
415
+ // TODO need to set assigned here too
416
+ return self . resolve_local ( expr, expr_assign. name . extract_identifier_str ( ) ?, true ) ;
338
417
}
339
418
340
419
Err ( LoxErr :: Internal {
0 commit comments