示例#1
0
// FuncPathName returns a unique function path and name.
func (comp *Compilation) FuncPathName(fn *ssa.Function) (path, name string) {
	rx := fn.Signature.Recv()
	pf := tgoutil.MakeID(comp.rootProgram.Fset.Position(fn.Pos()).String()) //fmt.Sprintf("fn%d", fn.Pos())
	if rx != nil {                                                          // it is not the name of a normal function, but that of a method, so append the method description
		pf = rx.Type().String() // NOTE no underlying()
	} else {
		if fn.Pkg != nil {
			pf = fn.Pkg.Object.Path() // was .Name(), but not unique
		} else {
			goroot := tgoutil.MakeID(LanguageList[comp.TargetLang].GOROOT + string(os.PathSeparator))
			pf1 := strings.Split(pf, goroot) // make auto-generated names shorter
			if len(pf1) == 2 {
				pf = pf1[1]
			} // TODO use GOPATH for names not in std pkgs
		}
	}
	return pf, fn.Name()
}
示例#2
0
// Handle an individual instruction.
func (comp *Compilation) emitInstruction(instruction interface{}, operands []*ssa.Value) (emitPhiFlag bool) {
	l := comp.TargetLang
	emitPhiFlag = true
	errorInfo := ""
	_, isDebug := instruction.(*ssa.DebugRef)
	if !isDebug { // Don't update the code position for debug refs
		prev := comp.LatestValidPosHash
		comp.MakePosHash(instruction.(ssa.Instruction).Pos()) // this so that we log the nearby position info
		if prev != comp.LatestValidPosHash {                  // new info, so put out an update
			if comp.DebugFlag { // but only in Debug mode
				fmt.Fprintln(&LanguageList[l].buffer,
					LanguageList[l].SetPosHash())
			}
		}
		errorInfo = comp.CodePosition(instruction.(ssa.Instruction).Pos())
	}
	if errorInfo == "" {
		errorInfo = comp.previousErrorInfo
	} else {
		comp.previousErrorInfo = "near " + errorInfo
		errorInfo = "@ " + errorInfo
	}
	errorInfo = reflect.TypeOf(instruction).String() + " " + errorInfo //TODO consider removing as for DEBUG only
	instrVal, hasVal := instruction.(ssa.Value)
	register := ""
	comment := ""
	if hasVal {
		register = comp.RegisterName(instrVal)
		comment = fmt.Sprintf("%s = %+v %s", register, instruction, errorInfo)
		//emitComment(comment)
		switch len(*instruction.(ssa.Value).Referrers()) {
		case 0: // no other instruction uses the result of this one
			comment += " [REGISTER VALUE UN-USED]"
			register = ""
		case 1: // only 1 other use of the register
			// TODO register optimisation currently disabled, consider reimplimentation
			user := (*instruction.(ssa.Value).Referrers())[0]
			if user.Block() == instruction.(ssa.Instruction).Block() {
				comment += " [REGISTER MAY BE OPTIMIZABLE]"
			}
		default: //multiple usage of the register
		}
		if len(register) > 0 {
			if LanguageList[comp.TargetLang].LangType(instruction.(ssa.Value).Type(), false, errorInfo) == "" { // NOTE an empty type def makes a register useless too
				register = ""
			}
		}
	} else {
		comment = fmt.Sprintf("%+v %s", instruction, errorInfo)
		//emitComment(comment)
	}
	switch instruction.(type) {
	case *ssa.Jump:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Jump(instruction.(*ssa.Jump).Block().Succs[0].Index,
				instruction.(*ssa.Jump).Block().Index,
				LanguageList[l].PhiCode(false, instruction.(*ssa.Jump).Block().Index,
					instruction.(*ssa.Jump).Block().Succs[0].Instrs,
					errorInfo))+
				LanguageList[l].Comment(comment))

	case *ssa.If:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].If(*operands[0],
				instruction.(*ssa.If).Block().Succs[0].Index,
				instruction.(*ssa.If).Block().Succs[1].Index,
				instruction.(*ssa.If).Block().Index,
				LanguageList[l].PhiCode(false, instruction.(*ssa.If).Block().Index,
					instruction.(*ssa.If).Block().Succs[0].Instrs, errorInfo),
				LanguageList[l].PhiCode(false, instruction.(*ssa.If).Block().Index,
					instruction.(*ssa.If).Block().Succs[1].Instrs, errorInfo),
				errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Phi:
		text := ""
		if len(*instruction.(*ssa.Phi).Referrers()) > 0 {
			phiEntries := make([]int, len(operands))
			valEntries := make([]interface{}, len(operands))
			for o := range operands {
				phiEntries[o] = instruction.(*ssa.Phi).Block().Preds[o].Index
				valEntries[o] = *operands[o]
			}
			text = LanguageList[l].Phi(register, phiEntries, valEntries,
				LanguageList[l].LangType(instrVal.Type(), true, errorInfo), errorInfo)
		}
		fmt.Fprintln(&LanguageList[l].buffer, text+LanguageList[l].Comment(comment))

	case *ssa.Call:
		if instruction.(*ssa.Call).Call.IsInvoke() {
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].EmitInvoke(register, getFnPath(instruction.(*ssa.Call).Parent()),
					false, false, comp.grMap[instruction.(*ssa.Call).Parent()],
					instruction.(*ssa.Call).Call, errorInfo)+LanguageList[l].Comment(comment))
		} else {
			switch instruction.(*ssa.Call).Call.Value.(type) {
			case *ssa.Builtin:
				comp.emitCall(true, false, false, comp.grMap[instruction.(*ssa.Call).Parent()],
					register, instruction.(*ssa.Call).Call, errorInfo, comment)
			default:
				comp.emitCall(false, false, false, comp.grMap[instruction.(*ssa.Call).Parent()],
					register, instruction.(*ssa.Call).Call, errorInfo, comment)
			}
		}

	case *ssa.Go:
		if instruction.(*ssa.Go).Call.IsInvoke() {
			if comp.grMap[instruction.(*ssa.Go).Parent()] != true {
				panic("attempt to Go a method, from a function that does not use goroutines at " + errorInfo)
			}
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].EmitInvoke(register, getFnPath(instruction.(*ssa.Go).Parent()),
					true, false, true, instruction.(*ssa.Go).Call, errorInfo)+
					LanguageList[l].Comment(comment))
		} else {
			switch instruction.(*ssa.Go).Call.Value.(type) {
			case *ssa.Builtin: // no builtin functions can be go'ed
				comp.LogError(errorInfo, "pogo", fmt.Errorf("builtin functions cannot be go'ed"))
			default:
				if comp.grMap[instruction.(*ssa.Go).Parent()] != true {
					panic("attempt to Go a function, from a function does not use goroutines at " + errorInfo)
				}
				comp.emitCall(false, true, false, true,
					register, instruction.(*ssa.Go).Call, errorInfo, comment)
			}
		}

	case *ssa.Defer:
		if instruction.(*ssa.Defer).Call.IsInvoke() {
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].EmitInvoke(register,
					getFnPath(instruction.(*ssa.Defer).Parent()),
					false, true, comp.grMap[instruction.(*ssa.Defer).Parent()],
					instruction.(*ssa.Defer).Call, errorInfo)+
					LanguageList[l].Comment(comment))
		} else {
			switch instruction.(*ssa.Defer).Call.Value.(type) {
			case *ssa.Builtin: // no builtin functions can be defer'ed - TODO: the spec does allow this in some circumstances
				switch instruction.(*ssa.Defer).Call.Value.(*ssa.Builtin).Name() {
				case "close":
					//LogError(errorInfo, "pogo", fmt.Errorf("builtin function close() cannot be defer'ed"))
					comp.emitCall(true, false, true, comp.grMap[instruction.(*ssa.Defer).Parent()],
						register, instruction.(*ssa.Defer).Call, errorInfo, comment)
				default:
					comp.LogError(errorInfo, "pogo", fmt.Errorf("builtin functions cannot be defer'ed"))
				}
			default:
				comp.emitCall(false, false, true, comp.grMap[instruction.(*ssa.Defer).Parent()],
					register, instruction.(*ssa.Defer).Call, errorInfo, comment)
			}
		}

	case *ssa.Return:
		emitPhiFlag = false
		r := LanguageList[l].Ret(operands, errorInfo)
		fmt.Fprintln(&LanguageList[l].buffer, r+LanguageList[l].Comment(comment))

	case *ssa.Panic:
		emitPhiFlag = false
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Panic(*operands[0], errorInfo,
				comp.grMap[instruction.(*ssa.Panic).Parent()])+LanguageList[l].Comment(comment))

	case *ssa.UnOp:
		if register == "" && instruction.(*ssa.UnOp).Op.String() != "<-" {
			comp.emitComment(comment)
		} else {
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].UnOp(register, instrVal.Type(), instruction.(*ssa.UnOp).Op.String(), *operands[0],
					instruction.(*ssa.UnOp).CommaOk, errorInfo)+
					LanguageList[l].Comment(comment))
		}

	case *ssa.BinOp:
		if register == "" {
			comp.emitComment(comment)
		} else {
			op := instruction.(*ssa.BinOp).Op.String()
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].BinOp(register, instrVal.Type(), op, *operands[0], *operands[1], errorInfo)+
					LanguageList[l].Comment(comment))
		}

	case *ssa.Store:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Store(*operands[0], *operands[1], errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Send:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Send(*operands[0], *operands[1], errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Convert:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Convert(register, LanguageList[l].LangType(instrVal.Type(), false, errorInfo), instrVal.Type(), *operands[0], errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.ChangeType:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].ChangeType(register, instruction.(ssa.Value).Type(), *operands[0], errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.MakeInterface:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MakeInterface(register, instruction.(ssa.Value).Type(), *operands[0], errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.ChangeInterface:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].ChangeInterface(register, instruction.(ssa.Value).Type(), *operands[0], errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.TypeAssert:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].TypeAssert(register, instruction.(*ssa.TypeAssert).X,
				instruction.(*ssa.TypeAssert).AssertedType, instruction.(*ssa.TypeAssert).CommaOk, errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.RunDefers:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].RunDefers(comp.grMap[instruction.(*ssa.RunDefers).Parent()])+
				LanguageList[l].Comment(comment))

	case *ssa.Alloc:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Alloc(register, instruction.(*ssa.Alloc).Heap,
				instruction.(*ssa.Alloc).Type(), errorInfo)+
				LanguageList[l].Comment(instruction.(*ssa.Alloc).Comment+" "+comment))

	case *ssa.MakeClosure:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MakeClosure(register,
				instruction,
				errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.MakeSlice:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MakeSlice(register,
				instruction,
				errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.MakeChan:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MakeChan(register,
				instruction,
				errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.MakeMap:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MakeMap(register,
				instruction,
				errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.MapUpdate:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].MapUpdate(*operands[0], *operands[1], *operands[2], errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Range:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Range(register, *operands[0], errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Next:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Next(register, *operands[0], instruction.(*ssa.Next).IsString,
				errorInfo)+LanguageList[l].Comment(comment))

	case *ssa.Lookup:
		fmt.Fprintln(&LanguageList[l].buffer,
			LanguageList[l].Lookup(register, *operands[0], *operands[1], instruction.(*ssa.Lookup).CommaOk, errorInfo)+
				LanguageList[l].Comment(comment))

	case *ssa.Extract:
		if register == "" { // rquired here because of a "feature" in the generated SSA form
			comp.emitComment(comment)
		} else {
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].Extract(register, *operands[0], instruction.(*ssa.Extract).Index, errorInfo)+
					LanguageList[l].Comment(comment))
		}

	case *ssa.Slice:
		// TODO see http://tip.golang.org/doc/go1.2#three_index
		// TODO add third parameter when SSA code provides it to enable slice instructions to specify a capacity
		if register == "" {
			comp.emitComment(comment)
		} else {
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].Slice(register, instruction.(*ssa.Slice).X,
					instruction.(*ssa.Slice).Low, instruction.(*ssa.Slice).High, errorInfo)+
					LanguageList[l].Comment(comment))

		}

	case *ssa.Index:
		if register == "" {
			comp.emitComment(comment)
		} else {
			doRangeCheck := true
			aLen := 0
			switch instruction.(*ssa.Index).X.Type().(type) {
			case *types.Array:
				aLen = int(instruction.(*ssa.Index).X.Type().(*types.Array).Len())
			case *types.Pointer:
				switch instruction.(*ssa.Index).X.Type().(*types.Pointer).Elem().(type) {
				case *types.Array:
					aLen = int(instruction.(*ssa.Index).X.Type().(*types.Pointer).Elem().(*types.Array).Len())
				}
			}
			if aLen > 0 {
				_, indexIsConst := instruction.(*ssa.Index).Index.(*ssa.Const)
				if indexIsConst {
					// this error handling is defensive, as the Go SSA code catches this error
					index := instruction.(*ssa.Index).Index.(*ssa.Const).Int64()
					if (index < 0) || (index >= int64(aLen)) {
						comp.LogError(errorInfo, "pogo", fmt.Errorf("index [%d] out of range: 0 to %d", index, aLen-1))
					}
					doRangeCheck = false
				}
			}
			if doRangeCheck {
				fmt.Fprintln(&LanguageList[l].buffer,
					LanguageList[l].RangeCheck(instruction.(*ssa.Index).X, instruction.(*ssa.Index).Index, aLen, errorInfo))
			}
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].Index(register, *operands[0], *operands[1], errorInfo)+
					LanguageList[l].Comment(comment))
		}

	case *ssa.IndexAddr:
		if register == "" {
			comp.emitComment(comment)
		} else {
			doRangeCheck := true
			aLen := 0
			switch instruction.(*ssa.IndexAddr).X.Type().(type) {
			case *types.Array:
				aLen = int(instruction.(*ssa.IndexAddr).X.Type().(*types.Array).Len())
			case *types.Pointer:
				switch instruction.(*ssa.IndexAddr).X.Type().(*types.Pointer).Elem().(type) {
				case *types.Array:
					aLen = int(instruction.(*ssa.IndexAddr).X.Type().(*types.Pointer).Elem().(*types.Array).Len())
				}
			}
			if aLen > 0 {
				_, indexIsConst := instruction.(*ssa.IndexAddr).Index.(*ssa.Const)
				if indexIsConst {
					index := instruction.(*ssa.IndexAddr).Index.(*ssa.Const).Int64()
					if (index < 0) || (index >= int64(aLen)) {
						comp.LogError(errorInfo, "pogo", fmt.Errorf("index [%d] out of range: 0 to %d", index, aLen-1))
					}
					doRangeCheck = false
				}
			}
			if doRangeCheck {
				fmt.Fprintln(&LanguageList[l].buffer,
					LanguageList[l].RangeCheck(instruction.(*ssa.IndexAddr).X, instruction.(*ssa.IndexAddr).Index, aLen, errorInfo)+
						LanguageList[l].Comment(comment+" [POINTER]"))
			}
			fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].IndexAddr(register, instruction, errorInfo),
				LanguageList[l].Comment(comment+" [POINTER]"))

		}

	case *ssa.FieldAddr:
		fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].FieldAddr(register, instruction, errorInfo),
			LanguageList[l].Comment(comment+" [POINTER]"))

	case *ssa.Field:
		if register == "" {
			comp.emitComment(comment)
		} else {
			st := instruction.(*ssa.Field).X.Type().Underlying().(*types.Struct)
			fName := tgoutil.MakeID(st.Field(instruction.(*ssa.Field).Field).Name())
			l := comp.TargetLang
			fmt.Fprintln(&LanguageList[l].buffer,
				LanguageList[l].Field(register, instruction.(*ssa.Field).X,
					instruction.(*ssa.Field).Field, fName, errorInfo, false)+
					LanguageList[l].Comment(comment))
		}

	case *ssa.DebugRef: // TODO the comment could include the actual Go code
		debugCode := ""
		ident, ok := instruction.(*ssa.DebugRef).Expr.(*ast.Ident)
		if ok {
			if ident.Obj != nil {
				if ident.Obj.Kind == ast.Var {
					//fmt.Printf("DEBUGref %s (%s) => %s %+v %+v %+v\n", instruction.(*ssa.DebugRef).X.Name(),
					//	instruction.(*ssa.DebugRef).X.Type().String(),
					//	ident.Name, ident.Obj.Decl, ident.Obj.Data, ident.Obj.Type)
					name := ident.Name
					glob, isGlob := instruction.(*ssa.DebugRef).X.(*ssa.Global)
					if isGlob {
						name = glob.Pkg.String()[len("package "):] + "." + name
					}
					debugCode = LanguageList[l].DebugRef(name, instruction.(*ssa.DebugRef).X, errorInfo)
				}
			}
		}
		fmt.Fprintln(&LanguageList[l].buffer, debugCode+LanguageList[l].Comment(comment))

	case *ssa.Select:
		text := LanguageList[l].Select(true, register, instruction, false, errorInfo)
		fmt.Fprintln(&LanguageList[l].buffer, text+LanguageList[l].Comment(comment))

	default:
		comp.emitComment(comment + " [NO CODE GENERATED]")
		comp.LogError(errorInfo, "pogo", fmt.Errorf("SSA instruction not implemented: %v", reflect.TypeOf(instruction)))
	}
	if false { //TODO add instruction detail DEBUG FLAG
		for o := range operands { // this loop for the creation of comments to show what is in the instructions
			val := *operands[o]
			vip := valIsPointer(val)
			if vip {
				vipOut := showIndirectValue(val)
				comp.emitComment(fmt.Sprintf("Op[%d].VIP: %+v", o, vipOut))
			} else {
				var ic interface{} = *operands[o]
				constVal, isConst := ic.(*ssa.Const)
				if isConst {
					comp.emitComment(fmt.Sprintf("Op[%d]: Constant= %+v", o, constVal))
				} else {
					comp.emitComment(fmt.Sprintf("Op[%d]: %v = %+v", o, (*operands[o]), val))
				}
			}
			// l := TargetLang
			// fmt.Fprintln(&LanguageList[l].buffer, LanguageList[l].Value(*operands[o], "TEST"))
		}
	}
	return // return value is named and set in the code above
}
示例#3
0
func (l langType) LangType(t types.Type, retInitVal bool, errorInfo string) string {
	if l.PogoComp().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:
				l.PogoComp().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 += tgoutil.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"
			}
			l.PogoComp().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
}
示例#4
0
package haxe

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"golang.org/x/tools/go/exact"
	"golang.org/x/tools/go/ssa"

	"github.com/tardisgo/tardisgo/tgoutil"
)

var pseudoFnPrefix = tgoutil.MakeID("github.com/tardisgo/tardisgo/haxe/hx_")

func (l langType) hxPseudoFuncs(fnToCall string, args []ssa.Value, errorInfo string) string {
	//fmt.Println("DEBUG l.hxPseudoFuncs()", fnToCall, args, errorInfo)
	fnToCall = strings.TrimPrefix(fnToCall, pseudoFnPrefix)

	switch fnToCall {
	case "SSource":
		fn := strings.Trim(args[0].(*ssa.Const).Value.String(), "\"")
		fn = l.hc.langEntry.TgtDir + string(os.PathSeparator) + fn + ".hx"
		code := strings.Trim(args[1].(*ssa.Const).Value.String(), "\"")
		code = strings.Replace(code, "\\n", "\n", -1)
		code = strings.Replace(code, "\\t", "\t", -1)
		code = strings.Replace(code, "\\\"", "\"", -1)
		//println("DEBUG fn: " + fn + "\nCode: " + code)
		err := ioutil.WriteFile(fn, []byte(code), 0666)