github.com/gotranspile/cxgo@v0.3.7/types/env.go (about) 1 package types 2 3 import ( 4 "os" 5 "sort" 6 "unsafe" 7 ) 8 9 // Default returns a default config. 10 func Default() Config { 11 var c Config 12 c.setDefaults() 13 return c 14 } 15 16 // Config32 returns a default types config for 32 bit systems. 17 func Config32() Config { 18 c := Config{PtrSize: 4, IntSize: 4} 19 c.setDefaults() 20 return c 21 } 22 23 // Config64 returns a default types config for 64 bit systems. 24 func Config64() Config { 25 c := Config{PtrSize: 8, IntSize: 8} 26 c.setDefaults() 27 return c 28 } 29 30 // Config stores configuration for base types. 31 type Config struct { 32 PtrSize int // size of pointers in bytes 33 IntSize int // default int size in bytes 34 WCharSize int // wchar_t size 35 WCharSigned bool // is wchar_t signed? 36 UseGoInt bool // use Go int for C int and long 37 } 38 39 func (c *Config) setDefaults() { 40 if c.WCharSize == 0 { 41 c.WCharSize = 2 42 } 43 if c.PtrSize == 0 { 44 switch os.Getenv("GOARCH") { 45 case "386": 46 c.PtrSize = 4 47 case "amd64": 48 c.PtrSize = 8 49 default: 50 c.PtrSize = int(unsafe.Sizeof((*int)(nil))) 51 } 52 } 53 if c.IntSize == 0 { 54 switch os.Getenv("GOARCH") { 55 case "386": 56 c.IntSize = 4 57 case "amd64": 58 c.IntSize = 8 59 default: 60 c.IntSize = int(unsafe.Sizeof(int(0))) 61 } 62 } 63 } 64 65 func NewEnv(c Config) *Env { 66 e := &Env{ 67 conf: c, 68 pkgs: make(map[string]*Package), 69 } 70 e.conf.setDefaults() 71 // Go must be first, because C definitions may depend on it 72 e.initGo() 73 e.initC() 74 75 // conversion functions 76 e.stringGo2C = NewIdent("libc.CString", e.FuncTT( 77 e.C().String(), 78 e.Go().String(), 79 )) 80 e.wstringGo2C = NewIdent("libc.CWString", e.FuncTT( 81 e.C().WString(), 82 e.Go().String(), 83 )) 84 e.stringC2Go = NewIdent("libc.GoString", e.FuncTT( 85 e.Go().String(), 86 e.C().String(), 87 )) 88 e.wstringC2Go = NewIdent("libc.GoWString", e.FuncTT( 89 e.Go().String(), 90 e.C().WString(), 91 )) 92 return e 93 } 94 95 type Env struct { 96 conf Config 97 98 c C 99 g *Go 100 pkgs map[string]*Package 101 stringGo2C *Ident 102 wstringGo2C *Ident 103 stringC2Go *Ident 104 wstringC2Go *Ident 105 } 106 107 // PtrSize returns size of the pointer. 108 func (e *Env) PtrSize() int { 109 return e.conf.PtrSize 110 } 111 112 // IntSize returns default size of the integer. 113 func (e *Env) IntSize() int { 114 return e.conf.IntSize 115 } 116 117 // PtrT returns a pointer type with a specified element. 118 func (e *Env) PtrT(t Type) PtrType { 119 return PtrT(e.conf.PtrSize, t) 120 } 121 122 // IntPtrT returns a signed int type that can hold a pointer diff. 123 func (e *Env) IntPtrT() IntType { 124 return IntT(e.conf.PtrSize) 125 } 126 127 // UintPtrT returns a unsigned int type that can hold a pointer. 128 // It is different from Go().Uintptr(), since it returns uint32/uint64 type directly. 129 func (e *Env) UintPtrT() IntType { 130 return UintT(e.conf.PtrSize) 131 } 132 133 // DefIntT returns a default signed int type. 134 // It is different from Go().Int(), since it returns int32/int64 type directly. 135 func (e *Env) DefIntT() Type { 136 if e.conf.UseGoInt { 137 return e.g.Int() 138 } 139 return IntT(e.conf.IntSize) 140 } 141 142 // DefUintT returns a default unsigned int type. 143 // It is different from Go().Uint(), since it returns uint32/uint64 type directly. 144 func (e *Env) DefUintT() Type { 145 if e.conf.UseGoInt { 146 return e.g.Uint() 147 } 148 return UintT(e.conf.IntSize) 149 } 150 151 // FuncT returns a function type with a given return type and named arguments. 152 // It's mostly useful for function declarations. See FuncTT for simplified version. 153 func (e *Env) FuncT(ret Type, args ...*Field) *FuncType { 154 return FuncT(e.conf.PtrSize, ret, args...) 155 } 156 157 // FuncTT returns a function type with a given return type and arguments. 158 // To name arguments, use FuncT. 159 func (e *Env) FuncTT(ret Type, args ...Type) *FuncType { 160 return FuncTT(e.conf.PtrSize, ret, args...) 161 } 162 163 // VarFuncT returns a variadic function type with a given return type and named arguments. 164 // It's mostly useful for function declarations. See VarFuncTT for simplified version. 165 func (e *Env) VarFuncT(ret Type, args ...*Field) *FuncType { 166 return VarFuncT(e.conf.PtrSize, ret, args...) 167 } 168 169 // VarFuncTT returns a variadic function type with a given return type and arguments. 170 // To name arguments, use VarFuncT. 171 func (e *Env) VarFuncTT(ret Type, args ...Type) *FuncType { 172 return VarFuncTT(e.conf.PtrSize, ret, args...) 173 } 174 175 func (e *Env) MethStructT(meth map[string]*FuncType) *StructType { 176 fields := make([]*Field, 0, len(meth)) 177 for name, ft := range meth { 178 id := NewIdent(name, ft) 179 fields = append(fields, &Field{ 180 Name: id, 181 }) 182 } 183 return StructT(fields) 184 } 185 186 // StringGo2C is a builtin function that converts Go string to C string. 187 func (e *Env) StringGo2C() *Ident { 188 return e.stringGo2C 189 } 190 191 // WStringGo2C is a builtin function that converts Go string to C wchar_t string. 192 func (e *Env) WStringGo2C() *Ident { 193 return e.wstringGo2C 194 } 195 196 // StringC2Go is a builtin function that converts C string to Go string. 197 func (e *Env) StringC2Go() *Ident { 198 return e.stringC2Go 199 } 200 201 // WStringC2Go is a builtin function that converts C wchar_t string to Go string. 202 func (e *Env) WStringC2Go() *Ident { 203 return e.wstringC2Go 204 } 205 206 func newPackage(name, path string) *Package { 207 return &Package{name: name, path: path} 208 } 209 210 func (e *Env) NewPackage(name, path string) *Package { 211 if path == "" { 212 path = name 213 } 214 p := newPackage(name, path) 215 e.pkgs[path] = p 216 return p 217 } 218 219 func (e *Env) PackageByPath(path string) *Package { 220 return e.pkgs[path] 221 } 222 223 func (e *Env) Packages() []*Package { 224 out := make([]*Package, 0, len(e.pkgs)) 225 for _, p := range e.pkgs { 226 out = append(out, p) 227 } 228 sort.Slice(out, func(i, j int) bool { 229 return out[i].path < out[j].path 230 }) 231 return out 232 } 233 234 type Package struct { 235 name string 236 path string 237 238 idents map[*Ident]struct{} 239 cnames map[string]Type 240 gonames map[string]Type 241 } 242 243 func (p *Package) checkNames(cname, goname string) string { 244 if cname != "" { 245 if _, ok := p.cnames[cname]; ok { 246 panic("type already exists: " + cname) 247 } 248 } 249 if goname == "" { 250 goname = goName(cname) 251 } 252 if goname != "" { 253 if _, ok := p.gonames[goname]; ok { 254 panic("type already exists: " + goname) 255 } 256 } 257 return goname 258 } 259 260 func (p *Package) setNames(cname, goname string, t Type) { 261 if cname != "" { 262 if p.cnames == nil { 263 p.cnames = make(map[string]Type) 264 } 265 p.cnames[cname] = t 266 } 267 if goname != "" { 268 if p.gonames == nil { 269 p.gonames = make(map[string]Type) 270 } 271 p.gonames[goname] = t 272 } 273 } 274 275 func (p *Package) NewAlias(cname, goname string, t Type) Type { 276 _ = p.checkNames(cname, goname) 277 p.setNames(cname, goname, t) 278 return t 279 } 280 281 func (p *Package) NewTypeC(cname string, t Type) Named { 282 return p.NewTypeGo(cname, "", t) 283 } 284 285 func (p *Package) NewTypeGo(cname, goname string, t Type) Named { 286 goname = p.checkNames(cname, goname) 287 288 nt := NamedTGo(cname, goname, t) 289 if p.idents == nil { 290 p.idents = make(map[*Ident]struct{}) 291 } 292 p.idents[nt.Name()] = struct{}{} 293 if cname != "" { 294 if p.cnames == nil { 295 p.cnames = make(map[string]Type) 296 } 297 p.cnames[cname] = nt 298 } 299 if goname != "" { 300 if p.gonames == nil { 301 p.gonames = make(map[string]Type) 302 } 303 p.gonames[goname] = nt 304 } 305 return nt 306 } 307 308 func (p *Package) CType(name string) Type { 309 return p.cnames[name] 310 } 311 312 func (p *Package) GoType(name string) Type { 313 return p.gonames[name] 314 } 315 316 func (p *Package) CNamedType(name string) Named { 317 t := p.cnames[name] 318 if t == nil { 319 return nil 320 } 321 nt, _ := t.(Named) 322 return nt 323 } 324 325 func (p *Package) GoNamedType(name string) Named { 326 t := p.gonames[name] 327 if t == nil { 328 return nil 329 } 330 nt, _ := t.(Named) 331 return nt 332 }