@@ -34,21 +34,21 @@ impl fmt::Display for ProcessorError {
3434#[ derive( Debug ) ]
3535pub enum PyResult {
3636 Return ( ObjectRef ) ,
37- Raise ( ObjectRef ) ,
37+ Raise ( ObjectRef , ObjectRef ) , // (exception, exc_type)
3838}
3939
4040
4141pub type PyFunction < EP > = fn ( & mut Processor < EP > , Vec < ObjectRef > ) -> Result < PyResult , ProcessorError > ;
4242
4343#[ derive( Debug ) ]
44- struct Loop {
45- begin : usize ,
46- end : usize ,
44+ enum Block {
45+ Loop ( usize , usize ) , // begin, end
46+ TryExcept ( usize , usize ) , // begin, end
4747}
4848
4949struct Stacks {
5050 var_stack : VectorStack < ObjectRef > ,
51- loop_stack : VectorStack < Loop > ,
51+ block_stack : VectorStack < Block > ,
5252}
5353
5454macro_rules! pop_stack {
@@ -57,6 +57,34 @@ macro_rules! pop_stack {
5757 }
5858}
5959
60+ macro_rules! raise {
61+ ( $stacks: expr, $program_counter: ident, $traceback: expr, $exception: expr, $exc_type: expr, $value: expr) => { {
62+ loop {
63+ match $stacks. block_stack. pop( ) {
64+ None => { // Root block; raise exception to calling function
65+ return Ok ( PyResult :: Raise ( $exception, $exc_type) )
66+ }
67+ Some ( Block :: TryExcept ( begin, end) ) => { // Found a try…except block
68+ $stacks. block_stack. push( Block :: TryExcept ( begin, end) ) ; // Push it back, it will be poped by PopExcept.
69+ $program_counter = end;
70+ let traceback = $traceback;
71+ let exception = $exception;
72+ $stacks. var_stack. push( traceback. clone( ) ) ; // traceback
73+ $stacks. var_stack. push( exception. clone( ) ) ; // exception
74+ $stacks. var_stack. push( $exc_type) ; // exception type
75+
76+ $stacks. var_stack. push( traceback) ; // traceback
77+ $stacks. var_stack. push( $value) ; // value
78+ $stacks. var_stack. push( exception) ; // exception
79+ break
80+ }
81+ Some ( _) => { // Non-try…except block, exit it.
82+ }
83+ }
84+ }
85+ } }
86+ }
87+
6088pub struct Processor < EP : EnvProxy > {
6189 pub envproxy : EP ,
6290 pub store : ObjectStore ,
@@ -169,7 +197,7 @@ impl<EP: EnvProxy> Processor<EP> {
169197 let bytecode: Vec < u8 > = code. code ;
170198 let instructions: Vec < Instruction > = instructions:: InstructionDecoder :: new ( bytecode. iter ( ) ) . into_iter ( ) . collect ( ) ;
171199 let mut program_counter = 0 as usize ;
172- let mut stacks = Stacks { var_stack : VectorStack :: new ( ) , loop_stack : VectorStack :: new ( ) } ;
200+ let mut stacks = Stacks { var_stack : VectorStack :: new ( ) , block_stack : VectorStack :: new ( ) } ;
173201 loop {
174202 let instruction = try!( instructions. get ( program_counter) . ok_or ( ProcessorError :: InvalidProgramCounter ) ) ;
175203 program_counter += 1 ;
@@ -178,6 +206,11 @@ impl<EP: EnvProxy> Processor<EP> {
178206 pop_stack ! ( stacks. var_stack) ;
179207 ( )
180208 } ,
209+ Instruction :: DupTop => {
210+ let val = pop_stack ! ( stacks. var_stack) ;
211+ stacks. var_stack . push ( val. clone ( ) ) ;
212+ stacks. var_stack . push ( val) ;
213+ }
181214 Instruction :: Nop => ( ) ,
182215 Instruction :: BinarySubscr => {
183216 let index_ref = pop_stack ! ( stacks. var_stack) ;
@@ -199,6 +232,24 @@ impl<EP: EnvProxy> Processor<EP> {
199232 stacks. var_stack . push ( self . store . allocate ( obj) ) ;
200233 }
201234 Instruction :: ReturnValue => return Ok ( PyResult :: Return ( pop_stack ! ( stacks. var_stack) ) ) ,
235+ Instruction :: PopBlock => { pop_stack ! ( stacks. block_stack) ; } ,
236+ Instruction :: EndFinally => {
237+ let status_ref = pop_stack ! ( stacks. var_stack) ;
238+ let status = self . store . deref ( & status_ref) ;
239+ match status. content {
240+ ObjectContent :: Int ( i) => panic ! ( "TODO: finally int status" ) , // TODO
241+ ObjectContent :: OtherObject => { }
242+ _ => panic ! ( "Invalid finally status" )
243+ }
244+ }
245+ Instruction :: PopExcept => {
246+ let mut three_last = stacks. var_stack . pop_all_and_get_n_last ( 3 ) . unwrap ( ) ; // TODO: check
247+ let exc_type = three_last. pop ( ) ;
248+ let exc_value = three_last. pop ( ) ;
249+ let exc_traceback = three_last. pop ( ) ;
250+ // TODO: do something with exc_*
251+ pop_stack ! ( stacks. block_stack) ;
252+ } ,
202253 Instruction :: StoreName ( i) => {
203254 let name = try!( code. names . get ( i) . ok_or ( ProcessorError :: InvalidNameIndex ) ) . clone ( ) ;
204255 let obj_ref = pop_stack ! ( stacks. var_stack) ;
@@ -218,10 +269,13 @@ impl<EP: EnvProxy> Processor<EP> {
218269 stacks. var_stack . push ( try!( self . load_attr ( & obj, name) ) )
219270 } ,
220271 Instruction :: SetupLoop ( i) => {
221- stacks. loop_stack . push ( Loop { begin : program_counter, end : program_counter+i } )
272+ stacks. block_stack . push ( Block :: Loop ( program_counter, program_counter+i) )
273+ }
274+ Instruction :: SetupExcept ( i) => {
275+ stacks. block_stack . push ( Block :: TryExcept ( program_counter, program_counter+i) )
222276 }
223277 Instruction :: CompareOp ( CmpOperator :: Eq ) => {
224- // TODO: enhance this
278+ // TODO: enrich this (support __eq__)
225279 let obj1 = self . store . deref ( & pop_stack ! ( stacks. var_stack) ) ;
226280 let obj2 = self . store . deref ( & pop_stack ! ( stacks. var_stack) ) ;
227281 if obj1. name == obj2. name && obj1. content == obj2. content {
@@ -231,6 +285,17 @@ impl<EP: EnvProxy> Processor<EP> {
231285 stacks. var_stack . push ( self . primitive_objects . false_obj . clone ( ) )
232286 } ;
233287 }
288+ Instruction :: CompareOp ( CmpOperator :: ExceptionMatch ) => {
289+ // TODO: add support for tuples
290+ let pattern_ref = pop_stack ! ( stacks. var_stack) ;
291+ let exc_ref = pop_stack ! ( stacks. var_stack) ;
292+ let isinstance = self . primitive_functions . get ( "isinstance" ) . unwrap ( ) . clone ( ) ;
293+ let res = try!( isinstance ( self , vec ! [ exc_ref, pattern_ref] ) ) ;
294+ match res {
295+ PyResult :: Return ( v) => stacks. var_stack . push ( v) ,
296+ _ => panic ! ( "Unexpected result of isinstance()" )
297+ }
298+ }
234299 Instruction :: JumpForward ( delta) => {
235300 program_counter += delta
236301 }
@@ -247,6 +312,23 @@ impl<EP: EnvProxy> Processor<EP> {
247312 }
248313 }
249314
315+ Instruction :: RaiseVarargs ( 0 ) => {
316+ panic ! ( "RaiseVarargs(0) not implemented." )
317+ }
318+ Instruction :: RaiseVarargs ( 1 ) => {
319+ let exception = pop_stack ! ( stacks. var_stack) ;
320+ let exc_type = exception. clone ( ) ;
321+ // TODO: add traceback
322+ raise ! ( stacks, program_counter, self . primitive_objects. none. clone( ) , exception, exc_type, self . primitive_objects. none. clone( ) ) ;
323+ }
324+ Instruction :: RaiseVarargs ( 2 ) => {
325+ panic ! ( "RaiseVarargs(2) not implemented." )
326+ }
327+ Instruction :: RaiseVarargs ( _) => {
328+ // Note: the doc lies, the argument can only be ≤ 2
329+ panic ! ( "Bad RaiseVarargs argument" ) // TODO: Raise an exception instead
330+ }
331+
250332 Instruction :: CallFunction ( nb_args, nb_kwargs) => {
251333 // See “Call constructs” at:
252334 // http://security.coverity.com/blog/2014/Nov/understanding-python-bytecode.html
@@ -256,7 +338,10 @@ impl<EP: EnvProxy> Processor<EP> {
256338 let ret = try!( self . call_function ( namespace, & func, args, kwargs) ) ;
257339 match ret {
258340 PyResult :: Return ( obj_ref) => stacks. var_stack . push ( obj_ref) ,
259- PyResult :: Raise ( obj_ref) => return Ok ( PyResult :: Raise ( obj_ref) )
341+ PyResult :: Raise ( exception, exc_type) => {
342+ // TODO: add frame to traceback
343+ raise ! ( stacks, program_counter, self . primitive_objects. none. clone( ) , exception, exc_type, self . primitive_objects. none. clone( ) )
344+ }
260345 } ;
261346 } ,
262347 Instruction :: MakeFunction ( 0 , 0 , 0 ) => {
0 commit comments