# SPDX-License-Identifier: BSD-2-Clause # Copyright (c) 2024 Phil Thompson from .specification import PySlot # A 4-tuple of the name, the type, True if the slot requires %MethodCode and # the number of arguments required (-1 if any number is valid). _SLOT_DEFINITIONS = ( ('__str__', PySlot.STR, True, 0), ('__int__', PySlot.INT, False, 0), ('__float__', PySlot.FLOAT, False, 0), ('__len__', PySlot.LEN, True, 0), ('__contains__', PySlot.CONTAINS, True, 1), ('__add__', PySlot.ADD, False, 1), ('__sub__', PySlot.SUB, False, 1), ('__mul__', PySlot.MUL, False, 1), ('__mod__', PySlot.MOD, False, 1), ('__floordiv__', PySlot.FLOORDIV, True, 1), ('__truediv__', PySlot.TRUEDIV, False, 1), ('__and__', PySlot.AND, False, 1), ('__or__', PySlot.OR, False, 1), ('__xor__', PySlot.XOR, False, 1), ('__lshift__', PySlot.LSHIFT, False, 1), ('__rshift__', PySlot.RSHIFT, False, 1), ('__iadd__', PySlot.IADD, False, 1), ('__isub__', PySlot.ISUB, False, 1), ('__imul__', PySlot.IMUL, False, 1), ('__imod__', PySlot.IMOD, False, 1), ('__ifloordiv__', PySlot.IFLOORDIV, True, 1), ('__itruediv__', PySlot.ITRUEDIV, False, 1), ('__iand__', PySlot.IAND, False, 1), ('__ior__', PySlot.IOR, False, 1), ('__ixor__', PySlot.IXOR, False, 1), ('__ilshift__', PySlot.ILSHIFT, False, 1), ('__irshift__', PySlot.IRSHIFT, False, 1), ('__invert__', PySlot.INVERT, False, 0), ('__call__', PySlot.CALL, False, -1), ('__getitem__', PySlot.GETITEM, False, 1), ('__setitem__', PySlot.SETITEM, True, 2), ('__delitem__', PySlot.DELITEM, True, 1), ('__lt__', PySlot.LT, False, 1), ('__le__', PySlot.LE, False, 1), ('__eq__', PySlot.EQ, False, 1), ('__ne__', PySlot.NE, False, 1), ('__gt__', PySlot.GT, False, 1), ('__ge__', PySlot.GE, False, 1), ('__bool__', PySlot.BOOL, True, 0), ('__neg__', PySlot.NEG, False, 0), ('__pos__', PySlot.POS, False, 0), ('__abs__', PySlot.ABS, True, 0), ('__repr__', PySlot.REPR, True, 0), ('__hash__', PySlot.HASH, True, 0), ('__index__', PySlot.INDEX, True, 0), ('__iter__', PySlot.ITER, True, 0), ('__next__', PySlot.NEXT, True, 0), ('__setattr__', PySlot.SETATTR, True, 2), ('__delattr__', PySlot.DELATTR, True, 1), ('__matmul__', PySlot.MATMUL, False, 1), ('__imatmul__', PySlot.IMATMUL, False, 1), ('__await__', PySlot.AWAIT, True, 0), ('__aiter__', PySlot.AITER, True, 0), ('__anext__', PySlot.ANEXT, True, 0), ) # The mapping of slot type to slot name. slot_type_name_map = {t: n for n, t, f, a in _SLOT_DEFINITIONS} # The mapping of slot name to a 3-tuple of type, %MethodCode flag and argument # count. slot_name_detail_map = {n: (t, f, a) for n, t, f, a in _SLOT_DEFINITIONS} def invalid_global_slot(slot): """ Return True if a slot cannot be specified as a global (ie. module level) slot. """ if slot in (PySlot.NEG, PySlot.POS): return False if is_number_slot(slot): return False if is_inplace_number_slot(slot): return False if is_rich_compare_slot(slot): return False return True def is_hash_return_slot(slot): """ Return True if a slot returns a Py_hash_t. """ return slot is PySlot.HASH _INPLACE_NUMBER_SLOTS = (PySlot.IADD, PySlot.ISUB, PySlot.IMUL, PySlot.IMOD, PySlot.IFLOORDIV, PySlot.ITRUEDIV, PySlot.IAND, PySlot.IOR, PySlot.IXOR, PySlot.ILSHIFT, PySlot.IRSHIFT, PySlot.IMATMUL) def is_inplace_number_slot(slot): """ Return True if a slot is an inplace binary numeric slot. """ return slot in _INPLACE_NUMBER_SLOTS _INPLACE_SEQUENCE_SLOTS = (PySlot.ICONCAT, PySlot.IREPEAT) def is_inplace_sequence_slot(slot): """ Return True if a slot is an inplace sequence slot. """ return slot in _INPLACE_SEQUENCE_SLOTS _INT_ARG_SLOTS = (PySlot.REPEAT, PySlot.IREPEAT) def is_int_arg_slot(slot): """ Return True if a slot taks an int argument. """ return slot in _INT_ARG_SLOTS _INT_RETURN_SLOTS = (PySlot.BOOL, PySlot.CONTAINS) def is_int_return_slot(slot): """ Return True if a slot returns an int. """ return slot in _INT_RETURN_SLOTS _MULTI_ARG_SLOTS = (PySlot.SETITEM, PySlot.CALL) def is_multi_arg_slot(slot): """ Return True if a slot takes more than one argument. """ return slot in _MULTI_ARG_SLOTS _NUMBER_SLOTS = (PySlot.ADD, PySlot.SUB, PySlot.MUL, PySlot.MOD, PySlot.FLOORDIV, PySlot.TRUEDIV, PySlot.AND, PySlot.OR, PySlot.XOR, PySlot.LSHIFT, PySlot.RSHIFT, PySlot.MATMUL) def is_number_slot(slot): """ Return True if a slot is a binary numeric slot. """ return slot in _NUMBER_SLOTS _RICH_COMPARE_SLOTS = (PySlot.LT, PySlot.LE, PySlot.EQ, PySlot.NE, PySlot.GT, PySlot.GE) def is_rich_compare_slot(slot): """ Return True if a slot is a rich comparision slot. """ return slot in _RICH_COMPARE_SLOTS def is_ssize_return_slot(slot): """ Return True if a slot returns a Py_ssize_t. """ return slot is PySlot.LEN _VOID_RETURN_SLOTS = (PySlot.SETITEM, PySlot.DELITEM, PySlot.SETATTR) def is_void_return_slot(slot): """ Return True if a slot returns a void. """ return slot in _VOID_RETURN_SLOTS _ZERO_ARG_SLOTS = (PySlot.STR, PySlot.INT, PySlot.FLOAT, PySlot.INVERT, PySlot.NEG, PySlot.LEN, PySlot.BOOL, PySlot.POS, PySlot.ABS, PySlot.REPR, PySlot.HASH, PySlot.INDEX, PySlot.ITER, PySlot.NEXT, PySlot.AWAIT, PySlot.AITER, PySlot.ANEXT) def is_zero_arg_slot(slot): """ Return True if a slot takes zero arguments. """ return slot in _ZERO_ARG_SLOTS # A map of slots and the names of their reflections. _SLOT_REFLECTIONS = { PySlot.ADD: '__radd__', PySlot.SUB: '__rsub__', PySlot.MUL: '__rmul__', PySlot.MATMUL: '__rmatmul__', PySlot.TRUEDIV: '__rtruediv__', PySlot.FLOORDIV: '__rfloordiv__', PySlot.MOD: '__rmod__', PySlot.LSHIFT: '__rlshift__', PySlot.RSHIFT: '__rrshift__', PySlot.AND: '__rand__', PySlot.OR: '__ror__', PySlot.XOR: '__rxor__', } def reflected_slot(slot): """ Return the name of the reflected version of a slot or None if it doesn't have one. """ return _SLOT_REFLECTIONS.get(slot)