Skip to content

Commit

Permalink
starlark: int: ignore base prefix unless matches explicit base
Browse files Browse the repository at this point in the history
Previously, when int was called with an explicit base,
it would report an error if the digit string starts
with a base prefix for a different base, such as int("0b101", 16).
Now, it uses the base prefix only if it matches the requested
base, so the example above would return 0x0b101, as would
int("0x0b101", 16).

See github.com/google/starlark-go/pull/344

PiperOrigin-RevId: 355479386
  • Loading branch information
adonovan authored and copybara-github committed Feb 3, 2021
1 parent 8346d16 commit 8fc7787
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 58 deletions.
9 changes: 2 additions & 7 deletions src/main/java/net/starlark/java/eval/StarlarkInt.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,9 @@ public static StarlarkInt parse(String s, int base) {
prefixBase = 16;
}
if (prefixBase != 0) {
digits = s.substring(2); // strip prefix
if (base == 0) {
if (base == 0 || base == prefixBase) {
base = prefixBase;
} else if (base != prefixBase) {
throw new NumberFormatException(
String.format(
"invalid base-%d literal: %s (%s prefix wants base %d)",
base, Starlark.repr(stringForErrors), s.substring(0, 2), prefixBase));
digits = s.substring(2); // strip prefix
}
}
}
Expand Down
115 changes: 64 additions & 51 deletions src/test/java/net/starlark/java/eval/testdata/int_constructor.star
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,52 @@ assert_fails(lambda: int(None), "got NoneType, want string, int, float, or bool"
assert_fails(lambda: int(""), "empty string")

# no base
assert_eq(int('0'), 0)
assert_eq(int('1'), 1)
assert_eq(int('42'), 42)
assert_eq(int('-1'), -1)
assert_eq(int('-1234'), -1234)
assert_eq(int('2147483647'), 2147483647)
assert_eq(int('-2147483648'), -2147483647 - 1)
assert_eq(int('123456789012345678901234567891234567890'), 123456789012345678901234567891234567890)
assert_eq(int('-123456789012345678901234567891234567890'), -123456789012345678901234567891234567890)
assert_eq(int('-0xabcdefabcdefabcdefabcdefabcdef', 0), -0xabcdefabcdefabcdefabcdefabcdef)
assert_eq(int('1111111111111', 2), 8191)
assert_eq(int('1111111111111', 5), 305175781)
assert_eq(int('1111111111111', 8), 78536544841)
assert_eq(int('1111111111111', 10), 1111111111111)
assert_eq(int('1111111111111', 16), 300239975158033)
assert_eq(int('1111111111111', 36), 4873763662273663093)
assert_eq(int('016'), 16) # zero ok when base != 0.
assert_eq(int('+42'), 42) # '+' prefix ok
assert_eq(int("0"), 0)
assert_eq(int("1"), 1)
assert_eq(int("42"), 42)
assert_eq(int("-1"), -1)
assert_eq(int("-1234"), -1234)
assert_eq(int("2147483647"), 2147483647)
assert_eq(int("-2147483648"), -2147483647 - 1)
assert_eq(int("123456789012345678901234567891234567890"), 123456789012345678901234567891234567890)
assert_eq(int("-123456789012345678901234567891234567890"), -123456789012345678901234567891234567890)
assert_eq(int("-0xabcdefabcdefabcdefabcdefabcdef", 0), -0xabcdefabcdefabcdefabcdefabcdef)
assert_eq(int("1111111111111", 2), 8191)
assert_eq(int("1111111111111", 5), 305175781)
assert_eq(int("1111111111111", 8), 78536544841)
assert_eq(int("1111111111111", 10), 1111111111111)
assert_eq(int("1111111111111", 16), 300239975158033)
assert_eq(int("1111111111111", 36), 4873763662273663093)
assert_eq(int("016"), 16) # zero ok when base != 0.
assert_eq(int("+42"), 42) # '+' prefix ok

# with base, no prefix
assert_eq(int('11', 2), 3)
assert_eq(int('11', 9), 10)
assert_eq(int('AF', 16), 175)
assert_eq(int('11', 36), 37)
assert_eq(int('az', 36), 395)
assert_eq(int('11', 10), 11)
assert_eq(int('11', 0), 11)
assert_eq(int("11", 2), 3)
assert_eq(int("11", 9), 10)
assert_eq(int("AF", 16), 175)
assert_eq(int("11", 36), 37)
assert_eq(int("az", 36), 395)
assert_eq(int("11", 10), 11)
assert_eq(int("11", 0), 11)

# base and prefix
assert_eq(int('0b11', 0), 3)
assert_eq(int('0B11', 2), 3)
assert_eq(int('0o11', 0), 9)
assert_eq(int('0O11', 8), 9)
assert_eq(int('0XFF', 0), 255)
assert_eq(int('0xFF', 16), 255)
assert_eq(int('0b11', 0), 3)
assert_eq(int('-0b11', 0), -3)
assert_eq(int('+0b11', 0), 3)
assert_eq(int('0B11', 2), 3)
assert_eq(int('0o11', 0), 9)
assert_eq(int('0O11', 8), 9)
assert_eq(int('-11', 2), -3)
assert_eq(int('016', 8), 14)
assert_eq(int('016', 16), 22)
assert_eq(int('0', 0), 0)
assert_eq(int('0x0b10', 16), 0x0b10)
assert_eq(int("0b11", 0), 3)
assert_eq(int("0B11", 2), 3)
assert_eq(int("0o11", 0), 9)
assert_eq(int("0O11", 8), 9)
assert_eq(int("0XFF", 0), 255)
assert_eq(int("0xFF", 16), 255)
assert_eq(int("0b11", 0), 3)
assert_eq(int("-0b11", 0), -3)
assert_eq(int("+0b11", 0), 3)
assert_eq(int("0B11", 2), 3)
assert_eq(int("0o11", 0), 9)
assert_eq(int("0O11", 8), 9)
assert_eq(int("-11", 2), -3)
assert_eq(int("016", 8), 14)
assert_eq(int("016", 16), 22)
assert_eq(int("0", 0), 0)
assert_eq(int("0x0b10", 16), 0x0b10)
assert_fails(lambda: int("0xFF", 8), 'invalid base-8 literal: "0xFF"')
assert_fails(lambda: int("016", 0), 'cannot infer base when string begins with a 0: "016"')
assert_fails(lambda: int("123", 3), 'invalid base-3 literal: "123"')
Expand All @@ -76,16 +78,27 @@ assert_fails(lambda: int(True, 2), "can't convert non-string with explicit base"
assert_fails(lambda: int(True, 10), "can't convert non-string with explicit base")
assert_fails(lambda: int(1, 2), "can't convert non-string with explicit base")

# Base prefix is honored only if base=0, or if the prefix matches the explicit base.
# See https://github.com/google/starlark-go/issues/337
assert_fails(lambda: int("0b0"), "invalid base-10 literal")
assert_eq(int("0b0", 0), 0)
assert_eq(int("0b0", 2), 0)
assert_eq(int("0b0", 16), 0xb0)
assert_eq(int("0x0b0", 16), 0xb0)
assert_eq(int("0x0b0", 0), 0xb0)
assert_eq(int("0x0b0101", 16), 0x0b0101)
assert_eq(int("0b0101", 2), 5) # prefix is redundant with explicit base

# This case is allowed in Python but not Skylark
assert_fails(lambda: int(), "missing 1 required positional argument: x")

# Unlike Python, leading and trailing whitespace is not allowed. Use int(s.strip()).
assert_fails(lambda: int(' 1'), 'invalid base-10 literal: " 1"')
assert_fails(lambda: int('1 '), 'invalid base-10 literal: "1 "')
assert_fails(lambda: int('-'), 'invalid base-10 literal: "-"')
assert_fails(lambda: int('+'), 'invalid base-10 literal: "[+]"')
assert_fails(lambda: int('0x'), 'invalid base-10 literal: "0x"')
assert_fails(lambda: int('1.5'), 'invalid base-10 literal: "1.5"')
assert_fails(lambda: int('ab'), 'invalid base-10 literal: "ab"')
assert_fails(lambda: int('--1'), 'invalid base-10 literal: "--1"')
assert_fails(lambda: int('-0x-10', 16), 'invalid base-16 literal: "-0x-10"')
assert_fails(lambda: int(" 1"), 'invalid base-10 literal: " 1"')
assert_fails(lambda: int("1 "), 'invalid base-10 literal: "1 "')
assert_fails(lambda: int("-"), 'invalid base-10 literal: "-"')
assert_fails(lambda: int("+"), 'invalid base-10 literal: "[+]"')
assert_fails(lambda: int("0x"), 'invalid base-10 literal: "0x"')
assert_fails(lambda: int("1.5"), 'invalid base-10 literal: "1.5"')
assert_fails(lambda: int("ab"), 'invalid base-10 literal: "ab"')
assert_fails(lambda: int("--1"), 'invalid base-10 literal: "--1"')
assert_fails(lambda: int("-0x-10", 16), 'invalid base-16 literal: "-0x-10"')

0 comments on commit 8fc7787

Please sign in to comment.