github.com/tardisgo/tardisgo@v0.0.0-20161119180838-e0dd9a7e46b5/haxe/base.go (about)

     1  // Copyright 2014 Elliott Stoneham and The TARDIS Go Authors
     2  // Use of this source code is governed by an MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package haxe
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"go/token"
    11  	"go/types"
    12  	"reflect"
    13  	"sort"
    14  	"strings"
    15  	"unicode"
    16  
    17  	"golang.org/x/tools/go/ssa"
    18  
    19  	"github.com/tardisgo/tardisgo/tgossa"
    20  	"github.com/tardisgo/tardisgo/tgoutil"
    21  )
    22  
    23  func (l langType) emitTrace(s string) string {
    24  	if l.PogoComp().TraceFlag {
    25  		return `trace(this._functionName,this._latestBlock,"TRACE ` + s + ` "` /* + ` "+Scheduler.stackDump()` */ + ");\n"
    26  	}
    27  	return ""
    28  }
    29  
    30  func (langType) LanguageName() string   { return "haxe" }
    31  func (langType) FileTypeSuffix() string { return ".hx" }
    32  
    33  // make a comment
    34  func (l langType) Comment(c string) string {
    35  	if c != "" && l.PogoComp().DebugFlag { // only comment if something to say and in debug mode
    36  		return " // " + c
    37  	}
    38  	return ""
    39  }
    40  
    41  const imports = `` // nothing currently
    42  
    43  const tardisgoLicence = `// This code generated using the TARDIS Go tool, elements are
    44  // Copyright 2014 Elliott Stoneham and The TARDIS Go Authors
    45  // Use of this source code is governed by an MIT-style
    46  // license that can be found in the LICENSE file at https://github.com/tardisgo/tardisgo
    47  `
    48  
    49  func (langType) FileStart(haxePackageName, headerText string) string {
    50  	if haxePackageName == "" {
    51  		haxePackageName = "tardis"
    52  	}
    53  	return "package " + haxePackageName + ";\n" + imports + headerText + tardisgoLicence
    54  }
    55  
    56  // TODO rename
    57  func (l langType) FileEnd() string {
    58  	return l.haxeruntime() // this deals with the individual runtime class files
    59  }
    60  
    61  // RegisterName returns the name of an ssa.Value, a utility function in case it needs to be altered.
    62  func (l langType) RegisterName(val ssa.Value) string {
    63  	//NOTE the SSA code says that name() should not be relied on, so this code may need to alter
    64  
    65  	if l.hc.useRegisterArray { // we must use a register array when there are too many registers declared at class level for C++/Java to handle
    66  		reg := val.Name()
    67  		if reg[0] != 't' {
    68  			panic("Register Name does not begin with t: " + reg)
    69  		}
    70  		return "_t[" + reg[1:] + "]"
    71  	}
    72  	return "_" + val.Name()
    73  }
    74  
    75  type regToFree struct {
    76  	reg, typ string
    77  }
    78  
    79  func recycle(list []regToFree) string {
    80  	ret := []string{}
    81  	for _, x := range list {
    82  		switch x.typ {
    83  		case "GOint64":
    84  			//ret += "#if !(cpp|cs|java) " + x.reg + "=null; #end\n" // TODO
    85  		default:
    86  			ret = append(ret, ""+x.reg+"=null; // "+x.typ+"") // this improves GC performance on all targets
    87  		}
    88  	}
    89  	ret = sort.StringSlice(ret) // make sure it is always done in the same order
    90  	return strings.Join(ret, "\n") + "\n"
    91  }
    92  
    93  func (l langType) FuncStart(packageName, objectName string, fn *ssa.Function, blks []*ssa.BasicBlock, position string, isPublic, trackPhi, usesGr bool, canOptMap map[string]bool, reconstruct []tgossa.BlockFormat) string {
    94  
    95  	//fmt.Println("DEBUG: HAXE FuncStart: ", packageName, ".", objectName, usesGr)
    96  
    97  	l.hc.nextReturnAddress = -1
    98  	l.hc.hadReturn = false
    99  	l.hc.hadBlockReturn = false
   100  	l.hc.pseudoBlockNext = -1
   101  	l.hc.currentfn = fn
   102  	l.hc.currentfnName = "Go_" + l.LangName(packageName, objectName)
   103  	l.hc.funcNamesUsed[l.hc.currentfnName] = true
   104  	l.hc.fnUsesGr = usesGr
   105  	l.hc.fnTracksPhi = trackPhi
   106  	l.hc.fnCanOptMap = canOptMap
   107  	nullOnExitList := []regToFree{} // names to set to null before we exit the function
   108  	l.reset1useMap()
   109  
   110  	if l.PogoComp().DebugFlag {
   111  		l.hc.reconstructInstrs = nil
   112  	} else {
   113  		l.hc.reconstructInstrs = reconstruct
   114  	}
   115  	l.hc.elseStack = []string{}
   116  
   117  	ret := ""
   118  
   119  	// need to make private classes, aside from correctness,
   120  	// because cpp & java have a problem with functions whose names are the same except for the case of the 1st letter
   121  	if isPublic {
   122  		ret += fmt.Sprintf(`#if js @:expose("Go_%s") #end `, l.LangName(packageName, objectName))
   123  	} else {
   124  		//	ret += "#if (!php) private #end " // for some reason making classes private is a problem in php
   125  	}
   126  	ret += fmt.Sprintf("class %s extends StackFrameBasis implements StackFrame { %s\n",
   127  		l.hc.currentfnName, l.Comment(position))
   128  
   129  	//Create the stack frame variables
   130  	hadBlank := false
   131  	for p := range fn.Params {
   132  		prefix := "p_"
   133  		if hadBlank && fn.Params[p].Name() == "_" {
   134  			prefix += fmt.Sprintf("%d", p)
   135  		}
   136  		pnam := prefix + tgoutil.MakeID(fn.Params[p].Name())
   137  		ptyp := l.LangType(fn.Params[p].Type() /*.Underlying()*/, false, fn.Params[p].Name()+position)
   138  		ret += "private var " + pnam + ":" + ptyp + ";\n"
   139  		switch ptyp {
   140  		case "Int", "Float", "Bool": // not objects
   141  		default:
   142  			nullOnExitList = append(nullOnExitList, regToFree{pnam, ptyp})
   143  		}
   144  		if fn.Params[p].Name() == "_" {
   145  			hadBlank = true
   146  		}
   147  	}
   148  	ret += "public function new(gr:Int,"
   149  	ret += "_bds:Array<Dynamic>" //bindings
   150  	for p := range fn.Params {
   151  		ret += ", "
   152  		pnam := "p_" + tgoutil.MakeID(fn.Params[p].Name())
   153  		ptyp := l.LangType(fn.Params[p].Type() /*.Underlying()*/, false, fn.Params[p].Name()+position)
   154  		ret += pnam + " : " + ptyp
   155  	}
   156  	ret += ") {\nsuper(gr," + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) + ",\"Go_" + l.LangName(packageName, objectName) + "\");\nthis._bds=_bds;\n"
   157  	hadBlank = false
   158  	for p := range fn.Params {
   159  		prefix := "this.p_"
   160  		if hadBlank && fn.Params[p].Name() == "_" {
   161  			prefix += fmt.Sprintf("%d", p)
   162  		}
   163  		ret += prefix + tgoutil.MakeID(fn.Params[p].Name()) + "=p_" + tgoutil.MakeID(fn.Params[p].Name()) + ";\n"
   164  		if l.PogoComp().DebugFlag {
   165  			ret += `this.setDebugVar("` + fn.Params[p].Name() + `",p_` + tgoutil.MakeID(fn.Params[p].Name()) + ");\n"
   166  		}
   167  		if fn.Params[p].Name() == "_" {
   168  			hadBlank = true
   169  		}
   170  	}
   171  	if fn.Recover != nil {
   172  		//for b := 0; b < len(blks); b++ {
   173  		//	if fn.Recover.Index == blks[b].Index {
   174  		//		ret += fmt.Sprintf("this._recoverNext=%d;\n", b)
   175  		//		break
   176  		//	}
   177  		//}
   178  		ret += fmt.Sprintf("this._recoverNext=%d;\n", fn.Recover.Index)
   179  	}
   180  	ret += l.emitTrace(`New:` + l.LangName(packageName, objectName))
   181  	ret += "Scheduler.push(gr,this);\n}\n"
   182  
   183  	rTyp := ""
   184  	rInit := ""
   185  	switch fn.Signature.Results().Len() {
   186  	case 0:
   187  		// NoOp
   188  	case 1:
   189  		rTyp = l.LangType(fn.Signature.Results().At(0).Type() /*.Underlying()*/, false, position)
   190  		rInit = l.LangType(fn.Signature.Results().At(0).Type() /*.Underlying()*/, true, position)
   191  	default:
   192  		rTyp = "{"
   193  		rInit = "{"
   194  		for r := 0; r < fn.Signature.Results().Len(); r++ {
   195  			if r != 0 {
   196  				rTyp += ", "
   197  				rInit += ", "
   198  			}
   199  			rTyp += fmt.Sprintf("r%d:", r) + l.LangType(fn.Signature.Results().At(r).Type() /*.Underlying()*/, false, position)
   200  			rInit += fmt.Sprintf("r%d:", r) + l.LangType(fn.Signature.Results().At(r).Type() /*.Underlying()*/, true, position)
   201  		}
   202  		rTyp += "}"
   203  		rInit += "}"
   204  	}
   205  	if rTyp != "" {
   206  		ret += "private var _res:" + rTyp + "=" + rInit + ";\n" // code may not be generated if return val is default
   207  		ret += "public inline function res():Dynamic " + "{return _res;}\n"
   208  	} else {
   209  		ret += "public inline function res():Dynamic {return null;}\n" // just to keep the interface definition happy
   210  	}
   211  
   212  	// call from haxe (TODO: maybe run in a new goroutine)
   213  	ret += "public static function hx( " // used to call this function from Haxe
   214  	for p := range fn.Params {
   215  		if p != 0 {
   216  			ret += ", "
   217  		}
   218  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name()) + " : " + l.LangType(fn.Params[p].Type() /*.Underlying()*/, false, fn.Params[p].Name()+position)
   219  	}
   220  	ret += ") : "
   221  	switch fn.Signature.Results().Len() {
   222  	case 0:
   223  		ret += "Void"
   224  	case 1:
   225  		ret += l.LangType(fn.Signature.Results().At(0).Type() /*.Underlying()*/, false, position)
   226  	default:
   227  		ret += "{"
   228  		for r := 0; r < fn.Signature.Results().Len(); r++ {
   229  			if r != 0 {
   230  				ret += ", "
   231  			}
   232  			ret += fmt.Sprintf("r%d:", r) + l.LangType(fn.Signature.Results().At(r).Type() /*.Underlying()*/, false, position)
   233  		}
   234  		ret += "}"
   235  	}
   236  	ret += " {\n"
   237  	ret += "if(!Go.doneInit) Go.init();\n" // very defensive TODO remove this once everyone understands that Go.init() must be called first
   238  	ret += "var _sf=new Go_" + l.LangName(packageName, objectName)
   239  	ret += "(0,null" // NOTE calls from Haxe hijack goroutine 0, so the main go goroutine will be suspended for the duration
   240  	for p := range fn.Params {
   241  		ret += ", "
   242  		if fn.Params[p].Type().Underlying().String() == "string" {
   243  			ret += "Force.fromHaxeString("
   244  		}
   245  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name())
   246  		if fn.Params[p].Type().Underlying().String() == "string" {
   247  			ret += ")"
   248  		}
   249  	}
   250  	ret += ").run(); \n"
   251  	if usesGr {
   252  		ret += "while(_sf._incomplete) Scheduler.runAll();\n" // TODO alter for multi-threading if ever implemented
   253  	}
   254  	if fn.Signature.Results().Len() > 0 {
   255  		if fn.Signature.Results().Len() == 1 {
   256  			if fn.Signature.Results().At(0).Type().Underlying().String() == "string" {
   257  				ret += "return Force.toHaxeString(cast(_sf.res(),String));\n"
   258  			} else {
   259  				ret += "return _sf.res();\n"
   260  			}
   261  		} else {
   262  			ret += "var _r = _sf.res();\n"
   263  			for rv := 0; rv < fn.Signature.Results().Len(); rv++ {
   264  				if fn.Signature.Results().At(rv).Type().Underlying().String() == "string" {
   265  					ret += fmt.Sprintf("_r.r%d = Force.toHaxeString(cast(_r.r%d,String));\n", rv, rv)
   266  				}
   267  			}
   268  			ret += "return _r;\n"
   269  		}
   270  	}
   271  	ret += "}\n"
   272  
   273  	// call from haxe go runtime - use current goroutine
   274  	ret += "public static function callFromRT( _gr:Int"
   275  	for p := range fn.Params {
   276  		//if p != 0 {
   277  		ret += ", "
   278  		//}
   279  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name()) + " : " + l.LangType(fn.Params[p].Type() /*.Underlying()*/, false, fn.Params[p].Name()+position)
   280  	}
   281  	ret += ") : "
   282  	switch fn.Signature.Results().Len() {
   283  	case 0:
   284  		ret += "Void"
   285  	case 1:
   286  		ret += l.LangType(fn.Signature.Results().At(0).Type() /*.Underlying()*/, false, position)
   287  	default:
   288  		ret += "{"
   289  		for r := 0; r < fn.Signature.Results().Len(); r++ {
   290  			if r != 0 {
   291  				ret += ", "
   292  			}
   293  			ret += fmt.Sprintf("r%d:", r) + l.LangType(fn.Signature.Results().At(r).Type() /*.Underlying()*/, false, position)
   294  		}
   295  		ret += "}"
   296  	}
   297  	ret += " {\n" /// we have already done Go.init() if we are calling from the runtime
   298  	ret += "var _sf=new Go_" + l.LangName(packageName, objectName)
   299  	ret += "(_gr,null" //  use the given Goroutine
   300  	for p := range fn.Params {
   301  		ret += ", "
   302  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name())
   303  	}
   304  	ret += ").run(); \n"
   305  	if usesGr {
   306  		ret += "while(_sf._incomplete) Scheduler.run1(_gr);\n" // NOTE no "panic()" or "go" code in runtime Go
   307  	}
   308  	if fn.Signature.Results().Len() > 0 {
   309  		ret += "return _sf.res();\n"
   310  	}
   311  	ret += "}\n"
   312  
   313  	// call
   314  	ret += "public static function call( gr:Int," //this just creates the stack frame, NOTE does not run anything because also used for defer
   315  	ret += "_bds:Array<Dynamic>"                  //bindings
   316  	for p := range fn.Params {
   317  		ret += ", "
   318  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name()) + " : " + l.LangType(fn.Params[p].Type() /*.Underlying()*/, false, fn.Params[p].Name()+position)
   319  	}
   320  	ret += ") : Go_" + l.LangName(packageName, objectName)
   321  	ret += "\n{" + ""
   322  	ret += "return "
   323  	ret += "new Go_" + l.LangName(packageName, objectName) + "(gr,_bds"
   324  	for p := range fn.Params {
   325  		ret += ", "
   326  		ret += "p_" + tgoutil.MakeID(fn.Params[p].Name())
   327  	}
   328  	ret += ");\n"
   329  	ret += "}\n"
   330  
   331  	if !usesGr {
   332  		if l.hc.reconstructInstrs != nil {
   333  			ret += l.runFunctionCode(packageName, objectName, "[ RECONSTRUCTED NON-GOROUTINE FUNCTION ]")
   334  		} else {
   335  			ret += l.runFunctionCode(packageName, objectName, "[ UN-RECONSTRUCTED NON-GOROUTINE FUNCTION ]")
   336  		}
   337  	}
   338  
   339  	/*
   340  		if reconstructInstrs != nil {
   341  			for k, v := range reconstructInstrs {
   342  				if v.IsWhileCandidate {
   343  					ret += fmt.Sprintf("#if jsX var _wh%d:Dynamic=null; #end\n", blks[k].Index)
   344  				}
   345  			}
   346  		}
   347  	*/
   348  
   349  	regCount := 0
   350  	regDefs := ""
   351  	l.hc.useRegisterArray = false
   352  
   353  	l.hc.pseudoNextReturnAddress = -1
   354  	for b := range blks {
   355  		for i := range blks[b].Instrs {
   356  			in := blks[b].Instrs[i]
   357  			if !l.CanInline(in) {
   358  
   359  				reg := l.Value(in, l.PogoComp().CodePosition(in.Pos()))
   360  
   361  				switch in.(type) {
   362  				case *ssa.Call:
   363  					switch in.(*ssa.Call).Call.Value.(type) {
   364  					case *ssa.Builtin:
   365  						//NoOp
   366  					default:
   367  						// Optimise here not to declare Stack Frames for pseudo-functions used when calling Haxe code direct
   368  						pp := l.getPackagePath(in.(*ssa.Call).Common())
   369  						ppBits := strings.Split(pp, "/")
   370  						if ppBits[len(ppBits)-1] != "hx" && !strings.HasPrefix(ppBits[len(ppBits)-1], "_") {
   371  							//if usesGr {
   372  							//	ret += "private "
   373  							//}
   374  							ret += fmt.Sprintf("var _SF%d:StackFrame", -l.hc.pseudoNextReturnAddress) //TODO set correct type, or let Haxe determine
   375  							nullOnExitList = append(nullOnExitList, regToFree{fmt.Sprintf("_SF%d", -l.hc.pseudoNextReturnAddress), "StackFrame"})
   376  							if usesGr {
   377  								ret += " #if jsinit =null #end " // v8 opt
   378  								ret += ";\n"
   379  							} else {
   380  								//if reconstructInstrs == nil {
   381  								//	ret += "=null;\n" // need to initalize when using the native stack for these vars
   382  								//} else {
   383  								ret += " #if jsinit =null #end " // v8 opt
   384  								ret += ";\n"
   385  								//}
   386  							}
   387  						}
   388  						l.hc.pseudoNextReturnAddress--
   389  					}
   390  				case *ssa.Send, *ssa.Select, *ssa.RunDefers, *ssa.Panic:
   391  					l.hc.pseudoNextReturnAddress--
   392  				case *ssa.UnOp:
   393  					if in.(*ssa.UnOp).Op == token.ARROW {
   394  						l.hc.pseudoNextReturnAddress--
   395  					}
   396  				case *ssa.Alloc:
   397  					if !in.(*ssa.Alloc).Heap { // allocate space on the stack if possible
   398  						//fmt.Println("DEBUG allocate stack space for", reg, "at", position)
   399  						if reg != "" {
   400  							reg = strings.TrimSuffix(reg, "inline()") // if there is one
   401  							ret += l.haxeVar(reg+"_stackalloc", "Object", "="+allocNewObject(in.(*ssa.Alloc).Type()), position, "FuncStart()") + "\n"
   402  						}
   403  					}
   404  				}
   405  
   406  				if reg != "" && !canOptMap[reg[1:]] { // only add the reg to the SF if not defined in sub-functions
   407  					// Underlying() not used in 2 lines below because of *ssa.(opaque type)
   408  					typ := l.LangType(in.(ssa.Value).Type(), false, reg+"@"+position)
   409  					init := l.LangType(in.(ssa.Value).Type(), true, reg+"@"+position) // this may be overkill...
   410  
   411  					if strings.HasPrefix(init, "{") || strings.HasPrefix(init, "Pointer.make") ||
   412  						strings.HasPrefix(init, "Object.make") || strings.HasPrefix(init, "new Slice") ||
   413  						strings.HasPrefix(init, "new Chan") || strings.HasPrefix(init, "new GOmap") ||
   414  						strings.HasPrefix(init, "new Complex") { // stop unnecessary initialisation
   415  						// all SSA registers are actually assigned to before use, so minimal initialisation is required, except for maps
   416  						init = "null"
   417  					}
   418  					if typ != "" {
   419  						switch len(*in.(ssa.Value).Referrers()) {
   420  						case 0: // don't allocate unused temporary variables
   421  						default:
   422  							if usesGr {
   423  								if init == "null" {
   424  									nullOnExitList = append(nullOnExitList, regToFree{reg, typ})
   425  								}
   426  								init = " #if jsinit =" + init + " #end " // only init in JS, to tell the var type for v8 opt
   427  							} else {
   428  								if init == "null" {
   429  									nullOnExitList = append(nullOnExitList, regToFree{reg, typ})
   430  								}
   431  								if init == "null" && l.hc.reconstructInstrs != nil {
   432  									init = " #if jsinit = null #end "
   433  								} else {
   434  									init = " = " + init + " " // when not using goroutines, sadly they all need initializing because the Haxe compiler objects
   435  								}
   436  							}
   437  							switch typ {
   438  							case "String", "GOint64":
   439  								nullOnExitList = append(nullOnExitList, regToFree{reg, typ})
   440  							}
   441  							hv := l.haxeVar(reg, typ, init, position, "FuncStart()") + "\n"
   442  							regDefs += hv
   443  							regCount++
   444  						}
   445  					}
   446  				}
   447  			}
   448  		}
   449  	}
   450  
   451  	if regCount > l.hc.langEntry.InstructionLimit { // should only affect very large init() fns
   452  		//fmt.Println("DEBUG regCount", currentfnName, regCount)
   453  		l.hc.useRegisterArray = true
   454  		ret += "var _t=new Array<Dynamic>();\n"
   455  		ret += "inline function nullOnExit(){_t=null;};\n"
   456  	} else {
   457  		l.hc.useRegisterArray = false
   458  		ret += regDefs
   459  		ret += "inline function nullOnExit(){\n"
   460  		ret += "#if nulltempvars\n"
   461  		ret += recycle(nullOnExitList)
   462  		ret += "#end\n"
   463  		ret += "nullOnExitSF();\n"
   464  		ret += "};\n"
   465  	}
   466  	//if trackPhi {
   467  	//	ret += "var _Phi:Int=0;\n"
   468  	//}
   469  
   470  	if usesGr {
   471  		ret += l.runFunctionCode(packageName, objectName, "")
   472  	}
   473  
   474  	return ret
   475  }
   476  
   477  func (l langType) runFunctionCode(packageName, objectName, msg string) string {
   478  	ret := "public function run():Go_" + l.LangName(packageName, objectName) + " { //" + msg + "\n"
   479  	ret += l.emitTrace(`Run: ` + l.LangName(packageName, objectName) + " " + msg)
   480  	return ret
   481  }
   482  
   483  func (l langType) whileCaseCode() string {
   484  	// NOTE this rather odd arrangement improves JS V8 optimization
   485  	ret := "#if uselocalfunctions\n"
   486  	ret += "function " + l.hc.currentfnName + "_loop():" + l.hc.currentfnName + "{\n"
   487  	ret += "\tvar retVal:" + l.hc.currentfnName + "=null;\n"
   488  
   489  	ret += "\twhile(retVal==null) \n"
   490  
   491  	if l.hc.fnUsesGr {
   492  		ret += "\t\tswitch(_Next){\n"
   493  		for k, v := range l.hc.localFunctionMap {
   494  			ret += fmt.Sprintf("\t\t\tcase %d: retVal=%s();\n", k, v)
   495  		}
   496  		ret += "\t\t}\n"
   497  	} else {
   498  		ret += "\t\tretVal=fnMap.get(_Next)();\n"
   499  		ret += "\tfnMap=null;\n" // tidy up
   500  	}
   501  	ret += "\treturn retVal;\n"
   502  	ret += "}\n"
   503  	if !l.hc.fnUsesGr {
   504  		ret += "return " + l.hc.currentfnName + "_loop();\n"
   505  	}
   506  	ret += "#else\n"
   507  	ret += "\tdefault: Scheduler.bbi();\n}\n"
   508  	ret += `
   509  	#if js
   510  		return null; }; // the end of a separate function to encourage JS V8 optimisation
   511  		while(sw()==null) {}  // repeatedly call the local JS function
   512  	#end
   513  `
   514  	ret += "#end\n"
   515  	return ret
   516  }
   517  
   518  func (l langType) RunEnd(fn *ssa.Function) string {
   519  	// TODO reoptimize if blocks >0 and no calls that create synthetic block entries
   520  	ret := ""
   521  	if l.hc.reconstructInstrs == nil {
   522  		ret += l.emitUnseenPseudoBlocks()
   523  		ret += l.whileCaseCode()
   524  		if l.hc.fnUsesGr {
   525  			ret += "\n#if !uselocalfunctions return this; } #end\n"
   526  		} else {
   527  			ret += "\n#if !uselocalfunctions return this; #end\n}\n"
   528  		}
   529  	} else {
   530  		ret += "// Func code all emitted (handle extra reconstruction block for function)\n"
   531  		l.hc.thisBlock++
   532  		ret += l.reconstructBlock()
   533  
   534  		//for b := thisBlock; b < len(reconstructInstrs); b++ {
   535  		//	for i := 0; i < reconstructInstrs[b].EndBracketCount; i++ {
   536  		//		ret += " } "
   537  		//	}
   538  		//}
   539  
   540  		// TODO optimise to only emit this code if directly previous block does not have an explicit return
   541  		ret += `this._incomplete=false;
   542  Scheduler.pop(this._goroutine);
   543  nullOnExit();
   544  return this;
   545  ` // for when the SSA code does not contain an explicit return;
   546  
   547  		ret += "}\n" // for the run function
   548  	}
   549  	return ret
   550  }
   551  func (l langType) FuncEnd(fn *ssa.Function) string {
   552  	// actually, the end of the class for that Go function
   553  	l.PogoComp().WriteAsClass(l.hc.currentfnName, "}\n")
   554  	return ``
   555  }
   556  
   557  // utiltiy to set-up a haxe variable
   558  func (l langType) haxeVar(reg, typ, init, position, errorStart string) string {
   559  	if typ == "" {
   560  		l.PogoComp().LogError(position, "Haxe", fmt.Errorf(errorStart+" unhandled initialisation for empty type"))
   561  		return ""
   562  	}
   563  	ret := "var " + reg + ":" + typ
   564  	if init != "" {
   565  		ret += init
   566  	}
   567  	return ret + ";"
   568  }
   569  
   570  func (l langType) SetPosHash() string {
   571  	return "this.setPH(" + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) + ");"
   572  }
   573  
   574  func (l langType) BlockStart(block []*ssa.BasicBlock, num int, emitPhi bool) string {
   575  	l.hc.rangeChecks = make(map[string]struct{})
   576  	l.hc.thisBlock = num
   577  	l.hc.tempVarList = []regToFree{}
   578  	l.hc.hadBlockReturn = false
   579  	// TODO optimise is only 1 block AND no calls
   580  	// TODO if len(block) > 1 { // no need for a case statement if only one block
   581  	ret := ""
   582  
   583  	ret += fmt.Sprintf("// BlockID: %d Idom: %v Dominees: %v Successors: %v\n",
   584  		block[num].Index, block[num].Idom(), block[num].Dominees(), block[num].Succs)
   585  
   586  	if l.hc.reconstructInstrs == nil { // Normal unreconstructed code
   587  
   588  		if num == 0 {
   589  			l.hc.localFunctionMap = make(map[int]string)
   590  			ret += `
   591  #if !uselocalfunctions
   592  	#if js
   593  		var sw = function(){ switch(_Next){  // put in a separate function to encourage JS V8 optimisation
   594  	#else
   595  		while(true) switch(_Next){  // while(true) and similar formulas disable JS V8 optimisation
   596  	#end
   597  #end
   598  `
   599  			ret += "#if uselocalfunctions "
   600  			if l.hc.fnUsesGr {
   601  				ret += "return " + l.hc.currentfnName + "_loop(); } "
   602  			} else {
   603  				ret += "var fnMap=new Map<Int,Void->" + l.hc.currentfnName + ">(); "
   604  			}
   605  			ret += "#end\n"
   606  		}
   607  		ret += fmt.Sprintf("#if !uselocalfunctions case %d: #end", block[num].Index) + l.Comment(block[num].Comment) + "\n"
   608  		if l.hc.fnUsesGr {
   609  			fn := fmt.Sprintf(l.hc.currentfnName+"_%d", block[num].Index)
   610  			l.hc.localFunctionMap[block[num].Index] = fn
   611  			ret += "#if uselocalfunctions function " + fn + "():" + l.hc.currentfnName + " { #end\n"
   612  		} else {
   613  			ret += fmt.Sprintf("#if uselocalfunctions fnMap.set(%d,function "+l.hc.currentfnName+"_%d():"+l.hc.currentfnName+" { #end\n",
   614  				block[num].Index, block[num].Index)
   615  		}
   616  		ret += l.emitTrace(fmt.Sprintf("Function: %s Block:%d", block[num].Parent(), block[num].Index))
   617  		if l.PogoComp().DebugFlag {
   618  			ret += "this.setLatest(" + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) + "," + fmt.Sprintf("%d", block[num].Index) + ");\n"
   619  		}
   620  
   621  	} else { // reconstruct
   622  		ret += l.reconstructBlock()
   623  	}
   624  	return ret
   625  }
   626  
   627  func (l langType) reconstructBlock() string {
   628  	ret := ""
   629  	for l.hc.reconstructInstrs[l.hc.thisBlock].Stack.Len() > 0 {
   630  		action, seq, idx, ok := l.hc.reconstructInstrs[l.hc.thisBlock].Stack.Pop()
   631  		if !ok {
   632  			msg := "haxe.reconstructBlock internal error blockStack is empty "
   633  			panic(msg)
   634  		}
   635  		switch action {
   636  		case tgossa.EndWhile:
   637  			ret += fmt.Sprintf(" break; } /* EndWhile for seq %d id %d */ \n", seq, idx)
   638  		case tgossa.NotElse:
   639  			ret += fmt.Sprintf(" } else { /* NotElse for seq %d id %d */ \n", seq, idx)
   640  		case tgossa.IsElse:
   641  			ret += fmt.Sprintf(" } else { /* for seq %d id %d */ \n", seq, idx)
   642  		case tgossa.EndElseBracket:
   643  			ret += fmt.Sprintf(" } /* EndElse for seq %d id %d */ \n", seq, idx)
   644  		}
   645  		switch action {
   646  		case tgossa.NotElse, tgossa.IsElse:
   647  			if len(l.hc.elseStack) == 0 {
   648  				msg := "haxe.reconstructBlock internal error elseStack is empty "
   649  				panic(msg)
   650  				//ret += " // DEBUG HELP! " + msg + "\n"
   651  			} else {
   652  				ret += l.hc.elseStack[len(l.hc.elseStack)-1]
   653  				l.hc.elseStack = l.hc.elseStack[0 : len(l.hc.elseStack)-1] // pop the stack
   654  			}
   655  		}
   656  		switch action {
   657  		case tgossa.NotElse:
   658  			ret += " /*end NotElse*/ } \n"
   659  		}
   660  	}
   661  	if l.hc.reconstructInstrs[l.hc.thisBlock].IsWhileCandidate {
   662  		ret += "\nwhile(true){\n"
   663  	}
   664  	return ret
   665  }
   666  
   667  func (l langType) BlockEnd(block []*ssa.BasicBlock, num int, emitPhi bool) string {
   668  	ret := ""
   669  	if l.hc.reconstructInstrs == nil { // Normal unreconstructed code
   670  		if !l.hc.hadBlockReturn {
   671  			ret += "#if uselocalfunctions return null; #end\n"
   672  		}
   673  		l.hc.hadBlockReturn = true
   674  		if l.hc.fnUsesGr {
   675  			ret += "#if uselocalfunctions } #end\n"
   676  		} else {
   677  			ret += "#if uselocalfunctions }); #end\n"
   678  		}
   679  	} else { // reconstruct
   680  		//for i := 0; i < reconstructInstrs[thisBlock].EndBracketCount; i++ {
   681  		//	ret += " } /* EndBracket */"
   682  		//}
   683  		//if block[num].Succs[len(block[num].Succs)-1].Index != block[num+1].Index {
   684  		//	ret += "continue;"
   685  		//}
   686  	}
   687  	return ret
   688  }
   689  
   690  func (l langType) Jump(block int, phi int, code string) string {
   691  
   692  	ret := l.nullTempVars()
   693  
   694  	if l.hc.reconstructInstrs == nil { // Normal unreconstructed code
   695  		// use tail-calls for backward jumps where we definately know the function name
   696  		return ret + code + fmt.Sprintf("_Next=%d;", block) + "\n#if uselocalfunctions return null; #end "
   697  	}
   698  	// reconstruct
   699  	ret += fmt.Sprintf("// Jump to ID %d\n", block) + code
   700  	for _, ri := range l.hc.reconstructInstrs { // TODO pull reconstruct lookup map through
   701  		if ri.Index == block {
   702  			if ri.Seq != l.hc.thisBlock+1 {
   703  				if ri.Seq < l.hc.thisBlock {
   704  					ret += "continue;\n"
   705  				} else {
   706  					//ret += "break;\n"
   707  				}
   708  			}
   709  			break
   710  		}
   711  	}
   712  	return ret
   713  }
   714  
   715  func (l langType) If(v interface{}, trueNext, falseNext, phi int, trueCode, falseCode, errorInfo string) string {
   716  	if l.hc.reconstructInstrs == nil { // Normal unreconstructed code
   717  		ret := "if(" + l.IndirectValue(v, errorInfo) + "){\n"
   718  		ret += l.Jump(trueNext, phi, trueCode)
   719  		ret += "\n}else{\n"
   720  		ret += l.Jump(falseNext, phi, falseCode)
   721  		return ret + "\n}\n"
   722  	}
   723  	// reconstruct
   724  	ret := ""
   725  	//if reconstructInstrs[thisBlock].IsWhile {
   726  	//	ret += fmt.Sprintf(
   727  	//		" #if jsX if(_wh%d==null) _wh%d = function():Dynamic { #end /*DEBUG-isWhile*/ while(",
   728  	//		phi, phi)
   729  	//} else {
   730  	ret += "if("
   731  	//}
   732  	if l.hc.reconstructInstrs[l.hc.thisBlock].ReversePolarity {
   733  		ret += "!(" + l.IndirectValue(v, errorInfo) + ")"
   734  	} else {
   735  		ret += l.IndirectValue(v, errorInfo)
   736  	}
   737  	ret += "){\n"
   738  	if l.hc.reconstructInstrs[l.hc.thisBlock].ReversePolarity {
   739  		ret += l.Jump(falseNext, phi, falseCode)
   740  		l.hc.elseStack = append(l.hc.elseStack, l.Jump(trueNext, phi, trueCode))
   741  	} else { // as you would expect
   742  		ret += l.Jump(trueNext, phi, trueCode)
   743  		l.hc.elseStack = append(l.hc.elseStack, l.Jump(falseNext, phi, falseCode))
   744  	}
   745  	return ret
   746  }
   747  
   748  func (l langType) Phi(register string, phiEntries []int, valEntries []interface{}, defaultValue, errorInfo string) string {
   749  	panic("haxe.Phi() should never be called")
   750  	/*
   751  		ret := register + "=("
   752  		for e := range phiEntries {
   753  			val := l.IndirectValue(valEntries[e], errorInfo)
   754  			ret += fmt.Sprintf("(_Phi==%d)?%s:", phiEntries[e], val)
   755  		}
   756  		return ret + defaultValue + ");"
   757  	*/
   758  }
   759  
   760  func (l langType) LangName(p, o string) string {
   761  	return tgoutil.MakeID(p) + "_" + tgoutil.MakeID(o)
   762  }
   763  
   764  // Returns the textual version of Value, possibly emmitting an error
   765  // can't merge with indirectValue, as this is used by emit-func-setup to get register names
   766  func (l langType) Value(v interface{}, errorInfo string) string {
   767  	val, ok := v.(ssa.Value)
   768  	if !ok {
   769  		return "" // if it is not a value, an empty string will be returned
   770  	}
   771  	switch v.(type) {
   772  	case *ssa.Global:
   773  		return "Go." + l.LangName(v.(*ssa.Global).Pkg.Pkg.Path() /* was .Name()*/, v.(*ssa.Global).Name())
   774  	case *ssa.Const:
   775  		ci := v.(*ssa.Const)
   776  		_, c := l.Const(*ci, errorInfo)
   777  		return c
   778  	case *ssa.Parameter:
   779  		return "p_" + tgoutil.MakeID(v.(*ssa.Parameter).Name())
   780  	case *ssa.FreeVar:
   781  		for n := 0; n < len(l.hc.currentfn.FreeVars); n++ {
   782  			if l.hc.currentfn.FreeVars[n].Name() == v.(*ssa.FreeVar).Name() {
   783  				return fmt.Sprintf(`_bds[%d /*%s*/]`, n, v.(*ssa.FreeVar).Name())
   784  			}
   785  		}
   786  		panic(fmt.Sprintf("unable to find FreeVar %s in function %s with freeVars %v",
   787  			v.(*ssa.FreeVar).Name(), l.hc.currentfn, l.hc.currentfn.FreeVars))
   788  	case *ssa.Function:
   789  		pk, _ := l.PogoComp().FuncPathName(v.(*ssa.Function)) //fmt.Sprintf("fn%d", v.(*ssa.Function).Pos())
   790  		if v.(*ssa.Function).Signature.Recv() != nil {        // it's a method
   791  			pn := v.(*ssa.Function).Signature.Recv().Pkg().Path() // was .Name()
   792  			pk = pn + "." + v.(*ssa.Function).Signature.Recv().Name()
   793  		} else {
   794  			if v.(*ssa.Function).Pkg != nil {
   795  				if v.(*ssa.Function).Pkg.Pkg != nil {
   796  					pk = v.(*ssa.Function).Pkg.Pkg.Path() // was .Name()
   797  				}
   798  			}
   799  		}
   800  		if len(v.(*ssa.Function).Blocks) > 0 { //the function actually exists
   801  			return "new Closure(Go_" + l.LangName(pk, v.(*ssa.Function).Name()) + ".call,null)" //TODO will change for go instr
   802  		}
   803  		// function has no implementation
   804  		// TODO maybe put a list of over-loaded functions here and only error if not found
   805  		// NOTE the reflect package comes through this path TODO fix!
   806  		l.PogoComp().LogWarning(errorInfo, "Haxe", fmt.Errorf("haxe.Value(): *ssa.Function has no implementation: %s", v.(*ssa.Function).Name()))
   807  		return "new Closure(null,null)" // Should fail at runtime if it is used...
   808  	case *ssa.UnOp:
   809  		switch v.(*ssa.UnOp).Op {
   810  		case token.ARROW, token.MUL:
   811  			return l.PogoComp().RegisterName(val)
   812  		}
   813  		return l.inlineRegisterName(v.(*ssa.UnOp))
   814  	case *ssa.BinOp:
   815  		return l.inlineRegisterName(v.(*ssa.BinOp))
   816  	case *ssa.Convert:
   817  		return l.inlineRegisterName(v.(*ssa.Convert))
   818  	default:
   819  		return l.PogoComp().RegisterName(val)
   820  	}
   821  }
   822  func (l langType) FieldAddr(register string, v interface{}, errorInfo string) string {
   823  	if register != "" {
   824  		ptr := l.IndirectValue(v.(*ssa.FieldAddr).X, errorInfo)
   825  		if l.PogoComp().DebugFlag {
   826  			ptr = "Pointer.check(" + ptr + ")"
   827  		}
   828  		fld := v.(*ssa.FieldAddr).X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct).Field(v.(*ssa.FieldAddr).Field)
   829  		off := fieldOffset(v.(*ssa.FieldAddr).X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Struct), v.(*ssa.FieldAddr).Field)
   830  		if off == 0 {
   831  			if l.is1usePtr(v) {
   832  				return l.set1usePtr(v.(ssa.Value), oneUsePtr{obj: ptr + ".obj", off: ptr + ".off"}) +
   833  					"// virtual oneUsePtr " + register + "=" + l.hc.map1usePtr[v.(ssa.Value)].obj + ":" + l.hc.map1usePtr[v.(ssa.Value)].off
   834  			}
   835  			return fmt.Sprintf(`%s=%s; // .fieldAddr( /*%d : %s */ %d )`, register,
   836  				ptr, v.(*ssa.FieldAddr).Field, fixKeyWds(fld.Name()), off)
   837  		}
   838  		if l.is1usePtr(v) {
   839  			return l.set1usePtr(v.(ssa.Value), oneUsePtr{obj: ptr + ".obj", off: fmt.Sprintf("%d", off) + "+" + ptr + ".off"}) +
   840  				"// virtual oneUsePtr " + register + "=" + l.hc.map1usePtr[v.(ssa.Value)].obj + ":" + l.hc.map1usePtr[v.(ssa.Value)].off
   841  		}
   842  		return l.deDupAssign(register, fmt.Sprintf(`%s.fieldAddr( /*%d : %s */ %d );`,
   843  			ptr, v.(*ssa.FieldAddr).Field, fixKeyWds(fld.Name()), off))
   844  	}
   845  	return ""
   846  }
   847  
   848  func wrapForceToUInt(v string, k types.BasicKind) string {
   849  	switch k {
   850  	case types.Uintptr:
   851  		return "Force.toUint32(Force.toInt(" + v + "))"
   852  	case types.Int64, types.Uint64:
   853  		return "Force.toUint32(GOint64.toInt(" + v + "))"
   854  	case types.Float32, types.Float64, types.UntypedFloat:
   855  		return "Force.toUint32(" + v + "<=0?Math.ceil(" + v + "):Math.floor(" + v + "))"
   856  	}
   857  	return v
   858  }
   859  
   860  func (l langType) IndexAddr(register string, v interface{}, errorInfo string) string {
   861  	if register == "" {
   862  		return "" // we can't make an address if there is nowhere to put it...
   863  	}
   864  	idxString := wrapForceToUInt(l.IndirectValue(v.(*ssa.IndexAddr).Index, errorInfo),
   865  		v.(*ssa.IndexAddr).Index.(ssa.Value).Type().Underlying().(*types.Basic).Kind())
   866  	switch v.(*ssa.IndexAddr).X.Type().Underlying().(type) {
   867  	case *types.Pointer:
   868  		ptr := l.IndirectValue(v.(*ssa.IndexAddr).X, errorInfo)
   869  		if l.PogoComp().DebugFlag {
   870  			ptr = "Pointer.check(" + ptr + ")"
   871  		}
   872  		ele := v.(*ssa.IndexAddr).X.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Elem().Underlying()
   873  		if idxString == "0" {
   874  			if l.is1usePtr(v) {
   875  				return l.set1usePtr(v.(ssa.Value), oneUsePtr{obj: ptr + ".obj", off: ptr + ".off"}) +
   876  					"// virtual oneUsePtr " + register + "=" + l.hc.map1usePtr[v.(ssa.Value)].obj + ":" + l.hc.map1usePtr[v.(ssa.Value)].off
   877  			}
   878  			return fmt.Sprintf(`%s=%s; // .addr(0)`, register, ptr)
   879  		}
   880  		idxString += arrayOffsetCalc(ele)
   881  		if l.is1usePtr(v) {
   882  			return l.set1usePtr(v.(ssa.Value), oneUsePtr{obj: ptr + ".obj", off: "(" + idxString + ")+" + ptr + ".off"}) +
   883  				"// virtual oneUsePtr " + register + "=" + l.hc.map1usePtr[v.(ssa.Value)].obj + ":" + l.hc.map1usePtr[v.(ssa.Value)].off
   884  		}
   885  		return l.deDupAssign(register, fmt.Sprintf(`%s.addr(%s);`, ptr, idxString))
   886  	case *types.Slice:
   887  		x := l.IndirectValue(v.(*ssa.IndexAddr).X, errorInfo)
   888  		if l.is1usePtr(v) {
   889  			return l.set1usePtr(v.(ssa.Value), oneUsePtr{obj: x + ".baseArray.obj", off: x + ".itemOff(" + idxString + ")+" + x + ".baseArray.off"}) +
   890  				"// virtual oneUsePtr " + register + "=" + l.hc.map1usePtr[v.(ssa.Value)].obj + ":" + l.hc.map1usePtr[v.(ssa.Value)].off
   891  		}
   892  		code := fmt.Sprintf(`%s.itemAddr(%s);`, x, idxString)
   893  		return l.deDupAssign(register, code)
   894  	default:
   895  		l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.IndirectValue():IndexAddr unknown operand type"))
   896  		return ""
   897  	}
   898  }
   899  
   900  func (l langType) IndirectValue(v interface{}, errorInfo string) string {
   901  	return l.Value(v, errorInfo)
   902  }
   903  
   904  func (l langType) intTypeCoersion(t types.Type, v, errorInfo string) string {
   905  	switch t.Underlying().(type) {
   906  	case *types.Basic:
   907  		switch t.Underlying().(*types.Basic).Kind() {
   908  		case types.Int8:
   909  			return "Force.toInt8(" + v + ")"
   910  		case types.Int16:
   911  			return "Force.toInt16(" + v + ")"
   912  		case types.Int32, types.Int: // NOTE type int is always int32
   913  			return "Force.toInt32(" + v + ")"
   914  		case types.Int64:
   915  			return "Force.toInt64(" + v + ")"
   916  		case types.Uint8:
   917  			return "Force.toUint8(" + v + ")"
   918  		case types.Uint16:
   919  			return "Force.toUint16(" + v + ")"
   920  		case types.Uint32, types.Uint, types.Uintptr: // NOTE type uint is always uint32
   921  			return "Force.toUint32(" + v + ")"
   922  		case types.Uint64:
   923  			return "Force.toUint64(" + v + ")"
   924  		case types.UntypedInt, types.UntypedRune:
   925  			l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.intTypeCoersion(): unhandled types.UntypedInt or types.UntypedRune"))
   926  			return ""
   927  		case types.Float32:
   928  			return "Force.toFloat32(" + v + ")"
   929  		case types.Float64, types.Bool:
   930  			return v
   931  		default:
   932  			l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.intTypeCoersion():unhandled basic kind %v",
   933  				t.Underlying().(*types.Basic).Kind()))
   934  			return v
   935  		}
   936  	default:
   937  		l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.intTypeCoersion():unhandled type %T", t.Underlying()))
   938  		return v
   939  	}
   940  }
   941  
   942  func (l langType) Store(v1, v2 interface{}, errorInfo string) string {
   943  	ptr := l.IndirectValue(v1, errorInfo)
   944  	if l.PogoComp().DebugFlag {
   945  		ptr = "Pointer.check(" + ptr + ")"
   946  	}
   947  	if l.is1usePtr(v1) {
   948  		oup, found := l.hc.map1usePtr[v1.(ssa.Value)]
   949  		if !found {
   950  			panic("haxe.Store can't find oneUsePtr " + v1.(ssa.Value).Name() + "=" + v1.(ssa.Value).String())
   951  		}
   952  		return oup.obj + ".set" + loadStoreSuffix(v2.(ssa.Value).Type().Underlying(), true) + oup.off + "," +
   953  			l.IndirectValue(v2, errorInfo) + ");" +
   954  			" /* " + v2.(ssa.Value).Type().Underlying().String() + " */ "
   955  	}
   956  	return ptr + ".store" + loadStoreSuffix(v2.(ssa.Value).Type().Underlying(), true) +
   957  		l.IndirectValue(v2, errorInfo) + ");" +
   958  		" /* " + v2.(ssa.Value).Type().Underlying().String() + " */ "
   959  }
   960  
   961  func (l langType) Send(v1, v2 interface{}, errorInfo string) string {
   962  	ret := fmt.Sprintf("_Next=%d;\n", l.hc.nextReturnAddress)
   963  	ret += "return this;\n"
   964  	if l.hc.fnUsesGr {
   965  		ret += "#if uselocalfunctions } #end\n"
   966  	} else {
   967  		ret += "#if uselocalfunctions }); #end\n"
   968  	}
   969  	ret += l.emitUnseenPseudoBlocks()
   970  	ret += fmt.Sprintf("#if !uselocalfunctions case %d: #end\n", l.hc.nextReturnAddress)
   971  	if l.hc.fnUsesGr {
   972  		fn := fmt.Sprintf(l.hc.currentfnName+"__%d", -l.hc.nextReturnAddress)
   973  		l.hc.localFunctionMap[l.hc.nextReturnAddress] = fn
   974  		ret += "#if uselocalfunctions function " + fn + "():" + l.hc.currentfnName + " { #end\n"
   975  	} else {
   976  		ret += fmt.Sprintf("#if uselocalfunctions fnMap.set(%d,function "+l.hc.currentfnName+"__%d():"+l.hc.currentfnName+" { #end\n",
   977  			l.hc.nextReturnAddress, -l.hc.nextReturnAddress)
   978  	}
   979  	//ret += fmt.Sprintf("#if uselocalfunctions function _Block_%d(){ #end\n", -nextReturnAddress)
   980  	if l.PogoComp().DebugFlag {
   981  		ret += "this.setLatest(" + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) + "," + fmt.Sprintf("%d", l.hc.nextReturnAddress) + ");\n"
   982  	}
   983  	ret += l.emitTrace(fmt.Sprintf("Block:%d", l.hc.nextReturnAddress))
   984  	// TODO panic if the chanel is null
   985  	ret += "if(!Channel.hasSpace(" + l.IndirectValue(v1, errorInfo) + "))return this;\n" // go round the loop again and wait if not OK
   986  	ret += l.IndirectValue(v1, errorInfo) + ".send(" + l.IndirectValue(v2, errorInfo) + ");"
   987  	l.hc.nextReturnAddress-- // decrement to set new return address for next code generation
   988  	l.hc.hadBlockReturn = false
   989  	return ret
   990  }
   991  
   992  func (l langType) emitReturnHere() string {
   993  	ret := ""
   994  	ret += fmt.Sprintf("_Next=%d;\n", l.hc.nextReturnAddress)
   995  	ret += "return this;\n"
   996  	if l.hc.fnUsesGr {
   997  		ret += "#if uselocalfunctions } #end\n"
   998  	} else {
   999  		ret += "#if uselocalfunctions }); #end\n"
  1000  	}
  1001  	ret += l.emitUnseenPseudoBlocks()
  1002  	ret += fmt.Sprintf("#if !uselocalfunctions case %d: #end\n", l.hc.nextReturnAddress)
  1003  	if l.hc.fnUsesGr {
  1004  		fn := fmt.Sprintf(l.hc.currentfnName+"__%d", -l.hc.nextReturnAddress)
  1005  		l.hc.localFunctionMap[l.hc.nextReturnAddress] = fn
  1006  		ret += "#if uselocalfunctions function " + fn + "():" + l.hc.currentfnName + " { #end\n"
  1007  	} else {
  1008  		ret += fmt.Sprintf("#if uselocalfunctions fnMap.set(%d,function "+l.hc.currentfnName+"__%d():"+l.hc.currentfnName+" { #end\n",
  1009  			l.hc.nextReturnAddress, -l.hc.nextReturnAddress)
  1010  	}
  1011  	//ret += fmt.Sprintf("#if uselocalfunctions function _Block_%d(){ #end\n", -nextReturnAddress)
  1012  	if l.PogoComp().DebugFlag {
  1013  		ret += "this.setLatest(" + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) + "," + fmt.Sprintf("%d", l.hc.nextReturnAddress) + ");\n"
  1014  	}
  1015  	ret += l.emitTrace(fmt.Sprintf("Block:%d", l.hc.nextReturnAddress))
  1016  	l.hc.hadBlockReturn = false
  1017  	return ret
  1018  }
  1019  
  1020  func (l langType) emitUnseenPseudoBlocks() string {
  1021  	ret := ""
  1022  	if l.hc.nextReturnAddress == l.hc.pseudoBlockNext {
  1023  		l.hc.pseudoBlockNext = l.hc.nextReturnAddress - 1
  1024  		return ret
  1025  	}
  1026  	// we've missed some
  1027  	for l.hc.pseudoBlockNext > l.hc.nextReturnAddress {
  1028  		if l.hc.fnUsesGr {
  1029  			fn := fmt.Sprintf(l.hc.currentfnName+"__%d", -l.hc.pseudoBlockNext)
  1030  			l.hc.localFunctionMap[l.hc.pseudoBlockNext] = fn
  1031  			ret += "#if uselocalfunctions function " + fn + "():" + l.hc.currentfnName + " {return null;}  #end\n"
  1032  		} else {
  1033  			ret += fmt.Sprintf("#if uselocalfunctions fnMap.set(%d,function "+l.hc.currentfnName+"_dummy_%d():"+l.hc.currentfnName+" {return null;}); #end\n",
  1034  				l.hc.pseudoBlockNext, -l.hc.pseudoBlockNext)
  1035  		}
  1036  		//ret += fmt.Sprintf("#if uselocalfunctions function _Block_%d():Dynamic{return null;} #end\n", -pseudoBlockNext)
  1037  		l.hc.pseudoBlockNext--
  1038  	}
  1039  	l.hc.pseudoBlockNext = l.hc.nextReturnAddress - 1
  1040  	return ret
  1041  }
  1042  
  1043  // if isSelect is false, v is the UnOp value, otherwise the ssa.Select instruction
  1044  /* SSA DOCUMENTAION EXTRACT
  1045  The Select instruction tests whether (or blocks until) one or more of the specified sent or received states is entered.
  1046  
  1047  Let n be the number of States for which Dir==RECV and T_i (0<=i<n) be the element type of each such state's Chan.
  1048  Select returns an n+2-tuple
  1049  
  1050  (index int, recvOk bool, r_0 T_0, ... r_n-1 T_n-1)
  1051  The tuple's components, described below, must be accessed via the Extract instruction.
  1052  
  1053  If Blocking, select waits until exactly one state holds, i.e. a channel becomes ready for the designated operation
  1054  of sending or receiving; select chooses one among the ready states pseudorandomly, performs the send or receive operation,
  1055  and sets 'index' to the index of the chosen channel.
  1056  
  1057  If !Blocking, select doesn't block if no states hold; instead it returns immediately with index equal to -1.
  1058  
  1059  If the chosen channel was used for a receive, the r_i component is set to the received value,
  1060  where i is the index of that state among all n receive states; otherwise r_i has the zero value of type T_i.
  1061  Note that the the receive index i is not the same as the state index index.
  1062  
  1063  The second component of the triple, recvOk, is a boolean whose value is true iff
  1064  the selected operation was a receive and the receive successfully yielded a value.
  1065  */
  1066  func (l langType) Select(isSelect bool, register string, v interface{}, CommaOK bool, errorInfo string) string {
  1067  	ret := l.emitReturnHere() // even if we are in a non-blocking select, we need to give the other goroutines a chance!
  1068  	if isSelect {
  1069  		sel := v.(*ssa.Select)
  1070  		if register == "" {
  1071  			l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("select statement has no register"))
  1072  			return ""
  1073  		}
  1074  		ret += register + "=" + l.LangType(v.(ssa.Value).Type(), true, errorInfo) + ";\n" //initialize
  1075  		ret += register + ".r0= -1;\n"                                                    // the returned index if nothing is found
  1076  
  1077  		if len(sel.States) > 0 { // only do the logic if there are states to choose between
  1078  			// TODO a blocking select with no states could be further optimised to stop the goroutine
  1079  
  1080  			// Spec requires a pseudo-random order to which item is processed
  1081  			ret += fmt.Sprintf("{ var _states:Array<Bool> = new Array(); var _rnd=Std.random(%d);\n", len(sel.States))
  1082  			for s := range sel.States {
  1083  				switch sel.States[s].Dir {
  1084  				case types.SendOnly:
  1085  					ch := l.IndirectValue(sel.States[s].Chan, errorInfo)
  1086  					ret += fmt.Sprintf("_states[%d]=Channel.hasSpace(%s);\n", s, ch)
  1087  				case types.RecvOnly:
  1088  					ch := l.IndirectValue(sel.States[s].Chan, errorInfo)
  1089  					ret += fmt.Sprintf("_states[%d]=Channel.hasContents(%s);\n", s, ch)
  1090  				default:
  1091  					l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("select statement has invalid ChanDir"))
  1092  					return ""
  1093  				}
  1094  			}
  1095  			ret += fmt.Sprintf("for(_s in 0...%d) {var _i=(_s+_rnd)%s%d; if(_states[_i]) {%s.r0=_i; break;};}\n",
  1096  				len(sel.States), "%", len(sel.States), register)
  1097  			ret += fmt.Sprintf("switch(%s.r0){", register)
  1098  			rxIdx := 0
  1099  			for s := range sel.States {
  1100  				ret += fmt.Sprintf("case %d:\n", s)
  1101  				switch sel.States[s].Dir {
  1102  				case types.SendOnly:
  1103  					ch := l.IndirectValue(sel.States[s].Chan, errorInfo)
  1104  					snd := l.IndirectValue(sel.States[s].Send, errorInfo)
  1105  					ret += fmt.Sprintf("%s.send(%s);\n", ch, snd)
  1106  				case types.RecvOnly:
  1107  					ch := l.IndirectValue(sel.States[s].Chan, errorInfo)
  1108  					ret += fmt.Sprintf("{ var _v=%s.receive(%s); ", ch,
  1109  						l.LangType(sel.States[s].Chan.(ssa.Value).Type().Underlying().(*types.Chan).Elem().Underlying(), true, errorInfo))
  1110  					ret += fmt.Sprintf("%s.r%d= _v.r0; ", register, 2+rxIdx)
  1111  					rxIdx++
  1112  					ret += register + ".r1= _v.r1; }\n"
  1113  				default:
  1114  					l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("select statement has invalid ChanDir"))
  1115  					return ""
  1116  				}
  1117  			}
  1118  			ret += "};}\n" // end switch; _states, _rnd scope
  1119  
  1120  		} // end only if len(sel.States)>0
  1121  
  1122  		if sel.Blocking {
  1123  			ret += "if(" + register + ".r0 == -1) return this;\n"
  1124  		}
  1125  
  1126  	} else {
  1127  		ret += "if(Channel.hasNoContents(" + l.IndirectValue(v, errorInfo) + "))return this;\n" // go round the loop again and wait if not OK
  1128  		if register != "" {
  1129  			ret += register + "="
  1130  		}
  1131  		ret += l.IndirectValue(v, errorInfo) + ".receive("
  1132  		ret += l.LangType(v.(ssa.Value).Type().Underlying().(*types.Chan).Elem().Underlying(), true, errorInfo) + ")" // put correct result into register
  1133  		if !CommaOK {
  1134  			ret += ".r0"
  1135  		}
  1136  		ret += ";"
  1137  	}
  1138  	l.hc.nextReturnAddress-- // decrement to set new return address for next code generation
  1139  	return ret
  1140  }
  1141  func (l langType) RegEq(r string) string {
  1142  	return r + "="
  1143  }
  1144  
  1145  func (l langType) Ret(values []*ssa.Value, errorInfo string) string {
  1146  	l.hc.hadReturn = true
  1147  	_BlockEnd := "this._incomplete=false;\nScheduler.pop(this._goroutine);\n"
  1148  	l.hc.hadBlockReturn = true
  1149  	//_BlockEnd += nullTempVars()
  1150  	_BlockEnd += "nullOnExit();\nreturn this;\n"
  1151  	switch len(values) {
  1152  	case 0:
  1153  		return l.emitTrace("Ret0") + _BlockEnd
  1154  	case 1:
  1155  		return l.emitTrace("Ret1") + "_res= " + l.IndirectValue(*values[0], errorInfo) + ";\n" + _BlockEnd
  1156  	default:
  1157  		ret := l.emitTrace("RetN") + "_res= {"
  1158  		for r := range values {
  1159  			if r != 0 {
  1160  				ret += ","
  1161  			}
  1162  			if l.LangType((*values[r]).Type().Underlying(), false, errorInfo) == "GOint64" {
  1163  				ret += fmt.Sprintf("r%d:", r) + l.IndirectValue(*values[r], errorInfo)
  1164  			} else {
  1165  				ret += fmt.Sprintf("r%d:", r) + l.IndirectValue(*values[r], errorInfo)
  1166  			}
  1167  		}
  1168  		return ret + "};\n" + _BlockEnd
  1169  	}
  1170  }
  1171  
  1172  func (l langType) Panic(v1 interface{}, errorInfo string, usesGr bool) string {
  1173  	ret := l.doCall("", nil, "Scheduler.panic(this._goroutine,"+l.IndirectValue(v1, errorInfo)+");\n", usesGr)
  1174  	ret += l.Ret(nil, errorInfo) // just in case we return to this point without _recoverNext being set & used
  1175  	return ret
  1176  }
  1177  
  1178  func (l langType) getPackagePath(cc *ssa.CallCommon) string {
  1179  	// This code to find the package name
  1180  	pn := "UNKNOWN" // package name
  1181  	if cc.StaticCallee() != nil {
  1182  		pn, _ = l.PogoComp().FuncPathName(cc.StaticCallee()) // was =fmt.Sprintf("fn%d", cc.StaticCallee().Pos())
  1183  	}
  1184  	if cc != nil {
  1185  		if cc.Method != nil {
  1186  			if cc.Method.Pkg() != nil {
  1187  				pn = cc.Method.Pkg().Path() // was .Name()
  1188  			}
  1189  		} else {
  1190  			if cc.StaticCallee() != nil {
  1191  				if cc.StaticCallee().Package() != nil {
  1192  					pn = cc.StaticCallee().Package().String()
  1193  				} else {
  1194  					if cc.StaticCallee().Object() != nil {
  1195  						if cc.StaticCallee().Object().Pkg() != nil {
  1196  							pn = cc.StaticCallee().Object().Pkg().Path() // was .Name()
  1197  						}
  1198  					}
  1199  				}
  1200  			}
  1201  		}
  1202  	}
  1203  	return pn
  1204  }
  1205  
  1206  func (l langType) Call(register string, cc ssa.CallCommon, args []ssa.Value, isBuiltin, isGo, isDefer, usesGr bool, fnToCall, errorInfo string) string {
  1207  	isHaxeAPI := false
  1208  	hashIf := ""  // #if  - only if required
  1209  	hashEnd := "" // #end - ditto
  1210  	ret := ""
  1211  
  1212  	//special case of: defer close(x)
  1213  	if isDefer && isBuiltin && fnToCall == "close" {
  1214  		fnToCall = "(new Closure(Go_haxegoruntime_defer_close.call,null))"
  1215  		isBuiltin = false
  1216  	}
  1217  
  1218  	if isBuiltin {
  1219  		if register != "" {
  1220  			register += "="
  1221  		}
  1222  		switch fnToCall { // TODO handle other built-in functions?
  1223  		case "len", "cap":
  1224  			switch args[0].Type().Underlying().(type) {
  1225  			case *types.Chan, *types.Slice:
  1226  				if fnToCall == "len" {
  1227  					return register + "({var _v=" + l.IndirectValue(args[0], errorInfo) + ";_v==null?0:(_v.len());});"
  1228  				}
  1229  				// cap
  1230  				return register + "({var _v=" + l.IndirectValue(args[0], errorInfo) + ";_v==null?0:(_v.cap());});"
  1231  			case *types.Array: // assume len (same as cap anyway)
  1232  				return register + l.IndirectValue(args[0], errorInfo /*, false*/) + ".length;"
  1233  			case *types.Map: // assume len(map)
  1234  				return register + "({var _v=" + l.IndirectValue(args[0], errorInfo) + ";_v==null?0:_v.len();});"
  1235  			case *types.Basic: // assume string as anything else would have produced an error previously
  1236  				return register + "Force.toUTF8length(this._goroutine," + l.IndirectValue(args[0], errorInfo /*, false*/) + ");"
  1237  			default: // TODO handle other types?
  1238  				// TODO error on string?
  1239  				l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Call() - unhandled len/cap type: %s",
  1240  					reflect.TypeOf(args[0].Type().Underlying())))
  1241  				return register + `null;`
  1242  			}
  1243  		case "print", "println":
  1244  			ret += "Console." + fnToCall + "(["
  1245  			/* DEBUG if we want to know where all the prints happen
  1246  			ret	+= fmt.Sprintf("Go.CPos(%d)", l.PogoComp().LatestValidPosHash)
  1247  			if len(args) > 0 {                  // if there are more arguments to pass, add a comma
  1248  				ret += ","
  1249  			}
  1250  			*/
  1251  		case "delete":
  1252  			return register + l.IndirectValue(args[0], errorInfo) + ".remove(" +
  1253  				l.serializeKey(l.IndirectValue(args[1], errorInfo),
  1254  					l.LangType(args[1].Type().Underlying(), false, errorInfo)) + ");"
  1255  		case "append":
  1256  			return register + l.append(args, errorInfo) + ";"
  1257  		case "copy": //TODO rework & test
  1258  			return l.copy(register, args, errorInfo) + ";"
  1259  		case "close":
  1260  			return register + "" + l.IndirectValue(args[0], errorInfo) + ".close();"
  1261  		case "recover":
  1262  			return register + "" + "Scheduler.recover(this._goroutine);"
  1263  		case "real":
  1264  			return register + "" + l.IndirectValue(args[0], errorInfo) + ".real;"
  1265  		case "imag":
  1266  			return register + "" + l.IndirectValue(args[0], errorInfo) + ".imag;"
  1267  		case "complex":
  1268  			return register + "new Complex(" + l.IndirectValue(args[0], errorInfo) + "," + l.IndirectValue(args[1], errorInfo) + ");"
  1269  		case "ssa:wrapnilchk":
  1270  			return register + "Scheduler.wrapnilchk(" + l.IndirectValue(args[0], errorInfo) + ");"
  1271  		default:
  1272  			l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Call() - Unhandled builtin function: %s", fnToCall))
  1273  			ret = "MISSING_BUILTIN("
  1274  		}
  1275  	} else {
  1276  		switch fnToCall {
  1277  
  1278  		//
  1279  		// Go library complex function rewriting
  1280  		//
  1281  		case "runtime_BBreakpoint":
  1282  			l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1283  			return "this.breakpoint();"
  1284  		case "runtime_UUnzipTTestFFSS":
  1285  			l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1286  			if l.hc.langEntry.TestFS != "" {
  1287  				return `Go_syscall_UUnzipFFSS.callFromRT(0,"` + l.hc.langEntry.TestFS + `");`
  1288  			}
  1289  			return ""
  1290  		//case "math_Inf":
  1291  		//	nextReturnAddress-- //decrement to set new return address for next call generation
  1292  		//	return register + "=(" + l.IndirectValue(args[0], errorInfo) + ">=0?Math.POSITIVE_INFINITY:Math.NEGATIVE_INFINITY);"
  1293  
  1294  		default:
  1295  			//
  1296  			// haxe interface pseudo-function re-writing
  1297  			//
  1298  			if strings.HasPrefix(fnToCall, pseudoFnPrefix) {
  1299  				l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1300  				if register != "" {
  1301  					register += "="
  1302  				}
  1303  				return register + l.hxPseudoFuncs(fnToCall, args, errorInfo)
  1304  			}
  1305  
  1306  			pn := l.getPackagePath(&cc)
  1307  			pnSplit := strings.Split(pn, "/")
  1308  			pn = pnSplit[len(pnSplit)-1]
  1309  			//fmt.Println("DEBUG package name", pn)
  1310  
  1311  			targetFunc := "Go_" + fnToCall + ".call"
  1312  
  1313  			if strings.HasPrefix(pn, "_") && // in a package that starts with "_"
  1314  				!strings.HasPrefix(fnToCall, "_t") { // and not a temp var TODO this may not always be accurate
  1315  				//fmt.Println("start _HAXELIB SPECIAL PROCESSING", pn, fnToCall)
  1316  
  1317  				// remove double uppercase characters in name
  1318  				ftc := ""
  1319  				skip := false
  1320  				for _, c := range fnToCall {
  1321  					if skip {
  1322  						skip = false
  1323  					} else {
  1324  						ftc += string(c)
  1325  						if unicode.IsUpper(c) {
  1326  							skip = true
  1327  						}
  1328  					}
  1329  				}
  1330  				fnToCall = ftc // fnToCall does not now contain doubled uppercase chars
  1331  
  1332  				l.hc.nextReturnAddress--                // decrement to set new return address for next call generation
  1333  				isBuiltin = true                        // pretend we are in a builtin function to avoid passing 1st param as bindings
  1334  				isHaxeAPI = true                        // we are calling a Haxe native function
  1335  				bits := strings.Split(fnToCall, "_47_") // split the parts of the string separated by /
  1336  				endbit := bits[len(bits)-1]
  1337  				foundDot := false
  1338  				if strings.Contains(endbit, "_dot_") { // it's a dot
  1339  					ss := strings.Split(endbit, "_dot_")
  1340  					endbit = "_ignore_" + ss[len(ss)-1]
  1341  					foundDot = true
  1342  				}
  1343  				bits = strings.Split(endbit, "_") // split RHS after / into parts separated by _
  1344  				bits = bits[2:]                   // discard the leading _ and package name
  1345  				switch bits[0][0:1] {             // the letter that gives the Haxe language in which to use the api
  1346  				case "X": // cross platform, so noOp
  1347  				case "P":
  1348  					hashIf = " #if cpp "
  1349  					hashEnd = " #end "
  1350  				case "C":
  1351  					hashIf = " #if cs "
  1352  					hashEnd = " #end "
  1353  				case "F":
  1354  					hashIf = " #if flash "
  1355  					hashEnd = " #end "
  1356  				case "J":
  1357  					hashIf = " #if java "
  1358  					hashEnd = " #end "
  1359  				case "S":
  1360  					hashIf = " #if js "
  1361  					hashEnd = " #end "
  1362  				case "N":
  1363  					hashIf = " #if neko "
  1364  					hashEnd = " #end "
  1365  				case "H":
  1366  					hashIf = " #if php "
  1367  					hashEnd = " #end "
  1368  				case "i":
  1369  					if bits[0] == "init" {
  1370  						return "" // no calls to _haxelib init functions
  1371  					}
  1372  					fallthrough
  1373  				default:
  1374  					l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("call to function %s unknown Haxe API first letter %v of %v",
  1375  						fnToCall, bits[0][0:1], bits))
  1376  				}
  1377  				bits[0] = bits[0][1:] // discard the magic letter from the front of the function name
  1378  
  1379  				if foundDot { // it's a Haxe method
  1380  					switch bits[len(bits)-1] {
  1381  					case "g": // get
  1382  						if register != "" {
  1383  							ret := l.IndirectValue(args[0], errorInfo) + "." + bits[len(bits)-2][1:]
  1384  							r := cc.Signature().Results()
  1385  							if r.Len() == 1 {
  1386  								switch r.At(0).Type().Underlying().(type) {
  1387  								case *types.Interface:
  1388  									ret = "Interface.fromDynamic(" + ret + ")"
  1389  								case *types.Basic:
  1390  									if r.At(0).Type().Underlying().(*types.Basic).Kind() == types.String {
  1391  										ret = "Force.fromHaxeString(" + ret + ")"
  1392  									}
  1393  								}
  1394  							}
  1395  							return hashIf + register + "=" + ret + ";" + hashEnd
  1396  						}
  1397  						return ""
  1398  					case "s": // set
  1399  						interfaceSuffix := ""
  1400  						interfacePrefix := ""
  1401  						switch args[1].Type().Underlying().(type) {
  1402  						case *types.Basic:
  1403  							if args[1].Type().Underlying().(*types.Basic).Kind() == types.String {
  1404  								interfacePrefix = "Force.toHaxeString("
  1405  								interfaceSuffix = ")"
  1406  							}
  1407  						case *types.Interface:
  1408  							interfacePrefix = "Force.toHaxeParam("
  1409  							interfaceSuffix = ")"
  1410  						}
  1411  						return hashIf + "" + l.IndirectValue(args[0], errorInfo) +
  1412  							"." + bits[len(bits)-2][1:] +
  1413  							"=" + interfacePrefix + l.IndirectValue(args[1], errorInfo) + interfaceSuffix + ";" + hashEnd
  1414  					default:
  1415  						bits = bits[:len(bits)-1]                                                      //  trim off the "_digit" suffix
  1416  						targetFunc = l.IndirectValue(args[0], errorInfo) + "." + bits[len(bits)-1][1:] //remove leading capital letter
  1417  
  1418  						args = args[1:]
  1419  					}
  1420  				} else {
  1421  					switch bits[len(bits)-1] {
  1422  					case "g": // special processing to get a class static variable or enum
  1423  						if register != "" {
  1424  							ret := strings.Join(strings.Split(strings.Join(bits[:len(bits)-1], "."), "..."), "_")
  1425  							r := cc.Signature().Results()
  1426  							if r.Len() == 1 {
  1427  								switch r.At(0).Type().Underlying().(type) {
  1428  								case *types.Interface:
  1429  									ret = "Interface.fromDynamic(" + ret + ")"
  1430  								case *types.Basic:
  1431  									if r.At(0).Type().Underlying().(*types.Basic).Kind() == types.String {
  1432  										ret = "Force.fromHaxeString(" + ret + ")"
  1433  									}
  1434  								}
  1435  							}
  1436  							return hashIf + register + "=" + ret + ";" + hashEnd
  1437  						}
  1438  						return ""
  1439  					case "s": // special processing to set a class static variable
  1440  						interfaceSuffix := ""
  1441  						interfacePrefix := ""
  1442  						switch args[0].Type().Underlying().(type) {
  1443  						case *types.Basic:
  1444  							if args[0].Type().Underlying().(*types.Basic).Kind() == types.String {
  1445  								interfacePrefix = "Force.toHaxeString("
  1446  								interfaceSuffix = ")"
  1447  							}
  1448  						case *types.Interface:
  1449  							interfacePrefix = "Force.toHaxeParam("
  1450  							interfaceSuffix = ")"
  1451  						}
  1452  						return hashIf + strings.Join(strings.Split(strings.Join(bits[:len(bits)-1], "."), "..."), "_") +
  1453  							"=" + interfacePrefix + l.IndirectValue(args[0], errorInfo) + interfaceSuffix + ";" + hashEnd
  1454  					default:
  1455  						bits = bits[:len(bits)-1] //  trim off the "_digit" suffix
  1456  						if bits[len(bits)-1] == "new" {
  1457  							targetFunc = "new " + strings.Join(bits[:len(bits)-1], ".") // put it back into the Haxe format for names
  1458  						} else {
  1459  							targetFunc = strings.Join(bits, ".") // put it back into the Haxe format for names
  1460  						}
  1461  					}
  1462  				}
  1463  				targetFunc = strings.Join(strings.Split(targetFunc, "..."), "_")
  1464  				// end _HAXELIB SPECIAL PROCESSING
  1465  			} else {
  1466  				olv, ok := fnToVarOverloadMap[fnToCall]
  1467  				if ok { // replace the function call with a variable
  1468  					l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1469  					if register == "" {
  1470  						return ""
  1471  					}
  1472  					return register + "=" + olv + ";"
  1473  				}
  1474  				olf, ok := fnOverloadMap[fnToCall]
  1475  				if ok { // replace one go function with another
  1476  					targetFunc = olf
  1477  				} else {
  1478  					olf, ok := builtinOverloadMap[fnToCall]
  1479  					if ok { // replace a go function with a haxe one
  1480  						targetFunc = olf
  1481  						l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1482  						isBuiltin = true         // pretend we are in a builtin function to avoid passing 1st param as bindings or waiting for completion
  1483  					} else {
  1484  						// TODO at this point the package-level overloading could occur, but I cannot make it reliable, so code removed
  1485  					}
  1486  				}
  1487  			}
  1488  
  1489  			switch cc.Value.(type) {
  1490  			case *ssa.Function: //simple case
  1491  				ret += targetFunc + "("
  1492  			case *ssa.MakeClosure: // it is a closure, but with a static callee
  1493  				ret += targetFunc + "("
  1494  			default: // closure with a dynamic callee
  1495  				ret += "Closure.callFn(" + fnToCall + ",[" // the callee is in a local variable
  1496  			}
  1497  		}
  1498  	}
  1499  	if !isBuiltin {
  1500  		if isGo {
  1501  			ret += "Scheduler.makeGoroutine(),"
  1502  		} else {
  1503  			ret += "this._goroutine,"
  1504  		}
  1505  	}
  1506  	switch cc.Value.(type) {
  1507  	case *ssa.Function: //simple case
  1508  		if !isBuiltin { // don't pass bindings to built-in functions
  1509  			ret += "[]" // goroutine + bindings
  1510  		}
  1511  	case *ssa.MakeClosure: // it is a closure, but with a static callee
  1512  		ret += "({var _v=" + l.IndirectValue(cc.Value, errorInfo) + ";_v==null?null:_v.bds;})"
  1513  	default: // closure with a dynamic callee
  1514  		if !isBuiltin { // don't pass bindings to built-in functions
  1515  			ret += fnToCall + "==null?null:" + fnToCall + ".bds"
  1516  		}
  1517  	}
  1518  	for arg := range args {
  1519  		if arg != 0 || !isBuiltin {
  1520  			ret += ","
  1521  		}
  1522  		// SAME LOGIC AS SWITCH IN INVOKE - keep in line
  1523  		switch args[arg].Type().Underlying().(type) { // TODO this may be in need of further optimization
  1524  		case *types.Pointer, *types.Slice, *types.Chan: // must pass a reference, not a copy
  1525  			ret += l.IndirectValue(args[arg], errorInfo)
  1526  		case *types.Interface:
  1527  			if isHaxeAPI {
  1528  				ret += "Force.toHaxeParam(" + l.IndirectValue(args[arg], errorInfo) + ")"
  1529  			} else {
  1530  				ret += l.IndirectValue(args[arg], errorInfo)
  1531  			}
  1532  		case *types.Basic:
  1533  			if isHaxeAPI && args[arg].Type().Underlying().(*types.Basic).Kind() == types.String {
  1534  				ret += "Force.toHaxeString(" + l.IndirectValue(args[arg], errorInfo) + ")"
  1535  			} else {
  1536  				ret += l.IndirectValue(args[arg], errorInfo)
  1537  			}
  1538  		default:
  1539  			ret += l.IndirectValue(args[arg], errorInfo)
  1540  		}
  1541  	}
  1542  	if isBuiltin {
  1543  		switch fnToCall {
  1544  		case "print", "println":
  1545  			ret += "]"
  1546  		}
  1547  		ret += ")"
  1548  	} else {
  1549  		switch cc.Value.(type) {
  1550  		case *ssa.Function, *ssa.MakeClosure: // it is a call with a list of args
  1551  			ret += ")"
  1552  		default: // it is a call with a single arg that is a list
  1553  			ret += "])" // the callee is in a local variable
  1554  		}
  1555  	}
  1556  	if isBuiltin {
  1557  		if isGo || isDefer {
  1558  			l.PogoComp().LogError(errorInfo, "Haxe",
  1559  				fmt.Errorf("calling a builtin function (%s) via 'go' or 'defer' is not supported",
  1560  					fnToCall))
  1561  		}
  1562  		if register != "" {
  1563  			//**************************
  1564  			// ensure correct conversions for interface{} <-> Dynamic when isHaxeAPI
  1565  			//**************************
  1566  			if isHaxeAPI {
  1567  				r := cc.Signature().Results()
  1568  				if r.Len() == 1 {
  1569  					switch r.At(0).Type().Underlying().(type) {
  1570  					case *types.Interface:
  1571  						ret = "Interface.fromDynamic(" + ret + ")"
  1572  					case *types.Basic:
  1573  						if r.At(0).Type().Underlying().(*types.Basic).Kind() == types.String {
  1574  							ret = "Force.fromHaxeString(" + ret + ")"
  1575  						}
  1576  					}
  1577  				}
  1578  			}
  1579  			return hashIf + register + "=" + ret + ";" + hashEnd
  1580  		}
  1581  		return hashIf + ret + ";" + hashEnd
  1582  	}
  1583  	if isGo {
  1584  		if isDefer {
  1585  			l.PogoComp().LogError(errorInfo, "Haxe",
  1586  				fmt.Errorf("calling a function (%s) using both 'go' and 'defer' is not supported",
  1587  					fnToCall))
  1588  		}
  1589  		return ret + "; "
  1590  	}
  1591  	if isDefer {
  1592  		return ret + ";\nthis.defer(Scheduler.pop(this._goroutine));"
  1593  	}
  1594  	return l.doCall(register, cc.Signature().Results(), ret+";\n", usesGr)
  1595  }
  1596  
  1597  func (l langType) RunDefers(usesGr bool) string {
  1598  	return l.doCall("", nil, "this.runDefers();\n", usesGr)
  1599  }
  1600  
  1601  func (l langType) doCall(register string, tuple *types.Tuple, callCode string, usesGr bool) string {
  1602  	ret := ""
  1603  	if register != "" {
  1604  		ret += fmt.Sprintf("_SF%d=", -l.hc.nextReturnAddress)
  1605  	}
  1606  	if usesGr {
  1607  		ret += callCode
  1608  		//await completion
  1609  		ret += fmt.Sprintf("_Next = %d;\n", l.hc.nextReturnAddress) // where to come back to
  1610  		l.hc.hadBlockReturn = false
  1611  		ret += "return this;\n"
  1612  		if l.hc.fnUsesGr {
  1613  			ret += "#if uselocalfunctions } #end"
  1614  		} else {
  1615  			ret += "#if uselocalfunctions }); #end\n"
  1616  		}
  1617  		ret += l.emitUnseenPseudoBlocks()
  1618  		ret += fmt.Sprintf("#if !uselocalfunctions case %d: #end\n", l.hc.nextReturnAddress) // emit code to come back to
  1619  		if l.hc.fnUsesGr {
  1620  			fn := fmt.Sprintf(l.hc.currentfnName+"__%d", -l.hc.nextReturnAddress)
  1621  			l.hc.localFunctionMap[l.hc.nextReturnAddress] = fn
  1622  			ret += "#if uselocalfunctions function " + fn + "():" + l.hc.currentfnName + " { #end\n"
  1623  		} else {
  1624  			ret += fmt.Sprintf("#if uselocalfunctions fnMap.set(%d,function "+l.hc.currentfnName+"__%d():"+l.hc.currentfnName+" { #end\n",
  1625  				l.hc.nextReturnAddress, -l.hc.nextReturnAddress)
  1626  		}
  1627  		//ret += fmt.Sprintf("#if uselocalfunctions function _Block_%d(){ #end\n",
  1628  		//	-nextReturnAddress) // optimize JS with closure to allow V8 to optimize big funcs
  1629  		if l.PogoComp().DebugFlag {
  1630  			ret += "this.setLatest(" + fmt.Sprintf("%d", l.PogoComp().LatestValidPosHash) +
  1631  				"," + fmt.Sprintf("%d", l.hc.nextReturnAddress) + ");\n"
  1632  		}
  1633  		ret += l.emitTrace(fmt.Sprintf("Block:%d", l.hc.nextReturnAddress))
  1634  	} else {
  1635  		callCode = strings.TrimSpace(callCode)
  1636  		if register != "" {
  1637  			ret += callCode
  1638  			ret += l.emitTrace(`OPTIMIZED CALL (via stack frame)`)
  1639  			ret += fmt.Sprintf("_SF%d.run();\n", -l.hc.nextReturnAddress)
  1640  		} else {
  1641  			if strings.HasSuffix(callCode, ";") {
  1642  				ret += l.emitTrace(`OPTIMIZED CALL (no stack frame)`)
  1643  				ret += fmt.Sprintf("%s.run();\n", strings.TrimSuffix(callCode, ";"))
  1644  			} else {
  1645  				ret += l.emitTrace(`OPTIMIZED CALL (via scheduler)`)
  1646  				ret += fmt.Sprintf("Scheduler.run1();\n")
  1647  				//was: ret += "Scheduler.run1(this._goroutine);\n"
  1648  			}
  1649  		}
  1650  	}
  1651  	if register != "" { // if register, set return value, but only for non-null stack frames
  1652  		registerZero := ""
  1653  		switch tuple.Len() {
  1654  		case 0: // nothing to do
  1655  		case 1:
  1656  			registerZero = l.LangType(tuple.At(0).Type(), true, callCode)
  1657  		default:
  1658  			registerZero = l.LangType(tuple, true, callCode)
  1659  		}
  1660  		if registerZero != "" {
  1661  			//ret += fmt.Sprintf("%s=(_SF%d==null)?%s:_SF%d.res();\n", // goroutine of -1 => null closure
  1662  			//	register, -nextReturnAddress, registerZero, -nextReturnAddress)
  1663  			ret += fmt.Sprintf("%s=_SF%d.res();\n", // will fail if _SF is null
  1664  				register, -l.hc.nextReturnAddress)
  1665  		}
  1666  	}
  1667  	l.hc.nextReturnAddress-- //decrement to set new return address for next call generation
  1668  	return ret
  1669  }
  1670  
  1671  func allocNewObject(t types.Type) string {
  1672  	typ := t.Underlying().(*types.Pointer).Elem().Underlying()
  1673  	switch typ.(type) {
  1674  
  1675  	// this should not be required...
  1676  	case *types.Array:
  1677  		ao := haxeStdSizes.Alignof(typ.(*types.Array).Elem().Underlying())
  1678  		so := haxeStdSizes.Sizeof(typ.(*types.Array).Elem().Underlying())
  1679  		for so%ao != 0 {
  1680  			so++
  1681  		}
  1682  		return fmt.Sprintf("Object.make(%d) /* Array: %s */",
  1683  			typ.(*types.Array).Len()*so, typ.String())
  1684  
  1685  	default:
  1686  		return fmt.Sprintf("Object.make(%d) /* %s */",
  1687  			haxeStdSizes.Sizeof(typ),
  1688  			typ.String())
  1689  	}
  1690  }
  1691  
  1692  func (l langType) Alloc(reg string, heap bool, v interface{}, errorInfo string) string {
  1693  	if reg == "" {
  1694  		return "" // if the register is not used, don't emit the code!
  1695  	}
  1696  	/*
  1697  		typ := v.(types.Type).Underlying().(*types.Pointer).Elem().Underlying()
  1698  		//ele := l.LangType(typ, false, errorInfo)
  1699  		ptrTyp := "Pointer"
  1700  		switch typ.(type) {
  1701  		case *types.Array:
  1702  			//ele = l.LangType(typ.(*types.Array).Elem().Underlying(), false, errorInfo)
  1703  			ptrTyp = "Pointer"
  1704  		case *types.Slice:
  1705  			//ele = "Slice"
  1706  			ptrTyp = "Pointer"
  1707  		case *types.Struct:
  1708  			//ele = "Dynamic"
  1709  			ptrTyp = "Pointer"
  1710  		}
  1711  		return reg + "=new " + ptrTyp +
  1712  			"(" + l.LangType(typ, true, errorInfo) + ");"
  1713  	*/
  1714  	/*
  1715  		switch typ.(type) {
  1716  		case *types.Array:
  1717  			typ = typ.(*types.Array).Underlying()
  1718  		case *types.Struct:
  1719  			typ = typ.(*types.Struct).Underlying()
  1720  		default:
  1721  			l.PogoComp().LogError(errorInfo, "Haxe",
  1722  				fmt.Errorf("haxe.Alloc() - unhandled type: %v", reflect.TypeOf(typ)))
  1723  			return ""
  1724  		}
  1725  	*/
  1726  	if heap {
  1727  		return fmt.Sprintf("%s=Pointer.make(%s);", reg, allocNewObject(v.(types.Type)))
  1728  	}
  1729  	//fmt.Println("DEBUG Alloc on Stack", reg, errorInfo)
  1730  	reg2 := strings.Replace(strings.Replace(reg, "[", "", 1), "]", "", 1) // just in case we're in a big init() and are using a register array
  1731  	return fmt.Sprintf("%s=Pointer.make(%s_stackalloc.clear());", reg, reg2)
  1732  }
  1733  
  1734  func (l langType) MakeChan(reg string, v interface{}, errorInfo string) string {
  1735  	//typeElem := l.LangType(v.(*ssa.MakeChan).Type().Underlying().(*types.Chan).Elem().Underlying(), false, errorInfo)
  1736  	size := l.IndirectValue(v.(*ssa.MakeChan).Size, errorInfo)
  1737  	return reg + "=new Channel(" + size + `);` // <" + typeElem + ">(" + size + `);`
  1738  }
  1739  
  1740  func newSliceCode(typeElem, initElem, capacity, length, errorInfo, itemSize string) string {
  1741  	//return "new Slice(new Pointer(new Make<" + typeElem + ">((" + capacity + ")*(" + itemSize + "))" +
  1742  	//	".array(" + initElem + "," + capacity + ")" +
  1743  	//	"),0," + length + "," + capacity + "," + itemSize + `)`
  1744  	return "new Slice(Pointer.make(Object.make((" + capacity + ")*(" + itemSize + "))" +
  1745  		"),0," + length + "," + capacity + "," + itemSize + `)`
  1746  }
  1747  
  1748  func (l langType) MakeSlice(reg string, v interface{}, errorInfo string) string {
  1749  	typeElem := l.LangType(v.(*ssa.MakeSlice).Type().Underlying().(*types.Slice).Elem().Underlying(), false, errorInfo)
  1750  	initElem := l.LangType(v.(*ssa.MakeSlice).Type().Underlying().(*types.Slice).Elem().Underlying(), true, errorInfo)
  1751  	length := wrapForceToUInt(l.IndirectValue(v.(*ssa.MakeSlice).Len, errorInfo),
  1752  		v.(*ssa.MakeSlice).Len.Type().Underlying().(*types.Basic).Kind()) // lengths can't be 64 bit
  1753  	capacity := wrapForceToUInt(l.IndirectValue(v.(*ssa.MakeSlice).Cap, errorInfo),
  1754  		v.(*ssa.MakeSlice).Cap.Type().Underlying().(*types.Basic).Kind()) // capacities can't be 64 bit
  1755  	itemSize := "1" + arrayOffsetCalc(v.(*ssa.MakeSlice).Type().Underlying().(*types.Slice).Elem().Underlying())
  1756  	return reg + "=" + newSliceCode(typeElem, initElem, capacity, length, errorInfo, itemSize) + `;`
  1757  }
  1758  
  1759  // TODO see http://tip.golang.org/doc/go1.2#three_index
  1760  // TODO add third parameter when SSA code provides it to enable slice instructions to specify a capacity
  1761  func (l langType) Slice(register string, x, lv, hv interface{}, errorInfo string) string {
  1762  	xString := l.IndirectValue(x, errorInfo) // the target must be an array
  1763  	if xString == "" {
  1764  		xString = l.IndirectValue(x, errorInfo)
  1765  	}
  1766  	lvString := "0"
  1767  	if lv != nil {
  1768  		lvString = wrapForceToUInt(l.IndirectValue(lv, errorInfo),
  1769  			lv.(ssa.Value).Type().Underlying().(*types.Basic).Kind())
  1770  	}
  1771  	hvString := "-1"
  1772  	if hv != nil {
  1773  		hvString = wrapForceToUInt(l.IndirectValue(hv, errorInfo),
  1774  			hv.(ssa.Value).Type().Underlying().(*types.Basic).Kind())
  1775  	}
  1776  	switch x.(ssa.Value).Type().Underlying().(type) {
  1777  	case *types.Slice:
  1778  		return register + "=({var _v=" + xString + `;_v==null?null:(_v.subSlice(` + lvString + `,` + hvString + `));});`
  1779  	case *types.Pointer:
  1780  		eleSz := "1" + arrayOffsetCalc(x.(ssa.Value).Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Elem().Underlying())
  1781  		return register + "=new Slice(" + xString + `,` + lvString + `,` + hvString + "," +
  1782  			fmt.Sprintf("%d", x.(ssa.Value).Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len()) +
  1783  			"," + eleSz + `);`
  1784  	case *types.Basic: // assume a string is in need of slicing...
  1785  		if hvString == "-1" {
  1786  			hvString = "(" + xString + ").length"
  1787  		}
  1788  		return register + "= ({var _lvs=" + lvString + ";(" + xString + ").substr(_lvs," + hvString + "-_lvs) ;});"
  1789  	default:
  1790  		l.PogoComp().LogError(errorInfo, "Haxe",
  1791  			fmt.Errorf("haxe.Slice() - unhandled type: %v", reflect.TypeOf(x.(ssa.Value).Type().Underlying())))
  1792  		return ""
  1793  	}
  1794  }
  1795  
  1796  func (l langType) Index(register string, v1, v2 interface{}, errorInfo string) string {
  1797  	keyString := wrapForceToUInt(l.IndirectValue(v2, errorInfo),
  1798  		v2.(ssa.Value).Type().Underlying().(*types.Basic).Kind())
  1799  	typ := v1.(ssa.Value).Type().Underlying().(*types.Array).Elem().Underlying()
  1800  	return register + "=" + //l.IndirectValue(v1, errorInfo) + "[" + l.IndirectValue(v2, errorInfo) + "];" + // assign value
  1801  		fmt.Sprintf("%s.get%s%s%s)",
  1802  			l.IndirectValue(v1, errorInfo),
  1803  			loadStoreSuffix(typ, true),
  1804  			keyString,
  1805  			arrayOffsetCalc(typ)) + ";"
  1806  }
  1807  
  1808  func (l langType) codeField(v interface{}, fNum int, fName, errorInfo string, isFunctionName bool) string {
  1809  	str := v.(ssa.Value).Type().Underlying().(*types.Struct)
  1810  	//return fmt.Sprintf(" /* %d */ ", fieldOffset(str, fNum)) +
  1811  	return fmt.Sprintf("%s.get%s%d)",
  1812  		l.IndirectValue(v, errorInfo),
  1813  		loadStoreSuffix(str.Field(fNum).Type().Underlying(), true),
  1814  		fieldOffset(str, fNum))
  1815  }
  1816  
  1817  // Field emits the code to load a field value into a register
  1818  func (l langType) Field(register string, v interface{}, fNum int, fName, errorInfo string, isFunctionName bool) string {
  1819  	if register != "" {
  1820  		return register + "=" + l.codeField(v, fNum, fName, errorInfo, isFunctionName) + ";"
  1821  	}
  1822  	return ""
  1823  }
  1824  
  1825  // RangeCheck emits range check code
  1826  func (l langType) RangeCheck(x, i interface{}, length int, errorInfo string) string {
  1827  	chk := ""
  1828  	iStr := ""
  1829  	switch i.(type) {
  1830  	case string:
  1831  		iStr = i.(string)
  1832  	default:
  1833  		iStr = l.IndirectValue(i, errorInfo)
  1834  	}
  1835  	if length <= 0 { // length unknown at compile time
  1836  		xStr := l.IndirectValue(x, errorInfo)
  1837  		tPtr := x.(ssa.Value).Type().Underlying()
  1838  		lStr := "" // should give a Haxe compile time error if this is not set below
  1839  		//fmt.Println("DEBUG:", l.LangType(x.(ssa.Value).Type().Underlying(), false, errorInfo))
  1840  		if l.LangType(tPtr, false, errorInfo) == "Pointer" {
  1841  			tPtr = tPtr.(*types.Pointer).Elem().Underlying()
  1842  		}
  1843  		switch l.LangType(tPtr, false, errorInfo) {
  1844  		case "Slice":
  1845  			lStr += "" + xStr + ".length"
  1846  		case "Object":
  1847  			lStr += fmt.Sprintf("%d", tPtr.(*types.Array).Len())
  1848  		}
  1849  		chk = fmt.Sprintf("Scheduler.wraprangechk(%s,%s);", iStr, lStr)
  1850  	} else {
  1851  		// length is known at compile time => an array
  1852  		chk = fmt.Sprintf("Scheduler.wraprangechk(%s,%d);", iStr, length)
  1853  	}
  1854  	ret := ""
  1855  	_, hadIt := l.hc.rangeChecks[chk]
  1856  	if !hadIt { // de-dupe
  1857  		ret = chk
  1858  		l.hc.rangeChecks[chk] = struct{}{}
  1859  	}
  1860  	return ret
  1861  }
  1862  
  1863  func (l langType) MakeMap(reg string, v interface{}, errorInfo string) string {
  1864  	if reg == "" {
  1865  		return ""
  1866  	}
  1867  	return reg + "=" + l.LangType(v.(*ssa.MakeMap).Type().Underlying(), true, errorInfo) + `;`
  1868  }
  1869  
  1870  func (l langType) serializeKey(val, haxeTyp string) string { // can the key be serialized?
  1871  	switch haxeTyp {
  1872  	case "String", "Int", "Float", "Bool",
  1873  		"Pointer", "Object", "GOint64", "Complex", "Interface", "Channel", "Slice":
  1874  		return val
  1875  	default:
  1876  		l.PogoComp().LogError("serializeKey", "haxe", errors.New("unsupported map key type: "+haxeTyp))
  1877  		return ""
  1878  	}
  1879  }
  1880  
  1881  func (l langType) MapUpdate(Map, Key, Value interface{}, errorInfo string) string {
  1882  	skey := l.serializeKey(l.IndirectValue(Key, errorInfo),
  1883  		l.LangType(Key.(ssa.Value).Type().Underlying(), false, errorInfo))
  1884  	ret := l.IndirectValue(Map, errorInfo) + ".set("
  1885  	ret += skey + "," //+ l.IndirectValue(Key, errorInfo) + ","
  1886  	ret += l.IndirectValue(Value, errorInfo) + ");"
  1887  	return ret
  1888  }
  1889  
  1890  func (l langType) Lookup(reg string, Map, Key interface{}, commaOk bool, errorInfo string) string {
  1891  	if reg == "" {
  1892  		return ""
  1893  	}
  1894  	keyString := l.IndirectValue(Key, errorInfo)
  1895  	// check if we are looking up in a string
  1896  	if l.LangType(Map.(ssa.Value).Type().Underlying(), false, errorInfo) == "String" {
  1897  		keyString = wrapForceToUInt(keyString, Key.(ssa.Value).Type().Underlying().(*types.Basic).Kind())
  1898  		valueCode := l.IndirectValue(Map, errorInfo) //+ ".charCodeAt(" + keyString + ")"
  1899  		if commaOk {
  1900  			return reg + "=Force.stringAtOK(" + valueCode + "," + keyString + ");"
  1901  			//return reg + "=(" + valueCode + "==null) ?" +
  1902  			//	"{r0:0,r1:false}:{r0:Std.int(" + valueCode + "),r1:true};"
  1903  		}
  1904  		return reg + "=Force.stringAt(" + valueCode + "," + keyString + ");"
  1905  		//return reg + "=(" + valueCode + "==null) ?" +
  1906  		//	"{Scheduler.ioor();0;}:Std.int(" + valueCode + ");"
  1907  	}
  1908  	// assume it is a Map
  1909  	keyString = l.serializeKey(keyString, l.LangType(Key.(ssa.Value).Type().Underlying(), false, errorInfo))
  1910  
  1911  	isNull := l.IndirectValue(Map, errorInfo) + ";var _ks=" + keyString + ";_map==null?"
  1912  
  1913  	li := l.LangType(Map.(ssa.Value).Type().Underlying().(*types.Map).Elem().Underlying(), true, errorInfo)
  1914  	if strings.HasPrefix(li, "new ") {
  1915  		li = "null" // no need for a full object declaration in this context
  1916  	}
  1917  	returnValue := /*l.IndirectValue(Map, errorInfo) +*/ "_map.get(_ks)" //.val
  1918  	//ltEle := l.LangType(Map.(ssa.Value).Type().Underlying().(*types.Map).Elem().Underlying(), false, errorInfo)
  1919  	//switch ltEle {
  1920  	//case "GOint64", "Int", "Float", "Bool", "String", "Pointer", "Slice":
  1921  	//	returnValue = "cast(" + returnValue + "," + ltEle + ")"
  1922  	//}
  1923  	eleExists := /*l.IndirectValue(Map, errorInfo) +*/ "_map.exists(_ks)"
  1924  	if commaOk {
  1925  		return reg + "=({var _map:GOmap=" + isNull + "{r0:" + li + ",r1:false}:{r0:" + returnValue + ",r1:" + eleExists + "};});"
  1926  	}
  1927  	return reg + "=({var _map:GOmap=" + isNull + li + ":" + returnValue + ";});" // the .get will check for existance and return the zero value if not
  1928  }
  1929  
  1930  func (l langType) Extract(reg string, tuple interface{}, index int, errorInfo string) string {
  1931  	tp := l.IndirectValue(tuple, errorInfo)
  1932  	if l.PogoComp().DebugFlag {
  1933  		tp = "Force.checkTuple(" + tp + ")"
  1934  	}
  1935  	return reg + "=" + tp + ".r" + fmt.Sprintf("%d", index) + ";"
  1936  }
  1937  
  1938  func (l langType) Range(reg string, v interface{}, errorInfo string) string {
  1939  
  1940  	switch l.LangType(v.(ssa.Value).Type().Underlying(), false, errorInfo) {
  1941  	case "String":
  1942  		return reg + "=new GOstringRange(this._goroutine," + l.IndirectValue(v, errorInfo) + ");"
  1943  		//return reg + "={k:0,v:Force.toUTF8slice(this._goroutine," + l.IndirectValue(v, errorInfo) + ")" + "};"
  1944  	default: // assume it is a Map {k: key itterator,m: the map,z: zero value of an entry}
  1945  		return reg + "=({var _map=" + l.IndirectValue(v, errorInfo) + ";_map==null?null:cast(_map,GOmap).range();});"
  1946  		/*
  1947  			keyTyp := l.LangType(v.(ssa.Value).Type().Underlying().(*types.Map).Key().Underlying(), false, errorInfo)
  1948  			if keyTyp != "Int" {
  1949  				keyTyp = "String"
  1950  			}
  1951  			return reg + "={k:" + l.IndirectValue(v, errorInfo) + ".keys(),m:" + l.IndirectValue(v, errorInfo) +
  1952  				",zk:" + l.LangType(v.(ssa.Value).Type().Underlying().(*types.Map).Key().Underlying(), true, errorInfo) +
  1953  				",zv:" + l.LangType(v.(ssa.Value).Type().Underlying().(*types.Map).Elem().Underlying(), true, errorInfo) +
  1954  
  1955  				//`,fk:function(m:` + l.LangType(v.(ssa.Value).Type().Underlying(), false, errorInfo) + ",k:" +
  1956  				//keyTyp + "):" +
  1957  				//l.LangType(v.(ssa.Value).Type().Underlying().(*types.Map).Key().Underlying(), false, errorInfo) +
  1958  				//"{return m.get(" + "k" + ").key;}" +
  1959  				//`,fv:function(m:` + l.LangType(v.(ssa.Value).Type().Underlying(), false, errorInfo) + ",k:" +
  1960  				//keyTyp + "):" +
  1961  				//l.LangType(v.(ssa.Value).Type().Underlying().(*types.Map).Elem().Underlying(), false, errorInfo) +
  1962  				//"{return m.get(" + "k" + ").val;}" +
  1963  
  1964  				`};`
  1965  		*/
  1966  	}
  1967  }
  1968  func (l langType) Next(register string, v interface{}, isString bool, errorInfo string) string {
  1969  	if isString {
  1970  		return register + "=cast(" + l.IndirectValue(v, errorInfo) + ",GOstringRange).next();"
  1971  		/*
  1972  			return register + "={var _thisK:Int=" + l.IndirectValue(v, errorInfo) + ".k;" +
  1973  				"if(" + l.IndirectValue(v, errorInfo) + ".k>=" + l.IndirectValue(v, errorInfo) + ".v.len()){r0:false,r1:0,r2:0};" +
  1974  				"else {" +
  1975  				"var _dr:{r0:Int,r1:Int}=Go_utf8_DDecodeRRune.callFromRT(this._goroutine," + l.IndirectValue(v, errorInfo) +
  1976  				".v.subSlice(_thisK,-1));" +
  1977  				l.IndirectValue(v, errorInfo) + ".k+=_dr.r1;" +
  1978  				"{r0:true,r1:cast(_thisK,Int),r2:cast(_dr.r0,Int)};}};"
  1979  		*/
  1980  	}
  1981  	// otherwise it is a map itterator
  1982  	return register + "=({var _map=" + l.IndirectValue(v, errorInfo) + ";_map==null?{r0:false,r1:null,r2:null}:cast(_map,GOmapRange).next();});"
  1983  	/*
  1984  		return register + "={var _hn:Bool=" + l.IndirectValue(v, errorInfo) + ".k.hasNext();\n" +
  1985  			"if(_hn){var _nxt=" + l.IndirectValue(v, errorInfo) + ".k.next();\n" +
  1986  			//"$type(" + l.IndirectValue(v, errorInfo) + ".m);\n" +
  1987  			"{r0:true,r1:" + l.IndirectValue(v, errorInfo) + ".m.get(_nxt).key," +
  1988  			"r2:" + l.IndirectValue(v, errorInfo) + ".m.get(_nxt).val};\n" +
  1989  			"}else{{r0:false,r1:" + l.IndirectValue(v, errorInfo) + ".zk,r2:" + l.IndirectValue(v, errorInfo) + ".zv};\n}};"
  1990  	*/
  1991  }
  1992  
  1993  func (l langType) MakeClosure(reg string, v interface{}, errorInfo string) string {
  1994  	// use a closure type
  1995  	ret := reg + "= new Closure(" + l.IndirectValue(v.(*ssa.MakeClosure).Fn, errorInfo) + ",["
  1996  	for b := range v.(*ssa.MakeClosure).Bindings {
  1997  		if b != 0 {
  1998  			ret += ","
  1999  		}
  2000  		//ret += `` + v.(*ssa.MakeClosure).Fn.(*ssa.Function).FreeVars[b].Name() + `: `
  2001  		ret += l.IndirectValue(v.(*ssa.MakeClosure).Bindings[b], errorInfo)
  2002  	}
  2003  	return ret + "]);"
  2004  
  2005  	//it does not work to try just returning the function, and let the invloking call do the binding
  2006  	//as in: return reg + "=" + l.IndirectValue(v.(*ssa.MakeClosure).Fn, errorInfo) + ";"
  2007  }
  2008  
  2009  func (l langType) EmitInvoke(register, path string, isGo, isDefer, usesGr bool, callCommon interface{}, errorInfo string) string {
  2010  	val := callCommon.(ssa.CallCommon).Value
  2011  	meth := callCommon.(ssa.CallCommon).Method.Name()
  2012  	ret := ""
  2013  	if l.PogoComp().DebugFlag {
  2014  		ret += l.IndirectValue(val, errorInfo) + "==null?Scheduler.unt():"
  2015  	}
  2016  	ret += "Interface.invoke(" + l.IndirectValue(val, errorInfo) + `,"` +
  2017  		path + `"` + `,"` + meth + `",[`
  2018  	if isGo {
  2019  		if isDefer {
  2020  			l.PogoComp().LogError(errorInfo, "Haxe",
  2021  				fmt.Errorf("calling a method (%s) using both 'go' and 'defer' is not supported",
  2022  					meth))
  2023  		}
  2024  		ret += "Scheduler.makeGoroutine()"
  2025  	} else {
  2026  		ret += "this._goroutine"
  2027  	}
  2028  	ret += `,[],` + l.IndirectValue(val, errorInfo) + ".val"
  2029  	args := callCommon.(ssa.CallCommon).Args
  2030  	for arg := range args {
  2031  		ret += ","
  2032  		// SAME LOGIC AS SWITCH IN CALL - keep in line
  2033  		switch args[arg].Type().Underlying().(type) { // TODO this may be in need of further optimization
  2034  		case *types.Pointer, *types.Slice, *types.Chan: // must pass a reference, not a copy
  2035  			ret += l.IndirectValue(args[arg], errorInfo)
  2036  		case *types.Basic, *types.Interface: // NOTE Complex is an object as is Int64 (in java & cs), but copy does not seem to be required
  2037  			ret += l.IndirectValue(args[arg], errorInfo)
  2038  		default: // TODO review
  2039  			ret += l.IndirectValue(args[arg], errorInfo)
  2040  		}
  2041  	}
  2042  	if isGo {
  2043  		return ret + "]); "
  2044  	}
  2045  	if isDefer {
  2046  		return ret + "]);\nthis.defer(Scheduler.pop(this._goroutine));"
  2047  	}
  2048  	cc := callCommon.(ssa.CallCommon)
  2049  	return l.doCall(register, cc.Signature().Results(), ret+"]);", usesGr)
  2050  }
  2051  
  2052  func (l langType) deDupAssign(register, code string) string {
  2053  	if l.hc.deDupRHS != nil {
  2054  		prevReg, found := l.hc.deDupRHS[code]
  2055  		if found {
  2056  			code = prevReg
  2057  		} else {
  2058  			l.hc.deDupRHS[code] = register + "; // DE-DUP: " + code
  2059  		}
  2060  	}
  2061  	return register + "=" + code
  2062  }
  2063  
  2064  const alwaysStackdump = false
  2065  
  2066  func (l langType) SubFnStart(id int, mustSplitCode bool, ins []ssa.Instruction) string {
  2067  	l.reset1useMap()
  2068  	l.hc.subFnInstrs = ins
  2069  	l.hc.deDupRHS = make(map[string]string)
  2070  	l.hc.tempVarList = []regToFree{}
  2071  	if mustSplitCode {
  2072  		l.hc.inMustSplitSubFn = true
  2073  	} else {
  2074  		if alwaysStackdump || l.PogoComp().DebugFlag {
  2075  			return "try {"
  2076  		}
  2077  		return ""
  2078  	}
  2079  	if alwaysStackdump || l.PogoComp().DebugFlag {
  2080  		return fmt.Sprintf("private "+"function SubFn%d():Void { try {", id)
  2081  	}
  2082  	return fmt.Sprintf("private "+"function SubFn%d():Void { ", id)
  2083  }
  2084  
  2085  func (l langType) SubFnEnd(id, pos int, mustSplitCode bool) string {
  2086  	l.hc.deDupRHS = nil
  2087  	l.hc.inMustSplitSubFn = false
  2088  	ret := ""
  2089  	ret += l.nullTempVars()
  2090  	if alwaysStackdump || l.PogoComp().DebugFlag {
  2091  		ret += fmt.Sprintf("} catch (c:Dynamic) {Scheduler.htc(c,%d);}", pos)
  2092  	}
  2093  	if mustSplitCode {
  2094  		ret += "}"
  2095  	}
  2096  	return ret
  2097  }
  2098  
  2099  func (l langType) SubFnCall(id int) string {
  2100  	return fmt.Sprintf("SubFn%d();", id)
  2101  }
  2102  
  2103  func (l langType) DeclareTempVar(v ssa.Value) string {
  2104  	if l.hc.useRegisterArray {
  2105  		return ""
  2106  	}
  2107  	if len(*(v.Referrers())) == 0 {
  2108  		return ""
  2109  	}
  2110  	if l.is1usePtr(v) {
  2111  		return "" // "// virtual oneUsePtr _" + v.Name()
  2112  	}
  2113  	typ := l.LangType(v.Type(), false, "temp var declaration")
  2114  	if typ == "" {
  2115  		return ""
  2116  	}
  2117  	if typ == "String" {
  2118  		l.hc.tempVarList = append(l.hc.tempVarList, regToFree{"_" + v.Name(), typ})
  2119  	}
  2120  	init := l.LangType(v.Type(), true, "temp var declaration")
  2121  	if init == "null" ||
  2122  		strings.HasPrefix(init, "new") ||
  2123  		strings.HasPrefix(init, "{") ||
  2124  		strings.HasPrefix(init, "Object.make") ||
  2125  		strings.HasPrefix(init, "Pointer.make") ||
  2126  		strings.HasPrefix(init, "GOint64") {
  2127  		init = "null"
  2128  		l.hc.tempVarList = append(l.hc.tempVarList, regToFree{"_" + v.Name(), typ})
  2129  	}
  2130  	init = "#if jsinit =" + init + " #end " // to allow V8 optimisation?
  2131  	return "var _" + v.Name() + ":" + typ + " " + init + ";"
  2132  }
  2133  
  2134  func (l langType) nullTempVars() string {
  2135  	ret := " #if nulltempvars\n"
  2136  	ret += recycle(l.hc.tempVarList) // NOTE this helps GC for all targets, especially C++
  2137  	ret += " #end\n"
  2138  	l.hc.tempVarList = []regToFree{}
  2139  	return ret
  2140  }