Builtin.py 22 KB

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