@@ -3,8 +3,10 @@ use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};
33use crate :: {
44 ast:: { BinaryOperation , Value } ,
55 compiler:: { FunctionBytecode , Instruction , Program } ,
6+ environment:: { Environment } ,
67} ;
78
9+
810impl fmt:: Display for Value {
911 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1012 match self {
@@ -34,7 +36,7 @@ impl fmt::Display for Value {
3436
3537#[ derive( Debug , Clone ) ]
3638pub struct Frame {
37- variables : HashMap < String , Value > ,
39+ env : Rc < RefCell < Environment > > ,
3840 instructions : Vec < Instruction > ,
3941 ip : usize ,
4042}
@@ -55,40 +57,35 @@ impl Runtime {
5557 }
5658
5759 fn load_variable ( & mut self , var : & str ) {
58- if let Some ( value) = self
59- . frames
60- . iter ( )
61- . rev ( )
62- . find_map ( |frame| frame. variables . get ( var) )
60+ let current_frame =
61+ self . frames . last ( ) . unwrap ( ) ;
62+
63+ if let Some ( value) =
64+ current_frame
65+ . env
66+ . borrow ( )
67+ . get ( var)
6368 {
64- self . stack . push ( ( * value) . clone ( ) ) ;
69+ self . stack . push ( value. clone ( ) ) ;
6570 } else {
6671 panic ! ( "{} is not defined" , var) ;
6772 }
6873 }
6974
7075 fn store_variable ( & mut self , var : String ) {
7176 if let Some ( value) = self . stack . pop ( ) {
72- self . frames . last_mut ( ) . unwrap ( ) . variables . insert ( var, value) ;
77+ self . frames . last_mut ( ) . unwrap ( ) . env . borrow_mut ( ) . variables . insert ( var, value) ;
7378 } else {
7479 panic ! ( "No defined value to store in {}" , var) ;
7580 }
7681 }
7782
7883 fn assign_variable ( & mut self , var : String ) {
79- if let Some ( value) = self
80- . frames
81- . iter_mut ( )
82- . rev ( )
83- . find_map ( |frame| frame. variables . get_mut ( & var) )
84- {
85- if let Some ( val) = self . stack . pop ( ) {
86- * value = val;
87- } else {
88- panic ! ( "No defined value to store in {}" , var) ;
89- }
84+ let current_frame = self . frames . last ( ) . unwrap ( ) ;
85+ if let Some ( val) = self . stack . pop ( ) {
86+ current_frame. env . borrow_mut ( ) . assign ( & var, val) ;
9087 } else {
91- panic ! ( "{} is not defined " , var) ;
88+ panic ! ( "No defined value to store in {} " , var) ;
9289 }
9390 }
9491
@@ -214,8 +211,12 @@ impl Runtime {
214211
215212pub fn execute ( program : Program , runtime : & mut Runtime ) {
216213 runtime. functions = program. functions ;
214+ let global_env =
215+ Rc :: new ( RefCell :: new (
216+ Environment :: new ( None )
217+ ) ) ;
217218 runtime. frames . push ( Frame {
218- variables : HashMap :: new ( ) ,
219+ env : global_env ,
219220 instructions : program. main ,
220221 ip : 0 ,
221222 } ) ;
@@ -315,7 +316,7 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
315316 }
316317 Instruction :: CallFunction ( name, arg_count) => {
317318 let func = runtime. functions . get ( & name) . expect ( "undefined function" ) ;
318- let mut locals = HashMap :: new ( ) ;
319+ // let mut locals = HashMap::new();
319320 // Pop args in reverse (last arg was pushed last)
320321 if arg_count != func. params . len ( ) {
321322 panic ! (
@@ -324,16 +325,21 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
324325 arg_count
325326 ) ;
326327 }
328+ let parnt_env = runtime. frames . last ( ) . unwrap ( ) . env . clone ( ) ;
329+ let local_env =
330+ Rc :: new ( RefCell :: new (
331+ Environment :: new ( Some ( parnt_env) )
332+ ) ) ;
327333 for param in func. params . iter ( ) . rev ( ) {
328- locals . insert ( param. clone ( ) , runtime. stack . pop ( ) . unwrap ( ) ) ;
334+ local_env . borrow_mut ( ) . variables . insert ( param. clone ( ) , runtime. stack . pop ( ) . unwrap ( ) ) ;
329335 }
330336 // Save caller's position (move past the CallFunction instruction)
331337 runtime. frames . last_mut ( ) . unwrap ( ) . ip += 1 ;
332338 // Push new frame
333339 runtime. frames . push ( Frame {
334340 instructions : func. instructions . clone ( ) ,
335341 ip : 0 ,
336- variables : locals ,
342+ env : local_env
337343 } ) ;
338344 continue ; // don't increment ip again
339345 }
0 commit comments