github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/x/typesx/util.go (about) 1 package typesx 2 3 import ( 4 "bytes" 5 "fmt" 6 "go/types" 7 "reflect" 8 "strconv" 9 "strings" 10 11 "golang.org/x/tools/go/packages" 12 13 "github.com/machinefi/w3bstream/pkg/depends/x/mapx" 14 ) 15 16 var ( 17 typs = mapx.New[string, types.Type]() 18 pkgs = mapx.New[string, *types.Package]() 19 basics = map[string]types.Type{} 20 21 LoadFiles = packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles 22 LoadImports = LoadFiles | packages.NeedImports 23 LoadTypes = LoadImports | packages.NeedTypes | packages.NeedTypesSizes 24 ) 25 26 // init basic types 27 func init() { 28 for _, b := range types.Typ { 29 basics[types.TypeString(b, nil)] = b 30 } 31 basics["interface {}"] = types.NewInterfaceType(nil, nil) 32 basics["error"] = NewPackage("errors").Scope().Lookup("New").Type(). 33 Underlying().(*types.Signature).Results().At(0).Type() 34 } 35 36 func NewGoTypeFromReflectType(t reflect.Type) types.Type { 37 underlying := func() types.Type { 38 k := t.Kind() 39 if IsBasicReflectKind(k) { 40 return types.Typ[ReflectKindToTypesKind[k]] 41 } 42 switch k { 43 case reflect.Array: 44 return types.NewArray( 45 NewGoTypeFromReflectType(t.Elem()), 46 int64(t.Len()), 47 ) 48 case reflect.Slice: 49 return types.NewSlice(NewGoTypeFromReflectType(t.Elem())) 50 case reflect.Map: 51 return types.NewMap( 52 NewGoTypeFromReflectType(t.Key()), 53 NewGoTypeFromReflectType(t.Elem()), 54 ) 55 case reflect.Chan: 56 return types.NewChan( 57 types.ChanDir(t.ChanDir()), 58 NewGoTypeFromReflectType(t.Elem()), 59 ) 60 case reflect.Func: 61 params := make([]*types.Var, t.NumIn()) 62 for i := range params { 63 v := t.In(i) 64 params[i] = types.NewParam(0, NewPackage(v.PkgPath()), "", NewGoTypeFromReflectType(v)) 65 } 66 results := make([]*types.Var, t.NumOut()) 67 for i := range results { 68 v := t.Out(i) 69 results[i] = types.NewParam(0, NewPackage(v.PkgPath()), "", NewGoTypeFromReflectType(v)) 70 } 71 return types.NewSignatureType( 72 nil, 73 nil, 74 nil, 75 types.NewTuple(params...), 76 types.NewTuple(results...), 77 t.IsVariadic(), 78 ) 79 case reflect.Interface: 80 fns := make([]*types.Func, t.NumMethod()) 81 for i := range fns { 82 f := t.Method(i) 83 fns[i] = types.NewFunc( 84 0, 85 NewPackage(f.PkgPath), 86 f.Name, 87 NewGoTypeFromReflectType(f.Type).(*types.Signature), 88 ) 89 } 90 return types.NewInterfaceType(fns, nil).Complete() 91 case reflect.Struct: 92 fields := make([]*types.Var, t.NumField()) 93 tags := make([]string, len(fields)) 94 for i := range fields { 95 f := t.Field(i) 96 fields[i] = types.NewField( 97 0, 98 NewPackage(f.PkgPath), 99 f.Name, 100 NewGoTypeFromReflectType(f.Type), 101 f.Anonymous, 102 ) 103 tags[i] = string(f.Tag) 104 } 105 return types.NewStruct(fields, tags) 106 } 107 return nil 108 } 109 110 stars := 0 111 112 indirect := func(t types.Type) types.Type { 113 for stars > 0 { 114 t = types.NewPointer(t) 115 stars-- 116 } 117 return t 118 } 119 120 for t.Kind() == reflect.Ptr { 121 t = t.Elem() 122 stars++ 123 } 124 name := t.Name() 125 path := t.PkgPath() 126 if name == "error" && path == "" { 127 return nil 128 } 129 130 if path != "" { 131 return indirect(TypeFor(path + "." + name)) 132 } 133 return indirect(underlying()) 134 } 135 136 func NewPackage(path string) *types.Package { 137 if path == "" { 138 return nil 139 } 140 if v, ok := pkgs.Load(path); ok { 141 return v 142 } 143 cfg := packages.Config{ 144 Overlay: make(map[string][]byte), 145 Tests: true, 146 Mode: LoadTypes, 147 } 148 pkg, err := packages.Load(&cfg, path) 149 if err != nil { 150 panic(err) 151 } 152 pkgs.Store(path, pkg[0].Types) 153 return pkg[0].Types 154 } 155 156 func TypeByName(path string, name string) types.Type { 157 if path == "" { 158 TypeFor(name) 159 } 160 return TypeFor(path + "." + name) 161 } 162 163 func PtrTo(t Type) Type { 164 switch x := t.(type) { 165 case *GoType: 166 return FromGoType(types.NewPointer(x.Type)) 167 case *ReflectType: 168 return FromReflectType(reflect.PtrTo(x.Type)) 169 } 170 return nil 171 } 172 173 func TypeString(t Type) string { 174 if pkg := t.PkgPath(); pkg != "" { 175 return pkg + "." + t.Name() 176 } 177 k := t.Kind() 178 if IsBasicReflectKind(k) { 179 return k.String() 180 } 181 182 switch k { 183 case reflect.Slice: 184 return "[]" + t.Elem().String() 185 case reflect.Array: 186 return fmt.Sprintf("[%d]%s", t.Len(), t.Elem().String()) 187 case reflect.Chan: 188 return "chan " + t.Elem().String() 189 case reflect.Map: 190 return fmt.Sprintf("map[%s]%s", t.Key().String(), t.Elem().String()) 191 case reflect.Struct: 192 b := bytes.NewBuffer(nil) 193 b.WriteString("struct {") 194 n := t.NumField() 195 for i := 0; i < n; i++ { 196 b.WriteRune(' ') 197 f := t.Field(i) 198 if !f.Anonymous() { 199 b.WriteString(f.Name()) 200 b.WriteRune(' ') 201 } 202 b.WriteString(f.Type().String()) 203 tag := f.Tag() 204 if tag != "" { 205 b.WriteRune(' ') 206 b.WriteString(strconv.Quote(string(tag))) 207 } 208 if i == n-1 { 209 b.WriteRune(' ') 210 } else { 211 b.WriteString(";") 212 } 213 } 214 b.WriteString("}") 215 return b.String() 216 case reflect.Interface: 217 if name := t.Name(); name == "error" { 218 return name 219 } 220 b := bytes.NewBuffer(nil) 221 b.WriteString("interface {") 222 n := t.NumMethod() 223 for i := 0; i < n; i++ { 224 b.WriteRune(' ') 225 m := t.Method(i) 226 pkg := m.PkgPath() 227 if pkg != "" { 228 b.WriteString(NewPackage(pkg).Name()) 229 b.WriteRune('.') 230 } 231 b.WriteString(m.Name()) 232 b.WriteString(m.Type().String()[4:]) 233 234 if i == n-1 { 235 b.WriteRune(' ') 236 } else { 237 b.WriteRune(';') 238 } 239 } 240 b.WriteString("}") 241 return b.String() 242 case reflect.Func: 243 b := bytes.NewBuffer(nil) 244 b.WriteString("func(") 245 { 246 n := t.NumIn() 247 for i := 0; i < n; i++ { 248 p := t.In(i) 249 if i == n-1 && t.IsVariadic() { 250 b.WriteString("...") 251 b.WriteString(p.Elem().String()) 252 } else { 253 b.WriteString(p.String()) 254 } 255 if i < n-1 { 256 b.WriteString(", ") 257 } 258 } 259 b.WriteString(")") 260 } 261 { 262 n := t.NumOut() 263 if n > 0 { 264 b.WriteRune(' ') 265 } 266 if n > 1 { 267 b.WriteString("(") 268 } 269 for i := 0; i < n; i++ { 270 if i > 0 { 271 b.WriteString(", ") 272 } 273 r := t.Out(i) 274 b.WriteString(r.String()) 275 } 276 if n > 1 { 277 b.WriteString(")") 278 } 279 } 280 return b.String() 281 } 282 return t.Name() 283 } 284 285 func TypeFor(id string) (t types.Type) { 286 if v, ok := typs.Load(id); ok { 287 return v.(types.Type) 288 } 289 290 defer func() { 291 if t == nil { 292 t = types.Typ[types.Invalid] 293 } 294 typs.Store(id, t) 295 }() 296 297 if id == "" { 298 return 299 } 300 301 if basic, ok := basics[id]; ok { 302 t = basic 303 return 304 } 305 306 // map[x] 307 l := strings.Index(id, "map[") 308 if l == 0 { 309 r := strings.Index(id, "]") 310 t = types.NewMap(TypeFor(id[4:r]), TypeFor(id[r+1:])) 311 return 312 } 313 314 // []x [n]x 315 l = strings.Index(id, "[") 316 if l == 0 { 317 r := strings.Index(id, "]") 318 if l == r-1 { 319 t = types.NewSlice(TypeFor(id[r+1:])) 320 return 321 } 322 n, err := strconv.ParseInt(id[1:r], 10, 64) 323 if err != nil { 324 // panic(err) 325 return // invalid 326 } 327 t = types.NewArray(TypeFor(id[r+1:]), n) 328 return 329 } else if l == -1 { 330 i := strings.LastIndex(id, ".") 331 if i <= 0 { 332 return // invalid 333 } 334 path := id[0:i] 335 name := id[i+1:] 336 pkg := NewPackage(path) 337 if pkg == nil { 338 return 339 } 340 if found := pkg.Scope().Lookup(name); found != nil { 341 t = found.Type() 342 return 343 } 344 return 345 } else { 346 r := strings.Index(id, "]") 347 full := id[0:l] 348 paramNames := strings.Split(id[l+1:r], ",") // github.com/x/y/z.AnyStruct[int,string] 349 if dot := strings.LastIndex(full, "."); dot > 0 { 350 path, name := full[0:dot], full[dot+1:] 351 if p := NewPackage(path); p != nil { 352 if found := p.Scope().Lookup(name); found != nil { 353 named := &(*found.(*types.TypeName).Type().(*types.Named)) 354 paramTypes := named.TypeParams() 355 if n := paramTypes.Len(); n > 0 { 356 params := make([]*types.TypeParam, n) 357 for i := 0; i < n; i++ { 358 params[i] = types.NewTypeParam( 359 paramTypes.At(i).Obj(), 360 TypeFor(paramNames[i]), 361 ) 362 } 363 named.SetTypeParams(params) 364 } 365 return found.Type() 366 } 367 } 368 } 369 } 370 return types.Typ[types.Invalid] 371 } 372 373 var ReflectKindToTypesKind = map[reflect.Kind]types.BasicKind{ 374 reflect.Bool: types.Bool, 375 reflect.Int: types.Int, 376 reflect.Int8: types.Int8, 377 reflect.Int16: types.Int16, 378 reflect.Int32: types.Int32, 379 reflect.Int64: types.Int64, 380 reflect.Uint: types.Uint, 381 reflect.Uint8: types.Uint8, 382 reflect.Uint16: types.Uint16, 383 reflect.Uint32: types.Uint32, 384 reflect.Uint64: types.Uint64, 385 reflect.Uintptr: types.Uintptr, 386 reflect.Float32: types.Float32, 387 reflect.Float64: types.Float64, 388 reflect.Complex64: types.Complex64, 389 reflect.Complex128: types.Complex128, 390 reflect.String: types.String, 391 reflect.UnsafePointer: types.UnsafePointer, 392 } 393 394 var TypesKindToReflectKind = map[types.BasicKind]reflect.Kind{ 395 types.Bool: reflect.Bool, 396 types.Int: reflect.Int, 397 types.Int8: reflect.Int8, 398 types.Int16: reflect.Int16, 399 types.Int32: reflect.Int32, 400 types.Int64: reflect.Int64, 401 types.Uint: reflect.Uint, 402 types.Uint8: reflect.Uint8, 403 types.Uint16: reflect.Uint16, 404 types.Uint32: reflect.Uint32, 405 types.Uint64: reflect.Uint64, 406 types.Uintptr: reflect.Uintptr, 407 types.Float32: reflect.Float32, 408 types.Float64: reflect.Float64, 409 types.Complex64: reflect.Complex64, 410 types.Complex128: reflect.Complex128, 411 types.String: reflect.String, 412 types.UnsafePointer: reflect.UnsafePointer, 413 types.UntypedBool: reflect.Bool, 414 types.UntypedInt: reflect.Int, 415 types.UntypedRune: reflect.Int32, 416 types.UntypedFloat: reflect.Float32, 417 types.UntypedComplex: reflect.Complex64, 418 types.UntypedString: reflect.String, 419 } 420 421 func IsBasicReflectKind(k reflect.Kind) bool { 422 switch k { 423 case reflect.Bool, 424 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 425 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 426 reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, 427 reflect.String, reflect.UnsafePointer: 428 return true 429 } 430 return false 431 } 432 433 func IsNumericReflectKind(k reflect.Kind) bool { 434 return IsIntegerReflectKind(k) || IsFloatReflectKind(k) 435 } 436 437 func IsIntegerReflectKind(k reflect.Kind) bool { 438 return IsSignedIntReflectKind(k) || IsUnsignedIntReflectKind(k) 439 } 440 441 func IsSignedIntReflectKind(k reflect.Kind) bool { 442 switch k { 443 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 444 return true 445 } 446 return false 447 } 448 449 func IsUnsignedIntReflectKind(k reflect.Kind) bool { 450 switch k { 451 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 452 return true 453 } 454 return false 455 } 456 457 func IsFloatReflectKind(k reflect.Kind) bool { 458 switch k { 459 case reflect.Float32, reflect.Float64: 460 return true 461 } 462 return false 463 }