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 }