cmd/compile: refactor import statement parsing

Combine parser's import_stmt and import_here methods as a single new
importdcl method, and cleanup conditional logic slightly to make the
code easier to follow.

Also, eliminate importfile's unused line parameter, and get rid of all
of its duplicate type assertions.

Change-Id: Ic37ae8490afedc533f98ead9feef383e3599bc01
Reviewed-on: https://go-review.googlesource.com/19629
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2015-12-01 12:15:25 -08:00
parent d930d69fd9
commit 113c4d2581
3 changed files with 70 additions and 90 deletions

View File

@ -492,8 +492,6 @@ var debugstr string
var Debug_checknil int
var Debug_typeassert int
var importmyname *Sym // my name for package
var localpkg *Pkg // package being compiled
var importpkg *Pkg // package being imported

View File

@ -687,21 +687,21 @@ func fakeimport() {
cannedimports("fake.o", "$$\n")
}
// TODO(gri) line argument doesn't appear to be used
func importfile(f *Val, line int) {
if _, ok := f.U.(string); !ok {
func importfile(f *Val) {
path_, ok := f.U.(string)
if !ok {
Yyerror("import statement not a string")
fakeimport()
return
}
if len(f.U.(string)) == 0 {
if len(path_) == 0 {
Yyerror("import path is empty")
fakeimport()
return
}
if isbadimport(f.U.(string)) {
if isbadimport(path_) {
fakeimport()
return
}
@ -710,18 +710,16 @@ func importfile(f *Val, line int) {
// but we reserve the import path "main" to identify
// the main package, just as we reserve the import
// path "math" to identify the standard math package.
if f.U.(string) == "main" {
if path_ == "main" {
Yyerror("cannot import \"main\"")
errorexit()
}
if myimportpath != "" && f.U.(string) == myimportpath {
Yyerror("import %q while compiling that package (import cycle)", f.U.(string))
if myimportpath != "" && path_ == myimportpath {
Yyerror("import %q while compiling that package (import cycle)", path_)
errorexit()
}
path_ := f.U.(string)
if mapped, ok := importMap[path_]; ok {
path_ = mapped
}
@ -763,7 +761,7 @@ func importfile(f *Val, line int) {
file, found := findpkg(path_)
if !found {
Yyerror("can't find import: %q", f.U.(string))
Yyerror("can't find import: %q", path_)
errorexit()
}
@ -788,7 +786,7 @@ func importfile(f *Val, line int) {
var imp *obj.Biobuf
imp, err = obj.Bopenr(file)
if err != nil {
Yyerror("can't open import: %q: %v", f.U.(string), err)
Yyerror("can't open import: %q: %v", path_, err)
errorexit()
}
@ -878,7 +876,7 @@ func importfile(f *Val, line int) {
incannedimport = 0
default:
Yyerror("no import in %q", f.U.(string))
Yyerror("no import in %q", path_)
}
}

View File

@ -323,108 +323,92 @@ func (p *parser) import_() {
p.want(LIMPORT)
if p.got('(') {
for p.tok != EOF && p.tok != ')' {
p.import_stmt()
p.importdcl()
if !p.osemi(')') {
break
}
}
p.want(')')
} else {
p.import_stmt()
}
}
func (p *parser) import_stmt() {
if trace && Debug['x'] != 0 {
defer p.trace("import_stmt")()
}
line := int32(p.import_here())
if p.tok == LPACKAGE {
p.import_package()
p.import_there()
ipkg := importpkg
my := importmyname
importpkg = nil
importmyname = nil
if my == nil {
my = Lookup(ipkg.Name)
}
pack := Nod(OPACK, nil, nil)
pack.Sym = my
pack.Name.Pkg = ipkg
pack.Lineno = line
if strings.HasPrefix(my.Name, ".") {
importdot(ipkg, pack)
return
}
if my.Name == "init" {
lineno = line
Yyerror("cannot import package as init - init must be a func")
return
}
if my.Name == "_" {
return
}
if my.Def != nil {
lineno = line
redeclare(my, "as imported package name")
}
my.Def = pack
my.Lastlineno = line
my.Block = 1 // at top level
return
}
p.import_there()
// When an invalid import path is passed to importfile,
// it calls Yyerror and then sets up a fake import with
// no package statement. This allows us to test more
// than one invalid import statement in a single file.
if nerrors == 0 {
Fatalf("phase error in import")
p.importdcl()
}
}
// ImportSpec = [ "." | PackageName ] ImportPath .
// ImportPath = string_lit .
//
// import_here switches the underlying lexed source to the export data
// of the imported package.
func (p *parser) import_here() int {
func (p *parser) importdcl() {
if trace && Debug['x'] != 0 {
defer p.trace("import_here")()
defer p.trace("importdcl")()
}
importmyname = nil
var my *Sym
switch p.tok {
case LNAME, '@', '?':
// import with given name
importmyname = p.sym()
my = p.sym()
case '.':
// import into my name space
importmyname = Lookup(".")
my = Lookup(".")
p.next()
}
var path Val
if p.tok == LLITERAL {
path = p.val
p.next()
} else {
if p.tok != LLITERAL {
p.syntax_error("missing import path; require quoted string")
p.advance(';', ')')
return
}
line := parserline()
importfile(&path, line)
return line
line := int32(parserline())
path := p.val
p.next()
importfile(&path)
if p.tok != LPACKAGE {
// When an invalid import path is passed to importfile,
// it calls Yyerror and then sets up a fake import with
// no package statement. This allows us to test more
// than one invalid import statement in a single file.
p.import_there()
if nerrors == 0 {
Fatalf("phase error in import")
}
return
}
p.import_package()
p.import_there()
ipkg := importpkg
importpkg = nil
if my == nil {
my = Lookup(ipkg.Name)
}
pack := Nod(OPACK, nil, nil)
pack.Sym = my
pack.Name.Pkg = ipkg
pack.Lineno = line
if strings.HasPrefix(my.Name, ".") {
importdot(ipkg, pack)
return
}
if my.Name == "init" {
lineno = line
Yyerror("cannot import package as init - init must be a func")
return
}
if my.Name == "_" {
return
}
if my.Def != nil {
lineno = line
redeclare(my, "as imported package name")
}
my.Def = pack
my.Lastlineno = line
my.Block = 1 // at top level
}
// import_package parses the header of an imported package as exported