{
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
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)){
/// 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);
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
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;
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 ()) {
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
}
#endregion
- using (IMLReader reader = new IMLReader(il,tmpXml)){
+ using (IMLReader reader = new IMLReader(IMLCtx,tmpXml)){
reader.Read ();
#region Styling and default values loading
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);
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) {
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);
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>