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  }