gopkg.in/docker/docker.v23@v23.0.11/pkg/plugins/pluginrpc-gen/parser.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "go/ast" 7 "go/parser" 8 "go/token" 9 "path" 10 "reflect" 11 "strings" 12 ) 13 14 var errBadReturn = errors.New("found return arg with no name: all args must be named") 15 16 type errUnexpectedType struct { 17 expected string 18 actual interface{} 19 } 20 21 func (e errUnexpectedType) Error() string { 22 return fmt.Sprintf("got wrong type expecting %s, got: %v", e.expected, reflect.TypeOf(e.actual)) 23 } 24 25 // ParsedPkg holds information about a package that has been parsed, 26 // its name and the list of functions. 27 type ParsedPkg struct { 28 Name string 29 Functions []function 30 Imports []importSpec 31 } 32 33 type function struct { 34 Name string 35 Args []arg 36 Returns []arg 37 Doc string 38 } 39 40 type arg struct { 41 Name string 42 ArgType string 43 PackageSelector string 44 } 45 46 func (a *arg) String() string { 47 return a.Name + " " + a.ArgType 48 } 49 50 type importSpec struct { 51 Name string 52 Path string 53 } 54 55 func (s *importSpec) String() string { 56 var ss string 57 if len(s.Name) != 0 { 58 ss += s.Name 59 } 60 ss += s.Path 61 return ss 62 } 63 64 // Parse parses the given file for an interface definition with the given name. 65 func Parse(filePath string, objName string) (*ParsedPkg, error) { 66 fs := token.NewFileSet() 67 pkg, err := parser.ParseFile(fs, filePath, nil, parser.AllErrors) 68 if err != nil { 69 return nil, err 70 } 71 p := &ParsedPkg{} 72 p.Name = pkg.Name.Name 73 obj, exists := pkg.Scope.Objects[objName] 74 if !exists { 75 return nil, fmt.Errorf("could not find object %s in %s", objName, filePath) 76 } 77 if obj.Kind != ast.Typ { 78 return nil, fmt.Errorf("exected type, got %s", obj.Kind) 79 } 80 spec, ok := obj.Decl.(*ast.TypeSpec) 81 if !ok { 82 return nil, errUnexpectedType{"*ast.TypeSpec", obj.Decl} 83 } 84 iface, ok := spec.Type.(*ast.InterfaceType) 85 if !ok { 86 return nil, errUnexpectedType{"*ast.InterfaceType", spec.Type} 87 } 88 89 p.Functions, err = parseInterface(iface) 90 if err != nil { 91 return nil, err 92 } 93 94 // figure out what imports will be needed 95 imports := make(map[string]importSpec) 96 for _, f := range p.Functions { 97 args := append(f.Args, f.Returns...) 98 for _, arg := range args { 99 if len(arg.PackageSelector) == 0 { 100 continue 101 } 102 103 for _, i := range pkg.Imports { 104 if i.Name != nil { 105 if i.Name.Name != arg.PackageSelector { 106 continue 107 } 108 imports[i.Path.Value] = importSpec{Name: arg.PackageSelector, Path: i.Path.Value} 109 break 110 } 111 112 _, name := path.Split(i.Path.Value) 113 splitName := strings.Split(name, "-") 114 if len(splitName) > 1 { 115 name = splitName[len(splitName)-1] 116 } 117 // import paths have quotes already added in, so need to remove them for name comparison 118 name = strings.TrimPrefix(name, `"`) 119 name = strings.TrimSuffix(name, `"`) 120 if name == arg.PackageSelector { 121 imports[i.Path.Value] = importSpec{Path: i.Path.Value} 122 break 123 } 124 } 125 } 126 } 127 128 for _, spec := range imports { 129 p.Imports = append(p.Imports, spec) 130 } 131 132 return p, nil 133 } 134 135 func parseInterface(iface *ast.InterfaceType) ([]function, error) { 136 var functions []function 137 for _, field := range iface.Methods.List { 138 switch f := field.Type.(type) { 139 case *ast.FuncType: 140 method, err := parseFunc(field) 141 if err != nil { 142 return nil, err 143 } 144 if method == nil { 145 continue 146 } 147 functions = append(functions, *method) 148 case *ast.Ident: 149 spec, ok := f.Obj.Decl.(*ast.TypeSpec) 150 if !ok { 151 return nil, errUnexpectedType{"*ast.TypeSpec", f.Obj.Decl} 152 } 153 iface, ok := spec.Type.(*ast.InterfaceType) 154 if !ok { 155 return nil, errUnexpectedType{"*ast.TypeSpec", spec.Type} 156 } 157 funcs, err := parseInterface(iface) 158 if err != nil { 159 fmt.Println(err) 160 continue 161 } 162 functions = append(functions, funcs...) 163 default: 164 return nil, errUnexpectedType{"*astFuncType or *ast.Ident", f} 165 } 166 } 167 return functions, nil 168 } 169 170 func parseFunc(field *ast.Field) (*function, error) { 171 f := field.Type.(*ast.FuncType) 172 method := &function{Name: field.Names[0].Name} 173 if _, exists := skipFuncs[method.Name]; exists { 174 fmt.Println("skipping:", method.Name) 175 return nil, nil 176 } 177 if f.Params != nil { 178 args, err := parseArgs(f.Params.List) 179 if err != nil { 180 return nil, err 181 } 182 method.Args = args 183 } 184 if f.Results != nil { 185 returns, err := parseArgs(f.Results.List) 186 if err != nil { 187 return nil, fmt.Errorf("error parsing function returns for %q: %v", method.Name, err) 188 } 189 method.Returns = returns 190 } 191 return method, nil 192 } 193 194 func parseArgs(fields []*ast.Field) ([]arg, error) { 195 var args []arg 196 for _, f := range fields { 197 if len(f.Names) == 0 { 198 return nil, errBadReturn 199 } 200 for _, name := range f.Names { 201 p, err := parseExpr(f.Type) 202 if err != nil { 203 return nil, err 204 } 205 args = append(args, arg{name.Name, p.value, p.pkg}) 206 } 207 } 208 return args, nil 209 } 210 211 type parsedExpr struct { 212 value string 213 pkg string 214 } 215 216 func parseExpr(e ast.Expr) (parsedExpr, error) { 217 var parsed parsedExpr 218 switch i := e.(type) { 219 case *ast.Ident: 220 parsed.value += i.Name 221 case *ast.StarExpr: 222 p, err := parseExpr(i.X) 223 if err != nil { 224 return parsed, err 225 } 226 parsed.value += "*" 227 parsed.value += p.value 228 parsed.pkg = p.pkg 229 case *ast.SelectorExpr: 230 p, err := parseExpr(i.X) 231 if err != nil { 232 return parsed, err 233 } 234 parsed.pkg = p.value 235 parsed.value += p.value + "." 236 parsed.value += i.Sel.Name 237 case *ast.MapType: 238 parsed.value += "map[" 239 p, err := parseExpr(i.Key) 240 if err != nil { 241 return parsed, err 242 } 243 parsed.value += p.value 244 parsed.value += "]" 245 p, err = parseExpr(i.Value) 246 if err != nil { 247 return parsed, err 248 } 249 parsed.value += p.value 250 parsed.pkg = p.pkg 251 case *ast.ArrayType: 252 parsed.value += "[]" 253 p, err := parseExpr(i.Elt) 254 if err != nil { 255 return parsed, err 256 } 257 parsed.value += p.value 258 parsed.pkg = p.pkg 259 default: 260 return parsed, errUnexpectedType{"*ast.Ident or *ast.StarExpr", i} 261 } 262 return parsed, nil 263 }