github.com/gotranspile/cxgo@v0.3.7/c_type.go (about) 1 package cxgo 2 3 import ( 4 "fmt" 5 "unicode" 6 "unicode/utf8" 7 8 "modernc.org/cc/v3" 9 "modernc.org/token" 10 11 "github.com/gotranspile/cxgo/types" 12 ) 13 14 func (g *translator) convertTypeOper(p cc.Operand, where token.Position) types.Type { 15 defer func() { 16 switch r := recover().(type) { 17 case nil: 18 case error: 19 panic(ErrorWithPos(r, where)) 20 default: 21 panic(ErrorWithPos(fmt.Errorf("%v", r), where)) 22 } 23 }() 24 if d := p.Declarator(); d != nil { 25 where = d.Position() 26 } 27 var conf IdentConfig 28 if d := p.Declarator(); d != nil { 29 conf = g.idents[d.Name().String()] 30 } 31 return g.convertTypeRoot(conf, p.Type(), where) 32 } 33 34 // convertType is similar to newTypeCC but it will first consult the type cache. 35 func (g *translator) convertType(conf IdentConfig, t cc.Type, where token.Position) types.Type { 36 // custom type overrides coming from the config 37 // note that we don't save them since they might depend 38 // not only on the input type, but also on a field name 39 switch conf.Type { 40 case HintBool: 41 return g.env.Go().Bool() 42 case HintIface: 43 return g.env.Go().Any() 44 case HintString: 45 return g.env.Go().String() 46 case HintSlice: 47 ct := g.newTypeCC(IdentConfig{}, t, where) 48 var elem types.Type 49 switch ct := ct.(type) { 50 case types.PtrType: 51 elem = ct.Elem() 52 case types.ArrayType: 53 elem = ct.Elem() 54 default: 55 panic("expected an array or a pointer") 56 } 57 if elem == types.UintT(1) { 58 elem = g.env.Go().Byte() 59 } 60 return types.SliceT(elem) 61 } 62 // allow invalid types, they might still be useful 63 // since one may define them in a separate Go file 64 // and make the code valid 65 if t.Kind() == cc.Invalid { 66 return types.UnkT(g.env.PtrSize()) 67 } 68 if ct, ok := g.ctypes[t]; ok { 69 return ct 70 } 71 ct := g.newTypeCC(conf, t, where) 72 g.ctypes[t] = ct 73 return ct 74 } 75 76 // convertTypeRoot is the same as convertType, but it applies a workaround for 77 // C function pointers. 78 func (g *translator) convertTypeRoot(conf IdentConfig, t cc.Type, where token.Position) types.Type { 79 ft := g.convertType(conf, t, where) 80 if p, ok := ft.(types.PtrType); ok && p.ElemKind().IsFunc() { 81 ft = p.Elem() 82 } 83 return ft 84 } 85 86 // convertTypeOpt is similar to convertType, but it also allows void type by returning nil. 87 func (g *translator) convertTypeOpt(conf IdentConfig, t cc.Type, where token.Position) types.Type { 88 if t == nil || t.Kind() == cc.Void || t.Kind() == cc.Invalid { 89 return nil 90 } 91 return g.convertType(conf, t, where) 92 } 93 94 // convertTypeRootOpt is similar to convertTypeRoot, but it also allows void type by returning nil. 95 func (g *translator) convertTypeRootOpt(conf IdentConfig, t cc.Type, where token.Position) types.Type { 96 if t == nil || t.Kind() == cc.Void || t.Kind() == cc.Invalid { 97 return nil 98 } 99 return g.convertTypeRoot(conf, t, where) 100 } 101 102 // replaceType checks if the type needs to be replaced. It usually happens for builtin types. 103 func (g *translator) replaceType(name string) (types.Type, bool) { 104 if t, ok := g.env.TypeByName(name); ok { 105 return t, true 106 } 107 if t := g.env.C().Type(name); t != nil { 108 return t, true 109 } 110 return nil, false 111 } 112 113 // newNamedTypeAt finds or creates a named type defined by specified CC types and tokens. 114 func (g *translator) newNamedTypeAt(name string, typ, elem cc.Type, where token.Position) types.Type { 115 if typ == elem { 116 switch typ.Kind() { 117 case cc.Struct, cc.Union: 118 default: 119 panic(fmt.Errorf("name: %s, elem: (%T) %v", name, elem, elem)) 120 } 121 } 122 conf := g.idents[name] 123 if typ, ok := g.replaceType(name); ok { 124 return typ 125 } 126 if c, ok := g.idents[name]; ok && c.Alias { 127 sub := g.convertTypeRoot(conf, elem, where) 128 g.ctypes[typ] = sub 129 g.aliases[name] = sub 130 return sub 131 } 132 return g.newOrFindNamedType(name, func() types.Type { 133 return g.convertTypeRoot(conf, elem, where) 134 }) 135 } 136 137 func (g *translator) newOrFindNamedTypedef(name string, underlying func() types.Type) types.Named { 138 if c, ok := g.idents[name]; ok && c.Alias { 139 if _, ok := g.aliases[name]; ok { 140 return nil 141 } 142 // we should register the underlying type with the current name, 143 // so all the accesses will use underlying type 144 t := underlying() 145 g.aliases[name] = t 146 // and we suppress the definition of this type 147 return nil 148 } 149 return g.newOrFindNamedType(name, underlying) 150 } 151 152 // newOrFindNamedType finds or creates a new named type with a given underlying type. 153 // The function is given because types may be recursive. 154 func (g *translator) newOrFindNamedType(name string, underlying func() types.Type) types.Named { 155 if _, ok := g.aliases[name]; ok { 156 panic("alias") 157 } 158 if typ, ok := g.named[name]; ok { 159 return typ 160 } 161 und := underlying() 162 if typ, ok := g.named[name]; ok { 163 return typ 164 } 165 return g.newNamedType(name, und) 166 } 167 168 // newNamedType creates a new named type based on the underlying type. 169 func (g *translator) newNamedType(name string, underlying types.Type) types.Named { 170 if _, ok := g.named[name]; ok { 171 panic("type with a same name already exists: " + name) 172 } 173 goname := "" 174 if c, ok := g.idents[name]; ok && c.Rename != "" { 175 goname = c.Rename 176 } 177 nt := types.NamedTGo(name, goname, underlying) 178 g.named[name] = nt 179 return nt 180 } 181 182 // newNamedTypeFrom creates a new named type based on a given CC type. 183 // It is similar to newNamedType, but accepts a CC type that should be bound to a new type. 184 func (g *translator) newNamedTypeFrom(name string, underlying types.Type, from cc.Type) types.Named { 185 if _, ok := g.ctypes[from]; ok { 186 panic("same C type already exists") 187 } 188 nt := g.newNamedType(name, underlying) 189 g.ctypes[from] = nt 190 return nt 191 } 192 193 // newOrFindNamedTypeFrom finds or creates a type with a given name, underlying type and source C type. 194 // It cannot return the NamedType because the type may have an override. 195 func (g *translator) newOrFindNamedTypeFrom(name string, elem func() types.Type, from cc.Type) types.Type { 196 if t, ok := g.ctypes[from]; ok { 197 return t 198 } 199 nt := g.newOrFindNamedType(name, elem) 200 g.ctypes[from] = nt 201 return nt 202 } 203 204 // newOrFindIncompleteNamedTypeFrom finds or creates a incomplete type with a given name and source C type. 205 // It cannot return the NamedType because the type may have an override, or the type may have been resolved to something else. 206 func (g *translator) newOrFindIncompleteNamedTypeFrom(name string, from cc.Type) types.Type { 207 return g.newOrFindNamedTypeFrom(name, nil, from) 208 } 209 210 func asExportedName(s string) string { 211 if len(s) == 0 { 212 return "" 213 } 214 r, n := utf8.DecodeRuneInString(s) 215 return string(unicode.ToUpper(r)) + s[n:] 216 } 217 218 // newTypeCC creates a new type based on a specified C type. This function will not consult the cache for a given type. 219 // It will recursively convert all the underlying and sub-types using convertType. 220 func (g *translator) newTypeCC(conf IdentConfig, t cc.Type, where token.Position) types.Type { 221 sname := t.Name().String() 222 if nt, ok := g.replaceType(sname); ok { 223 g.ctypes[t] = nt 224 return nt 225 } 226 // it's handled separately because it's the only type that is allowed to be incomplete 227 if t != t.Alias() { 228 if t.IsIncomplete() { 229 if nt, ok := g.named[sname]; ok { 230 return nt 231 } 232 return g.newOrFindNamedType(sname, func() types.Type { 233 return types.StructT(nil) 234 }) 235 } 236 if t, ok := g.aliases[sname]; ok { 237 return t 238 } 239 conf := g.idents[sname] 240 u := t.Alias() 241 sub := g.convertType(conf, u, where) 242 if sub, ok := sub.(types.Named); ok { 243 if name := t.Name(); name == u.Name() { 244 g.named[name.String()] = sub 245 g.ctypes[t] = sub 246 return sub 247 } 248 } 249 return g.newNamedTypeAt(sname, t, u, where) 250 } 251 switch t.Kind() { 252 case cc.Struct, cc.Union: 253 return g.convertStructType(conf, t, where) 254 } 255 if u := t.Alias(); t != u { 256 panic(fmt.Errorf("unhandled alias type: %T", t)) 257 } 258 switch kind := t.Kind(); kind { 259 case cc.UInt64, cc.UInt32, cc.UInt16, cc.UInt8: 260 return types.UintT(int(t.Size())) 261 case cc.Int64, cc.Int32, cc.Int16, cc.Int8: 262 return types.IntT(int(t.Size())) 263 case cc.SChar: 264 return g.env.C().SignedChar() 265 case cc.UChar: 266 return g.env.C().UnsignedChar() 267 case cc.Short: 268 return g.env.C().Short() 269 case cc.UShort: 270 return g.env.C().UnsignedShort() 271 case cc.Int: 272 return g.env.C().Int() 273 case cc.UInt: 274 return g.env.C().UnsignedInt() 275 case cc.Long: 276 return g.env.C().Long() 277 case cc.ULong: 278 return g.env.C().UnsignedLong() 279 case cc.LongLong: 280 return g.env.C().LongLong() 281 case cc.ULongLong: 282 return g.env.C().UnsignedLongLong() 283 case cc.Float: 284 return g.env.C().Float() 285 case cc.Double: 286 return g.env.C().Double() 287 case cc.LongDouble: 288 return types.FloatT(int(t.Size())) 289 case cc.Char: 290 return g.env.C().Char() 291 case cc.Bool: 292 return g.env.C().Bool() 293 case cc.Function: 294 return g.convertFuncType(conf, nil, t, where) 295 case cc.Ptr: 296 if t.Elem().Kind() == cc.Char { 297 return g.env.C().String() 298 } 299 if e := t.Elem(); e.Kind() == cc.Struct && e.NumField() == 1 { 300 // Go slices defined via cxgo builtins 301 f := e.FieldByIndex([]int{0}) 302 if f.Name().String() == types.GoPrefix+"slice_data" { 303 elem := g.convertType(IdentConfig{}, f.Type(), where) 304 return types.SliceT(elem) 305 } 306 } 307 var ptr types.PtrType 308 if name := t.Elem().Name(); name != 0 { 309 if pt, ok := g.namedPtrs[name.String()]; ok { 310 return pt 311 } 312 ptr = g.env.PtrT(nil) // incomplete 313 g.namedPtrs[name.String()] = ptr 314 } 315 // use Opt because of the void* 316 elem := g.convertTypeOpt(IdentConfig{}, t.Elem(), where) 317 if ptr != nil { 318 ptr.SetElem(elem) 319 return ptr 320 } 321 return g.env.PtrT(elem) 322 case cc.Array: 323 if t.Elem().Kind() == cc.Char { 324 return types.ArrayT(g.env.Go().Byte(), int(t.Len())) 325 } 326 elem := g.convertType(IdentConfig{}, t.Elem(), where) 327 return types.ArrayT( 328 elem, 329 int(t.Len()), 330 ) 331 case cc.Union: 332 if name := t.Name(); name != 0 { 333 u := t.Alias() 334 if name == u.Name() { 335 u = u.Alias() 336 } 337 return g.newNamedTypeAt(name.String(), t, u, where) 338 } 339 fconf := make(map[string]IdentConfig) 340 for _, f := range conf.Fields { 341 fconf[f.Name] = f 342 } 343 var fields []*types.Field 344 for i := 0; i < t.NumField(); i++ { 345 f := t.FieldByIndex([]int{i}) 346 name := f.Name().String() 347 fc := fconf[name] 348 ft := g.convertTypeRoot(fc, f.Type(), where) 349 fields = append(fields, &types.Field{ 350 Name: g.newIdent(name, ft), 351 }) 352 } 353 return types.UnionT(fields) 354 case cc.Enum: 355 return g.newTypeCC(IdentConfig{}, t.EnumType(), where) 356 default: 357 panic(fmt.Errorf("%T, %s (%s)", t, kind, t.String())) 358 } 359 } 360 361 func (g *translator) convertStructType(conf IdentConfig, t cc.Type, where token.Position) types.Type { 362 sname := t.Name().String() 363 if c, ok := g.idents[sname]; ok { 364 conf = c 365 } 366 fconf := make(map[string]IdentConfig) 367 for _, f := range conf.Fields { 368 fconf[f.Name] = f 369 } 370 buildType := func() types.Type { 371 var fields []*types.Field 372 for i := 0; i < t.NumField(); i++ { 373 f := t.FieldByIndex([]int{i}) 374 fc := fconf[f.Name().String()] 375 ft := g.convertTypeRoot(fc, f.Type(), where) 376 if f.Name() == 0 { 377 st := types.Unwrap(ft).(*types.StructType) 378 fields = append(fields, st.Fields()...) 379 continue 380 } 381 fname := g.newIdent(f.Name().String(), ft) 382 if fc.Rename != "" { 383 fname.GoName = fc.Rename 384 } else if !g.conf.UnexportedFields { 385 fname.GoName = asExportedName(fname.Name) 386 } 387 fields = append(fields, &types.Field{ 388 Name: fname, 389 }) 390 } 391 if !where.IsValid() { 392 panic(where) 393 } 394 var s *types.StructType 395 if t.Kind() == cc.Union { 396 s = types.UnionT(fields) 397 } else { 398 s = types.StructT(fields) 399 } 400 s.Where = where.String() 401 if t.Name() == 0 { 402 return s 403 } 404 return s 405 } 406 if t.Name() == 0 { 407 return buildType() 408 } 409 return g.newOrFindNamedType(sname, buildType) 410 } 411 412 func (g *translator) convertFuncType(conf IdentConfig, d *cc.Declarator, t cc.Type, where token.Position) *types.FuncType { 413 if kind := t.Kind(); kind != cc.Function { 414 panic(kind) 415 } 416 if d != nil { 417 where = d.Position() 418 } 419 var rconf IdentConfig 420 aconf := make(map[string]IdentConfig) 421 iconf := make(map[int]IdentConfig) 422 for _, f := range conf.Fields { 423 if f.Name != "" { 424 if f.Name == "return" { 425 rconf = f 426 } else { 427 aconf[f.Name] = f 428 } 429 } else { 430 iconf[f.Index] = f 431 } 432 } 433 var ( 434 args []*types.Field 435 named int 436 ) 437 for i, p := range t.Parameters() { 438 pt := p.Type() 439 if pt.Kind() == cc.Void { 440 continue 441 } 442 var fc IdentConfig 443 if ac, ok := aconf[p.Name().String()]; ok { 444 fc = ac 445 } else if ac, ok = iconf[i]; ok { 446 fc = ac 447 } 448 at := g.convertTypeRoot(fc, pt, where) 449 var name *types.Ident 450 if d != nil && p.Name() != 0 { 451 name = g.convertIdent(d.ParamScope(), p.Declarator().NameTok(), at).Ident 452 named++ 453 } else if p.Name() != 0 { 454 name = g.convertIdentWith(p.Declarator().NameTok().String(), at, p.Declarator()).Ident 455 named++ 456 } else { 457 name = types.NewUnnamed(at) 458 } 459 args = append(args, &types.Field{ 460 Name: name, 461 }) 462 } 463 if named != 0 && len(args) != named { 464 for i, a := range args { 465 if a.Name.Name == "" && a.Name.GoName == "" { 466 a.Name.GoName = fmt.Sprintf("a%d", i+1) 467 } 468 } 469 } 470 ret := g.convertTypeRootOpt(rconf, t.Result(), where) 471 if t.IsVariadic() { 472 return g.env.VarFuncT(ret, args...) 473 } 474 return g.env.FuncT(ret, args...) 475 } 476 477 func propagateConst(t types.Type) bool { 478 switch t := t.(type) { 479 case types.PtrType: 480 if !propagateConst(t.Elem()) { 481 //t.Const = true // TODO 482 } 483 return true 484 case types.ArrayType: 485 return propagateConst(t.Elem()) 486 case types.IntType: 487 //t.Const = true 488 return true 489 } 490 return false 491 } 492 493 func (g *translator) ZeroValue(t types.Type) Expr { 494 if t == nil { 495 panic("nil type") 496 } 497 switch t.Kind().Major() { 498 case types.Ptr, types.Func: 499 return g.Nil() 500 case types.Int, types.Float: 501 return cUintLit(0) 502 case types.Struct, types.Array: 503 return &CCompLitExpr{Type: t} 504 default: 505 panic(t) 506 } 507 }