aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/CompilerServices
diff options
context:
space:
mode:
Diffstat (limited to 'src/CompilerServices')
-rw-r--r--src/CompilerServices/CompilerServices.cs176
1 files changed, 176 insertions, 0 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
new file mode 100644
index 00000000..54f43486
--- /dev/null
+++ b/src/CompilerServices/CompilerServices.cs
@@ -0,0 +1,176 @@
+using System;
+using System.Reflection.Emit;
+using System.Reflection;
+
+namespace go
+{
+ public static class CompilerServices
+ {
+ public static void createDynHandler(string eventName,
+ object dstObj, Type handlerArgsType, string destProp, string src)
+ {
+ Type dstType = dstObj.GetType ();
+
+ Type[] args = {typeof(object), handlerArgsType};
+ DynamicMethod hello = new DynamicMethod("dynHandle",
+ typeof(void),
+ args,
+ dstType.Module);
+
+ MethodInfo dstMi = dstType.GetProperty (destProp).GetSetMethod ();
+ FieldInfo srcFi = typeof(go.Color).GetField (src, BindingFlags.Static|BindingFlags.Public);
+ ILGenerator il = hello.GetILGenerator(256);
+
+ il.Emit(OpCodes.Ldarg_0);
+ il.Emit (OpCodes.Ldsfld, srcFi);
+ il.Emit(OpCodes.Callvirt, dstMi);
+ il.Emit(OpCodes.Ret);
+ //hello.DefineParameter(1, ParameterAttributes.In, "instance");
+ //hello.DefineParameter(2, ParameterAttributes.In, "value");
+ FieldInfo fi = getEventHandlerField (dstType, eventName);
+ Delegate del = hello.CreateDelegate(fi.FieldType);
+ fi.SetValue(dstObj, del);
+
+ }
+ static int dynHandleCpt = 0;
+ public static void CompileEventSource(EventSource es)
+ {
+ Type srcType = es.Source.GetType ();
+
+ #region Retrieve EventHandler parameter type
+ EventInfo ei = srcType.GetEvent (es.EventName);
+ MethodInfo invoke = ei.EventHandlerType.GetMethod ("Invoke");
+ ParameterInfo[] pars = invoke.GetParameters ();
+
+ Type handlerArgsType = pars [1].ParameterType;
+ #endregion
+
+ Type[] args = {typeof(object), handlerArgsType};
+ DynamicMethod dm = new DynamicMethod("dynHandle_" + dynHandleCpt,
+ typeof(void),
+ args,
+ srcType.Module);
+
+ #region IL generation
+ ILGenerator il = dm.GetILGenerator(256);
+
+ string src = es.Handler.Trim();
+
+ if (! (src.StartsWith("{") || src.EndsWith ("}")))
+ throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", es.EventName, es.Handler));
+
+ src = src.Substring (1, src.Length - 2);
+ string[] srcLines = src.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
+ {
+ continue;
+ }
+ string lop = operandes [0].Trim ();
+ string rop = operandes [operandes.Length-1].Trim ();
+
+ #region LEFT OPERANDES
+ GraphicObject lopObj = es.Source; //default left operand base object is
+ //the first arg (object sender) of the event handler
+
+ string[] lopParts = lop.Split (new char[] { '.' });
+ if (lopParts.Length == 2) {//should search also for member of es.Source
+ lopObj = es.Source.FindByName (lopParts [0]);
+ if (lopObj==null)
+ throw new Exception (string.Format("GOML:Unknown name: {0}", lopParts[0]));
+ //TODO: should create private member holding ref of lopObj, and emit
+ //a call to FindByName(lopObjName) during #ctor or in a onLoad func or evt handler
+ throw new Exception (string.Format("GOML:obj tree ref not yet implemented", lopParts[0]));
+ }else
+ il.Emit(OpCodes.Ldarg_0); //load sender ref onto the stack
+
+ int i = lopParts.Length -1;
+
+ MemberInfo lopMbi = lopObj.GetType().GetMember (lopParts[i])[0];
+ OpCode lopSetOC;
+ dynamic lopSetMbi;
+ Type lopT = null;
+ switch (lopMbi.MemberType) {
+ case MemberTypes.Property:
+ PropertyInfo lopPi = srcType.GetProperty (lopParts[i]);
+ MethodInfo dstMi = lopPi.GetSetMethod ();
+ lopT = lopPi.PropertyType;
+ lopSetMbi = dstMi;
+ lopSetOC = OpCodes.Callvirt;
+ break;
+ case MemberTypes.Field:
+ FieldInfo dstFi = srcType.GetField(lopParts[i]);
+ lopT = dstFi.FieldType;
+ lopSetMbi = dstFi;
+ lopSetOC = OpCodes.Stfld;
+ break;
+ default:
+ throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));
+ }
+ #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{
+ //search for a static field in left operand type named 'rop name'
+ FieldInfo ropFi = lopT.GetField (rop, BindingFlags.Static|BindingFlags.Public);
+ if (ropFi != null)
+ {
+ il.Emit (OpCodes.Ldsfld, ropFi);
+ }else{
+ //search if parsing methods are present
+ MethodInfo lopTryParseMi = lopT.GetMethod("TryParse");
+
+ }
+ }
+
+ #endregion
+
+ //emit left operand assignment
+ il.Emit(lopSetOC, lopSetMbi);
+ }
+
+
+
+
+
+
+
+ il.Emit(OpCodes.Ret);
+
+ #endregion
+
+ FieldInfo evtFi = getEventHandlerField (srcType, es.EventName);
+ Delegate del = dm.CreateDelegate(evtFi.FieldType);
+ evtFi.SetValue(es.Source, del);
+ }
+
+ 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;
+ }
+ }
+}
+