[Xaml] Support import other xaml as the source of resource dictionary
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / XamlBuild / SetPropertiesVisitor.cs
1 /*
2  * Copyright(c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 using System.Xml;
21
22 using Mono.Cecil;
23 using Mono.Cecil.Cil;
24 using Mono.Cecil.Rocks;
25 using Tizen.NUI.Binding;
26 using Tizen.NUI.Binding.Internals;
27
28 using Tizen.NUI.Xaml;
29
30 using static Mono.Cecil.Cil.Instruction;
31 using static Mono.Cecil.Cil.OpCodes;
32
33 namespace Tizen.NUI.Xaml.Build.Tasks
34 {
35     class SetPropertiesVisitor : IXamlNodeVisitor
36     {
37         static int dtcount;
38         static int typedBindingCount;
39
40         static readonly IList<XmlName> skips = new List<XmlName>
41         {
42             XmlName.xKey,
43             XmlName.xTypeArguments,
44             XmlName.xArguments,
45             XmlName.xFactoryMethod,
46             XmlName.xName,
47             XmlName.xDataType
48         };
49
50         public SetPropertiesVisitor(ILContext context, bool stopOnResourceDictionary = false)
51         {
52             Context = context;
53             Module = context.Body.Method.Module;
54             StopOnResourceDictionary = stopOnResourceDictionary;
55         }
56
57         public ILContext Context { get; }
58         public bool StopOnResourceDictionary { get; }
59         public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
60         public bool StopOnDataTemplate => true;
61         public bool VisitNodeOnDataTemplate => true;
62         public bool SkipChildren(INode node, INode parentNode) => false;
63
64         public bool IsResourceDictionary(ElementNode node)
65         {
66             var parentVar = Context.Variables[(IElementNode)node];
67             return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
68                 || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
69         }
70
71         ModuleDefinition Module { get; }
72
73         public void Visit(ValueNode node, INode parentNode)
74         {
75             //TODO support Label text as element
76             XmlName propertyName;
77             if (!TryGetPropertyName(node, parentNode, out propertyName))
78             {
79                 if (!IsCollectionItem(node, parentNode))
80                     return;
81                 string contentProperty;
82                 if (!Context.Variables.ContainsKey((IElementNode)parentNode))
83                     return;
84                 var parentVar = Context.Variables[(IElementNode)parentNode];
85                 if ((contentProperty = GetContentProperty(parentVar.VariableType)) != null)
86                     propertyName = new XmlName(((IElementNode)parentNode).NamespaceURI, contentProperty);
87                 else
88                     return;
89             }
90
91             if (TrySetRuntimeName(propertyName, Context.Variables[(IElementNode)parentNode], node))
92                 return;
93             if (skips.Contains(propertyName))
94                 return;
95             if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
96                 return;
97             if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
98                 return;
99             Context.IL.Append(SetPropertyValue(Context.Variables [(IElementNode)parentNode], propertyName, node, Context, node));
100         }
101
102         public void Visit(MarkupNode node, INode parentNode)
103         {
104         }
105
106         public void Visit(ElementNode node, INode parentNode)
107         {
108             XmlName propertyName = XmlName.Empty;
109
110             //Simplify ListNodes with single elements
111             var pList = parentNode as ListNode;
112             if (pList != null && pList.CollectionItems.Count == 1) {
113                 propertyName = pList.XmlName;
114                 parentNode = parentNode.Parent;
115             }
116
117             if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
118                 return;
119
120             if (propertyName == XmlName._CreateContent) {
121                 SetDataTemplate((IElementNode)parentNode, node, Context, node);
122                 return;
123             }
124
125             //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
126             var vardef = Context.Variables[node];
127             var vardefref = new VariableDefinitionReference(vardef);
128             var localName = propertyName.LocalName;
129             TypeReference declaringTypeReference = null;
130             FieldReference bpRef = null;
131             var _ = false;
132             PropertyDefinition propertyRef = null;
133             if (parentNode is IElementNode && propertyName != XmlName.Empty) {
134                 bpRef = GetBindablePropertyReference(Context.Variables [(IElementNode)parentNode], propertyName.NamespaceURI, ref localName, out _, Context, node);
135                 propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
136             }
137             Context.IL.Append(ProvideValue(vardefref, Context, Module, node, bpRef:bpRef, propertyRef:propertyRef, propertyDeclaringTypeRef: declaringTypeReference));
138             if (vardef != vardefref.VariableDefinition)
139             {
140                 vardef = vardefref.VariableDefinition;
141                 Context.Body.Variables.Add(vardef);
142                 Context.Variables[node] = vardef;
143             }
144
145             if (propertyName != XmlName.Empty) {
146                 if (skips.Contains(propertyName))
147                     return;
148                 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
149                     return;
150                 
151                 Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
152             }
153             else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
154                 var parentVar = Context.Variables[(IElementNode)parentNode];
155                 string contentProperty;
156
157                 bool isAdded = false;
158
159                 if (parentVar.VariableType.IsArray)
160                 {
161                     isAdded = true;
162                 }
163                 else if (CanAddToResourceDictionary(parentVar, parentVar.VariableType, node, node, Context))
164                 {
165                     Context.IL.Emit(Ldloc, parentVar);
166                     Context.IL.Append(AddToResourceDictionary(node, node, Context));
167                     isAdded = true;
168                 }
169                 // Collection element, implicit content, or implicit collection element.
170                 else if (parentVar.VariableType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any())
171                 {
172                     var elementType = parentVar.VariableType;
173                     var paramType = Context.Variables[node].VariableType;
174
175                     foreach (var adderTuple in elementType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module))
176                     {
177                         var adderRef = Module.ImportReference(adderTuple.Item1);
178                         adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
179
180                         if (IsAddMethodOfCollection(Module, adderRef.Resolve()))
181                         {
182                             isAdded = true;
183                         }
184                         else if (paramType.InheritsFromOrImplements(adderTuple.Item1.Parameters[0].ParameterType.FullName))
185                         {
186                             isAdded = true;
187                         }
188
189                         if (isAdded)
190                         {
191                             Context.IL.Emit(Ldloc, parentVar);
192                             Context.IL.Emit(Ldloc, vardef);
193                             Context.IL.Emit(Callvirt, adderRef);
194                             if (adderRef.ReturnType.FullName != "System.Void")
195                                 Context.IL.Emit(Pop);
196                             break;
197                         }
198                     }
199                 }
200
201                 if (!isAdded && (contentProperty = GetContentProperty(parentVar.VariableType)) != null)
202                 {
203                     var name = new XmlName(node.NamespaceURI, contentProperty);
204                     if (skips.Contains(name))
205                         return;
206                     if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains(propertyName))
207                         return;
208                     Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], name, node, Context, node));
209                     isAdded = true;
210                 }
211                 
212                 if (!isAdded)
213                 {
214                     throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
215                 }
216             }
217             else if (IsCollectionItem(node, parentNode) && parentNode is ListNode)
218             {
219 //                IL_000d:  ldloc.2 
220 //                IL_000e:  callvirt instance class [mscorlib]System.Collections.Generic.IList`1<!0> class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Layout`1<class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.View>::get_Children()
221 //                IL_0013:  ldloc.0 
222 //                IL_0014:  callvirt instance void class [mscorlib]System.Collections.Generic.ICollection`1<class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.View>::Add(!0)
223
224                 var parentList = (ListNode)parentNode;
225                 var parent = Context.Variables[((IElementNode)parentNode.Parent)];
226
227                 if (skips.Contains(parentList.XmlName))
228                     return;
229                 if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
230                     return;
231                 var elementType = parent.VariableType;
232                 var localname = parentList.XmlName.LocalName;
233
234                 TypeReference propertyType;
235                 Context.IL.Append(GetPropertyValue(parent, parentList.XmlName, Context, node, out propertyType));
236
237                 if (CanAddToResourceDictionary(parent, propertyType, node, node, Context)) {
238                     Context.IL.Append(AddToResourceDictionary(node, node, Context));
239                     return;
240                 } 
241                 var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).FirstOrDefault();
242                 if (adderTuple == null)
243                     throw new XamlParseException($"Can not Add() elements to {parent.VariableType}.{localname}", node);
244                 var adderRef = Module.ImportReference(adderTuple.Item1);
245                 adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
246
247                 Context.IL.Emit(OpCodes.Ldloc, vardef);
248                 Context.IL.Emit(OpCodes.Callvirt, adderRef);
249                 if (adderRef.ReturnType.FullName != "System.Void")
250                         Context.IL.Emit(OpCodes.Pop);
251             }
252         }
253
254         private static bool IsAddMethodOfCollection(ModuleDefinition module, MethodDefinition methodDef)
255         {
256             return module.ImportReference(typeof(List<string>)).InheritsFromOrImplements(methodDef.DeclaringType);
257         }
258
259         public void Visit(RootNode node, INode parentNode)
260         {
261         }
262
263         public void Visit(ListNode node, INode parentNode)
264         {
265         }
266
267         public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
268         {
269             name = default(XmlName);
270             var parentElement = parentNode as IElementNode;
271             if (parentElement == null)
272                 return false;
273             foreach (var kvp in parentElement.Properties)
274             {
275                 if (kvp.Value != node)
276                     continue;
277                 name = kvp.Key;
278                 return true;
279             }
280             return false;
281         }
282
283         static bool IsCollectionItem(INode node, INode parentNode)
284         {
285             var parentList = parentNode as IListNode;
286             if (parentList == null)
287                 return false;
288             return parentList.CollectionItems.Contains(node);
289         }
290
291         internal static string GetContentProperty(TypeReference typeRef)
292         {
293             var typeDef = typeRef.ResolveCached();
294             var attributes = typeDef.CustomAttributes;
295             var attr =
296                 attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
297             if (attr != null)
298                 return attr.ConstructorArguments[0].Value as string;
299             if (typeDef.BaseType == null)
300                 return null;
301             return GetContentProperty(typeDef.BaseType);
302         }
303
304         public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
305                                                             ModuleDefinition module, ElementNode node, FieldReference bpRef = null,
306                                                             PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
307         {
308             GenericInstanceType markupExtension;
309             IList<TypeReference> genericArguments;
310             if (vardefref.VariableDefinition.VariableType.FullName == "Tizen.NUI.Xaml.ArrayExtension" &&
311                 vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1",
312                     out markupExtension, out genericArguments))
313             {
314                 var markExt = markupExtension.ResolveCached();
315                 var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
316                 var provideValue = module.ImportReference(provideValueInfo);
317                 provideValue =
318                     module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
319
320                 var typeNode = node.Properties[new XmlName("", "Type")];
321                 TypeReference arrayTypeRef;
322                 if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef))
323                     vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(arrayTypeRef.MakeArrayType()));
324                 else
325                     vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
326                 yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
327                 foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
328                     yield return instruction;
329                 yield return Instruction.Create(OpCodes.Callvirt, provideValue);
330
331                 if (arrayTypeRef != null)
332                     yield return Instruction.Create(OpCodes.Castclass, module.ImportReference(arrayTypeRef.MakeArrayType()));
333                 yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
334             }
335             else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Tizen.NUI.Xaml.IMarkupExtension`1",
336                 out markupExtension, out genericArguments))
337             {
338                 var acceptEmptyServiceProvider = vardefref.VariableDefinition.VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
339                 if (vardefref.VariableDefinition.VariableType.FullName == "Tizen.NUI.Xaml.BindingExtension")
340                     foreach (var instruction in CompileBindingPath(node, context, vardefref.VariableDefinition))
341                         yield return instruction;
342
343                 var markExt = markupExtension.ResolveCached();
344                 var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
345                 var provideValue = module.ImportReference(provideValueInfo);
346                 provideValue =
347                     module.ImportReference(provideValue.ResolveGenericParameters(markupExtension, module));
348
349                 vardefref.VariableDefinition = new VariableDefinition(module.ImportReference(genericArguments.First()));
350                 yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]);
351                 if (acceptEmptyServiceProvider)
352                     yield return Instruction.Create(OpCodes.Ldnull);
353                 else
354                     foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
355                         yield return instruction;
356                 yield return Instruction.Create(OpCodes.Callvirt, provideValue);
357                 yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition);
358             }
359             else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IMarkupExtension"))))
360             {
361                 var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
362                 vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
363                 yield return Create(Ldloc, context.Variables[node]);
364                 if (acceptEmptyServiceProvider)
365                     yield return Create(Ldnull);
366                 else
367                     foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
368                         yield return instruction;
369                 yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IMarkupExtension"),
370                                                                            methodName: "ProvideValue",
371                                                                            parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
372                 yield return Create(Stloc, vardefref.VariableDefinition);
373             }
374             else if (context.Variables[node].VariableType.ImplementsInterface(module.ImportReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"))))
375             {
376                 var acceptEmptyServiceProvider = context.Variables[node].VariableType.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "AcceptEmptyServiceProviderAttribute")) != null;
377                 var valueProviderType = context.Variables[node].VariableType;
378                 //If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
379                 var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module, (XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?[0].Value as string;
380                 Type compiledValueProviderType;
381                 if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null) {
382                     var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
383                     var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
384                     var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
385                         vardefref,
386                         context.Body.Method.Module,
387                         node as BaseNode,
388                         context});
389                     foreach (var i in instructions)
390                         yield return i;
391                     yield break;
392                 }
393
394                 vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
395                 yield return Create(Ldloc, context.Variables[node]);
396                 if (acceptEmptyServiceProvider)
397                     yield return Create(Ldnull);
398                 else
399                     foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef))
400                         yield return instruction;
401                 yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.xamlAssemblyName, XamlCTask.xamlNameSpace, "IValueProvider"),
402                                                                            methodName: "ProvideValue",
403                                                                            parameterTypes: new[] { ("System.ComponentModel", "System", "IServiceProvider") }));
404                 yield return Create(Stloc, vardefref.VariableDefinition);
405             }
406         }
407
408         //Once we get compiled IValueProvider, this will move to the BindingExpression
409         static IEnumerable<Instruction> CompileBindingPath(ElementNode node, ILContext context, VariableDefinition bindingExt)
410         {
411             //TODO support casting operators
412             var module = context.Module;
413
414             INode pathNode;
415             if (!node.Properties.TryGetValue(new XmlName("", "Path"), out pathNode) && node.CollectionItems.Any())
416                 pathNode = node.CollectionItems [0];
417             var path = (pathNode as ValueNode)?.Value as string;
418             BindingMode declaredmode;
419             if (   !node.Properties.TryGetValue(new XmlName("", "Mode"), out INode modeNode)
420                 || !Enum.TryParse((modeNode as ValueNode)?.Value as string, true, out declaredmode))
421                 declaredmode = BindingMode.TwoWay;    //meaning the mode isn't specified in the Binding extension. generate getters, setters, handlers
422
423             INode dataTypeNode = null;
424             IElementNode n = node;
425             while (n != null) {
426                 if (n.Properties.TryGetValue(XmlName.xDataType, out dataTypeNode))
427                     break;
428                 n = n.Parent as IElementNode;
429             }
430             var dataType = (dataTypeNode as ValueNode)?.Value as string;
431             if (dataType == null)
432                 yield break; //throw
433
434             var prefix = dataType.Contains(":") ? dataType.Substring(0, dataType.IndexOf(":", StringComparison.Ordinal)) : "";
435             var namespaceuri = node.NamespaceResolver.LookupNamespace(prefix) ?? "";
436             if (!string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(namespaceuri))
437                 throw new XamlParseException($"Undeclared xmlns prefix '{prefix}'", dataTypeNode as IXmlLineInfo);
438
439             var dtXType = new XmlType(namespaceuri, dataType, null);
440
441             var tSourceRef = dtXType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, module, (IXmlLineInfo)node);
442             if (tSourceRef == null)
443                 yield break; //throw
444
445             var properties = ParsePath(path, tSourceRef, node as IXmlLineInfo, module);
446             var tPropertyRef = properties != null && properties.Any() ? properties.Last().Item1.PropertyType : tSourceRef;
447             tPropertyRef = module.ImportReference(tPropertyRef);
448
449             var funcRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef }));
450             var actionRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Action`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef }));
451             var funcObjRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
452             var tupleRef = module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String}));
453             var typedBindingRef = module.ImportReference(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "TypedBinding`2")).MakeGenericInstanceType(new [] { tSourceRef, tPropertyRef}));
454
455             var ctorInfo =  module.ImportReference(typedBindingRef.ResolveCached().Methods.FirstOrDefault(md => md.IsConstructor && !md.IsStatic && md.Parameters.Count == 3 ));
456             var ctorinforef = ctorInfo.MakeGeneric(typedBindingRef, funcRef, actionRef, tupleRef);
457
458             yield return Instruction.Create(OpCodes.Ldloc, bindingExt);
459             foreach (var instruction in CompiledBindingGetGetter(tSourceRef, tPropertyRef, properties, node, context))
460                 yield return instruction;
461             if (declaredmode != BindingMode.OneTime && declaredmode != BindingMode.OneWay) { //if the mode is explicitly 1w, or 1t, no need for setters
462                 foreach (var instruction in CompiledBindingGetSetter(tSourceRef, tPropertyRef, properties, node, context))
463                     yield return instruction;
464             } else
465                 yield return Create(Ldnull);
466             if (declaredmode != BindingMode.OneTime) { //if the mode is explicitly 1t, no need for handlers
467                 foreach (var instruction in CompiledBindingGetHandlers(tSourceRef, tPropertyRef, properties, node, context))
468                     yield return instruction;
469             } else
470                 yield return Create(Ldnull);
471             yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(ctorinforef));
472             yield return Instruction.Create(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingExtension"), propertyName: "TypedBinding"));
473         }
474
475         static IList<Tuple<PropertyDefinition, string>> ParsePath(string path, TypeReference tSourceRef, IXmlLineInfo lineInfo, ModuleDefinition module)
476         {
477             if (string.IsNullOrWhiteSpace(path))
478                 return null;
479             path = path.Trim(' ', '.'); //trim leading or trailing dots
480             var parts = path.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);
481             var properties = new List<Tuple<PropertyDefinition, string>>();
482
483             var previousPartTypeRef = tSourceRef;
484             TypeReference _;
485             foreach (var part in parts) {
486                 var p = part;
487                 string indexArg = null;
488                 var lbIndex = p.IndexOf('[');
489                 if (lbIndex != -1) {
490                     var rbIndex = p.LastIndexOf(']');
491                     if (rbIndex == -1)
492                         throw new XamlParseException("Binding: Indexer did not contain closing bracket", lineInfo);
493                     
494                     var argLength = rbIndex - lbIndex - 1;
495                     if (argLength == 0)
496                         throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
497
498                     indexArg = p.Substring(lbIndex + 1, argLength).Trim();
499                     if (indexArg.Length == 0)
500                         throw new XamlParseException("Binding: Indexer did not contain arguments", lineInfo);
501                     
502                     p = p.Substring(0, lbIndex);
503                     p = p.Trim();
504                 }
505
506                 if (p.Length > 0) {
507                     var property = previousPartTypeRef.GetProperty(pd => pd.Name == p && pd.GetMethod != null && pd.GetMethod.IsPublic, out _)
508                                                       ?? throw new XamlParseException($"Binding: Property '{p}' not found on '{previousPartTypeRef}'", lineInfo);
509                     properties.Add(new Tuple<PropertyDefinition, string>(property,null));
510                     previousPartTypeRef = property.PropertyType;
511                 }
512                 if (indexArg != null) {
513                     var defaultMemberAttribute = previousPartTypeRef.GetCustomAttribute(module, ("mscorlib", "System.Reflection", "DefaultMemberAttribute"));
514                     var indexerName = defaultMemberAttribute?.ConstructorArguments?.FirstOrDefault().Value as string ?? "Item";
515                     var indexer = previousPartTypeRef.GetProperty(pd => pd.Name == indexerName && pd.GetMethod != null && pd.GetMethod.IsPublic, out _);
516                     properties.Add(new Tuple<PropertyDefinition, string>(indexer, indexArg));
517                     if (indexer.PropertyType != module.TypeSystem.String && indexer.PropertyType != module.TypeSystem.Int32)
518                         throw new XamlParseException($"Binding: Unsupported indexer index type: {indexer.PropertyType.FullName}", lineInfo);
519                     previousPartTypeRef = indexer.PropertyType;
520                 }
521             }
522             return properties;
523         }
524
525         static IEnumerable<Instruction> CompiledBindingGetGetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
526         {
527 //            .method private static hidebysig default string '<Main>m__0' (class ViewModel vm)  cil managed
528 //            {
529 //                .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() =  (01 00 00 00 ) // ...
530 //
531 //                IL_0000:  ldarg.0 
532 //                IL_0001:  callvirt instance class ViewModel class ViewModel::get_Model()
533 //                IL_0006:  callvirt instance string class ViewModel::get_Text()
534 //                IL_0006:  ret
535 //            }
536
537             var module = context.Module;
538             var getter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
539                                               MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
540                                               tPropertyRef) {
541                 Parameters = {
542                     new ParameterDefinition(tSourceRef)
543                 },
544                 CustomAttributes = {
545                     new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
546                 }
547             };
548             getter.Body.InitLocals = true;
549             var il = getter.Body.GetILProcessor();
550
551             if (properties == null || properties.Count == 0) { //return self
552                 il.Emit(Ldarg_0);
553                 il.Emit(Ret);
554             }
555             else {
556                 if (tSourceRef.IsValueType)
557                     il.Emit(Ldarga_S, (byte)0);
558                 else
559                     il.Emit(Ldarg_0);
560
561                 foreach (var propTuple in properties) {
562                     var property = propTuple.Item1;
563                     var indexerArg = propTuple.Item2;
564                     if (indexerArg != null) {
565                         if (property.GetMethod.Parameters[0].ParameterType == module.TypeSystem.String)
566                             il.Emit(Ldstr, indexerArg);
567                         else if (property.GetMethod.Parameters[0].ParameterType == module.TypeSystem.Int32) {
568                             int index;
569                             if (!int.TryParse(indexerArg, out index))
570                                 throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
571                             il.Emit(Ldc_I4, index);
572                         }
573                     }
574                     if (property.GetMethod.IsVirtual)
575                         il.Emit(Callvirt, module.ImportReference(property.GetMethod));
576                     else
577                         il.Emit(Call, module.ImportReference(property.GetMethod));
578                     }
579
580                 il.Emit(Ret);
581             }
582             context.Body.Method.DeclaringType.Methods.Add(getter);
583
584 //            IL_0007:  ldnull
585 //            IL_0008:  ldftn string class Test::'<Main>m__0'(class ViewModel)
586 //            IL_000e:  newobj instance void class [mscorlib]System.Func`2<class ViewModel, string>::'.ctor'(object, native int)
587
588             yield return Create(Ldnull);
589             yield return Create(Ldftn, getter);
590             yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`2"), paramCount: 2, classArguments: new[] { tSourceRef, tPropertyRef }));
591         }
592
593         static IEnumerable<Instruction> CompiledBindingGetSetter(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
594         {
595             if (properties == null || properties.Count == 0) {
596                 yield return Create(Ldnull);
597                 yield break;
598             }
599
600             //            .method private static hidebysig default void '<Main>m__1' (class ViewModel vm, string s)  cil managed
601             //            {
602             //                .custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() =  (01 00 00 00 ) // ....
603             //
604             //                IL_0000:  ldarg.0 
605             //                IL_0001:  callvirt instance class ViewModel class ViewModel::get_Model()
606             //                IL_0006:  ldarg.1 
607             //                IL_0007:  callvirt instance void class ViewModel::set_Text(string)
608             //                IL_000c:  ret
609             //            }
610
611             var module = context.Module;
612             var setter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}",
613                                               MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static,
614                                               module.TypeSystem.Void) {
615                 Parameters = {
616                     new ParameterDefinition(tSourceRef),
617                     new ParameterDefinition(tPropertyRef)
618                 },
619                 CustomAttributes = {
620                     new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
621                 }
622             };
623             setter.Body.InitLocals = true;
624
625             var il = setter.Body.GetILProcessor();
626             var lastProperty = properties.LastOrDefault();
627             var setterRef = lastProperty?.Item1.SetMethod;
628             if (setterRef == null) {
629                 yield return Create(Ldnull); //throw or not ?
630                 yield break;
631             }
632
633             if (tSourceRef.IsValueType)
634                 il.Emit(Ldarga_S, (byte)0);
635             else
636                 il.Emit(Ldarg_0);
637             for (int i = 0; i < properties.Count - 1; i++) {
638                 var property = properties[i].Item1;
639                 var indexerArg = properties[i].Item2;
640                 if (indexerArg != null) {
641                     if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
642                         il.Emit(Ldstr, indexerArg);
643                     else if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
644                         int index;
645                         if (!int.TryParse(indexerArg, out index))
646                             throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
647                         il.Emit(Ldc_I4, index);
648                     }
649                 }
650                 if (property.GetMethod.IsVirtual)
651                     il.Emit(Callvirt, module.ImportReference(property.GetMethod));
652                 else
653                     il.Emit(Call, module.ImportReference(property.GetMethod));
654             }
655
656             var indexer = properties.Last().Item2;
657             if (indexer != null) {
658                 if (lastProperty.Item1.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
659                     il.Emit(Ldstr, indexer);
660                 else if (lastProperty.Item1.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
661                     int index;
662                     if (!int.TryParse(indexer, out index))
663                         throw new XamlParseException($"Binding: {indexer} could not be parsed as an index for a {lastProperty.Item1.Name}", node as IXmlLineInfo);
664                     il.Emit(Ldc_I4, index);
665                 }
666             }
667
668             il.Emit(Ldarg_1);
669
670             if (setterRef.IsVirtual)
671                 il.Emit(Callvirt, module.ImportReference(setterRef));
672             else
673                 il.Emit(Call, module.ImportReference(setterRef));
674
675             il.Emit(Ret);
676
677             context.Body.Method.DeclaringType.Methods.Add(setter);
678
679 //            IL_0024: ldnull
680 //            IL_0025: ldftn void class Test::'<Main>m__1'(class ViewModel, string)
681 //            IL_002b: newobj instance void class [mscorlib]System.Action`2<class ViewModel, string>::'.ctor'(object, native int)
682             yield return Create(Ldnull);
683             yield return Create(Ldftn, setter);
684             yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Action`2"),
685                                                                    paramCount: 2,
686                                                                    classArguments:
687                                                                    new[] { tSourceRef, tPropertyRef }));
688         }
689
690         static IEnumerable<Instruction> CompiledBindingGetHandlers(TypeReference tSourceRef, TypeReference tPropertyRef, IList<Tuple<PropertyDefinition, string>> properties, ElementNode node, ILContext context)
691         {
692 //            .method private static hidebysig default object '<Main>m__2'(class ViewModel vm)  cil managed {
693 //                .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() =  (01 00 00 00 ) // ....
694 //                IL_0000:  ldarg.0 
695 //                IL_0001:  ret
696 //            } // end of method Test::<Main>m__2
697
698 //            .method private static hidebysig default object '<Main>m__3' (class ViewModel vm)  cil managed {
699 //                .custom instance void class [mscorlib] System.Runtime.CompilerServices.CompilerGeneratedAttribute::'.ctor'() =  (01 00 00 00 ) // ....
700 //                IL_0000:  ldarg.0 
701 //                IL_0001:  callvirt instance class ViewModel class ViewModel::get_Model()
702 //                IL_0006:  ret
703 //            }
704
705             var module = context.Module;
706
707             var partGetters = new List<MethodDefinition>();
708             if (properties == null || properties.Count == 0) {
709                 yield return Instruction.Create(OpCodes.Ldnull);
710                 yield break;
711             }
712                 
713             for (int i = 0; i < properties.Count; i++) {
714                 var tuple = properties [i];
715                 var partGetter = new MethodDefinition($"<{context.Body.Method.Name}>typedBindingsM__{typedBindingCount++}", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.Static, module.TypeSystem.Object) {
716                     Parameters = {
717                         new ParameterDefinition(tSourceRef)
718                     },
719                     CustomAttributes = {
720                         new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null))
721                     }
722                 };
723                 partGetter.Body.InitLocals = true;
724                 var il = partGetter.Body.GetILProcessor();
725
726                 if (i == 0) { //return self
727                     il.Emit(Ldarg_0);
728                     if (tSourceRef.IsValueType)
729                         il.Emit(Box, module.ImportReference(tSourceRef));
730
731                     il.Emit(Ret);
732                     context.Body.Method.DeclaringType.Methods.Add(partGetter);
733                     partGetters.Add(partGetter);
734                     continue;
735                 }
736
737                 if (tSourceRef.IsValueType)
738                     il.Emit(Ldarga_S, (byte)0);
739                 else
740                     il.Emit(Ldarg_0);
741                 var lastGetterTypeRef = tSourceRef;
742                 for (int j = 0; j < i; j++) {
743                     var propTuple = properties [j];
744                     var property = propTuple.Item1;
745                     var indexerArg = propTuple.Item2;
746                     if (indexerArg != null) {
747                         if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.String)
748                             il.Emit(OpCodes.Ldstr, indexerArg);
749                         else if (property.GetMethod.Parameters [0].ParameterType == module.TypeSystem.Int32) {
750                             int index;
751                             if (!int.TryParse(indexerArg, out index))
752                                 throw new XamlParseException($"Binding: {indexerArg} could not be parsed as an index for a {property.Name}", node as IXmlLineInfo);
753                             il.Emit(OpCodes.Ldc_I4, index);
754                         }
755                     }
756                     if (property.GetMethod.IsVirtual)
757                         il.Emit(Callvirt, module.ImportReference(property.GetMethod));
758                     else
759                         il.Emit(Call, module.ImportReference(property.GetMethod));
760                     lastGetterTypeRef = property.PropertyType;
761                 }
762                 if (lastGetterTypeRef.IsValueType)
763                     il.Emit(Box, module.ImportReference(lastGetterTypeRef));
764
765                 il.Emit(OpCodes.Ret);
766                 context.Body.Method.DeclaringType.Methods.Add(partGetter);
767                 partGetters.Add(partGetter);
768             }
769
770             var funcObjRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Func`2")).MakeGenericInstanceType(new [] { tSourceRef, module.TypeSystem.Object }));
771             var tupleRef = context.Module.ImportReference(module.ImportReference(("mscorlib", "System", "Tuple`2")).MakeGenericInstanceType(new [] { funcObjRef, module.TypeSystem.String }));
772             var funcCtor = module.ImportReference(funcObjRef.ResolveCached().GetConstructors().First());
773             funcCtor = funcCtor.MakeGeneric(funcObjRef, new [] { tSourceRef, module.TypeSystem.Object });
774             var tupleCtor = module.ImportReference(tupleRef.ResolveCached().GetConstructors().First());
775             tupleCtor = tupleCtor.MakeGeneric(tupleRef, new [] { funcObjRef, module.TypeSystem.String});
776
777 //            IL_003a:  ldc.i4.2 
778 //            IL_003b:  newarr class [mscorlib] System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel,object>,string>
779
780 //            IL_0040:  dup
781 //            IL_0041:  ldc.i4.0 
782 //            IL_0049:  ldnull
783 //            IL_004a:  ldftn object class Test::'<Main>m__2'(class ViewModel)
784 //            IL_0050:  newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
785 //            IL_005f:  ldstr "Model"
786 //            IL_0064:  newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
787 //            IL_0069:  stelem.ref 
788
789 //            IL_006a:  dup
790 //            IL_006b:  ldc.i4.1 
791 //            IL_0073:  ldnull
792 //            IL_0074:  ldftn object class Test::'<Main>m__3'(class ViewModel)
793 //            IL_007a:  newobj instance void class [mscorlib]System.Func`2<class ViewModel, object>::'.ctor'(object, native int)
794 //            IL_0089:  ldstr "Text"
795 //            IL_008e:  newobj instance void class [mscorlib]System.Tuple`2<class [mscorlib]System.Func`2<class ViewModel, object>, string>::'.ctor'(!0, !1)
796 //            IL_0093:  stelem.ref 
797
798             yield return Instruction.Create(OpCodes.Ldc_I4, properties.Count);
799             yield return Instruction.Create(OpCodes.Newarr, tupleRef);
800
801             for (var i = 0; i < properties.Count; i++) {
802                 yield return Instruction.Create(OpCodes.Dup);
803                 yield return Instruction.Create(OpCodes.Ldc_I4, i);
804                 yield return Instruction.Create(OpCodes.Ldnull);
805                 yield return Instruction.Create(OpCodes.Ldftn, partGetters [i]);
806                 yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(funcCtor));
807                 yield return Instruction.Create(OpCodes.Ldstr, properties [i].Item1.Name);
808                 yield return Instruction.Create(OpCodes.Newobj, module.ImportReference(tupleCtor));
809                 yield return Instruction.Create(OpCodes.Stelem_Ref);
810             }
811         }
812
813         public static IEnumerable<Instruction> SetPropertyValue(VariableDefinition parent, XmlName propertyName, INode valueNode, ILContext context, IXmlLineInfo iXmlLineInfo)
814         {
815             var module = context.Body.Method.Module;
816             var localName = propertyName.LocalName;
817             bool attached;
818
819             var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, iXmlLineInfo);
820
821             //If the target is an event, connect
822             if (CanConnectEvent(parent, localName, attached))
823             {
824                 var instrunctions = ConnectEvent(parent, localName, valueNode, iXmlLineInfo, context);
825                 if (null != context.InsOfAddEvent)
826                 {
827                     foreach (var ins in instrunctions)
828                     {
829                         context.InsOfAddEvent.Add(ins);
830                     }
831                 }
832                 return instrunctions;
833             }
834
835             //If Value is DynamicResource, SetDynamicResource
836             if (CanSetDynamicResource(bpRef, valueNode, context))
837                 return SetDynamicResource(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
838
839             //If Value is a BindingBase and target is a BP, SetBinding
840             if (CanSetBinding(bpRef, valueNode, context))
841                 return SetBinding(parent, bpRef, valueNode as IElementNode, iXmlLineInfo, context);
842
843             //If it's a property, set it
844             if (CanSet(parent, localName, valueNode, context))
845                 return Set(parent, localName, valueNode, iXmlLineInfo, context);
846
847             //If it's a BP, SetValue ()
848             if (CanSetValue(bpRef, attached, valueNode, iXmlLineInfo, context))
849                 return SetValue(parent, bpRef, valueNode, iXmlLineInfo, context);
850
851             //If it's an already initialized property, add to it
852             if (CanAdd(parent, propertyName, valueNode, iXmlLineInfo, context))
853                 return Add(parent, propertyName, valueNode, iXmlLineInfo, context);
854
855             throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
856         }
857
858         public static IEnumerable<Instruction> GetPropertyValue(VariableDefinition parent, XmlName propertyName, ILContext context, IXmlLineInfo lineInfo, out TypeReference propertyType)
859         {
860             var module = context.Body.Method.Module;
861             var localName = propertyName.LocalName;
862             bool attached;
863             var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
864
865             //If it's a BP, GetValue ()
866             if (CanGetValue(parent, bpRef, attached, lineInfo, context, out _))
867                 return GetValue(parent, bpRef, lineInfo, context, out propertyType);
868
869             //If it's a property, set it
870             if (CanGet(parent, localName, context, out _))
871                 return Get(parent, localName, lineInfo, context, out propertyType);
872
873             throw new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
874         }
875
876         static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, out bool attached, ILContext context, IXmlLineInfo iXmlLineInfo)
877         {
878             var module = context.Body.Method.Module;
879             TypeReference declaringTypeReference;
880
881             //If it's an attached BP, update elementType and propertyName
882             var bpOwnerType = parent.VariableType;
883             attached = GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo);
884             var name = $"{localName}Property";
885             FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name &&
886                                                         fd.IsStatic &&
887                                                         (fd.IsPublic || fd.IsAssembly), out declaringTypeReference);
888             if (bpRef != null) {
889                 bpRef = module.ImportReference(bpRef.ResolveGenericParameters(declaringTypeReference));
890                 bpRef.FieldType = module.ImportReference(bpRef.FieldType);
891             }
892             return bpRef;
893         }
894
895         static bool CanConnectEvent(VariableDefinition parent, string localName, bool attached)
896         {
897             return !attached && parent.VariableType.GetEvent(ed => ed.Name == localName, out _) != null;
898         }
899
900         static IEnumerable<Instruction> ConnectEvent(VariableDefinition parent, string localName, INode valueNode, IXmlLineInfo iXmlLineInfo, ILContext context)
901         {
902             var elementType = parent.VariableType;
903             var module = context.Body.Method.Module;
904             TypeReference eventDeclaringTypeRef;
905
906             var eventinfo = elementType.GetEvent(ed => ed.Name == localName, out eventDeclaringTypeRef);
907
908 //            IL_0007:  ldloc.0 
909 //            IL_0008:  ldarg.0 
910 //
911 //            IL_0009:  ldftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
912 //OR, if the handler is virtual
913 //            IL_000x:  ldarg.0 
914 //            IL_0009:  ldvirtftn instance void class Tizen.NUI.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs)
915 //
916 //            IL_000f:  newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int)
917 //            IL_0014:  callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Button::add_Clicked(class [mscorlib]System.EventHandler)
918
919             var value = ((ValueNode)valueNode).Value;
920
921             yield return Create(Ldloc, parent);
922             if (context.Root is VariableDefinition)
923                 yield return Create(Ldloc, context.Root as VariableDefinition);
924             else if (context.Root is FieldDefinition) {
925                 yield return Create(Ldarg_0);
926                 yield return Create(Ldfld, context.Root as FieldDefinition);
927             } else 
928                 throw new InvalidProgramException();
929             var declaringType = context.Body.Method.DeclaringType;
930             while (declaringType.IsNested)
931                 declaringType = declaringType.DeclaringType;
932             var handler = declaringType.AllMethods().FirstOrDefault(md => md.Name == value as string);
933             if (handler == null) 
934                 throw new XamlParseException($"EventHandler \"{value}\" not found in type \"{context.Body.Method.DeclaringType.FullName}\"", iXmlLineInfo);
935
936             //check if the handler signature matches the Invoke signature;
937             var invoke = module.ImportReference(eventinfo.EventType.ResolveCached().GetMethods().First(md => md.Name == "Invoke"));
938             invoke = invoke.ResolveGenericParameters(eventinfo.EventType, module);
939             if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
940             {
941                 TypeDefinition realType = eventinfo.EventType.ResolveCached();
942
943                 GenericInstanceType genericInstanceType = eventinfo.EventType as GenericInstanceType;
944
945                 if (null != genericInstanceType
946                     && genericInstanceType.GenericArguments.Count == realType.GenericParameters.Count)
947                 {
948                     Dictionary<string, TypeReference> dict = new Dictionary<string, TypeReference>();
949
950                     for (int i = 0; i < realType.GenericParameters.Count; i++)
951                     {
952                         string p = realType.GenericParameters[i].Name;
953                         TypeReference type = genericInstanceType.GenericArguments[i];
954
955                         dict.Add(p, type);
956                     }
957
958                     if (dict.ContainsKey(invoke.ReturnType.Name))
959                     {
960                         invoke.ReturnType = dict[invoke.ReturnType.Name];
961                     }
962
963                     for (int i = 0; i < invoke.Parameters.Count; i++)
964                     {
965                         if (dict.ContainsKey(invoke.Parameters[i].ParameterType.Name))
966                         {
967                             invoke.Parameters[i].ParameterType = dict[invoke.Parameters[i].ParameterType.Name];
968                         }
969                     }
970                 }
971             }
972
973             if (!handler.ReturnType.InheritsFromOrImplements(invoke.ReturnType))
974                 throw new XamlParseException($"Signature (return type) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
975             if (invoke.Parameters.Count != handler.Parameters.Count)
976                 throw new XamlParseException($"Signature (number of arguments) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
977             if (!invoke.ContainsGenericParameter)
978                 for (var i = 0; i < invoke.Parameters.Count;i++)
979                     if (!handler.Parameters[i].ParameterType.InheritsFromOrImplements(invoke.Parameters[i].ParameterType))
980                         throw new XamlParseException($"Signature (parameter {i}) of EventHandler \"{context.Body.Method.DeclaringType.FullName}.{value}\" doesn't match the event type", iXmlLineInfo);
981
982             if (handler.IsVirtual) {
983                 yield return Create(Ldarg_0);
984                 yield return Create(Ldvirtftn, handler);
985             } else
986                 yield return Create(Ldftn, handler);
987
988             //FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible).
989             var ctor = module.ImportReference(eventinfo.EventType.ResolveCached().GetConstructors().First());
990             ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module);
991             yield return Create(Newobj, module.ImportReference(ctor));
992             //Check if the handler has the same signature as the ctor (it should)
993             var adder = module.ImportReference(eventinfo.AddMethod);
994             adder = adder.ResolveGenericParameters(eventDeclaringTypeRef, module);
995             yield return Create(Callvirt, module.ImportReference(adder));
996         }
997
998         static bool CanSetDynamicResource(FieldReference bpRef, INode valueNode, ILContext context)
999         {
1000             if (bpRef == null)
1001                 return false;
1002             var elementNode = valueNode as IElementNode;
1003             if (elementNode == null)
1004                 return false;
1005             
1006             VariableDefinition varValue;
1007             if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
1008                 return false;
1009             return varValue.VariableType.FullName == typeof(DynamicResource).FullName;
1010         }
1011
1012         static IEnumerable<Instruction> SetDynamicResource(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
1013         {
1014             var module = context.Body.Method.Module;
1015
1016             yield return Create(Ldloc, parent);
1017             yield return Create(Ldsfld, bpRef);
1018             yield return Create(Ldloc, context.Variables[elementNode]);
1019             yield return Create(Callvirt, module.ImportPropertyGetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "DynamicResource"), propertyName: "Key"));
1020             yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingInternalNameSpace, "IDynamicResourceHandler"),
1021                                                                        methodName: "SetDynamicResource",
1022                                                                        parameterTypes: new[] {
1023                                                                            (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
1024                                                                            ("mscorlib", "System", "String"),
1025                                                                        }));
1026         }
1027
1028         static bool CanSetBinding(FieldReference bpRef, INode valueNode, ILContext context)
1029         {
1030             var module = context.Body.Method.Module;
1031
1032             if (bpRef == null)
1033                 return false;
1034             var elementNode = valueNode as IElementNode;
1035             if (elementNode == null)
1036                 return false;
1037
1038             VariableDefinition varValue;
1039             if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
1040                 return false;
1041
1042             var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")), module);
1043             if (implicitOperator != null)
1044                 return true;
1045
1046             return varValue.VariableType.InheritsFromOrImplements(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")));
1047         }
1048
1049         static IEnumerable<Instruction> SetBinding(VariableDefinition parent, FieldReference bpRef, IElementNode elementNode, IXmlLineInfo iXmlLineInfo, ILContext context)
1050         {
1051             var module = context.Body.Method.Module;
1052             var varValue = context.Variables [elementNode];
1053             var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase")), module);
1054
1055             //TODO: check if parent is a BP
1056             yield return Create(Ldloc, parent);
1057             yield return Create(Ldsfld, bpRef);
1058             yield return Create(Ldloc, varValue);
1059             if (implicitOperator != null) 
1060 //                IL_000f:  call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<BindingBase>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
1061                 yield return Create(Call, module.ImportReference(implicitOperator));
1062             yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
1063                                                                        methodName: "SetBinding",
1064                                                                        parameterTypes: new[] {
1065                                                                            (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
1066                                                                            (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindingBase"),
1067                                                                        }));
1068         }
1069
1070         static bool CanSetValue(FieldReference bpRef, bool attached, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1071         {
1072             var module = context.Body.Method.Module;
1073
1074             if (bpRef == null)
1075                 return false;
1076
1077             var valueNode = node as ValueNode;
1078             if (valueNode != null && valueNode.CanConvertValue(context.Body.Method.Module, bpRef))
1079                 return true;
1080
1081             var elementNode = node as IElementNode;
1082             if (elementNode == null)
1083                 return false;
1084
1085             VariableDefinition varValue;
1086             if (!context.Variables.TryGetValue(elementNode, out varValue))
1087                 return false;
1088
1089             var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1090             // If it's an attached BP, there's no second chance to handle IMarkupExtensions, so we try here.
1091             // Worst case scenario ? InvalidCastException at runtime
1092             if (attached && varValue.VariableType.FullName == "System.Object") 
1093                 return true;
1094             var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
1095             if (implicitOperator != null)
1096                 return true;
1097
1098             //as we're in the SetValue Scenario, we can accept value types, they'll be boxed
1099             if (varValue.VariableType.IsValueType && bpTypeRef.FullName == "System.Object")
1100                 return true;
1101
1102             return varValue.VariableType.InheritsFromOrImplements(bpTypeRef);
1103         }
1104
1105         static bool CanGetValue(VariableDefinition parent, FieldReference bpRef, bool attached, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1106         {
1107             var module = context.Body.Method.Module;
1108             propertyType = null;
1109
1110             if (bpRef == null)
1111                 return false;
1112
1113             if (!parent.VariableType.InheritsFromOrImplements(module.ImportReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"))))
1114                 return false;
1115
1116             propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1117             return true;
1118         }
1119
1120         static IEnumerable<Instruction> SetValue(VariableDefinition parent, FieldReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1121         {
1122             var valueNode = node as ValueNode;
1123             var elementNode = node as IElementNode;
1124             var module = context.Body.Method.Module;
1125
1126 //            IL_0007:  ldloc.0 
1127 //            IL_0008:  ldsfld class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableProperty [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::TextProperty
1128 //            IL_000d:  ldstr "foo"
1129 //            IL_0012:  callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableObject::SetValue(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.BindableProperty, object)
1130
1131             yield return Create(Ldloc, parent);
1132             yield return Create(Ldsfld, bpRef);
1133
1134             if (valueNode != null) {
1135                 foreach (var instruction in valueNode.PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef:bpRef), true, false))
1136                     yield return instruction;
1137             } else if (elementNode != null) {
1138                 var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1139                 var varDef = context.Variables[elementNode];
1140                 var varType = varDef.VariableType;
1141                 var implicitOperator = varDef.VariableType.GetImplicitOperatorTo(bpTypeRef, module);
1142                 yield return Create(Ldloc, varDef);
1143                 if (implicitOperator != null) {
1144                     yield return Create(Call, module.ImportReference(implicitOperator));
1145                     varType = module.ImportReference(bpTypeRef);
1146                 }
1147                 if (varType.IsValueType)
1148                     yield return Create(Box, varType);
1149             }
1150             yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
1151                                                                        methodName: "SetValue",
1152                                                                        parameterTypes: new[] {
1153                                                                            (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty"),
1154                                                                            ("mscorlib", "System", "Object"),
1155                                                                        }));
1156         }
1157
1158         static IEnumerable<Instruction> GetValue(VariableDefinition parent, FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1159         {
1160             var module = context.Body.Method.Module;
1161             propertyType = bpRef.GetBindablePropertyType(iXmlLineInfo, module);
1162
1163             return new[] {
1164                 Create(Ldloc, parent),
1165                 Create(Ldsfld, bpRef),
1166                 Create(Callvirt,  module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableObject"),
1167                                                                methodName: "GetValue",
1168                                                                parameterTypes: new[] { (XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "BindableProperty") })),
1169             };
1170         }
1171
1172         static bool CanSet(VariableDefinition parent, string localName, INode node, ILContext context)
1173         {
1174             var module = context.Body.Method.Module;
1175             TypeReference declaringTypeReference;
1176             var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1177             if (property == null)
1178                 return false;
1179             var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
1180             var propertySetter = property.SetMethod;
1181             if (propertySetter == null || !propertySetter.IsPublic || propertySetter.IsStatic)
1182                 return false;
1183
1184             var valueNode = node as ValueNode;
1185             if (valueNode != null && valueNode.CanConvertValue(context.Body.Method.Module, propertyType, new ICustomAttributeProvider[] { property, propertyType.ResolveCached()}))
1186                 return true;
1187
1188             var elementNode = node as IElementNode;
1189             if (elementNode == null)
1190                 return false;
1191
1192             var vardef = context.Variables [elementNode];
1193             var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
1194
1195             if (vardef.VariableType.InheritsFromOrImplements(propertyType))
1196                 return true;
1197             if (implicitOperator != null)
1198                 return true;
1199             if (propertyType.FullName == "System.Object")
1200                 return true;
1201
1202             //I'd like to get rid of this condition. This comment used to be //TODO replace latest check by a runtime type check
1203             if (vardef.VariableType.FullName == "System.Object")
1204                 return true;
1205
1206             return false;
1207         }
1208
1209         static bool CanGet(VariableDefinition parent, string localName, ILContext context, out TypeReference propertyType)
1210         {
1211             var module = context.Body.Method.Module;
1212             propertyType = null;
1213             TypeReference declaringTypeReference;
1214             var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1215             if (property == null)
1216                 return false;
1217             var propertyGetter = property.GetMethod;
1218             if (propertyGetter == null || !propertyGetter.IsPublic || propertyGetter.IsStatic)
1219                 return false;
1220
1221             module.ImportReference(parent.VariableType.ResolveCached());
1222             var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
1223             propertyGetterRef.ImportTypes(module);
1224             propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
1225
1226             return true;
1227         }
1228
1229         static IEnumerable<Instruction> Set(VariableDefinition parent, string localName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1230         {
1231             var module = context.Body.Method.Module;
1232             TypeReference declaringTypeReference;
1233             var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference);
1234             var propertySetter = property.SetMethod;
1235
1236 //            IL_0007:  ldloc.0
1237 //            IL_0008:  ldstr "foo"
1238 //            IL_000d:  callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.Label::set_Text(string)
1239
1240             module.ImportReference(parent.VariableType.ResolveCached());
1241             var propertySetterRef = module.ImportReference(module.ImportReference(propertySetter).ResolveGenericParameters(declaringTypeReference, module));
1242             propertySetterRef.ImportTypes(module);
1243             var propertyType = property.ResolveGenericPropertyType(declaringTypeReference, module);
1244             var valueNode = node as ValueNode;
1245             var elementNode = node as IElementNode;
1246
1247             //if it's a value type, load the address so we can invoke methods on it
1248             if (parent.VariableType.IsValueType)
1249                 yield return Instruction.Create(OpCodes.Ldloca, parent);
1250             else
1251                 yield return Instruction.Create(OpCodes.Ldloc, parent);
1252
1253             if (valueNode != null) {
1254                 foreach (var instruction in valueNode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider [] { property, propertyType.ResolveCached() }, valueNode.PushServiceProvider(context, propertyRef:property), false, true))
1255                     yield return instruction;
1256                 if (parent.VariableType.IsValueType)
1257                     yield return Instruction.Create(OpCodes.Call, propertySetterRef);
1258                 else
1259                     yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
1260             } else if (elementNode != null) {
1261                 var vardef = context.Variables [elementNode];
1262                 var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(propertyType, module);
1263                 yield return Instruction.Create(OpCodes.Ldloc, vardef);
1264                 if (!vardef.VariableType.InheritsFromOrImplements(propertyType) && implicitOperator != null) {
1265 //                    IL_000f:  call !0 class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<bool>::op_Implicit(class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.OnPlatform`1<!0>)
1266                     yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
1267                 } else if (!vardef.VariableType.IsValueType && propertyType.IsValueType)
1268                     yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(propertyType));
1269                 else if (vardef.VariableType.IsValueType && propertyType.FullName == "System.Object")
1270                     yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
1271                 if (parent.VariableType.IsValueType)
1272                     yield return Instruction.Create(OpCodes.Call, propertySetterRef);
1273                 else
1274                     yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef);
1275             }
1276         }
1277
1278         static IEnumerable<Instruction> Get(VariableDefinition parent, string localName, IXmlLineInfo iXmlLineInfo, ILContext context, out TypeReference propertyType)
1279         {
1280             var module = context.Body.Method.Module;
1281             var property = parent.VariableType.GetProperty(pd => pd.Name == localName, out var declaringTypeReference);
1282             var propertyGetter = property.GetMethod;
1283
1284             module.ImportReference(parent.VariableType.ResolveCached());
1285             var propertyGetterRef = module.ImportReference(module.ImportReference(propertyGetter).ResolveGenericParameters(declaringTypeReference, module));
1286             propertyGetterRef.ImportTypes(module);
1287             propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference);
1288
1289             if (parent.VariableType.IsValueType)
1290                 return new[] {
1291                     Instruction.Create(OpCodes.Ldloca, parent),
1292                     Instruction.Create(OpCodes.Call, propertyGetterRef),
1293                 };
1294             else
1295                 return new[] {
1296                     Instruction.Create(OpCodes.Ldloc, parent),
1297                     Instruction.Create(OpCodes.Callvirt, propertyGetterRef),
1298                 };
1299         }
1300
1301         static bool CanAdd(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo lineInfo, ILContext context)
1302         {
1303             var module = context.Body.Method.Module;
1304             var localName = propertyName.LocalName;
1305             bool attached;
1306             var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, out attached, context, lineInfo);
1307             TypeReference propertyType;
1308
1309             if (   !CanGetValue(parent, bpRef, attached, null, context, out propertyType)
1310                 && !CanGet(parent, localName, context, out propertyType))
1311                 return false;
1312
1313             //TODO check md.Parameters[0] type
1314             var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1315             if (adderTuple == null)
1316                 return false;
1317
1318             return true;
1319         }
1320
1321         static Dictionary<VariableDefinition, IList<string>> resourceNamesInUse = new Dictionary<VariableDefinition, IList<string>>();
1322         static bool CanAddToResourceDictionary(VariableDefinition parent, TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, ILContext context)
1323         {
1324             if (   collectionType.FullName != "Tizen.NUI.Binding.ResourceDictionary"
1325                 && collectionType.ResolveCached().BaseType?.FullName != "Tizen.NUI.Binding.ResourceDictionary")
1326                 return false;
1327
1328
1329             if (node.Properties.ContainsKey(XmlName.xKey)) {
1330                 var key = (node.Properties[XmlName.xKey] as ValueNode).Value as string;
1331                 if (!resourceNamesInUse.TryGetValue(parent, out var names))
1332                     resourceNamesInUse[parent] = (names = new List<string>());
1333                 if (names.Contains(key))
1334                     throw new XamlParseException($"A resource with the key '{key}' is already present in the ResourceDictionary.", lineInfo);
1335                 names.Add(key);
1336                 return true;
1337             }
1338
1339             //is there a RD.Add() overrides that accepts this ?
1340             var nodeTypeRef = context.Variables[node].VariableType;
1341             var module = context.Body.Method.Module;
1342             if (module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
1343                                              methodName: "Add",
1344                                              parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }) != null)
1345                 return true;
1346
1347             throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
1348         }
1349
1350         static IEnumerable<Instruction> Add(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
1351         {
1352             var module = context.Body.Method.Module;
1353             var elementNode = node as IElementNode;
1354             var vardef = context.Variables [elementNode];
1355
1356             TypeReference propertyType;
1357             foreach (var instruction in GetPropertyValue(parent, propertyName, context, iXmlLineInfo, out propertyType))
1358                 yield return instruction;
1359
1360             if (CanAddToResourceDictionary(parent, propertyType, elementNode, iXmlLineInfo, context)) {
1361                 foreach (var instruction in AddToResourceDictionary(elementNode, iXmlLineInfo, context))
1362                     yield return instruction;
1363                 yield break;
1364             }
1365
1366             var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
1367             var adderRef = module.ImportReference(adderTuple.Item1);
1368             adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
1369             var childType = GetParameterType(adderRef.Parameters[0]);
1370             var implicitOperator = vardef.VariableType.GetImplicitOperatorTo(childType, module);
1371
1372             yield return Instruction.Create(OpCodes.Ldloc, vardef);
1373             if (implicitOperator != null)
1374                 yield return Instruction.Create(OpCodes.Call, module.ImportReference(implicitOperator));
1375             if (implicitOperator == null && vardef.VariableType.IsValueType && !childType.IsValueType)
1376                 yield return Instruction.Create(OpCodes.Box, vardef.VariableType);
1377             yield return Instruction.Create(OpCodes.Callvirt, adderRef);
1378             if (adderRef.ReturnType.FullName != "System.Void")
1379                 yield return Instruction.Create(OpCodes.Pop);
1380         }
1381
1382         static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, ILContext context)
1383         {
1384             var module = context.Body.Method.Module;
1385
1386             if (node.Properties.ContainsKey(XmlName.xKey)) {
1387 //                IL_0014:  ldstr "key"
1388 //                IL_0019:  ldstr "foo"
1389 //                IL_001e:  callvirt instance void class [Tizen.NUI.Xaml.Core]Tizen.NUI.Xaml.ResourceDictionary::Add(string, object)
1390                 yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
1391                 var varDef = context.Variables[node];
1392                 yield return Create(Ldloc, varDef);
1393                 if (varDef.VariableType.IsValueType)
1394                     yield return Create(Box, module.ImportReference(varDef.VariableType));
1395                 yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
1396                                                                            methodName: "Add",
1397                                                                            parameterTypes: new[] {
1398                                                                                ("mscorlib", "System", "String"),
1399                                                                                ("mscorlib", "System", "Object"),
1400                                                                            }));
1401                 yield break;
1402             }
1403
1404             var nodeTypeRef = context.Variables[node].VariableType;
1405             yield return Create(Ldloc, context.Variables[node]);
1406             yield return Create(Callvirt, module.ImportMethodReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "ResourceDictionary"),
1407                                                                        methodName: "Add",
1408                                                                        parameterTypes: new[] { (nodeTypeRef.Scope.Name, nodeTypeRef.Namespace, nodeTypeRef.Name) }));
1409             yield break;
1410         }
1411
1412         public static TypeReference GetParameterType(ParameterDefinition param)
1413         {
1414             if (!param.ParameterType.IsGenericParameter)
1415                 return param.ParameterType;
1416             var type = (param.Method as MethodReference).DeclaringType as GenericInstanceType;
1417             return type.GenericArguments [0];
1418         }
1419
1420         static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname,
1421             ILContext context, IXmlLineInfo lineInfo)
1422         {
1423             var dotIdx = localname.IndexOf('.');
1424             if (dotIdx > 0)
1425             {
1426                 var typename = localname.Substring(0, dotIdx);
1427                 localname = localname.Substring(dotIdx + 1);
1428                 elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, context.Body.Method.Module, lineInfo);
1429                 return true;
1430             }
1431             return false;
1432         }
1433
1434         static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext,
1435             IXmlLineInfo xmlLineInfo)
1436         {
1437             var parentVar = parentContext.Variables[parentNode];
1438             //Push the DataTemplate to the stack, for setting the template
1439             parentContext.IL.Emit(OpCodes.Ldloc, parentVar);
1440
1441             //Create nested class
1442             //            .class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0'
1443             //            extends [mscorlib]System.Object
1444
1445
1446             var module = parentContext.Module;
1447             var anonType = new TypeDefinition(
1448                 null,
1449                 "_" + parentContext.Body.Method.Name + "_anonXamlCDataTemplate_" + dtcount++,
1450                 TypeAttributes.BeforeFieldInit |
1451                 TypeAttributes.Sealed |
1452                 TypeAttributes.NestedPrivate) {
1453                 BaseType = module.TypeSystem.Object,
1454                 CustomAttributes = {
1455                     new CustomAttribute (module.ImportCtorReference(("mscorlib", "System.Runtime.CompilerServices", "CompilerGeneratedAttribute"), parameterTypes: null)),
1456                 }
1457             };
1458
1459             parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType);
1460             var ctor = anonType.AddDefaultConstructor();
1461
1462             var loadTemplate = new MethodDefinition("LoadDataTemplate",
1463                 MethodAttributes.Assembly | MethodAttributes.HideBySig,
1464                 module.TypeSystem.Object);
1465             loadTemplate.Body.InitLocals = true;
1466             anonType.Methods.Add(loadTemplate);
1467
1468             var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.ImportArrayReference(("mscorlib", "System", "Object")));
1469             anonType.Fields.Add(parentValues);
1470
1471             TypeReference rootType = null;
1472             var vdefRoot = parentContext.Root as VariableDefinition;
1473             if (vdefRoot != null)
1474                 rootType = vdefRoot.VariableType;
1475             var fdefRoot = parentContext.Root as FieldDefinition;
1476             if (fdefRoot != null)
1477                 rootType = fdefRoot.FieldType;
1478
1479             var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType);
1480             anonType.Fields.Add(root);
1481
1482             //Fill the loadTemplate Body
1483             var templateIl = loadTemplate.Body.GetILProcessor();
1484             templateIl.Emit(OpCodes.Nop);
1485             var templateContext = new ILContext(templateIl, loadTemplate.Body, null, module, parentContext.EmbeddedResourceNameSpace, parentValues)
1486             {
1487                 Root = root
1488             };
1489             node.Accept(new CreateObjectVisitor(templateContext), null);
1490             node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null);
1491             node.Accept(new SetFieldVisitor(templateContext), null);
1492             node.Accept(new SetResourcesVisitor(templateContext), null);
1493             node.Accept(new SetPropertiesVisitor(templateContext, stopOnResourceDictionary: true), null);
1494
1495             templateIl.Emit(OpCodes.Ldloc, templateContext.Variables[node]);
1496             templateIl.Emit(OpCodes.Ret);
1497
1498             //Instanciate nested class
1499             var parentIl = parentContext.IL;
1500             parentIl.Emit(OpCodes.Newobj, ctor);
1501
1502             //Copy required local vars
1503             parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
1504             parentIl.Append(node.PushParentObjectsArray(parentContext));
1505             parentIl.Emit(OpCodes.Stfld, parentValues);
1506             parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance
1507             if (parentContext.Root is VariableDefinition)
1508                 parentIl.Emit(OpCodes.Ldloc, parentContext.Root as VariableDefinition);
1509             else if (parentContext.Root is FieldDefinition)
1510             {
1511                 parentIl.Emit(OpCodes.Ldarg_0);
1512                 parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition);
1513             }
1514             else
1515                 throw new InvalidProgramException();
1516             parentIl.Emit(OpCodes.Stfld, root);
1517
1518             //SetDataTemplate
1519             parentIl.Emit(Ldftn, loadTemplate);
1520             parentIl.Emit(Newobj, module.ImportCtorReference(("mscorlib", "System", "Func`1"),
1521                                                              classArguments: new[] { ("mscorlib", "System", "Object") },
1522                                                              paramCount: 2));
1523
1524             var setterRef = module.ImportPropertySetterReference((XamlCTask.bindingAssemblyName, XamlCTask.bindingNameSpace, "IDataTemplate"), propertyName: "LoadTemplate");
1525             parentContext.IL.Emit(OpCodes.Callvirt, setterRef);
1526
1527             loadTemplate.Body.Optimize();
1528         }
1529
1530         bool TrySetRuntimeName(XmlName propertyName, VariableDefinition variableDefinition, ValueNode node)
1531         {
1532             if (propertyName != XmlName.xName)
1533                 return false;
1534
1535             var attributes = variableDefinition.VariableType.ResolveCached()
1536                 .CustomAttributes.Where(attribute => attribute.AttributeType.FullName == "Tizen.NUI.Xaml.RuntimeNamePropertyAttribute").ToList();
1537
1538             if (!attributes.Any())
1539                 return false;
1540
1541             var runTimeName = attributes[0].ConstructorArguments[0].Value as string;
1542
1543             if (string.IsNullOrEmpty(runTimeName)) 
1544                 return false;
1545
1546             Context.IL.Append(SetPropertyValue(variableDefinition, new XmlName("", runTimeName), node, Context, node));
1547             return true;
1548         }
1549     }
1550 }
1551