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