aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/IML/IMLContext.cs
diff options
context:
space:
mode:
authorJean-Philippe Bruyère <jp_bruyere@hotmail.com>2018-02-03 06:24:28 +0100
committerJean-Philippe Bruyère <jp_bruyere@hotmail.com>2018-02-03 06:24:28 +0100
commit0f0cb8dcc87bda217a405e9899ef6ccf1eaf6ac0 (patch)
tree35a8267069cf01da6ef85b39a0012c3940b0b19b /src/IML/IMLContext.cs
parent726fe4f0acdee5bce7371c8db6b835668d95df17 (diff)
cairo mesh pattern, docker tests
Diffstat (limited to 'src/IML/IMLContext.cs')
-rw-r--r--src/IML/IMLContext.cs204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/IML/IMLContext.cs b/src/IML/IMLContext.cs
new file mode 100644
index 00000000..c8527087
--- /dev/null
+++ b/src/IML/IMLContext.cs
@@ -0,0 +1,204 @@
+//
+// Context.cs
+//
+// Author:
+// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
+//
+// Copyright (c) 2013-2017 Jean-Philippe Bruyère
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+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 IMLContext
+ {
+ 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 IMLContext (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
+ ConstructorInfo ci = rootType.GetConstructor (
+ BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
+ null, Type.EmptyTypes, null);
+ if (ci == null)
+ throw new Exception ("No default parameterless constructor found in " + rootType.Name);
+ il.Emit (OpCodes.Newobj, ci);
+ 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