1
0
mirror of https://github.com/golang/go synced 2024-11-18 18:54:42 -07:00

cmd/compile/internal/scanner: report at most one lexical error per number literal

Leave reporting of multiple errors for strings alone for now;
we probably want to see all incorrect escape sequences in
runes/strings independent of other errors.

Fixes #33961.

Change-Id: Id722e95f802687963eec647d1d1841bd6ed17d35
Reviewed-on: https://go-review.googlesource.com/c/go/+/192499
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Griesemer 2019-08-29 17:34:17 -07:00
parent a2cf16d42c
commit cdd2c265cc
2 changed files with 36 additions and 14 deletions

View File

@ -35,8 +35,8 @@ type scanner struct {
// current token, valid after calling next()
line, col uint
tok token
lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF")
bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be incorrect
lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF"); may be malformed if bad is true
bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be malformed
kind LitKind // valid if tok is _Literal
op Operator // valid if tok is _Operator, _AssignOp, or _IncOp
prec int // valid if tok is _Operator, _AssignOp, or _IncOp
@ -50,8 +50,6 @@ func (s *scanner) init(src io.Reader, errh func(line, col uint, msg string), mod
// errorf reports an error at the most recently read character position.
func (s *scanner) errorf(format string, args ...interface{}) {
// TODO(gri) Consider using s.bad to consistently suppress multiple errors
// per token, here and below.
s.bad = true
s.error(fmt.Sprintf(format, args...))
}
@ -495,18 +493,20 @@ func (s *scanner) number(c rune) {
digsep |= ds
}
if digsep&1 == 0 {
if digsep&1 == 0 && !s.bad {
s.errorf("%s has no digits", litname(prefix))
}
// exponent
if e := lower(c); e == 'e' || e == 'p' {
if !s.bad {
switch {
case e == 'e' && prefix != 0 && prefix != '0':
s.errorf("%q exponent requires decimal mantissa", c)
case e == 'p' && prefix != 'x':
s.errorf("%q exponent requires hexadecimal mantissa", c)
}
}
c = s.getr()
s.kind = FloatLit
if c == '+' || c == '-' {
@ -514,10 +514,10 @@ func (s *scanner) number(c rune) {
}
c, ds = s.digits(c, 10, nil)
digsep |= ds
if ds&1 == 0 {
if ds&1 == 0 && !s.bad {
s.errorf("exponent has no digits")
}
} else if prefix == 'x' && s.kind == FloatLit {
} else if prefix == 'x' && s.kind == FloatLit && !s.bad {
s.errorf("hexadecimal mantissa requires a 'p' exponent")
}
@ -532,11 +532,11 @@ func (s *scanner) number(c rune) {
s.lit = string(s.stopLit())
s.tok = _Literal
if s.kind == IntLit && invalid >= 0 {
if s.kind == IntLit && invalid >= 0 && !s.bad {
s.errorAtf(invalid, "invalid digit %q in %s", s.lit[invalid], litname(prefix))
}
if digsep&2 != 0 {
if digsep&2 != 0 && !s.bad {
if i := invalidSep(s.lit); i >= 0 {
s.errorAtf(i, "'_' must separate successive digits")
}

View File

@ -652,3 +652,25 @@ func TestIssue21938(t *testing.T) {
t.Errorf("got %s %q; want %s %q", got.tok, got.lit, _Literal, ".5")
}
}
func TestIssue33961(t *testing.T) {
literals := `08__ 0b.p 0b_._p 0x.e 0x.p`
for _, lit := range strings.Split(literals, " ") {
n := 0
var got scanner
got.init(strings.NewReader(lit), func(_, _ uint, msg string) {
// fmt.Printf("%s: %s\n", lit, msg) // uncomment for debugging
n++
}, 0)
got.next()
if n != 1 {
t.Errorf("%q: got %d errors; want 1", lit, n)
continue
}
if !got.bad {
t.Errorf("%q: got error but bad not set", lit)
}
}
}