1010from mypyc .emitfunc import native_function_header
1111from mypyc .emitwrapper import (
1212 generate_dunder_wrapper , generate_hash_wrapper , generate_richcompare_wrapper ,
13+ generate_bool_wrapper ,
1314)
1415from mypyc .ops import (
1516 ClassIR , FuncIR , FuncDecl , RType , RTuple , Environment , object_rprimitive , FuncSignature ,
@@ -31,6 +32,7 @@ def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
3132# We maintain a table from dunder function names to struct slots they
3233# correspond to and functions that generate a wrapper (if necessary)
3334# and return the function name to stick in the slot.
35+ # TODO: Add remaining dunder methods
3436SlotGenerator = Callable [[ClassIR , FuncIR , Emitter ], str ]
3537SlotTable = Mapping [str , Tuple [str , SlotGenerator ]]
3638
@@ -44,6 +46,19 @@ def wrapper_slot(cl: ClassIR, fn: FuncIR, emitter: Emitter) -> str:
4446 '__hash__' : ('tp_hash' , generate_hash_wrapper ),
4547}
4648
49+ AS_MAPPING_SLOT_DEFS = {
50+ '__getitem__' : ('mp_subscript' , generate_dunder_wrapper ),
51+ }
52+
53+ AS_NUMBER_SLOT_DEFS = {
54+ '__bool__' : ('nb_bool' , generate_bool_wrapper ),
55+ }
56+
57+ SIDE_TABLES = [
58+ ('as_mapping' , 'PyMappingMethods' , AS_MAPPING_SLOT_DEFS ),
59+ ('as_number' , 'PyNumberMethods' , AS_NUMBER_SLOT_DEFS ),
60+ ]
61+
4762
4863def generate_slots (cl : ClassIR , table : SlotTable , emitter : Emitter ) -> Dict [str , str ]:
4964 fields = OrderedDict () # type: Dict[str, str]
@@ -103,12 +118,14 @@ def emit_line() -> None:
103118 init_fn = cl .get_method ('__init__' )
104119
105120 # Fill out slots in the type object from dunder methods.
106- # TODO: Add remaining dunder methods
107121 fields .update (generate_slots (cl , SLOT_DEFS , emitter ))
108122
109- as_mapping_name = generate_as_mapping_for_class (cl , emitter )
110- if as_mapping_name :
111- fields ['tp_as_mapping' ] = '&{}' .format (as_mapping_name )
123+ # Fill out dunder methods that live in tables hanging off the side.
124+ for table_name , type , slot_defs in SIDE_TABLES :
125+ slots = generate_slots (cl , slot_defs , emitter )
126+ if slots :
127+ table_struct_name = generate_side_table_for_class (cl , table_name , type , slots , emitter )
128+ fields ['tp_{}' .format (table_name )] = '&{}' .format (table_struct_name )
112129
113130 richcompare_name = generate_richcompare_wrapper (cl , emitter )
114131 if richcompare_name :
@@ -457,18 +474,13 @@ def generate_methods_table(cl: ClassIR,
457474 emitter .emit_line ('};' )
458475
459476
460- AS_MAPPING_SLOT_DEFS = {
461- '__getitem__' : ('mp_subscript' , generate_dunder_wrapper ),
462- }
463-
464-
465- def generate_as_mapping_for_class (cl : ClassIR ,
477+ def generate_side_table_for_class (cl : ClassIR ,
478+ name : str ,
479+ type : str ,
480+ slots : Dict [str , str ],
466481 emitter : Emitter ) -> Optional [str ]:
467- slots = generate_slots (cl , AS_MAPPING_SLOT_DEFS , emitter )
468- if not slots :
469- return None
470- name = '{}_as_mapping' .format (cl .name_prefix (emitter .names ))
471- emitter .emit_line ('static PyMappingMethods {} = {{' .format (name ))
482+ name = '{}_{}' .format (cl .name_prefix (emitter .names ), name )
483+ emitter .emit_line ('static {} {} = {{' .format (type , name ))
472484 for field , value in slots .items ():
473485 emitter .emit_line (".{} = {}," .format (field , value ))
474486 emitter .emit_line ("};" )
0 commit comments