[pypy-svn] r11542 - in pypy/dist/pypy/objspace/std: . test

pedronis at codespeak.net pedronis at codespeak.net
Wed Apr 27 20:06:00 CEST 2005


Author: pedronis
Date: Wed Apr 27 20:06:00 2005
New Revision: 11542

Modified:
   pypy/dist/pypy/objspace/std/inttype.py
   pypy/dist/pypy/objspace/std/longtype.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/strutil.py
   pypy/dist/pypy/objspace/std/test/test_strutil.py
   pypy/dist/pypy/objspace/std/unicodeobject.py
Log:
- introduced a brain-dead newlong taking just a r_uint for now

- strutil.string_to_int now raises a exception if an overflow occurs

- strutil.string_to_long has become string_to_w_long and returns a wrapped space long

- changed tests to reflect this

- reworked inttype.descr__new__ and longtype.descr__new__ to not depend anymore on string_to_int falling back
  to Python longs (which would defeat the annotator) and to use string_to_w_long

- reworked some of unicodeobject related xxx code




Modified: pypy/dist/pypy/objspace/std/inttype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/inttype.py	(original)
+++ pypy/dist/pypy/objspace/std/inttype.py	Wed Apr 27 20:06:00 2005
@@ -1,21 +1,24 @@
 from pypy.objspace.std.stdtypedef import *
-from pypy.objspace.std.strutil import string_to_int, ParseStringError
+from pypy.objspace.std.strutil import string_to_int, string_to_w_long, ParseStringError, ParseStringOverflowError
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import NoneNotWrapped
 
 def descr__new__(space, w_inttype, w_value=0, w_base=NoneNotWrapped):
     from pypy.objspace.std.intobject import W_IntObject
+    w_longval = None
     if w_base is None:
         # check for easy cases
         if isinstance(w_value, W_IntObject):
             value = w_value.intval
         elif space.is_true(space.isinstance(w_value, space.w_str)):
             try:
-                # XXX can produce unwrapped long
-                value = string_to_int(space.str_w(w_value))
+                value = string_to_int(space, space.str_w(w_value))
             except ParseStringError, e:
                 raise OperationError(space.w_ValueError,
                                      space.wrap(e.msg))
+            except ParseStringOverflowError, e:
+                e.parser.rewind()                
+                w_longval = string_to_w_long(space, None, base=0, parser=e.parser)                
         else:
             # otherwise, use the __int__() method
             w_obj = space.int(w_value)
@@ -46,22 +49,20 @@
                                      space.wrap("int() can't convert non-string "
                                                 "with explicit base"))
         try:
-            # XXX can produce unwrapped long, need real long impl to know
-            # what to do
-            value = string_to_int(s, base)
+            value = string_to_int(space, s, base)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))
+        except ParseStringOverflowError, e:
+            e.parser.rewind()
+            w_longval = string_to_w_long(space, None, base, parser=e.parser)                        
 
-    if isinstance(value, long):
+    if w_longval is not None:
         if not space.is_true(space.is_(w_inttype, space.w_int)):
             raise OperationError(space.w_OverflowError,
                                  space.wrap(
                 "long int too large to convert to int"))          
-        from pypy.objspace.std.longobject import W_LongObject, args_from_long
-        w_obj = space.allocate_instance(W_LongObject, space.w_long)
-        w_obj.__init__(space, *args_from_long(value))
-        return w_obj
+        return w_longval
     else:
         w_obj = space.allocate_instance(W_IntObject, w_inttype)
         w_obj.__init__(space, value)

Modified: pypy/dist/pypy/objspace/std/longtype.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longtype.py	(original)
+++ pypy/dist/pypy/objspace/std/longtype.py	Wed Apr 27 20:06:00 2005
@@ -1,5 +1,5 @@
 from pypy.objspace.std.stdtypedef import *
-from pypy.objspace.std.strutil import string_to_long, ParseStringError
+from pypy.objspace.std.strutil import string_to_w_long, ParseStringError
 from pypy.interpreter.error import OperationError
 from pypy.objspace.std.inttype import int_typedef
 from pypy.interpreter.gateway import NoneNotWrapped
@@ -9,11 +9,10 @@
     if w_base is None:
         # check for easy cases
         if isinstance(w_value, W_LongObject):
-            value = w_value.longval()
+            pass
         elif space.is_true(space.isinstance(w_value, space.w_str)):
             try:
-                # XXX value can be unwrapped long
-                value = string_to_long(space.str_w(w_value))
+                w_value = string_to_w_long(space, space.str_w(w_value))
             except ParseStringError, e:
                 raise OperationError(space.w_ValueError,
                                      space.wrap(e.msg))
@@ -23,12 +22,21 @@
             # 'long(x)' should return whatever x.__long__() returned
             if space.is_true(space.is_(w_longtype, space.w_long)):
                 return w_obj
-            value = space.unwrap(w_obj) # XXX value can be unwrapped long
-            if isinstance(value, int):    # XXX typechecking in unwrap!
-                value = long(value)
-            if not isinstance(value, long):
+            if space.is_true(space.isinstance(w_obj, w_long)):
+                w_value = w_obj
+            elif space.is_true(space.isinstance(w_obj, w_int)):
+                intval = space.int_w(w_obj)
+                # xxx this logic needs to be put in 1 place                
+                if intval < 0:
+                    sign = -1
+                elif intval > 0:
+                    sign = 1
+                else:
+                    sign = 0
+                w_value = W_LongObject(space, [r_uint(abs(intval))], sign) 
+            else:
                 raise OperationError(space.w_ValueError,
-                                 space.wrap("value can't be converted to long"))
+                                    space.wrap("value can't be converted to long"))
     else:
         base = space.int_w(w_base)
 
@@ -43,14 +51,13 @@
                                      space.wrap("long() can't convert non-string "
                                                 "with explicit base"))
         try:
-            # XXX value can be unwrapped long
-            value = string_to_long(s, base)
+            w_value = string_to_w_long(space, s, base)
         except ParseStringError, e:
             raise OperationError(space.w_ValueError,
                                  space.wrap(e.msg))
-#XXX
+
     w_obj = space.allocate_instance(W_LongObject, w_longtype)
-    w_obj.__init__(space, *args_from_long(value))
+    w_obj.__init__(space, w_value.digits, w_value.sign)
     return w_obj
 
 # ____________________________________________________________

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Wed Apr 27 20:06:00 2005
@@ -242,6 +242,13 @@
     def newfloat(self, floatval):
         return W_FloatObject(self, floatval)
 
+    def newlong(self, uint): # for now just take a r_uint
+        if uint == 0:
+            sign = 0
+        else:
+            sign = 1
+        return W_LongObject(self, [uint], sign)
+        
     def newtuple(self, list_w):
         assert isinstance(list_w, list)
         return W_TupleObject(self, list_w)

Modified: pypy/dist/pypy/objspace/std/strutil.py
==============================================================================
--- pypy/dist/pypy/objspace/std/strutil.py	(original)
+++ pypy/dist/pypy/objspace/std/strutil.py	Wed Apr 27 20:06:00 2005
@@ -2,6 +2,8 @@
 Pure Python implementation of string utilities.
 """
 
+from pypy.tool.rarithmetic import r_uint, ovfcheck
+
 # XXX factor more functions out of stringobject.py.
 # This module is independent from PyPy.
 
@@ -15,38 +17,59 @@
         q -= 1
     return s[p:q]
 
-class InvalidLiteral(Exception):
-    pass
-
 class ParseStringError(Exception):
     def __init__(self, msg):
         self.msg = msg
 
-def _parse_string(s, literal, base, fname):
-    # internal utility for string_to_int() and string_to_long().
-    sign = 1
-    if s.startswith('-'):
-        sign = -1
-        s = strip_spaces(s[1:])
-    elif s.startswith('+'):
-        s = strip_spaces(s[1:])
-    if base == 0:
-        if s.startswith('0x') or s.startswith('0X'):
-            base = 16
-        elif s.startswith('0'):
-            base = 8
+class ParseStringOverflowError(Exception):
+    def __init__(self, parser):
+        self.parser = parser
+
+# iterator-like class
+class NumberStringParser:
+
+    def error(self):
+        if self.literal:
+            raise ParseStringError, 'invalid literal for %s(): %s' % (self.fname, self.literal)
         else:
-            base = 10
-    elif base < 2 or base > 36:
-        raise ParseStringError, "%s() base must be >= 2 and <= 36" % (fname,)
-    try:
+            raise ParseStringError, 'empty literal for %s()' % (self.fname,)        
+        
+    def __init__(self, s, literal, base, fname):
+        self.literal = literal
+        self.fname = fname
+        sign = 1
+        if s.startswith('-'):
+            sign = -1
+            s = strip_spaces(s[1:])
+        elif s.startswith('+'):
+            s = strip_spaces(s[1:])
+        self.sign = sign
+        
+        if base == 0:
+            if s.startswith('0x') or s.startswith('0X'):
+                base = 16
+            elif s.startswith('0'):
+                base = 8
+            else:
+                base = 10
+        elif base < 2 or base > 36:
+            raise ParseStringError, "%s() base must be >= 2 and <= 36" % (fname,)
+        self.base = base
+
         if not s:
-            raise InvalidLiteral
+            self.error()
         if base == 16 and (s.startswith('0x') or s.startswith('0X')):
             s = s[2:]
-        # XXX uses int-to-long overflow so far
-        result = 0
-        for c in s:
+        self.s = s
+        self.n = len(s)
+        self.i = 0
+
+    def rewind(self):
+        self.i = 0
+
+    def next_digit(self): # -1 => exhausted
+        if self.i < self.n:
+            c = self.s[self.i]
             digit = ord(c)
             if '0' <= c <= '9':
                 digit -= ord('0')
@@ -55,29 +78,59 @@
             elif 'a' <= c <= 'z':
                 digit = (digit - ord('a')) + 10
             else:
-                raise InvalidLiteral
-            if digit >= base:
-                raise InvalidLiteral
-            result = result*base + digit
-        return result * sign
-    except InvalidLiteral:
-        if literal:
-            raise ParseStringError, 'invalid literal for %s(): %s' % (fname, literal)
+                self.error()
+            if digit >= self.base:
+                self.error()
+            self.i += 1
+            return digit
         else:
-            raise ParseStringError, 'empty literal for %s()' % (fname,)
+            return -1
 
-def string_to_int(s, base=10):
+def string_to_int(space, s, base=10):
     """Utility to converts a string to an integer (or possibly a long).
     If base is 0, the proper base is guessed based on the leading
     characters of 's'.  Raises ParseStringError in case of error.
     """
     s = literal = strip_spaces(s)
-    return _parse_string(s, literal, base, 'int')
+    p = NumberStringParser(s, literal, base, 'int')
+    base = p.base
+    result = 0
+    while True:
+        digit = p.next_digit()
+        if digit == -1:
+            try:
+                result =  ovfcheck(p.sign*result)
+            except OverflowError:
+                raise ParseStringOverflowError(p)
+            else:
+                return result
+        try:
+            result = ovfcheck(result*base)
+            result = ovfcheck(result+digit)
+        except OverflowError:
+            raise ParseStringOverflowError(p)
 
-def string_to_long(s, base=10):
+def string_to_long(space, s, base=10, parser=None):
+    return string_to_w_long(space, s, base, parser).longval()
+
+def string_to_w_long(space, s, base=10, parser=None):
     """As string_to_int(), but ignores an optional 'l' or 'L' suffix."""
-    s = literal = strip_spaces(s)
-    if (s.endswith('l') or s.endswith('L')) and base < 22:
-        # in base 22 and above, 'L' is a valid digit!  try: long('L',22)
-        s = s[:-1]
-    return long(_parse_string(s, literal, base, 'long'))
+    if parser is None:
+        s = literal = strip_spaces(s)
+        if (s.endswith('l') or s.endswith('L')) and base < 22:
+            # in base 22 and above, 'L' is a valid digit!  try: long('L',22)
+            s = s[:-1]
+        p = NumberStringParser(s, literal, base, 'long')
+    else:
+        p = parser
+    w_base = space.newlong(r_uint(p.base))
+    w_result = space.newlong(r_uint(0))
+    while True:
+        digit = p.next_digit()
+        if digit == -1:
+            if p.sign == -1:
+                return space.neg(w_result)
+            else:
+                return w_result
+        w_result = space.add(space.mul(w_result,w_base),space.newlong(r_uint(digit)))
+

Modified: pypy/dist/pypy/objspace/std/test/test_strutil.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_strutil.py	(original)
+++ pypy/dist/pypy/objspace/std/test/test_strutil.py	Wed Apr 27 20:06:00 2005
@@ -6,6 +6,7 @@
 class TestStrUtil:
 
     def test_string_to_int(self):
+        space = self.space
         cases = [('0', 0),
                  ('1', 1),
                  ('9', 9),
@@ -13,7 +14,6 @@
                  ('09', 9),
                  ('0000101', 101),    # not octal unless base 0 or 8
                  ('5123', 5123),
-                 ('1891234174197319', 1891234174197319),
                  (' 0', 0),
                  ('0  ', 0),
                  (' \t \n   32313  \f  \v   \r  \n\r    ', 32313),
@@ -24,10 +24,11 @@
                  ('  -123456789 ', -123456789),
                  ]
         for s, expected in cases:
-            assert string_to_int(s) == expected
-            assert string_to_long(s) == expected
+            assert string_to_int(space, s) == expected
+            assert string_to_w_long(space, s).longval() == expected
 
     def test_string_to_int_base(self):
+        space = self.space        
         cases = [('111', 2, 7),
                  ('010', 2, 2),
                  ('102', 3, 11),
@@ -53,14 +54,15 @@
                  ('0X',  16, 0),    #     "           "
                  ]
         for s, base, expected in cases:
-            assert string_to_int(s, base) == expected
-            assert string_to_int('+'+s, base) == expected
-            assert string_to_int('-'+s, base) == -expected
-            assert string_to_int(s+'\n', base) == expected
-            assert string_to_int('  +'+s, base) == expected
-            assert string_to_int('-'+s+'  ', base) == -expected
+            assert string_to_int(space, s, base) == expected
+            assert string_to_int(space, '+'+s, base) == expected
+            assert string_to_int(space, '-'+s, base) == -expected
+            assert string_to_int(space, s+'\n', base) == expected
+            assert string_to_int(space, '  +'+s, base) == expected
+            assert string_to_int(space, '-'+s+'  ', base) == -expected
 
     def test_string_to_int_error(self):
+        space = self.space
         cases = ['0x123',    # must use base 0 or 16
                  ' 0X12 ',
                  '',
@@ -76,13 +78,18 @@
                  '@',
                  ]
         for s in cases:
-            raises(ParseStringError, string_to_int, s)
-            raises(ParseStringError, string_to_int, '  '+s)
-            raises(ParseStringError, string_to_int, s+'  ')
-            raises(ParseStringError, string_to_int, '+'+s)
-            raises(ParseStringError, string_to_int, '-'+s)
+            raises(ParseStringError, string_to_int, space, s)
+            raises(ParseStringError, string_to_int, space, '  '+s)
+            raises(ParseStringError, string_to_int, space, s+'  ')
+            raises(ParseStringError, string_to_int, space, '+'+s)
+            raises(ParseStringError, string_to_int, space, '-'+s)
+
+    def test_string_to_int_overflow(self):
+        space = self.space
+        raises(ParseStringOverflowError, string_to_int, space,'1891234174197319')
 
     def test_string_to_int_base_error(self):
+        space = self.space        
         cases = [('1', 1),
                  ('1', 37),
                  ('a', 0),
@@ -98,18 +105,20 @@
                  ('12.3', 16),
                  ]
         for s, base in cases:
-            raises(ParseStringError, string_to_int, s, base)
-            raises(ParseStringError, string_to_int, '  '+s, base)
-            raises(ParseStringError, string_to_int, s+'  ', base)
-            raises(ParseStringError, string_to_int, '+'+s, base)
-            raises(ParseStringError, string_to_int, '-'+s, base)
-
-    def test_string_to_long(self):
-        assert string_to_long('123L') == 123
-        assert string_to_long('123L  ') == 123
-        raises(ParseStringError, string_to_long, 'L')
-        raises(ParseStringError, string_to_long, 'L  ')
-        assert string_to_long('123L', 4) == 27
-        assert string_to_long('123L', 30) == 27000 + 1800 + 90 + 21
-        assert string_to_long('123L', 22) == 10648 + 968 + 66 + 21
-        assert string_to_long('123L', 21) == 441 + 42 + 3
+            raises(ParseStringError, string_to_int, space, s, base)
+            raises(ParseStringError, string_to_int, space, '  '+s, base)
+            raises(ParseStringError, string_to_int, space, s+'  ', base)
+            raises(ParseStringError, string_to_int, space, '+'+s, base)
+            raises(ParseStringError, string_to_int, space, '-'+s, base)
+
+    def test_string_to_w_long(self):
+        space = self.space
+        assert string_to_w_long(space, '123L').longval() == 123
+        assert string_to_w_long(space, '123L  ').longval() == 123
+        raises(ParseStringError, string_to_w_long, space, 'L')
+        raises(ParseStringError, string_to_w_long, space, 'L  ')
+        assert string_to_w_long(space, '123L', 4).longval() == 27
+        assert string_to_w_long(space, '123L', 30).longval() == 27000 + 1800 + 90 + 21
+        assert string_to_w_long(space, '123L', 22).longval() == 10648 + 968 + 66 + 21
+        assert string_to_w_long(space, '123L', 21).longval() == 441 + 42 + 3
+        assert string_to_w_long(space, '1891234174197319').longval() == 1891234174197319

Modified: pypy/dist/pypy/objspace/std/unicodeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/unicodeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/unicodeobject.py	Wed Apr 27 20:06:00 2005
@@ -1,7 +1,7 @@
 from pypy.objspace.std.objspace import *
 from pypy.objspace.std.fake import fake_type, wrap_exception
 from pypy.objspace.std.stringobject import W_StringObject
-from pypy.objspace.std.strutil import string_to_int, string_to_long, ParseStringError
+from pypy.objspace.std.strutil import string_to_w_long, ParseStringError
 
 W_UnicodeObject = fake_type(unicode)
 
@@ -75,23 +75,25 @@
     except:
         wrap_exception(space)
 
+# xxx unicode.__float__ should not exist. For now this approach avoids to deal with unicode in more places
 def float__Unicode(space, w_uni):
     try:
         return space.wrap(float(unicode_to_decimal_w(space, w_uni)))
     except:
         wrap_exception(space)
-
+        
+# xxx unicode.__int__ should not exist
 def int__Unicode(space, w_uni):
     try:
-        return space.wrap(string_to_int(unicode_to_decimal_w(space, w_uni)))
-    except ParseStringError, e:
-        raise OperationError(space.w_ValueError, space.wrap(e.msg))
+        s = unicode_to_decimal_w(space, w_uni)
     except:
         wrap_exception(space)
+    return space.call_function(space.w_int, space.wrap(s))
 
+# xxx unicode.__long__ should not exist
 def long__Unicode(space, w_uni):
     try:
-        return space.wrap(string_to_long(unicode_to_decimal_w(space, w_uni)))
+        return string_to_w_long(space, unicode_to_decimal_w(space, w_uni))
     except ParseStringError, e:
         raise OperationError(space.w_ValueError, space.wrap(e.msg))    
     except:



More information about the Pypy-commit mailing list