public static StackValue Coerce(StackValue sv, Type targetType, RuntimeCore runtimeCore) { ProtoCore.Runtime.RuntimeMemory rmem = runtimeCore.RuntimeMemory; //@TODO(Jun): FIX ME - abort coersion for default args if (sv.IsDefaultArgument) return sv; if (!( sv.metaData.type == targetType.UID || (runtimeCore.DSExecutable.classTable.ClassNodes[sv.metaData.type].ConvertibleTo(targetType.UID)) || sv.IsArray)) { runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kConversionNotPossible, Resources.kConvertNonConvertibleTypes); return StackValue.Null; } //if it's an array if (sv.IsArray && !targetType.IsIndexable) { //This is an array rank reduction //this may only be performed in recursion and is illegal here string errorMessage = String.Format(Resources.kConvertArrayToNonArray, runtimeCore.DSExecutable.TypeSystem.GetType(targetType.UID)); runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kConversionNotPossible, errorMessage); return StackValue.Null; } if (sv.IsArray && targetType.IsIndexable) { Validity.Assert(sv.IsArray); //We're being asked to convert an array into an array //walk over the structure converting each othe elements //Validity.Assert(targetType.rank != -1, "Arbitrary rank array conversion not yet implemented {2EAF557F-62DE-48F0-9BFA-F750BBCDF2CB}"); //Decrease level of reductions by one Type newTargetType = new Type(); newTargetType.UID = targetType.UID; if (targetType.rank != Constants.kArbitraryRank) { newTargetType.rank = targetType.rank - 1; } else { if (ArrayUtils.GetMaxRankForArray(sv, runtimeCore) == 1) { //Last unpacking newTargetType.rank = 0; } else { newTargetType.rank = Constants.kArbitraryRank; } } var array = runtimeCore.Heap.ToHeapObject<DSArray>(sv); return array.CopyArray(newTargetType, runtimeCore); } if (!sv.IsArray && !sv.IsNull && targetType.IsIndexable && targetType.rank != DSASM.Constants.kArbitraryRank) { //We're being asked to promote the value into an array if (targetType.rank == 1) { Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.Name = targetType.Name; newTargetType.rank = 0; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, runtimeCore); StackValue newSv = rmem.Heap.AllocateArray(new StackValue[] { coercedValue }); return newSv; } else { Validity.Assert(targetType.rank > 1, "Target rank should be greater than one for this clause"); Type newTargetType = new Type(); newTargetType.UID = targetType.UID; newTargetType.Name = targetType.Name; newTargetType.rank = targetType.rank - 1; //Upcast once StackValue coercedValue = Coerce(sv, newTargetType, runtimeCore); StackValue newSv = rmem.Heap.AllocateArray(new StackValue[] { coercedValue }); return newSv; } } if (sv.IsPointer) { StackValue ret = ClassCoerece(sv, targetType, runtimeCore); return ret; } //If it's anything other than array, just create a new copy switch (targetType.UID) { case (int)PrimitiveType.kInvalidType: runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kInvalidType, Resources.kInvalidType); return StackValue.Null; case (int)PrimitiveType.kTypeBool: return sv.ToBoolean(runtimeCore); case (int)PrimitiveType.kTypeChar: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeChar }; return newSV; } case (int)PrimitiveType.kTypeDouble: return sv.ToDouble(); case (int)PrimitiveType.kTypeFunctionPointer: if (sv.metaData.type != (int)PrimitiveType.kTypeFunctionPointer) { runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kTypeMismatch, Resources.kFailToConverToFunction); return StackValue.Null; } return sv; case (int)PrimitiveType.kTypeInt: { if (sv.metaData.type == (int)PrimitiveType.kTypeDouble) { //TODO(lukechurch): Once the API is improved (MAGN-5174) //Replace this with a log entry notification //core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kTypeConvertionCauseInfoLoss, Resources.kConvertDoubleToInt); } return sv.ToInteger(); } case (int)PrimitiveType.kTypeNull: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kTypeMismatch, Resources.kFailToConverToNull); return StackValue.Null; } return sv; } case (int)PrimitiveType.kTypePointer: { if (sv.metaData.type != (int)PrimitiveType.kTypeNull) { runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.kTypeMismatch, Resources.kFailToConverToPointer); return StackValue.Null; } return sv; } case (int)PrimitiveType.kTypeString: { StackValue newSV = sv.ShallowClone(); newSV.metaData = new MetaData { type = (int)PrimitiveType.kTypeString }; if (sv.metaData.type == (int)PrimitiveType.kTypeChar) { char ch = EncodingUtils.ConvertInt64ToCharacter(newSV.opdata); newSV = StackValue.BuildString(ch.ToString(), rmem.Heap); } return newSV; } case (int)PrimitiveType.kTypeVar: { return sv; } case (int)PrimitiveType.kTypeArray: { var array = runtimeCore.Heap.ToHeapObject<DSArray>(sv); return array.CopyArray(targetType, runtimeCore); } default: if (sv.IsNull) return StackValue.Null; else throw new NotImplementedException("Requested coercion not implemented"); } throw new NotImplementedException("Requested coercion not implemented"); }