Skip to content

Commit 4ad5537

Browse files
committed
cmd/compile: accept 'i' suffix orthogonally on all numbers
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent c3b4918 commit 4ad5537

File tree

5 files changed

+58
-34
lines changed

5 files changed

+58
-34
lines changed

src/cmd/compile/internal/gc/mpfloat.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,33 @@ func (a *Mpflt) SetString(as string) {
183183
// TODO(gri) remove this code once math/big.Float.Parse can handle separators
184184
as = strings.Replace(as, "_", "", -1) // strip separators
185185

186+
// TODO(gri) why is this needed?
186187
for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
187188
as = as[1:]
188189
}
189190

190-
f, _, err := a.Val.Parse(as, 0)
191-
if err != nil {
192-
yyerror("malformed constant: %s (%v)", as, err)
193-
a.Val.SetFloat64(0)
194-
return
191+
// Currently, Val.Parse below (== math/big.Float.Parse) does not
192+
// handle the 0o-octal prefix which can appear with octal integers
193+
// with 'i' suffix, which end up here as imaginary components of
194+
// complex numbers. Handle explicitly for now.
195+
// TODO(gri) remove once Float.Parse can handle octals (it handles 0b/0B)
196+
var f *big.Float
197+
if strings.HasPrefix(as, "0o") || strings.HasPrefix(as, "0O") {
198+
x, ok := new(big.Int).SetString(as[2:], 8)
199+
if !ok {
200+
yyerror("malformed constant: %s", as)
201+
a.Val.SetFloat64(0)
202+
return
203+
}
204+
f = a.Val.SetInt(x)
205+
} else {
206+
var err error
207+
f, _, err = a.Val.Parse(as, 0)
208+
if err != nil {
209+
yyerror("malformed constant: %s (%v)", as, err)
210+
a.Val.SetFloat64(0)
211+
return
212+
}
195213
}
196214

197215
if f.IsInf() {

src/cmd/compile/internal/syntax/scanner.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -512,9 +512,6 @@ func (s *scanner) number(c rune) {
512512
// suffix 'i'
513513
if c == 'i' {
514514
s.kind = ImagLit
515-
if prefix != 0 && prefix != '0' {
516-
s.error("invalid suffix 'i' on " + litname(prefix))
517-
}
518515
c = s.getr()
519516
}
520517
s.ungetr()

src/cmd/compile/internal/syntax/scanner_test.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,14 @@ func TestNumbers(t *testing.T) {
347347
{IntLit, "0b0190", "0b0190", "invalid digit '9' in binary literal"},
348348
{IntLit, "0b01a0", "0b01 a0", ""}, // only accept 0-9
349349

350-
// binary floats and imaginaries (invalid)
351350
{FloatLit, "0b.", "0b.", "invalid radix point in binary literal"},
352351
{FloatLit, "0b.1", "0b.1", "invalid radix point in binary literal"},
353352
{FloatLit, "0b1.0", "0b1.0", "invalid radix point in binary literal"},
354353
{FloatLit, "0b1e10", "0b1e10", "'e' exponent requires decimal mantissa"},
355354
{FloatLit, "0b1P-1", "0b1P-1", "'P' exponent requires hexadecimal mantissa"},
356-
{ImagLit, "0b10i", "0b10i", "invalid suffix 'i' on binary literal"},
355+
356+
{ImagLit, "0b10i", "0b10i", ""},
357+
{ImagLit, "0b10.0i", "0b10.0i", "invalid radix point in binary literal"},
357358

358359
// octals
359360
{IntLit, "0o0", "0o0", ""},
@@ -365,13 +366,14 @@ func TestNumbers(t *testing.T) {
365366
{IntLit, "0o1293", "0o1293", "invalid digit '9' in octal literal"},
366367
{IntLit, "0o12a3", "0o12 a3", ""}, // only accept 0-9
367368

368-
// octal floats and imaginaries (invalid)
369369
{FloatLit, "0o.", "0o.", "invalid radix point in octal literal"},
370370
{FloatLit, "0o.2", "0o.2", "invalid radix point in octal literal"},
371371
{FloatLit, "0o1.2", "0o1.2", "invalid radix point in octal literal"},
372372
{FloatLit, "0o1E+2", "0o1E+2", "'E' exponent requires decimal mantissa"},
373373
{FloatLit, "0o1p10", "0o1p10", "'p' exponent requires hexadecimal mantissa"},
374-
{ImagLit, "0o10i", "0o10i", "invalid suffix 'i' on octal literal"},
374+
375+
{ImagLit, "0o10i", "0o10i", ""},
376+
{ImagLit, "0o10e0i", "0o10e0i", "'e' exponent requires decimal mantissa"},
375377

376378
// 0-octals
377379
{IntLit, "0", "0", ""},
@@ -389,6 +391,9 @@ func TestNumbers(t *testing.T) {
389391

390392
{IntLit, "1f", "1 f", ""}, // only accept 0-9
391393

394+
{ImagLit, "0i", "0i", ""},
395+
{ImagLit, "0678i", "0678i", ""},
396+
392397
// decimal floats
393398
{FloatLit, "0.", "0.", ""},
394399
{FloatLit, "123.", "123.", ""},
@@ -424,7 +429,6 @@ func TestNumbers(t *testing.T) {
424429
{FloatLit, "0p0", "0p0", "'p' exponent requires hexadecimal mantissa"},
425430
{FloatLit, "1.0P-1", "1.0P-1", "'P' exponent requires hexadecimal mantissa"},
426431

427-
// decimal imaginaries
428432
{ImagLit, "0.i", "0.i", ""},
429433
{ImagLit, ".123i", ".123i", ""},
430434
{ImagLit, "123.123i", "123.123i", ""},
@@ -441,6 +445,8 @@ func TestNumbers(t *testing.T) {
441445
{IntLit, "0x", "0x", "hexadecimal literal has no digits"},
442446
{IntLit, "0x1g", "0x1 g", ""},
443447

448+
{ImagLit, "0xf00i", "0xf00i", ""},
449+
444450
// hexadecimal floats
445451
{FloatLit, "0x0p0", "0x0p0", ""},
446452
{FloatLit, "0x12efp-123", "0x12efp-123", ""},
@@ -459,9 +465,7 @@ func TestNumbers(t *testing.T) {
459465
{FloatLit, "0x1234PAB", "0x1234P AB", "exponent has no digits"},
460466
{FloatLit, "0x1.2p1a", "0x1.2p1 a", ""},
461467

462-
// hexadecimal imaginaries (invalid)
463-
{ImagLit, "0xf00i", "0xf00i", "invalid suffix 'i' on hexadecimal literal"},
464-
{ImagLit, "0xf00.bap+12i", "0xf00.bap+12i", "invalid suffix 'i' on hexadecimal literal"},
468+
{ImagLit, "0xf00.bap+12i", "0xf00.bap+12i", ""},
465469

466470
// separators
467471
{IntLit, "0b_1000_0001", "0b_1000_0001", ""},

src/cmd/compile/internal/syntax/tokens.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ func contains(tokset uint64, tok token) bool {
9292

9393
type LitKind uint
9494

95+
// TODO(gri) With the 'i' (imaginary) suffix now permitted on integer
96+
// and floating-point numbers, having a single ImagLit does
97+
// not represent the literal kind well anymore. Remove it?
9598
const (
9699
IntLit LitKind = iota
97100
FloatLit

test/literal2.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
// license that can be found in the LICENSE file.
66

77
// Test Go2 literal syntax for basic types.
8-
// TODO add more tests
8+
// Avoid running gofmt on this file to preserve the
9+
// test cases with upper-case prefixes (0B, 0O, 0X).
910

1011
package main
1112

@@ -17,7 +18,7 @@ func assert(cond bool) {
1718
}
1819
}
1920

20-
func equal(x, y float64) bool {
21+
func equal(x, y interface{}) bool {
2122
if x != y {
2223
fmt.Printf("%g != %g\n", x, y)
2324
return false
@@ -30,59 +31,60 @@ func main() {
3031
assert(0_1 == 01)
3132
assert(012 == 012)
3233
assert(0_1_2 == 012)
34+
assert(0_1_2i == complex(0, 12)) // decimal digits despite leading 0 for backward-compatibility
35+
assert(00089i == complex(0, 89)) // decimal digits despite leading 0 for backward-compatibility
3336

3437
// decimals
3538
assert(1_000_000 == 1000000)
39+
assert(1_000i == complex(0, 1000))
3640

3741
// hexadecimals
3842
assert(0x_1 == 0x1)
3943
assert(0x1_2 == 0x12)
40-
assert(0X_cafe_f00d == 0xcafef00d)
44+
assert(0x_cafe_f00d == 0xcafef00d)
45+
assert(0x_cafei == complex(0, 0xcafe))
4146

4247
// octals
4348
assert(0o_1 == 01)
4449
assert(0o12 == 012)
45-
assert(0O_1_2 == 012)
50+
assert(0o_1_2 == 012)
51+
assert(0o_1_2i == complex(0, 0o12))
4652

4753
// binaries
4854
assert(0b_1 == 1)
4955
assert(0b10 == 2)
5056
assert(0b_1_0 == 2)
57+
assert(0b_1_0i == complex(0, 2))
5158

5259
// decimal floats
5360
assert(0. == 0.0)
5461
assert(.0 == 0.0)
5562
assert(1_0. == 10.0)
5663
assert(.0_1 == 0.01)
5764
assert(1_0.0_1 == 10.01)
65+
assert(1_0.0_1i == complex(0, 10.01))
5866

5967
assert(0.e1_0 == 0.0e10)
6068
assert(.0e1_0 == 0.0e10)
6169
assert(1_0.e1_0 == 10.0e10)
6270
assert(.0_1e1_0 == 0.01e10)
6371
assert(1_0.0_1e1_0 == 10.01e10)
72+
assert(1_0.0_1e1_0i == complex(0, 10.01e10))
6473

6574
// hexadecimal floats
6675
assert(equal(0x1p-2, 0.25))
6776
assert(equal(0x2.p10, 2048.0))
6877
assert(equal(0x1.Fp+0, 1.9375))
69-
assert(equal(0X.8p-0, 0.5))
70-
assert(equal(0X1FFFP-16, 0.1249847412109375))
78+
assert(equal(0x.8p-0, 0.5))
79+
assert(equal(0x1FFFp-16, 0.1249847412109375))
7180
assert(equal(0x1.fffffffffffffp1023, 1.7976931348623157e308))
81+
assert(equal(0x1.fffffffffffffp1023i, complex(0, 1.7976931348623157e308)))
7282

7383
assert(equal(0x_1p-2, 0.25))
7484
assert(equal(0x2.p1_0, 2048.0))
7585
assert(equal(0x1_0.Fp+0, 16.9375))
76-
assert(equal(0X_0.8p-0, 0.5))
77-
assert(equal(0X_1FF_FP-16, 0.1249847412109375))
78-
assert(equal(0x1.f_ffff_ffff_ffffP1_023, 1.7976931348623157e308))
79-
80-
// imaginaries
81-
assert(0i == complex(0, 0))
82-
assert(09i == complex(0, 9)) // "09i" is a decimal int followed by "i"
83-
assert(1.2e+3i == complex(0, 1.2e+3))
84-
85-
assert(0_0i == complex(0, 0))
86-
assert(0_9i == complex(0, 9)) // "0_9i" is a decimal int followed by "i"
87-
assert(1.2_0e+0_3i == complex(0, 1.2e+3))
86+
assert(equal(0x_0.8p-0, 0.5))
87+
assert(equal(0x_1FF_Fp-16, 0.1249847412109375))
88+
assert(equal(0x1.f_ffff_ffff_ffffp1_023, 1.7976931348623157e308))
89+
assert(equal(0x1.f_ffff_ffff_ffffp1_023i, complex(0, 1.7976931348623157e308)))
8890
}

0 commit comments

Comments
 (0)