From: jpbruyere Date: Tue, 4 Oct 2016 06:41:39 +0000 (+0200) Subject: work in progress X-Git-Tag: v0.5.1~63^2~44 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=398b399174b0863ca8aee792cd6b42dd3dd27bb3;p=jp%2Fcrow.git work in progress --- diff --git a/Tests/Interfaces/Divers/0.crow b/Tests/Interfaces/Divers/0.crow index a7a2158a..a4436aae 100755 --- a/Tests/Interfaces/Divers/0.crow +++ b/Tests/Interfaces/Divers/0.crow @@ -129,7 +129,7 @@ - + diff --git a/src/IMLReader.cs b/src/IMLReader.cs index 1fae7a22..f9df89ff 100644 --- a/src/IMLReader.cs +++ b/src/IMLReader.cs @@ -30,11 +30,119 @@ namespace Crow { public class IMLReader : XmlTextReader { + static MethodInfo[] miAddChild = new MethodInfo[]{ + typeof(Container).GetMethod ("SetChild"), + typeof(Group).GetMethod ("AddChild"), + typeof(TemplatedControl).GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(TemplatedContainer).GetProperty ("Content").GetSetMethod (), + typeof(TemplatedGroup).GetMethod ("AddItem", BindingFlags.Instance | BindingFlags.Public), + //typeof(PrivateContainer).GetMethod ("SetChild", BindingFlags.Instance | BindingFlags.NonPublic) + }; + public enum SubNodeType{ + None, + Child, + Children, + Template, + Content, + Items, + ItemTemplate + } + public class Node { + public SubNodeType Type; + public int Index; + + public Node(){} + public Node(SubNodeType snt, int _index = 0){ + Type = snt; + Index = _index; + } + public static implicit operator SubNodeType(Node sn){ + return sn.Type; + } + public static implicit operator string(Node sn){ + return sn.ToString (); + } + public static implicit operator Node(SubNodeType sn){ + return new Node (sn); + } + public override bool Equals (object obj) + { + return obj is Node && this == (Node)obj; + } + public override int GetHashCode() + { + return Type.GetHashCode() ^ Index.GetHashCode(); + } + public static bool operator ==(Node x, Node y) + { + return x.Type == y.Type && x.Index == y.Index; + } + public static bool operator !=(Node x, Node y) + { + return !(x == y); + } + public override string ToString () + { + return string.Format ("{0}.{1}", (int)Type, Index); + } + public static Node Parse(string str){ + string[] tmp = str.Trim ().Split ('.'); + switch (tmp.Length) { + case 1: + return new Node ((SubNodeType)int.Parse (tmp [0])); + case 2: + return new Node ((SubNodeType)int.Parse (tmp [0]), int.Parse (tmp[1])); + case 0: + default: + return new Node (); + } + } + public static string AddressToString(Node[] address){ + string tmp = ""; + foreach (Node n in address) { + tmp += n.ToString () + ";"; + } + return string.IsNullOrEmpty(tmp) ? tmp : tmp.Substring (0, tmp.Length - 1); + } + public static Node[] AddressFromString(string address) { + List nodes = new List (); + string[] tmp = address.Split (';'); + for (int i = 0; i < tmp.Length; i++) + nodes.Add (Node.Parse (tmp [i])); + return nodes.ToArray(); + } + } + +// public class PropertyBinding { +// public string OriginePropertyName = ""; +// public MemberAddress Destination; +// } + public class MemberAddress { + public Node[] DestinationNode = null; + public string DestinationProperty = ""; + + public MemberAddress (){} + public MemberAddress (Node[] _node, string _property){ + DestinationNode = _node; + DestinationProperty = _property; + } + } InstanciatorInvoker loader = null; DynamicMethod dm = null; - public ILGenerator il = null; + public class IMLContext { + public ILGenerator il = null; + public SubNodeType curSubNodeType; + public Stack nodesStack = new Stack(); + + public Dictionary Names = new Dictionary(); + public Dictionary> PropertyBindings = new Dictionary>(); + } + public Type RootType = null; + public IMLContext IMLCtx; + + ILGenerator il { get { return IMLCtx.il; }} /// /// Finalize instatiator MSIL and return LoaderInvoker delegate @@ -48,6 +156,14 @@ namespace Crow return loader; } + protected int curDepth { + get { return IMLCtx.nodesStack.Count - 1;} + } + protected Node curNode { + get { return IMLCtx.nodesStack.Peek(); } + } + //protected Stack curTemplateDepth = new Stack(new int[] {0}); //current template root depth + #region CTOR public IMLReader (string path) : this(Interface.GetStreamFromPath (path)){ @@ -61,18 +177,20 @@ namespace Crow /// Used to parse xmlFrament with same code generator linked /// If ilGen=null, a new Code Generator will be created. /// - public IMLReader (ILGenerator ilGen, string xmlFragment) + public IMLReader (IMLContext ctx, string xmlFragment) : base(xmlFragment, XmlNodeType.Element,null){ - il = ilGen; - if (il != null) - return; - - createInstantiator(); + IMLCtx = ctx; +// +// if (IMLCtx != null) +// return; +// +// createInstantiator(); } #endregion void createInstantiator(){ + IMLCtx = new IMLContext(); readRootType(); InitEmitter(); emitLoader(RootType); @@ -88,7 +206,7 @@ namespace Crow CallingConventions.Standard, typeof(void),new Type[] {typeof(object), typeof(Interface)}, RootType, true); - il = dm.GetILGenerator(256); + IMLCtx.il = dm.GetILGenerator(256); il.DeclareLocal(typeof(GraphicObject)); il.Emit(OpCodes.Nop); //set local GraphicObject to root object passed as 1st argument @@ -97,17 +215,31 @@ namespace Crow CompilerServices.emitSetCurInterface (il); } void emitLoader(Type crowType){ + + + if (typeof(Group).IsAssignableFrom (crowType)) + IMLCtx.curSubNodeType = SubNodeType.Children; + else if (typeof(Container).IsAssignableFrom (crowType)) + IMLCtx.curSubNodeType = SubNodeType.Child; + else if (typeof(TemplatedContainer).IsAssignableFrom (crowType)) + IMLCtx.curSubNodeType = SubNodeType.Content; + else if (typeof(TemplatedGroup).IsAssignableFrom (crowType)) + IMLCtx.curSubNodeType = SubNodeType.Items; + else if (typeof(TemplatedControl).IsAssignableFrom (crowType)) + IMLCtx.curSubNodeType = SubNodeType.Template; + else + IMLCtx.curSubNodeType = SubNodeType.None; + string tmpXml = ReadOuterXml (); il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added #region Template and ItemTemplates loading - if (typeof(TemplatedControl).IsAssignableFrom (crowType)) { + if (IMLCtx.curSubNodeType >= SubNodeType.Template) { //if its a template, first read template elements - using (IMLReader reader = new IMLReader (il, tmpXml)) { + using (IMLReader reader = new IMLReader (IMLCtx, tmpXml)) { string templatePath = reader.GetAttribute ("Template"); - //string itemTemplatePath = reader.GetAttribute ("ItemTemplate"); List itemTemplateIds = new List (); bool inlineTemplate = false; @@ -119,8 +251,9 @@ namespace Crow if (reader.Name == "Template") { inlineTemplate = true; reader.Read (); - - readChildren (reader, crowType, true); + IMLCtx.nodesStack.Push(SubNodeType.Template); + readChildren (reader); + IMLCtx.nodesStack.Pop(); } else if (reader.Name == "ItemTemplate") { string dataType = "default", datas = "", path = ""; while (reader.MoveToNextAttribute ()) { @@ -162,9 +295,13 @@ namespace Crow reader.il.Emit (OpCodes.Callvirt,//call Interface.Load(path) CompilerServices.miIFaceLoad); } + MethodInfo mitmp = crowType.GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic); + if (mitmp == null) + System.Diagnostics.Debugger.Break(); reader.il.Emit (OpCodes.Callvirt,//load template - crowType.GetMethod ("loadTemplate", BindingFlags.Instance | BindingFlags.NonPublic)); + mitmp); } + //copy item templates (review this) foreach (string[] iTempId in itemTemplateIds) { reader.il.Emit (OpCodes.Ldloc_0);//load TempControl ref reader.il.Emit (OpCodes.Ldfld, CompilerServices.fldItemTemplates);//load ItemTemplates dic field @@ -187,7 +324,7 @@ namespace Crow } #endregion - using (IMLReader reader = new IMLReader(il,tmpXml)){ + using (IMLReader reader = new IMLReader(IMLCtx,tmpXml)){ reader.Read (); #region Styling and default values loading @@ -220,7 +357,12 @@ namespace Crow if (pi == null) throw new Exception ("Member '" + reader.Name + "' not found in " + crowType.Name); + if (pi.Name == "Name") + IMLCtx.Names.Add(reader.Value, Node.AddressToString(IMLCtx.nodesStack.ToArray())); + if (reader.Value.StartsWith ("{")) { + 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 (reader.il, pi, reader.Value); @@ -234,16 +376,92 @@ namespace Crow reader.il.Emit (OpCodes.Pop);//pop saved ref to current object return; } - - readChildren (reader, crowType); + IMLCtx.nodesStack.Push (IMLCtx.curSubNodeType); + readChildren (reader); + IMLCtx.nodesStack.Pop (); } il.Emit (OpCodes.Pop);//pop saved ref to current object } + void registerPropertyBinding(string origNode, string origProp, MemberAddress ma){ + if (!IMLCtx.PropertyBindings.ContainsKey(origNode)) + IMLCtx.PropertyBindings [origNode] = new Dictionary (); + IMLCtx.PropertyBindings [origNode] [origProp] = ma; + } + void readPropertyBinding(string srcProperty, string expression){ + //if binding exp = '{}' => binding is done on datasource + if (string.IsNullOrEmpty (expression)) { + registerPropertyBinding ("DS", "", new MemberAddress (IMLCtx.nodesStack.ToArray (), srcProperty)); + return; + } + +// if (expression.StartsWith ("²")) { +// expression = expression.Substring (1); +// TwoWayBinding = true; +// } +// + string [] bindingExp = expression.Split ('/'); + + + if (bindingExp.Length == 1) { + registerPropertyBinding ("DS", bindingExp [0], + new MemberAddress (IMLCtx.nodesStack.ToArray (), srcProperty)); + return; + } + + string targetName = ""; + string nodeId = ""; + Node[] target = IMLCtx.nodesStack.ToArray (); + + int nodeIdx = target.Length - 1;//index of target in nodeStack + int ptr = 0;//pointer in bindingExp splitted on '/' + +// //if exp start with '/' => WidgetName.property + if (string.IsNullOrEmpty (bindingExp [0])) { + string[] bindTrg = bindingExp [1].Split ('.'); + if (bindTrg.Length == 1) { + nodeId = Node.AddressToString (target); + targetName = bindTrg [0]; + }else if (bindTrg.Length == 2) { + nodeId = IMLCtx.Names [bindTrg [0]]; + targetName = bindTrg [1]; + } else + throw new Exception ("Syntax error in binding, expected 'go dot member'"); + } else { + if (bindingExp [0] == ".") { //template binding + //parse nodes up until template node + while (nodeIdx > 0) { + if (target [nodeIdx].Type == SubNodeType.Template) + break; + nodeIdx--; + } + ptr++; + } else { + while (ptr < bindingExp.Length - 1) { + if (bindingExp [ptr] == "..") + nodeIdx--; + else + break; + ptr++; + } + } + Node[] origine = new Node[nodeIdx + 1]; + Array.Copy (target, origine, nodeIdx + 1); + + int destLength = target.Length - nodeIdx; + Node[] dest = new Node[destLength]; + Array.Copy (target, nodeIdx, dest, 0, destLength); + + + nodeId = Node.AddressToString (origine); + targetName = bindingExp [ptr]; + } + + registerPropertyBinding (nodeId, targetName, new MemberAddress (IMLCtx.nodesStack.ToArray (), srcProperty)); + } /// /// Parse child node an generate corresponding msil /// - void readChildren(IMLReader reader, Type crowType, bool templateLoading = false){ - MethodInfo miAddChild = null; + void readChildren(IMLReader reader){ bool endTagReached = false; while (reader.Read()){ switch (reader.NodeType) { @@ -257,24 +475,8 @@ namespace Crow 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) && !templateLoading) - miAddChild = typeof(TemplatedContainer).GetProperty ("Content").GetSetMethod (); - else if (typeof(TemplatedGroup).IsAssignableFrom (crowType) && !templateLoading) - miAddChild = typeof(TemplatedGroup).GetMethod ("AddItem", - BindingFlags.Instance | BindingFlags.Public); - else if (typeof(TemplatedControl).IsAssignableFrom (crowType)) - miAddChild = typeof(TemplatedControl).GetMethod ("loadTemplate", - BindingFlags.Instance | BindingFlags.NonPublic); - 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); @@ -297,13 +499,16 @@ namespace Crow reader.emitLoader (t); reader.il.Emit (OpCodes.Ldloc_0);//load child on stack for parenting - reader.il.Emit (OpCodes.Callvirt, miAddChild); + reader.il.Emit (OpCodes.Callvirt, miAddChild [(int)IMLCtx.nodesStack.Peek ().Type -1]); 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 + + IMLCtx.nodesStack.Peek ().Index++; + break; } if (endTagReached) - break; + break; } } /// diff --git a/src/Instantiator.cs b/src/Instantiator.cs index 1a8cdb75..5903f4f1 100644 --- a/src/Instantiator.cs +++ b/src/Instantiator.cs @@ -35,6 +35,7 @@ namespace Crow string imlPath; + #region CTOR public Instantiator (string path){ imlPath = path; diff --git a/src/ItemTemplate.cs b/src/ItemTemplate.cs index fe26f7a7..7b6dbca8 100644 --- a/src/ItemTemplate.cs +++ b/src/ItemTemplate.cs @@ -41,6 +41,7 @@ namespace Crow : base(path) { strDataType = _dataType; fetchMethodName = _fetchDataMethod; + } public ItemTemplate (Type _root, InstanciatorInvoker _loader,string _dataType, string _fetchDataMethod) :base(_root, _loader)