github.com/alkemics/goflow@v0.2.1/gfutil/gfgo/parsing.go (about)

     1  package gfgo
     2  
     3  import (
     4  	"go/types"
     5  	"strings"
     6  
     7  	"github.com/alkemics/goflow"
     8  )
     9  
    10  func ParseType(typ types.Type) (string, []goflow.Import, error) {
    11  	imports, err := extractImports(typ)
    12  	if err != nil {
    13  		return "", nil, err
    14  	}
    15  	// Replace the full packages names with their name.
    16  	t := typ.String()
    17  	for i, imp := range imports {
    18  		t = strings.Replace(t, imp.Dir, imp.Pkg, -1)
    19  		// TODO: check this when we migrate to modules.
    20  		if strings.Contains(imp.Dir, "/vendor/") {
    21  			imports[i].Dir = imp.Dir[strings.Index(imp.Dir, "/vendor/")+8:]
    22  		}
    23  	}
    24  	return t, imports, nil
    25  }
    26  
    27  func extractImports(typ types.Type) ([]goflow.Import, error) {
    28  	switch typ := typ.(type) {
    29  	case *types.Basic:
    30  		return nil, nil
    31  	case *types.Interface:
    32  		return nil, nil
    33  	case *types.Array:
    34  		return extractImports(typ.Elem())
    35  	case *types.Slice:
    36  		return extractImports(typ.Elem())
    37  	case *types.Pointer:
    38  		return extractImports(typ.Elem())
    39  	case *types.Named:
    40  		pkg := typ.Obj().Pkg()
    41  		if pkg == nil {
    42  			// Typically the case for built-ins like 'error'
    43  			return nil, nil
    44  		}
    45  
    46  		return []goflow.Import{
    47  			{
    48  				Pkg: pkg.Name(),
    49  				Dir: pkg.Path(),
    50  			},
    51  		}, nil
    52  	case *types.Struct:
    53  		imports, _, err := toFields(structFields(typ))
    54  		if err != nil {
    55  			return nil, err
    56  		}
    57  
    58  		return imports, nil
    59  	case *types.Signature:
    60  		imports, _, _, err := ParseSignature(typ)
    61  		if err != nil {
    62  			return nil, err
    63  		}
    64  
    65  		return imports, nil
    66  	case *types.Map:
    67  		keyImports, err := extractImports(typ.Key())
    68  		if err != nil {
    69  			return nil, err
    70  		}
    71  
    72  		elemImports, err := extractImports(typ.Elem())
    73  		if err != nil {
    74  			return nil, err
    75  		}
    76  
    77  		imports := append(keyImports, elemImports...)
    78  		return imports, nil
    79  	}
    80  	return nil, TypeError{Type: typ}
    81  }
    82  
    83  func ParseSignature(signature *types.Signature) (imports []goflow.Import, inputs, outputs []goflow.Field, err error) {
    84  	var imps []goflow.Import
    85  
    86  	// Parse inputs.
    87  	if signature.Params() != nil {
    88  		imps, inputs, err = toFields(signature.Params())
    89  		if err != nil {
    90  			return nil, nil, nil, err
    91  		}
    92  
    93  		imports = append(imports, imps...)
    94  	}
    95  
    96  	// Parse outputs.
    97  	if signature.Results() != nil {
    98  		imps, outputs, err = toFields(signature.Results())
    99  		if err != nil {
   100  			return nil, nil, nil, err
   101  		}
   102  
   103  		imports = append(imports, imps...)
   104  	}
   105  
   106  	return imports, inputs, outputs, nil
   107  }
   108  
   109  func toFields(vars *types.Tuple) ([]goflow.Import, []goflow.Field, error) {
   110  	fields := make([]goflow.Field, vars.Len())
   111  	mergedImports := make([]goflow.Import, 0)
   112  	for i := 0; i < vars.Len(); i++ {
   113  		v := vars.At(i)
   114  		typ, imports, err := ParseType(v.Type())
   115  		if err != nil {
   116  			return nil, nil, InputParsingError{
   117  				InputIndex: i,
   118  				Err:        err,
   119  			}
   120  		}
   121  
   122  		fields[i] = goflow.Field{
   123  			Name: v.Name(),
   124  			Type: typ,
   125  		}
   126  
   127  		mergedImports = append(mergedImports, imports...)
   128  	}
   129  	return mergedImports, fields, nil
   130  }
   131  
   132  func structFields(s *types.Struct) *types.Tuple {
   133  	vars := make([]*types.Var, s.NumFields())
   134  	for i := 0; i < s.NumFields(); i++ {
   135  		vars[i] = s.Field(i)
   136  	}
   137  	return types.NewTuple(vars...)
   138  }