1
0
mirror of https://github.com/golang/go synced 2024-11-23 09:10:08 -07:00

go/parser: more tolerant parsing of import declarations

This is a port of CL 427156 from the syntax package's parser
to go/parser.

While at it, remove an unused token.Pos parameter from
parseSpecFunction and dependent declarations.

Also, consolidate the respective test file.

For #54511.

Change-Id: Id6a28eb3d23a46fa5fa1d85d2c4e634b7015513c
Reviewed-on: https://go-review.googlesource.com/c/go/+/427157
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2022-08-31 13:43:28 -07:00 committed by Gopher Robot
parent a330ca5c54
commit d394f99f49
3 changed files with 36 additions and 19 deletions

View File

@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The errors below are produced by the parser, but we check
// them here for consistency with the types2 tests.
package p
import ; // ERROR missing import path

View File

@ -399,9 +399,10 @@ var stmtStart = map[token.Token]bool{
}
var declStart = map[token.Token]bool{
token.CONST: true,
token.TYPE: true,
token.VAR: true,
token.IMPORT: true,
token.CONST: true,
token.TYPE: true,
token.VAR: true,
}
var exprEnd = map[token.Token]bool{
@ -2416,9 +2417,9 @@ func (p *parser) parseStmt() (s ast.Stmt) {
// ----------------------------------------------------------------------------
// Declarations
type parseSpecFunction func(doc *ast.CommentGroup, pos token.Pos, keyword token.Token, iota int) ast.Spec
type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"))
}
@ -2442,10 +2443,7 @@ func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Tok
p.next()
} else {
p.error(pos, "missing import path")
// don't advance if we're at a semicolon or closing parenthesis
if p.tok != token.SEMICOLON && p.tok != token.RPAREN {
p.next()
}
p.advance(exprEnd)
}
p.expectSemi() // call before accessing p.linecomment
@ -2461,7 +2459,7 @@ func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Tok
return spec
}
func (p *parser) parseValueSpec(doc *ast.CommentGroup, _ token.Pos, keyword token.Token, iota int) ast.Spec {
func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec {
if p.trace {
defer un(trace(p, keyword.String()+"Spec"))
}
@ -2520,7 +2518,7 @@ func (p *parser) parseGenericType(spec *ast.TypeSpec, openPos token.Pos, name0 *
spec.Type = p.parseType()
}
func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Pos, _ token.Token, _ int) ast.Spec {
func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"))
}
@ -2673,12 +2671,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
lparen = p.pos
p.next()
for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
list = append(list, f(p.leadComment, pos, keyword, iota))
list = append(list, f(p.leadComment, keyword, iota))
}
rparen = p.expect(token.RPAREN)
p.expectSemi()
} else {
list = append(list, f(nil, pos, keyword, 0))
list = append(list, f(nil, keyword, 0))
}
return &ast.GenDecl{
@ -2754,6 +2752,9 @@ func (p *parser) parseDecl(sync map[token.Token]bool) ast.Decl {
var f parseSpecFunction
switch p.tok {
case token.IMPORT:
f = p.parseImportSpec
case token.CONST, token.VAR:
f = p.parseValueSpec
@ -2813,7 +2814,14 @@ func (p *parser) parseFile() *ast.File {
if p.mode&ImportsOnly == 0 {
// rest of package body
prev := token.IMPORT
for p.tok != token.EOF {
// Continue to accept import declarations for error tolerance, but complain.
if p.tok == token.IMPORT && prev != token.IMPORT {
p.error(p.pos, "imports must appear before other declarations")
}
prev = p.tok
decls = append(decls, p.parseDecl(declStart))
}
}

View File

@ -1,4 +1,4 @@
// Copyright 2021 The Go Authors. All rights reserved.
// Copyright 2020 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.
@ -8,12 +8,14 @@
package p
import ; // ERROR missing import path
import ';' // ERROR import path must be a string
// TODO(gri) The parser should accept mixing imports with other
// top-level declarations for better error recovery.
// var _ int
import . ; // ERROR missing import path
import
var /* ERROR missing import path */ _ int
import .; // ERROR missing import path
import 'x' // ERROR import path must be a string
var _ int
import /* ERROR imports must appear before other declarations */ _ "math"
// Don't repeat previous error for each immediately following import ...
import ()
import (.) // ERROR missing import path
import (
@ -21,4 +23,8 @@ import (
.
) // ERROR missing import path
// ... but remind with error again if we start a new import section after
// other declarations
var _ = fmt.Println
import /* ERROR imports must appear before other declarations */ _ "math"
import _ "math"