diff options
Diffstat (limited to 'src/CompilerServices/CompilerServices.cs')
| -rw-r--r-- | src/CompilerServices/CompilerServices.cs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index 16ad5d8e..de49d32d 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Xml; +using Crow.IML; namespace Crow @@ -665,6 +666,135 @@ namespace Crow return Activator.CreateInstance (dstType); return null; } + public static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){ + if (orig.Count < dest.Count) { + for (int i = orig.Count - 1; i < dest.Count - 1; i++) + emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); + } else { + for (int j = dest.Count; j < orig.Count; j++) + il.Emit (OpCodes.Callvirt, typeof(ILayoutable).GetProperty ("Parent").GetGetMethod ()); + } + } + public static void emitGetInstance (ILGenerator il, NodeAddress dest){ + for (int i = 0; i < dest.Count - 1; i++) + emitGetChild (il, dest [i].CrowType, dest [i + 1].Index); + } + public static void emitGetChild(ILGenerator il, Type parentType, int index){ + if (typeof (Group).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic)); + il.Emit(OpCodes.Ldc_I4, index); + il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) })); + return; + } + if (typeof(Container).IsAssignableFrom (parentType) || index < 0) { + il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic)); + return; + } + if (typeof(TemplatedContainer).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ()); + return; + } + if (typeof(TemplatedGroup).IsAssignableFrom (parentType)) { + il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ()); + il.Emit(OpCodes.Ldc_I4, index); + il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) })); + return; + } + } + /// <summary> + /// Emit conversion from orig type to dest type + /// </summary> + public static void emitConvert(ILGenerator il, Type origType, Type destType){ + if (destType == typeof(string)) + il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); + else if (origType.IsValueType) { + if (destType != origType) { + il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType)); + }else + il.Emit (OpCodes.Unbox_Any, destType);//TODO:double check this + } else { + if (origType.IsAssignableFrom(destType)) + il.Emit (OpCodes.Castclass, destType); + else { + MethodInfo miIO = getImplicitOp (origType, destType); + if (miIO != null) + il.Emit (OpCodes.Callvirt, miIO); + } + } + } + /// <summary> + /// check type of current object on the stack and convert to dest type, + /// use loc_0 so store it as object!!! + /// </summary> + public static void emitConvert(ILGenerator il, Type dstType){ + System.Reflection.Emit.Label endConvert = il.DefineLabel (); + System.Reflection.Emit.Label convert = il.DefineLabel (); + + il.Emit (OpCodes.Dup); + il.Emit (OpCodes.Isinst, dstType); + il.Emit (OpCodes.Brfalse, convert); + + if (dstType.IsValueType) + il.Emit (OpCodes.Unbox_Any, dstType); + else + il.Emit (OpCodes.Isinst, dstType); + il.Emit (OpCodes.Br, endConvert); + + il.MarkLabel (convert); + + if (dstType == typeof(string)) { + il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString); + } else if (dstType.IsPrimitive) { + //il.Emit (OpCodes.Unbox_Any, dstType); + il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (dstType)); + } else if (dstType.IsValueType) { + il.Emit (OpCodes.Unbox_Any, dstType); + } else{ + il.Emit (OpCodes.Stloc_0); //save orig value in loc0 + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Callvirt, typeof(object).GetMethod ("GetType")); + il.Emit (OpCodes.Ldtoken, dstType);//push destination property type for testing + il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle); + il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.Public)); + il.Emit (OpCodes.Dup); + convert = il.DefineLabel (); + il.Emit (OpCodes.Brtrue, convert); + il.Emit (OpCodes.Pop); + il.Emit (OpCodes.Ldloc_0); + il.Emit (OpCodes.Isinst, dstType); + il.Emit (OpCodes.Br, endConvert); + + il.MarkLabel (convert); + il.Emit (OpCodes.Ldnull);//null instance for invoke + il.Emit (OpCodes.Ldc_I4_1); + il.Emit(OpCodes.Newarr, typeof(object)); + il.Emit (OpCodes.Dup);//duplicate the array ref + il.Emit (OpCodes.Ldc_I4_0);//push the index 0 + il.Emit (OpCodes.Ldloc_0);//push the orig value to convert + il.Emit (OpCodes.Stelem, typeof(object));//set the array element at index 0 + il.Emit (OpCodes.Callvirt, typeof(MethodInfo).GetMethod("Invoke", new Type[] { typeof(object), typeof (object[])})); + } + + il.MarkLabel (endConvert); + } + /// <summary> + /// search for an implicit conversion method in origine or destination classes + /// </summary> + public static MethodInfo getImplicitOp(Type origType, Type dstType){ + foreach(MethodInfo mi in origType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ + if (mi.Name == "op_Implicit") { + if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) + return mi; + } + } + foreach(MethodInfo mi in dstType.GetMethods(BindingFlags.Public|BindingFlags.Static)){ + if (mi.Name == "op_Implicit") { + if (mi.ReturnType == dstType && mi.GetParameters ().FirstOrDefault ().ParameterType == origType) + return mi; + } + } + return null; + } } } |