Author: Armin Rigo <ar...@tunes.org>
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
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to