22#include <stdint.h>
33#include <stdio.h>
44#include <stdlib.h>
5+ #include <string.h>
56#include <sys/types.h>
67
78#include "chunk.h"
@@ -58,7 +59,7 @@ typedef struct
5859{
5960 Local locals [UINT8_COUNT ];
6061 int local_count ;
61- int local_depth ;
62+ int scope_depth ;
6263
6364} Compiler ;
6465
@@ -175,7 +176,7 @@ static void emit_constant(Value value)
175176static void init_compiler (Compiler * compiler )
176177{
177178 compiler -> local_count = 0 ;
178- compiler -> local_depth = 0 ;
179+ compiler -> scope_depth = 0 ;
179180 current = compiler ;
180181}
181182
@@ -190,12 +191,20 @@ static void end_compiler()
190191
191192static void begin_scope ()
192193{
193- current -> local_depth ++ ;
194+ current -> scope_depth ++ ;
194195}
195196
196197static void end_scope ()
197198{
198- current -> local_depth -- ;
199+ current -> scope_depth -- ;
200+
201+ while (current -> local_count > 0 &&
202+ current -> locals [current -> local_count - 1 ].depth >
203+ current -> scope_depth )
204+ {
205+ emit_byte (OP_POP );
206+ current -> local_count -- ;
207+ }
199208}
200209
201210static void expression ();
@@ -209,14 +218,84 @@ static u8 identifier_constant(Token* name)
209218 return make_constant (OBJ_VAL (copy_string (name -> start , name -> length )));
210219}
211220
221+ static bool identifiers_equal (Token * t1 , Token * t2 )
222+ {
223+ if (t1 -> length != t2 -> length )
224+ return false;
225+
226+ return memcmp (t1 -> start , t2 -> start , t1 -> length ) == 0 ;
227+ }
228+
229+ static int resolve_local (Compiler * compiler , Token * name )
230+ {
231+ for (int i = compiler -> local_count - 1 ; i >= 0 ; i -- )
232+ {
233+ Local * local = & compiler -> locals [i ];
234+ if (identifiers_equal (name , & local -> name ))
235+ {
236+ if (local -> depth == -1 )
237+ error ("Can't read local variable in its initializer" );
238+
239+ return i ;
240+ }
241+ }
242+ return -1 ;
243+ }
244+
245+ static void add_local (Token name )
246+ {
247+ if (current -> local_count == UINT8_COUNT )
248+ {
249+ error ("Too many variables in function" );
250+ return ;
251+ }
252+ Local * local = & current -> locals [current -> local_count ++ ];
253+ local -> name = name ;
254+ local -> depth = -1 ;
255+ }
256+
257+ static void declare_variable ()
258+ {
259+ if (current -> scope_depth == 0 )
260+ return ;
261+
262+ Token * name = & parser .previous ;
263+
264+ for (int i = current -> local_count - 1 ; i >= 0 ; i -- )
265+ {
266+ Local * local = & current -> locals [i ];
267+ if (local -> depth != -1 && local -> depth < current -> scope_depth )
268+ break ;
269+
270+ if (identifiers_equal (name , & local -> name ))
271+ error ("Already variable with this name in this scope" );
272+ }
273+ add_local (* name );
274+ }
275+
212276static u8 parse_variable (char * error_message )
213277{
214278 consume (TOKEN_IDENTIFIER , error_message );
279+
280+ declare_variable ();
281+ if (current -> scope_depth > 0 )
282+ return 0 ;
283+
215284 return identifier_constant (& parser .previous );
216285}
217286
287+ static void mark_initialized ()
288+ {
289+ current -> locals [current -> local_count - 1 ].depth = current -> scope_depth ;
290+ }
291+
218292static void define_variable (u8 global )
219293{
294+ if (current -> scope_depth > 0 )
295+ {
296+ mark_initialized ();
297+ return ;
298+ }
220299 emit_bytes (OP_DEFINE_GLOBAL , global );
221300}
222301
@@ -302,15 +381,29 @@ static void string(bool can_assign)
302381
303382static void named_variable (Token name , bool can_assign )
304383{
305- u8 arg = identifier_constant (& name );
384+ u8 get_op , set_op ;
385+ int arg = resolve_local (current , & name );
386+
387+ if (arg != -1 )
388+ {
389+ get_op = OP_GET_LOCAL ;
390+ set_op = OP_SET_LOCAL ;
391+ }
392+ else
393+ {
394+ arg = identifier_constant (& name );
395+ get_op = OP_GET_GLOBAL ;
396+ set_op = OP_SET_GLOBAL ;
397+ }
398+
306399 if (can_assign && match (TOKEN_EQUAL ))
307400 {
308401 expression ();
309- emit_bytes (OP_SET_GLOBAL , arg );
402+ emit_bytes (set_op , ( u8 ) arg );
310403 }
311404 else
312405 {
313- emit_bytes (OP_GET_GLOBAL , arg );
406+ emit_bytes (get_op , ( u8 ) arg );
314407 }
315408}
316409
0 commit comments