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  }