github.com/gotranspile/cxgo@v0.3.7/libs/types.go (about)

     1  package libs
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  	"unsafe"
     8  
     9  	"github.com/gotranspile/cxgo/types"
    10  )
    11  
    12  func (c *Env) NewIdent(cname, goname string, v interface{}, typ types.Type) *types.Ident {
    13  	err := c.checkType(reflect.TypeOf(v), typ)
    14  	if err != nil {
    15  		panic(fmt.Errorf("unexpected type for %s: %w", goname, err))
    16  	}
    17  	return types.NewIdentGo(cname, goname, typ)
    18  }
    19  
    20  func (c *Env) checkErr(ok bool, exp reflect.Type, got types.Type) error {
    21  	if ok {
    22  		return nil
    23  	}
    24  	return fmt.Errorf("expected %v (%v), got: %T, %v (%+v)", exp, exp.Kind(), got, got.Kind(), got)
    25  }
    26  
    27  var (
    28  	rtUnsafe = reflect.TypeOf(unsafe.Pointer(nil))
    29  )
    30  
    31  func (c *Env) checkType(t1 reflect.Type, t2 types.Type) error {
    32  	if t1 != rtUnsafe && strings.Contains(t1.PkgPath(), ".") {
    33  		name1 := t1.Name()
    34  		nt2, ok := t2.(types.Named)
    35  		if !ok {
    36  			return fmt.Errorf("expected named type, got: %T", t2)
    37  		}
    38  		id := nt2.Name()
    39  		name2 := id.GoName
    40  		if name2 == "" {
    41  			name2 = id.Name
    42  		}
    43  		if name2 == "" {
    44  			return fmt.Errorf("expected type with a name, got: %+v", id)
    45  		}
    46  		if i := strings.LastIndex(name2, "."); i > 0 {
    47  			name2 = name2[i+1:]
    48  		}
    49  		if name1 != name2 {
    50  			return fmt.Errorf("expected type named %q, got: %q", name1, name2)
    51  		}
    52  		return nil
    53  	}
    54  	switch t1.Kind() {
    55  	case reflect.Bool:
    56  		return c.checkErr(t2 == types.BoolT(), t1, t2)
    57  	case reflect.Int:
    58  		return c.checkErr(t2 == c.Go().Int() || (t2.Kind().IsInt() && t2.Kind().IsUntyped()), t1, t2)
    59  	case reflect.Uint:
    60  		return c.checkErr(t2 == c.Go().Uint(), t1, t2)
    61  	case reflect.UnsafePointer:
    62  		return c.checkErr(t2 == c.Go().UnsafePtr() || types.Same(t2, c.PtrT(nil)), t1, t2)
    63  	case reflect.Uintptr:
    64  		return c.checkErr(t2 == c.Go().Uintptr(), t1, t2)
    65  	case reflect.String:
    66  		return c.checkErr(t2 == c.Go().String(), t1, t2)
    67  	case reflect.Float32:
    68  		return c.checkErr(t2 == types.FloatT(4), t1, t2)
    69  	case reflect.Float64:
    70  		return c.checkErr(t2 == types.FloatT(8), t1, t2)
    71  	case reflect.Int8:
    72  		return c.checkErr(t2 == types.IntT(1), t1, t2)
    73  	case reflect.Uint8:
    74  		return c.checkErr(t2 == types.UintT(1) || types.Same(t2, c.Go().Byte()), t1, t2)
    75  	case reflect.Int16:
    76  		return c.checkErr(t2 == types.IntT(2), t1, t2)
    77  	case reflect.Uint16:
    78  		if nt, ok := t2.(types.Named); ok && nt.Name().GoName == "libc.WChar" {
    79  			return nil
    80  		}
    81  		return c.checkErr(t2 == types.UintT(2), t1, t2)
    82  	case reflect.Int32:
    83  		return c.checkErr(t2 == types.IntT(4) || types.Same(t2, c.Go().Rune()), t1, t2)
    84  	case reflect.Uint32:
    85  		return c.checkErr(t2 == types.UintT(4), t1, t2)
    86  	case reflect.Int64:
    87  		return c.checkErr(t2 == types.IntT(8), t1, t2)
    88  	case reflect.Uint64:
    89  		return c.checkErr(t2 == types.UintT(8), t1, t2)
    90  	case reflect.Ptr:
    91  		p, ok := t2.(types.PtrType)
    92  		if !ok {
    93  			return fmt.Errorf("expected pointer, got: %T", t2)
    94  		}
    95  		return c.checkType(t1.Elem(), p.Elem())
    96  	case reflect.Func:
    97  		f, ok := t2.(*types.FuncType)
    98  		if !ok {
    99  			return fmt.Errorf("expected func, got: %T", t2)
   100  		}
   101  		if t1.NumOut() == 0 {
   102  			if f.Return() != nil {
   103  				return fmt.Errorf("expected void func, got: %T", f.Return())
   104  			}
   105  		} else if t1.NumOut() == 1 {
   106  			err := c.checkType(t1.Out(0), f.Return())
   107  			if err != nil {
   108  				return fmt.Errorf("unexpected return: %w", err)
   109  			}
   110  		} else {
   111  			return fmt.Errorf("func with multiple returns: %v", t1)
   112  		}
   113  		if t1.IsVariadic() != f.Variadic() {
   114  			return fmt.Errorf("variadic flags are different")
   115  		}
   116  		exp := t1.NumIn()
   117  		if t1.IsVariadic() {
   118  			exp--
   119  		}
   120  		if exp != f.ArgN() {
   121  			return fmt.Errorf("unexpected number of arguments: %d vs %d", exp, f.ArgN())
   122  		}
   123  		args := f.Args()
   124  		for i := 0; i < exp; i++ {
   125  			err := c.checkType(t1.In(i), args[i].Type())
   126  			if err != nil {
   127  				return fmt.Errorf("arg %d: %w", i, err)
   128  			}
   129  		}
   130  		return nil
   131  	case reflect.Struct:
   132  		_, ok := types.Unwrap(t2).(*types.StructType)
   133  		if !ok {
   134  			return fmt.Errorf("expected struct, got: %T", t2)
   135  		}
   136  		return nil
   137  	default:
   138  		return fmt.Errorf("unsupported type: %v (%v)", t1, t1.Kind())
   139  	}
   140  }