github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/haxe/tgotypes.go (about) 1 package haxe 2 3 import ( 4 "fmt" 5 "reflect" 6 "unicode" 7 "unicode/utf8" 8 9 "go/types" 10 //"golang.org/x/tools/go/ssa" 11 ) 12 13 const ( // from reflect package 14 kindDirectIface = 1 << 5 15 kindGCProg = 1 << 6 // Type.gc points to GC program 16 kindNoPointers = 1 << 7 17 kindMask = (1 << 5) - 1 18 ) 19 20 func escapedTypeString(s string) string { 21 buf := []byte(s) 22 r := "" 23 for _, ch := range buf { 24 r += fmt.Sprintf("\\x%x", ch) 25 } 26 return r 27 } 28 29 func synthTypesFor(t types.Type) {} 30 31 func getTypeInfo(t types.Type, tname string) (kind reflect.Kind, name string) { 32 if t == nil { 33 return reflect.Invalid, "" 34 } 35 if tname != "" { 36 name = tname 37 } 38 switch t.(type) { 39 case *types.Basic: 40 tb := t.(*types.Basic) 41 switch tb.Kind() { 42 case types.Bool: 43 kind = reflect.Bool 44 case types.Int: 45 kind = reflect.Int 46 case types.Int8: 47 kind = reflect.Int8 48 case types.Int16: 49 kind = reflect.Int16 50 case types.Int32: 51 kind = reflect.Int32 52 case types.Int64: 53 kind = reflect.Int64 54 case types.Uint: 55 kind = reflect.Uint 56 case types.Uint8: 57 kind = reflect.Uint8 58 case types.Uint16: 59 kind = reflect.Uint16 60 case types.Uint32: 61 kind = reflect.Uint32 62 case types.Uint64: 63 kind = reflect.Uint64 64 case types.Uintptr: 65 kind = reflect.Uintptr 66 case types.Float32: 67 kind = reflect.Float32 68 case types.Float64: 69 kind = reflect.Float64 70 case types.Complex64: 71 kind = reflect.Complex64 72 case types.Complex128: 73 kind = reflect.Complex128 74 case types.UnsafePointer: 75 kind = reflect.UnsafePointer 76 case types.String: 77 kind = reflect.String 78 case types.UntypedBool, types.UntypedComplex, types.UntypedFloat, types.UntypedInt, 79 types.UntypedNil, types.UntypedRune, types.UntypedString, types.Invalid: 80 kind = reflect.Invalid 81 default: 82 panic(fmt.Sprintf("haxe.getTypeinfo() unhandled basic kind: %s", tb.String())) 83 } 84 85 case *types.Array: 86 kind = reflect.Array 87 case *types.Chan: 88 kind = reflect.Chan 89 case *types.Signature: 90 kind = reflect.Func 91 case *types.Interface: 92 kind = reflect.Interface 93 case *types.Map: 94 kind = reflect.Map 95 case *types.Pointer: 96 kind = reflect.Ptr 97 case *types.Slice: 98 kind = reflect.Slice 99 case *types.Struct: 100 kind = reflect.Struct 101 case *types.Named: 102 if tname == "" { 103 tname = t.(*types.Named).Obj().Name() // only do this for the top-level type name 104 } 105 return getTypeInfo(t.Underlying(), tname) 106 case *types.Tuple: 107 kind = reflect.Invalid 108 default: 109 panic(fmt.Sprintf("haxe.getTypeinfo() unhandled type: %T", t)) 110 111 } 112 113 switch kind { 114 case reflect.UnsafePointer, reflect.Ptr, 115 reflect.Map, reflect.Chan, reflect.Func: // TODO not sure about these three 116 default: 117 kind |= kindNoPointers 118 } 119 120 // TODO work out when/if to set kindDirect 121 switch kind & kindMask { 122 case reflect.UnsafePointer, reflect.Ptr, 123 reflect.Map, reflect.Chan, reflect.Func: // TODO not sure about these three 124 kind |= kindDirectIface 125 default: 126 } 127 128 return 129 } 130 131 func (l langType) BuildTypeHaxe() string { 132 133 l.buildTBI() 134 for i, t := range l.hc.typesByID { 135 if i > 0 { 136 synthTypesFor(t) 137 } 138 } 139 l.buildTBI() 140 141 ret := "class Tgotypes {\n" 142 143 for i, t := range l.hc.typesByID { 144 if i > 0 { 145 ret += l.typeBuild(i, t) 146 } 147 } 148 149 ret += "public static function setup() {\nvar a=Go.haxegoruntime_TTypeTTable.load();\n" 150 ret += "var b=a.baseArray.obj;\nvar f=a.baseArray.off+a.itemOff(0);\nvar s=a.itemOff(1)-a.itemOff(0);\n" 151 for i := range l.hc.typesByID { 152 if i > 0 { 153 //fmt.Println("DEBUG setup",i,t) 154 ret += fmt.Sprintf( 155 "b.set((%d*s)+f,type%d());\n", 156 i, i) 157 } 158 } 159 160 ret += "}\n" + "}\n" 161 162 l.PogoComp().WriteAsClass("Tgotypes", ret) 163 164 //fmt.Println("DEBUG generated Haxe code:", ret) 165 166 return ret 167 } 168 169 func (l langType) typeBuild(i int, t types.Type) string { 170 sizes := &haxeStdSizes 171 ret := fmt.Sprintf( // sizeof largest struct (funcType) is 76 172 "private static var type%dptr:Pointer=null; // %s\npublic static function type%d():Pointer { if(type%dptr==null) { type%dptr=Pointer.make(Object.make(80));", 173 i, t.String(), i, i, i) 174 ret += "" 175 176 name := "" 177 if namedT, named := t.(*types.Named); named { 178 name = namedT.Obj().Name() 179 } 180 if basic, isBasic := t.(*types.Basic); isBasic { 181 name = basic.Name() 182 } 183 rtype, kind := l.rtypeBuild(i, sizes, t, name) 184 185 switch t.(type) { 186 case *types.Named: 187 t = t.(*types.Named).Underlying() 188 } 189 190 switch kind & kindMask { 191 case reflect.Invalid, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 192 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 193 reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String, reflect.UnsafePointer: 194 ret += fmt.Sprintf("Go_haxegoruntime_fillRRtype.callFromRT(0,type%dptr,%s)", i, rtype) 195 196 case reflect.Ptr: 197 ret += fmt.Sprintf("Go_haxegoruntime_fillPPtrTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 198 if l.hc.pte.At(t.(*types.Pointer).Elem()) == nil { 199 ret += fmt.Sprintf("/*elem:*/ nil,\n") 200 } else { 201 ret += fmt.Sprintf("/*elem:*/ type%d()\n", 202 l.hc.pte.At(t.(*types.Pointer).Elem()).(int)) 203 } 204 ret += ")" 205 206 case reflect.Array: 207 ret += fmt.Sprintf("Go_haxegoruntime_fillAArrayTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 208 ret += fmt.Sprintf("/*elem:*/ type%d(),\n", 209 l.hc.pte.At(t.(*types.Array).Elem()).(int)) 210 asl := "null" // slice type 211 for _, tt := range l.hc.pte.Keys() { 212 slt, isSlice := tt.(*types.Slice) 213 if isSlice { 214 if l.hc.pte.At(slt.Elem()) == l.hc.pte.At(t.(*types.Array).Elem()) { 215 asl = fmt.Sprintf("type%d()", 216 l.hc.pte.At(slt).(int)) 217 break 218 } 219 } 220 } 221 // TODO make missing slice types before we start outputting types to avoid not having one? 222 ret += fmt.Sprintf("/*slice:*/ %s,\n", asl) 223 ret += fmt.Sprintf("/*len:*/ %d\n", t.(*types.Array).Len()) 224 ret += ")" 225 226 case reflect.Slice: 227 ret += fmt.Sprintf("Go_haxegoruntime_fillSSliceTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 228 ret += fmt.Sprintf("/*elem:*/ type%d()\n", l.hc.pte.At(t.(*types.Slice).Elem()).(int)) 229 ret += ")" 230 231 case reflect.Struct: 232 fields := []*types.Var{} 233 for fld := 0; fld < t.(*types.Struct).NumFields(); fld++ { 234 fldInfo := t.(*types.Struct).Field(fld) 235 //if fldInfo.IsField() { 236 fields = append(fields, fldInfo) 237 //} 238 } 239 offs := sizes.Offsetsof(fields) 240 241 ret += fmt.Sprintf("Go_haxegoruntime_fillSStructTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n/*fields:*/ " 242 fret := "Go_haxegoruntime_newSStructFFieldSSlice.callFromRT(0)" 243 numFlds := t.(*types.Struct).NumFields() 244 for fld := 0; fld < numFlds; fld++ { 245 fldInfo := t.(*types.Struct).Field(fld) 246 name := fldInfo.Name() 247 path := fldInfo.Pkg().Path() 248 if fldInfo.Exported() { 249 path = "" 250 } 251 if fldInfo.Anonymous() { 252 name = "" 253 } 254 255 fret = "\tGo_haxegoruntime_addSStructFFieldSSlice.callFromRT(0," + fret + "," 256 fret += "\n\t\t/*name:*/ \"" + name + "\",\n" 257 fret += "\t\t/*pkgPath:*/ \"" + path + "\",\n" 258 fret += fmt.Sprintf("\t\t/*typ:*/ type%d(),// %s\n", l.hc.pte.At(fldInfo.Type()), fldInfo.Type().String()) 259 fret += "\t\t/*tag:*/ \"" + escapedTypeString(t.(*types.Struct).Tag(fld)) + "\", // " + t.(*types.Struct).Tag(fld) + "\n" 260 fret += fmt.Sprintf("\t\t/*offset:*/ %d\n", offs[fld]) 261 262 fret += "\t)" 263 } 264 265 ret += fret + ")" 266 267 case reflect.Interface: 268 ret += fmt.Sprintf("Go_haxegoruntime_fillIInterfaceTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n/*methods:*/ " 269 mret := "Go_haxegoruntime_newIImethodSSlice.callFromRT(0)" 270 for m := 0; m < t.(*types.Interface).NumMethods(); m++ { 271 meth := t.(*types.Interface).Method(m) 272 mret = "Go_haxegoruntime_addIImethodSSlice.callFromRT(0," + mret + "," 273 mret += "\t\t/*name:*/ \"" + meth.Name() + "\",\n" 274 path := "\"\"" 275 if !meth.Exported() { 276 path = "\"" + meth.Pkg().Path() + "\"" 277 } 278 mret += "\t\t/*pkgPath:*/ " + path + ",\n" 279 typ := "null" 280 iface := l.hc.pte.At(meth.Type()) 281 if iface != interface{}(nil) { 282 typ = fmt.Sprintf("type%d()", iface.(int)) 283 } 284 mret += fmt.Sprintf("\t\t/*typ:*/ %s // %s\n", typ, meth.String()) 285 mret += "\t)\n" 286 } 287 ret += mret + ")" 288 289 case reflect.Map: 290 ret += fmt.Sprintf("Go_haxegoruntime_fillMMapTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 291 ret += fmt.Sprintf("/*key:*/ type%d(),\n", 292 l.hc.pte.At(t.(*types.Map).Key()).(int)) 293 ret += fmt.Sprintf("/*elem:*/ type%d()\n", 294 l.hc.pte.At(t.(*types.Map).Elem()).(int)) 295 ret += ")" 296 297 case reflect.Func: 298 ret += fmt.Sprintf("Go_haxegoruntime_fillFFuncTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 299 ret += fmt.Sprintf("/*dotdotdot:*/ %v,\n", t.(*types.Signature).Variadic()) 300 ret += "/*in:*/ " 301 iret := "Go_haxegoruntime_newPPtrTToRRtypeSSlice.callFromRT(0)" 302 for i := 0; i < t.(*types.Signature).Params().Len(); i++ { 303 iret = fmt.Sprintf("Go_haxegoruntime_addPPtrTToRRtypeSSlice.callFromRT(0,%s,\n\ttype%d())", iret, 304 l.hc.pte.At((t.(*types.Signature).Params().At(i).Type())).(int)) 305 } 306 ret += iret + ",\n/*out:*/ " 307 oret := "Go_haxegoruntime_newPPtrTToRRtypeSSlice.callFromRT(0)" 308 for o := 0; o < t.(*types.Signature).Results().Len(); o++ { 309 oret = fmt.Sprintf("Go_haxegoruntime_addPPtrTToRRtypeSSlice.callFromRT(0,%s,\n\ttype%d())", oret, 310 l.hc.pte.At((t.(*types.Signature).Results().At(o).Type())).(int)) 311 } 312 ret += oret + " )\n" 313 314 case reflect.Chan: 315 ret += fmt.Sprintf("Go_haxegoruntime_fillCChanTType.callFromRT(0,type%dptr,\n/*rtype:*/ ", i) + rtype + ",\n" 316 ret += fmt.Sprintf("/*elem:*/ type%d(),\n", 317 l.hc.pte.At(t.(*types.Chan).Elem()).(int)) 318 reflectDir := reflect.ChanDir(0) 319 switch t.(*types.Chan).Dir() { 320 case types.SendRecv: 321 reflectDir = reflect.BothDir 322 case types.SendOnly: 323 reflectDir = reflect.SendDir 324 case types.RecvOnly: 325 reflectDir = reflect.RecvDir 326 } 327 ret += fmt.Sprintf("/*dir:*/ %d\n", reflectDir) 328 ret += ")" 329 330 default: 331 panic("unhandled reeflect.type") 332 } 333 334 ret += ";" 335 ret += fmt.Sprintf("}; return type%dptr; }\n", i) 336 return ret 337 } 338 func (l langType) rtypeBuild(i int, sizes types.Sizes, t types.Type, name string) (string, reflect.Kind) { 339 var kind reflect.Kind 340 kind, name = getTypeInfo(t, name) 341 sof := int64(4) 342 aof := int64(4) 343 if kind != reflect.Invalid { 344 sof = sizes.Sizeof(t) 345 aof = sizes.Alignof(t) 346 } 347 348 ret := "Go_haxegoruntime_newRRtype.callFromRT(0,\n" 349 ret += fmt.Sprintf("\t/*size:*/ %d,\n", sof) 350 ret += fmt.Sprintf("\t/*align:*/ %d,\n", aof) 351 ret += fmt.Sprintf("\t/*fieldAlign:*/ %d,\n", aof) // TODO check correct for fieldAlign 352 ret += fmt.Sprintf("\t/*kind:*/ %d, // %s\n", kind, (kind & ((1 << 5) - 1)).String()) 353 alg := "false" 354 if types.Comparable(t) { 355 alg = "true" 356 } 357 ret += fmt.Sprintf("\t/*comprable:*/ %s,\n", alg) // TODO change this to be the actual function 358 ret += fmt.Sprintf("\t/*string:*/ \"%s\", // %s\n", escapedTypeString(t.String()), t.String()) 359 ret += fmt.Sprintf("\t/*uncommonType:*/ %s,\n", l.uncommonBuild(i, sizes, name, t)) 360 ptt := "null" 361 for pti, pt := range l.hc.typesByID { 362 _, isPtr := pt.(*types.Pointer) 363 if isPtr { 364 ele := l.hc.pte.At(pt.(*types.Pointer).Elem()) 365 if ele != nil { 366 if i == ele.(int) { 367 ptt = fmt.Sprintf("type%d()", pti) 368 } 369 } 370 } 371 } 372 ret += fmt.Sprintf("\t/*ptrToThis:*/ %s", ptt) 373 ret += ")" 374 return ret, kind 375 } 376 377 func (l langType) uncommonBuild(i int, sizes types.Sizes, name string, t types.Type) string { 378 pkgPath := "" 379 tt := t 380 switch tt.(type) { 381 case *types.Pointer: 382 el, ok := tt.(*types.Pointer).Elem().(*types.Named) 383 if ok { 384 tt = el 385 } 386 } 387 switch tt.(type) { 388 case *types.Named: 389 obj := tt.(*types.Named).Obj() 390 if obj != nil { 391 pkg := obj.Pkg() 392 if pkg != nil { 393 pkgPath = pkg.Path() 394 } 395 } 396 } 397 398 var methods *types.MethodSet 399 numMethods := 0 400 methods = l.PogoComp().MethodSetFor(t) 401 numMethods = methods.Len() 402 if name != "" || numMethods > 0 { 403 ret := "Go_haxegoruntime_newPPtrTToUUncommonTType.callFromRT(0,\n" 404 ret += "\t\t/*name:*/ \"" + name + "\",\n" 405 ret += "\t\t/*pkgPath:*/ \"" + pkgPath + "\",\n" 406 ret += "\t\t/*methods:*/ " 407 meths := "Go_haxegoruntime_newMMethodSSlice.callFromRT(0)" 408 //_, isIF := t.Underlying().(*types.Interface) 409 //if !isIF { 410 for m := 0; m < numMethods; m++ { 411 sel := methods.At(m) 412 ssaFn := l.PogoComp().RootProgram().MethodValue(sel) 413 if l.PogoComp().FnIsCalled(ssaFn) { 414 fn := "null" 415 fnToCall := "null" 416 var name, str, path string 417 fid, haveFn := l.hc.pte.At(sel.Obj().Type()).(int) 418 if haveFn { 419 fn = fmt.Sprintf("type%d()", fid) 420 } 421 name = sel.Obj().Name() 422 str = sel.String() 423 funcObj, ok := sel.Obj().(*types.Func) 424 if ok { 425 pn := "unknown" 426 if funcObj.Pkg() != nil { 427 pn = sel.Obj().Pkg().Name() 428 path = sel.Obj().Pkg().Path() 429 } 430 fnToCall = `Go_` + l.LangName( 431 pn+":"+sel.Recv().String(), 432 funcObj.Name()) 433 } 434 435 // now write out the method information 436 meths = "Go_haxegoruntime_addMMethod.callFromRT(0," + meths + ",\n" 437 meths += fmt.Sprintf("\n\t\t\t/*name:*/ \"%s\", // %s\n", name, str) 438 rune1, _ := utf8.DecodeRune([]byte(name)) 439 if unicode.IsUpper(rune1) { 440 path = "" 441 } 442 443 meths += fmt.Sprintf("\t\t\t/*pkgPath:*/ \"%s\",\n", path) 444 // TODO should the two lines below be different? 445 meths += fmt.Sprintf("\t\t\t/*mtyp:*/ %s,\n", fn) 446 meths += fmt.Sprintf("\t\t\t/*typ:*/ %s,\n", fn) 447 // add links to the functions ... 448 449 if l.hc.funcNamesUsed[fnToCall] { 450 fnToCall += ".call" 451 } else { 452 //println("DEBUG uncommonBuild function name not found: ", fnToCall) 453 fnToCall = "null /* " + fnToCall + " */ " 454 } 455 meths += "\t\t\t" + fnToCall + "," + fnToCall + ")" 456 } 457 } 458 //} 459 ret += meths 460 return ret + "\t)" 461 } 462 return "null" 463 }