]> O.S.I.I.S - jp/crow.git/commitdiff
new instanciator class without IML.Reader, Context class will handle temorary parsing...
authorjpbruyere <jp.bruyere@hotmail.com>
Fri, 11 Nov 2016 10:09:23 +0000 (11:09 +0100)
committerjpbruyere <jp.bruyere@hotmail.com>
Fri, 11 Nov 2016 10:09:23 +0000 (11:09 +0100)
src/IML/Context.cs
src/Instantiator.cs
src/ItemTemplate.cs

index 2b505e066f77d5cd2364ee2aa4865d090a8fee27..e5bad2d4798d01c62cf395102853b2f7e2ccc04d 100644 (file)
@@ -20,7 +20,9 @@
 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 using System;
 using System.Collections.Generic;
+using System.Reflection;
 using System.Reflection.Emit;
+using System.Xml;
 
 namespace Crow.IML
 {
@@ -29,6 +31,10 @@ namespace Crow.IML
        /// </summary>
        public class Context
        {
+               public XmlTextReader reader = null;
+               public Type RootType = null;
+               public Node CurrentNode = null;
+               public DynamicMethod dm = null;
                public ILGenerator il = null;
                //public SubNodeType curSubNodeType;
                public Stack<Node> nodesStack = new Stack<Node> ();
@@ -36,8 +42,26 @@ namespace Crow.IML
                public Dictionary<string, string> Names = new Dictionary<string, string> ();
                public Dictionary<string, Dictionary<string, MemberAddress>> PropertyBindings = new Dictionary<string, Dictionary<string, MemberAddress>> ();
 
-               public Context ()
+               public Context (Type rootType)
                {
+                       RootType = rootType;
+                       dm = new DynamicMethod ("dyn_instantiator",
+                                       MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
+                                       CallingConventions.Standard,
+                                       typeof (void), new Type [] { typeof (object), typeof (Interface) }, RootType, true);
+                       il = dm.GetILGenerator (256);
+
+                       initILGen ();
+               }
+               void initILGen ()
+               {
+                       il.DeclareLocal (typeof (GraphicObject));
+                       il.Emit (OpCodes.Nop);
+                       //set local GraphicObject to root object passed as 1st argument
+                       il.Emit (OpCodes.Ldarg_0);
+                       il.Emit (OpCodes.Stloc_0);
+                       CompilerServices.emitSetCurInterface (il);
                }
+
        }
 }
\ No newline at end of file
index 2fde4fbae7e85b7803ee5a1d1e111c0b59c473ed..0c8391cd02f9386c10408a10d52d283efb36ce9a 100644 (file)
@@ -23,86 +23,316 @@ using System.Threading;
 using System.IO;
 using System.Text;
 using System.Diagnostics;
+using System.Xml;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Linq;
 
-namespace Crow
+namespace Crow.IML
 {
        public delegate void InstanciatorInvoker(object instance, Interface iface);
 
+       /// <summary>
+       /// Instantiators
+       /// </summary>
        public class Instantiator
        {
                public Type RootType;
                InstanciatorInvoker loader;
-               string imlPath;
-
-
 
                #region CTOR
-               public Instantiator (string path){
-                       imlPath = path;
+               public Instantiator (string path) : this (Interface.GetStreamFromPath(path)) {}
 
-                       #if DEBUG_LOAD
+               public Instantiator (Stream stream)
+               {
+#if DEBUG_LOAD
                        Stopwatch loadingTime = new Stopwatch ();
                        loadingTime.Start ();
-                       #endif
-                       try {
-                               using (IML.Reader itr = new IML.Reader (path)){
-                                       loader = itr.GetLoader ();
-                                       RootType = itr.RootType;
-                               }
-                       } catch (Exception ex) {
-                               throw new Exception ("Error loading <" + path + ">:\n", ex);
+#endif
+                       using (XmlTextReader itr = new XmlTextReader (stream)) {
+                               parseIML (itr);
                        }
-
-                       #if DEBUG_LOAD
+#if DEBUG_LOAD
                        loadingTime.Stop ();
                        Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms",
-                       loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, path);
-                       #endif
+                               loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath);
+#endif
+               }
+               public Instantiator (Type _root, InstanciatorInvoker _loader)
+               {
+                       RootType = _root;
+                       loader = _loader;
                }
-               public static Instantiator CreateFromImlFragment(string fragment){
+               public static Instantiator CreateFromImlFragment (string fragment)
+               {
                        try {
-                               using (Stream s = new MemoryStream(Encoding.UTF8.GetBytes(fragment))){
-                                       return new Instantiator(s);
+                               using (Stream s = new MemoryStream (Encoding.UTF8.GetBytes (fragment))) {
+                                       return new Instantiator (s);
                                }
                        } catch (Exception ex) {
                                throw new Exception ("Error loading fragment:\n" + fragment + "\n", ex);
                        }
                }
-               public Instantiator (Stream stream){
-                       #if DEBUG_LOAD
-                       Stopwatch loadingTime = new Stopwatch ();
-                       loadingTime.Start ();
-                       #endif
-                       using (IML.Reader itr = new IML.Reader (stream)){
-                               loader = itr.GetLoader ();
-                               RootType = itr.RootType;
+               #endregion
+
+               /// <summary>
+               /// Parses IML and build a dynamic method that will be used to instanciate one or multiple occurence of the IML file or fragment
+               /// </summary>
+               void parseIML (XmlTextReader reader) {
+                       Context ctx = new Context (findRootType (reader));
+
+                       ctx.CurrentNode = new Node (ctx.RootType);
+                       emitLoader (reader, ctx);
+
+                       reader.Read ();//close tag
+               }
+               /// <summary>
+               /// read first node to set GraphicObject class for loading
+               /// and let reader position on that node
+               /// </summary>
+               Type findRootType (XmlTextReader reader)
+               {
+                       string root = "Object";
+                       while (reader.Read ()) {
+                               if (reader.NodeType == XmlNodeType.Element) {
+                                       root = reader.Name;
+                                       break;
+                               }
                        }
-                       #if DEBUG_LOAD
-                       loadingTime.Stop ();
-                       Debug.WriteLine ("IML Instantiator creation '{2}' : {0} ticks, {1} ms",
-                               loadingTime.ElapsedTicks, loadingTime.ElapsedMilliseconds, imlPath);
-                       #endif
+
+                       Type t = Type.GetType ("Crow." + root);
+                       if (t == null) {
+                               Assembly a = Assembly.GetEntryAssembly ();
+                               foreach (Type expT in a.GetExportedTypes ()) {
+                                       if (expT.Name == root)
+                                               t = expT;
+                               }
+                       }
+                       return t;
                }
-               public Instantiator (Type _root, InstanciatorInvoker _loader)
+               void emitLoader (XmlTextReader reader, Context ctx)
                {
-                       RootType = _root;
-                       loader = _loader;
+                       string tmpXml = reader.ReadOuterXml ();
+
+                       ctx.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added
+
+                       if (ctx.CurrentNode.IsTemplate)
+                               emitTemplateLoad (ctx, tmpXml);
+
+                       emitGOLoad (ctx, tmpXml);
+
+                       ctx.il.Emit (OpCodes.Pop);//pop saved ref to current object
                }
-               #endregion
+               void emitTemplateLoad (Context ctx, string tmpXml) {
+                       //if its a template, first read template elements
+                       using (XmlTextReader reader = new XmlTextReader (tmpXml)) {
+                               List<string []> itemTemplateIds = new List<string []> ();
+                               bool inlineTemplate = false;
+
+                               string templatePath = reader.GetAttribute ("Template");
+
+                               reader.Read ();
+                               int depth = reader.Depth + 1;
+                               while (reader.Read ()) {
+                                       if (!reader.IsStartElement () || reader.Depth > depth)
+                                               continue;
+                                       if (reader.Name == "Template") {
+                                               inlineTemplate = true;
+                                               reader.Read ();
+                                               ctx.nodesStack.Push (ctx.CurrentNode);
+                                               readChildren (reader, ctx);
+                                               ctx.nodesStack.Pop ();
+                                       } else if (reader.Name == "ItemTemplate") {
+                                               string dataType = "default", datas = "", path = "";
+                                               while (reader.MoveToNextAttribute ()) {
+                                                       if (reader.Name == "DataType")
+                                                               dataType = reader.Value;
+                                                       else if (reader.Name == "Data")
+                                                               datas = reader.Value;
+                                                       else if (reader.Name == "Path")
+                                                               path = reader.Value;
+                                               }
+                                               reader.MoveToElement ();
+
+                                               string itemTmpID;
+
+                                               if (string.IsNullOrEmpty (path)) {
+                                                       itemTmpID = Guid.NewGuid ().ToString ();
+                                                       Interface.Instantiators [itemTmpID] =
+                                                               new ItemTemplate (reader.ReadInnerXml (), dataType, datas);
+
+                                               } else {
+                                                       if (!reader.IsEmptyElement)
+                                                               throw new Exception ("ItemTemplate with Path attribute may not include sub nodes");
+                                                       itemTmpID = path;
+                                                       Interface.Instantiators [itemTmpID] =
+                                                                                new ItemTemplate (Interface.GetStreamFromPath (itemTmpID), dataType, datas);
+                                               }
+                                               itemTemplateIds.Add (new string [] { dataType, itemTmpID, datas });
+                                       }
+                               }
+
+                               if (!inlineTemplate) {//load from path or default template
+                                       ctx.il.Emit (OpCodes.Ldloc_0);//Load  current templatedControl ref
+                                       if (string.IsNullOrEmpty (templatePath)) {
+                                               ctx.il.Emit (OpCodes.Ldnull);//default template loading
+                                       } else {
+                                               ctx.il.Emit (OpCodes.Ldarg_1);//load currentInterface
+                                               ctx.il.Emit (OpCodes.Ldstr, templatePath); //Load template path string
+                                               ctx.il.Emit (OpCodes.Callvirt,//call Interface.Load(path)
+                                                       CompilerServices.miIFaceLoad);
+                                       }
+                                       ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadTmp);//load template
+                               }
+                               //copy item templates (review this)
+                               foreach (string [] iTempId in itemTemplateIds) {
+                                       ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
+                                       ctx.il.Emit (OpCodes.Ldfld, CompilerServices.fldItemTemplates);//load ItemTemplates dic field
+                                       ctx.il.Emit (OpCodes.Ldstr, iTempId [0]);//load key
+                                       ctx.il.Emit (OpCodes.Ldstr, iTempId [1]);//load value
+                                       ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miGetITemp);
+                                       ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miAddITemp);
+
+                                       if (!string.IsNullOrEmpty (iTempId [2])) {
+                                               //expand delegate creation
+                                               ctx.il.Emit (OpCodes.Ldloc_0);//load TempControl ref
+                                               ctx.il.Emit (OpCodes.Ldfld, CompilerServices.fldItemTemplates);
+                                               ctx.il.Emit (OpCodes.Ldstr, iTempId [0]);//load key
+                                               ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miGetITempFromDic);
+                                               ctx.il.Emit (OpCodes.Ldloc_0);//load root of treeView
+                                               ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miCreateExpDel);
+                                       }
+                               }
+                       }
+                       ctx.CurrentNode.Index++;
+               }
+
+               void emitGOLoad (Context ctx, string tmpXml) {
+                       using (XmlTextReader reader = new XmlTextReader (tmpXml)) {
+                               reader.Read ();
+
+                               #region Styling and default values loading
+                               if (reader.HasAttributes) {
+                                       string style = reader.GetAttribute ("Style");
+                                       if (!string.IsNullOrEmpty (style))
+                                               CompilerServices.EmitSetValue (ctx.il, CompilerServices.piStyle, style);
+                               }
+                               ctx.il.Emit (OpCodes.Ldloc_0);
+                               ctx.il.Emit (OpCodes.Callvirt, CompilerServices.miLoadDefaultVals);
+                               #endregion
+
+                               #region Attributes reading
+                               if (reader.HasAttributes) {
+
+                                       while (reader.MoveToNextAttribute ()) {
+                                               if (reader.Name == "Style")
+                                                       continue;
+
+                                               MemberInfo mi = ctx.CurrentNode.CrowType.GetMember (reader.Name).FirstOrDefault ();
+                                               if (mi == null)
+                                                       throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNode.CrowType.Name);
+                                               if (mi.MemberType == MemberTypes.Event) {
+                                                       CompilerServices.emitBindingCreation (ctx.il, reader.Name, reader.Value);
+                                                       continue;
+                                               }
+                                               PropertyInfo pi = mi as PropertyInfo;
+                                               if (pi == null)
+                                                       throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNode.CrowType.Name);
+
+                                               if (pi.Name == "Name")
+                                                       ctx.Names.Add (reader.Value, Node.AddressToString (ctx.nodesStack.ToArray ()));
+
+                                               if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase)) {
+                                                       readPropertyBinding (reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
+
+                                                       //CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
+                                               } else
+                                                       CompilerServices.EmitSetValue (ctx.il, pi, reader.Value);
+
+                                       }
+                                       reader.MoveToElement ();
+                               }
+                               #endregion
+
+                               if (reader.IsEmptyElement) {
+                                       ctx.il.Emit (OpCodes.Pop);//pop saved ref to current object
+                                       return;
+                               }
+                               ctx.nodesStack.Push (ctx.CurrentNode);
+                               readChildren (reader, ctx);
+                               ctx.nodesStack.Pop ();
+                       }
+               }
+               /// <summary>
+               /// Parse child node an generate corresponding msil
+               /// </summary>
+               void readChildren (XmlTextReader reader, Context ctx)
+               {
+                       bool endTagReached = false;
+                       while (reader.Read ()) {
+                               switch (reader.NodeType) {
+                               case XmlNodeType.EndElement:
+                                       endTagReached = true;
+                                       break;
+                               case XmlNodeType.Element:
+                                       //skip Templates
+                                       if (reader.Name == "Template" ||
+                                               reader.Name == "ItemTemplate") {
+                                               reader.Skip ();
+                                               continue;
+                                       }
+
+                                       //push current instance on stack for parenting
+                                       //loc_0 will be used for child
+                                       ctx.il.Emit (OpCodes.Ldloc_0);
+
+                                       Type t = Type.GetType ("Crow." + reader.Name);
+                                       if (t == null) {
+                                               Assembly a = Assembly.GetEntryAssembly ();
+                                               foreach (Type expT in a.GetExportedTypes ()) {
+                                                       if (expT.Name == reader.Name)
+                                                               t = expT;
+                                               }
+                                       }
+                                       if (t == null)
+                                               throw new Exception (reader.Name + " type not found");
+
+                                       ctx.il.Emit (OpCodes.Newobj, t.GetConstructors () [0]);//TODO:search parameterless ctor
+                                       ctx.il.Emit (OpCodes.Stloc_0);//child is now loc_0
+                                       CompilerServices.emitSetCurInterface (ctx.il);
+
+                                       ctx.CurrentNode = new Node (t);
+                                       emitLoader (reader, ctx);
+
+                                       ctx.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting
+                                       ctx.il.Emit (OpCodes.Callvirt, ctx.nodesStack.Peek ().AddMethod);
+                                       ctx.il.Emit (OpCodes.Stloc_0); //reset local to current go
+                                       ctx.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added
+
+                                       ctx.nodesStack.Peek ().Index++;
+
+                                       break;
+                               }
+                               if (endTagReached)
+                                       break;
+                       }
+               }
+
 
                public GraphicObject CreateInstance(Interface iface){
                        GraphicObject tmp = (GraphicObject)Activator.CreateInstance(RootType);
                        loader (tmp, iface);
                        return tmp;
                }
-               public string GetImlSourcesCode(){
-                       try {
-                               using (StreamReader sr = new StreamReader (imlPath))
-                                       return sr.ReadToEnd();
-                       } catch (Exception ex) {
-                               throw new Exception ("Error getting sources for <" + imlPath + ">:", ex);
-                       }
-               }
+               //public string GetImlSourcesCode(){
+               //      try {
+               //              using (StreamReader sr = new StreamReader (imlPath))
+               //                      return sr.ReadToEnd();
+               //      } catch (Exception ex) {
+               //              throw new Exception ("Error getting sources for <" + imlPath + ">:", ex);
+               //      }
+               //}
        }
 }
 
index 7b6dbca8cbcd9d63560580001900864a7c378a5b..4fb85638ee9925568f2eaf27b795638bd6e77281 100644 (file)
@@ -43,9 +43,9 @@ namespace Crow
                        fetchMethodName = _fetchDataMethod;
 
                }
-               public ItemTemplate (Type _root, InstanciatorInvoker _loader,string _dataType, string _fetchDataMethod)
-                       :base(_root, _loader)
-               {
+               public ItemTemplate (Stream ImlFragment,string _dataType, string _fetchDataMethod)
+                       :base(ImlFragment)
+               {+-
                        strDataType = _dataType;
                        fetchMethodName = _fetchDataMethod;
                }