From 2b9e8c8dbbe55a2297340deb2fd685bbf881e153 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jean-Philippe=20Bruy=C3=A8re?= Date: Fri, 20 Jan 2017 08:16:44 +0100 Subject: [PATCH] code clean and comment --- src/CompilerServices/CompilerServices.cs | 277 ++++++++++++++++++----- src/GraphicObjects/GraphicObject.cs | 3 +- src/Instantiator.cs | 16 +- 3 files changed, 226 insertions(+), 70 deletions(-) diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index e2c657ce..9ddf9991 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -32,15 +32,15 @@ namespace Crow internal static MethodInfo miGetColCount = typeof(System.Collections.ICollection).GetProperty("Count").GetGetMethod(); internal static MethodInfo miGetDelegateListItem = typeof(List).GetMethod("get_Item", new Type[] { typeof(Int32) }); - internal static MethodInfo miCompileDynEventHandler = typeof(CompilerServices).GetMethod ("compileDynEventHandler", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miRemEvtHdlByName = typeof(CompilerServices).GetMethod("RemoveEventHandlerByName", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miRemEvtHdlByTarget = typeof(CompilerServices).GetMethod("RemoveEventHandlerByTarget", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miGetMethInfoWithRefx = typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miGetMembIinfoWithRefx = typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miSetValWithRefx = typeof(CompilerServices).GetMethod("setValueWithReflexion", BindingFlags.Static | BindingFlags.Public); - internal static MethodInfo miGetValWithRefx = typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.Public); + internal static MethodInfo miCompileDynEventHandler = typeof(CompilerServices).GetMethod ("compileDynEventHandler", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miRemEvtHdlByName = typeof(CompilerServices).GetMethod("removeEventHandlerByName", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miRemEvtHdlByTarget = typeof(CompilerServices).GetMethod("removeEventHandlerByTarget", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miGetMethInfoWithRefx = typeof(CompilerServices).GetMethod ("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miGetMembIinfoWithRefx = typeof(CompilerServices).GetMethod("getMemberInfoWithReflexion", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miSetValWithRefx = typeof(CompilerServices).GetMethod("setValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic); + internal static MethodInfo miGetValWithRefx = typeof(CompilerServices).GetMethod("getValueWithReflexion", BindingFlags.Static | BindingFlags.NonPublic); internal static MethodInfo miCreateDel = typeof(CompilerServices).GetMethod ("createDel", BindingFlags.Static | BindingFlags.NonPublic); - internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.Public); + internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.NonPublic); internal static FieldInfo fiCachedDel = typeof(Instantiator).GetField("cachedDelegates", BindingFlags.Instance | BindingFlags.NonPublic); internal static FieldInfo fiTemplateBinding = typeof(Instantiator).GetField("templateBinding", BindingFlags.Instance | BindingFlags.NonPublic); @@ -236,32 +236,14 @@ namespace Crow } #endregion + #region Reflexion helpers /// - /// retrieve event handler in class or ancestors - /// - public static FieldInfo GetEventHandlerField (Type type, string eventName) - { - FieldInfo fi; - Type ty = type; - do { - fi = ty.GetField (eventName, - BindingFlags.NonPublic | - BindingFlags.Instance | - BindingFlags.GetField); - ty = ty.BaseType; - if (ty == null) - break; - } while (fi == null); - return fi; - } - - /// - /// Gets extension methods defined in assembley for extendedType + /// Gets all extension methods defined in assembly for Type /// /// Extension methods enumerable /// Assembly /// Extended type to search for - public static IEnumerable GetExtensionMethods (Assembly assembly, + internal static IEnumerable GetExtensionMethods (Assembly assembly, Type extendedType) { IEnumerable query = null; @@ -270,11 +252,11 @@ namespace Crow do { query = from type in assembly.GetTypes () where type.IsSealed && !type.IsGenericType && !type.IsNested - from method in type.GetMethods (BindingFlags.Static - | BindingFlags.Public | BindingFlags.NonPublic) + from method in type.GetMethods (BindingFlags.Static + | BindingFlags.Public | BindingFlags.NonPublic) where method.IsDefined (typeof (ExtensionAttribute), false) where method.GetParameters () [0].ParameterType == curType - select method; + select method; if (query.Count () > 0) break; @@ -284,8 +266,13 @@ namespace Crow return query; } - - public static MethodInfo SearchExtMethod(Type t, string methodName){ + /// + /// search for extentions method in entry assembly then in crow assembly + /// + /// Extention MethodInfo + /// Extended type + /// Extention method name + internal static MethodInfo SearchExtMethod(Type t, string methodName){ MethodInfo mi = null; mi = GetExtensionMethods (Assembly.GetEntryAssembly(), t) .Where (em => em.Name == methodName).FirstOrDefault (); @@ -295,17 +282,39 @@ namespace Crow return GetExtensionMethods (Assembly.GetExecutingAssembly(), t) .Where (em => em.Name == methodName).FirstOrDefault (); } + /// + /// retrieve event handler in class or ancestors + /// + static FieldInfo getEventHandlerField (Type type, string eventName) + { + FieldInfo fi; + Type ty = type; + do { + fi = ty.GetField (eventName, + BindingFlags.NonPublic | + BindingFlags.Instance | + BindingFlags.GetField); + ty = ty.BaseType; + if (ty == null) + break; + } while (fi == null); + return fi; + } + - public static MemberInfo getMemberInfoWithReflexion(object instance, string member){ - return instance.GetType ().GetMember (member).FirstOrDefault(); + static MemberInfo getMemberInfoWithReflexion(object instance, string member){ + return instance.GetType ().GetMember (member)?.FirstOrDefault(); } - public static MethodInfo getMethodInfoWithReflexion(object instance, string method){ + static MethodInfo getMethodInfoWithReflexion(object instance, string method){ return instance.GetType ().GetMethod (method, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); } - public static Type getEventHandlerType(object instance, string eventName){ - return instance.GetType ().GetEvent (eventName).EventHandlerType; - } - public static void setValueWithReflexion(object dest, object value, string destMember){ + /// + /// set value, convert if required + /// + /// Destination instance + /// Value + /// Destination member + static void setValueWithReflexion(object dest, object value, string destMember){ Type destType = null; Type origType = null; object convertedVal = null; @@ -337,7 +346,11 @@ namespace Crow else if (miDest.MemberType == MemberTypes.Field) (miDest as FieldInfo).SetValue (dest, convertedVal); } - public static object getValueWithReflexion(object instance, MemberInfo mi){ + /// + /// Gets value with reflexion, return empty string ("") for string and object and return + /// default value for valueType data. + /// + static object getValueWithReflexion(object instance, MemberInfo mi){ object tmp = null; Type dstType = null; if (mi == null) @@ -361,7 +374,12 @@ namespace Crow return null; } - public static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){ + #endregion + + /// + /// Emits tree parsing command to fetch dest instance starting from orig node + /// + internal static void emitGetInstance (ILGenerator il, NodeAddress orig, NodeAddress dest){ int ptr = 0; while (orig [ptr] == dest [ptr]) { ptr++; @@ -375,13 +393,24 @@ namespace Crow ptr++; } } - public static void emitGetInstance (ILGenerator il, NodeAddress dest){ + /// + /// Emits tree parsing commands to get child starting at root node + /// + /// MSIL generator + /// Absolute Node Address of the instance to get + internal static void emitGetInstance (ILGenerator il, NodeAddress dest){ if (dest == null) return; 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){ + /// + /// Emits msil to fetch chil instance of current GraphicObject on the stack + /// + /// Il generator + /// Parent type + /// Index of child, -1 for template root + internal static void emitGetChild(ILGenerator il, Type parentType, int index){ if (typeof (Group).IsAssignableFrom (parentType)) { il.Emit (OpCodes.Ldfld, fiChildren); il.Emit(OpCodes.Ldc_I4, index); @@ -404,9 +433,9 @@ namespace Crow } } /// - /// Emit conversion from orig type to dest type + /// Emit MSIL for conversion from orig type to dest type /// - public static void emitConvert(ILGenerator il, Type origType, Type destType){ + internal static void emitConvert(ILGenerator il, Type origType, Type destType){ if (destType == CompilerServices.TObject) return; if (destType == typeof(string)) { @@ -439,7 +468,7 @@ namespace Crow /// check type of current object on the stack and convert to dest type, /// use loc_0 so store it as object!!! /// - public static void emitConvert(ILGenerator il, Type dstType){ + internal static void emitConvert(ILGenerator il, Type dstType){ System.Reflection.Emit.Label endConvert = il.DefineLabel (); System.Reflection.Emit.Label convert = il.DefineLabel (); @@ -503,7 +532,7 @@ namespace Crow /// /// search for an implicit conversion method in origine or destination classes /// - public static MethodInfo getImplicitOp(Type origType, Type dstType){ + 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) @@ -521,9 +550,9 @@ namespace Crow /// /// Removes delegate from event handler by name /// - public static void RemoveEventHandlerByName(object instance, string eventName, string delegateName){ + static void removeEventHandlerByName(object instance, string eventName, string delegateName){ Type t = instance.GetType (); - FieldInfo fiEvt = CompilerServices.GetEventHandlerField (t, eventName); + FieldInfo fiEvt = getEventHandlerField (t, eventName); if (fiEvt == null) { Debug.WriteLine ("RemoveHandlerByName: Event '" + eventName + "' not found in " + instance); return; @@ -544,9 +573,9 @@ namespace Crow /// /// Removes delegate from event handler by searching for the object they are bond to /// - public static void RemoveEventHandlerByTarget(object instance, string eventName, object target){ + static void removeEventHandlerByTarget(object instance, string eventName, object target){ Type t = instance.GetType (); - FieldInfo fiEvt = CompilerServices.GetEventHandlerField (t, eventName); + FieldInfo fiEvt = getEventHandlerField (t, eventName); EventInfo eiEvt = t.GetEvent (eventName); MulticastDelegate multiDel = fiEvt.GetValue (instance) as MulticastDelegate; if (multiDel != null) { @@ -560,7 +589,10 @@ namespace Crow } } } - internal static Delegate createDel(Type eventType, object instance, string method){ + /// + /// create delegate helper + /// + static Delegate createDel(Type eventType, object instance, string method){ Type t = instance.GetType (); MethodInfo mi = t.GetMethod (method, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (mi == null) { @@ -569,7 +601,7 @@ namespace Crow } return Delegate.CreateDelegate (eventType, instance, mi); } - public static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){ + public static Delegate compileDynEventHandler2(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){ #if DEBUG_BINDING Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression); #endif @@ -596,6 +628,130 @@ namespace Crow string [] srcLines = expression.Trim ().Split (new char [] { ';' }); + foreach (string srcLine in srcLines) { + string statement = srcLine.Trim (); + + string [] operandes = statement.Split (new char [] { '=' }); + if (operandes.Length < 2) //not an affectation + { + //maybe we could handle here handler function name + continue; + } + + string rop = operandes [operandes.Length - 1].Trim (); + + #region LEFT OPERANDES + string [] lopParts = operandes [0].Trim ().Split ('.'); + MemberInfo lopMI = null; + + il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node + + if (lopParts.Length > 1) { + NodeAddress lopNA = getNodeAdressFromBindingExp (currentNode, lopParts); + CompilerServices.emitGetInstance (il, currentNode, lopNA); + lopType = lopNA.NodeType; + } + + string [] bindTrg = lopParts.Last().Split ('.'); + + if (bindTrg.Length == 1) + lopMI = lopType.GetMember (bindTrg [0]).FirstOrDefault(); + else if (bindTrg.Length == 2) { + //named target + //TODO: + il.Emit(OpCodes.Ldstr, bindTrg[0]); + il.Emit(OpCodes.Callvirt, miFindByName); + lopMI = lopType.GetMember (bindTrg [1]).FirstOrDefault(); + } else + throw new Exception ("Syntax error in binding, expected 'go dot member'"); + + + if (lopMI == null) + throw new Exception (string.Format ("IML BINDING: Member not found")); + + OpCode lopSetOpCode; + dynamic lopSetMI; + Type lopT = null; + switch (lopMI.MemberType) { + case MemberTypes.Property: + lopSetOpCode = OpCodes.Callvirt; + PropertyInfo lopPi = lopMI as PropertyInfo; + lopT = lopPi.PropertyType; + lopSetMI = lopPi.GetSetMethod (); + break; + case MemberTypes.Field: + lopSetOpCode = OpCodes.Stfld; + FieldInfo dstFi = lopMI as FieldInfo; + lopT = dstFi.FieldType; + lopSetMI = dstFi; + break; + default: + throw new Exception (string.Format ("GOML:member type not handle")); + } + #endregion + + #region RIGHT OPERANDES + if (rop.StartsWith ("\'")) { + if (!rop.EndsWith ("\'")) + throw new Exception (string.Format + ("GOML:malformed string constant in handler: {0}", rop)); + string strcst = rop.Substring (1, rop.Length - 2); + + il.Emit (OpCodes.Ldstr, strcst); + + }else if (rop.StartsWith ("this",StringComparison.OrdinalIgnoreCase)){ + il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack + } else { + if (lopT.IsEnum) + throw new NotImplementedException (); + + MethodInfo lopParseMi = lopT.GetMethod ("Parse"); + if (lopParseMi == null) + throw new Exception (string.Format + ("GOML:no parse method found in: {0}", lopT.Name)); + il.Emit (OpCodes.Ldstr, rop); + il.Emit (OpCodes.Callvirt, lopParseMi); + il.Emit (OpCodes.Unbox_Any, lopT); + } + + #endregion + + //emit left operand assignment + il.Emit (lopSetOpCode, lopSetMI); + } + + il.Emit (OpCodes.Ret); + + return dm.CreateDelegate (sourceEvent.EventHandlerType); + } + + internal static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){ + #if DEBUG_BINDING + Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression); + #endif + + Type lopType = null; + + if (currentNode == null) + lopType = sourceEvent.DeclaringType;//TODO:double check if derived class could be returned + else + lopType = currentNode.NodeType; + + #region Retrieve EventHandler parameter type + MethodInfo evtInvoke = sourceEvent.EventHandlerType.GetMethod ("Invoke"); + ParameterInfo [] evtParams = evtInvoke.GetParameters (); + Type handlerArgsType = evtParams [1].ParameterType; + #endregion + + Type [] args = { CompilerServices.TObject, handlerArgsType }; + DynamicMethod dm = new DynamicMethod ("dyn_eventHandler", + typeof(void), + args, true); + ILGenerator il = dm.GetILGenerator (256); + il.Emit (OpCodes.Nop); + + string [] srcLines = expression.Trim ().Split (new char [] { ';' }); + foreach (string srcLine in srcLines) { string statement = srcLine.Trim (); @@ -667,7 +823,7 @@ namespace Crow il.Emit (OpCodes.Ldstr, strcst); - }else if (string.Equals(rop,"this",StringComparison.OrdinalIgnoreCase)){ + }else if (rop.StartsWith ("this",StringComparison.OrdinalIgnoreCase)){ il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack } else { if (lopT.IsEnum) @@ -692,7 +848,10 @@ namespace Crow return dm.CreateDelegate (sourceEvent.EventHandlerType); } - public static string[] splitOnSemiColumnOutsideAccolades (string expression){ + /// + /// Splits expression on semicolon but ignore those between accolades + /// + internal static string[] splitOnSemiColumnOutsideAccolades (string expression){ List exps = new List(); int accCount = 0; int expPtr = 0; @@ -716,10 +875,12 @@ namespace Crow exps.Add(expression); return exps.ToArray (); } + + /// /// Gets the node adress from binding expression splitted with '/' starting at a given node /// - public static NodeAddress getNodeAdressFromBindingExp(NodeAddress sourceAddr, string[] bindingExp){ + internal static NodeAddress getNodeAdressFromBindingExp(NodeAddress sourceAddr, string[] bindingExp){ int ptr = sourceAddr.Count - 1; //if exp start with '/' => Graphic tree parsing start at source diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs index 70334e12..e0e6affc 100644 --- a/src/GraphicObjects/GraphicObject.cs +++ b/src/GraphicObjects/GraphicObject.cs @@ -705,7 +705,7 @@ namespace Crow string expression; if (!getDefaultEvent(ei, styling, out expression)) continue; - //TODO:dynEventHandler could be cached somewhere, maybe a style instanciato class holding the styling delegate and bound to it. + //TODO:dynEventHandler could be cached somewhere, maybe a style instanciator class holding the styling delegate and bound to it. foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(expression)) { string trimed = exp.Trim(); if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase)){ @@ -718,6 +718,7 @@ namespace Crow il.Emit (OpCodes.Call, CompilerServices.miGetEvent); //push expression as 2nd arg of compile il.Emit (OpCodes.Ldstr, trimed.Substring (1, trimed.Length - 2)); + //push null as 3rd arg, currentNode, not known when instanciing il.Emit (OpCodes.Ldnull); il.Emit (OpCodes.Callvirt, CompilerServices.miCompileDynEventHandler); il.Emit (OpCodes.Castclass, ei.EventHandlerType); diff --git a/src/Instantiator.cs b/src/Instantiator.cs index db0bd353..305df437 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -356,7 +356,7 @@ namespace Crow void readPropertyBinding (Context ctx, string sourceMember, string expression) { NodeAddress sourceNA = ctx.CurrentNodeAddress; - BindingDefinition bindingDef = splitBindingExp (sourceNA, sourceMember, expression); + BindingDefinition bindingDef = genBindingDef (sourceNA, sourceMember, expression); #if DEBUG_BINDING Debug.WriteLine("Property Binding: " + bindingDef.ToString()); @@ -369,15 +369,9 @@ namespace Crow } /// - /// Splits the binding expression + /// get BindingDefinition from binding expression /// - /// true, if it's a two way binding, false otherwise. - /// Source Node address - /// Expression. - /// Target Node Address - /// Target member name - /// Target node name - BindingDefinition splitBindingExp(NodeAddress sourceNA, string sourceMember, string expression){ + BindingDefinition genBindingDef(NodeAddress sourceNA, string sourceMember, string expression){ BindingDefinition bindingDef = new BindingDefinition(sourceNA, sourceMember); if (string.IsNullOrEmpty (expression)) { return bindingDef; @@ -429,7 +423,7 @@ namespace Crow /// Emits handler method bindings void emitHandlerBinding (Context ctx, EventInfo sourceEvent, string expression){ NodeAddress currentNode = ctx.CurrentNodeAddress; - BindingDefinition bindingDef = splitBindingExp (currentNode, sourceEvent.Name, expression); + BindingDefinition bindingDef = genBindingDef (currentNode, sourceEvent.Name, expression); #if DEBUG_BINDING Debug.WriteLine("Event Binding: " + bindingDef.ToString()); @@ -437,7 +431,7 @@ namespace Crow if (bindingDef.IsTemplateBinding | bindingDef.IsDataSourceBinding) { //we need to bind datasource method to source event - DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler" + NewId, + DynamicMethod dm = new DynamicMethod ("dyn_dsORtmpChangedForHandler" + NewId, typeof(void), CompilerServices.argsBoundDSChange, true); -- 2.47.3