func BuildTypeHaxe() string { buildTBI() for i, t := range typesByID { if i > 0 { synthTypesFor(t) } } buildTBI() ret := "class Tgotypes {\n" for i, t := range typesByID { if i > 0 { ret += typeBuild(i, t) } } ret += "public static function setup() {\nvar a=Go.haxegoruntime_TTypeTTable.load();\n" ret += "var b=a.baseArray.obj;\nvar f=a.baseArray.off+a.itemOff(0);\nvar s=a.itemOff(1)-a.itemOff(0);\n" for i := range typesByID { if i > 0 { //fmt.Println("DEBUG setup",i,t) ret += fmt.Sprintf( "b.set((%d*s)+f,type%d());\n", i, i) } } ret += "}\n" + "}\n" pogo.WriteAsClass("Tgotypes", ret) //fmt.Println("DEBUG generated Haxe code:", ret) return ret }
// Type definitions are only carried through to Haxe to allow access to objects as if they were native Haxe classes. // TODO consider renaming func (l langType) TypeStart(nt *types.Named, err string) string { typName := "GoType" + l.LangName("", nt.String()) hxTyp := l.LangType(nt.Obj().Type(), false, nt.String()) ret := "" switch hxTyp { case "Object": ret += "class " + typName ret += " extends " + hxTyp + " {\n" default: ret += "abstract " + typName + "(" + hxTyp + ") from " + hxTyp + " to " + hxTyp + " {\n" } switch nt.Underlying().(type) { case *types.Struct: str := nt.Underlying().(*types.Struct) ret += "inline public function new(){ super new(" + strconv.Itoa(int(haxeStdSizes.Sizeof(nt.Obj().Type()))) + "); }\n" flds := []string{} for f := 0; f < str.NumFields(); f++ { fName := str.Field(f).Name() if len(fName) > 0 { if unicode.IsUpper(rune(fName[0])) { flds = append(flds, fName) } } } sort.Strings(flds) // make sure the fields are always in the same order in the file for _, fName := range flds { for f := 0; f < str.NumFields(); f++ { if fName == str.Field(f).Name() { haxeTyp := l.LangType(str.Field(f).Type(), false, nt.String()) fOff := fieldOffset(str, f) sfx := loadStoreSuffix(str.Field(f).Type(), true) ret += fmt.Sprintf("public var _%s(get,set):%s;\n", fName, haxeTyp) ret += fmt.Sprintf("function get__%s():%s { return get%s%d); }\n", fName, haxeTyp, sfx, fOff) ret += fmt.Sprintf("function set__%s(v:%s):%s { return set%s%d,v); }\n", fName, haxeTyp, haxeTyp, sfx, fOff) break } } } case *types.Array: ret += "inline public function new(){ super new(" + strconv.Itoa(int(haxeStdSizes.Sizeof(nt.Obj().Type()))) + "); }\n" default: // TODO not yet sure how to handle named types that are not structs ret += "inline public function new(v:" + hxTyp + ") { this = v; }\n" } meths := []string{} for m := 0; m < nt.NumMethods(); m++ { mName := nt.Method(m).Name() if len(mName) > 0 { if unicode.IsUpper(rune(mName[0])) { meths = append(meths, mName) } } } sort.Strings(meths) // make sure the methods always appear in the same order in the file for _, mName := range meths { for m := 0; m < nt.NumMethods(); m++ { meth := nt.Method(m) if mName == meth.Name() { sig := meth.Type().(*types.Signature) ret += "// " + mName + " " + sig.String() + "\n" ret += "public function _" + mName + "(" for p := 0; p < sig.Params().Len(); p++ { if p > 0 { ret += "," } ret += "_" + sig.Params().At(p).Name() + ":" + l.LangType(sig.Params().At(p).Type(), false, nt.String()) } ret += ")" switch sig.Results().Len() { case 0: ret += ":Void " case 1: ret += ":" + l.LangType(sig.Results().At(0).Type(), false, nt.String()) default: ret += ":{" for r := 0; r < sig.Results().Len(); r++ { if r > 0 { ret += "," } ret += fmt.Sprintf("r%d:%s", r, l.LangType(sig.Results().At(r).Type(), false, nt.String())) } ret += "}" } ret += "{\n\t" if sig.Results().Len() > 0 { ret += "return " } fnToCall := l.LangName( nt.Obj().Pkg().Name()+":"+sig.Recv().Type().String(), meth.Name()) ret += `Go_` + fnToCall + `.hx(this` for p := 0; p < sig.Params().Len(); p++ { ret += ", _" + sig.Params().At(p).Name() } ret += ");\n}\n" } } } pogo.WriteAsClass(typName, ret+"}\n") return "" //ret }
func (l langType) EmitTypeInfo() string { BuildTypeHaxe() // generate the code to emulate compiler reflect data output var ret string ret += "\nclass TypeInfo{\n\n" ret += fmt.Sprintf("public static var nextTypeID=%d;\n", pogo.NextTypeID) // must be last as will change during processing // TODO review if this is required ret += "public static function isHaxeClass(id:Int):Bool {\nswitch(id){" + "\n" for k := range pteKeys { v := pte.At(pteKeys[k]) goType := pteKeys[k].String() //fmt.Println("DEBUG full goType", goType) haxeClass := getHaxeClass(goType) if haxeClass != "" { ret += "case " + fmt.Sprintf("%d", v) + `: return true; // ` + goType + "\n" } } ret += `default: return false;}}` + "\n" ret += "public static function getName(id:Int):String {\n" ret += "\tif(id<0||id>=nextTypeID)return \"reflect.CREATED\"+Std.string(id);\n" ret += "\tif(id==0)return \"(haxeTypeID=0)\";" + "\n" ret += "\t#if (js || php || node) if(id==null)return \"(haxeTypeID=null)\"; #end\n" ret += "\t" + `return Go_haxegoruntime_getTTypeSString.callFromRT(0,id);` + "\n}\n" ret += "public static function typeString(i:Interface):String {\nreturn getName(i.typ);\n}\n" /* ret += "static var typIDs:Map<String,Int> = [" deDup := make(map[string]bool) for k := range pteKeys { v := pte.At(pteKeys[k]) nam := haxeStringConst("`"+preprocessTypeName(pteKeys[k].String())+"`", "CompilerInternal:haxe.EmitTypeInfo()") if len(nam) != 0 { if deDup[nam] { // have one already!! nam = fmt.Sprintf("%s (duplicate type name! this id=%d)\"", nam[:len(nam)-1], v) } else { deDup[nam] = true } ret += ` ` + nam + ` => ` + fmt.Sprintf("%d", v) + `,` + "\n" } } ret += "];\n" */ ret += "public static function getId(name:String):Int {\n" ret += "\tvar t:Int;\n" //ret += "\ttry { t=typIDs[name];\n" //ret += "\t} catch(x:Dynamic) { Scheduler.panicFromHaxe(\"TraceInfo.getId() not found:\"+name+x); t=-1; } ;\n" ret += "\t" + `t = Go_haxegoruntime_getTTypeIIDD.callFromRT(0,name);` + "\n" ret += "\treturn t;\n}\n" //function to answer the question is the type a concrete value? ret += "public static function isConcrete(t:Int):Bool {\nswitch(t){" + "\n" for T := range pteKeys { t := pte.At(pteKeys[T]) switch pteKeys[T].Underlying().(type) { case *types.Interface: ret += `case ` + fmt.Sprintf("%d", t) + `: return false;` + "\n" } } ret += "default: return true;}}\n" //emulation of: func IsIdentical(x, y Type) bool ret += "public static function isIdentical(v:Int,t:Int):Bool {\nif(v==t) return true;\nswitch(v){" + "\n" for V := range pteKeys { v := pte.At(pteKeys[V]) ret0 := "" for T := range pteKeys { t := pte.At(pteKeys[T]) if v != t && types.Identical(pteKeys[V], pteKeys[T]) { ret0 += `case ` + fmt.Sprintf("%d", t) + `: return true;` + "\n" } } if ret0 != "" { ret += `case ` + fmt.Sprintf("%d", v) + `: switch(t){` + "\n" ret += ret0 ret += "default: return false;}\n" } } ret += "default: return false;}}\n" ret += "}\n" pogo.WriteAsClass("TypeInfo", ret) ret = "class TypeAssign {" //emulation of: func IsAssignableTo(V, T Type) bool ret += "public static function isAssignableTo(v:Int,t:Int):Bool {\n\tif(v==t) return true;\n" ret += "\tfor(ae in isAsssignableToArray) if(ae==(v<<16|t)) return true;\n" ret += "\treturn false;\n}\n" ret += "static var isAsssignableToArray:Array<Int> = [" for V := range pteKeys { v := pte.At(pteKeys[V]) for T := range pteKeys { t := pte.At(pteKeys[T]) if v != t && types.AssignableTo(pteKeys[V], pteKeys[T]) { ret += fmt.Sprintf("%d,", v.(int)<<16|t.(int)) } } ret += "\n" } ret += "];\n" ret += "}\n" pogo.WriteAsClass("TypeAssign", ret) /* ret = "class TypeAssert {" //emulation of: func type.AsertableTo(V *Interface, T Type) bool ret += "public static function assertableTo(v:Int,t:Int):Bool {\n" //ret += "trace(\"DEBUG assertableTo()\",v,t);\n" ret += "\tif(v==t) return true;\n" ret += "\tfor(ae in isAssertableToArray) if(ae==(v<<16|t)) return true;\n" ret += "return false;\n}\n" ret += "static var isAssertableToArray:Array<Int> = [ " for tid, typ := range typesByID { ret0 := "" if typ != nil { for iid, ityp := range typesByID { if ityp != nil { iface, isIface := ityp.Underlying().(*types.Interface) if isIface { if tid != iid && types.AssertableTo(iface, typ) { ret0 += fmt.Sprintf("0x%08X,", (tid<<16)|iid) } } } } } if ret0 != "" { ret += ret0 ret += "\n" } } ret += "];\n" ret += "}\n" pogo.WriteAsClass("TypeAssert", ret) */ ret = "class TypeZero {" // function to give the zero value for each type ret += "public static function zeroValue(t:Int):Dynamic {\nswitch(t){" + "\n" for T := range pteKeys { t := pte.At(pteKeys[T]) z := l.LangType(pteKeys[T], true, "EmitTypeInfo()") if z == "" { z = "null" } if z != "null" { ret += `case ` + fmt.Sprintf("%d", t) + `: return ` ret += z + ";\n" } } ret += "default: return null;}}\n" ret += "}\n" pogo.WriteAsClass("TypeZero", ret) /* ret = "class MethodTypeInfo {" ret += "public static function method(t:Int,m:String):Dynamic {\nswitch(t){" + "\n" tta := pogo.TypesWithMethodSets() //[]types.Type sort.Sort(pogo.TypeSorter(tta)) for T := range tta { t := pte.At(tta[T]) if t != nil { // it is used? ret += `case ` + fmt.Sprintf("%d", t) + `: switch(m){` + "\n" ms := types.NewMethodSet(tta[T]) msNames := []string{} for m := 0; m < ms.Len(); m++ { msNames = append(msNames, ms.At(m).String()) } sort.Strings(msNames) deDup := make(map[string][]int) // TODO check this logic, required for non-public methods for pass := 1; pass <= 2; pass++ { for _, msString := range msNames { for m := 0; m < ms.Len(); m++ { if ms.At(m).String() == msString { // ensure we do this in a repeatable order funcObj, ok := ms.At(m).Obj().(*types.Func) pkgName := "unknown" if ok && funcObj.Pkg() != nil && ms.At(m).Recv() == tta[T] { line := "" ss := strings.Split(funcObj.Pkg().Name(), "/") pkgName = ss[len(ss)-1] if strings.HasPrefix(pkgName, "_") { // exclude functions in haxe for now // TODO NoOp for now... so haxe types cant be "Involked" when held in interface types // *** need to deal with getters and setters // *** also with calling parameters which are different for a Haxe API } else { switch pass { case 1: idx, exists := deDup[funcObj.Name()] if exists { if len(idx) > len(ms.At(m).Index()) { deDup[funcObj.Name()] = ms.At(m).Index() } } else { deDup[funcObj.Name()] = ms.At(m).Index() } case 2: idx, _ := deDup[funcObj.Name()] if len(idx) != len(ms.At(m).Index()) { line += "// Duplicate unused: " } line += `case "` + funcObj.Name() + `": return ` fnToCall := l.LangName( ms.At(m).Obj().Pkg().Name()+":"+ms.At(m).Recv().String(), funcObj.Name()) line += `Go_` + fnToCall + `.call` + "; " } } ret += line } if pass == 2 { ret += fmt.Sprintf("// %v %v %v %v\n", ms.At(m).Obj().Name(), ms.At(m).Kind(), ms.At(m).Index(), ms.At(m).Indirect()) } } } } } ret += "default:}\n" } } // TODO look for overloaded types at this point ret += "default:}\n Scheduler.panicFromHaxe( " + `"no method found!"` + "); return null;}\n" // TODO improve error pogo.WriteAsClass("MethodTypeInfo", ret+"}\n") */ return "" }