diff options
| author | jpbruyere <jp.bruyere@hotmail.com> | 2017-01-05 15:47:33 +0100 |
|---|---|---|
| committer | jpbruyere <jp.bruyere@hotmail.com> | 2017-01-05 15:47:33 +0100 |
| commit | 49346012274739fd39745f9e035ee8853149bc73 (patch) | |
| tree | b8757165c6b31a6d08b7caad2118ed76f463c287 /src/IML | |
| parent | 9c0f77e860a1852ee7de381a82118e6d8c7fb819 (diff) | |
| parent | 40b16003066ad42604fd82dc0eec9cfa0a4abeca (diff) | |
Merge branch 'master' into CrowIDE
Diffstat (limited to 'src/IML')
| -rw-r--r-- | src/IML/BindingDefinition.cs | 84 | ||||
| -rw-r--r-- | src/IML/Context.cs | 193 | ||||
| -rw-r--r-- | src/IML/EventBinding.cs | 39 | ||||
| -rw-r--r-- | src/IML/MemberAddress.cs | 110 | ||||
| -rw-r--r-- | src/IML/Node.cs | 85 | ||||
| -rw-r--r-- | src/IML/NodeAddress.cs | 69 | ||||
| -rw-r--r-- | src/IML/NodeStack.cs | 44 | ||||
| -rw-r--r-- | src/IML/Reader.cs | 223 |
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)); + } + + } +} + |