Author: Armin Rigo <[email protected]>
Branch:
Changeset: r94972:746e52c25681
Date: 2018-08-07 23:06 +0200
http://bitbucket.org/pypy/pypy/changeset/746e52c25681/
Log: Add flag 'no_implicit_octal' to string_to_int()
diff --git a/rpython/rlib/rarithmetic.py b/rpython/rlib/rarithmetic.py
--- a/rpython/rlib/rarithmetic.py
+++ b/rpython/rlib/rarithmetic.py
@@ -868,7 +868,7 @@
# String parsing support
# ---------------------------
-def string_to_int(s, base=10, allow_underscores=False):
+def string_to_int(s, base=10, allow_underscores=False,
no_implicit_octal=False):
"""Utility to converts a string to an integer.
If base is 0, the proper base is guessed based on the leading
characters of 's'. Raises ParseStringError in case of error.
@@ -884,6 +884,9 @@
while True:
digit = p.next_digit()
if digit == -1:
+ if no_implicit_octal:
+ if p.oldstyle_initial_zero and result != 0:
+ p.error()
return result
if p.sign == -1:
diff --git a/rpython/rlib/rstring.py b/rpython/rlib/rstring.py
--- a/rpython/rlib/rstring.py
+++ b/rpython/rlib/rstring.py
@@ -429,6 +429,7 @@
# iterator-like class
class NumberStringParser:
+ oldstyle_initial_zero = False
def error(self):
raise ParseStringError("invalid literal for %s() with base %d" %
@@ -445,7 +446,6 @@
self.sign = sign
self.original_base = base
self.allow_underscores = allow_underscores
- self.last_is_underscore = False
if base == 0:
if s.startswith('0x') or s.startswith('0X'):
@@ -453,6 +453,8 @@
elif s.startswith('0b') or s.startswith('0B'):
base = 2
elif s.startswith('0'): # also covers the '0o' case
+ if not (s.startswith('0o') or s.startswith('0O')):
+ self.oldstyle_initial_zero = True
base = 8
else:
base = 10
@@ -478,6 +480,11 @@
def next_digit(self): # -1 => exhausted
if self.i < self.n:
c = self.s[self.i]
+ if self.allow_underscores and c == '_':
+ self.i += 1
+ if self.i >= self.n:
+ self.error()
+ c = self.s[self.i]
digit = ord(c)
if '0' <= c <= '9':
digit -= ord('0')
@@ -485,22 +492,13 @@
digit = (digit - ord('A')) + 10
elif 'a' <= c <= 'z':
digit = (digit - ord('a')) + 10
- elif c == '_' and self.allow_underscores:
- if self.last_is_underscore:
- self.error()
- self.last_is_underscore = True
- self.i += 1
- return self.next_digit()
else:
self.error()
if digit >= self.base:
self.error()
self.i += 1
- self.last_is_underscore = False
return digit
else:
- if self.last_is_underscore:
- self.error()
return -1
def prev_digit(self):
diff --git a/rpython/rlib/test/test_rarithmetic.py
b/rpython/rlib/test/test_rarithmetic.py
--- a/rpython/rlib/test/test_rarithmetic.py
+++ b/rpython/rlib/test/test_rarithmetic.py
@@ -591,13 +591,36 @@
]
for x in VALID_UNDERSCORE_LITERALS:
print x
- y = string_to_int(x, base=0, allow_underscores=True)
+ y = string_to_int(x, base=0, allow_underscores=True,
+ no_implicit_octal=True)
assert y == int(x.replace('_', ''), base=0)
for x in INVALID_UNDERSCORE_LITERALS:
print x
py.test.raises(ParseStringError, string_to_int, x, base=0,
allow_underscores=True)
+ def test_no_implicit_octal(self):
+ TESTS = ['00', '000', '00_00', '02', '0377', '02_34']
+ for x in TESTS:
+ for valid_underscore in [False, True]:
+ for no_implicit_octal in [False, True]:
+ print x, valid_underscore, no_implicit_octal
+ expected_ok = True
+ if no_implicit_octal and any('1' <= c <= '7' for c in x):
+ expected_ok = False
+ if not valid_underscore and '_' in x:
+ expected_ok = False
+ if expected_ok:
+ y = string_to_int(x, base=0,
+ allow_underscores=valid_underscore,
+ no_implicit_octal=no_implicit_octal)
+ assert y == int(x.replace('_', ''), base=8)
+ else:
+ py.test.raises(ParseStringError, string_to_int, x,
+ base=0,
+ allow_underscores=valid_underscore,
+ no_implicit_octal=no_implicit_octal)
+
class TestExplicitIntsizes:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit