[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