github.com/wulonghui/docker@v1.8.0-rc2/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 "reflect" 10 "strings" 11 ) 12 13 var ErrBadReturn = errors.New("found return arg with no name: all args must be named") 14 15 type ErrUnexpectedType struct { 16 expected string 17 actual interface{} 18 } 19 20 func (e ErrUnexpectedType) Error() string { 21 return fmt.Sprintf("got wrong type expecting %s, got: %v", e.expected, reflect.TypeOf(e.actual)) 22 } 23 24 type parsedPkg struct { 25 Name string 26 Functions []function 27 } 28 29 type function struct { 30 Name string 31 Args []arg 32 Returns []arg 33 Doc string 34 } 35 36 type arg struct { 37 Name string 38 ArgType string 39 } 40 41 func (a *arg) String() string { 42 return strings.ToLower(a.Name) + " " + strings.ToLower(a.ArgType) 43 } 44 45 // Parses the given file for an interface definition with the given name 46 func Parse(filePath string, objName string) (*parsedPkg, error) { 47 fs := token.NewFileSet() 48 pkg, err := parser.ParseFile(fs, filePath, nil, parser.AllErrors) 49 if err != nil { 50 return nil, err 51 } 52 p := &parsedPkg{} 53 p.Name = pkg.Name.Name 54 obj, exists := pkg.Scope.Objects[objName] 55 if !exists { 56 return nil, fmt.Errorf("could not find object %s in %s", objName, filePath) 57 } 58 if obj.Kind != ast.Typ { 59 return nil, fmt.Errorf("exected type, got %s", obj.Kind) 60 } 61 spec, ok := obj.Decl.(*ast.TypeSpec) 62 if !ok { 63 return nil, ErrUnexpectedType{"*ast.TypeSpec", obj.Decl} 64 } 65 iface, ok := spec.Type.(*ast.InterfaceType) 66 if !ok { 67 return nil, ErrUnexpectedType{"*ast.InterfaceType", spec.Type} 68 } 69 70 p.Functions, err = parseInterface(iface) 71 if err != nil { 72 return nil, err 73 } 74 75 return p, nil 76 } 77 78 func parseInterface(iface *ast.InterfaceType) ([]function, error) { 79 var functions []function 80 for _, field := range iface.Methods.List { 81 switch f := field.Type.(type) { 82 case *ast.FuncType: 83 method, err := parseFunc(field) 84 if err != nil { 85 return nil, err 86 } 87 if method == nil { 88 continue 89 } 90 functions = append(functions, *method) 91 case *ast.Ident: 92 spec, ok := f.Obj.Decl.(*ast.TypeSpec) 93 if !ok { 94 return nil, ErrUnexpectedType{"*ast.TypeSpec", f.Obj.Decl} 95 } 96 iface, ok := spec.Type.(*ast.InterfaceType) 97 if !ok { 98 return nil, ErrUnexpectedType{"*ast.TypeSpec", spec.Type} 99 } 100 funcs, err := parseInterface(iface) 101 if err != nil { 102 fmt.Println(err) 103 continue 104 } 105 functions = append(functions, funcs...) 106 default: 107 return nil, ErrUnexpectedType{"*astFuncType or *ast.Ident", f} 108 } 109 } 110 return functions, nil 111 } 112 113 func parseFunc(field *ast.Field) (*function, error) { 114 f := field.Type.(*ast.FuncType) 115 method := &function{Name: field.Names[0].Name} 116 if _, exists := skipFuncs[method.Name]; exists { 117 fmt.Println("skipping:", method.Name) 118 return nil, nil 119 } 120 if f.Params != nil { 121 args, err := parseArgs(f.Params.List) 122 if err != nil { 123 return nil, err 124 } 125 method.Args = args 126 } 127 if f.Results != nil { 128 returns, err := parseArgs(f.Results.List) 129 if err != nil { 130 return nil, fmt.Errorf("error parsing function returns for %q: %v", method.Name, err) 131 } 132 method.Returns = returns 133 } 134 return method, nil 135 } 136 137 func parseArgs(fields []*ast.Field) ([]arg, error) { 138 var args []arg 139 for _, f := range fields { 140 if len(f.Names) == 0 { 141 return nil, ErrBadReturn 142 } 143 for _, name := range f.Names { 144 var typeName string 145 switch argType := f.Type.(type) { 146 case *ast.Ident: 147 typeName = argType.Name 148 case *ast.StarExpr: 149 i, ok := argType.X.(*ast.Ident) 150 if !ok { 151 return nil, ErrUnexpectedType{"*ast.Ident", f.Type} 152 } 153 typeName = "*" + i.Name 154 default: 155 return nil, ErrUnexpectedType{"*ast.Ident or *ast.StarExpr", f.Type} 156 } 157 158 args = append(args, arg{name.Name, typeName}) 159 } 160 } 161 return args, nil 162 }