1
- use std:: cell:: RefCell ;
1
+ use std:: cell:: { Cell , RefCell } ;
2
2
use std:: fmt;
3
3
4
4
use indexmap:: IndexMap ;
@@ -90,7 +90,7 @@ pub struct Frame {
90
90
/// Variables
91
91
pub scope : Scope ,
92
92
/// index of last instruction ran
93
- pub lasti : RefCell < usize > ,
93
+ pub lasti : Cell < usize > ,
94
94
}
95
95
96
96
impl PyValue for Frame {
@@ -105,6 +105,38 @@ pub enum ExecutionResult {
105
105
Yield ( PyObjectRef ) ,
106
106
}
107
107
108
+ impl ExecutionResult {
109
+ /// Extract an ExecutionResult from a PyResult returned from e.g. gen.__next__() or gen.send()
110
+ pub fn from_result ( vm : & VirtualMachine , res : PyResult ) -> PyResult < Self > {
111
+ match res {
112
+ Ok ( val) => Ok ( ExecutionResult :: Yield ( val) ) ,
113
+ Err ( err) => {
114
+ if objtype:: isinstance ( & err, & vm. ctx . exceptions . stop_iteration ) {
115
+ objiter:: stop_iter_value ( vm, & err) . map ( ExecutionResult :: Return )
116
+ } else {
117
+ Err ( err)
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ /// Turn an ExecutionResult into a PyResult that would be returned from a generator or coroutine
124
+ pub fn into_result ( self , vm : & VirtualMachine ) -> PyResult {
125
+ match self {
126
+ ExecutionResult :: Yield ( value) => Ok ( value) ,
127
+ ExecutionResult :: Return ( value) => {
128
+ let stop_iteration = vm. ctx . exceptions . stop_iteration . clone ( ) ;
129
+ let args = if vm. is_none ( & value) {
130
+ vec ! [ ]
131
+ } else {
132
+ vec ! [ value]
133
+ } ;
134
+ Err ( vm. new_exception_obj ( stop_iteration, args) . unwrap ( ) )
135
+ }
136
+ }
137
+ }
138
+ }
139
+
108
140
/// A valid execution result, or an exception
109
141
pub type FrameResult = PyResult < Option < ExecutionResult > > ;
110
142
@@ -128,7 +160,7 @@ impl Frame {
128
160
// save the callargs as locals
129
161
// globals: locals.clone(),
130
162
scope,
131
- lasti : RefCell :: new ( 0 ) ,
163
+ lasti : Cell :: new ( 0 ) ,
132
164
}
133
165
}
134
166
@@ -185,17 +217,40 @@ impl Frame {
185
217
}
186
218
}
187
219
188
- pub fn throw ( & self , vm : & VirtualMachine , exception : PyObjectRef ) -> PyResult < ExecutionResult > {
189
- match self . unwind_blocks ( vm, UnwindReason :: Raising { exception } ) {
190
- Ok ( None ) => self . run ( vm) ,
191
- Ok ( Some ( result) ) => Ok ( result) ,
192
- Err ( exception) => Err ( exception) ,
220
+ pub ( crate ) fn gen_throw (
221
+ & self ,
222
+ vm : & VirtualMachine ,
223
+ exc_type : PyClassRef ,
224
+ exc_val : PyObjectRef ,
225
+ exc_tb : PyObjectRef ,
226
+ ) -> PyResult {
227
+ if let bytecode:: Instruction :: YieldFrom = self . code . instructions [ self . lasti . get ( ) ] {
228
+ let coro = self . last_value ( ) ;
229
+ vm. call_method (
230
+ & coro,
231
+ "throw" ,
232
+ vec ! [ exc_type. into_object( ) , exc_val, exc_tb] ,
233
+ )
234
+ . or_else ( |err| {
235
+ self . pop_value ( ) ;
236
+ self . lasti . set ( self . lasti . get ( ) + 1 ) ;
237
+ let val = objiter:: stop_iter_value ( vm, & err) ?;
238
+ self . _send ( coro, val, vm)
239
+ } )
240
+ } else {
241
+ let exception = vm. new_exception_obj ( exc_type, vec ! [ exc_val] ) ?;
242
+ match self . unwind_blocks ( vm, UnwindReason :: Raising { exception } ) {
243
+ Ok ( None ) => self . run ( vm) ,
244
+ Ok ( Some ( result) ) => Ok ( result) ,
245
+ Err ( exception) => Err ( exception) ,
246
+ }
247
+ . and_then ( |res| res. into_result ( vm) )
193
248
}
194
249
}
195
250
196
251
pub fn fetch_instruction ( & self ) -> & bytecode:: Instruction {
197
- let ins2 = & self . code . instructions [ * self . lasti . borrow ( ) ] ;
198
- * self . lasti . borrow_mut ( ) += 1 ;
252
+ let ins2 = & self . code . instructions [ self . lasti . get ( ) ] ;
253
+ self . lasti . set ( self . lasti . get ( ) + 1 ) ;
199
254
ins2
200
255
}
201
256
@@ -954,20 +1009,35 @@ impl Frame {
954
1009
Err ( exception)
955
1010
}
956
1011
1012
+ fn _send ( & self , coro : PyObjectRef , val : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
1013
+ if vm. is_none ( & val) {
1014
+ objiter:: call_next ( vm, & coro)
1015
+ } else {
1016
+ vm. call_method ( & coro, "send" , vec ! [ val] )
1017
+ }
1018
+ }
1019
+
957
1020
fn execute_yield_from ( & self , vm : & VirtualMachine ) -> FrameResult {
958
1021
// Value send into iterator:
959
- self . pop_value ( ) ;
1022
+ let val = self . pop_value ( ) ;
960
1023
961
- let top_of_stack = self . last_value ( ) ;
962
- let next_obj = objiter:: get_next_object ( vm, & top_of_stack) ?;
1024
+ let coro = self . last_value ( ) ;
963
1025
964
- match next_obj {
965
- Some ( value) => {
1026
+ let result = self . _send ( coro, val, vm) ;
1027
+
1028
+ let result = ExecutionResult :: from_result ( vm, result) ?;
1029
+
1030
+ match result {
1031
+ ExecutionResult :: Yield ( value) => {
966
1032
// Set back program counter:
967
- * self . lasti . borrow_mut ( ) -= 1 ;
1033
+ self . lasti . set ( self . lasti . get ( ) - 1 ) ;
968
1034
Ok ( Some ( ExecutionResult :: Yield ( value) ) )
969
1035
}
970
- None => Ok ( None ) ,
1036
+ ExecutionResult :: Return ( value) => {
1037
+ self . pop_value ( ) ;
1038
+ self . push_value ( value) ;
1039
+ Ok ( None )
1040
+ }
971
1041
}
972
1042
}
973
1043
@@ -1006,7 +1076,7 @@ impl Frame {
1006
1076
let target_pc = self . code . label_map [ & label] ;
1007
1077
#[ cfg( feature = "vm-tracing-logging" ) ]
1008
1078
trace ! ( "jump from {:?} to {:?}" , self . lasti, target_pc) ;
1009
- self . lasti . replace ( target_pc) ;
1079
+ self . lasti . set ( target_pc) ;
1010
1080
}
1011
1081
1012
1082
/// The top of stack contains the iterator, lets push it forward
@@ -1238,7 +1308,7 @@ impl Frame {
1238
1308
}
1239
1309
1240
1310
pub fn get_lineno ( & self ) -> bytecode:: Location {
1241
- self . code . locations [ * self . lasti . borrow ( ) ] . clone ( )
1311
+ self . code . locations [ self . lasti . get ( ) ] . clone ( )
1242
1312
}
1243
1313
1244
1314
fn push_block ( & self , typ : BlockType ) {
0 commit comments