Esempio n. 1
0
// Returns the textual version of Value, possibly emmitting an error
// can't merge with indirectValue, as this is used by emit-func-setup to get register names
func (l langType) Value(v interface{}, errorInfo string) string {
	val, ok := v.(ssa.Value)
	if !ok {
		return "" // if it is not a value, an empty string will be returned
	}
	switch v.(type) {
	case *ssa.Global:
		return "Go." + l.LangName(v.(*ssa.Global).Pkg.Object.Name(), v.(*ssa.Global).Name())
	case *ssa.Alloc, *ssa.MakeSlice:
		return pogo.RegisterName(v.(ssa.Value))
	case *ssa.FieldAddr, *ssa.IndexAddr:
		return pogo.RegisterName(v.(ssa.Value))
	case *ssa.Const:
		ci := v.(*ssa.Const)
		_, c := l.Const(*ci, errorInfo)
		return c
	case *ssa.Parameter:
		return "p_" + pogo.MakeId(v.(*ssa.Parameter).Name())
	case *ssa.Capture:
		for b := range v.(*ssa.Capture).Parent().FreeVars {
			if v.(*ssa.Capture) == v.(*ssa.Capture).Parent().FreeVars[b] { // comparing the name gives the wrong result
				return `_bds[` + fmt.Sprintf("%d", b) + `]`
			}
		}
		pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Value(): *ssa.Capture name not found: %s", v.(*ssa.Capture).Name()))
		return `_bds["_b` + "ERROR: Captured bound variable name not found" + `"]` // TODO proper error
	case *ssa.Function:
		pk := "unknown"
		if v.(*ssa.Function).Signature.Recv() != nil { // it's a method
			pk = v.(*ssa.Function).Signature.Recv().Pkg().Name() + "." + v.(*ssa.Function).Signature.Recv().Name()
		} else {
			if v.(*ssa.Function).Pkg != nil {
				if v.(*ssa.Function).Pkg.Object != nil {
					pk = v.(*ssa.Function).Pkg.Object.Name()
				}
			}
		}
		if len(v.(*ssa.Function).Blocks) > 0 { //the function actually exists
			return "new Closure(Go_" + l.LangName(pk, v.(*ssa.Function).Name()) + ".call,[])" //TODO will change for go instr
		}
		// function has no implementation
		// TODO maybe put a list of over-loaded functions here and only error if not found
		// NOTE the reflect package comes through this path TODO fix!
		pogo.LogWarning(errorInfo, "Haxe", fmt.Errorf("haxe.Value(): *ssa.Function has no implementation: %s", v.(*ssa.Function).Name()))
		return "new Closure(null,[])" // Should fail at runtime if it is used...
	case *ssa.UnOp:
		return pogo.RegisterName(val)
	case *ssa.BinOp:
		return pogo.RegisterName(val)
	case *ssa.MakeInterface:
		return pogo.RegisterName(val)
	default:
		return pogo.RegisterName(val)
	}
}
Esempio n. 2
0
func (l langType) Convert(register, langType string, destType types.Type, v interface{}, errorInfo string) string {
	srcTyp := l.LangType(v.(ssa.Value).Type().Underlying(), false, errorInfo)
	if srcTyp == langType { // no cast required because the Haxe type is the same
		return register + "=" + l.IndirectValue(v, errorInfo) + ";"
	}
	switch langType { // target Haxe type
	case "Dynamic": // no cast allowed for dynamic variables
		return register + "=" + l.IndirectValue(v, errorInfo) + ";" // TODO review if this is correct for Int64
	case "String":
		switch srcTyp {
		case "Slice":
			switch v.(ssa.Value).Type().Underlying().(*types.Slice).Elem().Underlying().(*types.Basic).Kind() {
			case types.Rune: // []rune
				return "{var _r:Slice=Go_haxegoruntime_Runes2Raw.callFromRT(this._goroutine," + l.IndirectValue(v, errorInfo) + ");" +
					register + "=\"\";for(_i in 0..._r.len())" +
					register + "+=String.fromCharCode(_r.getAt(_i" + "));};"
			case types.Byte: // []byte
				return register + "=Force.toRawString(this._goroutine," + l.IndirectValue(v, errorInfo) + ");"
			default:
				pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Convert() - Unexpected slice type to convert to String"))
				return ""
			}
		case "Int": // make a string from a single rune
			return "{var _r:Slice=Go_haxegoruntime_Rune2Raw.callFromRT(this._goroutine," + l.IndirectValue(v, errorInfo) + ");" +
				register + "=\"\";for(_i in 0..._r.len())" +
				register + "+=String.fromCharCode(_r.getAt(_i" + "));};"
		case "GOint64": // make a string from a single rune (held in 64 bits)
			return "{var _r:Slice=Go_haxegoruntime_Rune2Raw.callFromRT(this._goroutine,GOint64.toInt(" + l.IndirectValue(v, errorInfo) + "));" +
				register + "=\"\";for(_i in 0..._r.len())" +
				register + "+=String.fromCharCode(_r.getAt(_i" + "));};"
		case "Dynamic":
			return register + "=cast(" + l.IndirectValue(v, errorInfo) + ",String);"
		default:
			pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Convert() - Unexpected type to convert to String: %s", srcTyp))
			return ""
		}
	case "Slice": // []rune or []byte
		if srcTyp != "String" {
			pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Convert() - Unexpected type to convert to %s ([]rune or []byte): %s",
				langType, srcTyp))
			return ""
		}
		switch destType.Underlying().(*types.Slice).Elem().Underlying().(*types.Basic).Kind() {
		case types.Rune:
			return register + "=" + newSliceCode("Int", "0",
				l.IndirectValue(v, errorInfo)+".length", l.IndirectValue(v, errorInfo)+".length", errorInfo) + ";" +
				"for(_i in 0..." + l.IndirectValue(v, errorInfo) + ".length)" +
				register + ".setAt(_i,({var _c:Null<Int>=" + l.IndirectValue(v, errorInfo) +
				`.charCodeAt(_i);(_c==null)?0:cast(_c,Int);})` + ");" +
				register + "=Go_haxegoruntime_Raw2Runes.callFromRT(this._goroutine," + register + ");"
		case types.Byte:
			return register + "=Force.toUTF8slice(this._goroutine," + l.IndirectValue(v, errorInfo) + ");"
		default:
			pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Convert() - Unexpected slice elementto convert to %s ([]rune/[]byte): %s",
				langType, srcTyp))
			return ""
		}
	case "Int": //TODO check that unsigned handelled correctly here
		vInt := ""
		switch srcTyp {
		case "GOint64":
			vInt = "GOint64.toInt(" + l.IndirectValue(v, errorInfo) + ")"
		case "Float":
			vInt = "{var _f:Float=" + l.IndirectValue(v, errorInfo) + ";_f>=0?Math.floor(_f):Math.ceil(_f);}"
		default:
			vInt = "cast(" + l.IndirectValue(v, errorInfo) + "," + langType + ")"
		}
		return register + "=" + l.intTypeCoersion(destType, vInt, errorInfo) + ";"
	case "GOint64":
		switch srcTyp {
		case "Int":
			return register + "=GOint64.ofInt(" + l.IndirectValue(v, errorInfo) + ");"
		case "Float":
			if destType.Underlying().(*types.Basic).Info()&types.IsUnsigned != 0 {
				return register + "=GOint64.ofUFloat(" + l.IndirectValue(v, errorInfo) + ");"
			}
			return register + "=GOint64.ofFloat(" + l.IndirectValue(v, errorInfo) + ");"
		case "Dynamic": // uintptr
			return register + "=" + l.IndirectValue(v, errorInfo) + ";" // let Haxe work out how to do the cast
		default:
			return register + "=cast(" + l.IndirectValue(v, errorInfo) + "," + langType + ");" //TODO unreliable in Java from Dynamic?
		}
	case "Float":
		switch srcTyp {
		case "GOint64":
			if v.(ssa.Value).Type().Underlying().(*types.Basic).Info()&types.IsUnsigned != 0 {
				return register + "=GOint64.toUFloat(" + l.IndirectValue(v, errorInfo) + ");"
			}
			return register + "=GOint64.toFloat(" + l.IndirectValue(v, errorInfo) + ");"
		case "Int":
			if v.(ssa.Value).Type().Underlying().(*types.Basic).Info()&types.IsUnsigned != 0 {
				return register + "=GOint64.toUFloat(GOint64.make(0," + l.IndirectValue(v, errorInfo) + "));"
			}
			return register + "=" + l.IndirectValue(v, errorInfo) + ";" // just the default conversion to float required
		default:
			return register + "=cast(" + l.IndirectValue(v, errorInfo) + "," + langType + ");"
		}
	case "UnsafePointer":
		pogo.LogWarning(errorInfo, "Haxe", fmt.Errorf("attempt to convert a value to be an Unsafe Pointer, which is unsupported"))
		return register + "=new UnsafePointer(" + l.IndirectValue(v, errorInfo) + ");" // this will generate a runtime exception if called
	default:
		if strings.HasPrefix(srcTyp, "Array<") {
			pogo.LogError(errorInfo, "Haxe", fmt.Errorf("haxe.Convert() - No way to convert to %s from %s ", langType, srcTyp))
			return ""
		}
		return register + "=cast(" + l.IndirectValue(v, errorInfo) + "," + langType + ");"
	}
}
Esempio n. 3
0
func (l langType) LangType(t types.Type, retInitVal bool, errorInfo string) string {
	if pogo.IsValidInPogo(t, errorInfo) {
		switch t.(type) {
		case *types.Basic:
			switch t.(*types.Basic).Kind() {
			case types.Bool, types.UntypedBool:
				if retInitVal {
					return "false"
				}
				return "Bool"
			case types.String, types.UntypedString:
				if retInitVal {
					return `""`
				}
				return "String"
			case types.Float64, types.Float32, types.UntypedFloat:
				if retInitVal {
					return "0.0"
				}
				return "Float"
			case types.Complex64, types.Complex128, types.UntypedComplex:
				if retInitVal {
					return "new Complex(0.0,0.0)"
				}
				return "Complex"
			case types.Int, types.Int8, types.Int16, types.Int32, types.UntypedRune,
				types.Uint8, types.Uint16, types.Uint, types.Uint32: // NOTE: untyped integers default to Int without a warning
				if retInitVal {
					return "0"
				}
				return "Int"
			case types.Int64, types.Uint64:
				if retInitVal {
					return "GOint64.make(0,0)"
				}
				return "GOint64"
			case types.UntypedInt: // TODO: investigate further the situations in which this warning is generated
				pogo.LogWarning(errorInfo, "Haxe", fmt.Errorf("haxe.LangType() types.UntypedInt is ambiguous"))
				return "UNTYPED_INT" // NOTE: if this value were ever to be used, it would cause a Haxe compilation error
			case types.UnsafePointer:
				if retInitVal {
					return "new UnsafePointer(null)" // TODO is this correct? or should it be null
				}
				return "UnsafePointer"
			case types.Uintptr: // Uintptr sometimes used as an integer type, sometimes as a container for another type
				if retInitVal {
					return "null"
				}
				return "Dynamic"
			default:
				pogo.LogWarning(errorInfo, "Haxe", fmt.Errorf("haxe.LangType() unrecognised basic type, Dynamic assumed"))
				if retInitVal {
					return "null"
				}
				return "Dynamic"
			}
		case *types.Interface:
			if retInitVal {
				return `null`
			}
			return "Interface"
		case *types.Named:
			return l.LangType(t.(*types.Named).Underlying(), retInitVal, errorInfo)
		case *types.Chan:
			if retInitVal {
				return "new Channel<" + l.LangType(t.(*types.Chan).Elem(), false, errorInfo) + ">(1)"
			}
			return "Channel<" + l.LangType(t.(*types.Chan).Elem(), false, errorInfo) + ">"
		case *types.Map:
			if retInitVal {
				return "new Map<" + l.LangType(t.(*types.Map).Key(), false, errorInfo) + "," +
					l.LangType(t.(*types.Map).Elem(), false, errorInfo) + ">()"
			}
			return "Map<" + l.LangType(t.(*types.Map).Key(), false, errorInfo) + "," +
				l.LangType(t.(*types.Map).Elem(), false, errorInfo) + ">"
		case *types.Slice:
			if retInitVal {
				return "new Slice(new Pointer(new Array<" + l.LangType(t.(*types.Slice).Elem(), false, errorInfo) +
					">()),0,0" + ")"
			}
			return "Slice"
		case *types.Array: // TODO consider using Vector rather than Array, if faster and can be made to work
			if retInitVal {
				return "{var _v=new Array<" +
					l.LangType(t.(*types.Array).Elem(), false, errorInfo) +
					fmt.Sprintf(">();for(_vi in 0...%d){_v[_vi]=%s;}; _v;}",
						t.(*types.Array).Len(), l.LangType(t.(*types.Array).Elem(), true, errorInfo))

			}
			return "Array<" + l.LangType(t.(*types.Array).Elem(), false, errorInfo) + ">"
		case *types.Struct: // TODO as this is fixed-length, should it be a Vector, like types.Array ?
			// TODO consider if it is possible to change from Array<Dynamic> to individual named elements - requires considerable work to do this
			if retInitVal {
				ret := "{var _v=new Array<Dynamic>();_v=["
				for ele := 0; ele < t.(*types.Struct).NumFields(); ele++ {
					if ele != 0 {
						ret += ","
					}
					ret += l.LangType(t.(*types.Struct).Field(ele).Type().Underlying(), true, errorInfo)
				}
				return ret + "]; _v;}"
			}
			return "Array<Dynamic>"
		case *types.Tuple: // what is returned by a call and some other instructions, not in the Go language spec!
			tup := t.(*types.Tuple)
			switch tup.Len() {
			case 0:
				return ""
			case 1:
				return l.LangType(tup.At(0).Type().Underlying(), retInitVal, errorInfo)
			default:
				ret := "{"
				for ele := 0; ele < tup.Len(); ele++ {
					if ele != 0 {
						ret += ","
					}
					ret += pogo.MakeId("r"+fmt.Sprintf("%d", ele)) +
						":" + l.LangType(tup.At(ele).Type().Underlying(), retInitVal, errorInfo)
				}
				return ret + "}"
			}
		case *types.Pointer:
			if retInitVal {
				// NOTE pointer declarations create endless recursion for self-referencing structures unless initialized with null
				return "null" //rather than: + l.LangType(t.(*types.Pointer).Elem(), retInitVal, errorInfo) + ")"
			}
			return "Pointer"
		case *types.Signature:
			if retInitVal {
				return "null"
			}
			ret := "Closure"
			return ret
		default:
			rTyp := reflect.TypeOf(t).String()
			if rTyp == "*ssa.opaqueType" { // NOTE the type for map itterators, not in the Go language spec!
				if retInitVal { // use dynamic type, brief tests seem OK, but may not always work on static hosts
					return "null"
				}
				return "Dynamic"
			}
			pogo.LogError(errorInfo, "Haxe",
				fmt.Errorf("haxe.LangType() internal error, unhandled non-basic type: %s", rTyp))
		}
	}
	return "UNKNOWN_LANGTYPE" // this should generate a Haxe compiler error
}
Esempio n. 4
0
func (l langType) LangType(t types.Type, retInitVal bool, errorInfo string) string {
	if pogo.IsValidInPogo(t, errorInfo) {
		switch t.(type) {
		case *types.Basic:
			switch t.(*types.Basic).Kind() {
			case types.Bool, types.UntypedBool:
				if retInitVal {
					return "false"
				}
				return "Bool"
			case types.String, types.UntypedString:
				if retInitVal {
					return `""`
				}
				return "String"
			case types.Float64, types.Float32, types.UntypedFloat:
				if retInitVal {
					return "0.0"
				}
				return "Float"
			case types.Complex64, types.Complex128, types.UntypedComplex:
				if retInitVal {
					return "new Complex(0.0,0.0)"
				}
				return "Complex"
			case types.Int, types.Int8, types.Int16, types.Int32, types.UntypedRune,
				types.Uint8, types.Uint16, types.Uint, types.Uint32: // NOTE: untyped runes default to Int without a warning
				if retInitVal {
					return "0"
				}
				return "Int"
			case types.Int64, types.Uint64:
				if retInitVal {
					return "GOint64.ofInt(0)"
				}
				return "GOint64"
			case types.UntypedInt: // TODO: investigate further the situations in which this warning is generated
				if retInitVal {
					return "0"
				}
				return "UNTYPED_INT" // NOTE: if this value were ever to be used, it would cause a Haxe compilation error
			case types.UnsafePointer:
				if retInitVal {
					return "null" // NOTE ALL pointers are unsafe
				}
				return "Pointer"
			case types.Uintptr: // Uintptr sometimes used as an integer type, sometimes as a container for another type
				if retInitVal {
					return "null"
				}
				return "Dynamic"
			default:
				pogo.LogWarning(errorInfo, "Haxe", fmt.Errorf("haxe.LangType() unrecognised basic type, Dynamic assumed"))
				if retInitVal {
					return "null"
				}
				return "Dynamic"
			}
		case *types.Interface:
			if retInitVal {
				return `null`
			}
			return "Interface"
		case *types.Named:
			haxeName := getHaxeClass(t.(*types.Named).String())
			//fmt.Println("DEBUG Go named type -> Haxe type :", t.(*types.Named).String(), "->", haxeName)
			if haxeName != "" {
				if retInitVal {
					return `null` // NOTE code to the right does not work in openfl/flash: `Type.createEmptyInstance(` + haxeName + ")"
				}
				return haxeName
			}
			return l.LangType(t.(*types.Named).Underlying(), retInitVal, errorInfo)
		case *types.Chan:
			if retInitVal {
				return "new Channel(1)" //waa: <" + l.LangType(t.(*types.Chan).Elem(), false, errorInfo) + ">(1)"
			}
			return "Channel" //was: <" + l.LangType(t.(*types.Chan).Elem(), false, errorInfo) + ">"
		case *types.Map:
			if retInitVal {
				k := t.(*types.Map).Key().Underlying()
				kv := l.LangType(k, true, errorInfo)
				e := t.(*types.Map).Elem().Underlying()
				ev := "null" // TODO review, required for encode/gob to stop recursion
				if _, isMap := e.(*types.Map); !isMap {
					ev = l.LangType(e, true, errorInfo)
				}
				return "new GOmap(" + kv + "," + ev + ")"
			}
			return "GOmap"
		case *types.Slice:
			if retInitVal {
				return "new Slice(Pointer.make(" +
					"Object.make(0)" +
					"),0,0,0," + "1" + arrayOffsetCalc(t.(*types.Slice).Elem().Underlying()) + ")"
			}
			return "Slice"
		case *types.Array:
			if retInitVal {
				return fmt.Sprintf("Object.make(%d)", haxeStdSizes.Sizeof(t))
			}
			return "Object"
		case *types.Struct:
			if retInitVal {
				return fmt.Sprintf("Object.make(%d)", haxeStdSizes.Sizeof(t.(*types.Struct).Underlying()))
			}
			return "Object"
		case *types.Tuple: // what is returned by a call and some other instructions, not in the Go language spec!
			tup := t.(*types.Tuple)
			switch tup.Len() {
			case 0:
				return ""
			case 1:
				return l.LangType(tup.At(0).Type().Underlying(), retInitVal, errorInfo)
			default:
				ret := "{"
				for ele := 0; ele < tup.Len(); ele++ {
					if ele != 0 {
						ret += ","
					}
					ret += pogo.MakeID("r"+fmt.Sprintf("%d", ele)) + ":"
					if !retInitVal {
						ret += "Null<"
					}
					ret += l.LangType(tup.At(ele).Type().Underlying(), retInitVal, errorInfo)
					if !retInitVal {
						ret += ">"
					}
				}
				return ret + "}"
			}
		case *types.Pointer:
			if retInitVal {
				// NOTE pointer declarations create endless recursion for self-referencing structures unless initialized with null
				return "null" //rather than: + l.LangType(t.(*types.Pointer).Elem(), retInitVal, errorInfo) + ")"
			}
			return "Pointer"
		case *types.Signature:
			if retInitVal {
				return "null"
			}
			ret := "Closure"
			return ret
		default:
			rTyp := reflect.TypeOf(t).String()
			if rTyp == "*ssa.opaqueType" { // NOTE the type for map itterators, not in the Go language spec!
				if retInitVal { // use dynamic type, brief tests seem OK, but may not always work on static hosts
					return "null"
				}
				return "Dynamic"
			}
			pogo.LogError(errorInfo, "Haxe",
				fmt.Errorf("haxe.LangType() internal error, unhandled non-basic type: %s", rTyp))
		}
	}
	return "UNKNOWN_LANGTYPE" // this should generate a Haxe compiler error
}