private static void ExplCheck(IScriptCodeGen scg, Token errorAt, bool explicitAllowed, string oldString, string newString) { if (!explicitAllowed) { scg.ErrorMsg(errorAt, "must explicitly cast from " + oldString + " to " + newString); } }
private static void TypeCastInteger2Bool(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0); scg.ilGen.Emit(errorAt, OpCodes.Ceq); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1); scg.ilGen.Emit(errorAt, OpCodes.Xor); }
private static void TypeCastFloat2Bool(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Ldc_R4, 0.0f); scg.ilGen.Emit(errorAt, OpCodes.Ceq); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_1); scg.ilGen.Emit(errorAt, OpCodes.Xor); }
private static void TypeCastList2Object(IScriptCodeGen scg, Token errorAt) { if (typeof(LSL_List).IsValueType) { scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(LSL_List)); } }
private static void TypeCastObject2List(IScriptCodeGen scg, Token errorAt) { if (typeof(LSL_List).IsValueType) { scg.ilGen.Emit(errorAt, OpCodes.Call, objectToListMethodInfo); } else { scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(LSL_List)); } }
/** * @brief If caller wants the unwrapped value on stack wrapped LSL-style, wrap it. */ private static void LSLWrap(IScriptCodeGen scg, Token errorAt, TokenType type) { if (type.ToLSLWrapType() == typeof(LSL_Float)) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslFloatConstructorInfo); } if (type.ToLSLWrapType() == typeof(LSL_Integer)) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslIntegerConstructorInfo); } if (type.ToLSLWrapType() == typeof(LSL_String)) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, lslStringConstructorInfo); } }
/** * @brief If value on the stack is an LSL-style wrapped value, unwrap it. */ public static void LSLUnwrap(IScriptCodeGen scg, Token errorAt, TokenType type) { if (type.ToLSLWrapType() == typeof(LSL_Float)) { scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo); } if (type.ToLSLWrapType() == typeof(LSL_Integer)) { scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo); } if (type.ToLSLWrapType() == typeof(LSL_String)) { scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslStringValueFieldInfo); } }
private static void TypeCastInteger2Float(IScriptCodeGen scg, Token errorAt) { if (typeof(double) == typeof(float)) { scg.ilGen.Emit(errorAt, OpCodes.Conv_R4); } else if (typeof(double) == typeof(double)) { scg.ilGen.Emit(errorAt, OpCodes.Conv_R8); } else { throw new Exception("unknown type"); } }
private static void TypeCastVector2Object(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(LSL_Vector)); }
private static void TypeCastString2Object(IScriptCodeGen scg, Token errorAt) { }
private static void TypeCastString2Vector(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, vectorConstrucorStringInfo); }
private static void TypeCastBool2Integer(IScriptCodeGen scg, Token errorAt) { }
private static void TypeCastObject2Vector(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, objectToVectorMethodInfo); }
private static void TypeCastFloat2Integer(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Conv_I4); }
private static void TypeCastObject2Exc(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(Exception)); }
/** * @brief Emit code that converts the top stack item from 'oldType' to 'newType' * @param scg = what script we are compiling * @param errorAt = token used for source location for error messages * @param oldType = type of item currently on the stack * @param newType = type to convert it to * @param explicitAllowed = false: only consider implicit casts * true: consider both implicit and explicit casts * @returns with code emitted for conversion (or error message output if not allowed, and stack left unchanged) */ public static void CastTopOfStack(IScriptCodeGen scg, Token errorAt, TokenType oldType, TokenType newType, bool explicitAllowed) { CastDelegate castDelegate; string oldString = oldType.ToString(); string newString = newType.ToString(); // 'key' -> 'bool' is the only time we care about key being different than string. if ((oldString == "key") && (newString == "bool")) { LSLUnwrap(scg, errorAt, oldType); scg.ilGen.Emit(errorAt, OpCodes.Call, keyToBoolMethodInfo); LSLWrap(scg, errorAt, newType); return; } // Treat key and string as same type for all other type casts. if (oldString == "key") { oldString = "string"; } if (newString == "key") { newString = "string"; } // If the types are the same, there is no conceptual casting needed. // However, there may be wraping/unwraping to/from the LSL wrappers. if (oldString == newString) { if (oldType.ToLSLWrapType() != newType.ToLSLWrapType()) { LSLUnwrap(scg, errorAt, oldType); LSLWrap(scg, errorAt, newType); } return; } // Script-defined classes can be cast up and down the tree. if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeClass)) { TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl; TokenDeclSDTypeClass newSDTC = ((TokenTypeSDTypeClass)newType).decl; // implicit cast allowed from leaf toward root for (TokenDeclSDTypeClass sdtc = oldSDTC; sdtc != null; sdtc = sdtc.extends) { if (sdtc == newSDTC) { return; } } // explicit cast allowed from root toward leaf for (TokenDeclSDTypeClass sdtc = newSDTC; sdtc != null; sdtc = sdtc.extends) { if (sdtc == oldSDTC) { ExplCheck(scg, errorAt, explicitAllowed, oldString, newString); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, newSDTC.sdTypeIndex); scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo); return; } } // not on same branch goto illcast; } // One script-defined interface type cannot be cast to another script-defined interface type, // unless the old interface declares that it implements the new interface. That proves that // the underlying object, no matter what type, implements the new interface. if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeInterface)) { TokenDeclSDTypeInterface oldDecl = ((TokenTypeSDTypeInterface)oldType).decl; TokenDeclSDTypeInterface newDecl = ((TokenTypeSDTypeInterface)newType).decl; if (!oldDecl.Implements(newDecl)) { goto illcast; } scg.ilGen.Emit(errorAt, OpCodes.Ldstr, newType.ToString()); scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo); return; } // A script-defined class type can be implicitly cast to a script-defined interface type that it // implements. The result is an array of delegates that give the class's implementation of the // various methods defined by the interface. if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeInterface)) { TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl; int intfIndex; if (!oldSDTC.intfIndices.TryGetValue(newType.ToString(), out intfIndex)) { goto illcast; } scg.ilGen.Emit(errorAt, OpCodes.Ldfld, sdtcITableFieldInfo); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, intfIndex); scg.ilGen.Emit(errorAt, OpCodes.Ldelem, typeof(Delegate[])); return; } // A script-defined interface type can be explicitly cast to a script-defined class type by // extracting the Target property from element 0 of the delegate array that is the interface // object and making sure it casts to the correct script-defined class type. // // But then only if the class type implements the interface type. if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeClass)) { TokenTypeSDTypeInterface oldSDTI = (TokenTypeSDTypeInterface)oldType; TokenTypeSDTypeClass newSDTC = (TokenTypeSDTypeClass)newType; if (!newSDTC.decl.CanCastToIntf(oldSDTI.decl)) { goto illcast; } ExplCheck(scg, errorAt, explicitAllowed, oldString, newString); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, newSDTC.decl.sdTypeIndex); scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastIFace2ClassMethodInfo); return; } // A script-defined interface type can be implicitly cast to object. if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeObject)) { return; } // An object can be explicitly cast to a script-defined interface. if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeInterface)) { ExplCheck(scg, errorAt, explicitAllowed, oldString, newString); scg.ilGen.Emit(errorAt, OpCodes.Ldstr, newString); scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo); return; } // Cast to void is always allowed, such as discarding value from 'i++' or function return value. if (newType is TokenTypeVoid) { scg.ilGen.Emit(errorAt, OpCodes.Pop); return; } // Cast from undef to object or script-defined type is always allowed. if ((oldType is TokenTypeUndef) && ((newType is TokenTypeObject) || (newType is TokenTypeSDTypeClass) || (newType is TokenTypeSDTypeInterface))) { return; } // Script-defined classes can be implicitly cast to objects. if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeObject)) { return; } // Script-defined classes can be explicitly cast from objects and other script-defined classes. // Note that we must manually check that it is the correct SDTypeClass however because as far as // mono is concerned, all SDTypeClass's are the same. if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeClass)) { ExplCheck(scg, errorAt, explicitAllowed, oldString, newString); scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, ((TokenTypeSDTypeClass)newType).decl.sdTypeIndex); scg.ilGen.Emit(errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo); return; } // Delegates can be implicitly cast to/from objects. if ((oldType is TokenTypeSDTypeDelegate) && (newType is TokenTypeObject)) { return; } if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeDelegate)) { scg.ilGen.Emit(errorAt, OpCodes.Castclass, newType.ToSysType()); return; } // Some actual conversion is needed, see if it is in table of legal casts. string key = oldString + " " + newString; if (!legalTypeCasts.TryGetValue(key, out castDelegate)) { key = oldString + "*" + newString; if (!legalTypeCasts.TryGetValue(key, out castDelegate)) { goto illcast; } ExplCheck(scg, errorAt, explicitAllowed, oldString, newString); } // Ok, output cast. But make sure it is in native form without any LSL wrapping // before passing to our casting routine. Then if caller is expecting an LSL- // wrapped value on the stack upon return, wrap it up after our casting. LSLUnwrap(scg, errorAt, oldType); castDelegate(scg, errorAt); LSLWrap(scg, errorAt, newType); return; illcast: scg.ErrorMsg(errorAt, "illegal to cast from " + oldString + " to " + newString); if (!(oldType is TokenTypeVoid)) { scg.ilGen.Emit(errorAt, OpCodes.Pop); } scg.PushDefaultValue(newType); }
private static void TypeCastObject2Array(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Castclass, typeof(XMR_Array)); }
private static void TypeCastString2Float(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, floatConstructorStringInfo); scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo); }
private static void TypeCastString2List(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, stringToListMethodInfo); }
private static void TypeCastInteger2Char(IScriptCodeGen scg, Token errorAt) { }
private static void TypeCastBool2Object(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(bool)); }
private static void TypeCastFloat2Object(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(double)); }
private static void TypeCastInteger2List(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, integerToListMethodInfo); }
private static void TypeCastObject2Char(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Unbox_Any, typeof(char)); }
private static void TypeCastRotation2String(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, rotationToStringMethodInfo); }
private static void TypeCastExc2String(IScriptCodeGen scg, Token errorAt) { scg.PushXMRInst(); scg.ilGen.Emit(errorAt, OpCodes.Call, excToStringMethodInfo); }
private static void TypeCastString2Integer(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Newobj, integerConstructorStringInfo); scg.ilGen.Emit(errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo); }
private static void TypeCastInteger2Object(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Box, typeof(int)); }
private static void TypeCastVector2String(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, vectorToStringMethodInfo); }
private static void TypeCastList2Bool(IScriptCodeGen scg, Token errorAt) { scg.ilGen.Emit(errorAt, OpCodes.Call, listToBoolMethodInfo); }