]> Cypherpunks repositories - gostls13.git/commitdiff
go/parser: more tolerant parsing of import declarations
authorRobert Griesemer <gri@golang.org>
Wed, 31 Aug 2022 20:43:28 +0000 (13:43 -0700)
committerGopher Robot <gobot@golang.org>
Fri, 2 Sep 2022 02:09:06 +0000 (02:09 +0000)
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>
src/cmd/compile/internal/types2/testdata/fixedbugs/issue43190.go
src/go/parser/parser.go
src/go/types/testdata/fixedbugs/issue43190.go

index 37b781ce9c4e55cc0284d97fc3533a8fcdf56807..898ad0b7d0491cfe6e6f2fb3e8bebeba14635a8a 100644 (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
index fcd6a4adcc9570b6852ec66d0a348e6cfb8c7775..6d1ab3481506761609a9646cf3273efd10352fd9 100644 (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))
                        }
                }
index 3a36a1eef5287d6b70ff6c4974ff770a42a2b40f..898ad0b7d0491cfe6e6f2fb3e8bebeba14635a8a 100644 (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"