@@ -6,8 +6,10 @@ use crate::util::{
6
6
use proc_macro2:: TokenStream ;
7
7
use quote:: { quote, quote_spanned, ToTokens } ;
8
8
use std:: collections:: HashMap ;
9
+ use syn:: parse:: { Parse , ParseStream , Result as ParsingResult } ;
9
10
use syn:: {
10
- parse_quote, spanned:: Spanned , Attribute , AttributeArgs , Ident , Item , Meta , NestedMeta , Result ,
11
+ parse_quote, spanned:: Spanned , Attribute , AttributeArgs , Ident , Item , LitStr , Meta , NestedMeta ,
12
+ Result , Token ,
11
13
} ;
12
14
use syn_ext:: ext:: * ;
13
15
@@ -288,6 +290,71 @@ pub(crate) fn impl_pyexception(
288
290
Ok ( ret)
289
291
}
290
292
293
+ pub ( crate ) fn impl_define_exception (
294
+ exc_def : PyExceptionDef ,
295
+ ) -> std:: result:: Result < TokenStream , Diagnostic > {
296
+ let PyExceptionDef {
297
+ class_name,
298
+ base_class,
299
+ ctx_name,
300
+ docs,
301
+ tp_new,
302
+ init,
303
+ } = exc_def;
304
+
305
+ // We need this method, because of how `CPython` copies `__new__`
306
+ // from `BaseException` in `SimpleExtendsException` macro.
307
+ // See: `BaseException_new`
308
+ let tp_new_slot = match tp_new {
309
+ Some ( tp_call) => quote ! { #tp_call( cls, args, vm) } ,
310
+ None => quote ! { #base_class:: tp_new( cls, args, vm) } ,
311
+ } ;
312
+
313
+ // We need this method, because of how `CPython` copies `__init__`
314
+ // from `BaseException` in `SimpleExtendsException` macro.
315
+ // See: `(initproc)BaseException_init`
316
+ let init_method = match init {
317
+ Some ( init_def) => quote ! { #init_def( zelf, args, vm) } ,
318
+ None => quote ! { #base_class:: init( zelf, args, vm) } ,
319
+ } ;
320
+
321
+ let ret = quote ! {
322
+ #[ pyexception( #class_name, #base_class) ]
323
+ #[ derive( Debug ) ]
324
+ #[ doc = #docs]
325
+ struct #class_name { }
326
+
327
+ // We need this to make extend mechanism work:
328
+ impl PyValue for #class_name {
329
+ fn class( vm: & VirtualMachine ) -> & PyTypeRef {
330
+ & vm. ctx. exceptions. #ctx_name
331
+ }
332
+ }
333
+
334
+ #[ pyimpl( flags( BASETYPE , HAS_DICT ) ) ]
335
+ impl #class_name {
336
+ #[ pyslot]
337
+ pub ( crate ) fn tp_new(
338
+ cls: PyTypeRef ,
339
+ args: FuncArgs ,
340
+ vm: & VirtualMachine ,
341
+ ) -> PyResult {
342
+ #tp_new_slot
343
+ }
344
+
345
+ #[ pymethod( magic) ]
346
+ pub ( crate ) fn init(
347
+ zelf: PyRef <PyBaseException >,
348
+ args: FuncArgs ,
349
+ vm: & VirtualMachine ,
350
+ ) -> PyResult <( ) > {
351
+ #init_method
352
+ }
353
+ }
354
+ } ;
355
+ Ok ( ret)
356
+ }
357
+
291
358
/// #[pymethod] and #[pyclassmethod]
292
359
struct MethodItem {
293
360
inner : ContentItemInner ,
@@ -971,6 +1038,50 @@ where
971
1038
Ok ( ( result, cfgs) )
972
1039
}
973
1040
1041
+ #[ derive( Debug ) ]
1042
+ pub ( crate ) struct PyExceptionDef {
1043
+ pub class_name : Ident ,
1044
+ pub base_class : Ident ,
1045
+ pub ctx_name : Ident ,
1046
+ pub docs : LitStr ,
1047
+
1048
+ /// Holds optional `tp_new` slot to be used instead of a default one:
1049
+ pub tp_new : Option < Ident > ,
1050
+ /// We also store `__init__` magic method, that can
1051
+ pub init : Option < Ident > ,
1052
+ }
1053
+
1054
+ impl Parse for PyExceptionDef {
1055
+ fn parse ( input : ParseStream ) -> ParsingResult < Self > {
1056
+ let class_name: Ident = input. parse ( ) ?;
1057
+ input. parse :: < Token ! [ , ] > ( ) ?;
1058
+
1059
+ let base_class: Ident = input. parse ( ) ?;
1060
+ input. parse :: < Token ! [ , ] > ( ) ?;
1061
+
1062
+ let ctx_name: Ident = input. parse ( ) ?;
1063
+ input. parse :: < Token ! [ , ] > ( ) ?;
1064
+
1065
+ let docs: LitStr = input. parse ( ) ?;
1066
+ input. parse :: < Option < Token ! [ , ] > > ( ) ?;
1067
+
1068
+ let tp_new: Option < Ident > = input. parse ( ) ?;
1069
+ input. parse :: < Option < Token ! [ , ] > > ( ) ?;
1070
+
1071
+ let init: Option < Ident > = input. parse ( ) ?;
1072
+ input. parse :: < Option < Token ! [ , ] > > ( ) ?; // leading `,`
1073
+
1074
+ Ok ( PyExceptionDef {
1075
+ class_name,
1076
+ base_class,
1077
+ ctx_name,
1078
+ docs,
1079
+ tp_new,
1080
+ init,
1081
+ } )
1082
+ }
1083
+ }
1084
+
974
1085
fn parse_vec_ident (
975
1086
attr : & [ NestedMeta ] ,
976
1087
item : & Item ,
0 commit comments