PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/objspace/descroperation.py

https://bitbucket.org/pypy/pypy/
Python | 874 lines | 699 code | 91 blank | 84 comment | 170 complexity | 2e46d9cdc344cfcc826886a738febf1e MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import operator
  2. from pypy.interpreter.error import OperationError, oefmt
  3. from pypy.interpreter.baseobjspace import ObjSpace
  4. from pypy.interpreter.function import Function, Method, FunctionWithFixedCode
  5. from pypy.interpreter.argument import Arguments
  6. from pypy.interpreter.typedef import default_identity_hash
  7. from rpython.tool.sourcetools import compile2, func_with_new_name
  8. from pypy.module.__builtin__.interp_classobj import W_InstanceObject
  9. from rpython.rlib.objectmodel import specialize
  10. from rpython.rlib import jit
  11. def object_getattribute(space):
  12. "Utility that returns the app-level descriptor object.__getattribute__."
  13. w_src, w_getattribute = space.lookup_in_type_where(space.w_object,
  14. '__getattribute__')
  15. return w_getattribute
  16. object_getattribute._annspecialcase_ = 'specialize:memo'
  17. def object_setattr(space):
  18. "Utility that returns the app-level descriptor object.__setattr__."
  19. w_src, w_setattr = space.lookup_in_type_where(space.w_object,
  20. '__setattr__')
  21. return w_setattr
  22. object_setattr._annspecialcase_ = 'specialize:memo'
  23. def object_delattr(space):
  24. "Utility that returns the app-level descriptor object.__delattr__."
  25. w_src, w_delattr = space.lookup_in_type_where(space.w_object,
  26. '__delattr__')
  27. return w_delattr
  28. object_delattr._annspecialcase_ = 'specialize:memo'
  29. def object_hash(space):
  30. "Utility that returns the app-level descriptor object.__hash__."
  31. w_src, w_hash = space.lookup_in_type_where(space.w_object,
  32. '__hash__')
  33. return w_hash
  34. object_hash._annspecialcase_ = 'specialize:memo'
  35. def type_eq(space):
  36. "Utility that returns the app-level descriptor type.__eq__."
  37. w_src, w_eq = space.lookup_in_type_where(space.w_type,
  38. '__eq__')
  39. return w_eq
  40. type_eq._annspecialcase_ = 'specialize:memo'
  41. def list_iter(space):
  42. "Utility that returns the app-level descriptor list.__iter__."
  43. w_src, w_iter = space.lookup_in_type_where(space.w_list,
  44. '__iter__')
  45. return w_iter
  46. list_iter._annspecialcase_ = 'specialize:memo'
  47. def tuple_iter(space):
  48. "Utility that returns the app-level descriptor tuple.__iter__."
  49. w_src, w_iter = space.lookup_in_type_where(space.w_tuple,
  50. '__iter__')
  51. return w_iter
  52. tuple_iter._annspecialcase_ = 'specialize:memo'
  53. def raiseattrerror(space, w_obj, name, w_descr=None):
  54. if w_descr is None:
  55. raise oefmt(space.w_AttributeError,
  56. "'%T' object has no attribute '%s'", w_obj, name)
  57. else:
  58. raise oefmt(space.w_AttributeError,
  59. "'%T' object attribute '%s' is read-only", w_obj, name)
  60. # Helpers for old-style and mix-style mixup
  61. def _same_class_w(space, w_obj1, w_obj2, w_typ1, w_typ2):
  62. if (space.is_oldstyle_instance(w_obj1) and
  63. space.is_oldstyle_instance(w_obj2)):
  64. assert isinstance(w_obj1, W_InstanceObject)
  65. assert isinstance(w_obj2, W_InstanceObject)
  66. return space.is_w(w_obj1.w_class, w_obj2.w_class)
  67. return space.is_w(w_typ1, w_typ2)
  68. class Object(object):
  69. def descr__getattribute__(space, w_obj, w_name):
  70. name = space.str_w(w_name)
  71. w_descr = space.lookup(w_obj, name)
  72. if w_descr is not None:
  73. if space.is_data_descr(w_descr):
  74. # Only override if __get__ is defined, too, for compatibility
  75. # with CPython.
  76. w_get = space.lookup(w_descr, "__get__")
  77. if w_get is not None:
  78. w_type = space.type(w_obj)
  79. return space.get_and_call_function(w_get, w_descr, w_obj,
  80. w_type)
  81. w_value = w_obj.getdictvalue(space, name)
  82. if w_value is not None:
  83. return w_value
  84. if w_descr is not None:
  85. return space.get(w_descr, w_obj)
  86. raiseattrerror(space, w_obj, name)
  87. def descr__setattr__(space, w_obj, w_name, w_value):
  88. name = space.str_w(w_name)
  89. w_descr = space.lookup(w_obj, name)
  90. if w_descr is not None:
  91. if space.is_data_descr(w_descr):
  92. space.set(w_descr, w_obj, w_value)
  93. return
  94. if w_obj.setdictvalue(space, name, w_value):
  95. return
  96. raiseattrerror(space, w_obj, name, w_descr)
  97. def descr__delattr__(space, w_obj, w_name):
  98. name = space.str_w(w_name)
  99. w_descr = space.lookup(w_obj, name)
  100. if w_descr is not None:
  101. if space.is_data_descr(w_descr):
  102. space.delete(w_descr, w_obj)
  103. return
  104. if w_obj.deldictvalue(space, name):
  105. return
  106. raiseattrerror(space, w_obj, name, w_descr)
  107. def descr__init__(space, w_obj, __args__):
  108. pass
  109. contains_jitdriver = jit.JitDriver(name='contains',
  110. greens=['w_type'], reds='auto')
  111. class DescrOperation(object):
  112. # This is meant to be a *mixin*.
  113. def is_data_descr(space, w_obj):
  114. return (space.lookup(w_obj, '__set__') is not None or
  115. space.lookup(w_obj, '__delete__') is not None)
  116. def get_and_call_args(space, w_descr, w_obj, args):
  117. # a special case for performance and to avoid infinite recursion
  118. if isinstance(w_descr, Function):
  119. return w_descr.call_obj_args(w_obj, args)
  120. else:
  121. w_impl = space.get(w_descr, w_obj)
  122. return space.call_args(w_impl, args)
  123. def get_and_call_function(space, w_descr, w_obj, *args_w):
  124. typ = type(w_descr)
  125. # a special case for performance and to avoid infinite recursion
  126. if typ is Function or typ is FunctionWithFixedCode:
  127. # isinstance(typ, Function) would not be correct here:
  128. # for a BuiltinFunction we must not use that shortcut, because a
  129. # builtin function binds differently than a normal function
  130. # see test_builtin_as_special_method_is_not_bound
  131. # in interpreter/test/test_function.py
  132. # the fastcall paths are purely for performance, but the resulting
  133. # increase of speed is huge
  134. return w_descr.funccall(w_obj, *args_w)
  135. else:
  136. args = Arguments(space, list(args_w))
  137. w_impl = space.get(w_descr, w_obj)
  138. return space.call_args(w_impl, args)
  139. def call_args(space, w_obj, args):
  140. # two special cases for performance
  141. if isinstance(w_obj, Function):
  142. return w_obj.call_args(args)
  143. if isinstance(w_obj, Method):
  144. return w_obj.call_args(args)
  145. w_descr = space.lookup(w_obj, '__call__')
  146. if w_descr is None:
  147. raise oefmt(space.w_TypeError,
  148. "'%T' object is not callable", w_obj)
  149. return space.get_and_call_args(w_descr, w_obj, args)
  150. def get(space, w_descr, w_obj, w_type=None):
  151. w_get = space.lookup(w_descr, '__get__')
  152. if w_get is None:
  153. return w_descr
  154. if w_type is None:
  155. w_type = space.type(w_obj)
  156. return space.get_and_call_function(w_get, w_descr, w_obj, w_type)
  157. def set(space, w_descr, w_obj, w_val):
  158. w_set = space.lookup(w_descr, '__set__')
  159. if w_set is None:
  160. raise oefmt(space.w_AttributeError,
  161. "'%T' object is not a descriptor with set", w_descr)
  162. return space.get_and_call_function(w_set, w_descr, w_obj, w_val)
  163. def delete(space, w_descr, w_obj):
  164. w_delete = space.lookup(w_descr, '__delete__')
  165. if w_delete is None:
  166. raise oefmt(space.w_AttributeError,
  167. "'%T' object is not a descriptor with delete", w_descr)
  168. return space.get_and_call_function(w_delete, w_descr, w_obj)
  169. def getattr(space, w_obj, w_name):
  170. # may be overridden in StdObjSpace
  171. w_descr = space.lookup(w_obj, '__getattribute__')
  172. return space._handle_getattribute(w_descr, w_obj, w_name)
  173. def _handle_getattribute(space, w_descr, w_obj, w_name):
  174. try:
  175. if w_descr is None: # obscure case
  176. raise OperationError(space.w_AttributeError, space.w_None)
  177. return space.get_and_call_function(w_descr, w_obj, w_name)
  178. except OperationError as e:
  179. if not e.match(space, space.w_AttributeError):
  180. raise
  181. w_descr = space.lookup(w_obj, '__getattr__')
  182. if w_descr is None:
  183. raise
  184. return space.get_and_call_function(w_descr, w_obj, w_name)
  185. def setattr(space, w_obj, w_name, w_val):
  186. w_descr = space.lookup(w_obj, '__setattr__')
  187. if w_descr is None:
  188. raise oefmt(space.w_AttributeError,
  189. "'%T' object is readonly", w_obj)
  190. return space.get_and_call_function(w_descr, w_obj, w_name, w_val)
  191. def delattr(space, w_obj, w_name):
  192. w_descr = space.lookup(w_obj, '__delattr__')
  193. if w_descr is None:
  194. raise oefmt(space.w_AttributeError,
  195. "'%T' object does not support attribute removal",
  196. w_obj)
  197. return space.get_and_call_function(w_descr, w_obj, w_name)
  198. def is_true(space, w_obj):
  199. w_descr = space.lookup(w_obj, "__nonzero__")
  200. if w_descr is None:
  201. w_descr = space.lookup(w_obj, "__len__")
  202. if w_descr is None:
  203. return True
  204. # call __len__
  205. w_res = space.get_and_call_function(w_descr, w_obj)
  206. return space._check_len_result(w_res) != 0
  207. # call __nonzero__
  208. w_res = space.get_and_call_function(w_descr, w_obj)
  209. # more shortcuts for common cases
  210. if space.is_w(w_res, space.w_False):
  211. return False
  212. if space.is_w(w_res, space.w_True):
  213. return True
  214. w_restype = space.type(w_res)
  215. # Note there is no check for bool here because the only possible
  216. # instances of bool are w_False and w_True, which are checked above.
  217. if space.is_w(w_restype, space.w_int):
  218. return space.int_w(w_res) != 0
  219. else:
  220. raise oefmt(space.w_TypeError,
  221. "__nonzero__ should return bool or integer")
  222. def nonzero(space, w_obj):
  223. if space.is_true(w_obj):
  224. return space.w_True
  225. else:
  226. return space.w_False
  227. def len(space, w_obj):
  228. w_descr = space.lookup(w_obj, '__len__')
  229. if w_descr is None:
  230. raise oefmt(space.w_TypeError, "'%T' has no length", w_obj)
  231. w_res = space.get_and_call_function(w_descr, w_obj)
  232. return space.wrap(space._check_len_result(w_res))
  233. def _check_len_result(space, w_obj):
  234. # Will complain if result is too big.
  235. result = space.int_w(space.int(w_obj))
  236. if result < 0:
  237. raise oefmt(space.w_ValueError, "__len__() should return >= 0")
  238. return result
  239. def iter(space, w_obj):
  240. w_descr = space.lookup(w_obj, '__iter__')
  241. if w_descr is None:
  242. if space.type(w_obj).flag_map_or_seq != 'M':
  243. w_descr = space.lookup(w_obj, '__getitem__')
  244. if w_descr is None:
  245. raise oefmt(space.w_TypeError,
  246. "'%T' object is not iterable", w_obj)
  247. return space.newseqiter(w_obj)
  248. w_iter = space.get_and_call_function(w_descr, w_obj)
  249. w_next = space.lookup(w_iter, 'next')
  250. if w_next is None:
  251. raise oefmt(space.w_TypeError, "iter() returned non-iterator")
  252. return w_iter
  253. def next(space, w_obj):
  254. w_descr = space.lookup(w_obj, 'next')
  255. if w_descr is None:
  256. raise oefmt(space.w_TypeError,
  257. "'%T' object is not an iterator", w_obj)
  258. return space.get_and_call_function(w_descr, w_obj)
  259. def getitem(space, w_obj, w_key):
  260. w_descr = space.lookup(w_obj, '__getitem__')
  261. if w_descr is None:
  262. raise oefmt(space.w_TypeError,
  263. "'%T' object is not subscriptable", w_obj)
  264. return space.get_and_call_function(w_descr, w_obj, w_key)
  265. def setitem(space, w_obj, w_key, w_val):
  266. w_descr = space.lookup(w_obj, '__setitem__')
  267. if w_descr is None:
  268. raise oefmt(space.w_TypeError,
  269. "'%T' object does not support item assignment", w_obj)
  270. return space.get_and_call_function(w_descr, w_obj, w_key, w_val)
  271. def delitem(space, w_obj, w_key):
  272. w_descr = space.lookup(w_obj, '__delitem__')
  273. if w_descr is None:
  274. raise oefmt(space.w_TypeError,
  275. "'%T' object does not support item deletion", w_obj)
  276. return space.get_and_call_function(w_descr, w_obj, w_key)
  277. def getslice(space, w_obj, w_start, w_stop):
  278. w_descr = space.lookup(w_obj, '__getslice__')
  279. if w_descr is None:
  280. w_slice = space.newslice(w_start, w_stop, space.w_None)
  281. return space.getitem(w_obj, w_slice)
  282. w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
  283. return space.get_and_call_function(w_descr, w_obj, w_start, w_stop)
  284. def setslice(space, w_obj, w_start, w_stop, w_sequence):
  285. w_descr = space.lookup(w_obj, '__setslice__')
  286. if w_descr is None:
  287. w_slice = space.newslice(w_start, w_stop, space.w_None)
  288. return space.setitem(w_obj, w_slice, w_sequence)
  289. w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
  290. return space.get_and_call_function(w_descr, w_obj, w_start, w_stop, w_sequence)
  291. def delslice(space, w_obj, w_start, w_stop):
  292. w_descr = space.lookup(w_obj, '__delslice__')
  293. if w_descr is None:
  294. w_slice = space.newslice(w_start, w_stop, space.w_None)
  295. return space.delitem(w_obj, w_slice)
  296. w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
  297. return space.get_and_call_function(w_descr, w_obj, w_start, w_stop)
  298. def format(space, w_obj, w_format_spec):
  299. w_descr = space.lookup(w_obj, '__format__')
  300. if w_descr is None:
  301. raise oefmt(space.w_TypeError,
  302. "'%T' object does not define __format__", w_obj)
  303. w_res = space.get_and_call_function(w_descr, w_obj, w_format_spec)
  304. if not space.isinstance_w(w_res, space.w_basestring):
  305. raise oefmt(space.w_TypeError,
  306. "%T.__format__ must return string or unicode, not %T",
  307. w_obj, w_res)
  308. return w_res
  309. def pow(space, w_obj1, w_obj2, w_obj3):
  310. w_typ1 = space.type(w_obj1)
  311. w_typ2 = space.type(w_obj2)
  312. w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, '__pow__')
  313. if _same_class_w(space, w_obj1, w_obj2, w_typ1, w_typ2):
  314. w_right_impl = None
  315. else:
  316. w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2, '__rpow__')
  317. # sse binop_impl
  318. if (w_left_src is not w_right_src
  319. and space.issubtype_w(w_typ2, w_typ1)):
  320. if (w_left_src and w_right_src and
  321. not space.abstract_issubclass_w(w_left_src, w_right_src) and
  322. not space.abstract_issubclass_w(w_typ1, w_right_src)):
  323. w_obj1, w_obj2 = w_obj2, w_obj1
  324. w_left_impl, w_right_impl = w_right_impl, w_left_impl
  325. if w_left_impl is not None:
  326. if space.is_w(w_obj3, space.w_None):
  327. w_res = space.get_and_call_function(w_left_impl, w_obj1, w_obj2)
  328. else:
  329. w_res = space.get_and_call_function(w_left_impl, w_obj1, w_obj2, w_obj3)
  330. if _check_notimplemented(space, w_res):
  331. return w_res
  332. if w_right_impl is not None:
  333. if space.is_w(w_obj3, space.w_None):
  334. w_res = space.get_and_call_function(w_right_impl, w_obj2, w_obj1)
  335. else:
  336. w_res = space.get_and_call_function(w_right_impl, w_obj2, w_obj1,
  337. w_obj3)
  338. if _check_notimplemented(space, w_res):
  339. return w_res
  340. raise oefmt(space.w_TypeError, "operands do not support **")
  341. def inplace_pow(space, w_lhs, w_rhs):
  342. w_impl = space.lookup(w_lhs, '__ipow__')
  343. if w_impl is not None:
  344. w_res = space.get_and_call_function(w_impl, w_lhs, w_rhs)
  345. if _check_notimplemented(space, w_res):
  346. return w_res
  347. return space.pow(w_lhs, w_rhs, space.w_None)
  348. def contains(space, w_container, w_item):
  349. w_descr = space.lookup(w_container, '__contains__')
  350. if w_descr is not None:
  351. w_result = space.get_and_call_function(w_descr, w_container, w_item)
  352. return space.nonzero(w_result)
  353. return space._contains(w_container, w_item)
  354. def _contains(space, w_container, w_item):
  355. w_iter = space.iter(w_container)
  356. w_type = space.type(w_iter)
  357. while 1:
  358. contains_jitdriver.jit_merge_point(w_type=w_type)
  359. try:
  360. w_next = space.next(w_iter)
  361. except OperationError as e:
  362. if not e.match(space, space.w_StopIteration):
  363. raise
  364. return space.w_False
  365. if space.eq_w(w_item, w_next):
  366. return space.w_True
  367. def hash(space, w_obj):
  368. w_hash = space.lookup(w_obj, '__hash__')
  369. if w_hash is None:
  370. # xxx there used to be logic about "do we have __eq__ or __cmp__"
  371. # here, but it does not really make sense, as 'object' has a
  372. # default __hash__. This path should only be taken under very
  373. # obscure circumstances.
  374. return default_identity_hash(space, w_obj)
  375. if space.is_w(w_hash, space.w_None):
  376. raise oefmt(space.w_TypeError,
  377. "'%T' objects are unhashable", w_obj)
  378. w_result = space.get_and_call_function(w_hash, w_obj)
  379. # issue 2346 : returns now -2 for hashing -1 like cpython
  380. if space.isinstance_w(w_result, space.w_int):
  381. h = space.int_w(w_result)
  382. elif space.isinstance_w(w_result, space.w_long):
  383. bigint = space.bigint_w(w_result)
  384. h = bigint.hash()
  385. else:
  386. raise oefmt(space.w_TypeError,
  387. "__hash__() should return an int or long")
  388. # turn -1 into -2 without using a condition, which would
  389. # create a potential bridge in the JIT
  390. h -= (h == -1)
  391. return space.wrap(h)
  392. def cmp(space, w_v, w_w):
  393. if space.is_w(w_v, w_w):
  394. return space.wrap(0)
  395. # The real comparison
  396. if space.is_w(space.type(w_v), space.type(w_w)):
  397. # for object of the same type, prefer __cmp__ over rich comparison.
  398. w_cmp = space.lookup(w_v, '__cmp__')
  399. w_res = _invoke_binop(space, w_cmp, w_v, w_w)
  400. if w_res is not None:
  401. return w_res
  402. # fall back to rich comparison.
  403. if space.eq_w(w_v, w_w):
  404. return space.wrap(0)
  405. elif space.is_true(space.lt(w_v, w_w)):
  406. return space.wrap(-1)
  407. return space.wrap(1)
  408. def coerce(space, w_obj1, w_obj2):
  409. w_res = space.try_coerce(w_obj1, w_obj2)
  410. if w_res is None:
  411. raise oefmt(space.w_TypeError, "coercion failed")
  412. return w_res
  413. def try_coerce(space, w_obj1, w_obj2):
  414. """Returns a wrapped 2-tuple or a real None if it failed."""
  415. w_typ1 = space.type(w_obj1)
  416. w_typ2 = space.type(w_obj2)
  417. w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, '__coerce__')
  418. if space.is_w(w_typ1, w_typ2):
  419. w_right_impl = None
  420. else:
  421. w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2, '__coerce__')
  422. if (w_left_src is not w_right_src
  423. and space.issubtype_w(w_typ2, w_typ1)):
  424. w_obj1, w_obj2 = w_obj2, w_obj1
  425. w_left_impl, w_right_impl = w_right_impl, w_left_impl
  426. w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
  427. if w_res is None or space.is_w(w_res, space.w_None):
  428. w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
  429. if w_res is None or space.is_w(w_res, space.w_None):
  430. return None
  431. if (not space.isinstance_w(w_res, space.w_tuple) or
  432. space.len_w(w_res) != 2):
  433. raise oefmt(space.w_TypeError,
  434. "coercion should return None or 2-tuple")
  435. w_res = space.newtuple([space.getitem(w_res, space.wrap(1)), space.getitem(w_res, space.wrap(0))])
  436. elif (not space.isinstance_w(w_res, space.w_tuple) or
  437. space.len_w(w_res) != 2):
  438. raise oefmt(space.w_TypeError,
  439. "coercion should return None or 2-tuple")
  440. return w_res
  441. def issubtype_w(space, w_sub, w_type):
  442. return space._type_issubtype(w_sub, w_type)
  443. def issubtype(space, w_sub, w_type):
  444. return space.wrap(space._type_issubtype(w_sub, w_type))
  445. @specialize.arg_or_var(2)
  446. def isinstance_w(space, w_inst, w_type):
  447. return space._type_isinstance(w_inst, w_type)
  448. @specialize.arg_or_var(2)
  449. def isinstance(space, w_inst, w_type):
  450. return space.wrap(space.isinstance_w(w_inst, w_type))
  451. # helpers
  452. def _check_notimplemented(space, w_obj):
  453. return not space.is_w(w_obj, space.w_NotImplemented)
  454. def _invoke_binop(space, w_impl, w_obj1, w_obj2):
  455. if w_impl is not None:
  456. w_res = space.get_and_call_function(w_impl, w_obj1, w_obj2)
  457. if _check_notimplemented(space, w_res):
  458. return w_res
  459. return None
  460. # helper for invoking __cmp__
  461. def _conditional_neg(space, w_obj, flag):
  462. if flag:
  463. return space.neg(w_obj)
  464. else:
  465. return w_obj
  466. def _cmp(space, w_obj1, w_obj2, symbol):
  467. w_typ1 = space.type(w_obj1)
  468. w_typ2 = space.type(w_obj2)
  469. w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, '__cmp__')
  470. do_neg1 = False
  471. do_neg2 = True
  472. if space.is_w(w_typ1, w_typ2):
  473. w_right_impl = None
  474. else:
  475. w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2, '__cmp__')
  476. if (w_left_src is not w_right_src
  477. and space.issubtype_w(w_typ2, w_typ1)):
  478. w_obj1, w_obj2 = w_obj2, w_obj1
  479. w_left_impl, w_right_impl = w_right_impl, w_left_impl
  480. do_neg1, do_neg2 = do_neg2, do_neg1
  481. w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
  482. if w_res is not None:
  483. return _conditional_neg(space, w_res, do_neg1)
  484. w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
  485. if w_res is not None:
  486. return _conditional_neg(space, w_res, do_neg2)
  487. # fall back to internal rules
  488. if space.is_w(w_obj1, w_obj2):
  489. return space.wrap(0)
  490. if space.is_w(w_obj1, space.w_None):
  491. return space.wrap(-1)
  492. if space.is_w(w_obj2, space.w_None):
  493. return space.wrap(1)
  494. if space.is_w(w_typ1, w_typ2):
  495. #print "WARNING, comparison by address!"
  496. lt = _id_cmpr(space, w_obj1, w_obj2, symbol)
  497. else:
  498. #print "WARNING, comparison by type name!"
  499. # the CPython rule is to compare type names; numbers are
  500. # smaller. So we compare the types by the following key:
  501. # (not_a_number_flag, type_name, type_id)
  502. num1 = number_check(space, w_obj1)
  503. num2 = number_check(space, w_obj2)
  504. if num1 != num2:
  505. lt = num1 # if obj1 is a number, it is Lower Than obj2
  506. else:
  507. name1 = w_typ1.getname(space)
  508. name2 = w_typ2.getname(space)
  509. if name1 != name2:
  510. lt = name1 < name2
  511. else:
  512. lt = _id_cmpr(space, w_typ1, w_typ2, symbol)
  513. if lt:
  514. return space.wrap(-1)
  515. else:
  516. return space.wrap(1)
  517. def _id_cmpr(space, w_obj1, w_obj2, symbol):
  518. if symbol == "==":
  519. return not space.is_w(w_obj1, w_obj2)
  520. elif symbol == "!=":
  521. return space.is_w(w_obj1, w_obj2)
  522. w_id1 = space.id(w_obj1)
  523. w_id2 = space.id(w_obj2)
  524. return space.is_true(space.lt(w_id1, w_id2))
  525. def number_check(space, w_obj):
  526. # avoid this as much as possible. It checks if w_obj "looks like"
  527. # it might be a number-ish thing.
  528. return (space.lookup(w_obj, '__int__') is not None or
  529. space.lookup(w_obj, '__float__') is not None)
  530. # what is the maximum value slices can get on CPython?
  531. # we need to stick to that value, because fake.py etc.
  532. class Temp(object):
  533. def __getslice__(self, i, j):
  534. return j
  535. slice_max = Temp()[:]
  536. del Temp
  537. def old_slice_range_getlength(space, w_obj):
  538. # NB. the language ref is inconsistent with the new-style class
  539. # behavior when w_obj doesn't implement __len__(), so we just
  540. # follow cpython. Also note that CPython slots make it easier
  541. # to check for object implementing it or not. We just catch errors
  542. # so this behavior is slightly different
  543. try:
  544. return space.len(w_obj)
  545. except OperationError as e:
  546. if not ((e.match(space, space.w_AttributeError) or
  547. e.match(space, space.w_TypeError))):
  548. raise
  549. return None
  550. def old_slice_range(space, w_obj, w_start, w_stop):
  551. """Only for backward compatibility for __getslice__()&co methods."""
  552. w_length = None
  553. if space.is_w(w_start, space.w_None):
  554. w_start = space.wrap(0)
  555. else:
  556. start = space.getindex_w(w_start, None)
  557. w_start = space.wrap(start)
  558. if start < 0:
  559. w_length = old_slice_range_getlength(space, w_obj)
  560. if w_length is not None:
  561. w_start = space.add(w_start, w_length)
  562. if space.is_w(w_stop, space.w_None):
  563. w_stop = space.wrap(slice_max)
  564. else:
  565. stop = space.getindex_w(w_stop, None)
  566. w_stop = space.wrap(stop)
  567. if stop < 0:
  568. if w_length is None:
  569. w_length = old_slice_range_getlength(space, w_obj)
  570. if w_length is not None:
  571. w_stop = space.add(w_stop, w_length)
  572. return w_start, w_stop
  573. # regular methods def helpers
  574. def _make_binop_impl(symbol, specialnames):
  575. left, right = specialnames
  576. errormsg = "unsupported operand type(s) for %s: '%%N' and '%%N'" % (
  577. symbol.replace('%', '%%'),)
  578. seq_bug_compat = (symbol == '+' or symbol == '*')
  579. def binop_impl(space, w_obj1, w_obj2):
  580. w_typ1 = space.type(w_obj1)
  581. w_typ2 = space.type(w_obj2)
  582. w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, left)
  583. if _same_class_w(space, w_obj1, w_obj2, w_typ1, w_typ2):
  584. w_right_impl = None
  585. else:
  586. w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2, right)
  587. # the logic to decide if the reverse operation should be tried
  588. # before the direct one is very obscure. For now, and for
  589. # sanity reasons, we just compare the two places where the
  590. # __xxx__ and __rxxx__ methods where found by identity.
  591. # Note that space.is_w() is potentially not happy if one of them
  592. # is None...
  593. if w_right_src and (w_left_src is not w_right_src) and w_left_src:
  594. # 'seq_bug_compat' is for cpython bug-to-bug compatibility:
  595. # see objspace/std/test/test_unicodeobject.*concat_overrides
  596. # and objspace/test/test_descrobject.*rmul_overrides.
  597. # For cases like "unicode + string subclass".
  598. if ((seq_bug_compat and w_typ1.flag_sequence_bug_compat
  599. and not w_typ2.flag_sequence_bug_compat)
  600. # the non-bug-compat part is the following check:
  601. or space.issubtype_w(w_typ2, w_typ1)):
  602. if (not space.abstract_issubclass_w(w_left_src, w_right_src) and
  603. not space.abstract_issubclass_w(w_typ1, w_right_src)):
  604. w_obj1, w_obj2 = w_obj2, w_obj1
  605. w_left_impl, w_right_impl = w_right_impl, w_left_impl
  606. w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
  607. if w_res is not None:
  608. return w_res
  609. w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
  610. if w_res is not None:
  611. return w_res
  612. raise oefmt(space.w_TypeError, errormsg, w_typ1, w_typ2)
  613. return func_with_new_name(binop_impl, "binop_%s_impl"%left.strip('_'))
  614. def _make_comparison_impl(symbol, specialnames):
  615. left, right = specialnames
  616. op = getattr(operator, left)
  617. def comparison_impl(space, w_obj1, w_obj2):
  618. w_typ1 = space.type(w_obj1)
  619. w_typ2 = space.type(w_obj2)
  620. w_left_src, w_left_impl = space.lookup_in_type_where(w_typ1, left)
  621. w_first = w_obj1
  622. w_second = w_obj2
  623. #
  624. if left == right and _same_class_w(space, w_obj1, w_obj2,
  625. w_typ1, w_typ2):
  626. # for __eq__ and __ne__, if the objects have the same
  627. # (old-style or new-style) class, then don't try the
  628. # opposite method, which is the same one.
  629. w_right_impl = None
  630. else:
  631. # in all other cases, try the opposite method.
  632. w_right_src, w_right_impl = space.lookup_in_type_where(w_typ2,right)
  633. if space.is_w(w_typ1, w_typ2):
  634. # if the type is the same, *or* if both are old-style classes,
  635. # then don't reverse: try left first, right next.
  636. pass
  637. elif space.issubtype_w(w_typ2, w_typ1):
  638. # for new-style classes, if typ2 is a subclass of typ1.
  639. w_obj1, w_obj2 = w_obj2, w_obj1
  640. w_left_impl, w_right_impl = w_right_impl, w_left_impl
  641. w_res = _invoke_binop(space, w_left_impl, w_obj1, w_obj2)
  642. if w_res is not None:
  643. return w_res
  644. w_res = _invoke_binop(space, w_right_impl, w_obj2, w_obj1)
  645. if w_res is not None:
  646. return w_res
  647. # fallback: lt(a, b) <= lt(cmp(a, b), 0) ...
  648. w_res = _cmp(space, w_first, w_second, symbol)
  649. res = space.int_w(w_res)
  650. return space.wrap(op(res, 0))
  651. return func_with_new_name(comparison_impl, 'comparison_%s_impl'%left.strip('_'))
  652. def _make_inplace_impl(symbol, specialnames):
  653. specialname, = specialnames
  654. assert specialname.startswith('__i') and specialname.endswith('__')
  655. noninplacespacemethod = specialname[3:-2]
  656. if noninplacespacemethod in ['or', 'and']:
  657. noninplacespacemethod += '_' # not too clean
  658. seq_bug_compat = (symbol == '+=' or symbol == '*=')
  659. rhs_method = '__r' + specialname[3:]
  660. def inplace_impl(space, w_lhs, w_rhs):
  661. w_impl = space.lookup(w_lhs, specialname)
  662. if w_impl is not None:
  663. # 'seq_bug_compat' is for cpython bug-to-bug compatibility:
  664. # see objspace/test/test_descrobject.*rmul_overrides.
  665. # For cases like "list += object-overriding-__radd__".
  666. if (seq_bug_compat and space.type(w_lhs).flag_sequence_bug_compat
  667. and not space.type(w_rhs).flag_sequence_bug_compat):
  668. w_res = _invoke_binop(space, space.lookup(w_rhs, rhs_method),
  669. w_rhs, w_lhs)
  670. if w_res is not None:
  671. return w_res
  672. # xxx if __radd__ is defined but returns NotImplemented,
  673. # then it might be called again below. Oh well, too bad.
  674. # Anyway that's a case where we're likely to end up in
  675. # a TypeError.
  676. #
  677. w_res = space.get_and_call_function(w_impl, w_lhs, w_rhs)
  678. if _check_notimplemented(space, w_res):
  679. return w_res
  680. # XXX fix the error message we get here
  681. return getattr(space, noninplacespacemethod)(w_lhs, w_rhs)
  682. return func_with_new_name(inplace_impl, 'inplace_%s_impl'%specialname.strip('_'))
  683. def _make_unaryop_impl(symbol, specialnames):
  684. specialname, = specialnames
  685. errormsg = "unsupported operand type for unary %s: '%%T'" % symbol
  686. def unaryop_impl(space, w_obj):
  687. w_impl = space.lookup(w_obj, specialname)
  688. if w_impl is None:
  689. raise oefmt(space.w_TypeError, errormsg, w_obj)
  690. return space.get_and_call_function(w_impl, w_obj)
  691. return func_with_new_name(unaryop_impl, 'unaryop_%s_impl'%specialname.strip('_'))
  692. # the following seven operations are really better to generate with
  693. # string-templating (and maybe we should consider this for
  694. # more of the above manually-coded operations as well)
  695. for targetname, specialname, checkerspec in [
  696. ('index', '__index__', ("space.w_int", "space.w_long")),
  697. ('long', '__long__', ("space.w_int", "space.w_long")),
  698. ('float', '__float__', ("space.w_float",))]:
  699. l = ["space.isinstance_w(w_result, %s)" % x
  700. for x in checkerspec]
  701. checker = " or ".join(l)
  702. if targetname == 'index':
  703. msg = "'%%T' object cannot be interpreted as an index"
  704. else:
  705. msg = "unsupported operand type for %(targetname)s(): '%%T'"
  706. msg = msg % locals()
  707. source = """if 1:
  708. def %(targetname)s(space, w_obj):
  709. w_impl = space.lookup(w_obj, %(specialname)r)
  710. if w_impl is None:
  711. raise oefmt(space.w_TypeError,
  712. %(msg)r,
  713. w_obj)
  714. w_result = space.get_and_call_function(w_impl, w_obj)
  715. if %(checker)s:
  716. return w_result
  717. raise oefmt(space.w_TypeError,
  718. "%(specialname)s returned non-%(targetname)s (type "
  719. "'%%T')", w_result)
  720. assert not hasattr(DescrOperation, %(targetname)r)
  721. DescrOperation.%(targetname)s = %(targetname)s
  722. del %(targetname)s
  723. \n""" % locals()
  724. exec compile2(source)
  725. for targetname, specialname in [
  726. ('str', '__str__'),
  727. ('repr', '__repr__'),
  728. ('oct', '__oct__'),
  729. ('hex', '__hex__')]:
  730. source = """if 1:
  731. def %(targetname)s(space, w_obj):
  732. w_impl = space.lookup(w_obj, %(specialname)r)
  733. if w_impl is None:
  734. raise oefmt(space.w_TypeError,
  735. "unsupported operand type for %(targetname)s(): "
  736. "'%%T'", w_obj)
  737. w_result = space.get_and_call_function(w_impl, w_obj)
  738. if space.isinstance_w(w_result, space.w_str):
  739. return w_result
  740. try:
  741. result = space.str_w(w_result)
  742. except OperationError, e:
  743. if not e.match(space, space.w_TypeError):
  744. raise
  745. raise oefmt(space.w_TypeError,
  746. "%(specialname)s returned non-%(targetname)s "
  747. "(type '%%T')", w_result)
  748. else:
  749. # re-wrap the result as a real string
  750. return space.wrap(result)
  751. assert not hasattr(DescrOperation, %(targetname)r)
  752. DescrOperation.%(targetname)s = %(targetname)s
  753. del %(targetname)s
  754. \n""" % locals()
  755. exec compile2(source)
  756. # add default operation implementations for all still missing ops
  757. for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable:
  758. if not hasattr(DescrOperation, _name):
  759. _impl_maker = None
  760. if _arity == 2 and _name in ['lt', 'le', 'gt', 'ge', 'ne', 'eq']:
  761. #print "comparison", _specialnames
  762. _impl_maker = _make_comparison_impl
  763. elif _arity == 2 and _name.startswith('inplace_'):
  764. #print "inplace", _specialnames
  765. _impl_maker = _make_inplace_impl
  766. elif _arity == 2 and len(_specialnames) == 2:
  767. #print "binop", _specialnames
  768. _impl_maker = _make_binop_impl
  769. elif _arity == 1 and len(_specialnames) == 1 and _name != 'int':
  770. #print "unaryop", _specialnames
  771. _impl_maker = _make_unaryop_impl
  772. if _impl_maker:
  773. setattr(DescrOperation,_name,_impl_maker(_symbol,_specialnames))
  774. elif _name not in ['is_', 'id','type','issubtype', 'int',
  775. # not really to be defined in DescrOperation
  776. 'ord', 'unichr', 'unicode']:
  777. raise Exception("missing def for operation %s" % _name)