github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/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  }