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 }