11use crate :: function:: PyFuncArgs ;
22use crate :: obj:: objsequence;
3+ use crate :: obj:: objtuple:: { PyTuple , PyTupleRef } ;
34use crate :: obj:: objtype;
45use crate :: obj:: objtype:: PyClassRef ;
56use crate :: pyobject:: { create_type, IdProtocol , PyContext , PyObjectRef , PyResult , TypeProtocol } ;
@@ -8,16 +9,12 @@ use std::fs::File;
89use std:: io:: { BufRead , BufReader } ;
910
1011fn exception_init ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
11- let zelf = args. args [ 0 ] . clone ( ) ;
12- let msg = if args. args . len ( ) > 1 {
13- args. args [ 1 ] . clone ( )
14- } else {
15- let empty_string = String :: default ( ) ;
16- vm. new_str ( empty_string)
17- } ;
12+ let exc_self = args. args [ 0 ] . clone ( ) ;
13+ let exc_args = vm. ctx . new_tuple ( args. args [ 1 ..] . to_vec ( ) ) ;
14+ vm. set_attr ( & exc_self, "args" , exc_args) ?;
15+
1816 let traceback = vm. ctx . new_list ( Vec :: new ( ) ) ;
19- vm. set_attr ( & zelf, "msg" , msg) ?;
20- vm. set_attr ( & zelf, "__traceback__" , traceback) ?;
17+ vm. set_attr ( & exc_self, "__traceback__" , traceback) ?;
2118 Ok ( vm. get_none ( ) )
2219}
2320
@@ -119,25 +116,70 @@ pub fn print_exception_inner(vm: &VirtualMachine, exc: &PyObjectRef) {
119116 }
120117}
121118
119+ fn exception_args_as_string ( vm : & VirtualMachine , varargs : PyTupleRef ) -> Vec < String > {
120+ match varargs. elements . len ( ) {
121+ 0 => vec ! [ ] ,
122+ 1 => {
123+ let args0_repr = match vm. to_repr ( & varargs. elements [ 0 ] ) {
124+ Ok ( args0_repr) => args0_repr. value . clone ( ) ,
125+ Err ( _) => "<element repr() failed>" . to_string ( ) ,
126+ } ;
127+ vec ! [ args0_repr]
128+ }
129+ _ => {
130+ let mut args_vec = Vec :: with_capacity ( varargs. elements . len ( ) ) ;
131+ for vararg in & varargs. elements {
132+ let arg_repr = match vm. to_repr ( vararg) {
133+ Ok ( arg_repr) => arg_repr. value . clone ( ) ,
134+ Err ( _) => "<element repr() failed>" . to_string ( ) ,
135+ } ;
136+ args_vec. push ( arg_repr) ;
137+ }
138+ args_vec
139+ }
140+ }
141+ }
142+
122143fn exception_str ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
123144 arg_check ! (
124145 vm,
125146 args,
126147 required = [ ( exc, Some ( vm. ctx. exceptions. exception_type. clone( ) ) ) ]
127148 ) ;
128- let msg = if let Ok ( m) = vm. get_attribute ( exc. clone ( ) , "msg" ) {
129- match vm. to_pystr ( & m) {
130- Ok ( msg) => msg,
131- _ => "<exception str() failed>" . to_string ( ) ,
132- }
133- } else {
134- panic ! ( "Error message must be set" ) ;
149+ let args = vm
150+ . get_attribute ( exc. clone ( ) , "args" )
151+ . unwrap ( )
152+ . downcast :: < PyTuple > ( )
153+ . expect ( "'args' must be a tuple" ) ;
154+ let args_str = exception_args_as_string ( vm, args) ;
155+ let joined_str = match args_str. len ( ) {
156+ 0 => "" . to_string ( ) ,
157+ 1 => args_str[ 0 ] . to_string ( ) ,
158+ _ => format ! ( "({})" , args_str. join( ", " ) ) ,
135159 } ;
136- let mut exc_repr = exc. class ( ) . name . clone ( ) ;
137- if !msg. is_empty ( ) {
138- & exc_repr. push_str ( & format ! ( ": {}" , msg) ) ;
139- }
140- Ok ( vm. new_str ( exc_repr) )
160+ Ok ( vm. new_str ( joined_str) )
161+ }
162+
163+ fn exception_repr ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
164+ arg_check ! (
165+ vm,
166+ args,
167+ required = [ ( exc, Some ( vm. ctx. exceptions. exception_type. clone( ) ) ) ]
168+ ) ;
169+ let args = vm
170+ . get_attribute ( exc. clone ( ) , "args" )
171+ . unwrap ( )
172+ . downcast :: < PyTuple > ( )
173+ . expect ( "'args' must be a tuple" ) ;
174+ let args_repr = exception_args_as_string ( vm, args) ;
175+
176+ let exc_repr = exc. class ( ) . name . clone ( ) ;
177+ let joined_str = match args_repr. len ( ) {
178+ 0 => format ! ( "{}()" , exc_repr) ,
179+ 1 => format ! ( "{}({})" , exc_repr, args_repr[ 0 ] . to_string( ) ) ,
180+ _ => format ! ( "{}({})" , exc_repr, args_repr. join( ", " ) ) ,
181+ } ;
182+ Ok ( vm. new_str ( joined_str) )
141183}
142184
143185#[ derive( Debug ) ]
@@ -266,6 +308,7 @@ pub fn init(context: &PyContext) {
266308
267309 let exception_type = & context. exceptions . exception_type ;
268310 extend_class ! ( context, exception_type, {
269- "__str__" => context. new_rustfunc( exception_str)
311+ "__str__" => context. new_rustfunc( exception_str) ,
312+ "__repr__" => context. new_rustfunc( exception_repr) ,
270313 } ) ;
271314}
0 commit comments