fix: reuse rather than re-import an already imported source package
This commit is contained in:
committed by
Traefiker Bot
parent
bfa9a267be
commit
2f0279f0f5
@@ -1,6 +1,8 @@
|
||||
package foo
|
||||
|
||||
import "./boo"
|
||||
import "github.com/containous/yaegi/_test/foo/boo"
|
||||
|
||||
var Bar = "BARR"
|
||||
var Boo = boo.Boo
|
||||
|
||||
func init() { println("init foo") }
|
||||
|
||||
5
_test/foo/bir.go
Normal file
5
_test/foo/bir.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package foo
|
||||
|
||||
import "github.com/containous/yaegi/_test/foo/boo"
|
||||
|
||||
var Bir = boo.Boo + "22"
|
||||
@@ -1,3 +1,5 @@
|
||||
package boo
|
||||
|
||||
var Boo = "Boo"
|
||||
|
||||
func init() { println("init boo") }
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package main
|
||||
|
||||
import "./foo"
|
||||
import "github.com/containous/yaegi/_test/foo"
|
||||
|
||||
func main() { println(foo.Bar, foo.Boo) }
|
||||
|
||||
// Output:
|
||||
// init boo
|
||||
// init foo
|
||||
// BARR Boo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package main
|
||||
|
||||
import "./p1"
|
||||
import "github.com/containous/yaegi/_test/p1"
|
||||
|
||||
func main() { println("num:", p1.Uint32()) }
|
||||
|
||||
|
||||
10
_test/import5.go
Normal file
10
_test/import5.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import boo "github.com/containous/yaegi/_test/foo"
|
||||
|
||||
func main() { println(boo.Bar, boo.Boo, boo.Bir) }
|
||||
|
||||
// Output:
|
||||
// init boo
|
||||
// init foo
|
||||
// BARR Boo Boo22
|
||||
@@ -121,8 +121,11 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
ipath = n.child[0].rval.String()
|
||||
name = path.Base(ipath)
|
||||
}
|
||||
// Try to import a binary package first, or a source package
|
||||
if interp.binPkg[ipath] != nil {
|
||||
if name == "." {
|
||||
switch name {
|
||||
case "_": // no import of symbols
|
||||
case ".": // import symbols in current scope
|
||||
for n, v := range interp.binPkg[ipath] {
|
||||
typ := v.Type()
|
||||
if isBinType(v) {
|
||||
@@ -130,14 +133,22 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
}
|
||||
sc.sym[n] = &symbol{kind: binSym, typ: &itype{cat: valueT, rtype: typ}, rval: v}
|
||||
}
|
||||
} else {
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT}, path: ipath}
|
||||
}
|
||||
} else {
|
||||
// TODO: make sure we do not import a src package more than once
|
||||
err = interp.importSrcFile(rpath, ipath, name)
|
||||
} else if err = interp.importSrc(rpath, ipath, name); err == nil {
|
||||
sc.types = interp.universe.types
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT}, path: ipath}
|
||||
switch name {
|
||||
case "_": // no import of symbols
|
||||
case ".": // import symbols in current namespace
|
||||
for k, v := range interp.srcPkg[ipath] {
|
||||
if canExport(k) {
|
||||
sc.sym[k] = v
|
||||
}
|
||||
}
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT}, path: ipath}
|
||||
}
|
||||
}
|
||||
|
||||
case typeSpec:
|
||||
|
||||
@@ -54,9 +54,12 @@ type frame struct {
|
||||
recovered interface{} // to handle panic recover
|
||||
}
|
||||
|
||||
// Exports stores the map of external values per package
|
||||
// Exports stores the map of binary packages per package path
|
||||
type Exports map[string]map[string]reflect.Value
|
||||
|
||||
// imports stores the map of source packages per package path
|
||||
type imports map[string]map[string]*symbol
|
||||
|
||||
// opt stores interpreter options
|
||||
type opt struct {
|
||||
astDot bool // display AST graph (debug)
|
||||
@@ -74,7 +77,8 @@ type Interpreter struct {
|
||||
fset *token.FileSet // fileset to locate node in source code
|
||||
universe *scope // interpreter global level scope
|
||||
scopes map[string]*scope // package level scopes, indexed by package name
|
||||
binPkg Exports // runtime binary values used in interpreter
|
||||
binPkg Exports // binary packages used in interpreter, indexed by path
|
||||
srcPkg imports // source packages used in interpreter, indexed by path
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -127,11 +131,12 @@ type Options struct {
|
||||
func New(options Options) *Interpreter {
|
||||
i := Interpreter{
|
||||
opt: opt{context: build.Default},
|
||||
frame: &frame{data: []reflect.Value{}},
|
||||
fset: token.NewFileSet(),
|
||||
universe: initUniverse(),
|
||||
scopes: map[string]*scope{},
|
||||
binPkg: Exports{"": map[string]reflect.Value{"_error": reflect.ValueOf((*_error)(nil))}},
|
||||
frame: &frame{data: []reflect.Value{}},
|
||||
srcPkg: imports{},
|
||||
}
|
||||
|
||||
i.opt.context.GOPATH = options.GoPath
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package interp_test
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -35,7 +36,6 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
file.Name() == "export1.go" || // non-main package
|
||||
file.Name() == "export0.go" || // non-main package
|
||||
file.Name() == "io0.go" || // use random number
|
||||
file.Name() == "import4.go" || // not compatible with go1.13
|
||||
file.Name() == "op1.go" || // expect error
|
||||
file.Name() == "bltn0.go" || // expect error
|
||||
file.Name() == "method16.go" || // private struct field
|
||||
@@ -79,7 +79,7 @@ func TestInterpConsistencyBuild(t *testing.T) {
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
i := interp.New(interp.Options{})
|
||||
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
|
||||
i.Name = filePath
|
||||
i.Use(stdlib.Symbols)
|
||||
i.Use(interp.Symbols)
|
||||
@@ -179,7 +179,7 @@ func TestInterpErrorConsistency(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
i := interp.New(interp.Options{})
|
||||
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
|
||||
i.Name = filePath
|
||||
i.Use(stdlib.Symbols)
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package interp_test
|
||||
|
||||
import (
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io/ioutil"
|
||||
@@ -51,7 +52,7 @@ func runCheck(t *testing.T, p string) {
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
|
||||
i := interp.New(interp.Options{})
|
||||
i := interp.New(interp.Options{GoPath: build.Default.GOPATH})
|
||||
i.Name = p
|
||||
i.Use(interp.Symbols)
|
||||
i.Use(stdlib.Symbols)
|
||||
|
||||
@@ -8,10 +8,14 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (interp *Interpreter) importSrcFile(rPath, path, alias string) error {
|
||||
func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
var dir string
|
||||
var err error
|
||||
|
||||
if interp.srcPkg[path] != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// For relative import paths in the form "./xxx" or "../xxx", the initial
|
||||
// base path is the directory of the interpreter input file, or "." if no file
|
||||
// was provided.
|
||||
@@ -92,6 +96,10 @@ func (interp *Interpreter) importSrcFile(rPath, path, alias string) error {
|
||||
initNodes = append(initNodes, nodes...)
|
||||
}
|
||||
|
||||
// Register source package in the interpreter. The package contains only
|
||||
// the global symbols in the package scope.
|
||||
interp.srcPkg[path] = interp.scopes[pkgName].sym
|
||||
|
||||
// Rename imported pkgName to alias if they are different
|
||||
if pkgName != alias {
|
||||
interp.scopes[alias] = interp.scopes[pkgName]
|
||||
|
||||
@@ -383,7 +383,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
if v, ok := pkg[name]; ok {
|
||||
t.cat = valueT
|
||||
t.rtype = v.Type()
|
||||
if isBinType(v) {
|
||||
if isBinType(v) { // a bin type is encoded as a pointer on nil value
|
||||
t.rtype = t.rtype.Elem()
|
||||
}
|
||||
} else {
|
||||
@@ -391,9 +391,9 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
|
||||
case srcPkgT:
|
||||
spkg := interp.scopes[pkg]
|
||||
if st, ok := spkg.sym[name]; ok {
|
||||
t = st.typ
|
||||
pkg := interp.srcPkg[sym.path]
|
||||
if s, ok := pkg[name]; ok {
|
||||
t = s.typ
|
||||
} else {
|
||||
t.incomplete = true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user