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

     1  package haxe
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"go/constant"
    11  
    12  	"golang.org/x/tools/go/ssa"
    13  
    14  	"github.com/tardisgo/tardisgo/tgoutil"
    15  )
    16  
    17  var pseudoFnPrefix = tgoutil.MakeID("github.com/tardisgo/tardisgo/haxe/hx_")
    18  
    19  func (l langType) hxPseudoFuncs(fnToCall string, args []ssa.Value, errorInfo string) string {
    20  	//fmt.Println("DEBUG l.hxPseudoFuncs()", fnToCall, args, errorInfo)
    21  	fnToCall = strings.TrimPrefix(fnToCall, pseudoFnPrefix)
    22  
    23  	switch fnToCall {
    24  	case "SSource":
    25  		fn := strings.Trim(args[0].(*ssa.Const).Value.String(), "\"")
    26  		fn = l.hc.langEntry.TgtDir + string(os.PathSeparator) + fn + ".hx"
    27  		code := strings.Trim(args[1].(*ssa.Const).Value.String(), "\"")
    28  		code = strings.Replace(code, "\\n", "\n", -1)
    29  		code = strings.Replace(code, "\\t", "\t", -1)
    30  		code = strings.Replace(code, "\\\"", "\"", -1)
    31  		//println("DEBUG fn: " + fn + "\nCode: " + code)
    32  		err := ioutil.WriteFile(fn, []byte(code), 0666)
    33  		if err != nil {
    34  			l.PogoComp().LogError(errorInfo, "Haxe", err)
    35  		}
    36  		return ""
    37  	case "init":
    38  		return "" // no need to generate code for the go init function
    39  	case "RResource":
    40  		return "Slice.fromResource(" + l.IndirectValue(args[0], errorInfo) + ");"
    41  	case "MMalloc":
    42  		return "Pointer.make(Object.make(Force.toInt(" + l.IndirectValue(args[0], errorInfo) + ")));"
    43  	case "IIsNNull":
    44  		return l.IndirectValue(args[0], errorInfo) + "==null;"
    45  	case "NNull":
    46  		return "null;"
    47  	case "CComplex":
    48  		return "cast(" + l.IndirectValue(args[0], errorInfo) + ",Complex);"
    49  	case "IInt64":
    50  		return "new GOint64(" + l.IndirectValue(args[0], errorInfo) + ");"
    51  	case "CCallbackFFunc":
    52  		// NOTE there will be a preceeding MakeInterface call that is made redundant by this code
    53  		if len(args) == 1 {
    54  			goMI, ok := args[0].(*ssa.MakeInterface)
    55  			if ok {
    56  				goFn, ok := (*(goMI.Operands(nil)[0])).(*ssa.Function)
    57  				if ok {
    58  					return "new Interface(-1," + l.IndirectValue(args[0], errorInfo) + ".val.buildCallbackFn()); // Go_" + l.FuncName(goFn)
    59  				}
    60  				_, ok = (*(goMI.Operands(nil)[0])).(*ssa.MakeClosure)
    61  				if ok {
    62  					return "new Interface(-1," + l.IndirectValue(args[0], errorInfo) + ".val.buildCallbackFn());"
    63  				}
    64  				con, ok := (*(goMI.Operands(nil)[0])).(*ssa.Const)
    65  				if ok {
    66  					return "new Interface(-1," + l.tgoString(l.IndirectValue(con, errorInfo), errorInfo) + ");"
    67  				}
    68  			}
    69  		}
    70  		l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("hx.Func() argument is not a function constant"))
    71  		return ""
    72  	}
    73  
    74  	argOff := 1 // because of the ifLogic
    75  	wrapStart := ""
    76  	wrapEnd := ""
    77  	usesArgs := true
    78  
    79  	ifLogic := l.IndirectValue(args[0], errorInfo)
    80  	//fmt.Println("DEBUG:ifLogic=", ifLogic, "AT", errorInfo)
    81  	ifLogic = l.tgoString(ifLogic, errorInfo)
    82  	if len(ifLogic) > 0 {
    83  		wrapStart = " #if (" + ifLogic + ") "
    84  		defVal := "null"
    85  		if strings.HasSuffix(fnToCall, "Bool") {
    86  			defVal = "false"
    87  		}
    88  		if strings.HasSuffix(fnToCall, "Int") {
    89  			defVal = "0"
    90  		}
    91  		if strings.HasSuffix(fnToCall, "Float") {
    92  			defVal = "0.0"
    93  		}
    94  		if strings.HasSuffix(fnToCall, "String") {
    95  			defVal = `""`
    96  		}
    97  		wrapEnd = " #else " + defVal + "; #end "
    98  	}
    99  
   100  	if strings.HasSuffix(fnToCall, "SString") &&
   101  		!strings.HasPrefix(fnToCall, "CCode") &&
   102  		!strings.HasPrefix(fnToCall, "FFset") &&
   103  		!strings.HasPrefix(fnToCall, "SSet") {
   104  		wrapStart += " Force.fromHaxeString({"
   105  		wrapEnd = "});" + wrapEnd
   106  	}
   107  
   108  	if strings.HasSuffix(fnToCall, "IIface") {
   109  		argOff = 2
   110  		wrapStart += "new Interface(TypeInfo.getId(" + l.IndirectValue(args[1], errorInfo) + "),{"
   111  		wrapEnd = "});" + wrapEnd
   112  	}
   113  	code := ""
   114  	if strings.HasPrefix(fnToCall, "NNew") {
   115  		code = "new "
   116  	}
   117  	if strings.HasPrefix(fnToCall, "CCode") || strings.HasPrefix(fnToCall, "GGet") {
   118  		givenConst, givenConstOK := args[argOff].(*ssa.Const)
   119  		if givenConstOK {
   120  			if givenConst.Value.Kind() == constant.String {
   121  				goto codeOK
   122  			}
   123  		}
   124  		l.PogoComp().LogError(errorInfo, "Haxe",
   125  			fmt.Errorf("hx.???() code is not a usable string constant: %s", args[argOff].String()))
   126  		return ""
   127  	codeOK:
   128  		tcode := strings.Trim(givenConst.Value.String(), `"`) // trim quotes
   129  		tcode = strings.Replace(tcode, "\\\"", "\"", -1)      // replace backslash quote with quote
   130  		//println("DEBUG string=", tcode)
   131  		code += tcode
   132  	} else {
   133  		code += strings.Trim(l.IndirectValue(args[argOff], errorInfo), `"`) // trim quotes if it has any
   134  	}
   135  	if strings.HasPrefix(fnToCall, "CCall") ||
   136  		strings.HasPrefix(fnToCall, "MMeth") || strings.HasPrefix(fnToCall, "NNew") {
   137  		argOff++
   138  		if strings.HasPrefix(fnToCall, "MMeth") {
   139  			haxeType := l.tgoString(l.IndirectValue(args[argOff], errorInfo), errorInfo)
   140  			if len(haxeType) > 0 {
   141  				code = "cast(" + code + "," + haxeType + ")"
   142  			}
   143  			argOff++
   144  			obj := l.IndirectValue(args[argOff], errorInfo)
   145  			code += "." + strings.Trim(obj, `"`) + "("
   146  			argOff++
   147  		} else {
   148  			code += "("
   149  		}
   150  		textLen := l.IndirectValue(args[argOff], errorInfo) // see Const() for format
   151  		aLen, err := strconv.ParseUint(textLen, 0, 64)
   152  		if err != nil {
   153  			code += " ERROR Go ParseUint on number of arguments to hx.Meth() or hx.Call() - " + err.Error() + "! "
   154  		} else {
   155  			if aLen == 0 {
   156  				usesArgs = false
   157  			}
   158  			for i := uint64(0); i < aLen; i++ {
   159  				if i > 0 {
   160  					code += ","
   161  				}
   162  				//code += fmt.Sprintf("Force.toHaxeParam(_a.itemAddr(%d).load())", i)
   163  				code += fmt.Sprintf("Force.toHaxeParam(_a.param(%d))", i)
   164  			}
   165  		}
   166  		code += ");"
   167  	}
   168  	if strings.HasPrefix(fnToCall, "GGet") {
   169  		code += ";"
   170  		usesArgs = false
   171  	}
   172  	if strings.HasPrefix(fnToCall, "SSet") {
   173  		argOff++
   174  		code = code + "=" + l.IndirectValue(args[argOff], errorInfo) + ";"
   175  		usesArgs = false
   176  	}
   177  	if strings.HasPrefix(fnToCall, "FFget") {
   178  		argOff++
   179  		if l.IndirectValue(args[argOff], errorInfo) != `""` {
   180  			code = "cast(" + code + "," + l.tgoString(l.IndirectValue(args[argOff], errorInfo), errorInfo) + ")"
   181  		}
   182  		code += "." + l.tgoString(l.IndirectValue(args[argOff+1], errorInfo), errorInfo) + "; "
   183  		usesArgs = false
   184  	}
   185  	if strings.HasPrefix(fnToCall, "FFset") {
   186  		argOff++
   187  		if l.IndirectValue(args[argOff], errorInfo) != `""` {
   188  			code = "cast(" + code + "," + l.tgoString(l.IndirectValue(args[argOff], errorInfo), errorInfo) + ")"
   189  		}
   190  		code += "." + l.tgoString(l.IndirectValue(args[argOff+1], errorInfo), errorInfo) +
   191  			"=Force.toHaxeParam(" + l.IndirectValue(args[argOff+2], errorInfo) + "); "
   192  		usesArgs = false
   193  	}
   194  
   195  	ret := "{"
   196  	if usesArgs {
   197  		ret += "var _a=" + l.IndirectValue(args[argOff+1], errorInfo) + "; "
   198  	}
   199  	return ret + wrapStart + code + wrapEnd + " }"
   200  }
   201  
   202  func (l langType) tgoString(s, errorInfo string) string {
   203  	bits := strings.Split(s, `"`)
   204  	if len(bits) < 2 {
   205  		l.PogoComp().LogError(errorInfo, "Haxe", fmt.Errorf("hx.() argument is not a usable string constant"))
   206  		return ""
   207  	}
   208  	return bits[1]
   209  }