@@ -32,16 +32,120 @@ use crate::vm::VirtualMachine;
3232 * When a name is looked up, it is check in its scope.
3333 */
3434#[ derive( Debug ) ]
35+ struct RcListNode < T > {
36+ elem : T ,
37+ next : Option < Rc < RcListNode < T > > > ,
38+ }
39+
40+ #[ derive( Debug , Clone ) ]
41+ struct RcList < T > {
42+ head : Option < Rc < RcListNode < T > > > ,
43+ }
44+
45+ struct Iter < ' a , T : ' a > {
46+ next : Option < & ' a RcListNode < T > > ,
47+ }
48+
49+ impl < T > RcList < T > {
50+ pub fn new ( ) -> Self {
51+ RcList { head : None }
52+ }
53+
54+ pub fn insert ( self , elem : T ) -> Self {
55+ RcList {
56+ head : Some ( Rc :: new ( RcListNode {
57+ elem,
58+ next : self . head ,
59+ } ) ) ,
60+ }
61+ }
62+
63+ pub fn iter ( & self ) -> Iter < T > {
64+ Iter {
65+ next : self . head . as_ref ( ) . map ( |node| & * * node) ,
66+ }
67+ }
68+ }
69+
70+ impl < ' a , T > Iterator for Iter < ' a , T > {
71+ type Item = & ' a T ;
72+
73+ fn next ( & mut self ) -> Option < Self :: Item > {
74+ self . next . map ( |node| {
75+ self . next = node. next . as_ref ( ) . map ( |node| & * * node) ;
76+ & node. elem
77+ } )
78+ }
79+ }
80+
81+ #[ derive( Debug , Clone ) ]
3582pub struct Scope {
36- pub locals : PyObjectRef , // Variables
37- // TODO: pub locals: RefCell<PyAttributes>, // Variables
38- pub parent : Option < Rc < Scope > > , // Parent scope
83+ locals : RcList < PyObjectRef > ,
84+ pub globals : PyObjectRef ,
3985}
40- pub type ScopeRef = Rc < Scope > ;
4186
4287impl Scope {
43- pub fn new ( locals : PyObjectRef , parent : Option < ScopeRef > ) -> ScopeRef {
44- Rc :: new ( Scope { locals, parent } )
88+ pub fn new ( locals : Option < PyObjectRef > , globals : PyObjectRef ) -> Scope {
89+ let locals = match locals {
90+ Some ( dict) => RcList :: new ( ) . insert ( dict) ,
91+ None => RcList :: new ( ) ,
92+ } ;
93+ Scope { locals, globals }
94+ }
95+
96+ pub fn get_locals ( & self ) -> PyObjectRef {
97+ match self . locals . iter ( ) . next ( ) {
98+ Some ( dict) => dict. clone ( ) ,
99+ None => self . globals . clone ( ) ,
100+ }
101+ }
102+
103+ pub fn get_only_locals ( & self ) -> Option < PyObjectRef > {
104+ match self . locals . iter ( ) . next ( ) {
105+ Some ( dict) => Some ( dict. clone ( ) ) ,
106+ None => None ,
107+ }
108+ }
109+
110+ pub fn child_scope_with_locals ( & self , locals : PyObjectRef ) -> Scope {
111+ Scope {
112+ locals : self . locals . clone ( ) . insert ( locals) ,
113+ globals : self . globals . clone ( ) ,
114+ }
115+ }
116+
117+ pub fn child_scope ( & self , ctx : & PyContext ) -> Scope {
118+ self . child_scope_with_locals ( ctx. new_dict ( ) )
119+ }
120+ }
121+
122+ pub trait NameProtocol {
123+ fn load_name ( & self , vm : & VirtualMachine , name : & str ) -> Option < PyObjectRef > ;
124+ fn store_name ( & self , vm : & VirtualMachine , name : & str , value : PyObjectRef ) ;
125+ fn delete_name ( & self , vm : & VirtualMachine , name : & str ) ;
126+ }
127+
128+ impl NameProtocol for Scope {
129+ fn load_name ( & self , vm : & VirtualMachine , name : & str ) -> Option < PyObjectRef > {
130+ for dict in self . locals . iter ( ) {
131+ if let Some ( value) = dict. get_item ( name) {
132+ return Some ( value) ;
133+ }
134+ }
135+
136+ if let Some ( value) = self . globals . get_item ( name) {
137+ return Some ( value) ;
138+ }
139+
140+ vm. builtins . get_item ( name)
141+ }
142+
143+ fn store_name ( & self , vm : & VirtualMachine , key : & str , value : PyObjectRef ) {
144+ self . get_locals ( ) . set_item ( & vm. ctx , key, value)
145+ }
146+
147+ fn delete_name ( & self , _vm : & VirtualMachine , key : & str ) {
148+ self . get_locals ( ) . del_item ( key)
45149 }
46150}
47151
@@ -73,7 +177,7 @@ pub struct Frame {
73177 // We need 1 stack per frame
74178 stack : RefCell < Vec < PyObjectRef > > , // The main data frame of the stack machine
75179 blocks : RefCell < Vec < Block > > , // Block frames, for controlling loops and exceptions
76- pub scope : ScopeRef , // Variables
180+ pub scope : Scope , // Variables
77181 pub lasti : RefCell < usize > , // index of last instruction ran
78182}
79183
@@ -93,7 +197,7 @@ pub enum ExecutionResult {
93197pub type FrameResult = Result < Option < ExecutionResult > , PyObjectRef > ;
94198
95199impl Frame {
96- pub fn new ( code : PyObjectRef , scope : ScopeRef ) -> Frame {
200+ pub fn new ( code : PyObjectRef , scope : Scope ) -> Frame {
97201 //populate the globals and locals
98202 //TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95
99203 /*
@@ -735,9 +839,7 @@ impl Frame {
735839 let obj = import_module ( vm, current_path, module) ?;
736840
737841 for ( k, v) in obj. get_key_value_pairs ( ) . iter ( ) {
738- self . scope
739- . locals
740- . set_item ( & vm. ctx , & objstr:: get_value ( k) , v. clone ( ) ) ;
842+ self . scope . store_name ( & vm, & objstr:: get_value ( k) , v. clone ( ) ) ;
741843 }
742844 Ok ( None )
743845 }
@@ -859,35 +961,26 @@ impl Frame {
859961
860962 fn store_name ( & self , vm : & mut VirtualMachine , name : & str ) -> FrameResult {
861963 let obj = self . pop_value ( ) ;
862- self . scope . locals . set_item ( & vm. ctx , name, obj) ;
964+ self . scope . store_name ( & vm, name, obj) ;
863965 Ok ( None )
864966 }
865967
866968 fn delete_name ( & self , vm : & mut VirtualMachine , name : & str ) -> FrameResult {
867- let name = vm. ctx . new_str ( name. to_string ( ) ) ;
868- vm. call_method ( & self . scope . locals , "__delitem__" , vec ! [ name] ) ?;
969+ self . scope . delete_name ( vm, name) ;
869970 Ok ( None )
870971 }
871972
872973 fn load_name ( & self , vm : & mut VirtualMachine , name : & str ) -> FrameResult {
873- // Lookup name in scope and put it onto the stack!
874- let mut scope = self . scope . clone ( ) ;
875- loop {
876- if scope. locals . contains_key ( name) {
877- let obj = scope. locals . get_item ( name) . unwrap ( ) ;
878- self . push_value ( obj) ;
879- return Ok ( None ) ;
974+ match self . scope . load_name ( & vm, name) {
975+ Some ( value) => {
976+ self . push_value ( value) ;
977+ Ok ( None )
880978 }
881- match & scope. parent {
882- Some ( parent_scope) => {
883- scope = parent_scope. clone ( ) ;
884- }
885- None => {
886- let name_error_type = vm. ctx . exceptions . name_error . clone ( ) ;
887- let msg = format ! ( "name '{}' is not defined" , name) ;
888- let name_error = vm. new_exception ( name_error_type, msg) ;
889- return Err ( name_error) ;
890- }
979+ None => {
980+ let name_error_type = vm. ctx . exceptions . name_error . clone ( ) ;
981+ let msg = format ! ( "name '{}' is not defined" , name) ;
982+ let name_error = vm. new_exception ( name_error_type, msg) ;
983+ Err ( name_error)
891984 }
892985 }
893986 }
@@ -1138,7 +1231,7 @@ impl fmt::Debug for Frame {
11381231 . map ( |elem| format ! ( "\n > {:?}" , elem) )
11391232 . collect :: < Vec < _ > > ( )
11401233 . join ( "" ) ;
1141- let local_str = match self . scope . locals . payload :: < PyDict > ( ) {
1234+ let local_str = match self . scope . get_locals ( ) . payload :: < PyDict > ( ) {
11421235 Some ( dict) => objdict:: get_key_value_pairs_from_content ( & dict. entries . borrow ( ) )
11431236 . iter ( )
11441237 . map ( |elem| format ! ( "\n {:?} = {:?}" , elem. 0 , elem. 1 ) )
0 commit comments