aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/IML
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2017-01-05 15:47:33 +0100
committerjpbruyere <jp.bruyere@hotmail.com>2017-01-05 15:47:33 +0100
commit49346012274739fd39745f9e035ee8853149bc73 (patch)
treeb8757165c6b31a6d08b7caad2118ed76f463c287 /src/IML
parent9c0f77e860a1852ee7de381a82118e6d8c7fb819 (diff)
parent40b16003066ad42604fd82dc0eec9cfa0a4abeca (diff)
Merge branch 'master' into CrowIDE
Diffstat (limited to 'src/IML')
-rw-r--r--src/IML/BindingDefinition.cs84
-rw-r--r--src/IML/Context.cs193
-rw-r--r--src/IML/EventBinding.cs39
-rw-r--r--src/IML/MemberAddress.cs110
-rw-r--r--src/IML/Node.cs85
-rw-r--r--src/IML/NodeAddress.cs69
-rw-r--r--src/IML/NodeStack.cs44
-rw-r--r--src/IML/Reader.cs223
8 files changed, 847 insertions, 0 deletions
diff --git a/src/IML/BindingDefinition.cs b/src/IML/BindingDefinition.cs
new file mode 100644
index 00000000..eadbc9df
--- /dev/null
+++ b/src/IML/BindingDefinition.cs
@@ -0,0 +1,84 @@
+//
+// BindingDefinition.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// store binding source and target addresses and member names
+ /// </summary>
+ public class BindingDefinition
+ {
+ public NodeAddress SourceNA = null;
+ public string SourceMember = "";
+ public NodeAddress TargetNA = null;
+ public string TargetMember = "";
+ public string TargetName = "";
+ public bool TwoWay = false;
+
+ #region CTOR
+ public BindingDefinition (NodeAddress _sourceNA, string _sourceMember){
+ SourceNA = _sourceNA;
+ SourceMember = _sourceMember;
+ }
+ public BindingDefinition (NodeAddress _sourceNA, string _sourceMember, NodeAddress _targetNA, string _targetMember, string _targetName = "", bool _twoWay = false)
+ {
+ SourceNA = _sourceNA;
+ SourceMember = _sourceMember;
+ TargetNA = _targetNA;
+ TargetMember = _targetMember;
+ TargetName = _targetName;
+ TwoWay = _twoWay;
+ }
+ #endregion
+
+ public bool IsDataSourceBinding { get { return TargetNA == null; }}
+ public bool IsTemplateBinding { get { return IsDataSourceBinding ? false : TargetNA.Count == 0; }}
+ public bool HasUnresolvedTargetName { get { return !string.IsNullOrEmpty(TargetName); }}
+ public MemberAddress SourceMemberAddress { get { return new MemberAddress (SourceNA, SourceMember);}}
+ public MemberAddress TargetMemberAddress { get { return new MemberAddress (TargetNA, TargetMember);}}
+
+ /// <summary>
+ /// replace the target node address with corresponding named node address, and clear the target name once resolved
+ /// </summary>
+ /// <param name="newTargetNA">Named Node</param>
+ public void ResolveTargetName(NodeAddress newTargetNA){
+ TargetNA = newTargetNA;
+ TargetName = "";
+ }
+
+ public override string ToString ()
+ {
+ string tmp = string.Format ("Source:{0}.{1}", SourceNA, SourceMember);
+ if (TwoWay)
+ tmp += " <=> ";
+ else
+ tmp += " <= ";
+
+ if (string.IsNullOrEmpty (TargetName))
+ tmp += string.Format ("Target:{0}.{1}]", TargetNA, TargetMember);
+ else
+ tmp += string.Format ("Target:{0}.{1}.{2}]", TargetNA, TargetName, TargetMember);
+ return tmp;
+ }
+ }
+}
+
diff --git a/src/IML/Context.cs b/src/IML/Context.cs
new file mode 100644
index 00000000..7f739c37
--- /dev/null
+++ b/src/IML/Context.cs
@@ -0,0 +1,193 @@
+//
+// Context.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Xml;
+
+namespace Crow.IML
+{
+ public class DataSourceBinding {
+ public bool TwoWay;
+ public MemberAddress Source;
+ public string DataSourceMember;
+ }
+ /// <summary>
+ /// Context while parsing IML, this will store what's needed only while parsing and not during instancing
+ /// </summary>
+ public class Context
+ {
+ public XmlTextReader reader = null;
+ public Type RootType = null;
+
+ public DynamicMethod dm = null;
+ public ILGenerator il = null;
+ //public SubNodeType curSubNodeType;
+ public NodeStack nodesStack = new NodeStack ();
+
+ /// <summary> store addresses of named node for name resolution at end of parsing </summary>
+ public Dictionary<string, List<NodeAddress>> Names = new Dictionary<string, List<NodeAddress>>();
+ /// <summary> Store non datasource binding (in tree and template) by origine and orig member </summary>
+ public Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>> Bindings =
+ new Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>>();
+ /// <summary> Store binding with name in target, will be resolved at end of parsing </summary>
+ public List<BindingDefinition> UnresolvedTargets = new List<BindingDefinition>();
+
+
+ public Context (Type rootType)
+ {
+ RootType = rootType;
+ dm = new DynamicMethod ("dyn_instantiator",
+ CompilerServices.TObject, new Type [] { typeof (Instantiator), typeof (Interface) }, true);
+ il = dm.GetILGenerator (256);
+
+ il.DeclareLocal (typeof (GraphicObject));
+ il.Emit (OpCodes.Nop);
+ //set local GraphicObject to root object
+ il.Emit (OpCodes.Newobj, rootType.GetConstructors () [0]);
+ il.Emit (OpCodes.Stloc_0);
+ CompilerServices.emitSetCurInterface (il);
+ }
+
+ public NodeAddress CurrentNodeAddress {
+ get {
+ Node[] n = nodesStack.ToArray ();
+ Array.Reverse (n);
+ return new NodeAddress(n);
+ }
+ }
+ public Type CurrentNodeType {
+ get { return nodesStack.Peek().CrowType; }
+ }
+ public void StorePropertyBinding(NodeAddress origNA, string origMember, NodeAddress destNA, string destMember){
+ Dictionary<string, List<MemberAddress>> nodeBindings = null;
+ if (Bindings.ContainsKey (origNA))
+ nodeBindings = Bindings [origNA];
+ else {
+ nodeBindings = new Dictionary<string, List<MemberAddress>> ();
+ Bindings [origNA] = nodeBindings;
+ }
+
+ if (!nodeBindings.ContainsKey (origMember))
+ nodeBindings [origMember] = new List<MemberAddress> ();
+ nodeBindings [origMember].Add (new MemberAddress (destNA, destMember));
+ }
+ public void StorePropertyBinding(BindingDefinition bindDef){
+ if (bindDef.HasUnresolvedTargetName) {
+ UnresolvedTargets.Add (bindDef);
+ return;
+ }
+ StorePropertyBinding (bindDef.TargetNA, bindDef.TargetMember, bindDef.SourceNA, bindDef.SourceMember);
+ if (bindDef.TwoWay)
+ StorePropertyBinding (bindDef.SourceNA, bindDef.SourceMember, bindDef.TargetNA, bindDef.TargetMember);
+ }
+ public void StoreCurrentName(string name){
+ if (!Names.ContainsKey(name))
+ Names[name] = new List<NodeAddress>();
+ Names[name].Add(CurrentNodeAddress);
+ }
+ public void ResolveNamedTargets(){//TODO:methodinfo fetching is redundant with early parsing
+ foreach (BindingDefinition bd in UnresolvedTargets) {
+ if (bd.HasUnresolvedTargetName) {
+ try {
+ ResolveName (bd);
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.ToString ());
+ continue;
+ }
+ }
+
+ if (bd is EventBinding) {
+ emitHandlerMethodAddition (bd as EventBinding);
+ continue;
+ }
+
+ MemberInfo miSource = bd.SourceMemberAddress.member;
+ if (miSource == null)
+ throw new Exception ("Source member '" + bd.SourceMember + "' not found");
+ StorePropertyBinding (bd);
+ }
+ }
+ public void ResolveName (BindingDefinition bd){
+
+ if (!Names.ContainsKey (bd.TargetName))
+ throw new Exception ("Target Name '" + bd.TargetName + "' not found");
+
+ NodeAddress resolvedNA = null;
+ foreach (NodeAddress na in Names[bd.TargetName]) {
+ bool naMatch = true;
+ for (int i = 0; i < bd.TargetNA.Count; i++) {
+ if (bd.TargetNA [i] != na [i]) {
+ naMatch = false;
+ break;
+ }
+ }
+ if (naMatch) {
+ resolvedNA = na;
+ break;
+ }
+ }
+
+ if (resolvedNA == null)
+ throw new Exception ("Target Name '" + bd.TargetName + "' not found");
+
+ bd.ResolveTargetName (resolvedNA);
+ }
+
+ /// <summary>
+ /// Emits cached delegate handler addition in the context of instantiator (ctx)
+ /// </summary>
+ public void emitCachedDelegateHandlerAddition(int index, EventInfo evt, NodeAddress address = null){
+ il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
+ CompilerServices.emitGetInstance (il, address);
+ il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ il.Emit(OpCodes.Ldfld, CompilerServices.fiCachedDel);
+ il.Emit(OpCodes.Ldc_I4, index);//load delegate index
+ il.Emit(OpCodes.Callvirt, CompilerServices.miGetDelegateListItem);
+ il.Emit(OpCodes.Callvirt, evt.AddMethod);//call add event
+ }
+ /// <summary>
+ /// Emits the handler method addition, done at end of parsing, Loc_0 is root node instance
+ /// </summary>
+ /// <param name="bd">Bd.</param>
+ /// <param name="evt">passed as arg to prevent refetching it for the 3rd time</param>
+ public void emitHandlerMethodAddition(EventBinding bd){
+ //fetch source instance with address for handler addition (as 1st arg of handler.add)
+ il.Emit (OpCodes.Ldloc_0);//push root
+ CompilerServices.emitGetInstance (il, bd.SourceNA);
+
+ //load handlerType of sourceEvent to create handler delegate (1st arg)
+ il.Emit (OpCodes.Ldtoken, bd.SourceEvent.EventHandlerType);
+ il.Emit (OpCodes.Call, CompilerServices.miGetTypeFromHandle);
+ //load target the where the method is defined (2nd arg)
+ il.Emit (OpCodes.Ldloc_0);
+ CompilerServices.emitGetInstance (il, bd.TargetNA);
+ //load methodInfo (3rd arg)
+ il.Emit (OpCodes.Ldstr, bd.TargetMember);
+
+ il.Emit (OpCodes.Callvirt, CompilerServices.miCreateDel);
+
+ il.Emit (OpCodes.Callvirt, bd.SourceEvent.AddMethod);//call add event
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/IML/EventBinding.cs b/src/IML/EventBinding.cs
new file mode 100644
index 00000000..90a797e0
--- /dev/null
+++ b/src/IML/EventBinding.cs
@@ -0,0 +1,39 @@
+//
+// EventBinding.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Reflection;
+
+namespace Crow.IML
+{
+ public class EventBinding : BindingDefinition
+ {
+ public EventInfo SourceEvent;
+
+ #region CTOR
+ public EventBinding (NodeAddress _sourceNA, EventInfo _sourceEvt, NodeAddress _targetNA, string _targetMember, string _targetName = "")
+ : base (_sourceNA, _sourceEvt.Name, _targetNA, _targetMember, _targetName)
+ {
+ SourceEvent = _sourceEvt;
+ }
+ #endregion
+ }
+}
+
diff --git a/src/IML/MemberAddress.cs b/src/IML/MemberAddress.cs
new file mode 100644
index 00000000..a131927e
--- /dev/null
+++ b/src/IML/MemberAddress.cs
@@ -0,0 +1,110 @@
+//
+// MemberAddress.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Linq;
+using System.Reflection;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// Address member of a node
+ /// </summary>
+ public struct MemberAddress
+ {
+ public string memberName;
+ public MemberInfo member;
+ public NodeAddress Address;
+
+ public PropertyInfo Property { get { return member as PropertyInfo; }}
+ public bool IsTemplateBinding { get { return Address == null ? false : Address.Count == 0; }}
+// public string Name {
+// get { return memberName; }
+// set { memberName = value; }
+// }
+
+ public MemberAddress (NodeAddress _address, string _member, bool findMember = true)
+ {
+ Address = _address;
+ memberName = _member;
+ member = null;
+
+ if (Address == null)
+ return;
+ if (Address.Count == 0)
+ return;
+
+ if (!findMember)
+ return;
+ if (!tryFindMember ())
+ throw new Exception ("Member Not Found: " + memberName);
+ }
+ public MemberAddress (NodeAddress _address, MemberInfo _member)
+ {
+ Address = _address;
+ member = _member;
+ memberName = "";
+
+ if (member != null)
+ memberName = member.Name;
+ }
+
+ #region Equality Compare
+ public override bool Equals (object obj)
+ {
+ return obj is MemberAddress && this == (MemberAddress)obj;
+ }
+ public override int GetHashCode ()
+ {
+ return Address.GetHashCode () ^ member.GetHashCode ();
+ }
+ public static bool operator == (MemberAddress x, MemberAddress y)
+ {
+ return x.Address == y.Address && x.memberName == y.memberName;
+ }
+ public static bool operator != (MemberAddress x, MemberAddress y)
+ {
+ return !(x == y);
+ }
+ #endregion
+
+ bool tryFindMember ()
+ {
+ if (member != null)
+ throw new Exception ("member already found");
+ if (Address == null)
+ return false;
+ if (Address.Count == 0)
+ return false;
+ Type t = Address.LastOrDefault ().CrowType;
+ member = t.GetMember (memberName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).FirstOrDefault ();
+
+ #region search for extensions methods if member not found in type
+ if (member == null && !string.IsNullOrEmpty (memberName)) {
+ Assembly a = Assembly.GetExecutingAssembly ();
+ string mn = memberName;
+ member = CompilerServices.GetExtensionMethods (a, t).Where (em => em.Name == mn).FirstOrDefault ();
+ }
+ #endregion
+
+ return member != null;
+ }
+ }
+}
diff --git a/src/IML/Node.cs b/src/IML/Node.cs
new file mode 100644
index 00000000..4ba61c03
--- /dev/null
+++ b/src/IML/Node.cs
@@ -0,0 +1,85 @@
+//
+// Node.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections.Generic;
+
+namespace Crow.IML
+{
+ /// <summary>
+ /// IML Node are defined with a type and the index in the parent,
+ /// </summary>
+ public struct Node
+ {
+ /// <summary> Current node type</summary>
+ public Type CrowType;
+ /// <summary> Index in parent, -1 for template</summary>
+ public int Index;
+
+ public Node (Type crowType, int _index = 0)
+ {
+ CrowType = crowType;
+ Index = _index;
+ }
+
+ public MethodInfo GetAddMethod(int childIdx){
+ if (typeof (Group).IsAssignableFrom (CrowType))
+ return CompilerServices.miAddChild;
+ if (typeof (Container).IsAssignableFrom (CrowType))
+ return CompilerServices.miSetChild;
+ if (typeof (TemplatedContainer).IsAssignableFrom (CrowType))
+ return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.piContent.GetSetMethod();
+ if (typeof (TemplatedGroup).IsAssignableFrom (CrowType))
+ return childIdx < 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
+ if (typeof (TemplatedControl).IsAssignableFrom (CrowType))
+ return CompilerServices.miLoadTmp;
+ return null;
+ }
+
+ #region Equality Compare
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+ Node n = (Node)obj;
+ return CrowType == n.CrowType && Index == n.Index;
+ }
+ public override int GetHashCode ()
+ {
+ return CrowType.GetHashCode () ^ Index.GetHashCode ();
+ }
+ #endregion
+
+ public bool HasTemplate {
+ get { return typeof (TemplatedControl).IsAssignableFrom (CrowType);}
+ }
+
+ public static implicit operator string (Node sn)
+ {
+ return sn.ToString ();
+ }
+ public override string ToString ()
+ {
+ return string.Format ("{0}.{1}", CrowType.FullName, Index);
+ }
+ }
+}
diff --git a/src/IML/NodeAddress.cs b/src/IML/NodeAddress.cs
new file mode 100644
index 00000000..460998da
--- /dev/null
+++ b/src/IML/NodeAddress.cs
@@ -0,0 +1,69 @@
+//
+// NodeAddress.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace Crow.IML
+{
+ public class NodeAddress : List<Node>
+ {
+ public NodeAddress (Node[] nodes) : base(nodes) {
+ }
+
+ public Type NodeType { get { return Count == 0 ? null : this[this.Count -1].CrowType; }}
+
+ public override bool Equals (object obj)
+ {
+ if (obj == null)
+ return false;
+
+ NodeAddress na = (NodeAddress)obj;
+ return this.SequenceEqual (na);
+ }
+ public override int GetHashCode ()
+ {
+ unchecked {
+ int hash = 19;
+ foreach (Node n in this)
+ hash = hash * 31 + (n == null ? 0 : n.GetHashCode ());
+ return hash;
+ }
+ }
+
+ public override string ToString ()
+ {
+ string tmp = "";
+ foreach (Node n in this)
+ tmp += string.Format ("{0};", n.Index);
+ return tmp;
+ }
+ }
+
+ public class NamedNodeAddress : NodeAddress {
+ public string Name;
+ public NamedNodeAddress(string name, Node[] nodes) : base(nodes){
+ Name = name;
+ }
+ }
+}
diff --git a/src/IML/NodeStack.cs b/src/IML/NodeStack.cs
new file mode 100644
index 00000000..bec45e26
--- /dev/null
+++ b/src/IML/NodeStack.cs
@@ -0,0 +1,44 @@
+//
+// NodeStack.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Collections.Generic;
+
+namespace Crow.IML
+{
+ public class NodeStack : Stack<Node>
+ {
+ public NodeStack () : base()
+ {
+ }
+ public void IncrementCurrentNodeIndex(){
+ Node n = this.Pop();
+ this.Push (new Node (n.CrowType, n.Index + 1));
+ }
+ public void DecrementCurrentNodeIndex(){
+ Node n = this.Pop();
+ this.Push (new Node (n.CrowType, n.Index - 1));
+ }
+ public void ResetCurrentNodeIndex(){
+ this.Push (new Node (this.Pop().CrowType));
+ }
+ }
+}
+
diff --git a/src/IML/Reader.cs b/src/IML/Reader.cs
new file mode 100644
index 00000000..7a0c8405
--- /dev/null
+++ b/src/IML/Reader.cs
@@ -0,0 +1,223 @@
+//
+// IMLReader.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// 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 <http://www.gnu.org/licenses/>.
+using System;
+using System.Xml;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace Crow.IML2
+{
+ public class Reader : XmlTextReader
+ {
+ static List<Type> CrowTypes = new List<Type> ();
+
+ public enum SubNodeType{
+ None,
+ Child,
+ Children,
+ Template,
+ Content,
+ Items,
+ ItemTemplate
+ }
+
+ //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 Type RootType = null;
+ public Context context;
+
+ InstanciatorInvoker loader = null;
+ DynamicMethod dm = null;
+
+ ILGenerator il { get { return context.il; }}
+
+ /// <summary>
+ /// Finalize instatiator MSIL and return LoaderInvoker delegate
+ /// </summary>
+ public InstanciatorInvoker GetLoader(){
+ if (loader != null)
+ return loader;
+
+ il.Emit(OpCodes.Ret);
+ loader = (InstanciatorInvoker)dm.CreateDelegate (typeof(InstanciatorInvoker));
+ return loader;
+ }
+
+ protected int curDepth {
+ get { return context.nodesStack.Count - 1;}
+ }
+ protected Node curNode {
+ get { return context.nodesStack.Peek(); }
+ }
+ //protected Stack<int> curTemplateDepth = new Stack<int>(new int[] {0}); //current template root depth
+
+ #region CTOR
+ public Reader (string path)
+ : this(Interface.GetStreamFromPath (path)){
+ }
+ public Reader (Stream stream)
+ : base(stream)
+ {
+ createInstantiator ();
+ }
+ /// <summary>
+ /// Used to parse xmlFrament with same code generator linked
+ /// If ilGen=null, a new Code Generator will be created.
+ /// </summary>
+ public Reader (Context ctx, string xmlFragment)
+ : base(xmlFragment, XmlNodeType.Element,null){
+
+ context = ctx;
+//
+// if (IMLCtx != null)
+// return;
+//
+// createInstantiator();
+ }
+ #endregion
+
+
+ void createBindingDelegates(){
+// foreach (Dictionary<string, MemberAddress> pb in IMLCtx.PropertyBindings) {
+//
+// }
+ }
+
+
+ void registerPropertyBinding(string origNode, string origProp, MemberAddress ma){
+ if (!context.PropertyBindings.ContainsKey(origNode))
+ context.PropertyBindings [origNode] = new Dictionary<string, MemberAddress> ();
+ context.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 (context.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 (context.nodesStack.ToArray (), srcProperty));
+ return;
+ }
+
+ string targetName = "";
+ string nodeId = "";
+ Node[] target = context.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 = context.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];
+ try {
+ Array.Copy (target, origine, nodeIdx + 1);
+
+ int destLength = target.Length - nodeIdx;
+ Node[] dest = new Node[destLength];
+ Array.Copy (target, nodeIdx, dest, 0, destLength);
+
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine (ex.ToString ());
+ }
+
+
+ nodeId = Node.AddressToString (origine);
+ targetName = bindingExp [ptr];
+ }
+
+ registerPropertyBinding (nodeId, targetName, new MemberAddress (context.nodesStack.ToArray (), srcProperty));
+ }
+
+ }
+}
+