diff --git a/_test/ret3.go b/_test/ret3.go index 0465cc0c..fd771be3 100644 --- a/_test/ret3.go +++ b/_test/ret3.go @@ -2,11 +2,11 @@ package main import "fmt" +func r2() (int, int) { return 1, 2 } + func main() { fmt.Println(r2()) } -func r2() (int, int) { return 1, 2 } - // Output: // 1 2 diff --git a/_test/src4.go b/_test/src4.go index 727fe956..15b7ac93 100644 --- a/_test/src4.go +++ b/_test/src4.go @@ -5,6 +5,3 @@ import "github.com/containous/gi/_test/provider" func main() { provider.F1() } - -// Output: -// Hello from Foo diff --git a/interp/ast.go b/interp/ast.go index 6a71498c..d4cfe727 100644 --- a/interp/ast.go +++ b/interp/ast.go @@ -261,9 +261,8 @@ func (a Action) String() string { // of CFG, in order to accomodate forward type declarations // Ast parses src string containing Go code and generates the corresponding AST. -// The AST root node is returned. -func (interp *Interpreter) Ast(src string) (*Node, *NodeMap) { - def := NodeMap{} +// The package name and the AST root node are returned. +func (interp *Interpreter) Ast(src string) (string, *Node) { fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(fset, "sample.go", src, 0) if err != nil { @@ -494,8 +493,6 @@ func (interp *Interpreter) Ast(src string) (*Node, *NodeMap) { // function is not a method, create an empty receiver list addChild(&root, n, &index, FieldList, Nop) } - // Add func name to definitions - def[a.Name.Name] = n st.push(n) case *ast.FuncLit: @@ -609,10 +606,7 @@ func (interp *Interpreter) Ast(src string) (*Node, *NodeMap) { st.push(addChild(&root, anc, &index, TypeAssertExpr, TypeAssert)) case *ast.TypeSpec: - n := addChild(&root, anc, &index, TypeSpec, Nop) - // Add type name to definitions - def[a.Name.Name] = n - st.push(n) + st.push(addChild(&root, anc, &index, TypeSpec, Nop)) case *ast.UnaryExpr: var kind = UnaryExpr @@ -657,7 +651,7 @@ func (interp *Interpreter) Ast(src string) (*Node, *NodeMap) { } return true }) - return root, &def + return pkgName, root } type nodestack []*Node diff --git a/interp/cfg.go b/interp/cfg.go index 574035a6..44260a8e 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -13,7 +13,6 @@ type Symbol struct { node *Node // Node value if index is negative index int // index of value in frame or -1 pkgbin *SymMap // Map of package symbols if typ.cat is BinPkgT, or nil - pkgsrc *NodeMap // Map of package symbols if typ.cat is SrcPkgT, or nil bin interface{} // Symbol from imported bin package if typ.cat is BinT, or nil } @@ -50,14 +49,14 @@ type FrameIndex struct { // PkgContext type stores current state of a package during compiling type PkgContext struct { frameIndex *FrameIndex - nodeMap *NodeMap + NodeMap } // Cfg generates a control flow graph (CFG) from AST (wiring successors in AST) // 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, sdef *NodeMap) []*Node { +func (interp *Interpreter) Cfg(root *Node) []*Node { scope := &Scope{sym: map[string]*Symbol{}} frameIndex := &FrameIndex{} var loop, loopRestart *Node @@ -66,13 +65,7 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { var exports *SymMap var expval *ValueMap var iotaValue int - var srcPkg *NodeMap - - // Fill root scope with initial symbol definitions - for name, node := range *sdef { - scope.sym[name] = &Symbol{node: node, index: -1} - } - log.Println(interp.srcPkg["provider"]) + var pkgName string root.Walk(func(n *Node) bool { // Pre-order processing @@ -91,10 +84,9 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { scope = scope.push(0) case File: - pkgName := n.child[0].ident - srcPkg = interp.srcPkg[pkgName] - if srcPkg == nil { - srcPkg = &NodeMap{} + pkgName = n.child[0].ident + if _, ok := interp.context[pkgName]; !ok { + interp.context[pkgName] = PkgContext{NodeMap: NodeMap{}} } if pkg, ok := interp.Exports[pkgName]; ok { exports = pkg @@ -174,6 +166,7 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { } // TODO: deprecate use of interp.types in favor of scope.sym interp.types[n.child[0].ident] = n.typ + interp.context[pkgName].NodeMap[n.child[0].ident] = n scope.sym[n.child[0].ident] = &Symbol{typ: n.typ} // TODO: export type for use by runtime return false @@ -427,6 +420,8 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { n.typ = interp.types[def.child[2].child[j].child[0].child[0].ident] } n.fsize = l + } else { + log.Println(n.index, "call to unknown def") } } } else if n.child[0].kind == SelectorSrc { @@ -578,6 +573,9 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { n.typ = n.child[2].typ n.val = n scope.sym[funcName].typ = n.typ + scope.sym[funcName].node = n + scope.sym[funcName].index = -1 + interp.context[pkgName].NodeMap[funcName] = n case FuncLit: n.typ = n.child[2].typ @@ -628,12 +626,12 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { } else if n.typ != nil { if n.typ.cat == BinPkgT { n.val = sym.pkgbin - } else if n.typ.cat == SrcPkgT { - n.val = sym.pkgsrc } + } else { + n.sym = sym } n.recv = n - } else if node, ok := (*srcPkg)[n.ident]; ok { + } else if node, ok := interp.context[pkgName].NodeMap[n.ident]; ok { n.val = node n.typ = node.typ n.kind = node.kind @@ -649,17 +647,20 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { symFrameIndex := frameIndex symScope := scope level := 0 + // Back to package level scope for symFrameIndex.anc != nil { level++ - symScope = symScope.anc symFrameIndex = symFrameIndex.anc } + for symScope.anc != nil { + symScope = symScope.anc + } symFrameIndex.max++ symScope.sym[n.ident] = &Symbol{index: symFrameIndex.max} - (*sdef)[n.ident] = n + interp.context[pkgName].NodeMap[n.ident] = n n.findex = symFrameIndex.max n.level = level - log.Println(n.index, n.ident, n.anc.kind, "unresolved, create new at pkg level", n.findex, level) + n.sym = symScope.sym[n.ident] } } @@ -719,7 +720,7 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { } else { // TODO: make sure we do not import a src package more than once interp.importSrcFile(ipath) - scope.sym[name] = &Symbol{typ: &Type{cat: SrcPkgT}, pkgsrc: interp.srcPkg[name]} + scope.sym[name] = &Symbol{typ: &Type{cat: SrcPkgT}} } case KeyValueExpr: @@ -818,15 +819,13 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { n.run = nop } else if n.typ.cat == SrcPkgT { // Resolve source package symbol - pkgSrc := n.child[0].val.(*NodeMap) - name := n.child[1].ident - if node, ok := (*pkgSrc)[name]; ok { + if node, ok := interp.context[n.child[0].ident].NodeMap[n.child[1].ident]; ok { n.val = node n.run = nop n.kind = SelectorSrc n.typ = node.typ } else { - log.Println(n.index, "selector unresolved:", n.child[0].ident+"."+name) + log.Println(n.index, "selector unresolved:", n.child[0].ident+"."+n.child[1].ident) } } else if fi := n.typ.fieldIndex(n.child[1].ident); fi >= 0 { // Resolve struct field index @@ -896,7 +895,6 @@ func (interp *Interpreter) Cfg(root *Node, sdef *NodeMap) []*Node { } } }) - log.Println(sdef) return initNodes } diff --git a/interp/interp.go b/interp/interp.go index 1b9bca3c..c0f02224 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -2,6 +2,7 @@ package interp import ( + "log" "reflect" ) @@ -19,6 +20,7 @@ type Node struct { flen int // frame length (function definition) level int // number of frame indirections to access value kind Kind // kind of node + sym *Symbol // associated symbol typ *Type // type of value in frame, or nil recv *Node // method receiver node for call, or nil frame *Frame // frame pointer, only used for script callbacks from runtime (wrapNode) @@ -41,6 +43,8 @@ type NodeMap map[string]*Node // PkgSrcMap stores package source nodes type PkgSrcMap map[string]*NodeMap +type PkgCtxMap map[string]PkgContext + // SymMap stores executable symbols indexed by name type SymMap map[string]interface{} @@ -66,7 +70,7 @@ type Interpreter struct { Opt Frame *Frame types TypeMap - srcPkg PkgSrcMap + context PkgCtxMap binPkg PkgMap Exports PkgMap Expval PkgValueMap @@ -91,7 +95,7 @@ func NewInterpreter(opt Opt) *Interpreter { return &Interpreter{ Opt: opt, types: defaultTypes, - srcPkg: make(PkgSrcMap), + context: make(PkgCtxMap), binPkg: make(PkgMap), Exports: make(PkgMap), Expval: make(PkgValueMap), @@ -116,16 +120,17 @@ func (i *Interpreter) ImportBin(pkg *map[string]*map[string]interface{}) { // Eval evaluates Go code represented as a string. It returns a map on // current interpreted package exported symbols -func (i *Interpreter) Eval(src string) (string, *NodeMap) { +func (i *Interpreter) Eval(src string) string { // Parse source to AST - root, sdef := i.Ast(src) + pkgName, root := i.Ast(src) + log.Println(pkgName) if i.AstDot { root.AstDot(DotX()) } // Annotate AST with CFG infos - initNodes := i.Cfg(root, sdef) - if entry, ok := (*sdef)[i.Entry]; ok { + initNodes := i.Cfg(root) + if entry, ok := i.context[pkgName].NodeMap[i.Entry]; ok { initNodes = append(initNodes, entry) } @@ -141,5 +146,5 @@ func (i *Interpreter) Eval(src string) (string, *NodeMap) { Run(n, i.Frame, nil, nil, nil, nil, true, false) } } - return root.child[0].ident, sdef + return root.child[0].ident } diff --git a/interp/interp_test.go b/interp/interp_test.go index f65389ff..f2e07b9d 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -1839,11 +1839,11 @@ package main import "fmt" +func r2() (int, int) { return 1, 2 } + func main() { fmt.Println(r2()) } - -func r2() (int, int) { return 1, 2 } ` i := NewInterpreter(Opt{Entry: "main"}) i.ImportBin(export.Pkg) @@ -2594,6 +2594,21 @@ func main() { // Hello from Foo } +func Example_src4() { + src := ` +package main + +import "github.com/containous/gi/_test/provider" + +func main() { + provider.F1() +}` + i := NewInterpreter(Opt{Entry: "main"}) + i.ImportBin(export.Pkg) + i.Eval(src) + +} + func Example_str() { src := ` package main diff --git a/interp/run.go b/interp/run.go index 9f157b2c..05972702 100644 --- a/interp/run.go +++ b/interp/run.go @@ -2,7 +2,6 @@ package interp import ( "fmt" - "log" "reflect" "time" ) @@ -128,7 +127,15 @@ func value(n *Node, f *Frame) interface{} { case Rvalue: return n.rval default: - //log.Println(n.index, n.ident, n.findex, n.level, f) + if n.sym != nil { + if n.sym.index < 0 { + return value(n.sym.node, f) + } + for level := n.level; level > 0; level-- { + f = f.anc + } + return f.data[n.sym.index] + } for level := n.level; level > 0; level-- { f = f.anc } @@ -140,11 +147,19 @@ func value(n *Node, f *Frame) interface{} { } func addrValue(n *Node, f *Frame) *interface{} { - log.Println(n.index, n.ident, n.kind, n.level, n.findex) switch n.kind { case BasicLit, FuncDecl, Rvalue: return &n.val default: + if n.sym != nil { + if n.sym.index < 0 { + return addrValue(n.sym.node, f) + } + for level := n.level; level > 0; level-- { + f = f.anc + } + return &f.data[n.sym.index] + } for level := n.level; level > 0; level-- { f = f.anc } @@ -307,6 +322,7 @@ func call(n *Node, f *Frame) { recv = n.child[0].recv rseq = n.child[0].child[1].val.([]int) } + //log.Println(n.index, "call", n.child[0].ident, value(n.child[0], f)) fn := value(n.child[0], f).(*Node) var ret []int if len(fn.child[2].child) > 1 { @@ -390,11 +406,12 @@ func callBin(n *Node, f *Frame) { in[i] = value(c, f).(reflect.Value) c.frame = f } else { + //log.Println(value(c, f), c.sym, c.level) in[i] = reflect.ValueOf(value(c, f)) } } fun := value(n.child[0], f).(reflect.Value) - log.Println("in:", in) + //log.Println(n.index, "in:", in) v := fun.Call(in) for i := 0; i < n.fsize; i++ { f.data[n.findex+i] = v[i].Interface() @@ -720,7 +737,7 @@ func slice(n *Node, f *Frame) { // slice expression, no low value func slice0(n *Node, f *Frame) { - log.Println(n.index, n.child[0].ident, value(n.child[0], f)) + //log.Println(n.index, n.child[0].ident, value(n.child[0], f)) a := value(n.child[0], f).([]interface{}) switch len(n.child) { case 1: diff --git a/interp/src.go b/interp/src.go index 9804e40c..c217759e 100644 --- a/interp/src.go +++ b/interp/src.go @@ -26,13 +26,9 @@ func (interp *Interpreter) importSrcFile(path string) { if err != nil { log.Fatal(err) } - pkgName, sdef := interp.Eval(string(buf)) - if interp.srcPkg[pkgName] == nil { - s := make(NodeMap) - interp.srcPkg[pkgName] = &s - } - for name, node := range *sdef { - (*interp.srcPkg[pkgName])[name] = node + pkgName := interp.Eval(string(buf)) + if _, ok := interp.context[pkgName]; !ok { + interp.context[pkgName] = PkgContext{NodeMap: NodeMap{}} } } }