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  }