}
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{
// ----------------------------------------------------------------------------
// 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"))
}
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
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"))
}
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"))
}
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{
var f parseSpecFunction
switch p.tok {
+ case token.IMPORT:
+ f = p.parseImportSpec
+
case token.CONST, token.VAR:
f = p.parseValueSpec
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))
}
}
-// 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.
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 (
.
) // 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"