Commit cdd2c265 authored by Robert Griesemer's avatar Robert Griesemer

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: default avatarEmmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent a2cf16d4
...@@ -35,8 +35,8 @@ type scanner struct { ...@@ -35,8 +35,8 @@ type scanner struct {
// current token, valid after calling next() // current token, valid after calling next()
line, col uint line, col uint
tok token tok token
lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF") 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 incorrect bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be malformed
kind LitKind // valid if tok is _Literal kind LitKind // valid if tok is _Literal
op Operator // valid if tok is _Operator, _AssignOp, or _IncOp op Operator // valid if tok is _Operator, _AssignOp, or _IncOp
prec int // 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 ...@@ -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. // errorf reports an error at the most recently read character position.
func (s *scanner) errorf(format string, args ...interface{}) { 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.bad = true
s.error(fmt.Sprintf(format, args...)) s.error(fmt.Sprintf(format, args...))
} }
...@@ -495,17 +493,19 @@ func (s *scanner) number(c rune) { ...@@ -495,17 +493,19 @@ func (s *scanner) number(c rune) {
digsep |= ds digsep |= ds
} }
if digsep&1 == 0 { if digsep&1 == 0 && !s.bad {
s.errorf("%s has no digits", litname(prefix)) s.errorf("%s has no digits", litname(prefix))
} }
// exponent // exponent
if e := lower(c); e == 'e' || e == 'p' { if e := lower(c); e == 'e' || e == 'p' {
switch { if !s.bad {
case e == 'e' && prefix != 0 && prefix != '0': switch {
s.errorf("%q exponent requires decimal mantissa", c) case e == 'e' && prefix != 0 && prefix != '0':
case e == 'p' && prefix != 'x': s.errorf("%q exponent requires decimal mantissa", c)
s.errorf("%q exponent requires hexadecimal mantissa", c) case e == 'p' && prefix != 'x':
s.errorf("%q exponent requires hexadecimal mantissa", c)
}
} }
c = s.getr() c = s.getr()
s.kind = FloatLit s.kind = FloatLit
...@@ -514,10 +514,10 @@ func (s *scanner) number(c rune) { ...@@ -514,10 +514,10 @@ func (s *scanner) number(c rune) {
} }
c, ds = s.digits(c, 10, nil) c, ds = s.digits(c, 10, nil)
digsep |= ds digsep |= ds
if ds&1 == 0 { if ds&1 == 0 && !s.bad {
s.errorf("exponent has no digits") 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") s.errorf("hexadecimal mantissa requires a 'p' exponent")
} }
...@@ -532,11 +532,11 @@ func (s *scanner) number(c rune) { ...@@ -532,11 +532,11 @@ func (s *scanner) number(c rune) {
s.lit = string(s.stopLit()) s.lit = string(s.stopLit())
s.tok = _Literal 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)) 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 { if i := invalidSep(s.lit); i >= 0 {
s.errorAtf(i, "'_' must separate successive digits") s.errorAtf(i, "'_' must separate successive digits")
} }
......
...@@ -652,3 +652,25 @@ func TestIssue21938(t *testing.T) { ...@@ -652,3 +652,25 @@ func TestIssue21938(t *testing.T) {
t.Errorf("got %s %q; want %s %q", got.tok, got.lit, _Literal, ".5") 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)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment