fix: import different source packages with same base name
This commit is contained in:
7
_test/b1/foo/foo.go
Normal file
7
_test/b1/foo/foo.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package foo
|
||||
|
||||
import bar "github.com/containous/yaegi/_test/b2/foo"
|
||||
|
||||
var Desc = "in b1/foo"
|
||||
|
||||
var Desc2 = Desc + bar.Desc
|
||||
3
_test/b2/foo/foo.go
Normal file
3
_test/b2/foo/foo.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package foo
|
||||
|
||||
var Desc = "in b2/foo"
|
||||
10
_test/import8.go
Normal file
10
_test/import8.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "github.com/containous/yaegi/_test/b1/foo"
|
||||
|
||||
func main() {
|
||||
println(foo.Desc)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in b1/foo
|
||||
@@ -42,8 +42,8 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
|
||||
// and pre-compute frame sizes and indexes for all un-named (temporary) and named
|
||||
// variables. A list of nodes of init functions is returned.
|
||||
// Following this pass, the CFG is ready to run
|
||||
func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
sc, pkgName := interp.initScopePkg(root)
|
||||
func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var initNodes []*node
|
||||
var iotaValue int
|
||||
var err error
|
||||
@@ -901,10 +901,10 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
|
||||
sc = sc.pop()
|
||||
funcName := n.child[1].ident
|
||||
if !isMethod(n) {
|
||||
interp.scopes[pkgName].sym[funcName].index = -1 // to force value to n.val
|
||||
interp.scopes[pkgName].sym[funcName].typ = n.typ
|
||||
interp.scopes[pkgName].sym[funcName].kind = funcSym
|
||||
interp.scopes[pkgName].sym[funcName].node = n
|
||||
interp.scopes[pkgID].sym[funcName].index = -1 // to force value to n.val
|
||||
interp.scopes[pkgID].sym[funcName].typ = n.typ
|
||||
interp.scopes[pkgID].sym[funcName].kind = funcSym
|
||||
interp.scopes[pkgID].sym[funcName].node = n
|
||||
}
|
||||
|
||||
case funcLit:
|
||||
@@ -1787,13 +1787,6 @@ func getExec(n *node) bltn {
|
||||
return n.exec
|
||||
}
|
||||
|
||||
func fileNode(n *node) *node {
|
||||
if n == nil || n.kind == fileStmt {
|
||||
return n
|
||||
}
|
||||
return fileNode(n.anc)
|
||||
}
|
||||
|
||||
// setExec recursively sets the node exec builtin function by walking the CFG
|
||||
// from the entry point (first node to exec).
|
||||
func setExec(n *node) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
// variables and functions symbols at package level, prior to CFG.
|
||||
// All function bodies are skipped. GTA is necessary to handle out of
|
||||
// order declarations and multiple source files packages.
|
||||
func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
sc, _ := interp.initScopePkg(root)
|
||||
func (interp *Interpreter) gta(root *node, rpath, pkgID string) ([]*node, error) {
|
||||
sc := interp.initScopePkg(pkgID)
|
||||
var err error
|
||||
var iotaValue int
|
||||
var revisit []*node
|
||||
@@ -146,7 +146,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) {
|
||||
default: // import symbols in package namespace
|
||||
sc.sym[name] = &symbol{kind: pkgSym, typ: &itype{cat: binPkgT, path: ipath}}
|
||||
}
|
||||
} else if err = interp.importSrc(rpath, ipath, name); err == nil {
|
||||
} else if err = interp.importSrc(rpath, ipath); err == nil {
|
||||
sc.types = interp.universe.types
|
||||
switch name {
|
||||
case "_": // no import of symbols
|
||||
|
||||
@@ -283,7 +283,7 @@ func (interp *Interpreter) resizeFrame() {
|
||||
func (interp *Interpreter) main() *node {
|
||||
interp.mutex.RLock()
|
||||
defer interp.mutex.RUnlock()
|
||||
if m, ok := interp.scopes[mainID]; ok && m.sym[mainID] != nil {
|
||||
if m, ok := interp.scopes[interp.Name]; ok && m.sym[mainID] != nil {
|
||||
return m.sym[mainID].node
|
||||
}
|
||||
return nil
|
||||
@@ -308,18 +308,18 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
|
||||
}
|
||||
|
||||
// Global type analysis
|
||||
revisit, err := interp.gta(root, pkgName)
|
||||
revisit, err := interp.gta(root, pkgName, interp.Name)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
for _, n := range revisit {
|
||||
if _, err = interp.gta(n, pkgName); err != nil {
|
||||
if _, err = interp.gta(n, pkgName, interp.Name); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
// Annotate AST with CFG infos
|
||||
initNodes, err := interp.cfg(root)
|
||||
initNodes, err := interp.cfg(root, interp.Name)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
@@ -336,7 +336,7 @@ func (interp *Interpreter) Eval(src string) (reflect.Value, error) {
|
||||
interp.mutex.Lock()
|
||||
if interp.universe.sym[pkgName] == nil {
|
||||
// Make the package visible under a path identical to its name
|
||||
interp.srcPkg[pkgName] = interp.scopes[pkgName].sym
|
||||
interp.srcPkg[pkgName] = interp.scopes[interp.Name].sym
|
||||
interp.universe.sym[pkgName] = &symbol{kind: pkgSym, typ: &itype{cat: srcPkgT, path: pkgName}}
|
||||
}
|
||||
interp.mutex.Unlock()
|
||||
|
||||
@@ -78,6 +78,7 @@ type scope struct {
|
||||
def *node // function definition node this scope belongs to, or nil
|
||||
loop *node // loop exit node for break statement
|
||||
loopRestart *node // loop restart node for continue statement
|
||||
pkgID string // unique id of package in which scope is defined
|
||||
types []reflect.Type // Frame layout, may be shared by same level scopes
|
||||
level int // Frame level: number of frame indirections to access var during execution
|
||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
||||
@@ -97,8 +98,8 @@ func (s *scope) push(indirect bool) *scope {
|
||||
sc.global = s.global
|
||||
sc.level = s.level
|
||||
}
|
||||
// inherit loop state from ancestor
|
||||
sc.loop, sc.loopRestart = s.loop, s.loopRestart
|
||||
// inherit loop state and pkgID from ancestor
|
||||
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
|
||||
return &sc
|
||||
}
|
||||
|
||||
@@ -160,19 +161,15 @@ func (s *scope) add(typ *itype) (index int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (interp *Interpreter) initScopePkg(n *node) (*scope, string) {
|
||||
func (interp *Interpreter) initScopePkg(pkgID string) *scope {
|
||||
sc := interp.universe
|
||||
pkgName := mainID
|
||||
|
||||
if p := fileNode(n); p != nil {
|
||||
pkgName = p.child[0].ident
|
||||
}
|
||||
|
||||
interp.mutex.Lock()
|
||||
if _, ok := interp.scopes[pkgName]; !ok {
|
||||
interp.scopes[pkgName] = sc.pushBloc()
|
||||
if _, ok := interp.scopes[pkgID]; !ok {
|
||||
interp.scopes[pkgID] = sc.pushBloc()
|
||||
}
|
||||
sc = interp.scopes[pkgName]
|
||||
sc = interp.scopes[pkgID]
|
||||
sc.pkgID = pkgID
|
||||
interp.mutex.Unlock()
|
||||
return sc, pkgName
|
||||
return sc
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
func (interp *Interpreter) importSrc(rPath, path string) error {
|
||||
var dir string
|
||||
var err error
|
||||
|
||||
@@ -29,6 +29,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
} else if dir, rPath, err = pkgDir(interp.context.GOPATH, rPath, path); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if interp.rdir[path] {
|
||||
return fmt.Errorf("import cycle not allowed\n\timports %s", path)
|
||||
}
|
||||
@@ -66,6 +67,9 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
if root == nil {
|
||||
continue
|
||||
}
|
||||
if interp.astDot {
|
||||
root.astDot(dotX(), name)
|
||||
}
|
||||
if pkgName == "" {
|
||||
pkgName = pname
|
||||
} else if pkgName != pname {
|
||||
@@ -75,7 +79,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
|
||||
subRPath := effectivePkg(rPath, path)
|
||||
var list []*node
|
||||
list, err = interp.gta(root, subRPath)
|
||||
list, err = interp.gta(root, subRPath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -85,7 +89,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// revisit incomplete nodes where GTA could not complete
|
||||
for pkg, nodes := range revisit {
|
||||
for _, n := range nodes {
|
||||
if _, err = interp.gta(n, pkg); err != nil {
|
||||
if _, err = interp.gta(n, pkg, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -94,7 +98,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// Generate control flow graphs
|
||||
for _, root := range rootNodes {
|
||||
var nodes []*node
|
||||
if nodes, err = interp.cfg(root); err != nil {
|
||||
if nodes, err = interp.cfg(root, path); err != nil {
|
||||
return err
|
||||
}
|
||||
initNodes = append(initNodes, nodes...)
|
||||
@@ -103,13 +107,7 @@ func (interp *Interpreter) importSrc(rPath, path, alias string) error {
|
||||
// Register source package in the interpreter. The package contains only
|
||||
// the global symbols in the package scope.
|
||||
interp.mutex.Lock()
|
||||
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]
|
||||
delete(interp.scopes, pkgName)
|
||||
}
|
||||
interp.srcPkg[path] = interp.scopes[path].sym
|
||||
|
||||
interp.frame.mutex.Lock()
|
||||
interp.resizeFrame()
|
||||
@@ -189,7 +187,7 @@ func effectivePkg(root, path string) string {
|
||||
for i := 0; i < len(splitPath); i++ {
|
||||
part := splitPath[len(splitPath)-1-i]
|
||||
|
||||
if part == splitRoot[len(splitRoot)-1-rootIndex] {
|
||||
if part == splitRoot[len(splitRoot)-1-rootIndex] && i != 0 {
|
||||
prevRootIndex = rootIndex
|
||||
rootIndex++
|
||||
} else if prevRootIndex == rootIndex {
|
||||
|
||||
@@ -176,7 +176,7 @@ func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
|
||||
}
|
||||
} else {
|
||||
// Evaluate constant array size expression
|
||||
if _, err = interp.cfg(n.child[0]); err != nil {
|
||||
if _, err = interp.cfg(n.child[0], sc.pkgID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t.incomplete = true
|
||||
|
||||
Reference in New Issue
Block a user