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