func (v *typeView) insertMethod(m *[]*types.Func, elems *[]*typeView, before bool, i int, success, fail func()) { if !before { i++ } sig := &types.Signature{Recv: types.NewVar(0, v.currentPkg, "", *v.typ)} *m = append((*m)[:i], append([]*types.Func{types.NewFunc(0, v.currentPkg, "", sig)}, (*m)[i:]...)...) v.refresh() t := (*elems)[i] t.edit(func() { if *t.typ == nil || len(t.name.Text()) == 0 { *m = append((*m)[:i], (*m)[i+1:]...) v.refresh() if fail != nil { fail() } else { if !before { i-- } SetKeyFocus((*elems)[i]) } } else { if success != nil { success() } else { SetKeyFocus(t) } } }) }
func (r *reader) obj(x ast.Expr) types.Object { switch x := x.(type) { case *ast.Ident: if obj := r.scope.LookupParent(x.Name); obj != nil { if v, ok := obj.(*types.Var); ok && v.Pkg == nil { // ignore local vars return nil } return obj } return unknownObject{pkg: r.pkg, name: x.Name} case *ast.SelectorExpr: // TODO: Type.Method and pkg.Type.Method n1 := name(x.X) n2 := x.Sel.Name switch obj := r.scope.LookupParent(n1).(type) { case *types.PkgName: if obj := obj.Pkg.Scope().Lookup(n2); obj != nil { return obj } return unknownObject{pkg: obj.Pkg, name: n2} case *types.Var: t := obj.Type fm, _, addr := types.LookupFieldOrMethod(t, r.pkg, n2) switch fm := fm.(type) { case *types.Func: sig := fm.Type.(*types.Signature) return types.NewFunc(0, r.pkg, n2, types.NewSignature(nil, newVar("", t), sig.Params, sig.Results, sig.IsVariadic)) case *types.Var: return field{fm, t, addr} } return unknownObject{pkg: obj.Pkg, recv: t, name: n2} } } panic("unreachable") }
func (r *reader) value(b *block, x, y ast.Expr, set bool, s ast.Stmt) { if x2, ok := x.(*ast.UnaryExpr); ok { x = x2.X } var obj types.Object if _, ok := x.(*ast.StarExpr); !ok { // StarExpr indicates an assignment (*x = y), for which obj must be nil obj = r.obj(x) if u, ok := obj.(unknownObject); ok { if _, ok := s.(*ast.DeclStmt); ok { obj = types.NewConst(0, u.pkg, u.name, nil, nil) } else { var t types.Type if set { t = r.scope.Lookup(name(y)).(*types.Var).Type } addr := false if s, ok := s.(*ast.AssignStmt); ok { if s.Tok == token.DEFINE { _, addr = s.Rhs[0].(*ast.UnaryExpr) } } if u.recv != nil { obj = field{types.NewVar(0, u.pkg, u.name, t), u.recv, addr} // it may be a method val, but a non-addressable field is close enough } else { if addr { obj = types.NewVar(0, u.pkg, u.name, t) } else { obj = types.NewFunc(0, u.pkg, u.name, types.NewSignature(nil, newVar("", u.recv), nil, nil, false)) } } } //unknown(obj) == true } } n := newValueNode(obj, r.pkg, set) b.addNode(n) switch x := x.(type) { case *ast.SelectorExpr: r.in(x.X, n.x) case *ast.StarExpr: r.in(x.X, n.x) } if set { r.in(y, n.y) } else { r.out(y, n.y) } r.seq(n, s) }
func (b *browser) KeyPress(event KeyEvent) { if b.options.canFuncAsVal && event.Shift != b.funcAsVal { b.funcAsVal = event.Shift b.refresh() } switch event.Key { case KeyUp: if b.newObj == nil { b.i-- if b.i < 0 { b.i += len(b.objs) } b.refresh() } case KeyDown: if b.newObj == nil { b.i++ if b.i >= len(b.objs) { b.i -= len(b.objs) } b.refresh() } case KeyLeft: if len(b.path) > 0 && b.newObj == nil { parent := b.path[0] b.path = b.path[1:] i := len(b.pathTexts) - 1 b.pathTexts[i].Close() b.pathTexts = b.pathTexts[:i] b.clearText() b.makeCurrent(parent) } case KeyEnter: obj := b.currentObj() if obj == nil { return } if pkg, ok := obj.(*pkgObject); ok && event.Shift && b.options.mutable && b.newObj == nil { Show(b.pkgName) b.pkgName.Accept = func(name string) { if pkg.pkgName != name { pkg.pkgName = name savePackageName(pkg.importPath, name) } b.refresh() SetKeyFocus(b) } b.pkgName.Reject = func() { b.refresh() SetKeyFocus(b) } SetKeyFocus(b.pkgName) return } if event.Command && b.options.mutable && b.newObj == nil { b.newObj = obj b.oldName = obj.GetName() if p, ok := obj.(*pkgObject); ok { delete(pkgs, p.importPath) delete(pkgObjects, p.importPath) } else { if objs := obj.GetPkg().Scope().Objects; objs[obj.GetName()] == obj { delete(objs, obj.GetName()) } else { t, _ := indirect(obj.(*types.Func).Type.(*types.Signature).Recv.Type) n := t.(*types.Named) for i, f2 := range n.Methods { if f2 == obj { n.Methods = append(n.Methods[:i], n.Methods[i+1:]...) break } } } } b.text.SetText(obj.GetName()) return } if obj := b.newObj; obj != nil { if !b.unique(obj.GetName()) { return } b.newObj = nil if p, ok := obj.(*pkgObject); ok { oldImportPath := p.importPath if len(b.path) > 0 { parent := b.path[0].(*pkgObject) p.srcDir = parent.srcDir p.importPath = path.Join(parent.importPath, p.name) } else { dirs := build.Default.SrcDirs() p.srcDir = dirs[len(dirs)-1] p.importPath = p.name } pkgObjects[p.importPath] = p if b.oldName != "" { b.oldName = "" if err := refactor.MovePackage(oldImportPath, p.importPath); err != nil { fmt.Printf("error moving package %s: %s\n", oldImportPath, err) } b.clearText() return } p.pkgName = p.name path := p.fullPath() if err := os.Mkdir(path, 0777); err != nil { fmt.Printf("error creating %s: %s\n", path, err) b.clearText() return } } else { if isMethod(obj) { recv := b.path[0].(*types.TypeName).Type.(*types.Named) recv.Methods = append(recv.Methods, obj.(*types.Func)) } else { pkgs[b.path[0].(*pkgObject).importPath].Scope().Insert(obj) } if b.oldName != "" { newName := obj.GetName() setObjectName(obj, b.oldName) oldPaths := []string{fluxPath(obj)} if t, ok := obj.(*types.TypeName); ok { for _, m := range t.Type.(*types.Named).Methods { oldPaths = append(oldPaths, fluxPath(m)) } } recv := "" if isMethod(obj) { t, _ := indirect(obj.(*types.Func).Type.(*types.Signature).Recv.Type) recv = t.(*types.Named).Obj.Name } if err := refactor.Rename(obj.GetPkg().Path, recv, b.oldName, newName); err != nil { fmt.Printf("error renaming %v to %v: %v\n", b.oldName, newName, err) b.oldName = "" b.clearText() return } setObjectName(obj, newName) newPaths := []string{fluxPath(obj)} if t, ok := obj.(*types.TypeName); ok { for _, m := range t.Type.(*types.Named).Methods { newPaths = append(newPaths, fluxPath(m)) } } for i := range oldPaths { if err := os.Rename(oldPaths[i], newPaths[i]); err != nil { fmt.Println("error renaming files: ", err) } } b.oldName = "" b.clearText() return } } b.makeCurrent(obj) } _, isPkg := obj.(*pkgObject) _, isType := obj.(*types.TypeName) if !(isPkg || isType && !b.options.acceptTypes) { b.finished = true b.accepted(obj) return } fallthrough case KeyRight: if b.newObj == nil { switch obj := b.currentObj().(type) { case *pkgObject, *types.TypeName: if t, ok := obj.(*types.TypeName); ok { if _, ok = t.Type.(*types.Basic); ok || t.Type == nil || !b.options.enterTypes { break } } b.path = append(objects{obj}, b.path...) sep := "." if _, ok := obj.(*pkgObject); ok { sep = "/" } t := NewText(obj.GetName() + sep) t.SetTextColor(color(obj, true, b.funcAsVal)) t.SetBackgroundColor(Color{0, 0, 0, .7}) b.Add(t) x := 0.0 if t, ok := b.lastPathText(); ok { x = Pos(t).X + Width(t) } t.Move(Pt(x, 0)) b.pathTexts = append(b.pathTexts, t) b.clearText() } } case KeyEscape: if b.newObj != nil { if b.oldName != "" { setObjectName(b.newObj, b.oldName) b.oldName = "" if isMethod(b.newObj) { recv := b.path[0].(*types.TypeName).Type.(*types.Named) recv.Methods = append(recv.Methods, b.newObj.(*types.Func)) } else { pkgs[b.path[0].(*pkgObject).importPath].Scope().Insert(b.newObj) } } else if b.i < len(b.objs)-1 { b.i++ } b.newObj = nil b.clearText() } else { b.cancel() } case KeyBackspace: if !event.Command && len(b.text.Text()) > 0 { b.text.KeyPress(event) break } fallthrough case KeyDelete: if event.Command && b.options.mutable && b.newObj == nil { b.clearText() if deleteObj(b.currentObj()) { if b.i > 0 { b.i-- } b.clearText() } } default: if event.Command && (event.Key == KeyN || event.Key == KeyW || event.Key == KeyQ) { b.ViewBase.KeyPress(event) return } if !b.options.mutable { b.text.KeyPress(event) return } makeInPkg := false var pkg *types.Package var recv *types.TypeName if len(b.path) > 0 { switch obj := b.path[0].(type) { case *pkgObject: makeInPkg = true pkg = pkgs[obj.importPath] case *types.TypeName: recv = obj pkg = obj.Pkg } } makePkgInRoot := len(b.path) == 0 && event.Text == "1" makeMethod := recv != nil && event.Text == "3" if b.newObj == nil && event.Command && (makePkgInRoot || makeInPkg || makeMethod) { switch event.Text { case "1": b.newObj = &pkgObject{} case "2": t := types.NewTypeName(0, pkg, "", nil) t.Type = &types.Named{Obj: t} b.newObj = t case "3": sig := &types.Signature{} if recv != nil { sig.Recv = newVar("", &types.Pointer{Elem: recv.Type}) } b.newObj = types.NewFunc(0, pkg, "", sig) case "4": b.newObj = types.NewVar(0, pkg, "", nil) case "5": b.newObj = types.NewConst(0, pkg, "", nil, nil) default: b.text.KeyPress(event) return } b.clearText() } else { b.text.KeyPress(event) } } }
func (b browser) filteredObjs() (objs objects) { add := func(obj types.Object) { if invisible(obj, b.currentPkg) { return } if _, ok := obj.(*pkgObject); ok || b.options.objFilter == nil || b.options.objFilter(obj) { objs = append(objs, obj) } } addSubPkgs := func(importPath string) { seen := map[string]bool{} for _, srcDir := range build.Default.SrcDirs() { files, err := ioutil.ReadDir(filepath.Join(srcDir, importPath)) if err != nil { continue } for _, f := range files { name := filepath.Base(f.Name()) if !f.IsDir() || !unicode.IsLetter([]rune(name)[0]) || name == "testdata" || seen[name] { continue } if _, ok := b.newObj.(*pkgObject); ok && name == b.oldName { // when editing a package path, it will be added in filteredObjs as newObj, so don't add it here continue } seen[name] = true importPath := path.Join(importPath, name) pkgObj, ok := pkgObjects[importPath] if !ok { if pkg, err := build.Import(importPath, "", build.AllowBinary); err == nil { name = pkg.Name } pkgObj = &pkgObject{nil, path.Base(importPath), srcDir, importPath, name} pkgObjects[importPath] = pkgObj } add(pkgObj) } } } if b.typ != nil { mset := types.NewMethodSet(b.typ) for i := 0; i < mset.Len(); i++ { m := mset.At(i) // m.Type() has the correct receiver for inherited methods (m.Obj does not) add(types.NewFunc(0, m.Obj.GetPkg(), m.Obj.GetName(), m.Type().(*types.Signature))) } fset := types.NewFieldSet(b.typ) for i := 0; i < fset.Len(); i++ { f := fset.At(i) add(field{f.Obj.(*types.Var), f.Recv, f.Indirect}) } } else if len(b.path) > 0 { switch obj := b.path[0].(type) { case *pkgObject: if pkg, err := getPackage(obj.importPath); err == nil { for _, obj := range pkg.Scope().Objects { add(obj) } } else { if _, ok := err.(*build.NoGoError); !ok { fmt.Println(err) } pkgs[obj.importPath] = types.NewPackage(obj.importPath, obj.pkgName, types.NewScope(types.Universe)) } addSubPkgs(obj.importPath) case *types.TypeName: for _, m := range intuitiveMethodSet(obj.Type) { if types.IsIdentical(m.Obj.(*types.Func).Type.(*types.Signature).Recv.Type, m.Recv) { // preserve Object identity for non-inherited methods so that fluxObjs works add(m.Obj) } else { // m.Type() has the correct receiver for inherited methods (m.Obj does not) add(types.NewFunc(0, m.Obj.GetPkg(), m.Obj.GetName(), m.Type().(*types.Signature))) } } } } else { for _, name := range []string{"break", "call", "continue", "convert", "defer", "func", "go", "if", "loop", "return", "select", "typeAssert"} { add(special{newVar(name, nil)}) } for _, name := range []string{"=", "*"} { add(newVar(name, nil)) } pkgs := b.imports if b.currentPkg != nil { pkgs = append(pkgs, b.currentPkg) } for _, p := range pkgs { for _, obj := range p.Scope().Objects { add(obj) } } for _, obj := range types.Universe.Objects { switch obj.GetName() { case "nil", "print", "println": continue } add(obj) } for _, op := range []string{"!", "&&", "||", "+", "-", "*", "/", "%", "&", "|", "^", "&^", "<<", ">>", "==", "!=", "<", "<=", ">", ">=", "[]", "[:]", "<-"} { add(types.NewFunc(0, nil, op, nil)) } for _, t := range []*types.TypeName{protoPointer, protoArray, protoSlice, protoMap, protoChan, protoFunc, protoInterface, protoStruct} { add(t) } addSubPkgs("") } sort.Sort(objs) return }
func (r *reader) typ(x ast.Expr) types.Type { switch x := x.(type) { case *ast.Ident: if t, ok := r.scope.LookupParent(x.Name).(*types.TypeName); ok { return t.Type } return types.NewNamed(types.NewTypeName(0, r.pkg, x.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true case *ast.SelectorExpr: pkg := r.scope.LookupParent(name(x.X)).(*types.PkgName).Pkg if t, ok := pkg.Scope().Lookup(x.Sel.Name).(*types.TypeName); ok { return t.Type } return types.NewNamed(types.NewTypeName(0, r.pkg, x.Sel.Name, nil), types.Typ[types.Invalid], nil) //unknown(t.Obj) == true case *ast.StarExpr: return types.NewPointer(r.typ(x.X)) case *ast.ArrayType: elem := r.typ(x.Elt) if x.Len != nil { // TODO: x.Len return types.NewArray(elem, 0) } return types.NewSlice(elem) case *ast.Ellipsis: return types.NewSlice(r.typ(x.Elt)) case *ast.MapType: return types.NewMap(r.typ(x.Key), r.typ(x.Value)) case *ast.ChanType: dir := types.SendRecv if x.Dir&ast.SEND == 0 { dir = types.RecvOnly } if x.Dir&ast.RECV == 0 { dir = types.SendOnly } return types.NewChan(dir, r.typ(x.Value)) case *ast.FuncType: var params, results []*types.Var for _, f := range x.Params.List { t := r.typ(f.Type) if f.Names == nil { params = append(params, types.NewParam(0, r.pkg, "", t)) } for _, n := range f.Names { params = append(params, types.NewParam(0, r.pkg, n.Name, t)) } } variadic := false if x.Results != nil { for _, f := range x.Results.List { t := r.typ(f.Type) if f.Names == nil { results = append(results, types.NewParam(0, r.pkg, "", t)) } for _, n := range f.Names { results = append(results, types.NewParam(0, r.pkg, n.Name, t)) } _, variadic = f.Type.(*ast.Ellipsis) } } return types.NewSignature(nil, nil, params, results, variadic) case *ast.StructType: var fields []*types.Var if x.Fields != nil { for _, f := range x.Fields.List { t := r.typ(f.Type) if f.Names == nil { fields = append(fields, types.NewField(0, r.pkg, "", t, true)) } for _, n := range f.Names { fields = append(fields, types.NewField(0, r.pkg, n.Name, t, false)) } } } return types.NewStruct(fields, nil) case *ast.InterfaceType: var methods []*types.Func var embeddeds []*types.Named if x.Methods != nil { for _, f := range x.Methods.List { switch t := r.typ(f.Type).(type) { case *types.Signature: methods = append(methods, types.NewFunc(0, r.pkg, f.Names[0].Name, t)) case *types.Named: embeddeds = append(embeddeds, t) } } } return types.NewInterface(methods, embeddeds) } panic("unreachable") }
func (r *reader) call(b *block, x *ast.CallExpr, godefer string, s ast.Stmt) node { obj := r.obj(x.Fun) if u, ok := obj.(unknownObject); ok { sig := &types.Signature{} if u.recv != nil { sig.Recv = newVar("", u.recv) } for _, arg := range x.Args { sig.Params = append(sig.Params, newVar("", r.scope.Lookup(name(arg)).(*types.Var).Type)) } if s, ok := s.(*ast.AssignStmt); ok { for _ = range s.Lhs { sig.Results = append(sig.Results, newVar("", nil)) } } obj = types.NewFunc(0, u.pkg, u.name, sig) //unknown(obj) == true } n := newCallNode(obj, r.pkg, godefer) b.addNode(n) args := x.Args switch { case isMethod(obj): recv := x.Fun.(*ast.SelectorExpr).X args = append([]ast.Expr{recv}, args...) case obj == nil: // func value call args = append([]ast.Expr{x.Fun}, args...) } if n, ok := n.(interface { setType(types.Type) }); ok { n.setType(r.typ(args[0])) args = args[1:] } for i, arg := range args { if i >= len(ins(n)) { var newInput func(*types.Var) *port var v *types.Var switch n := n.(type) { case *callNode: newInput = n.newInput _, v = n.variadic() case *appendNode: newInput = n.newInput v = ins(n)[0].obj } if v != nil { if x.Ellipsis == 0 { v = newVar(v.Name, v.Type.(*types.Slice).Elem) } in := newInput(v) if x.Ellipsis != 0 { in.valView.setEllipsis() } } else { in := newInput(newVar("", r.scope.Lookup(name(arg)).(*types.Var).Type)) in.bad = true } } r.in(arg, ins(n)[i]) } r.seq(n, s) return n }
func (r *reader) block(b *block, s []ast.Stmt) { for _, s := range s { switch s := s.(type) { case *ast.AssignStmt: if s.Tok == token.DEFINE { switch x := s.Rhs[0].(type) { case *ast.BinaryExpr: n := newOperatorNode(types.NewFunc(0, nil, x.Op.String(), nil)) b.addNode(n) r.in(x.X, n.ins[0]) r.in(x.Y, n.ins[1]) r.out(s.Lhs[0], n.outs[0]) case *ast.CallExpr: if p, ok := x.Fun.(*ast.ParenExpr); ok { // writer puts conversions in parens for easy recognition n := newConvertNode(r.pkg) b.addNode(n) n.setType(r.typ(p.X)) r.in(x.Args[0], n.ins[0]) r.out(s.Lhs[0], n.outs[0]) } else { n := r.call(b, x, "", s) for i, res := range s.Lhs { if i >= len(outs(n)) { out := n.(*callNode).newOutput(nil) out.bad = true } r.out(res, outs(n)[i]) } } case *ast.CompositeLit: r.compositeLit(b, x, false, s) case *ast.FuncLit: n := newFuncNode(nil, b.childArranged) b.addNode(n) n.output.setType(r.typ(x.Type)) r.out(s.Lhs[0], n.output) r.fun(n, x.Type, x.Body) case *ast.Ident, *ast.SelectorExpr, *ast.StarExpr: r.value(b, x, s.Lhs[0], false, s) case *ast.IndexExpr: r.index(b, x, s.Lhs[0], false, s) case *ast.SliceExpr: n := newSliceNode() b.addNode(n) r.in(x.X, n.x) r.in(x.Low, n.low) if x.High == nil { n.removePortBase(n.high) n.high = nil } else { r.in(x.High, n.high) } if x.Max != nil { n.max = n.newInput(newVar("max", types.Typ[types.Int])) r.in(x.Max, n.max) } r.out(s.Lhs[0], n.y) case *ast.TypeAssertExpr: n := newTypeAssertNode(r.pkg) b.addNode(n) n.setType(r.typ(x.Type)) r.in(x.X, n.ins[0]) r.out(s.Lhs[0], n.outs[0]) r.out(s.Lhs[1], n.outs[1]) case *ast.UnaryExpr: switch x.Op { case token.AND: switch y := x.X.(type) { case *ast.CompositeLit: r.compositeLit(b, y, true, s) case *ast.IndexExpr: r.index(b, y, s.Lhs[0], false, s) default: r.value(b, x, s.Lhs[0], false, s) } case token.NOT: n := newOperatorNode(types.NewFunc(0, nil, x.Op.String(), nil)) b.addNode(n) r.in(x.X, n.ins[0]) r.out(s.Lhs[0], n.outs[0]) case token.ARROW: n := r.sendrecv(b, x.X, nil, s) r.out(s.Lhs[0], n.elem) r.out(s.Lhs[1], n.ok) } } } else { lh := s.Lhs[0] rh := s.Rhs[0] if x, ok := lh.(*ast.IndexExpr); ok { r.index(b, x, rh, true, s) } else if id, ok := lh.(*ast.Ident); !ok || r.conns[id.Name] == nil { r.value(b, lh, rh, true, s) } else { c := newConnection() lh := name(lh) rh := name(rh) c.setSrc(r.ports[rh]) if cmt, ok := r.cmap[s]; ok { c.src.conntxt.SetText(cmt[0].List[0].Text[2:]) c.toggleHidden() } if p, ok := r.ports[lh]; ok { c.feedback = true c.setDst(p) } else { r.conns[lh] = append(r.conns[lh], c) } } } case *ast.BranchStmt: n := newBranchNode(s.Tok.String()) b.addNode(n) r.seq(n, s) case *ast.DeclStmt: decl := s.Decl.(*ast.GenDecl) v := decl.Specs[0].(*ast.ValueSpec) switch decl.Tok { case token.VAR: name := v.Names[0].Name if v.Type != nil { r.scope.Insert(newVar(name, r.typ(v.Type))) // local var has nil Pkg r.conns[name] = []*connection{} } else { r.out(v.Names[0], b.node.(*loopNode).inputsNode.outs[1]) } case token.CONST: switch x := v.Values[0].(type) { case *ast.BasicLit: n := newBasicLiteralNode(x.Kind) b.addNode(n) switch x.Kind { case token.INT, token.FLOAT: n.text.SetText(x.Value) case token.IMAG: // TODO case token.STRING, token.CHAR: text, _ := strconv.Unquote(x.Value) n.text.SetText(text) } r.out(v.Names[0], n.outs[0]) r.seq(n, s) case *ast.Ident, *ast.SelectorExpr: r.value(b, x, v.Names[0], false, s) } } case *ast.DeferStmt: r.call(b, s.Call, "defer ", s) case *ast.ExprStmt: switch x := s.X.(type) { case *ast.CallExpr: r.call(b, x, "", s) case *ast.UnaryExpr: r.sendrecv(b, x.X, nil, s) } case *ast.ForStmt: n := newLoopNode(b.childArranged) b.addNode(n) if s.Cond != nil { r.in(s.Cond.(*ast.BinaryExpr).Y, n.input) } if s.Init != nil { r.out(s.Init.(*ast.AssignStmt).Lhs[0], n.inputsNode.outs[0]) } r.block(n.loopblk, s.Body.List) r.seq(n, s) case *ast.GoStmt: r.call(b, s.Call, "go ", s) case *ast.IfStmt: n := newIfNode(b.childArranged) b.addNode(n) for s := ast.Stmt(s); s != nil; { b, cond := n.newBlock() switch s2 := s.(type) { case *ast.IfStmt: r.in(s2.Cond, cond) r.block(b, s2.Body.List) s = s2.Else case *ast.BlockStmt: r.block(b, s2.List) s = nil } } r.seq(n, s) case *ast.RangeStmt: n := newLoopNode(b.childArranged) b.addNode(n) r.in(s.X, n.input) r.out(s.Key, n.inputsNode.outs[0]) if s.Value != nil { r.out(s.Value, n.inputsNode.outs[1]) } r.block(n.loopblk, s.Body.List) r.seq(n, s) case *ast.ReturnStmt: n := newBranchNode("return") b.addNode(n) r.seq(n, s) case *ast.SelectStmt: n := newSelectNode(b.childArranged) b.addNode(n) for _, s := range s.Body.List { s := s.(*ast.CommClause) c := n.newCase() switch s := s.Comm.(type) { case *ast.AssignStmt: c.send = false r.in(s.Rhs[0].(*ast.UnaryExpr).X, c.ch) r.out(s.Lhs[0], c.elemOk.outs[0]) r.out(s.Lhs[1], c.elemOk.outs[1]) case *ast.ExprStmt: c.send = false r.in(s.X.(*ast.UnaryExpr).X, c.ch) case *ast.SendStmt: r.in(s.Chan, c.ch) r.in(s.Value, c.elem) case nil: c.setDefault() } r.block(c.blk, s.Body) } r.seq(n, s) case *ast.SendStmt: r.sendrecv(b, s.Chan, s.Value, s) } } }