]> Cypherpunks repositories - gostls13.git/commitdiff
strconv: add 0b, 0o integer prefixes in ParseInt, ParseUint
authorRuss Cox <rsc@golang.org>
Wed, 30 Jan 2019 02:21:38 +0000 (21:21 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 12 Feb 2019 14:48:26 +0000 (14:48 +0000)
This CL modifies ParseInt and ParseUint to recognize
0b and 0o as binary and octal base prefixes when base == 0.

See golang.org/design/19308-number-literals for background.

For #19308.
For #12711.

Change-Id: I8efe067f415aa517bdefbff7e230d3fa1694d530
Reviewed-on: https://go-review.googlesource.com/c/160244
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
src/strconv/atoi.go
src/strconv/atoi_test.go

index ecbc9f4bbe86bfd36c68391301a6d35c06a33045..31774d0c9a383dd05499a039924ba31a6670df8e 100644 (file)
@@ -71,18 +71,22 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
 
        case base == 0:
                // Look for octal, hex prefix.
-               switch {
-               case s[0] == '0' && len(s) >= 3 && lower(s[1]) == 'x':
-                       if len(s) < 3 {
-                               return 0, syntaxError(fnParseUint, s0)
+               base = 10
+               if s[0] == '0' {
+                       switch {
+                       case len(s) >= 3 && lower(s[1]) == 'b':
+                               base = 2
+                               s = s[2:]
+                       case len(s) >= 3 && lower(s[1]) == 'o':
+                               base = 8
+                               s = s[2:]
+                       case len(s) >= 3 && lower(s[1]) == 'x':
+                               base = 16
+                               s = s[2:]
+                       default:
+                               base = 8
+                               s = s[1:]
                        }
-                       base = 16
-                       s = s[2:]
-               case s[0] == '0':
-                       base = 8
-                       s = s[1:]
-               default:
-                       base = 10
                }
 
        default:
@@ -149,13 +153,14 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) {
 // bit size (0 to 64) and returns the corresponding value i.
 //
 // If base == 0, the base is implied by the string's prefix:
-// base 16 for "0x", base 8 for "0", and base 10 otherwise.
-// For bases 1, below 0 or above 36 an error is returned.
+// base 2 for "0b", base 8 for "0" or "0o", base 16 for "0x",
+// and base 10 otherwise.
+// If base is below 0, is 1, or is above 36, an error is returned.
 //
 // The bitSize argument specifies the integer type
 // that the result must fit into. Bit sizes 0, 8, 16, 32, and 64
 // correspond to int, int8, int16, int32, and int64.
-// For a bitSize below 0 or above 64 an error is returned.
+// If bitSize is below 0 or above 64, an error is returned.
 //
 // The errors that ParseInt returns have concrete type *NumError
 // and include err.Num = s. If s is empty or contains invalid
index ec0542abf840ca6df33322c367471ffd8b305a0c..8b0576b659ec9b29b5ec728d8dbb3950a09cd6f1 100644 (file)
@@ -65,42 +65,69 @@ var parseUint64BaseTests = []parseUint64BaseTest{
        {"01777777777777777777778", 0, 0, ErrSyntax},
        {"02000000000000000000000", 0, 1<<64 - 1, ErrRange},
        {"0200000000000000000000", 0, 1 << 61, nil},
+       {"0b", 0, 0, ErrSyntax},
+       {"0B", 0, 0, ErrSyntax},
+       {"0b101", 0, 5, nil},
+       {"0B101", 0, 5, nil},
+       {"0o", 0, 0, ErrSyntax},
+       {"0O", 0, 0, ErrSyntax},
+       {"0o377", 0, 255, nil},
+       {"0O377", 0, 255, nil},
 
        // underscores allowed with base == 0 only
-       {"1_2_3_4_5", 0, 12345, nil},
+       {"1_2_3_4_5", 0, 12345, nil}, // base 0 => 10
        {"_12345", 0, 0, ErrSyntax},
        {"1__2345", 0, 0, ErrSyntax},
        {"12345_", 0, 0, ErrSyntax},
 
-       {"1_2_3_4_5", 10, 0, ErrSyntax},
+       {"1_2_3_4_5", 10, 0, ErrSyntax}, // base 10
        {"_12345", 10, 0, ErrSyntax},
        {"1__2345", 10, 0, ErrSyntax},
        {"12345_", 10, 0, ErrSyntax},
 
-       {"0x_1_2_3_4_5", 0, 0x12345, nil},
+       {"0x_1_2_3_4_5", 0, 0x12345, nil}, // base 0 => 16
        {"_0x12345", 0, 0, ErrSyntax},
        {"0x__12345", 0, 0, ErrSyntax},
        {"0x1__2345", 0, 0, ErrSyntax},
        {"0x1234__5", 0, 0, ErrSyntax},
        {"0x12345_", 0, 0, ErrSyntax},
 
-       {"1_2_3_4_5", 16, 0, ErrSyntax},
+       {"1_2_3_4_5", 16, 0, ErrSyntax}, // base 16
        {"_12345", 16, 0, ErrSyntax},
        {"1__2345", 16, 0, ErrSyntax},
        {"1234__5", 16, 0, ErrSyntax},
        {"12345_", 16, 0, ErrSyntax},
 
-       {"0_1_2_3_4_5", 0, 012345, nil},
+       {"0_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0377)
        {"_012345", 0, 0, ErrSyntax},
        {"0__12345", 0, 0, ErrSyntax},
        {"01234__5", 0, 0, ErrSyntax},
        {"012345_", 0, 0, ErrSyntax},
 
-       {"0_1_2_3_4_5", 8, 0, ErrSyntax},
+       {"0o_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0o377)
+       {"_0o12345", 0, 0, ErrSyntax},
+       {"0o__12345", 0, 0, ErrSyntax},
+       {"0o1234__5", 0, 0, ErrSyntax},
+       {"0o12345_", 0, 0, ErrSyntax},
+
+       {"0_1_2_3_4_5", 8, 0, ErrSyntax}, // base 8
        {"_012345", 8, 0, ErrSyntax},
        {"0__12345", 8, 0, ErrSyntax},
        {"01234__5", 8, 0, ErrSyntax},
        {"012345_", 8, 0, ErrSyntax},
+
+       {"0b_1_0_1", 0, 5, nil}, // base 0 => 2 (0b101)
+       {"_0b101", 0, 0, ErrSyntax},
+       {"0b__101", 0, 0, ErrSyntax},
+       {"0b1__01", 0, 0, ErrSyntax},
+       {"0b10__1", 0, 0, ErrSyntax},
+       {"0b101_", 0, 0, ErrSyntax},
+
+       {"1_0_1", 2, 0, ErrSyntax}, // base 2
+       {"_101", 2, 0, ErrSyntax},
+       {"1_01", 2, 0, ErrSyntax},
+       {"10_1", 2, 0, ErrSyntax},
+       {"101_", 2, 0, ErrSyntax},
 }
 
 type parseInt64Test struct {