From: jpbruyere Date: Tue, 9 Aug 2016 21:59:33 +0000 (+0200) Subject: move MSIL generator from IML into IMLReader. X-Git-Tag: v0.4~11^2~4 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=5a03df5faeda15e2d99c4c656eb62ed21817fdf6;p=jp%2Fcrow.git move MSIL generator from IML into IMLReader. modifié : src/CompilerServices/CompilerServices.cs rename : src/IMLInstantiatorBuilder.cs => src/IMLReader.cs modifié : src/Interface.cs modifié : Crow.csproj --- diff --git a/Crow.csproj b/Crow.csproj index 0d75d56c..49e94a6e 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -136,8 +136,8 @@ - + diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs index da15dbf5..d06cd29b 100644 --- a/src/CompilerServices/CompilerServices.cs +++ b/src/CompilerServices/CompilerServices.cs @@ -14,163 +14,14 @@ namespace Crow { static MethodInfo miAddBinding = typeof(GraphicObject).GetMethod ("BindMember"); - public static void BuildInstanciator(IMLInstantiatorBuilder builder, Type crowType){ - string tmpXml = builder.ReadOuterXml (); - builder.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added - - if (typeof(TemplatedControl).IsAssignableFrom (crowType)) { - //if its a template, first read template elements - using (IMLInstantiatorBuilder reader = new IMLInstantiatorBuilder (builder.il, tmpXml)) { - - string template = reader.GetAttribute ("Template"); - - bool inlineTemplate = false; - if (string.IsNullOrEmpty (template)) { - reader.Read (); - - while (reader.Read ()) { - if (!reader.IsStartElement ()) - continue; - if (reader.Name == "Template") { - inlineTemplate = true; - reader.Read (); - - readChildren (reader, crowType); - continue; - } - } - if (!inlineTemplate) { - DefaultTemplate dt = (DefaultTemplate)crowType.GetCustomAttributes (typeof(DefaultTemplate), true).FirstOrDefault(); - template = dt.Path; - } - } - if (!inlineTemplate) { - reader.il.Emit (OpCodes.Ldloc_0);//Load this templateControl ref - - reader.il.Emit (OpCodes.Ldstr, template); //Load template path string - reader.il.Emit (OpCodes.Callvirt,//call Interface.Load(path) - typeof(Interface).GetMethod ("Load", BindingFlags.Static | BindingFlags.Public)); - } - reader.il.Emit (OpCodes.Callvirt,//add child - typeof(TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic)); - } - } - - using (IMLInstantiatorBuilder reader = new IMLInstantiatorBuilder(builder.il,tmpXml)){ - reader.Read (); - - if (reader.HasAttributes) { - string style = reader.GetAttribute ("Style"); - if (!string.IsNullOrEmpty (style)) { - PropertyInfo pi = crowType.GetProperty ("Style"); - CompilerServices.EmitSetValue (reader.il, pi, style); - } - } - if (reader.HasAttributes) { - reader.il.Emit (OpCodes.Ldloc_0); - reader.il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetMethod ("loadDefaultValues")); - - MethodInfo miAddBinding = typeof(GraphicObject).GetMethod ("BindMember"); - - while (reader.MoveToNextAttribute ()) { - if (reader.Name == "Style") - continue; - - MemberInfo mi = crowType.GetMember (reader.Name).FirstOrDefault(); - if (mi == null) - throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); - if (mi.MemberType == MemberTypes.Event) { - emitBindingCreation (reader.il, reader.Name, reader.Value); - continue; - } - PropertyInfo pi = mi as PropertyInfo; - if (pi == null) - throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); - - if (reader.Value.StartsWith ("{")) { - emitBindingCreation (reader.il, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2)); - }else - CompilerServices.EmitSetValue (reader.il, pi, reader.Value); - - } - reader.MoveToElement (); - } - - if (reader.IsEmptyElement) { - reader.il.Emit (OpCodes.Pop);//pop saved ref to current object - return; - } - - readChildren (reader, crowType); - } - builder.il.Emit (OpCodes.Pop);//pop saved ref to current object - } - static void emitBindingCreation(ILGenerator il, string memberName, string expression){ + public static void emitBindingCreation(ILGenerator il, string memberName, string expression){ il.Emit (OpCodes.Ldloc_0); il.Emit (OpCodes.Ldstr, memberName); il.Emit (OpCodes.Ldstr, expression); il.Emit (OpCodes.Callvirt, miAddBinding); } - static void readChildren(IMLInstantiatorBuilder reader, Type crowType){ - MethodInfo miAddChild = null; - bool endTagReached = false; - while (reader.Read()){ - switch (reader.NodeType) { - case XmlNodeType.EndElement: - endTagReached = true; - break; - case XmlNodeType.Element: - //Templates - if (reader.Name == "Template" || - reader.Name == "ItemTemplate") { - reader.Skip (); - continue; - } - - - if (miAddChild == null) { - if (typeof(Group).IsAssignableFrom (crowType)) - miAddChild = typeof(Group).GetMethod ("AddChild"); - else if (typeof(Container).IsAssignableFrom (crowType)) - miAddChild = typeof(Container).GetMethod ("SetChild"); - else if (typeof(TemplatedContainer).IsAssignableFrom (crowType)) - miAddChild = typeof(TemplatedContainer).GetProperty("Content").GetSetMethod(); - else if (typeof(PrivateContainer).IsAssignableFrom (crowType)) - miAddChild = typeof(PrivateContainer).GetMethod ("SetChild", - BindingFlags.Instance | BindingFlags.NonPublic); - } - - //push current instance on stack for parenting - //loc_0 will be used for child - reader.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"); - - reader.il.Emit(OpCodes.Newobj, t.GetConstructors () [0]); - reader.il.Emit (OpCodes.Stloc_0);//child is now loc_0 - - BuildInstanciator(reader, t); - - reader.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting - reader.il.Emit (OpCodes.Callvirt, miAddChild); - reader.il.Emit (OpCodes.Stloc_0); //reset local to current go - reader.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added - break; - } - if (endTagReached) - break; - } - } public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){ il.Emit (OpCodes.Ldloc_0); @@ -283,6 +134,7 @@ namespace Crow } il.Emit (OpCodes.Callvirt, pi.GetSetMethod ()); } + public static void ResolveBindings (List Bindings) { if (Bindings == null) diff --git a/src/IMLInstantiatorBuilder.cs b/src/IMLInstantiatorBuilder.cs deleted file mode 100644 index a9c078d4..00000000 --- a/src/IMLInstantiatorBuilder.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// IMLReader.cs -// -// Author: -// Jean-Philippe Bruyère -// -// Copyright (c) 2016 jp -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -using System; -using System.Xml; -using System.IO; -using System.Reflection; -using System.Reflection.Emit; - -namespace Crow -{ - public class IMLInstantiatorBuilder : XmlTextReader - { - public Stream ImlStream; - public Type RootType = null; - - DynamicMethod dm = null; - public ILGenerator il = null; - - public IMLInstantiatorBuilder (Stream stream) - : base(stream) - { - ImlStream = stream; - } - public IMLInstantiatorBuilder (ILGenerator ilGen, string xmlFragment) - : base(xmlFragment, XmlNodeType.Element,null){ - il = ilGen; - } - /// - /// Inits il generator, RootType must have been read first - /// - public void InitEmitter(){ - - dm = new DynamicMethod("dyn_instantiator", - MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, - CallingConventions.Standard, - typeof(void),new Type[] {typeof(object)}, RootType, true); - - il = dm.GetILGenerator(256); - 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); - } - - /// - /// read first node to set GraphicObject class for loading - /// and let reader position on that node - /// - public Type ReadRootType () - { - string root = "Object"; - while (Read()) { - if (NodeType == XmlNodeType.Element) { - root = this.Name; - break; - } - } - - 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; - } - } - RootType = t; - return t; - } - /// - /// Finalize instatiator MSIL and return LoaderInvoker delegate - /// - public Instantiator GetInstanciator(){ - il.Emit(OpCodes.Ret); - - return new Instantiator (RootType, - (Interface.LoaderInvoker)dm.CreateDelegate (typeof(Interface.LoaderInvoker))); - } - } -} - diff --git a/src/IMLReader.cs b/src/IMLReader.cs new file mode 100644 index 00000000..c1238081 --- /dev/null +++ b/src/IMLReader.cs @@ -0,0 +1,287 @@ +// +// IMLReader.cs +// +// Author: +// Jean-Philippe Bruyère +// +// Copyright (c) 2016 jp +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +using System; +using System.Xml; +using System.IO; +using System.Reflection; +using System.Reflection.Emit; +using System.Linq; + +namespace Crow +{ + public class IMLReader : XmlTextReader + { + public string ImlPath; + public Stream ImlStream; + public Type RootType = null; + + DynamicMethod dm = null; + public ILGenerator il = null; + + #region CTOR + public IMLReader (string path) + : this(Interface.GetStreamFromPath (path)){ + ImlPath = path; + } + public IMLReader (Stream stream) + : base(stream) + { + ImlStream = stream; + readRootType(); + InitEmitter(); + BuildInstanciator(RootType); + Read();//close tag + } + public IMLReader (ILGenerator ilGen, string xmlFragment) + : base(xmlFragment, XmlNodeType.Element,null){ + il = ilGen; + } + #endregion + + /// + /// Finalize instatiator MSIL and return LoaderInvoker delegate + /// + public Instantiator GetInstanciator(){ + il.Emit(OpCodes.Ret); + + return new Instantiator (RootType, + (Interface.LoaderInvoker)dm.CreateDelegate (typeof(Interface.LoaderInvoker))); + } + + /// + /// Inits il generator, RootType must have been read first + /// + void InitEmitter(){ + + dm = new DynamicMethod("dyn_instantiator", + MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot, + CallingConventions.Standard, + typeof(void),new Type[] {typeof(object)}, RootType, true); + + il = dm.GetILGenerator(256); + 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); + } + void BuildInstanciator(Type crowType){ + string tmpXml = ReadOuterXml (); + + il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added + + if (typeof(TemplatedControl).IsAssignableFrom (crowType)) { + //if its a template, first read template elements + using (IMLReader reader = new IMLReader (il, tmpXml)) { + + string template = reader.GetAttribute ("Template"); + + bool inlineTemplate = false; + if (string.IsNullOrEmpty (template)) { + reader.Read (); + + while (reader.Read ()) { + if (!reader.IsStartElement ()) + continue; + if (reader.Name == "Template") { + inlineTemplate = true; + reader.Read (); + + readChildren (reader, crowType); + continue; + }else if (reader.Name == "ItemTemplate") { + reader.Skip (); + // string dataType = "default", datas = "", itemTmp; + // while (reader.MoveToNextAttribute ()) { + // if (reader.Name == "DataType") + // dataType = reader.Value; + // else if (reader.Name == "Data") + // datas = reader.Value; + // } + // + // reader.Read(); + // itemTmp = .ReadInnerXml (); + // + // if (ItemTemplates == null) + // ItemTemplates = new Dictionary (); + // //TODO:check encoding + // ItemTemplates[dataType] = new ItemTemplate (Encoding.UTF8.GetBytes(itemTmp)); + // if (!string.IsNullOrEmpty (datas)) + // ItemTemplates [dataType].CreateExpandDelegate(this, dataType, datas); + + continue; + } + } + if (!inlineTemplate) { + DefaultTemplate dt = (DefaultTemplate)crowType.GetCustomAttributes (typeof(DefaultTemplate), true).FirstOrDefault(); + template = dt.Path; + } + } + if (!inlineTemplate) { + reader.il.Emit (OpCodes.Ldloc_0);//Load this templateControl ref + + reader.il.Emit (OpCodes.Ldstr, template); //Load template path string + reader.il.Emit (OpCodes.Callvirt,//call Interface.Load(path) + typeof(Interface).GetMethod ("Load", BindingFlags.Static | BindingFlags.Public)); + } + reader.il.Emit (OpCodes.Callvirt,//add child + crowType.GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic)); + } + } + + using (IMLReader reader = new IMLReader(il,tmpXml)){ + reader.Read (); + + if (reader.HasAttributes) { + string style = reader.GetAttribute ("Style"); + if (!string.IsNullOrEmpty (style)) { + PropertyInfo pi = crowType.GetProperty ("Style"); + CompilerServices.EmitSetValue (reader.il, pi, style); + } + } + if (reader.HasAttributes) { + reader.il.Emit (OpCodes.Ldloc_0); + reader.il.Emit (OpCodes.Callvirt, typeof(GraphicObject).GetMethod ("loadDefaultValues")); + + MethodInfo miAddBinding = typeof(GraphicObject).GetMethod ("BindMember"); + + while (reader.MoveToNextAttribute ()) { + if (reader.Name == "Style") + continue; + + MemberInfo mi = crowType.GetMember (reader.Name).FirstOrDefault(); + if (mi == null) + throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); + if (mi.MemberType == MemberTypes.Event) { + CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value); + continue; + } + PropertyInfo pi = mi as PropertyInfo; + if (pi == null) + throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); + + if (reader.Value.StartsWith ("{")) { + CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2)); + }else + CompilerServices.EmitSetValue (reader.il, pi, reader.Value); + + } + reader.MoveToElement (); + } + + if (reader.IsEmptyElement) { + reader.il.Emit (OpCodes.Pop);//pop saved ref to current object + return; + } + + readChildren (reader, crowType); + } + il.Emit (OpCodes.Pop);//pop saved ref to current object + } + /// + /// Parse child node an generate corresponding msil + /// + void readChildren(IMLReader reader, Type crowType){ + MethodInfo miAddChild = null; + bool endTagReached = false; + while (reader.Read()){ + switch (reader.NodeType) { + case XmlNodeType.EndElement: + endTagReached = true; + break; + case XmlNodeType.Element: + //Templates + if (reader.Name == "Template" || + reader.Name == "ItemTemplate") { + reader.Skip (); + continue; + } + + if (miAddChild == null) { + if (typeof(Group).IsAssignableFrom (crowType)) + miAddChild = typeof(Group).GetMethod ("AddChild"); + else if (typeof(Container).IsAssignableFrom (crowType)) + miAddChild = typeof(Container).GetMethod ("SetChild"); + else if (typeof(TemplatedContainer).IsAssignableFrom (crowType)) + miAddChild = typeof(TemplatedContainer).GetProperty("Content").GetSetMethod(); + else if (typeof(PrivateContainer).IsAssignableFrom (crowType)) + miAddChild = typeof(PrivateContainer).GetMethod ("SetChild", + BindingFlags.Instance | BindingFlags.NonPublic); + } + + //push current instance on stack for parenting + //loc_0 will be used for child + reader.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"); + + reader.il.Emit(OpCodes.Newobj, t.GetConstructors () [0]); + reader.il.Emit (OpCodes.Stloc_0);//child is now loc_0 + + reader.BuildInstanciator(t); + + reader.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting + reader.il.Emit (OpCodes.Callvirt, miAddChild); + reader.il.Emit (OpCodes.Stloc_0); //reset local to current go + reader.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added + break; + } + if (endTagReached) + break; + } + } + /// + /// read first node to set GraphicObject class for loading + /// and let reader position on that node + /// + Type readRootType () + { + string root = "Object"; + while (Read()) { + if (NodeType == XmlNodeType.Element) { + root = this.Name; + break; + } + } + + 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; + } + } + RootType = t; + return t; + } + } +} + diff --git a/src/Interface.cs b/src/Interface.cs index 57291370..f3d8c73b 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -200,7 +200,7 @@ namespace Crow if (!Instantiators.ContainsKey(path)) BuildInstaciator(path); tmp = Instantiators [path].CreateInstance (); - + } catch (Exception ex) { throw new Exception ("Error loading <" + path + ">:", ex); } @@ -220,14 +220,8 @@ namespace Crow #endif try { - using (Stream stream = GetStreamFromPath (path)) { - using (IMLInstantiatorBuilder itr = new IMLInstantiatorBuilder (stream)){ - itr.ReadRootType(); - itr.InitEmitter(); - CompilerServices.BuildInstanciator(itr, itr.RootType); - itr.Read();//close tag - Instantiators[path] = itr.GetInstanciator(); - } + using (IMLReader itr = new IMLReader (path)){ + Instantiators[path] = itr.GetInstanciator(); } } catch (Exception ex) { throw new Exception ("Error loading <" + path + ">:", ex);