aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/CompilerServices
diff options
context:
space:
mode:
Diffstat (limited to 'src/CompilerServices')
-rw-r--r--src/CompilerServices/CompilerServices.cs259
1 files changed, 65 insertions, 194 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
index c626a6e2..dc2f7a1c 100644
--- a/src/CompilerServices/CompilerServices.cs
+++ b/src/CompilerServices/CompilerServices.cs
@@ -42,6 +42,9 @@ namespace Crow
internal static MethodInfo miCreateDel = typeof(CompilerServices).GetMethod ("createDel", BindingFlags.Static | BindingFlags.NonPublic);
internal static MethodInfo miGetImplOp = typeof(CompilerServices).GetMethod ("getImplicitOp", BindingFlags.Static | BindingFlags.NonPublic);
+
+ internal static MethodInfo miGoUpLevels = typeof(CompilerServices).GetMethod("goUpNbLevels", 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);
internal static MethodInfo miDSChangeEmitHelper = typeof(Instantiator).GetMethod("dataSourceChangedEmitHelper", BindingFlags.Instance | BindingFlags.NonPublic);
@@ -602,7 +605,7 @@ namespace Crow
return Delegate.CreateDelegate (eventType, instance, mi);
}
- public static Delegate compileDynEventHandler2(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){
+ internal static Delegate compileDynEventHandler(EventInfo sourceEvent, string expression, NodeAddress currentNode = null){
#if DEBUG_BINDING
Debug.WriteLine ("\tCompile Event {0}: {1}", sourceEvent.Name, expression);
#endif
@@ -630,95 +633,71 @@ 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
+ if (string.IsNullOrEmpty (srcLine))
continue;
- }
+ string [] operandes = srcLine.Trim ().Split (new char [] { '=' });
+ if (operandes.Length != 2) //not an affectation
+ throw new NotSupportedException ();
- string rop = operandes [operandes.Length - 1].Trim ();
+ System.Reflection.Emit.Label cancel = il.DefineLabel ();
+ System.Reflection.Emit.Label cancelFinalSet = il.DefineLabel ();
+ System.Reflection.Emit.Label success = il.DefineLabel ();
- #region LEFT OPERANDES
- string [] lopParts = operandes [0].Trim ().Split ('.');
- MemberInfo lopMI = null;
+ BindingMember lop = new BindingMember (operandes [0].Trim ());
+ BindingMember rop = new BindingMember (operandes [1].Trim ());
il.Emit (OpCodes.Ldarg_0); //load sender ref onto the stack, the current node
- if (lopParts.Length > 1) {
- NodeAddress lopNA = currentNode.ResolveExpression (ref operandes [0]);
- 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"));
+ #region Left operande
+ PropertyInfo lopPI = null;
- 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"));
- }
+ //in dyn handler, no datasource binding, so single name in expression are also handled as current node property
+ if (lop.IsSingleName)
+ lopPI = lopType.GetProperty (lop.Tokens [0]);
+ else if (lop.IsCurrentNodeProperty)
+ lopPI = lopType.GetProperty (lop.Tokens [1]);
+ else
+ lop.emitGetTarget (il, cancel);
#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 ();
+ if (rop.IsStringConstant){
+ il.Emit (OpCodes.Ldstr, rop.Tokens[0]);
+ lop.emitSetProperty (il, cancelFinalSet);
+ }else if (rop.LevelsUp ==0 && !string.IsNullOrEmpty(rop.Tokens[0])) {//parsable constant depending on lop type
+ //if left operand is member of current node, it's easy to fetch type, else we should use reflexion in msil
+ if (lopPI == null){//accept GraphicObj members, but it's restricive
+ //TODO: we should get the parse method by reflexion, or something else
+ lopPI = typeof(GraphicObject).GetProperty (lop.Tokens [lop.Tokens.Length-1]);
+ if (lopPI == null)
+ throw new NotSupportedException ();
+ }
- MethodInfo lopParseMi = lopT.GetMethod ("Parse");
+ MethodInfo lopParseMi = lopPI.PropertyType.GetMethod ("Parse");
if (lopParseMi == null)
throw new Exception (string.Format
- ("GOML:no parse method found in: {0}", lopT.Name));
- il.Emit (OpCodes.Ldstr, rop);
+ ("IML: no static 'Parse' method found in: {0}", lopPI.PropertyType.Name));
+
+ il.Emit (OpCodes.Ldstr, operandes [1].Trim ());
il.Emit (OpCodes.Callvirt, lopParseMi);
- il.Emit (OpCodes.Unbox_Any, lopT);
- }
+ il.Emit (OpCodes.Unbox_Any, lopPI.PropertyType);
+ //emit left operand assignment
+ il.Emit (OpCodes.Callvirt, lopPI.GetSetMethod());
+ } else {//tree parsing and propert gets
+ rop.emitGetTarget (il, cancel);
+ rop.emitGetProperty (il, cancel);
+ lop.emitSetProperty (il, cancelFinalSet);
+ }
#endregion
- //emit left operand assignment
- il.Emit (lopSetOpCode, lopSetMI);
+ il.Emit (OpCodes.Br, success);
+
+ il.MarkLabel (cancelFinalSet);
+ il.Emit (OpCodes.Pop); //pop null MemberInfo on the stack causing cancelation
+ il.MarkLabel (cancel);
+ il.Emit (OpCodes.Pop); //pop null instance on the stack causing cancelation
+ il.MarkLabel (success);
}
il.Emit (OpCodes.Ret);
@@ -726,128 +705,20 @@ namespace Crow
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 ();
-
- 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
-
- if (lopParts.Length > 1) {
- NodeAddress lopNA = currentNode.ResolveExpression (ref operandes [0]);
- 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);
+ /// <summary>
+ /// MSIL helper, go n levels up
+ /// </summary>
+ /// <returns><c>true</c>, if logical parents are not null</returns>
+ /// <param name="instance">Start Instance</param>
+ /// <param name="levelCount">Levels to go upward</param>
+ internal static ILayoutable goUpNbLevels(ILayoutable instance, int levelCount){
+ ILayoutable tmp = instance;
+ int i = 0;
+ while (tmp != null && i < levelCount) {
+ tmp = tmp.LogicalParent;
+ i++;
}
-
- il.Emit (OpCodes.Ret);
-
- return dm.CreateDelegate (sourceEvent.EventHandlerType);
+ return tmp;
}
/// <summary>
/// Splits expression on semicolon but ignore those between accolades