diff --git a/_test/b1/foo/foo.go b/_test/b1/foo/foo.go new file mode 100644 index 000000000..2bf142311 --- /dev/null +++ b/_test/b1/foo/foo.go @@ -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 diff --git a/_test/b2/foo/foo.go b/_test/b2/foo/foo.go new file mode 100644 index 000000000..7e1e6eee9 --- /dev/null +++ b/_test/b2/foo/foo.go @@ -0,0 +1,3 @@ +package foo + +var Desc = "in b2/foo" diff --git a/_test/import8.go b/_test/import8.go new file mode 100644 index 000000000..863f68ac4 --- /dev/null +++ b/_test/import8.go @@ -0,0 +1,10 @@ +package main + +import "github.com/containous/yaegi/_test/b1/foo" + +func main() { + println(foo.Desc) +} + +// Output: +// in b1/foo diff --git a/interp/cfg.go b/interp/cfg.go index fe9c35b47..36389efa7 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -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) { diff --git a/interp/gta.go b/interp/gta.go index d20328105..3f2441953 100644 --- a/interp/gta.go +++ b/interp/gta.go @@ -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 diff --git a/interp/interp.go b/interp/interp.go index 8fe3de84b..b1f13b8b6 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -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() diff --git a/interp/scope.go b/interp/scope.go index 8b93befb9..ad2479124 100644 --- a/interp/scope.go +++ b/interp/scope.go @@ -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 } diff --git a/interp/src.go b/interp/src.go index ddc652ad4..986491122 100644 --- a/interp/src.go +++ b/interp/src.go @@ -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 { diff --git a/interp/type.go b/interp/type.go index 179db7c7a..b201b6638 100644 --- a/interp/type.go +++ b/interp/type.go @@ -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