aboutsummaryrefslogtreecommitdiffstatsci
path: root/src
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2016-12-15 18:32:52 +0100
committerjpbruyere <jp.bruyere@hotmail.com>2016-12-15 18:32:52 +0100
commit0819cdcf926fe7d54e85cbee440c2b334676b2b3 (patch)
treefb02c6ddc20fe8ad1d3966f9d0819c9d98aab93f /src
parentaba894f6a5bb41200e969ccdd7045800ff36e74a (diff)
emit bind datasource handler methods
modifié : src/CompilerServices/CompilerServices.cs modifié : src/IML/Context.cs modifié : src/Instantiator.cs
Diffstat (limited to 'src')
-rw-r--r--src/CompilerServices/CompilerServices.cs7
-rw-r--r--src/IML/Context.cs8
-rw-r--r--src/Instantiator.cs105
3 files changed, 108 insertions, 12 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
index 731d1b5e..ba824c62 100644
--- a/src/CompilerServices/CompilerServices.cs
+++ b/src/CompilerServices/CompilerServices.cs
@@ -28,6 +28,7 @@ namespace Crow
public static MethodInfo miCreateExpDel = typeof(ItemTemplate).GetMethod ("CreateExpandDelegate");
public static MethodInfo miLoadDefaultVals = typeof (GraphicObject).GetMethod ("loadDefaultValues");
public static PropertyInfo piStyle = typeof (GraphicObject).GetProperty ("Style");
+ public static MethodInfo miGetTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
#region tree handling methods
internal static MethodInfo miSetChild = typeof (Container).GetMethod ("SetChild");
internal static MethodInfo miAddChild = typeof (Group).GetMethod ("AddChild");
@@ -635,6 +636,12 @@ namespace Crow
public static MemberInfo getMemberInfoWithReflexion(object instance, string member){
return instance.GetType ().GetMember (member).FirstOrDefault();
}
+ public 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 object getValueWithReflexion(object instance, MemberInfo mi){
object tmp = null;
Type dstType = null;
diff --git a/src/IML/Context.cs b/src/IML/Context.cs
index 4f9ba30d..79ab8a31 100644
--- a/src/IML/Context.cs
+++ b/src/IML/Context.cs
@@ -83,5 +83,13 @@ namespace Crow.IML
CompilerServices.emitSetCurInterface (il);
}
+ public void emitDataSourceChangedHandlerAddition(int index){
+ il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
+ il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dataSourceChangedDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
+ il.Emit(OpCodes.Ldc_I4, index);//load delegate index
+ il.Emit(OpCodes.Callvirt, typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+ il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetEvent("DataSourceChanged").AddMethod);//call add event
+ }
}
} \ No newline at end of file
diff --git a/src/Instantiator.cs b/src/Instantiator.cs
index 7db2967f..dcf53259 100644
--- a/src/Instantiator.cs
+++ b/src/Instantiator.cs
@@ -251,15 +251,21 @@ namespace Crow
MemberInfo mi = ctx.CurrentNodeType.GetMember (reader.Name).FirstOrDefault ();
if (mi == null)
throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNodeType.Name);
+
if (mi.MemberType == MemberTypes.Event) {
- if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
- emitEventHandler(ctx, mi as EventInfo,reader.Value.Substring (1, reader.Value.Length - 2));
- //else //emit handler binding
+ foreach (string exp in splitOnSemiColumnOutsideAccolades(reader.Value)) {
+ string trimed = exp.Trim();
+ if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
+ emitEventHandler (ctx, mi as EventInfo, trimed.Substring (1, trimed.Length - 2));
+ else
+ emitHandlerBinding (ctx, mi as EventInfo, trimed);
+ }
+
continue;
}
PropertyInfo pi = mi as PropertyInfo;
if (pi == null)
- throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNodeType.Name);
+ throw new Exception ("Member '" + reader.Name + "' is not a property in " + ctx.CurrentNodeType.Name);
if (pi.Name == "Name"){
if (!ctx.Names.ContainsKey(reader.Value))
@@ -282,6 +288,30 @@ namespace Crow
ctx.nodesStack.ResetCurrentNodeIndex ();
}
}
+ string[] splitOnSemiColumnOutsideAccolades (string expression){
+ List<String> exps = new List<string>();
+ int accCount = 0;
+ int expPtr = 0;
+ for (int c = 0; c < expression.Length; c++) {
+ switch (expression[c]){
+ case '{':
+ accCount++;
+ break;
+ case '}':
+ accCount--;
+ break;
+ case ';':
+ if (accCount > 0)
+ break;
+ exps.Add(expression.Substring(expPtr, c - expPtr - 1));
+ expPtr = c + 1;
+ break;
+ }
+ }
+ if (exps.Count == 0)
+ exps.Add(expression);
+ return exps.ToArray ();
+ }
/// <summary>
/// Parse child node an generate corresponding msil
/// </summary>
@@ -560,19 +590,18 @@ namespace Crow
dataSourceChangedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
#endregion
- #region Emit datasourcechanged handler binding in the loader context
- ctx.il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
- ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
- ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dataSourceChangedDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
- ctx.il.Emit(OpCodes.Ldc_I4, delDSIndex);//load delegate index
- ctx.il.Emit(OpCodes.Callvirt, typeof(List<Delegate>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
- ctx.il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetEvent("DataSourceChanged").AddMethod);//call add event
- #endregion
+ //Emit datasourcechanged handler binding in the loader context
+ ctx.emitDataSourceChangedHandlerAddition(delDSIndex);
}
+
+ #region Emit Helper
void dataSourceChangedEmitHelper(object dscSource, IValueChange dataSource, int dynMethIdx){
dataSource.ValueChanged +=
(EventHandler<ValueChangeEventArgs>)dsValueChangedDynMeths [dynMethIdx].CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>), dscSource);
}
+ #endregion
+
+
/// <summary>
/// Compile events expression in IML attributes, and store the result in the instanciator
/// Those handlers will be bound when instatiing
@@ -714,6 +743,58 @@ namespace Crow
#endregion
}
+ void emitHandlerBinding (Context ctx, EventInfo sourceEvent, string expression){
+ string[] bindingExp = expression.Split ('/');
+
+ if (bindingExp.Length == 1) {
+ //datasource handler
+ //we need to bind datasource method to source event
+ DynamicMethod dm = new DynamicMethod ("dyn_dschangedForHandler",
+ typeof (void),
+ CompilerServices.argsDSChange, true);
+
+ ILGenerator il = dm.GetILGenerator (256);
+
+ il.DeclareLocal (typeof(MethodInfo));//used to cancel binding if method doesn't exist
+
+ il.Emit (OpCodes.Nop);
+
+ //fetch method in datasource and test if it exist
+ il.Emit (OpCodes.Ldarg_2);//load new datasource
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldstr, bindingExp[0]);//load handler method name
+ il.Emit (OpCodes.Call, typeof(CompilerServices).GetMethod("getMethodInfoWithReflexion", BindingFlags.Static | BindingFlags.Public));
+ il.Emit (OpCodes.Stloc_0);//save MethodInfo
+ il.Emit (OpCodes.Ldloc_0);//push mi for test if null
+ System.Reflection.Emit.Label methodNotFound = il.DefineLabel ();
+ il.Emit (OpCodes.Brfalse, methodNotFound);
+
+ il.Emit (OpCodes.Ldarg_1);//load datasource change source where the event handler is as 1st arg of handler.add
+
+ //loat handlerType of sourceEvent to create delegate (1st arg)
+ il.Emit(OpCodes.Ldtoken, sourceEvent.EventHandlerType);
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ il.Emit (OpCodes.Ldarg_2);//load new datasource where the method is defined
+ il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
+ il.Emit (OpCodes.Ldloc_0);//load methodInfo (3rd arg)
+
+ il.Emit (OpCodes.Callvirt, typeof(Delegate).GetMethod ("CreateDelegate",
+ new Type[] {typeof(Type), typeof(object), typeof(MethodInfo)}));//create bound delegate
+ il.Emit(OpCodes.Callvirt, sourceEvent.AddMethod);//call add event
+
+ il.MarkLabel(methodNotFound);
+ il.Emit (OpCodes.Ret);
+
+ //store dschange delegate in instatiator instance for access while instancing graphic object
+ int delDSIndex = dataSourceChangedDelegates.Count;
+ dataSourceChangedDelegates.Add(dm.CreateDelegate (CompilerServices.ehTypeDSChange, this));
+
+ //Emit datasourcechanged handler binding in the loader context
+ ctx.emitDataSourceChangedHandlerAddition(delDSIndex);
+ return;
+ }
+ }
+
/// <summary>
/// Create and store in the instanciator the ValueChanged delegates
/// those delegates uses grtree functions to set destination value so they don't