@@ -32,16 +32,120 @@ use crate::vm::VirtualMachine;
32
32
* When a name is looked up, it is check in its scope.
33
33
*/
34
34
#[ 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 ) ]
35
82
pub 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 ,
39
85
}
40
- pub type ScopeRef = Rc < Scope > ;
41
86
42
87
impl 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)
45
149
}
46
150
}
47
151
@@ -73,7 +177,7 @@ pub struct Frame {
73
177
// We need 1 stack per frame
74
178
stack : RefCell < Vec < PyObjectRef > > , // The main data frame of the stack machine
75
179
blocks : RefCell < Vec < Block > > , // Block frames, for controlling loops and exceptions
76
- pub scope : ScopeRef , // Variables
180
+ pub scope : Scope , // Variables
77
181
pub lasti : RefCell < usize > , // index of last instruction ran
78
182
}
79
183
@@ -93,7 +197,7 @@ pub enum ExecutionResult {
93
197
pub type FrameResult = Result < Option < ExecutionResult > , PyObjectRef > ;
94
198
95
199
impl Frame {
96
- pub fn new ( code : PyObjectRef , scope : ScopeRef ) -> Frame {
200
+ pub fn new ( code : PyObjectRef , scope : Scope ) -> Frame {
97
201
//populate the globals and locals
98
202
//TODO: This is wrong, check https://github.com/nedbat/byterun/blob/31e6c4a8212c35b5157919abff43a7daa0f377c6/byterun/pyvm2.py#L95
99
203
/*
@@ -735,9 +839,7 @@ impl Frame {
735
839
let obj = import_module ( vm, current_path, module) ?;
736
840
737
841
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 ( ) ) ;
741
843
}
742
844
Ok ( None )
743
845
}
@@ -859,35 +961,26 @@ impl Frame {
859
961
860
962
fn store_name ( & self , vm : & mut VirtualMachine , name : & str ) -> FrameResult {
861
963
let obj = self . pop_value ( ) ;
862
- self . scope . locals . set_item ( & vm. ctx , name, obj) ;
964
+ self . scope . store_name ( & vm, name, obj) ;
863
965
Ok ( None )
864
966
}
865
967
866
968
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) ;
869
970
Ok ( None )
870
971
}
871
972
872
973
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 )
880
978
}
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)
891
984
}
892
985
}
893
986
}
@@ -1138,7 +1231,7 @@ impl fmt::Debug for Frame {
1138
1231
. map ( |elem| format ! ( "\n > {:?}" , elem) )
1139
1232
. collect :: < Vec < _ > > ( )
1140
1233
. join ( "" ) ;
1141
- let local_str = match self . scope . locals . payload :: < PyDict > ( ) {
1234
+ let local_str = match self . scope . get_locals ( ) . payload :: < PyDict > ( ) {
1142
1235
Some ( dict) => objdict:: get_key_value_pairs_from_content ( & dict. entries . borrow ( ) )
1143
1236
. iter ( )
1144
1237
. map ( |elem| format ! ( "\n {:?} = {:?}" , elem. 0 , elem. 1 ) )
0 commit comments