1#
2#   Builtin Definitions
3#
4
5from __future__ import absolute_import
6
7from .Symtab import BuiltinScope, StructOrUnionScope
8from .Code import UtilityCode
9from .TypeSlots import Signature
10from . import PyrexTypes
11from . import Options
12
13
14# C-level implementations of builtin types, functions and methods
15
16iter_next_utility_code = UtilityCode.load("IterNext", "ObjectHandling.c")
17getattr_utility_code = UtilityCode.load("GetAttr", "ObjectHandling.c")
18getattr3_utility_code = UtilityCode.load("GetAttr3", "Builtins.c")
19pyexec_utility_code = UtilityCode.load("PyExec", "Builtins.c")
20pyexec_globals_utility_code = UtilityCode.load("PyExecGlobals", "Builtins.c")
21globals_utility_code = UtilityCode.load("Globals", "Builtins.c")
22
23builtin_utility_code = {
24    'StopAsyncIteration': UtilityCode.load_cached("StopAsyncIteration", "Coroutine.c"),
25}
26
27
28# mapping from builtins to their C-level equivalents
29
30class _BuiltinOverride(object):
31    def __init__(self, py_name, args, ret_type, cname, py_equiv="*",
32                 utility_code=None, sig=None, func_type=None,
33                 is_strict_signature=False, builtin_return_type=None,
34                 nogil=None):
35        self.py_name, self.cname, self.py_equiv = py_name, cname, py_equiv
36        self.args, self.ret_type = args, ret_type
37        self.func_type, self.sig = func_type, sig
38        self.builtin_return_type = builtin_return_type
39        self.is_strict_signature = is_strict_signature
40        self.utility_code = utility_code
41        self.nogil = nogil
42
43    def build_func_type(self, sig=None, self_arg=None):
44        if sig is None:
45            sig = Signature(self.args, self.ret_type, nogil=self.nogil)
46            sig.exception_check = False  # not needed for the current builtins
47        func_type = sig.function_type(self_arg)
48        if self.is_strict_signature:
49            func_type.is_strict_signature = True
50        if self.builtin_return_type:
51            func_type.return_type = builtin_types[self.builtin_return_type]
52        return func_type
53
54
55class BuiltinAttribute(object):
56    def __init__(self, py_name, cname=None, field_type=None, field_type_name=None):
57        self.py_name = py_name
58        self.cname = cname or py_name
59        self.field_type_name = field_type_name  # can't do the lookup before the type is declared!
60        self.field_type = field_type
61
62    def declare_in_type(self, self_type):
63        if self.field_type_name is not None:
64            # lazy type lookup
65            field_type = builtin_scope.lookup(self.field_type_name).type
66        else:
67            field_type = self.field_type or PyrexTypes.py_object_type
68        entry = self_type.scope.declare(self.py_name, self.cname, field_type, None, 'private')
69        entry.is_variable = True
70
71
72class BuiltinFunction(_BuiltinOverride):
73    def declare_in_scope(self, scope):
74        func_type, sig = self.func_type, self.sig
75        if func_type is None:
76            func_type = self.build_func_type(sig)
77        scope.declare_builtin_cfunction(self.py_name, func_type, self.cname,
78                                        self.py_equiv, self.utility_code)
79
80
81class BuiltinMethod(_BuiltinOverride):
82    def declare_in_type(self, self_type):
83        method_type, sig = self.func_type, self.sig
84        if method_type is None:
85            # override 'self' type (first argument)
86            self_arg = PyrexTypes.CFuncTypeArg("", self_type, None)
87            self_arg.not_none = True
88            self_arg.accept_builtin_subtypes = True
89            method_type = self.build_func_type(sig, self_arg)
90        self_type.scope.declare_builtin_cfunction(
91            self.py_name, method_type, self.cname, utility_code=self.utility_code)
92
93
94builtin_function_table = [
95    # name,        args,   return,  C API func,           py equiv = "*"
96    BuiltinFunction('abs',        "d",    "d",     "fabs",
97                    is_strict_signature=True, nogil=True),
98    BuiltinFunction('abs',        "f",    "f",     "fabsf",
99                    is_strict_signature=True, nogil=True),
100    BuiltinFunction('abs',        "i",    "i",     "abs",
101                    is_strict_signature=True, nogil=True),
102    BuiltinFunction('abs',        "l",    "l",     "labs",
103                    is_strict_signature=True, nogil=True),
104    BuiltinFunction('abs',        None,    None,   "__Pyx_abs_longlong",
105                utility_code = UtilityCode.load("abs_longlong", "Builtins.c"),
106                func_type = PyrexTypes.CFuncType(
107                    PyrexTypes.c_longlong_type, [
108                        PyrexTypes.CFuncTypeArg("arg", PyrexTypes.c_longlong_type, None)
109                        ],
110                    is_strict_signature = True, nogil=True)),
111    ] + list(
112        BuiltinFunction('abs',        None,    None,   "/*abs_{0}*/".format(t.specialization_name()),
113                    func_type = PyrexTypes.CFuncType(
114                        t,
115                        [PyrexTypes.CFuncTypeArg("arg", t, None)],
116                        is_strict_signature = True, nogil=True))
117                            for t in (PyrexTypes.c_uint_type, PyrexTypes.c_ulong_type, PyrexTypes.c_ulonglong_type)
118             ) + list(
119        BuiltinFunction('abs',        None,    None,   "__Pyx_c_abs{0}".format(t.funcsuffix),
120                    func_type = PyrexTypes.CFuncType(
121                        t.real_type, [
122                            PyrexTypes.CFuncTypeArg("arg", t, None)
123                            ],
124                            is_strict_signature = True, nogil=True))
125                        for t in (PyrexTypes.c_float_complex_type,
126                                  PyrexTypes.c_double_complex_type,
127                                  PyrexTypes.c_longdouble_complex_type)
128                        ) + [
129    BuiltinFunction('abs',        "O",    "O",     "__Pyx_PyNumber_Absolute",
130                    utility_code=UtilityCode.load("py_abs", "Builtins.c")),
131    #('all',       "",     "",      ""),
132    #('any',       "",     "",      ""),
133    #('ascii',     "",     "",      ""),
134    #('bin',       "",     "",      ""),
135    BuiltinFunction('callable',   "O",    "b",     "__Pyx_PyCallable_Check",
136                    utility_code = UtilityCode.load("CallableCheck", "ObjectHandling.c")),
137    #('chr',       "",     "",      ""),
138    #('cmp', "",   "",     "",      ""), # int PyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
139    #('compile',   "",     "",      ""), # PyObject* Py_CompileString(    char *str, char *filename, int start)
140    BuiltinFunction('delattr',    "OO",   "r",     "PyObject_DelAttr"),
141    BuiltinFunction('dir',        "O",    "O",     "PyObject_Dir"),
142    BuiltinFunction('divmod',     "OO",   "O",     "PyNumber_Divmod"),
143    BuiltinFunction('exec',       "O",    "O",     "__Pyx_PyExecGlobals",
144                    utility_code = pyexec_globals_utility_code),
145    BuiltinFunction('exec',       "OO",   "O",     "__Pyx_PyExec2",
146                    utility_code = pyexec_utility_code),
147    BuiltinFunction('exec',       "OOO",  "O",     "__Pyx_PyExec3",
148                    utility_code = pyexec_utility_code),
149    #('eval',      "",     "",      ""),
150    #('execfile',  "",     "",      ""),
151    #('filter',    "",     "",      ""),
152    BuiltinFunction('getattr3',   "OOO",  "O",     "__Pyx_GetAttr3",     "getattr",
153                    utility_code=getattr3_utility_code),  # Pyrex legacy
154    BuiltinFunction('getattr',    "OOO",  "O",     "__Pyx_GetAttr3",
155                    utility_code=getattr3_utility_code),
156    BuiltinFunction('getattr',    "OO",   "O",     "__Pyx_GetAttr",
157                    utility_code=getattr_utility_code),
158    BuiltinFunction('hasattr',    "OO",   "b",     "__Pyx_HasAttr",
159                    utility_code = UtilityCode.load("HasAttr", "Builtins.c")),
160    BuiltinFunction('hash',       "O",    "h",     "PyObject_Hash"),
161    #('hex',       "",     "",      ""),
162    #('id',        "",     "",      ""),
163    #('input',     "",     "",      ""),
164    BuiltinFunction('intern',     "O",    "O",     "__Pyx_Intern",
165                    utility_code = UtilityCode.load("Intern", "Builtins.c")),
166    BuiltinFunction('isinstance', "OO",   "b",     "PyObject_IsInstance"),
167    BuiltinFunction('issubclass', "OO",   "b",     "PyObject_IsSubclass"),
168    BuiltinFunction('iter',       "OO",   "O",     "PyCallIter_New"),
169    BuiltinFunction('iter',       "O",    "O",     "PyObject_GetIter"),
170    BuiltinFunction('len',        "O",    "z",     "PyObject_Length"),
171    BuiltinFunction('locals',     "",     "O",     "__pyx_locals"),
172    #('map',       "",     "",      ""),
173    #('max',       "",     "",      ""),
174    #('min',       "",     "",      ""),
175    BuiltinFunction('next',       "O",    "O",     "__Pyx_PyIter_Next",
176                    utility_code = iter_next_utility_code),   # not available in Py2 => implemented here
177    BuiltinFunction('next',      "OO",    "O",     "__Pyx_PyIter_Next2",
178                    utility_code = iter_next_utility_code),  # not available in Py2 => implemented here
179    #('oct',       "",     "",      ""),
180    #('open',       "ss",   "O",     "PyFile_FromString"),   # not in Py3
181] + [
182    BuiltinFunction('ord',        None,    None,   "__Pyx_long_cast",
183                    func_type=PyrexTypes.CFuncType(
184                        PyrexTypes.c_long_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)],
185                        is_strict_signature=True))
186    for c_type in [PyrexTypes.c_py_ucs4_type, PyrexTypes.c_py_unicode_type]
187] + [
188    BuiltinFunction('ord',        None,    None,   "__Pyx_uchar_cast",
189                    func_type=PyrexTypes.CFuncType(
190                        PyrexTypes.c_uchar_type, [PyrexTypes.CFuncTypeArg("c", c_type, None)],
191                        is_strict_signature=True))
192    for c_type in [PyrexTypes.c_char_type, PyrexTypes.c_schar_type, PyrexTypes.c_uchar_type]
193] + [
194    BuiltinFunction('ord',        None,    None,   "__Pyx_PyObject_Ord",
195                    utility_code=UtilityCode.load_cached("object_ord", "Builtins.c"),
196                    func_type=PyrexTypes.CFuncType(
197                        PyrexTypes.c_long_type, [
198                            PyrexTypes.CFuncTypeArg("c", PyrexTypes.py_object_type, None)
199                        ],
200                        exception_value="(long)(Py_UCS4)-1")),
201    BuiltinFunction('pow',        "OOO",  "O",     "PyNumber_Power"),
202    BuiltinFunction('pow',        "OO",   "O",     "__Pyx_PyNumber_Power2",
203                    utility_code = UtilityCode.load("pow2", "Builtins.c")),
204    #('range',     "",     "",      ""),
205    #('raw_input', "",     "",      ""),
206    #('reduce',    "",     "",      ""),
207    BuiltinFunction('reload',     "O",    "O",     "PyImport_ReloadModule"),
208    BuiltinFunction('repr',       "O",    "O",     "PyObject_Repr"),  # , builtin_return_type='str'),  # add in Cython 3.1
209    #('round',     "",     "",      ""),
210    BuiltinFunction('setattr',    "OOO",  "r",     "PyObject_SetAttr"),
211    #('sum',       "",     "",      ""),
212    #('sorted',    "",     "",      ""),
213    #('type',       "O",    "O",     "PyObject_Type"),
214    BuiltinFunction('unichr',     "l",    "O",      "PyUnicode_FromOrdinal", builtin_return_type='unicode'),
215    #('unicode',   "",     "",      ""),
216    #('vars',      "",     "",      ""),
217    #('zip',       "",     "",      ""),
218    #  Can't do these easily until we have builtin type entries.
219    #('typecheck',  "OO",   "i",     "PyObject_TypeCheck", False),
220    #('issubtype',  "OO",   "i",     "PyType_IsSubtype",   False),
221
222    # Put in namespace append optimization.
223    BuiltinFunction('__Pyx_PyObject_Append', "OO",  "O",     "__Pyx_PyObject_Append"),
224
225    # This is conditionally looked up based on a compiler directive.
226    BuiltinFunction('__Pyx_Globals',    "",     "O",     "__Pyx_Globals",
227                    utility_code=globals_utility_code),
228]
229
230
231# Builtin types
232#  bool
233#  buffer
234#  classmethod
235#  dict
236#  enumerate
237#  file
238#  float
239#  int
240#  list
241#  long
242#  object
243#  property
244#  slice
245#  staticmethod
246#  super
247#  str
248#  tuple
249#  type
250#  xrange
251
252builtin_types_table = [
253
254    ("type",    "PyType_Type",     []),
255
256# This conflicts with the C++ bool type, and unfortunately
257# C++ is too liberal about PyObject* <-> bool conversions,
258# resulting in unintuitive runtime behavior and segfaults.
259#    ("bool",    "PyBool_Type",     []),
260
261    ("int",     "PyInt_Type",      []),
262    ("long",    "PyLong_Type",     []),
263    ("float",   "PyFloat_Type",    []),
264
265    ("complex", "PyComplex_Type",  [BuiltinAttribute('cval', field_type_name = 'Py_complex'),
266                                    BuiltinAttribute('real', 'cval.real', field_type = PyrexTypes.c_double_type),
267                                    BuiltinAttribute('imag', 'cval.imag', field_type = PyrexTypes.c_double_type),
268                                    ]),
269
270    ("basestring", "PyBaseString_Type", [
271                                    BuiltinMethod("join",  "TO",   "T", "__Pyx_PyBaseString_Join",
272                                                  utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
273                                    ]),
274    ("bytearray", "PyByteArray_Type", [
275                                    ]),
276    ("bytes",   "PyBytes_Type",    [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
277                                    BuiltinMethod("join",  "TO",   "O", "__Pyx_PyBytes_Join",
278                                                  utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
279                                    ]),
280    ("str",     "PyString_Type",   [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
281                                    BuiltinMethod("join",  "TO",   "O", "__Pyx_PyString_Join",
282                                                  builtin_return_type='basestring',
283                                                  utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
284                                    ]),
285    ("unicode", "PyUnicode_Type",  [BuiltinMethod("__contains__",  "TO",   "b", "PyUnicode_Contains"),
286                                    BuiltinMethod("join",  "TO",   "T", "PyUnicode_Join"),
287                                    ]),
288
289    ("tuple",   "PyTuple_Type",    [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
290                                    ]),
291
292    ("list",    "PyList_Type",     [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
293                                    BuiltinMethod("insert",  "TzO",  "r", "PyList_Insert"),
294                                    BuiltinMethod("reverse", "T",    "r", "PyList_Reverse"),
295                                    BuiltinMethod("append",  "TO",   "r", "__Pyx_PyList_Append",
296                                                  utility_code=UtilityCode.load("ListAppend", "Optimize.c")),
297                                    BuiltinMethod("extend",  "TO",   "r", "__Pyx_PyList_Extend",
298                                                  utility_code=UtilityCode.load("ListExtend", "Optimize.c")),
299                                    ]),
300
301    ("dict",    "PyDict_Type",     [BuiltinMethod("__contains__",  "TO",   "b", "PyDict_Contains"),
302                                    BuiltinMethod("has_key",       "TO",   "b", "PyDict_Contains"),
303                                    BuiltinMethod("items",  "T",   "O", "__Pyx_PyDict_Items",
304                                                  utility_code=UtilityCode.load("py_dict_items", "Builtins.c")),
305                                    BuiltinMethod("keys",   "T",   "O", "__Pyx_PyDict_Keys",
306                                                  utility_code=UtilityCode.load("py_dict_keys", "Builtins.c")),
307                                    BuiltinMethod("values", "T",   "O", "__Pyx_PyDict_Values",
308                                                  utility_code=UtilityCode.load("py_dict_values", "Builtins.c")),
309                                    BuiltinMethod("iteritems",  "T",   "O", "__Pyx_PyDict_IterItems",
310                                                  utility_code=UtilityCode.load("py_dict_iteritems", "Builtins.c")),
311                                    BuiltinMethod("iterkeys",   "T",   "O", "__Pyx_PyDict_IterKeys",
312                                                  utility_code=UtilityCode.load("py_dict_iterkeys", "Builtins.c")),
313                                    BuiltinMethod("itervalues", "T",   "O", "__Pyx_PyDict_IterValues",
314                                                  utility_code=UtilityCode.load("py_dict_itervalues", "Builtins.c")),
315                                    BuiltinMethod("viewitems",  "T",   "O", "__Pyx_PyDict_ViewItems",
316                                                  utility_code=UtilityCode.load("py_dict_viewitems", "Builtins.c")),
317                                    BuiltinMethod("viewkeys",   "T",   "O", "__Pyx_PyDict_ViewKeys",
318                                                  utility_code=UtilityCode.load("py_dict_viewkeys", "Builtins.c")),
319                                    BuiltinMethod("viewvalues", "T",   "O", "__Pyx_PyDict_ViewValues",
320                                                  utility_code=UtilityCode.load("py_dict_viewvalues", "Builtins.c")),
321                                    BuiltinMethod("clear",  "T",   "r", "__Pyx_PyDict_Clear",
322                                                  utility_code=UtilityCode.load("py_dict_clear", "Optimize.c")),
323                                    BuiltinMethod("copy",   "T",   "T", "PyDict_Copy")]),
324
325    ("slice",   "PySlice_Type",    [BuiltinAttribute('start'),
326                                    BuiltinAttribute('stop'),
327                                    BuiltinAttribute('step'),
328                                    ]),
329#    ("file",    "PyFile_Type",     []),  # not in Py3
330
331    ("set",       "PySet_Type",    [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
332                                    BuiltinMethod("clear",   "T",  "r", "PySet_Clear"),
333                                    # discard() and remove() have a special treatment for unhashable values
334                                    BuiltinMethod("discard", "TO", "r", "__Pyx_PySet_Discard",
335                                                  utility_code=UtilityCode.load("py_set_discard", "Optimize.c")),
336                                    BuiltinMethod("remove",  "TO", "r", "__Pyx_PySet_Remove",
337                                                  utility_code=UtilityCode.load("py_set_remove", "Optimize.c")),
338                                    # update is actually variadic (see Github issue #1645)
339#                                    BuiltinMethod("update",     "TO", "r", "__Pyx_PySet_Update",
340#                                                  utility_code=UtilityCode.load_cached("PySet_Update", "Builtins.c")),
341                                    BuiltinMethod("add",     "TO", "r", "PySet_Add"),
342                                    BuiltinMethod("pop",     "T",  "O", "PySet_Pop")]),
343    ("frozenset", "PyFrozenSet_Type", []),
344    ("Exception", "((PyTypeObject*)PyExc_Exception)[0]", []),
345    ("StopAsyncIteration", "((PyTypeObject*)__Pyx_PyExc_StopAsyncIteration)[0]", []),
346]
347
348
349types_that_construct_their_instance = frozenset({
350    # some builtin types do not always return an instance of
351    # themselves - these do:
352    'type', 'bool', 'long', 'float', 'complex',
353    'bytes', 'unicode', 'bytearray',
354    'tuple', 'list', 'dict', 'set', 'frozenset',
355    # 'str',             # only in Py3.x
356    # 'file',            # only in Py2.x
357})
358
359
360builtin_structs_table = [
361    ('Py_buffer', 'Py_buffer',
362     [("buf",        PyrexTypes.c_void_ptr_type),
363      ("obj",        PyrexTypes.py_object_type),
364      ("len",        PyrexTypes.c_py_ssize_t_type),
365      ("itemsize",   PyrexTypes.c_py_ssize_t_type),
366      ("readonly",   PyrexTypes.c_bint_type),
367      ("ndim",       PyrexTypes.c_int_type),
368      ("format",     PyrexTypes.c_char_ptr_type),
369      ("shape",      PyrexTypes.c_py_ssize_t_ptr_type),
370      ("strides",    PyrexTypes.c_py_ssize_t_ptr_type),
371      ("suboffsets", PyrexTypes.c_py_ssize_t_ptr_type),
372      ("smalltable", PyrexTypes.CArrayType(PyrexTypes.c_py_ssize_t_type, 2)),
373      ("internal",   PyrexTypes.c_void_ptr_type),
374      ]),
375    ('Py_complex', 'Py_complex',
376     [('real', PyrexTypes.c_double_type),
377      ('imag', PyrexTypes.c_double_type),
378      ])
379]
380
381# set up builtin scope
382
383builtin_scope = BuiltinScope()
384
385def init_builtin_funcs():
386    for bf in builtin_function_table:
387        bf.declare_in_scope(builtin_scope)
388
389builtin_types = {}
390
391def init_builtin_types():
392    global builtin_types
393    for name, cname, methods in builtin_types_table:
394        utility = builtin_utility_code.get(name)
395        if name == 'frozenset':
396            objstruct_cname = 'PySetObject'
397        elif name == 'bytearray':
398            objstruct_cname = 'PyByteArrayObject'
399        elif name == 'bool':
400            objstruct_cname = None
401        elif name == 'Exception':
402            objstruct_cname = "PyBaseExceptionObject"
403        elif name == 'StopAsyncIteration':
404            objstruct_cname = "PyBaseExceptionObject"
405        else:
406            objstruct_cname = 'Py%sObject' % name.capitalize()
407        the_type = builtin_scope.declare_builtin_type(name, cname, utility, objstruct_cname)
408        builtin_types[name] = the_type
409        for method in methods:
410            method.declare_in_type(the_type)
411
412def init_builtin_structs():
413    for name, cname, attribute_types in builtin_structs_table:
414        scope = StructOrUnionScope(name)
415        for attribute_name, attribute_type in attribute_types:
416            scope.declare_var(attribute_name, attribute_type, None,
417                              attribute_name, allow_pyobject=True)
418        builtin_scope.declare_struct_or_union(
419            name, "struct", scope, 1, None, cname = cname)
420
421
422def init_builtins():
423    init_builtin_structs()
424    init_builtin_types()
425    init_builtin_funcs()
426
427    builtin_scope.declare_var(
428        '__debug__', PyrexTypes.c_const_type(PyrexTypes.c_bint_type),
429        pos=None, cname='(!Py_OptimizeFlag)', is_cdef=True)
430
431    global list_type, tuple_type, dict_type, set_type, frozenset_type
432    global bytes_type, str_type, unicode_type, basestring_type, slice_type
433    global float_type, long_type, bool_type, type_type, complex_type, bytearray_type
434    type_type  = builtin_scope.lookup('type').type
435    list_type  = builtin_scope.lookup('list').type
436    tuple_type = builtin_scope.lookup('tuple').type
437    dict_type  = builtin_scope.lookup('dict').type
438    set_type   = builtin_scope.lookup('set').type
439    frozenset_type = builtin_scope.lookup('frozenset').type
440    slice_type   = builtin_scope.lookup('slice').type
441    bytes_type = builtin_scope.lookup('bytes').type
442    str_type   = builtin_scope.lookup('str').type
443    unicode_type = builtin_scope.lookup('unicode').type
444    basestring_type = builtin_scope.lookup('basestring').type
445    bytearray_type = builtin_scope.lookup('bytearray').type
446    float_type = builtin_scope.lookup('float').type
447    long_type = builtin_scope.lookup('long').type
448    bool_type  = builtin_scope.lookup('bool').type
449    complex_type  = builtin_scope.lookup('complex').type
450
451
452init_builtins()
453