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