]> O.S.I.I.S - jp/crow.git/commitdiff
work in progress
authorjpbruyere <jp.bruyere@hotmail.com>
Tue, 4 Oct 2016 06:41:39 +0000 (08:41 +0200)
committerjpbruyere <jp.bruyere@hotmail.com>
Tue, 4 Oct 2016 06:41:39 +0000 (08:41 +0200)
Tests/Interfaces/Divers/0.crow
src/IMLReader.cs
src/Instantiator.cs
src/ItemTemplate.cs

index a7a2158ab91c7c188795acab9fb371cd6424fa5f..a4436aae2d03e221b2ac5c98dcd46baacc8b3512 100755 (executable)
                                                <RadioButton/>
                                        </VerticalStack>
                                </TabItem>
-                               <TabItem Name="TabItem2" Caption="Tab 3" Background="Gray">
+                               <TabItem Name="TabItem3" Caption="Tab 3" Background="Gray">
                                        <Container Margin="5" CornerRadius="2">
                                                <TextBox Height="Stretched" Margin="5" Multiline="true" TextAlignment="TopLeft"/>
                                        </Container>
index 1fae7a22f2e882f295f383f18da8e0a518d9aa9f..f9df89fffd5a55fdd5dce425a2a6a411f0022c00 100644 (file)
@@ -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<Node> nodes = new List<Node> ();
+                               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<Node> nodesStack = new Stack<Node>();
+
+                       public Dictionary<string, string> Names =  new Dictionary<string, string>();
+                       public Dictionary<string, Dictionary<string, MemberAddress>> PropertyBindings = new Dictionary<string, Dictionary<string, MemberAddress>>();
+               }
+
                public Type RootType = null;
+               public IMLContext IMLCtx;
+
+               ILGenerator il { get { return IMLCtx.il; }}
 
                /// <summary>
                /// 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<int> curTemplateDepth = new Stack<int>(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.
                /// </summary>
-               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<string[]> itemTemplateIds = new List<string[]> ();
                                        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<string, MemberAddress> ();
+                       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));
+               }
                /// <summary>
                /// Parse child node an generate corresponding msil
                /// </summary>
-               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;                          
                        }
                }
                /// <summary>
index 1a8cdb7551bdb253e1f7df05d4050cc4ea444af8..5903f4f19f80a10103a7b5aac2b146fb79c62c0f 100644 (file)
@@ -35,6 +35,7 @@ namespace Crow
                string imlPath;
 
 
+
                #region CTOR
                public Instantiator (string path){
                        imlPath = path;
index fe26f7a721fc8a46e32390168eabfd52b7c7dbec..7b6dbca8cbcd9d63560580001900864a7c378a5b 100644 (file)
@@ -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)