Author: Philip Jenvey <pjen...@underboss.org> Branch: py3.3 Changeset: r74191:3820173e81e3 Date: 2014-10-24 13:48 -0700 http://bitbucket.org/pypy/pypy/changeset/3820173e81e3/
Log: merge py3k diff too long, truncating to 2000 out of 5270 lines diff --git a/lib_pypy/_tkinter/app.py b/lib_pypy/_tkinter/app.py --- a/lib_pypy/_tkinter/app.py +++ b/lib_pypy/_tkinter/app.py @@ -439,7 +439,7 @@ if isinstance(s, int): return s s = s.encode('utf-8') - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("int*") res = tklib.Tcl_GetBoolean(self.interp, s, v) @@ -451,7 +451,7 @@ if isinstance(s, int): return s s = s.encode('utf-8') - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("int*") res = tklib.Tcl_GetInt(self.interp, s, v) @@ -463,7 +463,7 @@ if isinstance(s, float): return s s = s.encode('utf-8') - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("double*") res = tklib.Tcl_GetDouble(self.interp, s, v) @@ -472,7 +472,7 @@ return v[0] def exprboolean(self, s): - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("int*") res = tklib.Tcl_ExprBoolean(self.interp, s, v) @@ -481,7 +481,7 @@ return v[0] def exprlong(self, s): - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("long*") res = tklib.Tcl_ExprLong(self.interp, s, v) @@ -490,7 +490,7 @@ return v[0] def exprdouble(self, s): - if '\x00' in s: + if b'\x00' in s: raise TypeError v = tkffi.new("double*") res = tklib.Tcl_ExprDouble(self.interp, s, v) @@ -499,7 +499,7 @@ return v[0] def exprstring(self, s): - if '\x00' in s: + if b'\x00' in s: raise TypeError res = tklib.Tcl_ExprString(self.interp, s) if res == tklib.TCL_ERROR: diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -22,3 +22,6 @@ .. branch: ClassRepr Refactor ClassRepr and make normalizecalls independent of the rtyper. + +.. branch: remove-remaining-smm +Remove all remaining multimethods. diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py --- a/pypy/goal/targetpypystandalone.py +++ b/pypy/goal/targetpypystandalone.py @@ -310,7 +310,8 @@ return self.get_entry_point(config) def jitpolicy(self, driver): - from pypy.module.pypyjit.policy import PyPyJitPolicy, pypy_hooks + from pypy.module.pypyjit.policy import PyPyJitPolicy + from pypy.module.pypyjit.hooks import pypy_hooks return PyPyJitPolicy(pypy_hooks) def get_entry_point(self, config): diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1902,5 +1902,4 @@ 'newdict', 'newslice', 'call_args', - 'marshal_w', ] diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py --- a/pypy/interpreter/gateway.py +++ b/pypy/interpreter/gateway.py @@ -644,6 +644,17 @@ elif unwrap_spec == [ObjSpace, W_Root, Arguments]: self.__class__ = BuiltinCodePassThroughArguments1 self.func__args__ = func + elif unwrap_spec == [self_type, ObjSpace, Arguments]: + self.__class__ = BuiltinCodePassThroughArguments1 + miniglobals = {'func': func, 'self_type': self_type} + d = {} + source = """if 1: + def _call(space, w_obj, args): + self = space.descr_self_interp_w(self_type, w_obj) + return func(self, space, args) + \n""" + exec compile2(source) in miniglobals, d + self.func__args__ = d['_call'] else: self.__class__ = globals()['BuiltinCode%d' % arity] setattr(self, 'fastfunc_%d' % arity, fastfunc) diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py --- a/pypy/interpreter/test/test_gateway.py +++ b/pypy/interpreter/test/test_gateway.py @@ -906,11 +906,33 @@ assert len(called) == 1 assert isinstance(called[0], argument.Arguments) + def test_pass_trough_arguments_method(self): + space = self.space + + called = [] + + class W_Something(W_Root): + def f(self, space, __args__): + called.append(__args__) + a_w, _ = __args__.unpack() + return space.newtuple([space.wrap('f')]+a_w) + + w_f = space.wrap(gateway.interp2app_temp(W_Something.f)) + + w_self = space.wrap(W_Something()) + args = argument.Arguments(space, [space.wrap(7)]) + + w_res = space.call_obj_args(w_f, w_self, args) + assert space.is_true(space.eq(w_res, space.wrap(('f', 7)))) + + # white-box check for opt + assert called[0] is args + class AppTestKeywordsToBuiltinSanity(object): def test_type(self): class X(object): - def __init__(self, **kw): + def __init__(myself, **kw): pass clash = type.__call__.__code__.co_varnames[0] @@ -926,7 +948,6 @@ X(**{clash: 33}) object.__new__(X, **{clash: 33}) - def test_dict_new(self): clash = dict.__new__.__code__.co_varnames[0] diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -2,6 +2,7 @@ from pypy.interpreter.gateway import WrappedDefault, unwrap_spec from rpython.rlib.rarithmetic import intmask from rpython.rlib import rstackovf +from pypy.objspace.std.marshal_impl import marshal, get_unmarshallers Py_MARSHAL_VERSION = 2 @@ -139,6 +140,26 @@ raise OperationError(space.w_ValueError, space.wrap(msg)) class Marshaller(_Base): + """ + atomic types including typecode: + + atom(tc) puts single typecode + atom_int(tc, int) puts code and int + atom_int64(tc, int64) puts code and int64 + atom_str(tc, str) puts code, len and string + atom_strlist(tc, strlist) puts code, len and list of strings + + building blocks for compound types: + + start(typecode) sets the type character + put(s) puts a string with fixed length + put_short(int) puts a short integer + put_int(int) puts an integer + put_pascal(s) puts a short string + put_w_obj(w_obj) puts a wrapped object + put_tuple_w(TYPE, tuple_w) puts tuple_w, an unwrapped list of wrapped objects + """ + # _annspecialcase_ = "specialize:ctr_location" # polymorphic # does not work with subclassing @@ -217,7 +238,7 @@ self.put(x) def put_w_obj(self, w_obj): - self.space.marshal_w(w_obj, self) + marshal(self.space, w_obj, self) def dump_w_obj(self, w_obj): space = self.space @@ -243,7 +264,7 @@ idx = 0 while idx < lng: w_obj = lst_w[idx] - self.space.marshal_w(w_obj, self) + marshal(self.space, w_obj, self) idx += 1 def _overflow(self): @@ -333,14 +354,11 @@ u.raise_exc("bad marshal data (unknown type code)") -def register(codes, func): - """NOT_RPYTHON""" - for code in codes: - Unmarshaller._dispatch[ord(code)] = func - class Unmarshaller(_Base): _dispatch = [invalid_typecode] * 256 + for tc, func in get_unmarshallers(): + _dispatch[ord(tc)] = func def __init__(self, space, reader): self.space = space diff --git a/pypy/module/marshal/test/test_marshalimpl.py b/pypy/module/marshal/test/test_marshalimpl.py --- a/pypy/module/marshal/test/test_marshalimpl.py +++ b/pypy/module/marshal/test/test_marshalimpl.py @@ -72,7 +72,7 @@ expected = marshal.dumps(long(x)) w_obj = space.wraplong(x) m = FakeM() - space.marshal_w(w_obj, m) + interp_marshal.marshal(space, w_obj, m) assert ''.join(m.seen) == expected # u = interp_marshal.StringUnmarshaller(space, space.wrapbytes(expected)) diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -3,8 +3,8 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.objspace.std.bytesobject import W_BytesObject -from pypy.objspace.std.complextype import complex_typedef -from pypy.objspace.std.floattype import float_typedef +from pypy.objspace.std.complexobject import W_ComplexObject +from pypy.objspace.std.floatobject import W_FloatObject from pypy.objspace.std.intobject import W_IntObject from pypy.objspace.std.unicodeobject import W_UnicodeObject from rpython.rlib.rarithmetic import LONG_BIT @@ -784,7 +784,7 @@ __reduce__ = interp2app(W_Float32Box.descr_reduce), ) -W_Float64Box.typedef = TypeDef("numpy.float64", (W_FloatingBox.typedef, float_typedef), +W_Float64Box.typedef = TypeDef("numpy.float64", (W_FloatingBox.typedef, W_FloatObject.typedef), __new__ = interp2app(W_Float64Box.descr__new__.im_func), __reduce__ = interp2app(W_Float64Box.descr_reduce), as_integer_ratio = interp2app(W_Float64Box.descr_as_integer_ratio), @@ -799,7 +799,7 @@ __complex__ = interp2app(W_GenericBox.item), ) -W_Complex128Box.typedef = TypeDef("numpy.complex128", (W_ComplexFloatingBox.typedef, complex_typedef), +W_Complex128Box.typedef = TypeDef("numpy.complex128", (W_ComplexFloatingBox.typedef, W_ComplexObject.typedef), __new__ = interp2app(W_Complex128Box.descr__new__.im_func), __reduce__ = interp2app(W_Complex128Box.descr_reduce), ) @@ -810,7 +810,7 @@ __reduce__ = interp2app(W_FloatLongBox.descr_reduce), ) - W_ComplexLongBox.typedef = TypeDef("numpy.complex%d" % (long_double_size * 16), (W_ComplexFloatingBox.typedef, complex_typedef), + W_ComplexLongBox.typedef = TypeDef("numpy.complex%d" % (long_double_size * 16), (W_ComplexFloatingBox.typedef, W_ComplexObject.typedef), __new__ = interp2app(W_ComplexLongBox.descr__new__.im_func), __reduce__ = interp2app(W_ComplexLongBox.descr_reduce), __complex__ = interp2app(W_GenericBox.item), diff --git a/pypy/module/posix/interp_nt.py b/pypy/module/posix/interp_nt.py --- a/pypy/module/posix/interp_nt.py +++ b/pypy/module/posix/interp_nt.py @@ -21,6 +21,9 @@ """ eci = ExternalCompilationInfo( includes=['windows.h'], + post_include_bits=[ + "DWORD " + "pypy_GetFinalPathNameByHandle(FARPROC, HANDLE, LPTSTR, DWORD, DWORD);"], separate_module_sources=[separate_module_source], export_symbols=['pypy_GetFinalPathNameByHandle'] ) diff --git a/pypy/module/pypyjit/__init__.py b/pypy/module/pypyjit/__init__.py --- a/pypy/module/pypyjit/__init__.py +++ b/pypy/module/pypyjit/__init__.py @@ -24,7 +24,7 @@ def setup_after_space_initialization(self): # force the __extend__ hacks to occur early from pypy.module.pypyjit.interp_jit import pypyjitdriver - from pypy.module.pypyjit.policy import pypy_hooks + from pypy.module.pypyjit.hooks import pypy_hooks # add the 'defaults' attribute from rpython.rlib.jit import PARAMETERS space = self.space diff --git a/pypy/module/pypyjit/hooks.py b/pypy/module/pypyjit/hooks.py new file mode 100644 --- /dev/null +++ b/pypy/module/pypyjit/hooks.py @@ -0,0 +1,89 @@ + +from rpython.rlib import jit_hooks +from rpython.rlib.jit import JitHookInterface, Counters + +from pypy.interpreter.error import OperationError +from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, + WrappedOp, W_JitLoopInfo, wrap_oplist) + +class PyPyJitIface(JitHookInterface): + def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if space.is_true(cache.w_abort_hook): + cache.in_recursion = True + oplist_w = wrap_oplist(space, logops, operations) + try: + try: + space.call_function(cache.w_abort_hook, + space.wrap(jitdriver.name), + wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), + space.wrap(Counters.counter_names[reason]), + space.newlist(oplist_w) + ) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_abort_hook) + finally: + cache.in_recursion = False + + def after_compile(self, debug_info): + self._compile_hook(debug_info, is_bridge=False) + + def after_compile_bridge(self, debug_info): + self._compile_hook(debug_info, is_bridge=True) + + def before_compile(self, debug_info): + self._optimize_hook(debug_info, is_bridge=False) + + def before_compile_bridge(self, debug_info): + self._optimize_hook(debug_info, is_bridge=True) + + def _compile_hook(self, debug_info, is_bridge): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if space.is_true(cache.w_compile_hook): + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + cache.in_recursion = True + try: + try: + space.call_function(cache.w_compile_hook, + space.wrap(w_debug_info)) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + finally: + cache.in_recursion = False + + def _optimize_hook(self, debug_info, is_bridge=False): + space = self.space + cache = space.fromcache(Cache) + if cache.in_recursion: + return + if space.is_true(cache.w_optimize_hook): + w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) + cache.in_recursion = True + try: + try: + w_res = space.call_function(cache.w_optimize_hook, + space.wrap(w_debug_info)) + if space.is_w(w_res, space.w_None): + return + l = [] + for w_item in space.listview(w_res): + item = space.interp_w(WrappedOp, w_item) + l.append(jit_hooks._cast_to_resop(item.op)) + del debug_info.operations[:] # modifying operations above is + # probably not a great idea since types may not work + # and we'll end up with half-working list and + # a segfault/fatal RPython error + for elem in l: + debug_info.operations.append(elem) + except OperationError, e: + e.write_unraisable(space, "jit hook ", cache.w_compile_hook) + finally: + cache.in_recursion = False + +pypy_hooks = PyPyJitIface() diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py --- a/pypy/module/pypyjit/policy.py +++ b/pypy/module/pypyjit/policy.py @@ -1,93 +1,4 @@ from rpython.jit.codewriter.policy import JitPolicy -from rpython.rlib import jit_hooks -from rpython.rlib.jit import JitHookInterface, Counters - -from pypy.interpreter.error import OperationError -from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey, - WrappedOp, W_JitLoopInfo, wrap_oplist) - - -class PyPyJitIface(JitHookInterface): - def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_abort_hook): - cache.in_recursion = True - oplist_w = wrap_oplist(space, logops, operations) - try: - try: - space.call_function(cache.w_abort_hook, - space.wrap(jitdriver.name), - wrap_greenkey(space, jitdriver, greenkey, greenkey_repr), - space.wrap(Counters.counter_names[reason]), - space.newlist(oplist_w) - ) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_abort_hook) - finally: - cache.in_recursion = False - - def after_compile(self, debug_info): - self._compile_hook(debug_info, is_bridge=False) - - def after_compile_bridge(self, debug_info): - self._compile_hook(debug_info, is_bridge=True) - - def before_compile(self, debug_info): - self._optimize_hook(debug_info, is_bridge=False) - - def before_compile_bridge(self, debug_info): - self._optimize_hook(debug_info, is_bridge=True) - - def _compile_hook(self, debug_info, is_bridge): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_compile_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - space.call_function(cache.w_compile_hook, - space.wrap(w_debug_info)) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - - def _optimize_hook(self, debug_info, is_bridge=False): - space = self.space - cache = space.fromcache(Cache) - if cache.in_recursion: - return - if space.is_true(cache.w_optimize_hook): - w_debug_info = W_JitLoopInfo(space, debug_info, is_bridge) - cache.in_recursion = True - try: - try: - w_res = space.call_function(cache.w_optimize_hook, - space.wrap(w_debug_info)) - if space.is_w(w_res, space.w_None): - return - l = [] - for w_item in space.listview(w_res): - item = space.interp_w(WrappedOp, w_item) - l.append(jit_hooks._cast_to_resop(item.op)) - del debug_info.operations[:] # modifying operations above is - # probably not a great idea since types may not work - # and we'll end up with half-working list and - # a segfault/fatal RPython error - for elem in l: - debug_info.operations.append(elem) - except OperationError, e: - e.write_unraisable(space, "jit hook ", cache.w_compile_hook) - finally: - cache.in_recursion = False - -pypy_hooks = PyPyJitIface() class PyPyJitPolicy(JitPolicy): @@ -103,19 +14,13 @@ return True if '.' in modname: modname, rest = modname.split('.', 1) + if modname in ['unicodedata', 'gc', '_minimal_curses', 'cpyext']: + return False else: rest = '' - if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions', - 'imp', 'sys', 'array', 'itertools', 'operator', - 'posix', '_socket', '_sre', '_lsprof', '_weakref', - '__pypy__', 'cStringIO', '_collections', 'struct', - 'mmap', 'marshal', '_codecs', 'rctime', 'cppyy', - '_cffi_backend', 'pyexpat', '_continuation', '_io', - 'thread', 'select', '_random']: - if modname == 'pypyjit' and 'interp_resop' in rest: - return False - return True - return False + if modname == 'pypyjit' and 'interp_resop' in rest: + return False + return True def look_inside_function(self, func): mod = func.__module__ or '?' diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py --- a/pypy/module/pypyjit/test_pypy_c/test_string.py +++ b/pypy/module/pypyjit/test_pypy_c/test_string.py @@ -85,7 +85,7 @@ i95 = getfield_gc_pure(p93, descr=<FieldS rpython.rlib.rbigint.rbigint.inst_size .*>) i96 = int_gt(i95, .*) guard_false(i96, descr=...) - i94 = call(ConstClass(rbigint._toint_helper), p93, descr=<Calli 8 r EF=3>) + i94 = call(ConstClass(rbigint._toint_helper), p93, descr=<Calli . r EF=3>) guard_no_exception(descr=...) i95 = int_add_ovf(i6, i94) guard_no_overflow(descr=...) diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py --- a/pypy/module/pypyjit/test_pypy_c/test_thread.py +++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py @@ -70,7 +70,6 @@ i59 = int_is_true(i58) guard_true(i59, descr=...) i60 = int_sub(i44, 1) - guard_not_invalidated(descr=...) p62 = force_token() setfield_gc(p0, p62, descr=<FieldP pypy.interpreter.pyframe.PyFrame.vable_token 8>) i63 = call_release_gil(..., i37, 0, descr=<Calli 4 ii EF=6>) diff --git a/pypy/objspace/std/complexobject.py b/pypy/objspace/std/complexobject.py --- a/pypy/objspace/std/complexobject.py +++ b/pypy/objspace/std/complexobject.py @@ -1,57 +1,181 @@ import math -from pypy.interpreter.error import OperationError +from pypy.interpreter.baseobjspace import W_Root +from pypy.interpreter.error import OperationError, oefmt +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault from pypy.objspace.std import newformat -from pypy.objspace.std.intobject import W_IntObject -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.floatobject import W_FloatObject, _hash_float -from pypy.objspace.std.longobject import W_LongObject +from pypy.objspace.std.floatobject import _hash_float +from pypy.objspace.std.stdtypedef import GetSetProperty, StdTypeDef +from pypy.objspace.std.unicodeobject import unicode_to_decimal_w +from rpython.rlib import jit, rcomplex +from rpython.rlib.rarithmetic import intmask, r_ulonglong from rpython.rlib.rbigint import rbigint from rpython.rlib.rfloat import ( - formatd, DTSF_STR_PRECISION, isinf, isnan, copysign) -from rpython.rlib import jit, rcomplex -from rpython.rlib.rarithmetic import intmask, r_ulonglong + formatd, DTSF_STR_PRECISION, isinf, isnan, copysign, string_to_float) +from rpython.rlib.rstring import ParseStringError +from rpython.tool.sourcetools import func_with_new_name HASH_IMAG = 1000003 -class W_AbstractComplexObject(W_Object): - __slots__ = () +def _split_complex(s): + slen = len(s) + if slen == 0: + raise ValueError + realstart = 0 + realstop = 0 + imagstart = 0 + imagstop = 0 + imagsign = ' ' + i = 0 + # ignore whitespace at beginning and end + while i < slen and s[i] == ' ': + i += 1 + while slen > 0 and s[slen-1] == ' ': + slen -= 1 - def is_w(self, space, w_other): - from rpython.rlib.longlong2float import float2longlong - if not isinstance(w_other, W_AbstractComplexObject): - return False - if self.user_overridden_class or w_other.user_overridden_class: - return self is w_other - real1 = space.float_w(space.getattr(self, space.wrap("real"))) - real2 = space.float_w(space.getattr(w_other, space.wrap("real"))) - imag1 = space.float_w(space.getattr(self, space.wrap("imag"))) - imag2 = space.float_w(space.getattr(w_other, space.wrap("imag"))) - real1 = float2longlong(real1) - real2 = float2longlong(real2) - imag1 = float2longlong(imag1) - imag2 = float2longlong(imag2) - return real1 == real2 and imag1 == imag2 + if s[i] == '(' and s[slen-1] == ')': + i += 1 + slen -= 1 + # ignore whitespace after bracket + while i < slen and s[i] == ' ': + i += 1 + while slen > 0 and s[slen-1] == ' ': + slen -= 1 - def immutable_unique_id(self, space): - if self.user_overridden_class: - return None - from rpython.rlib.longlong2float import float2longlong - from pypy.objspace.std.model import IDTAG_COMPLEX as tag - real = space.float_w(space.getattr(self, space.wrap("real"))) - imag = space.float_w(space.getattr(self, space.wrap("imag"))) - real_b = rbigint.fromrarith_int(float2longlong(real)) - imag_b = rbigint.fromrarith_int(r_ulonglong(float2longlong(imag))) - val = real_b.lshift(64).or_(imag_b).lshift(3).or_(rbigint.fromint(tag)) - return space.newlong_from_rbigint(val) + # extract first number + realstart = i + pc = s[i] + while i < slen and s[i] != ' ': + if s[i] in ('+', '-') and pc not in ('e', 'E') and i != realstart: + break + pc = s[i] + i += 1 + realstop = i -class W_ComplexObject(W_AbstractComplexObject): - """This is a reimplementation of the CPython "PyComplexObject" + # return appropriate strings is only one number is there + if i >= slen: + newstop = realstop - 1 + if newstop < 0: + raise ValueError + if s[newstop] in ('j', 'J'): + if realstart == newstop: + imagpart = '1.0' + elif realstart == newstop-1 and s[realstart] == '+': + imagpart = '1.0' + elif realstart == newstop-1 and s[realstart] == '-': + imagpart = '-1.0' + else: + imagpart = s[realstart:newstop] + return '0.0', imagpart + else: + return s[realstart:realstop], '0.0' + + # find sign for imaginary part + if s[i] == '-' or s[i] == '+': + imagsign = s[i] + else: + raise ValueError + + i += 1 + if i >= slen: + raise ValueError + + imagstart = i + pc = s[i] + while i < slen and s[i] != ' ': + if s[i] in ('+', '-') and pc not in ('e', 'E'): + break + pc = s[i] + i += 1 + + imagstop = i - 1 + if imagstop < 0: + raise ValueError + if s[imagstop] not in ('j', 'J'): + raise ValueError + if imagstop < imagstart: + raise ValueError + + if i < slen: + raise ValueError + + realpart = s[realstart:realstop] + if imagstart == imagstop: + imagpart = '1.0' + else: + imagpart = s[imagstart:imagstop] + if imagsign == '-': + imagpart = imagsign + imagpart + + return realpart, imagpart + + +def format_float(x, code, precision): + # like float2string, except that the ".0" is not necessary + if isinf(x): + if x > 0.0: + return "inf" + else: + return "-inf" + elif isnan(x): + return "nan" + else: + return formatd(x, code, precision) + +def repr_format(x): + return format_float(x, 'r', 0) + +def str_format(x): + return format_float(x, 'g', DTSF_STR_PRECISION) + + +def unpackcomplex(space, w_complex, strict_typing=True): """ - from pypy.objspace.std.complextype import complex_typedef as typedef + convert w_complex into a complex and return the unwrapped (real, imag) + tuple. If strict_typing==True, we also typecheck the value returned by + __complex__ to actually be a complex (and not e.g. a float). + See test___complex___returning_non_complex. + """ + if type(w_complex) is W_ComplexObject: + return (w_complex.realval, w_complex.imagval) + # + # test for a '__complex__' method, and call it if found. + w_z = None + w_method = space.lookup(w_complex, '__complex__') + if w_method is not None: + w_z = space.get_and_call_function(w_method, w_complex) + # + if w_z is not None: + # __complex__() must return a complex or (float,int,long) object + # (XXX should not use isinstance here) + if not strict_typing and (space.isinstance_w(w_z, space.w_int) or + space.isinstance_w(w_z, space.w_float)): + return (space.float_w(w_z), 0.0) + elif isinstance(w_z, W_ComplexObject): + return (w_z.realval, w_z.imagval) + raise oefmt(space.w_TypeError, + "__complex__() must return a complex number") + + # + # no '__complex__' method, so we assume it is a float, + # unless it is an instance of some subclass of complex. + if space.isinstance_w(w_complex, space.gettypefor(W_ComplexObject)): + real = space.float(space.getattr(w_complex, space.wrap("real"))) + imag = space.float(space.getattr(w_complex, space.wrap("imag"))) + return (space.float_w(real), space.float_w(imag)) + # + # Check that it is not a string (on which space.float() would succeed). + if (space.isinstance_w(w_complex, space.w_str) or + space.isinstance_w(w_complex, space.w_unicode)): + raise oefmt(space.w_TypeError, + "complex number expected, got '%T'", w_complex) + # + return (space.float_w(space.float(w_complex)), 0.0) + + +class W_ComplexObject(W_Root): _immutable_fields_ = ['realval', 'imagval'] def __init__(self, realval=0.0, imgval=0.0): @@ -63,7 +187,7 @@ def __repr__(self): """ representation for debugging purposes """ - return "<W_ComplexObject(%f,%f)>" % (self.realval, self.imagval) + return "<W_ComplexObject(%f, %f)>" % (self.realval, self.imagval) def as_tuple(self): return (self.realval, self.imagval) @@ -104,162 +228,331 @@ return w_result + def is_w(self, space, w_other): + from rpython.rlib.longlong2float import float2longlong + if not isinstance(w_other, W_ComplexObject): + return False + if self.user_overridden_class or w_other.user_overridden_class: + return self is w_other + real1 = space.float_w(space.getattr(self, space.wrap("real"))) + real2 = space.float_w(space.getattr(w_other, space.wrap("real"))) + imag1 = space.float_w(space.getattr(self, space.wrap("imag"))) + imag2 = space.float_w(space.getattr(w_other, space.wrap("imag"))) + real1 = float2longlong(real1) + real2 = float2longlong(real2) + imag1 = float2longlong(imag1) + imag2 = float2longlong(imag2) + return real1 == real2 and imag1 == imag2 + + def immutable_unique_id(self, space): + if self.user_overridden_class: + return None + from rpython.rlib.longlong2float import float2longlong + from pypy.objspace.std.model import IDTAG_COMPLEX as tag + real = space.float_w(space.getattr(self, space.wrap("real"))) + imag = space.float_w(space.getattr(self, space.wrap("imag"))) + real_b = rbigint.fromrarith_int(float2longlong(real)) + imag_b = rbigint.fromrarith_int(r_ulonglong(float2longlong(imag))) + val = real_b.lshift(64).or_(imag_b).lshift(3).or_(rbigint.fromint(tag)) + return space.newlong_from_rbigint(val) + def int(self, space): - raise OperationError(space.w_TypeError, space.wrap("can't convert complex to int; use int(abs(z))")) + raise oefmt(space.w_TypeError, + "can't convert complex to int; use int(abs(z))") -registerimplementation(W_ComplexObject) + def _to_complex(self, space, w_obj): + if isinstance(w_obj, W_ComplexObject): + return w_obj + if space.isinstance_w(w_obj, space.w_int): + w_float = space.float_w(w_obj) + return W_ComplexObject(w_float, 0.0) + if space.isinstance_w(w_obj, space.w_float): + return W_ComplexObject(space.float_w(w_obj), 0.0) + + @staticmethod + @unwrap_spec(w_real=WrappedDefault(0.0)) + def descr__new__(space, w_complextype, w_real, w_imag=None): + # if w_real is already a complex number and there is no second + # argument, return it. Note that we cannot return w_real if + # it is an instance of a *subclass* of complex, or if w_complextype + # is itself a subclass of complex. + noarg2 = w_imag is None + if (noarg2 and space.is_w(w_complextype, space.w_complex) + and space.is_w(space.type(w_real), space.w_complex)): + return w_real + + if space.isinstance_w(w_real, space.w_unicode): + # a string argument + if not noarg2: + raise oefmt(space.w_TypeError, "complex() can't take second" + " arg if first is a string") + unistr = unicode_to_decimal_w(space, w_real) + try: + realstr, imagstr = _split_complex(unistr) + except ValueError: + raise oefmt(space.w_ValueError, + "complex() arg is a malformed string") + try: + realval = string_to_float(realstr) + imagval = string_to_float(imagstr) + except ParseStringError: + raise oefmt(space.w_ValueError, + "complex() arg is a malformed string") + + else: + # non-string arguments + realval, imagval = unpackcomplex(space, w_real, + strict_typing=False) + + # now take w_imag into account + if not noarg2: + # complex(x, y) == x+y*j, even if 'y' is already a complex. + realval2, imagval2 = unpackcomplex(space, w_imag, + strict_typing=False) + + # try to preserve the signs of zeroes of realval and realval2 + if imagval2 != 0.0: + realval -= imagval2 + + if imagval != 0.0: + imagval += realval2 + else: + imagval = realval2 + # done + w_obj = space.allocate_instance(W_ComplexObject, w_complextype) + W_ComplexObject.__init__(w_obj, realval, imagval) + return w_obj + + def descr___getnewargs__(self, space): + return space.newtuple([space.newfloat(self.realval), + space.newfloat(self.imagval)]) + + def descr_repr(self, space): + if self.realval == 0 and copysign(1., self.realval) == 1.: + return space.wrap(repr_format(self.imagval) + 'j') + sign = (copysign(1., self.imagval) == 1. or + isnan(self.imagval)) and '+' or '' + return space.wrap('(' + repr_format(self.realval) + + sign + repr_format(self.imagval) + 'j)') + + def descr_str(self, space): + if self.realval == 0 and copysign(1., self.realval) == 1.: + return space.wrap(str_format(self.imagval) + 'j') + sign = (copysign(1., self.imagval) == 1. or + isnan(self.imagval)) and '+' or '' + return space.wrap('(' + str_format(self.realval) + + sign + str_format(self.imagval) + 'j)') + + def descr_hash(self, space): + hashreal = _hash_float(space, self.realval) + hashimg = _hash_float(space, self.imagval) + combined = intmask(hashreal + HASH_IMAG * hashimg) + return space.newint(-2 if combined == -1 else combined) + + def descr_format(self, space, w_format_spec): + return newformat.run_formatter(space, w_format_spec, "format_complex", + self) + + def descr_bool(self, space): + return space.newbool((self.realval != 0.0) or (self.imagval != 0.0)) + + def descr_float(self, space): + raise oefmt(space.w_TypeError, + "can't convert complex to float; use abs(z)") + + def descr_neg(self, space): + return W_ComplexObject(-self.realval, -self.imagval) + + def descr_pos(self, space): + return W_ComplexObject(self.realval, self.imagval) + + def descr_abs(self, space): + try: + return space.newfloat(math.hypot(self.realval, self.imagval)) + except OverflowError, e: + raise OperationError(space.w_OverflowError, space.wrap(str(e))) + + def descr_eq(self, space, w_other): + if isinstance(w_other, W_ComplexObject): + return space.newbool((self.realval == w_other.realval) and + (self.imagval == w_other.imagval)) + if (space.isinstance_w(w_other, space.w_int) or + space.isinstance_w(w_other, space.w_float)): + if self.imagval: + return space.w_False + return space.eq(space.newfloat(self.realval), w_other) + return space.w_NotImplemented + + def descr_ne(self, space, w_other): + if isinstance(w_other, W_ComplexObject): + return space.newbool((self.realval != w_other.realval) or + (self.imagval != w_other.imagval)) + if (space.isinstance_w(w_other, space.w_int)): + if self.imagval: + return space.w_True + return space.ne(space.newfloat(self.realval), w_other) + return space.w_NotImplemented + + def _fail_cmp(self, space, w_other): + return space.w_NotImplemented + + def descr_add(self, space, w_rhs): + w_rhs = self._to_complex(space, w_rhs) + if w_rhs is None: + return space.w_NotImplemented + return W_ComplexObject(self.realval + w_rhs.realval, + self.imagval + w_rhs.imagval) + + def descr_radd(self, space, w_lhs): + w_lhs = self._to_complex(space, w_lhs) + if w_lhs is None: + return space.w_NotImplemented + return W_ComplexObject(w_lhs.realval + self.realval, + w_lhs.imagval + self.imagval) + + def descr_sub(self, space, w_rhs): + w_rhs = self._to_complex(space, w_rhs) + if w_rhs is None: + return space.w_NotImplemented + return W_ComplexObject(self.realval - w_rhs.realval, + self.imagval - w_rhs.imagval) + + def descr_rsub(self, space, w_lhs): + w_lhs = self._to_complex(space, w_lhs) + if w_lhs is None: + return space.w_NotImplemented + return W_ComplexObject(w_lhs.realval - self.realval, + w_lhs.imagval - self.imagval) + + def descr_mul(self, space, w_rhs): + w_rhs = self._to_complex(space, w_rhs) + if w_rhs is None: + return space.w_NotImplemented + return self.mul(w_rhs) + + def descr_rmul(self, space, w_lhs): + w_lhs = self._to_complex(space, w_lhs) + if w_lhs is None: + return space.w_NotImplemented + return w_lhs.mul(self) + + def descr_truediv(self, space, w_rhs): + w_rhs = self._to_complex(space, w_rhs) + if w_rhs is None: + return space.w_NotImplemented + try: + return self.div(w_rhs) + except ZeroDivisionError, e: + raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e))) + + def descr_rtruediv(self, space, w_lhs): + w_lhs = self._to_complex(space, w_lhs) + if w_lhs is None: + return space.w_NotImplemented + try: + return w_lhs.div(self) + except ZeroDivisionError, e: + raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e))) + + def descr_floordiv(self, space, w_rhs): + raise oefmt(space.w_TypeError, "can't take floor of complex number.") + descr_rfloordiv = func_with_new_name(descr_floordiv, 'descr_rfloordiv') + + def descr_mod(self, space, w_rhs): + raise oefmt(space.w_TypeError, "can't mod complex numbers.") + descr_rmod = func_with_new_name(descr_mod, 'descr_rmod') + + def descr_divmod(self, space, w_rhs): + raise oefmt(space.w_TypeError, + "can't take floor or mod of complex number.") + descr_rdivmod = func_with_new_name(descr_divmod, 'descr_rdivmod') + + @unwrap_spec(w_third_arg=WrappedDefault(None)) + def descr_pow(self, space, w_exponent, w_third_arg): + w_exponent = self._to_complex(space, w_exponent) + if w_exponent is None: + return space.w_NotImplemented + if not space.is_w(w_third_arg, space.w_None): + raise oefmt(space.w_ValueError, 'complex modulo') + try: + r = w_exponent.realval + if (w_exponent.imagval == 0.0 and -100.0 <= r <= 100.0 and + r == int(r)): + w_p = self.pow_small_int(int(r)) + else: + w_p = self.pow(w_exponent) + except ZeroDivisionError: + raise oefmt(space.w_ZeroDivisionError, + "0.0 to a negative or complex power") + except OverflowError: + raise oefmt(space.w_OverflowError, "complex exponentiation") + return w_p + + @unwrap_spec(w_third_arg=WrappedDefault(None)) + def descr_rpow(self, space, w_lhs, w_third_arg): + w_lhs = self._to_complex(space, w_lhs) + if w_lhs is None: + return space.w_NotImplemented + return w_lhs.descr_pow(space, self, w_third_arg) + + def descr_conjugate(self, space): + """(A+Bj).conjugate() -> A-Bj""" + return space.newcomplex(self.realval, -self.imagval) + w_one = W_ComplexObject(1, 0) -def delegate_Bool2Complex(space, w_bool): - return W_ComplexObject(w_bool.intval, 0.0) +def complexwprop(name, doc): + def fget(space, w_obj): + if not isinstance(w_obj, W_ComplexObject): + raise oefmt(space.w_TypeError, "descriptor is for 'complex'") + return space.newfloat(getattr(w_obj, name)) + return GetSetProperty(fget, doc=doc) -def delegate_Int2Complex(space, w_int): - return W_ComplexObject(w_int.intval, 0.0) +W_ComplexObject.typedef = StdTypeDef("complex", + __doc__ = """complex(real[, imag]) -> complex number -def delegate_Long2Complex(space, w_long): - dval = w_long.tofloat(space) - return W_ComplexObject(dval, 0.0) +Create a complex number from a real part and an optional imaginary part. +This is equivalent to (real + imag*1j) where imag defaults to 0.""", + __new__ = interp2app(W_ComplexObject.descr__new__), + __getnewargs__ = interp2app(W_ComplexObject.descr___getnewargs__), + real = complexwprop('realval', doc="the real part of a complex number"), + imag = complexwprop('imagval', + doc="the imaginary part of a complex number"), + __repr__ = interp2app(W_ComplexObject.descr_repr), + __str__ = interp2app(W_ComplexObject.descr_str), + __hash__ = interp2app(W_ComplexObject.descr_hash), + __format__ = interp2app(W_ComplexObject.descr_format), + __bool__ = interp2app(W_ComplexObject.descr_bool), + __float__ = interp2app(W_ComplexObject.descr_float), + __neg__ = interp2app(W_ComplexObject.descr_neg), + __pos__ = interp2app(W_ComplexObject.descr_pos), + __abs__ = interp2app(W_ComplexObject.descr_abs), -def delegate_Float2Complex(space, w_float): - return W_ComplexObject(w_float.floatval, 0.0) + __eq__ = interp2app(W_ComplexObject.descr_eq), + __ne__ = interp2app(W_ComplexObject.descr_ne), + __lt__ = interp2app(W_ComplexObject._fail_cmp), + __le__ = interp2app(W_ComplexObject._fail_cmp), + __gt__ = interp2app(W_ComplexObject._fail_cmp), + __ge__ = interp2app(W_ComplexObject._fail_cmp), -def hash__Complex(space, w_value): - hashreal = _hash_float(space, w_value.realval) - hashimg = _hash_float(space, w_value.imagval) - combined = intmask(hashreal + HASH_IMAG * hashimg) - return space.newint(-2 if combined == -1 else combined) + __add__ = interp2app(W_ComplexObject.descr_add), + __radd__ = interp2app(W_ComplexObject.descr_radd), + __sub__ = interp2app(W_ComplexObject.descr_sub), + __rsub__ = interp2app(W_ComplexObject.descr_rsub), + __mul__ = interp2app(W_ComplexObject.descr_mul), + __rmul__ = interp2app(W_ComplexObject.descr_rmul), + __truediv__ = interp2app(W_ComplexObject.descr_truediv), + __rtruediv__ = interp2app(W_ComplexObject.descr_rtruediv), + __floordiv__ = interp2app(W_ComplexObject.descr_floordiv), + __rfloordiv__ = interp2app(W_ComplexObject.descr_rfloordiv), + __mod__ = interp2app(W_ComplexObject.descr_mod), + __rmod__ = interp2app(W_ComplexObject.descr_rmod), + __divmod__ = interp2app(W_ComplexObject.descr_divmod), + __rdivmod__ = interp2app(W_ComplexObject.descr_rdivmod), + __pow__ = interp2app(W_ComplexObject.descr_pow), + __rpow__ = interp2app(W_ComplexObject.descr_rpow), -def add__Complex_Complex(space, w_complex1, w_complex2): - return W_ComplexObject(w_complex1.realval + w_complex2.realval, - w_complex1.imagval + w_complex2.imagval) - -def sub__Complex_Complex(space, w_complex1, w_complex2): - return W_ComplexObject(w_complex1.realval - w_complex2.realval, - w_complex1.imagval - w_complex2.imagval) - -def mul__Complex_Complex(space, w_complex1, w_complex2): - return w_complex1.mul(w_complex2) - -def div__Complex_Complex(space, w_complex1, w_complex2): - try: - return w_complex1.div(w_complex2) - except ZeroDivisionError, e: - raise OperationError(space.w_ZeroDivisionError, space.wrap(str(e))) - -truediv__Complex_Complex = div__Complex_Complex - -def pow__Complex_Complex_ANY(space, w_complex, w_exponent, thirdArg): - if not space.is_w(thirdArg, space.w_None): - raise OperationError(space.w_ValueError, space.wrap('complex modulo')) - try: - r = w_exponent.realval - if w_exponent.imagval == 0.0 and -100.0 <= r <= 100.0 and r == int(r): - w_p = w_complex.pow_small_int(int(r)) - else: - w_p = w_complex.pow(w_exponent) - except ZeroDivisionError: - raise OperationError(space.w_ZeroDivisionError, space.wrap("0.0 to a negative or complex power")) - except OverflowError: - raise OperationError(space.w_OverflowError, space.wrap("complex exponentiation")) - return w_p - -def neg__Complex(space, w_complex): - return W_ComplexObject(-w_complex.realval, -w_complex.imagval) - -def pos__Complex(space, w_complex): - return W_ComplexObject(w_complex.realval, w_complex.imagval) - -def abs__Complex(space, w_complex): - try: - return space.newfloat(math.hypot(w_complex.realval, w_complex.imagval)) - except OverflowError, e: - raise OperationError(space.w_OverflowError, space.wrap(str(e))) - -def eq__Complex_Complex(space, w_complex1, w_complex2): - return space.newbool((w_complex1.realval == w_complex2.realval) and - (w_complex1.imagval == w_complex2.imagval)) - -def ne__Complex_Complex(space, w_complex1, w_complex2): - return space.newbool((w_complex1.realval != w_complex2.realval) or - (w_complex1.imagval != w_complex2.imagval)) - -def eq__Complex_Long(space, w_complex1, w_long2): - if w_complex1.imagval: - return space.w_False - return space.eq(space.newfloat(w_complex1.realval), w_long2) -eq__Complex_Int = eq__Complex_Long - -def eq__Long_Complex(space, w_long1, w_complex2): - return eq__Complex_Long(space, w_complex2, w_long1) -eq__Int_Complex = eq__Long_Complex - -def ne__Complex_Long(space, w_complex1, w_long2): - if w_complex1.imagval: - return space.w_True - return space.ne(space.newfloat(w_complex1.realval), w_long2) -ne__Complex_Int = ne__Complex_Long - -def ne__Long_Complex(space, w_long1, w_complex2): - return ne__Complex_Long(space, w_complex2, w_long1) -ne__Int_Complex = ne__Long_Complex - -def lt__Complex_Complex(space, w_complex1, w_complex2): - from pypy.objspace.std.model import FailedToImplement - raise FailedToImplement - -gt__Complex_Complex = lt__Complex_Complex -ge__Complex_Complex = lt__Complex_Complex -le__Complex_Complex = lt__Complex_Complex - -def nonzero__Complex(space, w_complex): - return space.newbool((w_complex.realval != 0.0) or - (w_complex.imagval != 0.0)) - -def float__Complex(space, w_complex): - raise OperationError(space.w_TypeError, space.wrap("can't convert complex to float; use abs(z)")) - -def complex_conjugate__Complex(space, w_self): - #w_real = space.call_function(space.w_float,space.wrap(w_self.realval)) - #w_imag = space.call_function(space.w_float,space.wrap(-w_self.imagval)) - return space.newcomplex(w_self.realval,-w_self.imagval) - -def format_float(x, code, precision): - # like float2string, except that the ".0" is not necessary - if isinf(x): - if x > 0.0: - return "inf" - else: - return "-inf" - elif isnan(x): - return "nan" - else: - return formatd(x, code, precision) - -def repr_format(x): - return format_float(x, 'r', 0) -def str_format(x): - return format_float(x, 'g', DTSF_STR_PRECISION) - -def repr__Complex(space, w_complex): - if w_complex.realval == 0 and copysign(1., w_complex.realval) == 1.: - return space.wrap(repr_format(w_complex.imagval) + 'j') - sign = (copysign(1., w_complex.imagval) == 1. or - isnan(w_complex.imagval)) and '+' or '' - return space.wrap('(' + repr_format(w_complex.realval) - + sign + repr_format(w_complex.imagval) + 'j)') - -def str__Complex(space, w_complex): - if w_complex.realval == 0 and copysign(1., w_complex.realval) == 1.: - return space.wrap(str_format(w_complex.imagval) + 'j') - sign = (copysign(1., w_complex.imagval) == 1. or - isnan(w_complex.imagval)) and '+' or '' - return space.wrap('(' + str_format(w_complex.realval) - + sign + str_format(w_complex.imagval) + 'j)') - -def format__Complex_ANY(space, w_complex, w_format_spec): - return newformat.run_formatter(space, w_format_spec, "format_complex", w_complex) - -from pypy.objspace.std import complextype -register_all(vars(), complextype) + conjugate = interp2app(W_ComplexObject.descr_conjugate), +) diff --git a/pypy/objspace/std/complextype.py b/pypy/objspace/std/complextype.py deleted file mode 100644 --- a/pypy/objspace/std/complextype.py +++ /dev/null @@ -1,240 +0,0 @@ -from pypy.interpreter.error import OperationError, oefmt -from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.stdtypedef import GetSetProperty, StdTypeDef -from pypy.objspace.std.stdtypedef import StdObjSpaceMultiMethod -from pypy.objspace.std.unicodeobject import unicode_to_decimal_w -from rpython.rlib.rfloat import string_to_float -from rpython.rlib.rstring import ParseStringError - -# ERRORCODES - -ERR_WRONG_SECOND = "complex() can't take second arg if first is a string" -ERR_MALFORMED = "complex() arg is a malformed string" - -complex_conjugate = StdObjSpaceMultiMethod('conjugate', 1, - doc="(A+Bj).conjugate() -> A-Bj") - -register_all(vars(),globals()) - -def _split_complex(s): - slen = len(s) - if slen == 0: - raise ValueError - realstart = 0 - realstop = 0 - imagstart = 0 - imagstop = 0 - imagsign = ' ' - i = 0 - # ignore whitespace at beginning and end - while i < slen and s[i] == ' ': - i += 1 - while slen > 0 and s[slen-1] == ' ': - slen -= 1 - - if s[i] == '(' and s[slen-1] == ')': - i += 1 - slen -= 1 - # ignore whitespace after bracket - while i < slen and s[i] == ' ': - i += 1 - while slen > 0 and s[slen-1] == ' ': - slen -= 1 - - # extract first number - realstart = i - pc = s[i] - while i < slen and s[i] != ' ': - if s[i] in ('+', '-') and pc not in ('e', 'E') and i != realstart: - break - pc = s[i] - i += 1 - - realstop = i - - # return appropriate strings is only one number is there - if i >= slen: - newstop = realstop - 1 - if newstop < 0: - raise ValueError - if s[newstop] in ('j', 'J'): - if realstart == newstop: - imagpart = '1.0' - elif realstart == newstop-1 and s[realstart] == '+': - imagpart = '1.0' - elif realstart == newstop-1 and s[realstart] == '-': - imagpart = '-1.0' - else: - imagpart = s[realstart:newstop] - return '0.0', imagpart - else: - return s[realstart:realstop], '0.0' - - # find sign for imaginary part - if s[i] == '-' or s[i] == '+': - imagsign = s[i] - else: - raise ValueError - - i += 1 - if i >= slen: - raise ValueError - - imagstart = i - pc = s[i] - while i < slen and s[i] != ' ': - if s[i] in ('+', '-') and pc not in ('e', 'E'): - break - pc = s[i] - i += 1 - - imagstop = i - 1 - if imagstop < 0: - raise ValueError - if s[imagstop] not in ('j', 'J'): - raise ValueError - if imagstop < imagstart: - raise ValueError - - if i < slen: - raise ValueError - - realpart = s[realstart:realstop] - if imagstart == imagstop: - imagpart = '1.0' - else: - imagpart = s[imagstart:imagstop] - if imagsign == '-': - imagpart = imagsign + imagpart - - return realpart, imagpart - - -@unwrap_spec(w_real = WrappedDefault(0.0)) -def descr__new__(space, w_complextype, w_real, w_imag=None): - from pypy.objspace.std.complexobject import W_ComplexObject - - # if w_real is already a complex number and there is no second - # argument, return it. Note that we cannot return w_real if - # it is an instance of a *subclass* of complex, or if w_complextype - # is itself a subclass of complex. - noarg2 = w_imag is None - if (noarg2 and space.is_w(w_complextype, space.w_complex) - and space.is_w(space.type(w_real), space.w_complex)): - return w_real - - if space.isinstance_w(w_real, space.w_unicode): - # a string argument - if not noarg2: - raise OperationError(space.w_TypeError, - space.wrap("complex() can't take second arg" - " if first is a string")) - unistr = unicode_to_decimal_w(space, w_real) - try: - realstr, imagstr = _split_complex(unistr) - except ValueError: - raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED)) - try: - realval = string_to_float(realstr) - imagval = string_to_float(imagstr) - except ParseStringError: - raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED)) - - else: - # non-string arguments - realval, imagval = unpackcomplex(space, w_real, strict_typing=False) - - # now take w_imag into account - if not noarg2: - # complex(x, y) == x+y*j, even if 'y' is already a complex. - realval2, imagval2 = unpackcomplex(space, w_imag, strict_typing=False) - - # try to preserve the signs of zeroes of realval and realval2 - if imagval2 != 0.0: - realval -= imagval2 - - if imagval != 0.0: - imagval += realval2 - else: - imagval = realval2 - # done - w_obj = space.allocate_instance(W_ComplexObject, w_complextype) - W_ComplexObject.__init__(w_obj, realval, imagval) - return w_obj - - -def unpackcomplex(space, w_complex, strict_typing=True): - """ - convert w_complex into a complex and return the unwrapped (real, imag) - tuple. If strict_typing==True, we also typecheck the value returned by - __complex__ to actually be a complex (and not e.g. a float). - See test___complex___returning_non_complex. - """ - from pypy.objspace.std.complexobject import W_ComplexObject - if type(w_complex) is W_ComplexObject: - return (w_complex.realval, w_complex.imagval) - # - # test for a '__complex__' method, and call it if found. - w_z = None - w_method = space.lookup(w_complex, '__complex__') - if w_method is not None: - w_z = space.get_and_call_function(w_method, w_complex) - # - if w_z is not None: - # __complex__() must return a complex or (float,int,long) object - # (XXX should not use isinstance here) - if not strict_typing and (space.isinstance_w(w_z, space.w_int) or - space.isinstance_w(w_z, space.w_float)): - return (space.float_w(w_z), 0.0) - elif isinstance(w_z, W_ComplexObject): - return (w_z.realval, w_z.imagval) - raise OperationError(space.w_TypeError, - space.wrap("__complex__() must return" - " a complex number")) - - # - # no '__complex__' method, so we assume it is a float, - # unless it is an instance of some subclass of complex. - if space.isinstance_w(w_complex, space.gettypefor(W_ComplexObject)): - real = space.float(space.getattr(w_complex, space.wrap("real"))) - imag = space.float(space.getattr(w_complex, space.wrap("imag"))) - return (space.float_w(real), space.float_w(imag)) - # - # Check that it is not a string (on which space.float() would succeed). - if (space.isinstance_w(w_complex, space.w_str) or - space.isinstance_w(w_complex, space.w_unicode)): - raise oefmt(space.w_TypeError, - "complex number expected, got '%T'", w_complex) - # - return (space.float_w(space.float(w_complex)), 0.0) - - -def complexwprop(name, doc): - def fget(space, w_obj): - from pypy.objspace.std.complexobject import W_ComplexObject - if not isinstance(w_obj, W_ComplexObject): - raise OperationError(space.w_TypeError, - space.wrap("descriptor is for 'complex'")) - return space.newfloat(getattr(w_obj, name)) - return GetSetProperty(fget, doc=doc) - -def descr___getnewargs__(space, w_self): - from pypy.objspace.std.complexobject import W_ComplexObject - assert isinstance(w_self, W_ComplexObject) - return space.newtuple([space.newfloat(w_self.realval), - space.newfloat(w_self.imagval)]) - -complex_typedef = StdTypeDef("complex", - __doc__ = """complex(real[, imag]) -> complex number - -Create a complex number from a real part and an optional imaginary part. -This is equivalent to (real + imag*1j) where imag defaults to 0.""", - __new__ = interp2app(descr__new__), - __getnewargs__ = interp2app(descr___getnewargs__), - real = complexwprop('realval', doc="the real part of a complex number"), - imag = complexwprop('imagval', - doc="the imaginary part of a complex number"), - ) - -complex_typedef.registermethods(globals()) diff --git a/pypy/objspace/std/default.py b/pypy/objspace/std/default.py deleted file mode 100644 --- a/pypy/objspace/std/default.py +++ /dev/null @@ -1,11 +0,0 @@ -"""Default implementation for some operation.""" - -from pypy.objspace.std.register_all import register_all - - -# __init__ should succeed if called internally as a multimethod - -def init__ANY(space, w_obj, __args__): - pass - -register_all(vars()) diff --git a/pypy/objspace/std/dictproxyobject.py b/pypy/objspace/std/dictproxyobject.py --- a/pypy/objspace/std/dictproxyobject.py +++ b/pypy/objspace/std/dictproxyobject.py @@ -1,5 +1,3 @@ -#from pypy.objspace.std.model import registerimplementation, W_Object -#from pypy.objspace.std.register_all import register_all from pypy.objspace.std.dictmultiobject import DictStrategy, create_iterator_classes from pypy.objspace.std.typeobject import unwrap_cell from pypy.interpreter.error import OperationError, oefmt diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py --- a/pypy/objspace/std/floatobject.py +++ b/pypy/objspace/std/floatobject.py @@ -1,139 +1,35 @@ import math import operator +import sys +from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError, oefmt +from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault +from pypy.interpreter.typedef import GetSetProperty from pypy.objspace.std import newformat -from pypy.objspace.std.floattype import float_typedef, W_AbstractFloatObject -from pypy.objspace.std.intobject import HASH_BITS, HASH_MODULUS -from pypy.objspace.std.multimethod import FailedToImplementArgs -from pypy.objspace.std.model import registerimplementation, W_Object -from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.longobject import W_LongObject, newlong_from_float -from pypy.objspace.std.noneobject import W_NoneObject +from pypy.objspace.std.intobject import HASH_BITS, HASH_MODULUS, W_IntObject +from pypy.objspace.std.longobject import ( + W_AbstractLongObject, newlong_from_float) from rpython.rlib.rarithmetic import ( LONG_BIT, intmask, ovfcheck_float_to_int, r_uint) +from pypy.objspace.std.stdtypedef import StdTypeDef +from pypy.objspace.std.util import wrap_parsestringerror +from rpython.rlib import rarithmetic, rfloat +from rpython.rlib.rbigint import rbigint from rpython.rlib.rfloat import ( isinf, isnan, isfinite, INFINITY, NAN, copysign, formatd, DTSF_ADD_DOT_0, float_as_rbigint_ratio) -from rpython.rlib.rbigint import rbigint -from rpython.rlib import rfloat +from rpython.rlib.rstring import ParseStringError from rpython.tool.sourcetools import func_with_new_name +from rpython.rlib.unroll import unrolling_iterable from rpython.rtyper.lltypesystem.module.ll_math import math_fmod -from pypy.objspace.std.intobject import W_IntObject - HASH_INF = 314159 HASH_NAN = 0 -class W_FloatObject(W_AbstractFloatObject): - """This is a implementation of the app-level 'float' type. - The constructor takes an RPython float as an argument.""" - _immutable_fields_ = ['floatval'] - - typedef = float_typedef - - def __init__(self, floatval): - self.floatval = floatval - - def unwrap(self, space): - return self.floatval - - def int_w(self, space, allow_conversion=True): - self._typed_unwrap_error(space, "integer") - - def bigint_w(self, space, allow_conversion=True): - self._typed_unwrap_error(space, "integer") - - def float_w(self, space, allow_conversion=True): - return self.floatval - - def _float_w(self, space): - return self.floatval - - def int(self, space): - if (type(self) is not W_FloatObject and - space.is_overloaded(self, space.w_float, '__int__')): - return W_Object.int(self, space) - try: - value = ovfcheck_float_to_int(self.floatval) - except OverflowError: - return newlong_from_float(space, self.floatval) - else: - return space.newint(value) - - def __repr__(self): - return "<W_FloatObject(%f)>" % self.floatval - -registerimplementation(W_FloatObject) - -# bool-to-float delegation -def delegate_Bool2Float(space, w_bool): - return W_FloatObject(float(w_bool.intval)) - -# int-to-float delegation -def delegate_Int2Float(space, w_intobj): - return W_FloatObject(float(w_intobj.intval)) - -# long-to-float delegation -def delegate_Long2Float(space, w_longobj): - return W_FloatObject(w_longobj.tofloat(space)) - - -# float__Float is supposed to do nothing, unless it has -# a derived float object, where it should return -# an exact one. -def float__Float(space, w_float1): - if space.is_w(space.type(w_float1), space.w_float): - return w_float1 - a = w_float1.floatval - return W_FloatObject(a) - -def trunc__Float(space, w_floatobj): - whole = math.modf(w_floatobj.floatval)[1] - try: - value = ovfcheck_float_to_int(whole) - except OverflowError: - return newlong_from_float(space, whole) - else: - return space.newint(value) - -def _char_from_hex(number): - return "0123456789abcdef"[number] - -TOHEX_NBITS = rfloat.DBL_MANT_DIG + 3 - (rfloat.DBL_MANT_DIG + 2) % 4 - -def float_hex__Float(space, w_float): - value = w_float.floatval - if not isfinite(value): - return str__Float(space, w_float) - if value == 0.0: - if copysign(1., value) == -1.: - return space.wrap("-0x0.0p+0") - else: - return space.wrap("0x0.0p+0") - mant, exp = math.frexp(value) - shift = 1 - max(rfloat.DBL_MIN_EXP - exp, 0) - mant = math.ldexp(mant, shift) - mant = abs(mant) - exp -= shift - result = ['\0'] * ((TOHEX_NBITS - 1) // 4 + 2) - result[0] = _char_from_hex(int(mant)) - mant -= int(mant) - result[1] = "." - for i in range((TOHEX_NBITS - 1) // 4): - mant *= 16.0 - result[i + 2] = _char_from_hex(int(mant)) - mant -= int(mant) - if exp < 0: - sign = "-" - else: - sign = "+" - exp = abs(exp) - s = ''.join(result) - if value < 0.0: - return space.wrap("-0x%sp%s%d" % (s, sign, exp)) - else: - return space.wrap("0x%sp%s%d" % (s, sign, exp)) +# Here 0.30103 is an upper bound for log10(2) +NDIGITS_MAX = int((rfloat.DBL_MANT_DIG - rfloat.DBL_MIN_EXP) * 0.30103) +NDIGITS_MIN = -int((rfloat.DBL_MAX_EXP + 1) * 0.30103) def float2string(x, code, precision): # we special-case explicitly inf and nan here @@ -148,34 +44,60 @@ s = "nan" return s -def repr__Float(space, w_float): - return space.wrap(float2string(w_float.floatval, 'r', 0)) -str__Float = repr__Float +def detect_floatformat(): + from rpython.rtyper.lltypesystem import rffi, lltype + buf = lltype.malloc(rffi.CCHARP.TO, 8, flavor='raw') + rffi.cast(rffi.DOUBLEP, buf)[0] = 9006104071832581.0 + packed = rffi.charpsize2str(buf, 8) + if packed == "\x43\x3f\xff\x01\x02\x03\x04\x05": + double_format = 'IEEE, big-endian' + elif packed == "\x05\x04\x03\x02\x01\xff\x3f\x43": + double_format = 'IEEE, little-endian' + else: + double_format = 'unknown' + lltype.free(buf, flavor='raw') + # + buf = lltype.malloc(rffi.CCHARP.TO, 4, flavor='raw') + rffi.cast(rffi.FLOATP, buf)[0] = rarithmetic.r_singlefloat(16711938.0) + packed = rffi.charpsize2str(buf, 4) + if packed == "\x4b\x7f\x01\x02": + float_format = 'IEEE, big-endian' + elif packed == "\x02\x01\x7f\x4b": + float_format = 'IEEE, little-endian' + else: + float_format = 'unknown' + lltype.free(buf, flavor='raw') -def format__Float_ANY(space, w_float, w_spec): - return newformat.run_formatter(space, w_spec, "format_float", w_float) + return double_format, float_format -# ____________________________________________________________ -# A mess to handle all cases of float comparison without relying -# on delegation, which can unfortunately loose precision when -# casting an int or a long to a float. +_double_format, _float_format = detect_floatformat() -def list_compare_funcs(declarator): - for op in ['lt', 'le', 'eq', 'ne', 'gt', 'ge']: - func, name = declarator(op) - globals()[name] = func_with_new_name(func, name) -def _reverse(opname): - if opname[0] == 'l': return 'g' + opname[1:] - elif opname[0] == 'g': return 'l' + opname[1:] - else: return opname +_alpha = zip("abcdef", range(10, 16)) + zip("ABCDEF", range(10, 16)) +_hex_to_int = zip("0123456789", range(10)) + _alpha +_hex_to_int_iterable = unrolling_iterable(_hex_to_int) +def _hex_from_char(c): + for h, v in _hex_to_int_iterable: + if h == c: + return v + return -1 -def declare_compare_bigint(opname): - """Return a helper function that implements a float-bigint comparison.""" +def _hex_digit(s, j, co_end, float_digits): + if j < float_digits: + i = co_end - j + else: + i = co_end - 1 - j + return _hex_from_char(s[i]) + +def _char_from_hex(number): + return "0123456789abcdef"[number] + + +def make_compare_func(opname): op = getattr(operator, opname) - # + if opname == 'eq' or opname == 'ne': def do_compare_bigint(f1, b2): """f1 is a float. b2 is a bigint.""" @@ -201,73 +123,578 @@ f1 = math.floor(f1) b1 = rbigint.fromfloat(f1) return getattr(b1, opname)(b2) - # - return do_compare_bigint, 'compare_bigint_' + opname -list_compare_funcs(declare_compare_bigint) + def _compare(self, space, w_other): + if isinstance(w_other, W_FloatObject): + return space.newbool(op(self.floatval, w_other.floatval)) + if isinstance(w_other, W_IntObject): + f1 = self.floatval + i2 = space.int_w(w_other) + f2 = float(i2) + if LONG_BIT > 32 and int(f2) != i2: + res = do_compare_bigint(f1, rbigint.fromint(i2)) + else: + res = op(f1, f2) + return space.newbool(res) + if isinstance(w_other, W_AbstractLongObject): + return space.newbool(do_compare_bigint(self.floatval, + space.bigint_w(w_other))) + return space.w_NotImplemented + return func_with_new_name(_compare, 'descr_' + opname) -def declare_cmp_float_float(opname): - op = getattr(operator, opname) - def f(space, w_float1, w_float2): - f1 = w_float1.floatval - f2 = w_float2.floatval - return space.newbool(op(f1, f2)) - return f, opname + "__Float_Float" -list_compare_funcs(declare_cmp_float_float) -def declare_cmp_float_int(opname): - op = getattr(operator, opname) - compare = globals()['compare_bigint_' + opname] - def f(space, w_float1, w_int2): - f1 = w_float1.floatval - i2 = w_int2.intval - f2 = float(i2) - if LONG_BIT > 32 and int(f2) != i2: - res = compare(f1, rbigint.fromint(i2)) +class W_FloatObject(W_Root): + """This is a implementation of the app-level 'float' type. + The constructor takes an RPython float as an argument.""" + _immutable_fields_ = ['floatval'] + + def __init__(self, floatval): + self.floatval = floatval + + def unwrap(self, space): + return self.floatval + + def int_w(self, space, allow_conversion=True): + self._typed_unwrap_error(space, "integer") + + def bigint_w(self, space, allow_conversion=True): + self._typed_unwrap_error(space, "integer") + + def float_w(self, space, allow_conversion=True): + return self.floatval + + def _float_w(self, space): + return self.floatval + + def int(self, space): + if (type(self) is not W_FloatObject and + space.is_overloaded(self, space.w_float, '__int__')): + return W_Root.int(self, space) + try: + value = ovfcheck_float_to_int(self.floatval) + except OverflowError: + return newlong_from_float(space, self.floatval) else: - res = op(f1, f2) - return space.newbool(res) - return f, opname + "__Float_Int" -list_compare_funcs(declare_cmp_float_int) + return space.newint(value) -def declare_cmp_float_long(opname): - compare = globals()['compare_bigint_' + opname] - def f(space, w_float1, w_long2): - f1 = w_float1.floatval - b2 = w_long2.num - return space.newbool(compare(f1, b2)) - return f, opname + "__Float_Long" -list_compare_funcs(declare_cmp_float_long) + def is_w(self, space, w_other): + from rpython.rlib.longlong2float import float2longlong + if not isinstance(w_other, W_FloatObject): + return False + if self.user_overridden_class or w_other.user_overridden_class: + return self is w_other + one = float2longlong(space.float_w(self)) + two = float2longlong(space.float_w(w_other)) + return one == two -def declare_cmp_int_float(opname): - op = getattr(operator, opname) - revcompare = globals()['compare_bigint_' + _reverse(opname)] - def f(space, w_int1, w_float2): - f2 = w_float2.floatval - i1 = w_int1.intval - f1 = float(i1) - if LONG_BIT > 32 and int(f1) != i1: - res = revcompare(f2, rbigint.fromint(i1)) + def immutable_unique_id(self, space): + if self.user_overridden_class: + return None + from rpython.rlib.longlong2float import float2longlong + from pypy.objspace.std.model import IDTAG_FLOAT as tag + val = float2longlong(space.float_w(self)) + b = rbigint.fromrarith_int(val) + b = b.lshift(3).or_(rbigint.fromint(tag)) + return space.newlong_from_rbigint(b) + + def __repr__(self): + return "<W_FloatObject(%f)>" % self.floatval + + @staticmethod + @unwrap_spec(w_x=WrappedDefault(0.0)) + def descr__new__(space, w_floattype, w_x): + def _string_to_float(space, w_source, string): + try: + return rfloat.string_to_float(string) + except ParseStringError as e: + raise wrap_parsestringerror(space, e, w_source) + + w_value = w_x # 'x' is the keyword argument name in CPython + if space.lookup(w_value, "__float__") is not None: + w_obj = space.float(w_value) + if space.is_w(w_floattype, space.w_float): + return w_obj + value = space.float_w(w_obj) + elif space.isinstance_w(w_value, space.w_unicode): + from unicodeobject import unicode_to_decimal_w + value = _string_to_float(space, w_value, + unicode_to_decimal_w(space, w_value)) else: - res = op(f1, f2) - return space.newbool(res) - return f, opname + "__Int_Float" -list_compare_funcs(declare_cmp_int_float) + try: + value = space.charbuf_w(w_value) + except OperationError as e: + if e.match(space, space.w_TypeError): + raise oefmt( + space.w_TypeError, + "float() argument must be a string or a number") + raise + value = _string_to_float(space, w_value, value) + w_obj = space.allocate_instance(W_FloatObject, w_floattype) + W_FloatObject.__init__(w_obj, value) + return w_obj -def declare_cmp_long_float(opname): - revcompare = globals()['compare_bigint_' + _reverse(opname)] - def f(space, w_long1, w_float2): - f2 = w_float2.floatval - b1 = w_long1.num - return space.newbool(revcompare(f2, b1)) - return f, opname + "__Long_Float" -list_compare_funcs(declare_cmp_long_float) + @staticmethod + @unwrap_spec(kind=str) + def descr___getformat__(space, w_cls, kind): + if kind == "float": + return space.wrap(_float_format) + elif kind == "double": + return space.wrap(_double_format) + raise oefmt(space.w_ValueError, "only float and double are valid") + @staticmethod + @unwrap_spec(s=str) + def descr_fromhex(space, w_cls, s): + length = len(s) + i = 0 + value = 0.0 + while i < length and s[i].isspace(): + i += 1 + if i == length: + raise oefmt(space.w_ValueError, "invalid hex string") + sign = 1 + if s[i] == "-": + sign = -1 + i += 1 + elif s[i] == "+": + i += 1 + if length == i: + raise oefmt(space.w_ValueError, "invalid hex string") + if s[i] == "i" or s[i] == "I": + i += 1 + if length - i >= 2 and s[i:i + 2].lower() == "nf": + i += 2 + value = rfloat.INFINITY + if length - i >= 5 and s[i:i + 5].lower() == "inity": + i += 5 + elif s[i] == "n" or s[i] == "N": + i += 1 + if length - i >= 2 and s[i:i + 2].lower() == "an": + i += 2 + value = rfloat.NAN + else: + if (s[i] == "0" and length - i > 1 and + (s[i + 1] == "x" or s[i + 1] == "X")): + i += 2 + co_start = i + while i < length and _hex_from_char(s[i]) >= 0: + i += 1 + whole_end = i + if i < length and s[i] == ".": + i += 1 + while i < length and _hex_from_char(s[i]) >= 0: + i += 1 + co_end = i - 1 + else: + co_end = i _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit