3
3
*/
4
4
5
5
use crate :: frame:: { ExecutionResult , FrameRef } ;
6
- use crate :: obj:: objtype:: PyClassRef ;
7
- use crate :: pyobject:: { PyContext , PyObjectRef , PyRef , PyResult , PyValue } ;
6
+ use crate :: obj:: objtype:: { isinstance , PyClassRef } ;
7
+ use crate :: pyobject:: { PyClassImpl , PyContext , PyObjectRef , PyRef , PyResult , PyValue } ;
8
8
use crate :: vm:: VirtualMachine ;
9
9
10
10
pub type PyGeneratorRef = PyRef < PyGenerator > ;
11
11
12
+ #[ pyclass( name = "generator" , __inside_vm) ]
12
13
#[ derive( Debug ) ]
13
14
pub struct PyGenerator {
14
15
frame : FrameRef ,
@@ -20,38 +21,59 @@ impl PyValue for PyGenerator {
20
21
}
21
22
}
22
23
23
- impl PyGeneratorRef {
24
+ #[ pyimpl( __inside_vm) ]
25
+ impl PyGenerator {
24
26
pub fn new ( frame : FrameRef , vm : & VirtualMachine ) -> PyGeneratorRef {
25
27
PyGenerator { frame } . into_ref ( vm)
26
28
}
27
29
28
- fn iter ( self , _vm : & VirtualMachine ) -> PyGeneratorRef {
29
- self
30
+ #[ pymethod( name = "__iter__" ) ]
31
+ fn iter ( zelf : PyGeneratorRef , _vm : & VirtualMachine ) -> PyGeneratorRef {
32
+ zelf
30
33
}
31
34
32
- fn next ( self , vm : & VirtualMachine ) -> PyResult {
35
+ #[ pymethod( name = "__next__" ) ]
36
+ fn next ( & self , vm : & VirtualMachine ) -> PyResult {
33
37
self . send ( vm. get_none ( ) , vm)
34
38
}
35
39
36
- fn send ( self , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
40
+ #[ pymethod]
41
+ fn send ( & self , value : PyObjectRef , vm : & VirtualMachine ) -> PyResult {
37
42
self . frame . push_value ( value. clone ( ) ) ;
38
43
39
- match vm. run_frame ( self . frame . clone ( ) ) ? {
40
- ExecutionResult :: Yield ( value) => Ok ( value) ,
41
- ExecutionResult :: Return ( _value) => {
42
- // Stop iteration!
43
- let stop_iteration = vm. ctx . exceptions . stop_iteration . clone ( ) ;
44
- Err ( vm. new_exception ( stop_iteration, "End of generator" . to_string ( ) ) )
45
- }
44
+ let result = vm. run_frame ( self . frame . clone ( ) ) ?;
45
+ handle_execution_result ( result, vm)
46
+ }
47
+
48
+ #[ pymethod]
49
+ fn throw (
50
+ & self ,
51
+ _exc_type : PyObjectRef ,
52
+ exc_val : PyObjectRef ,
53
+ _exc_tb : PyObjectRef ,
54
+ vm : & VirtualMachine ,
55
+ ) -> PyResult {
56
+ // TODO what should we do with the other parameters? CPython normalises them with
57
+ // PyErr_NormalizeException, do we want to do the same.
58
+ if !isinstance ( & exc_val, & vm. ctx . exceptions . base_exception_type ) {
59
+ return Err ( vm. new_type_error ( "Can't throw non exception" . to_string ( ) ) ) ;
60
+ }
61
+ let result = vm. frame_throw ( self . frame . clone ( ) , exc_val) ?;
62
+ handle_execution_result ( result, vm)
63
+ }
64
+ }
65
+
66
+ fn handle_execution_result ( result : ExecutionResult , vm : & VirtualMachine ) -> PyResult {
67
+ match result {
68
+ ExecutionResult :: Yield ( value) => Ok ( value) ,
69
+ ExecutionResult :: Return ( _value) => {
70
+ // Stop iteration!
71
+ let stop_iteration = vm. ctx . exceptions . stop_iteration . clone ( ) ;
72
+ Err ( vm. new_exception ( stop_iteration, "End of generator" . to_string ( ) ) )
46
73
}
47
74
}
48
75
}
49
76
50
- pub fn init ( context : & PyContext ) {
51
- let generator_type = & context. generator_type ;
52
- extend_class ! ( context, generator_type, {
53
- "__iter__" => context. new_rustfunc( PyGeneratorRef :: iter) ,
54
- "__next__" => context. new_rustfunc( PyGeneratorRef :: next) ,
55
- "send" => context. new_rustfunc( PyGeneratorRef :: send)
56
- } ) ;
77
+ pub fn init ( ctx : & PyContext ) {
78
+ PyGenerator :: extend_class ( ctx, & ctx. generator_type ) ;
57
79
}
0 commit comments