p.next()
default:
p.errorExpected(p.pos, "';'")
- syncStmt(p)
+ p.syncStmt()
}
}
}
}
}
+// TODO(gri) The syncX methods below all use the same pattern. Factor.
+
// syncStmt advances to the next statement.
// Used for synchronization after an error.
//
-func syncStmt(p *parser) {
+func (p *parser) syncStmt() {
for {
switch p.tok {
case token.BREAK, token.CONST, token.CONTINUE, token.DEFER,
// syncDecl advances to the next declaration.
// Used for synchronization after an error.
//
-func syncDecl(p *parser) {
+func (p *parser) syncDecl() {
for {
switch p.tok {
case token.CONST, token.TYPE, token.VAR:
}
}
+// syncExprEnd advances to the likely end of an expression.
+// Used for synchronization after an error.
+//
+func (p *parser) syncExprEnd() {
+ for {
+ switch p.tok {
+ case token.COMMA, token.COLON, token.SEMICOLON, token.RPAREN, token.RBRACK, token.RBRACE:
+ // see comments in syncStmt
+ if p.pos == p.syncPos && p.syncCnt < 10 {
+ p.syncCnt++
+ return
+ }
+ if p.pos > p.syncPos {
+ p.syncPos = p.pos
+ p.syncCnt = 0
+ return
+ }
+ case token.EOF:
+ return
+ }
+ p.next()
+ }
+}
+
// safePos returns a valid file position for a given position: If pos
// is valid to begin with, safePos returns pos. If pos is out-of-range,
// safePos returns the EOF position.
if typ == nil {
pos := p.pos
p.errorExpected(pos, "type")
- p.next() // make progress
+ p.syncExprEnd()
return &ast.BadExpr{From: pos, To: p.pos}
}
// we have an error
pos := p.pos
p.errorExpected(pos, "operand")
- syncStmt(p)
+ p.syncStmt()
return &ast.BadExpr{From: pos, To: p.pos}
}
switch p.tok {
case token.CONST, token.TYPE, token.VAR:
- s = &ast.DeclStmt{Decl: p.parseDecl(syncStmt)}
+ s = &ast.DeclStmt{Decl: p.parseDecl((*parser).syncStmt)}
case
// tokens that may start an expression
token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
// no statement found
pos := p.pos
p.errorExpected(pos, "statement")
- syncStmt(p)
+ p.syncStmt()
s = &ast.BadStmt{From: pos, To: p.pos}
}
if p.mode&ImportsOnly == 0 {
// rest of package body
for p.tok != token.EOF {
- decls = append(decls, p.parseDecl(syncDecl))
+ decls = append(decls, p.parseDecl((*parser).syncDecl))
}
}
}
--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test case for issue 23434: Better synchronization of
+// parser after missing type. There should be exactly
+// one error each time, with now follow errors.
+
+package p
+
+func g() {
+ m := make(map[string]! /* ERROR "expected type, found '!'" */ )
+ for {
+ x := 1
+ print(x)
+ }
+}
+
+func f() {
+ m := make(map[string]) /* ERROR "expected type, found '\)'" */
+ for {
+ x := 1
+ print(x)
+ }
+}