@@ -6,7 +6,6 @@ use super::stack::{Stack, VectorStack};
6
6
use self :: instructions:: Instruction ;
7
7
use std:: fmt;
8
8
use std:: collections:: HashMap ;
9
- use std:: io:: Write ;
10
9
use std:: io:: Read ;
11
10
use super :: marshal;
12
11
@@ -23,7 +22,6 @@ pub enum ProcessorError {
23
22
InvalidVarnameIndex ,
24
23
UnknownPrimitive ( String ) ,
25
24
UnmarshalError ( marshal:: decode:: UnmarshalError ) ,
26
- Exception ( String ) ,
27
25
}
28
26
29
27
impl fmt:: Display for ProcessorError {
@@ -32,8 +30,13 @@ impl fmt::Display for ProcessorError {
32
30
}
33
31
}
34
32
33
+ #[ derive( Debug ) ]
34
+ pub enum PyResult {
35
+ Return ( ObjectRef ) ,
36
+ }
35
37
36
- pub type PyFunction < EP > = fn ( & mut Processor < EP > , Vec < ObjectRef > ) -> Result < ObjectRef , ProcessorError > ;
38
+
39
+ pub type PyFunction < EP > = fn ( & mut Processor < EP > , Vec < ObjectRef > ) -> Result < PyResult , ProcessorError > ;
37
40
38
41
pub struct Processor < EP : EnvProxy > {
39
42
pub envproxy : EP ,
@@ -43,6 +46,7 @@ pub struct Processor<EP: EnvProxy> {
43
46
44
47
impl < EP : EnvProxy > Processor < EP > {
45
48
49
+ // Load a name from the namespace (only __primitive__ and locals for now)
46
50
fn load_name ( & mut self , namespace : & mut HashMap < String , ObjectRef > , name : String ) -> Result < ObjectRef , ProcessorError > {
47
51
if name == "__primitives__" {
48
52
Ok ( self . store . allocate ( ObjectContent :: PrimitiveNamespace ) )
@@ -51,11 +55,12 @@ impl<EP: EnvProxy> Processor<EP> {
51
55
Ok ( obj_ref. clone ( ) )
52
56
}
53
57
else {
54
- panic ! ( format!( "Cannot load {}: neither a primitive or in namespace." , name) )
58
+ panic ! ( format!( "Cannot load {}: neither __primitive__ or in namespace." , name) )
55
59
}
56
60
}
57
61
58
- fn call_function ( & mut self , namespace : & mut HashMap < String , ObjectRef > , func_ref : & ObjectRef , args : Vec < ObjectRef > , kwargs : Vec < ObjectRef > ) -> Result < ObjectRef , ProcessorError > {
62
+ // Call a primitive / function / code object, with arguments.
63
+ fn call_function ( & mut self , namespace : & mut HashMap < String , ObjectRef > , func_ref : & ObjectRef , args : Vec < ObjectRef > , kwargs : Vec < ObjectRef > ) -> Result < PyResult , ProcessorError > {
59
64
// TODO: clone only if necessary
60
65
match self . store . deref ( func_ref) . content . clone ( ) {
61
66
ObjectContent :: Code ( code) => {
@@ -82,11 +87,13 @@ impl<EP: EnvProxy> Processor<EP> {
82
87
}
83
88
}
84
89
85
- fn run_code ( & mut self , namespace : & mut HashMap < String , ObjectRef > , code : Code ) -> Result < ObjectRef , ProcessorError > {
90
+ // Main interpreter loop
91
10000
code>
+ // See https://docs.python.org/3/library/dis.html for a description of instructions
92
+ fn run_code ( & mut self , namespace : & mut HashMap < String , ObjectRef > , code : Code ) -> Result < PyResult , ProcessorError > {
86
93
let bytecode: Vec < u8 > = code. code ;
87
94
let instructions: Vec < Instruction > = instructions:: InstructionDecoder :: new ( bytecode. iter ( ) ) . into_iter ( ) . collect ( ) ;
88
95
let mut program_counter = 0 as usize ;
89
- let mut stack = VectorStack :: new ( ) ;
96
+ let mut stack = VectorStack :: < ObjectRef > :: new ( ) ;
90
97
loop {
91
98
let instruction = try!( instructions. get ( program_counter) . ok_or ( ProcessorError :: InvalidProgramCounter ) ) ;
92
99
program_counter += 1 ;
@@ -95,11 +102,11 @@ impl<EP: EnvProxy> Processor<EP> {
95
102
try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
96
103
( )
97
104
} ,
98
- Instruction :: ReturnValue => return Ok ( try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ) ,
105
+ Instruction :: ReturnValue => return Ok ( PyResult :: Return ( try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ) ) ,
99
106
Instruction :: StoreName ( i) => {
100
107
let name = try!( code. names . get ( i) . ok_or ( ProcessorError :: InvalidNameIndex ) ) . clone ( ) ;
101
- let obj = try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
102
- namespace. insert ( name, obj ) ;
108
+ let obj_ref = try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
109
+ namespace. insert ( name, obj_ref ) ;
103
110
}
104
111
Instruction :: LoadConst ( i) => stack. push ( try!( code. consts . get ( i) . ok_or ( ProcessorError :: InvalidConstIndex ) ) . clone ( ) ) ,
105
112
Instruction :: LoadName ( i) | Instruction :: LoadGlobal ( i) => {
@@ -126,8 +133,10 @@ impl<EP: EnvProxy> Processor<EP> {
126
133
let kwargs = try!( stack. pop_many ( nb_kwargs* 2 ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
127
134
let args = try!( stack. pop_many ( nb_args) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
128
135
let func = try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
129
- let ret_value = self . call_function ( namespace, & func, args, kwargs) ;
130
- stack. push ( try!( ret_value) )
136
+ let ret = try!( self . call_function ( namespace, & func, args, kwargs) ) ;
137
+ match ret {
138
+ PyResult :: Return ( obj_ref) => stack. push ( obj_ref) ,
139
+ } ;
131
140
} ,
132
141
Instruction :: MakeFunction ( 0 , 0 , 0 ) => {
133
142
// TODO: consume default arguments and annotations
@@ -143,24 +152,26 @@ impl<EP: EnvProxy> Processor<EP> {
143
152
} ;
144
153
}
145
154
146
- pub fn run_module ( & mut self , namespace : & mut HashMap < String , ObjectRef > , module_name : String ) -> Result < ( ) , ProcessorError > {
155
+ /// Load a module from its name and run it.
156
+ /// Functions and attributes will be added in the `namespace`.
157
+ pub fn run_module ( & mut self , namespace : & mut HashMap < String , ObjectRef > , module_name : String ) -> Result < PyResult , ProcessorError > {
147
158
let mut builtins_bytecode = self . envproxy . open_module ( module_name) ;
148
159
let mut buf = [ 0 ; 12 ] ;
149
- builtins_bytecode. read_exact ( & mut buf) ;
160
+ builtins_bytecode. read_exact ( & mut buf) . unwrap ( ) ;
150
161
let builtins_code = try!( marshal:: read_object ( & mut builtins_bytecode, & mut self . store ) . map_err ( ProcessorError :: UnmarshalError ) ) ;
151
162
let builtins_code = match self . store . deref ( & builtins_code) . content {
152
163
ObjectContent :: Code ( ref code) => code. clone ( ) ,
153
164
ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
154
165
} ;
155
- try!( self . run_code ( namespace, * builtins_code) ) ;
156
- Ok ( ( ) )
166
+ self . run_code ( namespace, * builtins_code)
157
167
}
158
168
159
- pub fn run_code_object ( & mut self , module : ObjectRef ) -> Result < ObjectRef , ProcessorError > {
169
+ /// Entry point to run code. Loads builtins in the code's namespace and then run it.
170
+ pub fn run_code_object ( & mut self , code_object : ObjectRef ) -> Result < PyResult , ProcessorError > {
160
171
let mut builtins = HashMap :: new ( ) ;
161
- self . run_module ( & mut builtins, "builtins" . to_string ( ) ) ;
172
+ try! ( self . run_module ( & mut builtins, "builtins" . to_string ( ) ) ) ;
162
173
163
- let code = match self . store . deref ( & module ) . content {
174
+ let code = match self . store . deref ( & code_object ) . content {
164
175
ObjectContent :: Code ( ref code) => code. clone ( ) ,
165
176
ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
166
177
} ;
0 commit comments