TypeSlots.py 34.9 KB
Newer Older
William Stein's avatar
William Stein committed
1
#
2 3
#   Tables describing slots in the CPython type object
#   and associated know-how.
William Stein's avatar
William Stein committed
4 5
#

6 7 8 9
from __future__ import absolute_import

from . import Naming
from . import PyrexTypes
10
from .Errors import error
William Stein's avatar
William Stein committed
11

12
invisible = ['__cinit__', '__dealloc__', '__richcmp__',
13 14
             '__nonzero__', '__bool__']

15

16
class Signature(object):
William Stein's avatar
William Stein committed
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
    #  Method slot signature descriptor.
    #
    #  has_dummy_arg      boolean
    #  has_generic_args   boolean
    #  fixed_arg_format   string
    #  ret_format         string
    #  error_value        string
    #
    #  The formats are strings made up of the following
    #  characters:
    #
    #    'O'  Python object
    #    'T'  Python object of the type of 'self'
    #    'v'  void
    #    'p'  void *
    #    'P'  void **
    #    'i'  int
34
    #    'b'  bint
William Stein's avatar
William Stein committed
35 36
    #    'I'  int *
    #    'l'  long
37 38
    #    'f'  float
    #    'd'  double
39
    #    'h'  Py_hash_t
40 41
    #    'z'  Py_ssize_t
    #    'Z'  Py_ssize_t *
William Stein's avatar
William Stein committed
42 43 44
    #    's'  char *
    #    'S'  char **
    #    'r'  int used only to signal exception
45
    #    'B'  Py_buffer *
William Stein's avatar
William Stein committed
46 47 48 49
    #    '-'  dummy 'self' argument (not used)
    #    '*'  rest of args passed as generic Python
    #           arg tuple and kw dict (must be last
    #           char in format string)
50

William Stein's avatar
William Stein committed
51 52 53 54 55 56
    format_map = {
        'O': PyrexTypes.py_object_type,
        'v': PyrexTypes.c_void_type,
        'p': PyrexTypes.c_void_ptr_type,
        'P': PyrexTypes.c_void_ptr_ptr_type,
        'i': PyrexTypes.c_int_type,
57
        'b': PyrexTypes.c_bint_type,
William Stein's avatar
William Stein committed
58 59
        'I': PyrexTypes.c_int_ptr_type,
        'l': PyrexTypes.c_long_type,
60 61
        'f': PyrexTypes.c_float_type,
        'd': PyrexTypes.c_double_type,
62
        'h': PyrexTypes.c_py_hash_t_type,
63 64
        'z': PyrexTypes.c_py_ssize_t_type,
        'Z': PyrexTypes.c_py_ssize_t_ptr_type,
William Stein's avatar
William Stein committed
65 66 67
        's': PyrexTypes.c_char_ptr_type,
        'S': PyrexTypes.c_char_ptr_ptr_type,
        'r': PyrexTypes.c_returncode_type,
68
        'B': PyrexTypes.c_py_buffer_ptr_type,
William Stein's avatar
William Stein committed
69 70 71
        # 'T', '-' and '*' are handled otherwise
        # and are not looked up in here
    }
72

Stefan Behnel's avatar
Stefan Behnel committed
73
    type_to_format_map = dict(
74
        (type_, format_) for format_, type_ in format_map.items())
75

William Stein's avatar
William Stein committed
76
    error_value_map = {
77
        'O': "NULL",
Stefan Behnel's avatar
Stefan Behnel committed
78
        'T': "NULL",
William Stein's avatar
William Stein committed
79
        'i': "-1",
80
        'b': "-1",
William Stein's avatar
William Stein committed
81 82
        'l': "-1",
        'r': "-1",
83
        'h': "-1",
84
        'z': "-1",
William Stein's avatar
William Stein committed
85
    }
86

William Stein's avatar
William Stein committed
87 88 89 90 91 92 93 94 95 96 97 98
    def __init__(self, arg_format, ret_format):
        self.has_dummy_arg = 0
        self.has_generic_args = 0
        if arg_format[:1] == '-':
            self.has_dummy_arg = 1
            arg_format = arg_format[1:]
        if arg_format[-1:] == '*':
            self.has_generic_args = 1
            arg_format = arg_format[:-1]
        self.fixed_arg_format = arg_format
        self.ret_format = ret_format
        self.error_value = self.error_value_map.get(ret_format, None)
99
        self.exception_check = ret_format != 'r' and self.error_value is not None
100
        self.is_staticmethod = False
101

102 103 104 105 106 107
    def __repr__(self):
        return '<Signature[%s(%s%s)]>' % (
            self.ret_format,
            ', '.join(self.fixed_arg_format),
            '*' if self.has_generic_args else '')

William Stein's avatar
William Stein committed
108 109
    def num_fixed_args(self):
        return len(self.fixed_arg_format)
110

William Stein's avatar
William Stein committed
111
    def is_self_arg(self, i):
Stefan Behnel's avatar
Stefan Behnel committed
112
        # argument is 'self' for methods or 'class' for classmethods
William Stein's avatar
William Stein committed
113
        return self.fixed_arg_format[i] == 'T'
114

Stefan Behnel's avatar
Stefan Behnel committed
115 116 117
    def returns_self_type(self):
        # return type is same as 'self' argument type
        return self.ret_format == 'T'
118

William Stein's avatar
William Stein committed
119 120
    def fixed_arg_type(self, i):
        return self.format_map[self.fixed_arg_format[i]]
121

William Stein's avatar
William Stein committed
122 123
    def return_type(self):
        return self.format_map[self.ret_format]
124

125 126 127 128 129
    def format_from_type(self, arg_type):
        if arg_type.is_pyobject:
            arg_type = PyrexTypes.py_object_type
        return self.type_to_format_map[arg_type]

130 131
    def exception_value(self):
        return self.error_value_map.get(self.ret_format)
132

133
    def function_type(self, self_arg_override=None):
134 135
        #  Construct a C function type descriptor for this signature
        args = []
136
        for i in range(self.num_fixed_args()):
137 138 139 140 141 142
            if self_arg_override is not None and self.is_self_arg(i):
                assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg)
                args.append(self_arg_override)
            else:
                arg_type = self.fixed_arg_type(i)
                args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
Stefan Behnel's avatar
Stefan Behnel committed
143 144 145 146
        if self_arg_override is not None and self.returns_self_type():
            ret_type = self_arg_override.type
        else:
            ret_type = self.return_type()
147
        exc_value = self.exception_value()
148 149 150
        return PyrexTypes.CFuncType(
            ret_type, args, exception_value=exc_value,
            exception_check=self.exception_check)
151

152 153
    def method_flags(self):
        if self.ret_format == "O":
Stefan Behnel's avatar
Stefan Behnel committed
154 155 156
            full_args = self.fixed_arg_format
            if self.has_dummy_arg:
                full_args = "O" + full_args
157 158 159 160 161 162 163
            if full_args in ["O", "T"]:
                if self.has_generic_args:
                    return [method_varargs, method_keywords]
                else:
                    return [method_noargs]
            elif full_args in ["OO", "TO"] and not self.has_generic_args:
                return [method_onearg]
164 165 166

            if self.is_staticmethod:
                return [method_varargs, method_keywords]
167
        return None
William Stein's avatar
William Stein committed
168 169


170
class SlotDescriptor(object):
William Stein's avatar
William Stein committed
171 172 173 174
    #  Abstract base class for type slot descriptors.
    #
    #  slot_name    string           Member name of the slot in the type object
    #  is_initialised_dynamically    Is initialised by code in the module init function
175
    #  is_inherited                  Is inherited by subtypes (see PyType_Ready())
176
    #  py3                           Indicates presence of slot in Python 3
177
    #  py2                           Indicates presence of slot in Python 2
178
    #  ifdef                         Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.)
179

180
    def __init__(self, slot_name, dynamic=False, inherited=False,
181
                 py3=True, py2=True, ifdef=None):
William Stein's avatar
William Stein committed
182 183
        self.slot_name = slot_name
        self.is_initialised_dynamically = dynamic
184
        self.is_inherited = inherited
185
        self.ifdef = ifdef
186 187
        self.py3 = py3
        self.py2 = py2
188

189 190 191 192 193 194 195 196 197 198 199 200 201
    def preprocessor_guard_code(self):
        ifdef = self.ifdef
        py2 = self.py2
        py3 = self.py3
        guard = None
        if ifdef:
            guard = ("#if %s" % ifdef)
        elif not py3 or py3 == '<RESERVED>':
            guard = ("#if PY_MAJOR_VERSION < 3")
        elif not py2:
            guard = ("#if PY_MAJOR_VERSION >= 3")
        return guard

William Stein's avatar
William Stein committed
202
    def generate(self, scope, code):
203 204 205 206
        preprocessor_guard = self.preprocessor_guard_code()
        if preprocessor_guard:
            code.putln(preprocessor_guard)

207
        end_pypy_guard = False
William Stein's avatar
William Stein committed
208
        if self.is_initialised_dynamically:
209
            value = "0"
William Stein's avatar
William Stein committed
210 211
        else:
            value = self.slot_code(scope)
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
            if value == "0" and self.is_inherited:
                # PyPy currently has a broken PyType_Ready() that fails to
                # inherit some slots.  To work around this, we explicitly
                # set inherited slots here, but only in PyPy since CPython
                # handles this better than we do.
                inherited_value = value
                current_scope = scope
                while (inherited_value == "0"
                       and current_scope.parent_type
                       and current_scope.parent_type.base_type
                       and current_scope.parent_type.base_type.scope):
                    current_scope = current_scope.parent_type.base_type.scope
                    inherited_value = self.slot_code(current_scope)
                if inherited_value != "0":
                    code.putln("#if CYTHON_COMPILING_IN_PYPY")
                    code.putln("%s, /*%s*/" % (inherited_value, self.slot_name))
                    code.putln("#else")
                    end_pypy_guard = True
230

William Stein's avatar
William Stein committed
231
        code.putln("%s, /*%s*/" % (value, self.slot_name))
232 233 234 235

        if end_pypy_guard:
            code.putln("#endif")

236 237 238 239
        if self.py3 == '<RESERVED>':
            code.putln("#else")
            code.putln("0, /*reserved*/")
        if preprocessor_guard:
240
            code.putln("#endif")
241

242 243
    # Some C implementations have trouble statically
    # initialising a global with a pointer to an extern
William Stein's avatar
William Stein committed
244 245 246 247 248 249
    # function, so we initialise some of the type slots
    # in the module init function instead.

    def generate_dynamic_init_code(self, scope, code):
        if self.is_initialised_dynamically:
            value = self.slot_code(scope)
Stefan Behnel's avatar
Stefan Behnel committed
250
            if value != "0":
William Stein's avatar
William Stein committed
251
                code.putln("%s.%s = %s;" % (
252 253
                    scope.parent_type.typeobj_cname,
                    self.slot_name,
William Stein's avatar
William Stein committed
254 255
                    value
                    )
256
                )
William Stein's avatar
William Stein committed
257 258 259 260 261 262


class FixedSlot(SlotDescriptor):
    #  Descriptor for a type slot with a fixed value.
    #
    #  value        string
263

264 265
    def __init__(self, slot_name, value, py3=True, py2=True, ifdef=None):
        SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef)
William Stein's avatar
William Stein committed
266
        self.value = value
267

William Stein's avatar
William Stein committed
268 269 270 271 272 273
    def slot_code(self, scope):
        return self.value


class EmptySlot(FixedSlot):
    #  Descriptor for a type slot whose value is always 0.
274

275 276
    def __init__(self, slot_name, py3=True, py2=True, ifdef=None):
        FixedSlot.__init__(self, slot_name, "0", py3=py3, py2=py2, ifdef=ifdef)
William Stein's avatar
William Stein committed
277 278 279 280 281 282 283


class MethodSlot(SlotDescriptor):
    #  Type slot descriptor for a user-definable method.
    #
    #  signature    Signature
    #  method_name  string           The __xxx__ name of the method
284
    #  alternatives [string]         Alternative list of __xxx__ names for the method
285 286

    def __init__(self, signature, slot_name, method_name, fallback=None,
287 288 289
                 py3=True, py2=True, ifdef=None, inherited=True):
        SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2,
                                ifdef=ifdef, inherited=inherited)
William Stein's avatar
William Stein committed
290 291 292
        self.signature = signature
        self.slot_name = slot_name
        self.method_name = method_name
293
        self.alternatives = []
William Stein's avatar
William Stein committed
294
        method_name_to_slot[method_name] = self
295 296 297 298 299 300 301 302
        #
        if fallback:
            self.alternatives.append(fallback)
        for alt in (self.py2, self.py3):
            if isinstance(alt, (tuple, list)):
                slot_name, method_name = alt
                self.alternatives.append(method_name)
                method_name_to_slot[method_name] = self
William Stein's avatar
William Stein committed
303 304 305

    def slot_code(self, scope):
        entry = scope.lookup_here(self.method_name)
306
        if entry and entry.func_cname:
William Stein's avatar
William Stein committed
307
            return entry.func_cname
308 309
        for method_name in self.alternatives:
            entry = scope.lookup_here(method_name)
310 311 312
            if entry and entry.func_cname:
                return entry.func_cname
        return "0"
William Stein's avatar
William Stein committed
313 314 315 316


class InternalMethodSlot(SlotDescriptor):
    #  Type slot descriptor for a method which is always
William Stein's avatar
William Stein committed
317
    #  synthesized by Cython.
William Stein's avatar
William Stein committed
318 319 320
    #
    #  slot_name    string           Member name of the slot in the type object

321 322
    def __init__(self, slot_name, **kargs):
        SlotDescriptor.__init__(self, slot_name, **kargs)
William Stein's avatar
William Stein committed
323 324 325 326 327

    def slot_code(self, scope):
        return scope.mangle_internal(self.slot_name)


328 329 330
class GCDependentSlot(InternalMethodSlot):
    #  Descriptor for a slot whose value depends on whether
    #  the type participates in GC.
331

332 333
    def __init__(self, slot_name, **kargs):
        InternalMethodSlot.__init__(self, slot_name, **kargs)
334

335
    def slot_code(self, scope):
336
        if not scope.needs_gc():
337
            return "0"
338 339 340 341
        if not scope.has_cyclic_pyobject_attrs:
            # if the type does not have GC relevant object attributes, it can
            # delegate GC methods to its parent - iff the parent functions
            # are defined in the same module
342 343
            parent_type_scope = scope.parent_type.base_type.scope
            if scope.parent_scope is parent_type_scope.parent_scope:
344 345 346 347
                entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
                if entry.visibility != 'extern':
                    return self.slot_code(parent_type_scope)
        return InternalMethodSlot.slot_code(self, scope)
348 349


350 351 352 353 354 355 356 357
class GCClearReferencesSlot(GCDependentSlot):

    def slot_code(self, scope):
        if scope.needs_tp_clear():
            return GCDependentSlot.slot_code(self, scope)
        return "0"


358 359
class ConstructorSlot(InternalMethodSlot):
    #  Descriptor for tp_new and tp_dealloc.
360

361 362
    def __init__(self, slot_name, method, **kargs):
        InternalMethodSlot.__init__(self, slot_name, **kargs)
363
        self.method = method
364

365
    def slot_code(self, scope):
366 367 368
        if (self.slot_name != 'tp_new'
                and scope.parent_type.base_type
                and not scope.has_pyobject_attrs
369
                and not scope.has_memoryview_attrs
370
                and not scope.has_cpp_class_attrs
371
                and not scope.lookup_here(self.method)):
372 373 374 375 376 377 378 379
            # if the type does not have object attributes, it can
            # delegate GC methods to its parent - iff the parent
            # functions are defined in the same module
            parent_type_scope = scope.parent_type.base_type.scope
            if scope.parent_scope is parent_type_scope.parent_scope:
                entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
                if entry.visibility != 'extern':
                    return self.slot_code(parent_type_scope)
380
        return InternalMethodSlot.slot_code(self, scope)
381 382


William Stein's avatar
William Stein committed
383 384 385 386 387 388 389
class SyntheticSlot(InternalMethodSlot):
    #  Type slot descriptor for a synthesized method which
    #  dispatches to one or more user-defined methods depending
    #  on its arguments. If none of the relevant methods are
    #  defined, the method will not be synthesized and an
    #  alternative default value will be placed in the type
    #  slot.
390

391 392
    def __init__(self, slot_name, user_methods, default_value, **kargs):
        InternalMethodSlot.__init__(self, slot_name, **kargs)
William Stein's avatar
William Stein committed
393 394
        self.user_methods = user_methods
        self.default_value = default_value
395

William Stein's avatar
William Stein committed
396 397 398 399 400 401 402 403 404
    def slot_code(self, scope):
        if scope.defines_any(self.user_methods):
            return InternalMethodSlot.slot_code(self, scope)
        else:
            return self.default_value


class TypeFlagsSlot(SlotDescriptor):
    #  Descriptor for the type flags slot.
405

William Stein's avatar
William Stein committed
406
    def slot_code(self, scope):
407 408 409 410 411 412
        value = "Py_TPFLAGS_DEFAULT"
        if scope.directives['type_version_tag']:
            # it's not in 'Py_TPFLAGS_DEFAULT' in Py2
            value += "|Py_TPFLAGS_HAVE_VERSION_TAG"
        else:
            # it's enabled in 'Py_TPFLAGS_DEFAULT' in Py3
413
            value = "(%s&~Py_TPFLAGS_HAVE_VERSION_TAG)" % value
414
        value += "|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER"
415
        if not scope.parent_type.is_final_type:
416
            value += "|Py_TPFLAGS_BASETYPE"
417 418
        if scope.needs_gc():
            value += "|Py_TPFLAGS_HAVE_GC"
William Stein's avatar
William Stein committed
419
        return value
420

William Stein's avatar
William Stein committed
421 422 423

class DocStringSlot(SlotDescriptor):
    #  Descriptor for the docstring slot.
424

William Stein's avatar
William Stein committed
425
    def slot_code(self, scope):
426 427
        doc = scope.doc
        if doc is None:
William Stein's avatar
William Stein committed
428
            return "0"
429 430 431
        if doc.is_unicode:
            doc = doc.as_utf8_string()
        return doc.as_c_string_literal()
William Stein's avatar
William Stein committed
432 433 434 435 436 437


class SuiteSlot(SlotDescriptor):
    #  Descriptor for a substructure of the type object.
    #
    #  sub_slots   [SlotDescriptor]
438

439 440
    def __init__(self, sub_slots, slot_type, slot_name, ifdef=None):
        SlotDescriptor.__init__(self, slot_name, ifdef=ifdef)
William Stein's avatar
William Stein committed
441 442 443
        self.sub_slots = sub_slots
        self.slot_type = slot_type
        substructures.append(self)
444

445 446 447 448 449 450
    def is_empty(self, scope):
        for slot in self.sub_slots:
            if slot.slot_code(scope) != "0":
                return False
        return True

William Stein's avatar
William Stein committed
451 452
    def substructure_cname(self, scope):
        return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name)
453

William Stein's avatar
William Stein committed
454
    def slot_code(self, scope):
455 456 457
        if not self.is_empty(scope):
            return "&%s" % self.substructure_cname(scope)
        return "0"
458

William Stein's avatar
William Stein committed
459
    def generate_substructure(self, scope, code):
460 461
        if not self.is_empty(scope):
            code.putln("")
462 463
            if self.ifdef:
                code.putln("#if %s" % self.ifdef)
464 465 466 467 468 469 470
            code.putln(
                "static %s %s = {" % (
                    self.slot_type,
                    self.substructure_cname(scope)))
            for slot in self.sub_slots:
                slot.generate(scope, code)
            code.putln("};")
471 472
            if self.ifdef:
                code.putln("#endif")
William Stein's avatar
William Stein committed
473 474 475 476 477

substructures = []   # List of all SuiteSlot instances

class MethodTableSlot(SlotDescriptor):
    #  Slot descriptor for the method table.
478

William Stein's avatar
William Stein committed
479
    def slot_code(self, scope):
480
        if scope.pyfunc_entries:
481 482 483
            return scope.method_table_cname
        else:
            return "0"
William Stein's avatar
William Stein committed
484 485 486 487


class MemberTableSlot(SlotDescriptor):
    #  Slot descriptor for the table of Python-accessible attributes.
488

William Stein's avatar
William Stein committed
489
    def slot_code(self, scope):
490
        return "0"
William Stein's avatar
William Stein committed
491 492 493 494


class GetSetSlot(SlotDescriptor):
    #  Slot descriptor for the table of attribute get & set methods.
495

William Stein's avatar
William Stein committed
496
    def slot_code(self, scope):
497
        if scope.property_entries:
William Stein's avatar
William Stein committed
498 499 500 501 502 503 504 505 506 507
            return scope.getset_table_cname
        else:
            return "0"


class BaseClassSlot(SlotDescriptor):
    #  Slot descriptor for the base class slot.

    def __init__(self, name):
        SlotDescriptor.__init__(self, name, dynamic = 1)
508

William Stein's avatar
William Stein committed
509 510 511 512
    def generate_dynamic_init_code(self, scope, code):
        base_type = scope.parent_type.base_type
        if base_type:
            code.putln("%s.%s = %s;" % (
513
                scope.parent_type.typeobj_cname,
William Stein's avatar
William Stein committed
514 515 516
                self.slot_name,
                base_type.typeptr_cname))

517

518 519 520 521 522
class DictOffsetSlot(SlotDescriptor):
    #  Slot descriptor for a class' dict offset, for dynamic attributes.

    def slot_code(self, scope):
        dict_entry = scope.lookup_here("__dict__")
523 524
        if dict_entry and dict_entry.is_variable:
            if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type':
525 526 527 528 529 530 531 532 533 534 535 536 537 538
                error(dict_entry.pos, "__dict__ slot must be of type 'dict'")
                return "0"
            type = scope.parent_type
            if type.typedef_flag:
                objstruct = type.objstruct_cname
            else:
                objstruct = "struct %s" % type.objstruct_cname
            return ("offsetof(%s, %s)" % (
                        objstruct,
                        dict_entry.cname))
        else:
            return "0"


William Stein's avatar
William Stein committed
539 540 541 542 543 544 545 546
# The following dictionary maps __xxx__ method names to slot descriptors.

method_name_to_slot = {}

## The following slots are (or could be) initialised with an
## extern function pointer.
#
#slots_initialised_from_extern = (
Robert Bradshaw's avatar
Robert Bradshaw committed
547
#    "tp_free",
William Stein's avatar
William Stein committed
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
#)

#------------------------------------------------------------------------------------------
#
#  Utility functions for accessing slot table data structures
#
#------------------------------------------------------------------------------------------

def get_special_method_signature(name):
    #  Given a method name, if it is a special method,
    #  return its signature, else return None.
    slot = method_name_to_slot.get(name)
    if slot:
        return slot.signature
    else:
        return None

565

William Stein's avatar
William Stein committed
566 567 568 569
def get_property_accessor_signature(name):
    #  Return signature of accessor for an extension type
    #  property, else None.
    return property_accessor_signatures.get(name)
570

571

Robert Bradshaw's avatar
Robert Bradshaw committed
572
def get_base_slot_function(scope, slot):
573
    #  Returns the function implementing this slot in the baseclass.
Robert Bradshaw's avatar
Robert Bradshaw committed
574
    #  This is useful for enabling the compiler to optimize calls
575
    #  that recursively climb the class hierarchy.
Robert Bradshaw's avatar
Robert Bradshaw committed
576 577 578 579 580 581 582 583
    base_type = scope.parent_type.base_type
    if scope.parent_scope is base_type.scope.parent_scope:
        parent_slot = slot.slot_code(base_type.scope)
        if parent_slot != '0':
            entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name)
            if entry.visibility != 'extern':
                return parent_slot
    return None
William Stein's avatar
William Stein committed
584

585 586 587 588 589 590 591 592 593 594 595 596

def get_slot_function(scope, slot):
    #  Returns the function implementing this slot in the baseclass.
    #  This is useful for enabling the compiler to optimize calls
    #  that recursively climb the class hierarchy.
    slot_code = slot.slot_code(scope)
    if slot_code != '0':
        entry = scope.parent_scope.lookup_here(scope.parent_type.name)
        if entry.visibility != 'extern':
            return slot_code
    return None

William Stein's avatar
William Stein committed
597 598 599 600 601 602 603 604 605 606
#------------------------------------------------------------------------------------------
#
#  Signatures for generic Python functions and methods.
#
#------------------------------------------------------------------------------------------

pyfunction_signature = Signature("-*", "O")
pymethod_signature = Signature("T*", "O")

#------------------------------------------------------------------------------------------
607 608 609 610 611 612 613 614 615
#
#  Signatures for simple Python functions.
#
#------------------------------------------------------------------------------------------

pyfunction_noargs = Signature("-", "O")
pyfunction_onearg = Signature("-O", "O")

#------------------------------------------------------------------------------------------
William Stein's avatar
William Stein committed
616 617 618 619 620 621 622 623 624 625 626 627 628
#
#  Signatures for the various kinds of function that
#  can appear in the type object and its substructures.
#
#------------------------------------------------------------------------------------------

unaryfunc = Signature("T", "O")            # typedef PyObject * (*unaryfunc)(PyObject *);
binaryfunc = Signature("OO", "O")          # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ibinaryfunc = Signature("TO", "O")         # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *);
ternaryfunc = Signature("OOO", "O")        # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
iternaryfunc = Signature("TOO", "O")       # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
callfunc = Signature("T*", "O")            # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
inquiry = Signature("T", "i")              # typedef int (*inquiry)(PyObject *);
629
lenfunc = Signature("T", "z")              # typedef Py_ssize_t (*lenfunc)(PyObject *);
630

William Stein's avatar
William Stein committed
631 632
                                           # typedef int (*coercion)(PyObject **, PyObject **);
intargfunc = Signature("Ti", "O")          # typedef PyObject *(*intargfunc)(PyObject *, int);
633
ssizeargfunc = Signature("Tz", "O")        # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
William Stein's avatar
William Stein committed
634
intintargfunc = Signature("Tii", "O")      # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
635
ssizessizeargfunc = Signature("Tzz", "O")  # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
William Stein's avatar
William Stein committed
636
intobjargproc = Signature("TiO", 'r')      # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
637
ssizeobjargproc = Signature("TzO", 'r')    # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
William Stein's avatar
William Stein committed
638
intintobjargproc = Signature("TiiO", 'r')  # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
639
ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
640

William Stein's avatar
William Stein committed
641
intintargproc = Signature("Tii", 'r')
642
ssizessizeargproc = Signature("Tzz", 'r')
William Stein's avatar
William Stein committed
643 644
objargfunc = Signature("TO", "O")
objobjargproc = Signature("TOO", 'r')      # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
645 646 647 648
readbufferproc = Signature("TzP", "z")     # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
writebufferproc = Signature("TzP", "z")    # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
segcountproc = Signature("TZ", "z")        # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
charbufferproc = Signature("TzS", "z")     # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
William Stein's avatar
William Stein committed
649 650 651 652 653 654 655 656 657 658 659 660 661
objargproc = Signature("TO", 'r')          # typedef int (*objobjproc)(PyObject *, PyObject *);
                                           # typedef int (*visitproc)(PyObject *, void *);
                                           # typedef int (*traverseproc)(PyObject *, visitproc, void *);

destructor = Signature("T", "v")           # typedef void (*destructor)(PyObject *);
# printfunc = Signature("TFi", 'r')        # typedef int (*printfunc)(PyObject *, FILE *, int);
                                           # typedef PyObject *(*getattrfunc)(PyObject *, char *);
getattrofunc = Signature("TO", "O")        # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
                                           # typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
setattrofunc = Signature("TOO", 'r')       # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *);
delattrofunc = Signature("TO", 'r')
cmpfunc = Signature("TO", "i")             # typedef int (*cmpfunc)(PyObject *, PyObject *);
reprfunc = Signature("T", "O")             # typedef PyObject *(*reprfunc)(PyObject *);
662
hashfunc = Signature("T", "h")             # typedef Py_hash_t (*hashfunc)(PyObject *);
William Stein's avatar
William Stein committed
663 664 665 666 667 668 669 670 671 672 673
                                           # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
richcmpfunc = Signature("OOi", "O")        # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int);
getiterfunc = Signature("T", "O")          # typedef PyObject *(*getiterfunc) (PyObject *);
iternextfunc = Signature("T", "O")         # typedef PyObject *(*iternextfunc) (PyObject *);
descrgetfunc = Signature("TOO", "O")       # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *);
descrsetfunc = Signature("TOO", 'r')       # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *);
descrdelfunc = Signature("TO", 'r')
initproc = Signature("T*", 'r')            # typedef int (*initproc)(PyObject *, PyObject *, PyObject *);
                                           # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
                                           # typedef PyObject *(*allocfunc)(struct _typeobject *, int);

674 675 676 677
getbufferproc = Signature("TBi", "r")      # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int);
releasebufferproc = Signature("TB", "v")   # typedef void (*releasebufferproc)(PyObject *, Py_buffer *);


William Stein's avatar
William Stein committed
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
#------------------------------------------------------------------------------------------
#
#  Signatures for accessor methods of properties.
#
#------------------------------------------------------------------------------------------

property_accessor_signatures = {
    '__get__': Signature("T", "O"),
    '__set__': Signature("TO", 'r'),
    '__del__': Signature("T", 'r')
}

#------------------------------------------------------------------------------------------
#
#  Descriptor tables for the slots of the various type object
#  substructures, in the order they appear in the structure.
#
#------------------------------------------------------------------------------------------

697 698
PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || CYTHON_COMPILING_IN_PYPY"

William Stein's avatar
William Stein committed
699 700 701 702
PyNumberMethods = (
    MethodSlot(binaryfunc, "nb_add", "__add__"),
    MethodSlot(binaryfunc, "nb_subtract", "__sub__"),
    MethodSlot(binaryfunc, "nb_multiply", "__mul__"),
703
    MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD),
William Stein's avatar
William Stein committed
704 705 706 707 708 709
    MethodSlot(binaryfunc, "nb_remainder", "__mod__"),
    MethodSlot(binaryfunc, "nb_divmod", "__divmod__"),
    MethodSlot(ternaryfunc, "nb_power", "__pow__"),
    MethodSlot(unaryfunc, "nb_negative", "__neg__"),
    MethodSlot(unaryfunc, "nb_positive", "__pos__"),
    MethodSlot(unaryfunc, "nb_absolute", "__abs__"),
710
    MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")),
William Stein's avatar
William Stein committed
711 712 713 714 715 716
    MethodSlot(unaryfunc, "nb_invert", "__invert__"),
    MethodSlot(binaryfunc, "nb_lshift", "__lshift__"),
    MethodSlot(binaryfunc, "nb_rshift", "__rshift__"),
    MethodSlot(binaryfunc, "nb_and", "__and__"),
    MethodSlot(binaryfunc, "nb_xor", "__xor__"),
    MethodSlot(binaryfunc, "nb_or", "__or__"),
717
    EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD),
718 719
    MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"),
    MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = "<RESERVED>"),
William Stein's avatar
William Stein committed
720
    MethodSlot(unaryfunc, "nb_float", "__float__"),
721 722
    MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD),
    MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD),
723

William Stein's avatar
William Stein committed
724 725 726 727
    # Added in release 2.0
    MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"),
    MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"),
    MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"),
728
    MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD),
William Stein's avatar
William Stein committed
729
    MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"),
Lisandro Dalcin's avatar
Lisandro Dalcin committed
730
    MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!!
William Stein's avatar
William Stein committed
731 732 733 734 735
    MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"),
    MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"),
    MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"),
    MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"),
    MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"),
736

William Stein's avatar
William Stein committed
737 738 739 740 741 742
    # Added in release 2.2
    # The following require the Py_TPFLAGS_HAVE_CLASS flag
    MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"),
    MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
    MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
    MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
743 744

    # Added in release 2.5
745 746 747 748 749
    MethodSlot(unaryfunc, "nb_index", "__index__"),

    # Added in release 3.5
    MethodSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"),
    MethodSlot(ibinaryfunc, "nb_inplace_matrix_multiply", "__imatmul__", ifdef="PY_VERSION_HEX >= 0x03050000"),
William Stein's avatar
William Stein committed
750 751 752
)

PySequenceMethods = (
753
    MethodSlot(lenfunc, "sq_length", "__len__"),
William Stein's avatar
William Stein committed
754 755 756
    EmptySlot("sq_concat"), # nb_add used instead
    EmptySlot("sq_repeat"), # nb_multiply used instead
    SyntheticSlot("sq_item", ["__getitem__"], "0"),    #EmptySlot("sq_item"),   # mp_subscript used instead
757
    MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"),
William Stein's avatar
William Stein committed
758
    EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
Stefan Behnel's avatar
Stefan Behnel committed
759
    SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
William Stein's avatar
William Stein committed
760 761 762 763 764 765
    MethodSlot(cmpfunc, "sq_contains", "__contains__"),
    EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead
    EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead
)

PyMappingMethods = (
766
    MethodSlot(lenfunc, "mp_length", "__len__"),
William Stein's avatar
William Stein committed
767 768 769 770 771
    MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
    SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
)

PyBufferProcs = (
772 773 774 775
    MethodSlot(readbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False),
    MethodSlot(writebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False),
    MethodSlot(segcountproc, "bf_getsegcount", "__getsegcount__", py3 = False),
    MethodSlot(charbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False),
776

777 778
    MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__"),
    MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__")
William Stein's avatar
William Stein committed
779 780
)

781 782 783 784 785 786
PyAsyncMethods = (
    MethodSlot(unaryfunc, "am_await", "__await__"),
    MethodSlot(unaryfunc, "am_aiter", "__aiter__"),
    MethodSlot(unaryfunc, "am_anext", "__anext__"),
)

William Stein's avatar
William Stein committed
787 788 789 790 791 792 793 794 795
#------------------------------------------------------------------------------------------
#
#  The main slot table. This table contains descriptors for all the
#  top-level type slots, beginning with tp_dealloc, in the order they
#  appear in the type object.
#
#------------------------------------------------------------------------------------------

slot_table = (
796
    ConstructorSlot("tp_dealloc", '__dealloc__'),
William Stein's avatar
William Stein committed
797 798 799
    EmptySlot("tp_print"), #MethodSlot(printfunc, "tp_print", "__print__"),
    EmptySlot("tp_getattr"),
    EmptySlot("tp_setattr"),
800 801 802 803 804

    # tp_compare (Py2) / tp_reserved (Py3<3.5) / tp_as_async (Py3.5+) is always used as tp_as_async in Py3
    MethodSlot(cmpfunc, "tp_compare", "__cmp__", ifdef="PY_MAJOR_VERSION < 3"),
    SuiteSlot(PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async", ifdef="PY_MAJOR_VERSION >= 3"),

William Stein's avatar
William Stein committed
805
    MethodSlot(reprfunc, "tp_repr", "__repr__"),
806

William Stein's avatar
William Stein committed
807 808 809 810
    SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"),
    SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"),
    SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"),

811
    MethodSlot(hashfunc, "tp_hash", "__hash__", inherited=False),    # Py3 checks for __richcmp__
William Stein's avatar
William Stein committed
812 813
    MethodSlot(callfunc, "tp_call", "__call__"),
    MethodSlot(reprfunc, "tp_str", "__str__"),
814

815
    SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"),
William Stein's avatar
William Stein committed
816 817 818
    SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),

    SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
819

William Stein's avatar
William Stein committed
820 821 822
    TypeFlagsSlot("tp_flags"),
    DocStringSlot("tp_doc"),

823
    GCDependentSlot("tp_traverse"),
824
    GCClearReferencesSlot("tp_clear"),
William Stein's avatar
William Stein committed
825 826

    # Later -- synthesize a method to split into separate ops?
827
    MethodSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False),  # Py3 checks for __hash__
William Stein's avatar
William Stein committed
828 829 830 831 832 833 834 835 836

    EmptySlot("tp_weaklistoffset"),

    MethodSlot(getiterfunc, "tp_iter", "__iter__"),
    MethodSlot(iternextfunc, "tp_iternext", "__next__"),

    MethodTableSlot("tp_methods"),
    MemberTableSlot("tp_members"),
    GetSetSlot("tp_getset"),
837

William Stein's avatar
William Stein committed
838 839
    BaseClassSlot("tp_base"), #EmptySlot("tp_base"),
    EmptySlot("tp_dict"),
840

William Stein's avatar
William Stein committed
841 842
    SyntheticSlot("tp_descr_get", ["__get__"], "0"),
    SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"),
843

844
    DictOffsetSlot("tp_dictoffset"),
845

William Stein's avatar
William Stein committed
846 847
    MethodSlot(initproc, "tp_init", "__init__"),
    EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"),
848
    InternalMethodSlot("tp_new"),
849
    EmptySlot("tp_free"),
850

William Stein's avatar
William Stein committed
851 852 853 854 855 856
    EmptySlot("tp_is_gc"),
    EmptySlot("tp_bases"),
    EmptySlot("tp_mro"),
    EmptySlot("tp_cache"),
    EmptySlot("tp_subclasses"),
    EmptySlot("tp_weaklist"),
857
    EmptySlot("tp_del"),
858
    EmptySlot("tp_version_tag"),
859
    EmptySlot("tp_finalize", ifdef="PY_VERSION_HEX >= 0x030400a1"),
William Stein's avatar
William Stein committed
860 861 862 863 864 865
)

#------------------------------------------------------------------------------------------
#
#  Descriptors for special methods which don't appear directly
#  in the type object or its substructures. These methods are
William Stein's avatar
William Stein committed
866
#  called from slot functions synthesized by Cython.
William Stein's avatar
William Stein committed
867 868 869
#
#------------------------------------------------------------------------------------------

870
MethodSlot(initproc, "", "__cinit__")
William Stein's avatar
William Stein committed
871 872 873
MethodSlot(destructor, "", "__dealloc__")
MethodSlot(objobjargproc, "", "__setitem__")
MethodSlot(objargproc, "", "__delitem__")
874 875
MethodSlot(ssizessizeobjargproc, "", "__setslice__")
MethodSlot(ssizessizeargproc, "", "__delslice__")
William Stein's avatar
William Stein committed
876 877 878 879 880 881
MethodSlot(getattrofunc, "", "__getattr__")
MethodSlot(setattrofunc, "", "__setattr__")
MethodSlot(delattrofunc, "", "__delattr__")
MethodSlot(descrgetfunc, "", "__get__")
MethodSlot(descrsetfunc, "", "__set__")
MethodSlot(descrdelfunc, "", "__delete__")
882 883


884
# Method flags for python-exposed methods.
885 886 887 888 889 890

method_noargs   = "METH_NOARGS"
method_onearg   = "METH_O"
method_varargs  = "METH_VARARGS"
method_keywords = "METH_KEYWORDS"
method_coexist  = "METH_COEXIST"