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  }