func (w writer) qualifiedName(obj types.Object) string { n := obj.GetName() if p, ok := w.pkgNames[obj.GetPkg()]; ok { return p + "." + n } return n }
func newValueNode(obj types.Object, currentPkg *types.Package, set bool) *valueNode { n := &valueNode{obj: obj, set: set} n.nodeBase = newNodeBase(n) dot := "" switch obj.(type) { case field, *types.Func, nil: if _, ok := obj.(*types.Func); !ok || isMethod(obj) { n.x = n.newInput(nil) if obj == nil { n.x.connsChanged = n.connsChanged } dot = "." } } if obj != nil { if p := obj.GetPkg(); p != currentPkg && p != nil && dot == "" { n.pkg.setPkg(p) } n.text.SetText(dot + obj.GetName()) } n.text.SetTextColor(color(&types.Var{}, true, false)) if set { n.y = n.newInput(nil) } else { n.y = n.newOutput(nil) } n.addSeqPorts() n.connsChanged() return n }
func objLess(o1, o2 types.Object) bool { n1, n2 := o1.GetName(), o2.GetName() switch o1.(type) { case special: switch o2.(type) { case special: return n1 < n2 default: return true } case *types.TypeName: switch o2.(type) { case special: return false case *types.TypeName: return n1 < n2 default: return true } case *types.Func, *types.Builtin: switch o2.(type) { case special, *types.TypeName: return false case *types.Func, *types.Builtin: return n1 < n2 default: return true } case *types.Var, field: switch o2.(type) { default: return false case *types.Var, field: return n1 < n2 case *types.Const, *pkgObject: return true } case *types.Const: switch o2.(type) { default: return false case *types.Const: return n1 < n2 case *pkgObject: return true } case *pkgObject: switch o2.(type) { default: return false case *pkgObject: return n1 < n2 } } panic("unreachable") }
func isCompositeType(obj types.Object) bool { switch obj { case protoArray, protoSlice, protoMap, protoStruct: return true } if obj, ok := obj.(*types.TypeName); ok { switch underlying(obj.GetType()).(type) { case *types.Array, *types.Slice, *types.Map, *types.Struct: return true } } return false }
func isMakeableType(obj types.Object) bool { switch obj { case protoSlice, protoMap, protoChan: return true } if obj, ok := obj.(*types.TypeName); ok { switch underlying(obj.GetType()).(type) { case *types.Slice, *types.Map, *types.Chan: return true } } return false }
func setObjectName(obj types.Object, name string) { switch obj := obj.(type) { case *pkgObject: obj.name = name case *types.TypeName: obj.Name = name case *types.Func: obj.Name = name case *types.Var: obj.Name = name case *types.Const: obj.Name = name } }
func loadFunc(obj types.Object) *funcNode { f := newFuncNode(obj, nil) fset := token.NewFileSet() file, err := parser.ParseFile(fset, fluxPath(obj), nil, parser.ParseComments) if err == nil { r := &reader{fset, obj.GetPkg(), types.NewScope(obj.GetPkg().Scope()), map[string]*port{}, map[string][]*connection{}, ast.NewCommentMap(fset, file, file.Comments), map[int]node{}} for _, i := range file.Imports { path, _ := strconv.Unquote(i.Path.Value) pkg, err := getPackage(path) if err != nil { fmt.Printf("error importing %s: %s\n", i.Path.Value, err) continue } name := pkg.Name if i.Name != nil { name = i.Name.Name } r.scope.Insert(types.NewPkgName(0, pkg, name)) } decl := file.Decls[len(file.Decls)-1].(*ast.FuncDecl) // get param and result var names from the source, as the obj names might not match if decl.Recv != nil { r.out(decl.Recv.List[0].Names[0], f.inputsNode.newOutput(obj.GetType().(*types.Signature).Recv)) } r.fun(f, decl.Type, decl.Body) } else { // this is a new func; save it if isMethod(obj) { f.inputsNode.newOutput(obj.GetType().(*types.Signature).Recv) } saveFunc(f) } return f }
func newOperatorNode(obj types.Object) *operatorNode { n := &operatorNode{op: obj.GetName()} n.nodeBase = newNodeBase(n) n.text.SetText(n.op) n.text.SetTextColor(color(&types.Func{}, true, false)) n.newInput(nil).connsChanged = n.connsChanged if n.op != "!" { n.newInput(nil).connsChanged = n.connsChanged } n.newOutput(nil) n.connsChanged() return n }
func newWriter(obj types.Object) *writer { src, err := os.Create(fluxPath(obj)) if err != nil { fmt.Printf("error creating %s: %s\n", fluxPath(obj), err) return nil } w := &writer{src, obj.GetPkg(), map[*types.Package]string{}, map[string]int{}, 0, map[node]int{}, 0} fluxObjs[obj] = true w.write("// Generated by Flux, not meant for human consumption. Editing may make it unreadable by Flux.\n\n") w.write("package %s\n\n", w.pkg.Name) for _, name := range append(types.Universe.Names(), w.pkg.Scope().Names()...) { w.name(name) } return w }
func unknown(obj types.Object) bool { switch obj := obj.(type) { case field: fm, _, _ := types.LookupFieldOrMethod(obj.recv, obj.Pkg, obj.Name) _, ok := fm.(*types.Var) return !ok case *types.Func: if sig, ok := obj.Type.(*types.Signature); ok && sig.Recv != nil { fm, _, _ := types.LookupFieldOrMethod(sig.Recv.Type, obj.Pkg, obj.Name) _, ok := fm.(*types.Func) return !ok } } pkg := obj.GetPkg() return pkg != nil && pkg.Scope().Lookup(obj.GetName()) == nil }
func isGoDeferrable(obj types.Object) bool { switch obj := obj.(type) { case special: return obj.Name == "call" case *types.Builtin: switch obj.Name { case "close", "copy", "delete", "panic", "recover": return true } case *types.Func: return !isOperator(obj) case *types.TypeName: _, ok := obj.GetType().(*types.Named) return ok } return false }
func color(obj types.Object, bright, funcAsVal bool) Color { alpha := .7 if bright { alpha = 1 } switch obj.(type) { case special: return Color{1, 1, .6, alpha} case *pkgObject: return Color{1, 1, 1, alpha} case *types.TypeName: return Color{.6, 1, .6, alpha} case *types.Func, *types.Builtin: if funcAsVal && obj.GetPkg() != nil { //Pkg==nil == builtin return color(&types.Var{}, bright, funcAsVal) } return Color{1, .6, .6, alpha} case *types.Var, *types.Const, field: return Color{.6, .6, 1, alpha} } panic(fmt.Sprintf("unknown object type %T", obj)) }
func fluxPath(obj types.Object) string { pkg, err := build.Import(obj.GetPkg().Path, "", build.FindOnly) if err != nil { fmt.Println("error importing \"%s\": %s\n", obj.GetPkg().Path, err) return "" } name := obj.GetName() if !obj.IsExported() { // unexported names are suffixed with "-" to avoid possible conflicts on case-insensitive systems name += "-" } if isMethod(obj) { t, _ := indirect(obj.GetType().(*types.Signature).Recv.Type) recv := t.(*types.Named).Obj typeName := recv.Name if !recv.IsExported() { typeName += "-" } name = typeName + "." + name } return filepath.Join(pkg.Dir, name+".flux.go") }
func deleteObj(obj types.Object) bool { if p, ok := obj.(*pkgObject); ok { if p, err := getPackage(p.importPath); err == nil { for _, obj := range p.Scope().Objects { deleteObj(obj) } } dir := p.fullPath() os.Remove(filepath.Join(dir, "package.flux.go")) os.Remove(filepath.Join(dir, ".DS_Store")) if files, err := ioutil.ReadDir(dir); err != nil || len(files) > 0 || trash.Trash(dir) != nil { return false } delete(pkgObjects, p.importPath) delete(pkgs, p.importPath) return true } if !fluxObjs[obj] { return false } if t, ok := obj.(*types.TypeName); ok { t := t.Type.(*types.Named) for _, m := range t.Methods { deleteObj(m) } if len(t.Methods) > 0 { return false } } if trash.Trash(fluxPath(obj)) != nil { return false } 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 } } } delete(fluxObjs, obj) return true }
func (b *block) newNode(obj types.Object, funcAsVal bool, godefer string) node { var n node currentPkg := b.func_().pkg() switch obj := obj.(type) { case special: switch obj.Name { case "break", "continue", "return": n = newBranchNode(obj.Name) case "call": n = newCallNode(nil, currentPkg, godefer) case "convert": n = newConvertNode(currentPkg) case "func": n = newFuncNode(nil, b.childArranged) case "go", "defer": godefer = obj.Name + " " browser := newBrowser(browserOptions{objFilter: isGoDeferrable, enterTypes: true}, b) browser.Move(Center(b)) browser.accepted = func(obj types.Object) { browser.Close() b.newNode(obj, false, godefer) } browser.canceled = func() { browser.Close() SetKeyFocus(b) } b.Add(browser) SetKeyFocus(browser) return nil case "if": i := newIfNode(b.childArranged) i.newBlock() n = i case "loop": n = newLoopNode(b.childArranged) case "select": n = newSelectNode(b.childArranged) case "typeAssert": n = newTypeAssertNode(currentPkg) } case *types.Func, *types.Builtin: if obj.GetName() == "[]" { n = newIndexNode(false) } else if obj.GetName() == "[:]" { n = newSliceNode() } else if obj.GetName() == "<-" { n = newChanNode(true) } else if isOperator(obj) { n = newOperatorNode(obj) } else if funcAsVal && obj.GetPkg() != nil { //Pkg==nil == builtin n = newValueNode(obj, currentPkg, false) } else { n = newCallNode(obj, currentPkg, godefer) } case *types.Var, *types.Const, field: switch obj.GetName() { default: n = newValueNode(obj, currentPkg, false) case "=": n = newValueNode(nil, nil, true) case "*": n = newValueNode(nil, nil, false) } } b.addNode(n) MoveCenter(n, Center(b)) if nn, ok := n.(interface { editType() }); ok { nn.editType() } else { SetKeyFocus(n) } return n }
func newCallNode(obj types.Object, currentPkg *types.Package, godefer string) node { if obj == nil { n := &callNode{} n.nodeBase = newGoDeferNodeBase(n, godefer) if godefer == "" { n.text.SetText("call") } else { n.text.SetText("") //trigger TextChanged } n.text.SetTextColor(color(special{}, true, false)) n.addSeqPorts() in := n.newInput(nil) in.connsChanged = func() { t := inputType(in) in.setType(t) // TODO: add/remove/modify only the affected ports. beware: t == in.obj.Type because portsNode mutates the signature in place. for _, p := range append(ins(n)[1:], outs(n)...) { n.removePortBase(p) } if t != nil { n.addPorts(underlying(t).(*types.Signature)) } } return n } if sig, ok := obj.GetType().(*types.Signature); ok { n := &callNode{obj: obj} n.nodeBase = newGoDeferNodeBase(n, godefer) name := obj.GetName() if sig.Recv != nil { name = "." + name } else if p := obj.GetPkg(); p != currentPkg && p != nil { n.pkg.setPkg(obj.GetPkg()) } n.text.SetText(name) n.text.SetTextColor(color(&types.Func{}, true, false)) n.addSeqPorts() n.addPorts(sig) return n } switch name := obj.GetName(); name { case "append": return newAppendNode() case "close": return newCloseNode(godefer) case "complex": return newComplexNode() case "copy": return newCopyNode(godefer) case "delete": return newDeleteNode(godefer) case "len", "cap": return newLenCapNode(name) case "make": return newMakeNode(currentPkg) case "new": return newNewNode(currentPkg) case "panic", "recover": return newPanicRecoverNode(name, godefer) case "real", "imag": return newRealImagNode(name) default: panic("unknown builtin: " + name) } }
func invisible(obj types.Object, p *types.Package) bool { p2 := obj.GetPkg() return !(p2 == nil || p == nil || p2 == p || obj.IsExported()) }
func isOperator(obj types.Object) bool { name := obj.GetName() return len(name) > 0 && !unicode.IsLetter([]rune(name)[0]) }