@@ -2,7 +2,7 @@ use crate::error::Diagnostic;
22use crate :: util:: {
33 format_doc, iter_use_idents, pyclass_ident_and_attrs, text_signature, AttrItemMeta ,
44 AttributeExt , ClassItemMeta , ContentItem , ContentItemInner , ErrorVec , ItemMeta , ItemNursery ,
5- SimpleItemMeta , ALL_ALLOWED_NAMES ,
5+ ModuleItemMeta , SimpleItemMeta , ALL_ALLOWED_NAMES ,
66} ;
77use proc_macro2:: { Span , TokenStream } ;
88use quote:: { quote, quote_spanned, ToTokens } ;
@@ -45,7 +45,9 @@ impl FromStr for AttrName {
4545#[ derive( Default ) ]
4646struct ModuleContext {
4747 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
4951 errors : Vec < syn:: Error > ,
5052}
5153
@@ -56,7 +58,7 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
5658 } ;
5759 let fake_ident = Ident :: new ( "pymodule" , module_item. span ( ) ) ;
5860 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 ( ) ) ?;
6062
6163 // generation resources
6264 let mut context = ModuleContext {
@@ -91,7 +93,8 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
9193
9294 // append additional items
9395 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 ( ) ?;
9598 let doc = doc. or_else ( || {
9699 crate :: doc:: Database :: shared ( )
97100 . try_path ( module_name)
@@ -104,29 +107,99 @@ pub fn impl_pymodule(attr: AttributeArgs, module_item: Item) -> Result<TokenStre
104107 } else {
105108 quote ! ( None )
106109 } ;
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+ }
107157 items. extend ( iter_chain ! [
108158 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+ }
110174 } ,
111175 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+ }
113183 } ,
114184 parse_quote! {
115- pub ( crate ) fn extend_module(
185+ // TODO: remove once PyMethodDef done
186+ pub ( crate ) fn __init_methods(
116187 vm: & :: rustpython_vm:: VirtualMachine ,
117188 module: & :: rustpython_vm:: Py <:: rustpython_vm:: builtins:: PyModule >,
118189 ) {
119- #module_extend_items
190+ #(
191+ super :: #withs:: __init_methods( vm, module) ;
192+ ) *
193+ let ctx = & vm. ctx;
194+ #function_items
120195 }
121196 } ,
122197 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) ;
130203 }
131204 } ,
132205 ] ) ;
@@ -248,6 +321,53 @@ where
248321 Ok ( ( result, cfgs) )
249322}
250323
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+
251371/// #[pyfunction]
252372struct FunctionItem {
253373 inner : ContentItemInner < AttrName > ,
@@ -318,7 +438,7 @@ impl ModuleItem for FunctionItem {
318438 let py_name = item_meta. simple_name ( ) ?;
319439 let sig_doc = text_signature ( func. sig ( ) , & py_name) ;
320440
321- let ( tokens, py_names) = {
441+ let ( tokens, py_names, doc ) = {
322442 let module = args. module_name ( ) ;
323443 let doc = args. attrs . doc ( ) . or_else ( || {
324444 crate :: doc:: Database :: shared ( )
@@ -332,10 +452,10 @@ impl ModuleItem for FunctionItem {
332452 } else {
333453 sig_doc
334454 } ;
335- let doc = quote ! ( . with_doc( #doc. to_owned( ) , & vm. ctx) ) ;
455+ let with_doc = quote ! ( . with_doc( #doc. to_owned( ) , & vm. ctx) ) ;
336456 let new_func = quote_spanned ! ( ident. span( ) =>
337457 vm. ctx. make_func_def( vm. ctx. intern_str( #py_name) , #ident)
338- #doc
458+ #with_doc
339459 . into_function( )
340460 . with_module( vm. new_pyobj( #module. to_owned( ) ) )
341461 . into_ref( & vm. ctx)
@@ -348,6 +468,7 @@ impl ModuleItem for FunctionItem {
348468 vm. __module_set_attr( module, #py_name, func) . unwrap( ) ;
349469 } } ,
350470 vec ! [ py_name] ,
471+ doc,
351472 )
352473 } else {
353474 let mut py_names = HashSet :: new ( ) ;
@@ -381,17 +502,18 @@ impl ModuleItem for FunctionItem {
381502 }
382503 } } ,
383504 py_names,
505+ doc,
384506 )
385507 }
386508 } ;
387509
388- args. context . module_extend_items . add_item (
389- ident. clone ( ) ,
510+ args. context . function_items . add_item ( FunctionNurseryItem {
511+ ident : ident . to_owned ( ) ,
390512 py_names,
391- args. cfgs . to_vec ( ) ,
513+ cfgs : args. cfgs . to_vec ( ) ,
514+ doc,
392515 tokens,
393- 10 ,
394- ) ?;
516+ } ) ;
395517 Ok ( ( ) )
396518 }
397519}
@@ -432,8 +554,8 @@ impl ModuleItem for ClassItem {
432554 class_meta. class_name ( ) ?
433555 } ;
434556 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) ) ;
437559 ) ;
438560 ( class_name, class_new)
439561 } ;
@@ -473,7 +595,7 @@ impl ModuleItem for ClassItem {
473595 } ,
474596 } ;
475597
476- args. context . module_extend_items . add_item (
598+ args. context . attribute_items . add_item (
477599 ident. clone ( ) ,
478600 py_names,
479601 args. cfgs . to_vec ( ) ,
@@ -561,7 +683,7 @@ impl ModuleItem for AttributeItem {
561683 let tokens = quote_spanned ! { ident. span( ) =>
562684 vm. __module_set_attr( module, #py_name, vm. new_pyobj( #ident) ) . unwrap( ) ;
563685 } ;
564- args. context . module_extend_items . add_item (
686+ args. context . attribute_items . add_item (
565687 ident. clone ( ) ,
566688 vec ! [ py_name] ,
567689 cfgs. clone ( ) ,
@@ -624,7 +746,7 @@ impl ModuleItem for AttributeItem {
624746 } ;
625747
626748 args. context
627- . module_extend_items
749+ . attribute_items
628750 . add_item ( ident, py_names, cfgs, tokens, 1 ) ?;
629751
630752 Ok ( ( ) )
0 commit comments