]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: accept 'i' suffix orthogonally on all numbers
authorRobert Griesemer <gri@golang.org>
Fri, 15 Feb 2019 01:34:29 +0000 (17:34 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 19 Feb 2019 22:45:09 +0000 (22:45 +0000)
This change accepts the 'i' suffix on binary and octal integer
literals as well as hexadecimal floats. The suffix was already
accepted on decimal integers and floats.

Note that 0123i == 123i for backward-compatibility (and 09i is
valid).

See also the respective language in the spec change:
https://golang.org/cl/161098

Change-Id: I9d2d755cba36a3fa7b9e24308c73754d4568daaf
Reviewed-on: https://go-review.googlesource.com/c/162878
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/compile/internal/gc/mpfloat.go
src/cmd/compile/internal/syntax/scanner.go
src/cmd/compile/internal/syntax/scanner_test.go
src/cmd/compile/internal/syntax/tokens.go
test/literal2.go

index b3a9af452adbfc95c6564baaa6e87424d2aa172b..c1bbd3c1b49de16950bada1cd2b039798389670e 100644 (file)
@@ -183,15 +183,33 @@ func (a *Mpflt) SetString(as string) {
        // TODO(gri) remove this code once math/big.Float.Parse can handle separators
        as = strings.Replace(as, "_", "", -1) // strip separators
 
+       // TODO(gri) why is this needed?
        for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
                as = as[1:]
        }
 
-       f, _, err := a.Val.Parse(as, 0)
-       if err != nil {
-               yyerror("malformed constant: %s (%v)", as, err)
-               a.Val.SetFloat64(0)
-               return
+       // Currently, Val.Parse below (== math/big.Float.Parse) does not
+       // handle the 0o-octal prefix which can appear with octal integers
+       // with 'i' suffix, which end up here as imaginary components of
+       // complex numbers. Handle explicitly for now.
+       // TODO(gri) remove once Float.Parse can handle octals (it handles 0b/0B)
+       var f *big.Float
+       if strings.HasPrefix(as, "0o") || strings.HasPrefix(as, "0O") {
+               x, ok := new(big.Int).SetString(as[2:], 8)
+               if !ok {
+                       yyerror("malformed constant: %s", as)
+                       a.Val.SetFloat64(0)
+                       return
+               }
+               f = a.Val.SetInt(x)
+       } else {
+               var err error
+               f, _, err = a.Val.Parse(as, 0)
+               if err != nil {
+                       yyerror("malformed constant: %s (%v)", as, err)
+                       a.Val.SetFloat64(0)
+                       return
+               }
        }
 
        if f.IsInf() {
index 0a77d48b3da2695b2c51df83dfe5dea0cc61df4a..fbb3e1a40e6f26647aede35c44db1168dd6849f3 100644 (file)
@@ -512,9 +512,6 @@ func (s *scanner) number(c rune) {
        // suffix 'i'
        if c == 'i' {
                s.kind = ImagLit
-               if prefix != 0 && prefix != '0' {
-                       s.error("invalid suffix 'i' on " + litname(prefix))
-               }
                c = s.getr()
        }
        s.ungetr()
index 0f0579e2a5efb2a7e7c10b0c1b7970940bd2a719..bfc44950bed22f4a6a5b23fbdd1b2e6ce1a679cc 100644 (file)
@@ -347,13 +347,14 @@ func TestNumbers(t *testing.T) {
                {IntLit, "0b0190", "0b0190", "invalid digit '9' in binary literal"},
                {IntLit, "0b01a0", "0b01 a0", ""}, // only accept 0-9
 
-               // binary floats and imaginaries (invalid)
                {FloatLit, "0b.", "0b.", "invalid radix point in binary literal"},
                {FloatLit, "0b.1", "0b.1", "invalid radix point in binary literal"},
                {FloatLit, "0b1.0", "0b1.0", "invalid radix point in binary literal"},
                {FloatLit, "0b1e10", "0b1e10", "'e' exponent requires decimal mantissa"},
                {FloatLit, "0b1P-1", "0b1P-1", "'P' exponent requires hexadecimal mantissa"},
-               {ImagLit, "0b10i", "0b10i", "invalid suffix 'i' on binary literal"},
+
+               {ImagLit, "0b10i", "0b10i", ""},
+               {ImagLit, "0b10.0i", "0b10.0i", "invalid radix point in binary literal"},
 
                // octals
                {IntLit, "0o0", "0o0", ""},
@@ -365,13 +366,14 @@ func TestNumbers(t *testing.T) {
                {IntLit, "0o1293", "0o1293", "invalid digit '9' in octal literal"},
                {IntLit, "0o12a3", "0o12 a3", ""}, // only accept 0-9
 
-               // octal floats and imaginaries (invalid)
                {FloatLit, "0o.", "0o.", "invalid radix point in octal literal"},
                {FloatLit, "0o.2", "0o.2", "invalid radix point in octal literal"},
                {FloatLit, "0o1.2", "0o1.2", "invalid radix point in octal literal"},
                {FloatLit, "0o1E+2", "0o1E+2", "'E' exponent requires decimal mantissa"},
                {FloatLit, "0o1p10", "0o1p10", "'p' exponent requires hexadecimal mantissa"},
-               {ImagLit, "0o10i", "0o10i", "invalid suffix 'i' on octal literal"},
+
+               {ImagLit, "0o10i", "0o10i", ""},
+               {ImagLit, "0o10e0i", "0o10e0i", "'e' exponent requires decimal mantissa"},
 
                // 0-octals
                {IntLit, "0", "0", ""},
@@ -389,6 +391,9 @@ func TestNumbers(t *testing.T) {
 
                {IntLit, "1f", "1 f", ""}, // only accept 0-9
 
+               {ImagLit, "0i", "0i", ""},
+               {ImagLit, "0678i", "0678i", ""},
+
                // decimal floats
                {FloatLit, "0.", "0.", ""},
                {FloatLit, "123.", "123.", ""},
@@ -424,7 +429,6 @@ func TestNumbers(t *testing.T) {
                {FloatLit, "0p0", "0p0", "'p' exponent requires hexadecimal mantissa"},
                {FloatLit, "1.0P-1", "1.0P-1", "'P' exponent requires hexadecimal mantissa"},
 
-               // decimal imaginaries
                {ImagLit, "0.i", "0.i", ""},
                {ImagLit, ".123i", ".123i", ""},
                {ImagLit, "123.123i", "123.123i", ""},
@@ -441,6 +445,8 @@ func TestNumbers(t *testing.T) {
                {IntLit, "0x", "0x", "hexadecimal literal has no digits"},
                {IntLit, "0x1g", "0x1 g", ""},
 
+               {ImagLit, "0xf00i", "0xf00i", ""},
+
                // hexadecimal floats
                {FloatLit, "0x0p0", "0x0p0", ""},
                {FloatLit, "0x12efp-123", "0x12efp-123", ""},
@@ -459,9 +465,7 @@ func TestNumbers(t *testing.T) {
                {FloatLit, "0x1234PAB", "0x1234P AB", "exponent has no digits"},
                {FloatLit, "0x1.2p1a", "0x1.2p1 a", ""},
 
-               // hexadecimal imaginaries (invalid)
-               {ImagLit, "0xf00i", "0xf00i", "invalid suffix 'i' on hexadecimal literal"},
-               {ImagLit, "0xf00.bap+12i", "0xf00.bap+12i", "invalid suffix 'i' on hexadecimal literal"},
+               {ImagLit, "0xf00.bap+12i", "0xf00.bap+12i", ""},
 
                // separators
                {IntLit, "0b_1000_0001", "0b_1000_0001", ""},
index e00255a45e517c316a38cb68ecb1069339d17f82..9b26c9f12f52dc4b44dbe5fce36d4ed7fcb3392b 100644 (file)
@@ -92,6 +92,9 @@ func contains(tokset uint64, tok token) bool {
 
 type LitKind uint
 
+// TODO(gri) With the 'i' (imaginary) suffix now permitted on integer
+//           and floating-point numbers, having a single ImagLit does
+//           not represent the literal kind well anymore. Remove it?
 const (
        IntLit LitKind = iota
        FloatLit
index dbe22a012ed7e49d77f02cbc655c7f828e3989b3..f552e33adaffeb7254e2efb1b1ef6b6434fd38ff 100644 (file)
@@ -5,7 +5,8 @@
 // license that can be found in the LICENSE file.
 
 // Test Go2 literal syntax for basic types.
-// TODO add more tests
+// Avoid running gofmt on this file to preserve the
+// test cases with upper-case prefixes (0B, 0O, 0X).
 
 package main
 
@@ -17,7 +18,7 @@ func assert(cond bool) {
        }
 }
 
-func equal(x, y float64) bool {
+func equal(x, y interface{}) bool {
        if x != y {
                fmt.Printf("%g != %g\n", x, y)
                return false
@@ -30,24 +31,30 @@ func main() {
        assert(0_1 == 01)
        assert(012 == 012)
        assert(0_1_2 == 012)
+       assert(0_1_2i == complex(0, 12)) // decimal digits despite leading 0 for backward-compatibility
+       assert(00089i == complex(0, 89)) // decimal digits despite leading 0 for backward-compatibility
 
        // decimals
        assert(1_000_000 == 1000000)
+       assert(1_000i == complex(0, 1000))
 
        // hexadecimals
        assert(0x_1 == 0x1)
        assert(0x1_2 == 0x12)
-       assert(0X_cafe_f00d == 0xcafef00d)
+       assert(0x_cafe_f00d == 0xcafef00d)
+       assert(0x_cafei == complex(0, 0xcafe))
 
        // octals
        assert(0o_1 == 01)
        assert(0o12 == 012)
-       assert(0O_1_2 == 012)
+       assert(0o_1_2 == 012)
+       assert(0o_1_2i == complex(0, 0o12))
 
        // binaries
        assert(0b_1 == 1)
        assert(0b10 == 2)
        assert(0b_1_0 == 2)
+       assert(0b_1_0i == complex(0, 2))
 
        // decimal floats
        assert(0. == 0.0)
@@ -55,34 +62,29 @@ func main() {
        assert(1_0. == 10.0)
        assert(.0_1 == 0.01)
        assert(1_0.0_1 == 10.01)
+       assert(1_0.0_1i == complex(0, 10.01))
 
        assert(0.e1_0 == 0.0e10)
        assert(.0e1_0 == 0.0e10)
        assert(1_0.e1_0 == 10.0e10)
        assert(.0_1e1_0 == 0.01e10)
        assert(1_0.0_1e1_0 == 10.01e10)
+       assert(1_0.0_1e1_0i == complex(0, 10.01e10))
 
        // hexadecimal floats
        assert(equal(0x1p-2, 0.25))
        assert(equal(0x2.p10, 2048.0))
        assert(equal(0x1.Fp+0, 1.9375))
-       assert(equal(0X.8p-0, 0.5))
-       assert(equal(0X1FFFP-16, 0.1249847412109375))
+       assert(equal(0x.8p-0, 0.5))
+       assert(equal(0x1FFFp-16, 0.1249847412109375))
        assert(equal(0x1.fffffffffffffp1023, 1.7976931348623157e308))
+       assert(equal(0x1.fffffffffffffp1023i, complex(0, 1.7976931348623157e308)))
 
        assert(equal(0x_1p-2, 0.25))
        assert(equal(0x2.p1_0, 2048.0))
        assert(equal(0x1_0.Fp+0, 16.9375))
-       assert(equal(0X_0.8p-0, 0.5))
-       assert(equal(0X_1FF_FP-16, 0.1249847412109375))
-       assert(equal(0x1.f_ffff_ffff_ffffP1_023, 1.7976931348623157e308))
-
-       // imaginaries
-       assert(0i == complex(0, 0))
-       assert(09i == complex(0, 9)) // "09i" is a decimal int followed by "i"
-       assert(1.2e+3i == complex(0, 1.2e+3))
-
-       assert(0_0i == complex(0, 0))
-       assert(0_9i == complex(0, 9)) // "0_9i" is a decimal int followed by "i"
-       assert(1.2_0e+0_3i == complex(0, 1.2e+3))
+       assert(equal(0x_0.8p-0, 0.5))
+       assert(equal(0x_1FF_Fp-16, 0.1249847412109375))
+       assert(equal(0x1.f_ffff_ffff_ffffp1_023, 1.7976931348623157e308))
+       assert(equal(0x1.f_ffff_ffff_ffffp1_023i, complex(0, 1.7976931348623157e308)))
 }