@@ -2,7 +2,7 @@ use crate::error::Diagnostic;
2
2
use crate :: util:: {
3
3
format_doc, iter_use_idents, pyclass_ident_and_attrs, text_signature, AttrItemMeta ,
4
4
AttributeExt , ClassItemMeta , ContentItem , ContentItemInner , ErrorVec , ItemMeta , ItemNursery ,
5
- SimpleItemMeta , ALL_ALLOWED_NAMES ,
5
+ ModuleItemMeta , SimpleItemMeta , ALL_ALLOWED_NAMES ,
6
6
} ;
7
7
use proc_macro2:: { Span , TokenStream } ;
8
8
use quote:: { quote, quote_spanned, ToTokens } ;
@@ -45,7 +45,9 @@ impl FromStr for AttrName {
45
45
#[ derive( Default ) ]
46
46
struct ModuleContext {
47
47
name : String ,
48
- module_extend_items : ItemNursery ,
48
+ function_items : FunctionNursery ,
49
+ attribute_items : ItemNursery ,
50
+ has_extend_module : bool , // TODO: check if `fn extend_module` exists
49
51
errors : Vec < syn:: Error > ,
50
52
}
51
53
@@ -56,7 +58,7 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
56
58
} ;
57
59
let fake_ident = Ident :: new ( "pymodule" , module_item. span ( ) ) ;
58
60
let module_meta =
59
- SimpleItemMeta :: from_nested ( module_item. ident . clone ( ) , fake_ident, attr. into_iter ( ) ) ?;
61
+ ModuleItemMeta :: from_nested ( module_item. ident . clone ( ) , fake_ident, attr. into_iter ( ) ) ?;
60
62
61
63
// generation resources
62
64
let mut context = ModuleContext {
@@ -91,7 +93,8 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
91
93
92
94
// append additional items
93
95
let module_name = context. name . as_str ( ) ;
94
- let module_extend_items = context. module_extend_items . validate ( ) ?;
96
+ let function_items = context. function_items . validate ( ) ?;
97
+ let attribute_items = context. attribute_items . validate ( ) ?;
95
98
let doc = doc. or_else ( || {
96
99
crate :: doc:: Database :: shared ( )
97
100
. try_path ( module_name)
@@ -104,29 +107,99 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
104
107
} else {
105
108
quote ! ( None )
106
109
} ;
110
+ let is_submodule = module_meta. sub ( ) ?;
111
+ let withs = module_meta. with ( ) ?;
112
+ if !is_submodule {
113
+ items. extend ( iter_chain ! [
114
+ parse_quote! {
115
+ pub ( crate ) const MODULE_NAME : & ' static str = #module_name;
116
+ } ,
117
+ parse_quote! {
118
+ pub ( crate ) const DOC : Option <& ' static str > = #doc;
119
+ } ,
120
+ parse_quote! {
121
+ pub ( crate ) fn __module_def(
122
+ ctx: & :: rustpython_vm:: Context ,
123
+ ) -> & ' static :: rustpython_vm:: builtins:: PyModuleDef {
124
+ DEF . get_or_init( || {
125
+ let mut def = :: rustpython_vm:: builtins:: PyModuleDef {
126
+ name: ctx. intern_str( MODULE_NAME ) ,
127
+ doc: DOC . map( |doc| ctx. intern_str( doc) ) ,
128
+ slots: Default :: default ( ) ,
129
+ } ;
130
+ def. slots. exec = Some ( extend_module) ;
131
+ def
132
+ } )
133
+ }
134
+ } ,
135
+ parse_quote! {
136
+ #[ allow( dead_code) ]
137
+ pub ( crate ) fn make_module(
138
+ vm: & :: rustpython_vm:: VirtualMachine
139
+ ) -> :: rustpython_vm:: PyRef <:: rustpython_vm:: builtins:: PyModule > {
140
+ use :: rustpython_vm:: PyPayload ;
141
+ let module = :: rustpython_vm:: builtins:: PyModule :: from_def( __module_def( & vm. ctx) ) . into_ref( & vm. ctx) ;
142
+ __init_dict( vm, & module) ;
143
+ extend_module( vm, & module) . unwrap( ) ;
144
+ module
145
+ }
146
+ } ,
147
+ ] ) ;
148
+ }
149
+ if !is_submodule && !context. has_extend_module {
150
+ items. push ( parse_quote ! {
151
+ pub ( crate ) fn extend_module( vm: & :: rustpython_vm:: VirtualMachine , module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >) -> :: rustpython_vm:: PyResult <( ) > {
152
+ __extend_module( vm, module) ;
153
+ Ok ( ( ) )
154
+ }
155
+ } ) ;
156
+ }
107
157
items. extend ( iter_chain ! [
108
158
parse_quote! {
109
- pub ( crate ) const MODULE_NAME : & ' static str = #module_name;
159
+ :: rustpython_vm:: common:: static_cell! {
160
+ pub ( crate ) static DEF : :: rustpython_vm:: builtins:: PyModuleDef ;
161
+ }
162
+ } ,
163
+ parse_quote! {
164
+ pub ( crate ) fn __init_attributes(
165
+ vm: & :: rustpython_vm:: VirtualMachine ,
166
+ module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >,
167
+ ) {
168
+ #(
169
+ super :: #withs:: __init_attributes( vm, module) ;
170
+ ) *
171
+ let ctx = & vm. ctx;
172
+ #attribute_items
173
+ }
110
174
} ,
111
175
parse_quote! {
112
- pub ( crate ) const DOC : Option <& ' static str > = #doc;
176
+ pub ( crate ) fn __extend_module(
177
+ vm: & :: rustpython_vm:: VirtualMachine ,
178
+ module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >,
179
+ ) {
180
+ __init_methods( vm, module) ;
181
+ __init_attributes( vm, module) ;
182
+ }
113
183
} ,
114
184
parse_quote! {
115
- pub ( crate ) fn extend_module(
185
+ // TODO: remove once PyMethodDef done
186
+ pub ( crate ) fn __init_methods(
116
187
vm: & :: rustpython_vm:: VirtualMachine ,
117
188
module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >,
118
189
) {
119
- #module_extend_items
190
+ #(
191
+ super :: #withs:: __init_methods( vm, module) ;
192
+ ) *
193
+ let ctx = & vm. ctx;
194
+ #function_items
120
195
}
121
196
} ,
122
197
parse_quote! {
123
- #[ allow( dead_code) ]
124
- pub ( crate ) fn make_module(
125
- vm: & :: rustpython_vm:: VirtualMachine
126
- ) -> :: rustpython_vm:: PyRef <:: rustpython_vm:: builtins:: PyModule > {
127
- let module = vm. new_module( MODULE_NAME , vm. ctx. new_dict( ) , DOC ) ;
128
- extend_module( vm, & module) ;
129
- module
198
+ pub ( crate ) fn __init_dict(
199
+ vm: & :: rustpython_vm:: VirtualMachine ,
200
+ module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >,
201
+ ) {
202
+ :: rustpython_vm:: builtins:: PyModule :: __init_dict_from_def( vm, module) ;
130
203
}
131
204
} ,
132
205
] ) ;
@@ -248,6 +321,53 @@ where
248
321
Ok ( ( result, cfgs) )
249
322
}
250
323
324
+ #[ derive( Default ) ]
325
+ struct FunctionNursery {
326
+ items : Vec < FunctionNurseryItem > ,
327
+ }
328
+
329
+ struct FunctionNurseryItem {
330
+ py_names : Vec < String > ,
331
+ cfgs : Vec < Attribute > ,
332
+ ident : Ident ,
333
+ #[ allow( dead_code) ]
334
+ doc : String ,
335
+ tokens : TokenStream ,
336
+ }
337
+
338
+ impl FunctionNursery {
339
+ fn add_item ( & mut self , item : FunctionNurseryItem ) {
340
+ self . items . push ( item) ;
341
+ }
342
+
343
+ fn validate ( self ) -> Result < ValidatedFunctionNursery > {
344
+ let mut name_set = HashSet :: new ( ) ;
345
+ for item in & self . items {
346
+ for py_name in & item. py_names {
347
+ if !name_set. insert ( ( py_name. to_owned ( ) , & item. cfgs ) ) {
348
+ bail_span ! ( item. ident, "duplicate method name `{}`" , py_name) ;
349
+ }
350
+ }
351
+ }
352
+ Ok ( ValidatedFunctionNursery ( self ) )
353
+ }
354
+ }
355
+
356
+ struct ValidatedFunctionNursery ( FunctionNursery ) ;
357
+
358
+ impl ToTokens for ValidatedFunctionNursery {
359
+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
360
+ for item in & self . 0 . items {
361
+ let cfgs = & item. cfgs ;
362
+ let item_tokens = & item. tokens ;
363
+ tokens. extend ( quote ! {
364
+ #( #cfgs) *
365
+ #item_tokens
366
+ } ) ;
367
+ }
368
+ }
369
+ }
370
+
251
371
/// #[pyfunction]
252
372
struct FunctionItem {
253
373
inner : ContentItemInner < AttrName > ,
@@ -318,7 +438,7 @@ impl ModuleItem for FunctionItem {
318
438
let py_name = item_meta. simple_name ( ) ?;
319
439
let sig_doc = text_signature ( func. sig ( ) , & py_name) ;
320
440
321
- let ( tokens, py_names) = {
441
+ let ( tokens, py_names, doc ) = {
322
442
let module = args. module_name ( ) ;
323
443
let doc = args. attrs . doc ( ) . or_else ( || {
324
444
crate :: doc:: Database :: shared ( )
@@ -332,10 +452,10 @@ impl ModuleItem for FunctionItem {
332
452
} else {
333
453
sig_doc
334
454
} ;
335
- let doc = quote ! ( . with_doc( #doc. to_owned( ) , & vm. ctx) ) ;
455
+ let with_doc = quote ! ( . with_doc( #doc. to_owned( ) , & vm. ctx) ) ;
336
456
let new_func = quote_spanned ! ( ident. span( ) =>
337
457
vm. ctx. make_func_def( vm. ctx. intern_str( #py_name) , #ident)
338
- #doc
458
+ #with_doc
339
459
. into_function( )
340
460
. with_module( vm. new_pyobj( #module. to_owned( ) ) )
341
461
. into_ref( & vm. ctx)
@@ -348,6 +468,7 @@ impl ModuleItem for FunctionItem {
348
468
vm. __module_set_attr( module, #py_name, func) . unwrap( ) ;
349
469
} } ,
350
470
vec ! [ py_name] ,
471
+ doc,
351
472
)
352
473
} else {
353
474
let mut py_names = HashSet :: new ( ) ;
@@ -381,17 +502,18 @@ impl ModuleItem for FunctionItem {
381
502
}
382
503
} } ,
383
504
py_names,
505
+ doc,
384
506
)
385
507
}
386
508
} ;
387
509
388
- args. context . module_extend_items . add_item (
389
- ident. clone ( ) ,
510
+ args. context . function_items . add_item ( FunctionNurseryItem {
511
+ ident : ident . to_owned ( ) ,
390
512
py_names,
391
- args. cfgs . to_vec ( ) ,
513
+ cfgs : args. cfgs . to_vec ( ) ,
514
+ doc,
392
515
tokens,
393
- 10 ,
394
- ) ?;
516
+ } ) ;
395
517
Ok ( ( ) )
396
518
}
397
519
}
@@ -432,8 +554,8 @@ impl ModuleItem for ClassItem {
432
554
class_meta. class_name ( ) ?
433
555
} ;
434
556
let class_new = quote_spanned ! ( ident. span( ) =>
435
- let new_class = <#ident as :: rustpython_vm:: class:: PyClassImpl >:: make_class( & vm . ctx) ;
436
- new_class. set_attr( rustpython_vm:: identifier!( vm , __module__) , vm. new_pyobj( #module_name) ) ;
557
+ let new_class = <#ident as :: rustpython_vm:: class:: PyClassImpl >:: make_class( ctx) ;
558
+ new_class. set_attr( rustpython_vm:: identifier!( ctx , __module__) , vm. new_pyobj( #module_name) ) ;
437
559
) ;
438
560
( class_name, class_new)
439
561
} ;
@@ -473,7 +595,7 @@ impl ModuleItem for ClassItem {
473
595
} ,
474
596
} ;
475
597
476
- args. context . module_extend_items . add_item (
598
+ args. context . attribute_items . add_item (
477
599
ident. clone ( ) ,
478
600
py_names,
479
601
args. cfgs . to_vec ( ) ,
@@ -561,7 +683,7 @@ impl ModuleItem for AttributeItem {
561
683
let tokens = quote_spanned ! { ident. span( ) =>
562
684
vm. __module_set_attr( module, #py_name, vm. new_pyobj( #ident) ) . unwrap( ) ;
563
685
} ;
564
- args. context . module_extend_items . add_item (
686
+ args. context . attribute_items . add_item (
565
687
ident. clone ( ) ,
566
688
vec ! [ py_name] ,
567
689
cfgs. clone ( ) ,
@@ -624,7 +746,7 @@ impl ModuleItem for AttributeItem {
624
746
} ;
625
747
626
748
args. context
627
- . module_extend_items
749
+ . attribute_items
628
750
. add_item ( ident, py_names, cfgs, tokens, 1 ) ?;
629
751
630
752
Ok ( ( ) )
0 commit comments