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