[NUI] Add file comment and end empty line
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / XamlBuild / NodeILExtensions.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;
19 using System.Collections.Generic;
20 using System.Globalization;
21 using System.Linq;
22 using System.Xml;
23 using Mono.Cecil;
24 using Mono.Cecil.Cil;
25 using Tizen.NUI.Binding;
26 using Tizen.NUI.EXaml;
27 using Tizen.NUI.EXaml.Build.Tasks;
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     static class NodeILExtensions
36     {
37         public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders)
38         {
39             TypeReference typeConverter = null;
40             foreach (var attributeProvider in attributeProviders) {
41                 CustomAttribute typeConverterAttribute;
42                 if (
43                     (typeConverterAttribute =
44                         attributeProvider.CustomAttributes.FirstOrDefault(
45                             cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null) {
46                     typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
47                     break;
48                 }
49             }
50
51             return node.CanConvertValue(module, targetTypeRef, typeConverter);
52         }
53
54         public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, MemberReference bpRef)
55         {
56             var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
57             var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
58             return node.CanConvertValue(module, targetTypeRef, typeConverter);
59         }
60
61         public static bool CanConvertValue(this ValueNode node, ModuleDefinition module, TypeReference targetTypeRef, TypeReference typeConverter)
62         {
63             var str = (string)node.Value;
64
65             //If there's a [TypeConverter], use it
66             if (typeConverter != null && str != null) {
67                 var typeConvAttribute = typeConverter.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "TypeConversionAttribute"));
68                 if (typeConvAttribute == null) //trust the unattributed TypeConverter
69                     return true;
70                 var toType = typeConvAttribute.ConstructorArguments.First().Value as TypeReference;
71                 return toType.InheritsFromOrImplements(targetTypeRef);
72             }
73
74             if (targetTypeRef.FullName == "System.String")
75             {
76                 return true;
77             }
78
79             var implicitOperator = targetTypeRef.GetImplicitOperatorTo(module.ImportReference(node.Value.GetType()), module);
80             if (implicitOperator != null)
81             {
82                 return true;
83             }
84
85             if (true == targetTypeRef.IsInterface(typeof(IList).FullName))
86             {
87                 return false;
88             }
89
90             ///No reason to return false
91             return true;
92         }
93
94         public static object GetBaseValue(EXamlContext context, string str, TypeReference targetTypeRef)
95         {
96             //Obvious Built-in conversions
97             if (str == null) //if default parameter is null, exception will throw
98                 return null;
99             else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
100                 return GetParsedEnum(context, targetTypeRef, str);
101             else if (targetTypeRef.FullName == "System.Char")
102                 return Char.Parse(str);
103             else if (targetTypeRef.FullName == "System.SByte")
104                 return SByte.Parse(str, CultureInfo.InvariantCulture);
105             else if (targetTypeRef.FullName == "System.Int16")
106                 return Int16.Parse(str, CultureInfo.InvariantCulture);
107             else if (targetTypeRef.FullName == "System.Int32")
108                 return Int32.Parse(str, CultureInfo.InvariantCulture);
109             else if (targetTypeRef.FullName == "System.Int64")
110                 return Int64.Parse(str, CultureInfo.InvariantCulture);
111             else if (targetTypeRef.FullName == "System.Byte")
112                 return Byte.Parse(str, CultureInfo.InvariantCulture);
113             else if (targetTypeRef.FullName == "System.UInt16")
114                 return UInt16.Parse(str, CultureInfo.InvariantCulture);
115             else if (targetTypeRef.FullName == "System.UInt32")
116                 return UInt32.Parse(str, CultureInfo.InvariantCulture);
117             else if (targetTypeRef.FullName == "System.UInt64")
118                 return UInt64.Parse(str, CultureInfo.InvariantCulture);
119             else if (targetTypeRef.FullName == "System.Single")
120                 return Single.Parse(str, CultureInfo.InvariantCulture);
121             else if (targetTypeRef.FullName == "System.Double")
122                 return Double.Parse(str, CultureInfo.InvariantCulture);
123             else if (targetTypeRef.FullName == "System.Boolean")
124             {
125                 if (Boolean.Parse(str))
126                     return true;
127                 else
128                     return false;
129             }
130             else if (targetTypeRef.FullName == "System.TimeSpan")
131             {
132                 var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
133                 return ts;
134             }
135             else if (targetTypeRef.FullName == "System.DateTime")
136             {
137                 var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
138                 return dt;
139             }
140             else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
141                 return str.Substring(2);
142             else if (targetTypeRef.FullName == "System.String")
143                 return str;
144             else if (targetTypeRef.FullName == "System.Object")
145                 return str;
146             else if (targetTypeRef.FullName == "System.Decimal")
147             {
148                 decimal outdecimal;
149                 if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
150                 {
151                     return outdecimal;
152                 }
153                 else
154                 {
155                     return null;
156                 }
157             }
158
159             var originalTypeRef = targetTypeRef;
160             var module = targetTypeRef.Resolve().Module;
161
162             var isNullable = false;
163             MethodReference nullableCtor = null;
164             if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
165             {
166                 var nullableTypeRef = targetTypeRef;
167                 targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
168                 isNullable = true;
169                 nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
170                 nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
171             }
172
173             var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
174
175             if (implicitOperator != null)
176             {
177                 //Fang: Need to deal
178                 //yield return Create(Ldstr, node.Value as string);
179                 //yield return Create(Call, module.ImportReference(implicitOperator));
180             }
181             else
182             {
183                 bool isNotNull = false;
184
185                 var targetType = targetTypeRef.ResolveCached();
186
187                 foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
188                 {
189                     TypeReference typeReference = null;
190
191                     if (method.Parameters[0].ParameterType.IsGenericParameter)
192                     {
193                         var genericType = targetTypeRef as GenericInstanceType;
194
195                         if (null != genericType)
196                         {
197                             for (int i = 0; i < targetType.GenericParameters.Count; i++)
198                             {
199                                 if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
200                                 {
201                                     typeReference = genericType.GenericArguments[i];
202                                 }
203                             }
204                         }
205                     }
206                     else
207                     {
208                         typeReference = method.Parameters[0].ParameterType;
209                     }
210
211                     if (null != typeReference)
212                     {
213                         isNotNull = true;
214                         if (typeReference.ResolveCached().FullName == "System.Nullable`1")
215                         {
216                             var genericType = typeReference as GenericInstanceType;
217                             typeReference = genericType.GenericArguments[0];
218                         }
219
220                         //Fang: Need to deal nullable type
221                         //TypeReference convertType = null;
222                         //var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
223
224                         //foreach (var ins in insList)
225                         //{
226                         //    yield return ins;
227                         //}
228                     }
229                 }
230
231                 if (!isNotNull)
232                 {
233                     return null;
234                 }
235             }
236
237             if (isNullable)
238             {
239                 //yield return Create(Newobj, module.ImportReference(nullableCtor));
240             }
241             //if (originalTypeRef.IsValueType && boxValueTypes)
242             //{
243             //    yield return Create(Box, module.ImportReference(originalTypeRef));
244             //}
245             return null;
246         }
247
248         public static object GetBaseValue(this ValueNode node, EXamlContext context, TypeReference targetTypeRef)
249         {
250             var str = (string)node.Value;
251             object ret = null;
252
253             if ("System.String" != targetTypeRef.FullName)
254             {
255                 if (str.EndsWith("dp"))
256                 {
257                     var value = GetBaseValue(context, str.Substring(0, str.Length - "dp".Length), targetTypeRef);
258                     ret = new EXamlCreateDPObject(context, value, targetTypeRef, "dp");
259                 }
260                 else if (str.EndsWith("px"))
261                 {
262                     var value = GetBaseValue(context, str.Substring(0, str.Length - "px".Length), targetTypeRef);
263                     ret = new EXamlCreateDPObject(context, value, targetTypeRef, "px");
264                 }
265             }
266
267             if (null == ret)
268             {
269                 ret = GetBaseValue(context, str, targetTypeRef);
270             }
271
272             return ret;
273         }
274
275         public static TypeReference GetConverterType(this ValueNode node, IEnumerable<ICustomAttributeProvider> attributeProviders)
276         {
277             TypeReference typeConverter = null;
278             foreach (var attributeProvider in attributeProviders)
279             {
280                 CustomAttribute typeConverterAttribute;
281                 if (
282                     (typeConverterAttribute =
283                         attributeProvider.CustomAttributes.FirstOrDefault(
284                             cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
285                 {
286                     typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
287                     break;
288                 }
289             }
290
291             return typeConverter;
292         }
293
294         public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
295             TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders,
296             IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
297         {
298             TypeReference typeConverter = null;
299             foreach (var attributeProvider in attributeProviders)
300             {
301                 CustomAttribute typeConverterAttribute;
302                 if (
303                     (typeConverterAttribute =
304                         attributeProvider.CustomAttributes.FirstOrDefault(
305                             cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null)
306                 {
307                     typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference;
308                     break;
309                 }
310             }
311             return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
312                 unboxValueTypes);
313         }
314
315         public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, FieldReference bpRef,
316             IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes)
317         {
318             var module = context.Body.Method.Module;
319             var targetTypeRef = bpRef.GetBindablePropertyType(node, module);
320             var typeConverter = bpRef.GetBindablePropertyTypeConverter(module);
321
322             return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes,
323                 unboxValueTypes);
324         }
325
326         public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context,
327             TypeReference targetTypeRef, TypeReference typeConverter, IEnumerable<Instruction> pushServiceProvider,
328             bool boxValueTypes, bool unboxValueTypes)
329         {
330             var module = context.Body.Method.Module;
331             var str = (string)node.Value;
332
333             //If the TypeConverter has a ProvideCompiledAttribute that can be resolved, shortcut this
334             var compiledConverterName = typeConverter?.GetCustomAttribute(module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "ProvideCompiledAttribute"))?.ConstructorArguments?.First().Value as string;
335
336             if (null == compiledConverterName)
337             {
338                 compiledConverterName = "Tizen.NUI.Xaml.Core.XamlC." + targetTypeRef.Name + "TypeConverter";
339             }
340
341             Type compiledConverterType;
342             if (compiledConverterName != null && (compiledConverterType = Type.GetType (compiledConverterName)) != null) {
343                 var compiledConverter = Activator.CreateInstance (compiledConverterType);
344                 var converter = typeof(ICompiledTypeConverter).GetMethods ().FirstOrDefault (md => md.Name == "ConvertFromString");
345                 IEnumerable<Instruction> instructions = (IEnumerable<Instruction>)converter.Invoke (compiledConverter, new object[] {
346                     node.Value as string, context, node as BaseNode});
347
348                 if (null != instructions)
349                 {
350                     foreach (var i in instructions)
351                         yield return i;
352                     if (targetTypeRef.IsValueType && boxValueTypes)
353                         yield return Instruction.Create(OpCodes.Box, module.ImportReference(targetTypeRef));
354                     yield break;
355                 }
356             }
357
358             //If there's a [TypeConverter], use it
359             if (typeConverter != null)
360             {
361                 var isExtendedConverter = typeConverter.ImplementsInterface(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter")));
362                 var typeConverterCtorRef = module.ImportCtorReference(typeConverter, paramCount: 0);
363                 var convertFromInvariantStringDefinition = isExtendedConverter
364                     ? module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "IExtendedTypeConverter"))
365                         .ResolveCached()
366                         .Methods.FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 2)
367                     : typeConverter.ResolveCached()
368                         .AllMethods()
369                         .FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 1);
370                 var convertFromInvariantStringReference = module.ImportReference(convertFromInvariantStringDefinition);
371
372                 yield return Instruction.Create(OpCodes.Newobj, typeConverterCtorRef);
373                 yield return Instruction.Create(OpCodes.Ldstr, node.Value as string);
374
375                 if (isExtendedConverter)
376                 {
377                     foreach (var instruction in pushServiceProvider)
378                         yield return instruction;
379                 }
380
381                 yield return Instruction.Create(OpCodes.Callvirt, convertFromInvariantStringReference);
382
383                 if (targetTypeRef.IsValueType && unboxValueTypes)
384                     yield return Instruction.Create(OpCodes.Unbox_Any, module.ImportReference(targetTypeRef));
385
386                 //ConvertFrom returns an object, no need to Box
387                 yield break;
388             }
389             var originalTypeRef = targetTypeRef;
390             var isNullable = false;
391             MethodReference nullableCtor = null;
392             if (targetTypeRef.ResolveCached().FullName == "System.Nullable`1")
393             {
394                 var nullableTypeRef = targetTypeRef;
395                 targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0];
396                 isNullable = true;
397                 nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1;
398                 nullableCtor = nullableCtor.ResolveGenericParameters(nullableTypeRef, module);
399             }
400
401             var implicitOperator = module.TypeSystem.String.GetImplicitOperatorTo(targetTypeRef, module);
402
403             //Obvious Built-in conversions
404             if (str == null) //if default parameter is null, exception will throw
405                 yield return Create(OpCodes.Ldnull);
406             else if (targetTypeRef.ResolveCached().BaseType != null && targetTypeRef.ResolveCached().BaseType.FullName == "System.Enum")
407                 yield return PushParsedEnum(targetTypeRef, str, node);
408             else if (targetTypeRef.FullName == "System.Char")
409                 yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str));
410             else if (targetTypeRef.FullName == "System.SByte")
411                 yield return Instruction.Create(OpCodes.Ldc_I4, SByte.Parse(str, CultureInfo.InvariantCulture));
412             else if (targetTypeRef.FullName == "System.Int16")
413             {
414                 if (str.EndsWith("dp") || str.EndsWith("px"))
415                 {
416                     var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
417
418                     foreach (var ins in insOfDPValue)
419                     {
420                         yield return ins;
421                     }
422                 }
423                 else
424                 {
425                     yield return Instruction.Create(OpCodes.Ldc_I4, Int16.Parse(str, CultureInfo.InvariantCulture));
426                 }
427             }
428             else if (targetTypeRef.FullName == "System.Int32")
429                 yield return Instruction.Create(OpCodes.Ldc_I4, Int32.Parse(str, CultureInfo.InvariantCulture));
430             else if (targetTypeRef.FullName == "System.Int64")
431                 yield return Instruction.Create(OpCodes.Ldc_I8, Int64.Parse(str, CultureInfo.InvariantCulture));
432             else if (targetTypeRef.FullName == "System.Byte")
433                 yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
434             else if (targetTypeRef.FullName == "System.UInt16")
435                 yield return Instruction.Create(OpCodes.Ldc_I4, unchecked((int)UInt16.Parse(str, CultureInfo.InvariantCulture)));
436             else if (targetTypeRef.FullName == "System.UInt32")
437                 yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((uint)UInt32.Parse(str, CultureInfo.InvariantCulture)));
438             else if (targetTypeRef.FullName == "System.UInt64")
439                 yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((long)UInt64.Parse(str, CultureInfo.InvariantCulture)));
440             else if (targetTypeRef.FullName == "System.Single")
441             {
442                 if (str.EndsWith("dp") || str.EndsWith("px"))
443                 {
444                     var insOfDPValue = GetDPValue(module, node, targetTypeRef, str);
445
446                     foreach (var ins in insOfDPValue)
447                     {
448                         yield return ins;
449                     }
450                 }
451                 else
452                 {
453                     yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture));
454                 }
455             }
456             else if (targetTypeRef.FullName == "System.Double")
457                 yield return Instruction.Create(OpCodes.Ldc_R8, Double.Parse(str, CultureInfo.InvariantCulture));
458             else if (targetTypeRef.FullName == "System.Boolean")
459             {
460                 if (Boolean.Parse(str))
461                     yield return Instruction.Create(OpCodes.Ldc_I4_1);
462                 else
463                     yield return Instruction.Create(OpCodes.Ldc_I4_0);
464             }
465             else if (targetTypeRef.FullName == "System.TimeSpan")
466             {
467                 var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture);
468                 var ticks = ts.Ticks;
469                 yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
470                 yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "TimeSpan"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
471             }
472             else if (targetTypeRef.FullName == "System.DateTime")
473             {
474                 var dt = DateTime.Parse(str, CultureInfo.InvariantCulture);
475                 var ticks = dt.Ticks;
476                 yield return Instruction.Create(OpCodes.Ldc_I8, ticks);
477                 yield return Instruction.Create(OpCodes.Newobj, module.ImportCtorReference(("mscorlib", "System", "DateTime"), parameterTypes: new[] { ("mscorlib", "System", "Int64") }));
478             }
479             else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal))
480                 yield return Instruction.Create(OpCodes.Ldstr, str.Substring(2));
481             else if (targetTypeRef.FullName == "System.String")
482                 yield return Instruction.Create(OpCodes.Ldstr, str);
483             else if (targetTypeRef.FullName == "System.Object")
484                 yield return Instruction.Create(OpCodes.Ldstr, str);
485             else if (targetTypeRef.FullName == "System.Decimal")
486             {
487                 decimal outdecimal;
488                 if (decimal.TryParse(str, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
489                 {
490                     var vardef = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Decimal")));
491                     context.Body.Variables.Add(vardef);
492                     //Use an extra temp var so we can push the value to the stack, just like other cases
493                     //IL_0003:  ldstr "adecimal"
494                     //IL_0008:  ldc.i4.s 0x6f
495                     //IL_000a:  call class [mscorlib]System.Globalization.CultureInfo class [mscorlib]System.Globalization.CultureInfo::get_InvariantCulture()
496                     //IL_000f:  ldloca.s 0
497                     //IL_0011:  call bool valuetype [mscorlib]System.Decimal::TryParse(string, valuetype [mscorlib]System.Globalization.NumberStyles, class [mscorlib]System.IFormatProvider, [out] valuetype [mscorlib]System.Decimal&)
498                     //IL_0016:  pop
499                     yield return Create(Ldstr, str);
500                     yield return Create(Ldc_I4, 0x6f); //NumberStyles.Number
501                     yield return Create(Call, module.ImportPropertyGetterReference(("mscorlib", "System.Globalization", "CultureInfo"),
502                                                                                    propertyName: "InvariantCulture", isStatic: true));
503                     yield return Create(Ldloca, vardef);
504                     yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Decimal"),
505                                                                            methodName: "TryParse",
506                                                                            parameterTypes: new[] {
507                                                                                ("mscorlib", "System", "String"),
508                                                                                ("mscorlib", "System.Globalization", "NumberStyles"),
509                                                                                ("mscorlib", "System", "IFormatProvider"),
510                                                                                ("mscorlib", "System", "Decimal"),
511                                                                            },
512                                                                            isStatic: true));
513                     yield return Create(Pop);
514                     yield return Create(Ldloc, vardef);
515                 }
516                 else
517                 {
518                     yield return Create(Ldc_I4_0);
519                     yield return Create(Newobj, module.ImportCtorReference(("mscorlib", "System", "Decimal"), parameterTypes: new[] { ("mscorlib", "System", "Int32") }));
520                 }
521             }
522             else if (implicitOperator != null)
523             {
524                 yield return Create(Ldstr, node.Value as string);
525                 yield return Create(Call, module.ImportReference(implicitOperator));
526             }
527             else
528             {
529                 bool isNotNull = false;
530
531                 var targetType = targetTypeRef.ResolveCached();
532
533                 foreach (var method in targetType.Methods.Where(a => a.Name == "op_Implicit"))
534                 {
535                     TypeReference typeReference = null;
536
537                     if (method.Parameters[0].ParameterType.IsGenericParameter)
538                     {
539                         var genericType = targetTypeRef as GenericInstanceType;
540
541                         if (null != genericType)
542                         {
543                             for (int i = 0; i < targetType.GenericParameters.Count; i++)
544                             {
545                                 if (method.Parameters[0].ParameterType == targetType.GenericParameters[i])
546                                 {
547                                     typeReference = genericType.GenericArguments[i];
548                                 }
549                             }
550                         }
551                     }
552                     else
553                     {
554                         typeReference = method.Parameters[0].ParameterType;
555                     }
556
557                     if (null != typeReference)
558                     {
559                         isNotNull = true;
560                         if (typeReference.ResolveCached().FullName == "System.Nullable`1")
561                         {
562                             var genericType = typeReference as GenericInstanceType;
563                             typeReference = genericType.GenericArguments[0];
564                         }
565
566                         TypeReference convertType = null;
567                         var insList = PushConvertedValue(node, context, typeReference, convertType, pushServiceProvider, boxValueTypes, unboxValueTypes);
568
569                         foreach (var ins in insList)
570                         {
571                             yield return ins;
572                         }
573                     }
574                 }
575
576                 if (!isNotNull)
577                 {
578                     yield return Create(Ldnull);
579                 }
580             }
581
582             if (isNullable)
583                 yield return Create(Newobj, module.ImportReference(nullableCtor));
584             if (originalTypeRef.IsValueType && boxValueTypes)
585                 yield return Create(Box, module.ImportReference(originalTypeRef));
586         }
587
588         private static TypeDefinition typeOfGraphicManager;
589         private static MethodReference getMethodOfInstance;
590         private static MethodReference methodOfConvertScriptToPixel;
591
592         static private IEnumerable<Instruction> GetDPValue(ModuleDefinition module, ValueNode node, TypeReference targetTypeRef, string str)
593         {
594             if (null == typeOfGraphicManager)
595             {
596                 typeOfGraphicManager = module.GetTypeDefinition(("Tizen.NUI", "Tizen.NUI", "GraphicsTypeManager"));
597             }
598
599             if (null == getMethodOfInstance)
600             {
601                 var propertyOfInstance = typeOfGraphicManager.Properties.FirstOrDefault(a => a.Name == "Instance");
602                 getMethodOfInstance = propertyOfInstance.GetMethod;
603                 getMethodOfInstance = module.ImportReference(getMethodOfInstance);
604             }
605
606             yield return Create(Call, getMethodOfInstance);
607             yield return Create(Ldstr, str);
608
609             if (null == methodOfConvertScriptToPixel)
610             {
611                 methodOfConvertScriptToPixel = typeOfGraphicManager.Methods.FirstOrDefault(a => a.Name == "ConvertScriptToPixel");
612                 methodOfConvertScriptToPixel = module.ImportReference(methodOfConvertScriptToPixel);
613             }
614
615             yield return Create(Callvirt, methodOfConvertScriptToPixel);
616
617             var convertType = typeof(System.Convert);
618             var typeOfConvert = module.GetTypeDefinition((convertType.Assembly.FullName, convertType.Namespace, convertType.Name));
619
620             var methodOfTo = typeOfConvert.Methods.FirstOrDefault(a => a.Name == "To" + targetTypeRef.Name);
621
622             yield return Create(Box, module.ImportReference(targetTypeRef));
623
624             yield return Create(Call, module.ImportReference(methodOfTo));
625         }
626
627         static public object GetParsedEnum(EXamlContext context, TypeReference enumRef, string value)
628         {
629             var enumDef = enumRef.ResolveCached();
630             if (!enumDef.IsEnum)
631                 throw new InvalidOperationException();
632
633             bool isStrMatchEnumValue = false;
634
635             foreach (var field in enumDef.Fields)
636             {
637                 if (field.Name == "value__")
638                     continue;
639
640                 if (field.Name == value)
641                 {
642                     isStrMatchEnumValue = true;
643                     break;
644                 }
645             }
646
647             if (!isStrMatchEnumValue)
648             {
649                 foreach (var field in enumDef.Fields)
650                 {
651                     if (field.Name == "value__")
652                         continue;
653                     if (IsStringMatchObject(field.Constant, value))
654                     {
655                         isStrMatchEnumValue = true;
656                         value = field.Name;
657                         break;
658                     }
659                 }
660             }
661
662             if (!isStrMatchEnumValue)
663             {
664                 throw new Exception($"{value} is not value of {enumRef.FullName}");
665             }
666
667             return new EXamlCreateObject(context, value, enumRef);
668         }
669
670         static Instruction PushParsedEnum(TypeReference enumRef, string value, IXmlLineInfo lineInfo)
671         {
672             var enumDef = enumRef.ResolveCached();
673             if (!enumDef.IsEnum)
674                 throw new InvalidOperationException();
675
676             // The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.
677             // https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
678             byte b = 0; sbyte sb = 0; short s = 0; ushort us = 0;
679             int i = 0; uint ui = 0; long l = 0; ulong ul = 0;
680             bool found = false;
681             TypeReference typeRef = null;
682
683             foreach (var field in enumDef.Fields)
684                 if (field.Name == "value__")
685                     typeRef = field.FieldType;
686
687             if (typeRef == null)
688                 throw new ArgumentException();
689
690             foreach (var v in value.Split(',')) {
691                 foreach (var field in enumDef.Fields) {
692                     if (field.Name == "value__")
693                         continue;
694                     if (field.Name == v.Trim()) {
695                         switch (typeRef.FullName) {
696                         case "System.Byte":
697                             b |= (byte)field.Constant;
698                             break;
699                         case "System.SByte":
700                             if (found)
701                                 throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
702                             sb = (sbyte)field.Constant;
703                             break;
704                         case "System.Int16":
705                             s |= (short)field.Constant;
706                             break;
707                         case "System.UInt16":
708                             us |= (ushort)field.Constant;
709                             break;
710                         case "System.Int32":
711                             i |= (int)field.Constant;
712                             break;
713                         case "System.UInt32":
714                             ui |= (uint)field.Constant;
715                             break;
716                         case "System.Int64":
717                             l |= (long)field.Constant;
718                             break;
719                         case "System.UInt64":
720                             ul |= (ulong)field.Constant;
721                             break;
722                         }
723                         found = true;
724                     }
725                 }
726
727                 if (!found)
728                 {
729                     foreach (var field in enumDef.Fields)
730                     {
731                         if (field.Name == "value__")
732                             continue;
733                         if (IsStringMatchObject(field.Constant, v))
734                         {
735                             switch (typeRef.FullName)
736                             {
737                                 case "System.Byte":
738                                     b |= (byte)field.Constant;
739                                     break;
740                                 case "System.SByte":
741                                     if (found)
742                                         throw new XamlParseException($"Multi-valued enums are not valid on sbyte enum types", lineInfo);
743                                     sb = (sbyte)field.Constant;
744                                     break;
745                                 case "System.Int16":
746                                     s |= (short)field.Constant;
747                                     break;
748                                 case "System.UInt16":
749                                     us |= (ushort)field.Constant;
750                                     break;
751                                 case "System.Int32":
752                                     i |= (int)field.Constant;
753                                     break;
754                                 case "System.UInt32":
755                                     ui |= (uint)field.Constant;
756                                     break;
757                                 case "System.Int64":
758                                     l |= (long)field.Constant;
759                                     break;
760                                 case "System.UInt64":
761                                     ul |= (ulong)field.Constant;
762                                     break;
763                             }
764                             found = true;
765                         }
766                     }
767                 }
768             }
769
770             if (!found)
771                 throw new XamlParseException($"Enum value not found for {value}", lineInfo);
772                 
773             switch (typeRef.FullName) {
774             case "System.Byte":
775                 return Instruction.Create(OpCodes.Ldc_I4, (int)b);
776             case "System.SByte":
777                 return Instruction.Create(OpCodes.Ldc_I4, (int)sb);
778             case "System.Int16":
779                 return Instruction.Create(OpCodes.Ldc_I4, (int)s);
780             case "System.UInt16":
781                 return Instruction.Create(OpCodes.Ldc_I4, (int)us);
782             case "System.Int32":
783                 return Instruction.Create(OpCodes.Ldc_I4, (int)i);
784             case "System.UInt32":
785                 return Instruction.Create(OpCodes.Ldc_I8, (uint)ui);
786             case "System.Int64":
787                 return Instruction.Create(OpCodes.Ldc_I8, (long)l);
788             case "System.UInt64":
789                 return Instruction.Create(OpCodes.Ldc_I8, (ulong)ul);
790             default:
791                 throw new XamlParseException($"Enum value not found for {value}", lineInfo);
792             }
793         }
794
795         private static bool IsStringMatchObject(object obj, string str)
796         {
797             try
798             {
799                 switch (obj.GetType().FullName)
800                 {
801                     case "System.Byte":
802                         return (byte)obj == byte.Parse(str);
803                     case "System.SByte":
804                         return (sbyte)obj == sbyte.Parse(str);
805                     case "System.Int16":
806                         return (Int16)obj == Int16.Parse(str);
807                     case "System.UInt16":
808                         return (UInt16)obj == UInt16.Parse(str);
809                     case "System.Int32":
810                         return (Int32)obj == Int32.Parse(str);
811                     case "System.UInt32":
812                         return (UInt32)obj == UInt32.Parse(str);
813                     case "System.Int64":
814                         return (Int64)obj == Int64.Parse(str);
815                     case "System.UInt64":
816                         return (UInt64)obj == UInt64.Parse(str);
817                 }
818             }
819             catch (Exception e)
820             {
821             }
822
823             return false;
824         }
825
826         public static IEnumerable<Instruction> PushXmlLineInfo(this INode node, ILContext context)
827         {
828             var module = context.Body.Method.Module;
829
830             var xmlLineInfo = node as IXmlLineInfo;
831             if (xmlLineInfo == null) {
832                 yield return Create(Ldnull);
833                 yield break;
834             }
835             MethodReference ctor;
836             if (xmlLineInfo.HasLineInfo()) {
837                 yield return Create(Ldc_I4, xmlLineInfo.LineNumber);
838                 yield return Create(Ldc_I4, xmlLineInfo.LinePosition);
839                 ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: new[] {
840                     ("mscorlib", "System", "Int32"),
841                     ("mscorlib", "System", "Int32"),
842                 });
843             }
844             else
845                 ctor = module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfo"), parameterTypes: null);
846             yield return Create(Newobj, ctor);
847         }
848
849         public static IEnumerable<Instruction> PushParentObjectsArray(this INode node, ILContext context)
850         {
851             var module = context.Body.Method.Module;
852
853             var nodes = new List<IElementNode>();
854             INode n = node.Parent;
855             while (n != null)
856             {
857                 var en = n as IElementNode;
858                 if (en != null && context.Variables.ContainsKey(en))
859                     nodes.Add(en);
860                 n = n.Parent;
861             }
862
863             if (nodes.Count == 0 && context.ParentContextValues == null)
864             {
865                 yield return Instruction.Create(OpCodes.Ldnull);
866                 yield break;
867             }
868
869             if (nodes.Count == 0)
870             {
871                 yield return Instruction.Create(OpCodes.Ldarg_0);
872                 yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
873                 yield break;
874             }
875
876             //Compute parent object length
877             if (context.ParentContextValues != null)
878             {
879                 yield return Instruction.Create(OpCodes.Ldarg_0);
880                 yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues);
881                 yield return Instruction.Create(OpCodes.Ldlen);
882                 yield return Instruction.Create(OpCodes.Conv_I4);
883             }
884             else
885                 yield return Instruction.Create(OpCodes.Ldc_I4_0);
886             var parentObjectLength = new VariableDefinition(module.TypeSystem.Int32);
887             context.Body.Variables.Add(parentObjectLength);
888             yield return Instruction.Create(OpCodes.Stloc, parentObjectLength);
889
890             //Create the final array
891             yield return Instruction.Create(OpCodes.Ldloc, parentObjectLength);
892             yield return Instruction.Create(OpCodes.Ldc_I4, nodes.Count);
893             yield return Instruction.Create(OpCodes.Add);
894             yield return Instruction.Create(OpCodes.Newarr, module.TypeSystem.Object);
895             var finalArray = new VariableDefinition(module.ImportArrayReference(("mscorlib", "System", "Object")));
896             context.Body.Variables.Add(finalArray);
897             yield return Instruction.Create(OpCodes.Stloc, finalArray);
898
899             //Copy original array to final
900             if (context.ParentContextValues != null)
901             {
902                 yield return Create(Ldarg_0);
903                 yield return Create(Ldfld, context.ParentContextValues); //sourceArray
904                 yield return Create(Ldc_I4_0); //sourceIndex
905                 yield return Create(Ldloc, finalArray); //destinationArray
906                 yield return Create(Ldc_I4, nodes.Count); //destinationIndex
907                 yield return Create(Ldloc, parentObjectLength); //length
908                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Array"),
909                                                                        methodName: "Copy",
910                                                                        parameterTypes: new[] {
911                                                                            ("mscorlib", "System", "Array"),
912                                                                            ("mscorlib", "System", "Int32"),
913                                                                            ("mscorlib", "System", "Array"),
914                                                                            ("mscorlib", "System", "Int32"),
915                                                                            ("mscorlib", "System", "Int32"),
916                                                                        },
917                                                                        isStatic: true));
918             }
919
920             //Add nodes to array
921             yield return Instruction.Create(OpCodes.Ldloc, finalArray);
922             if (nodes.Count > 0)
923             {
924                 for (var i = 0; i < nodes.Count; i++)
925                 {
926                     var en = nodes[i];
927                     yield return Instruction.Create(OpCodes.Dup);
928                     yield return Instruction.Create(OpCodes.Ldc_I4, i);
929                     yield return Instruction.Create(OpCodes.Ldloc, context.Variables[en]);
930                     if (context.Variables[en].VariableType.IsValueType)
931                         yield return Instruction.Create(OpCodes.Box, module.ImportReference(context.Variables[en].VariableType));
932                     yield return Instruction.Create(OpCodes.Stelem_Ref);
933                 }
934             }
935         }
936
937         static IEnumerable<Instruction> PushTargetProperty(FieldReference bpRef, PropertyReference propertyRef, TypeReference declaringTypeReference, ModuleDefinition module)
938         {
939             if (bpRef != null) {
940                 yield return Create(Ldsfld, bpRef);
941                 yield break;
942             }
943             if (propertyRef != null) {
944                 yield return Create(Ldtoken, module.ImportReference(declaringTypeReference ?? propertyRef.DeclaringType));
945                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
946                 yield return Create(Ldstr, propertyRef.Name);
947                 yield return Create(Call, module.ImportMethodReference(("System.Reflection.Extensions", "System.Reflection", "RuntimeReflectionExtensions"),
948                                                                        methodName: "GetRuntimeProperty",
949                                                                        parameterTypes: new[]{
950                                                                            ("mscorlib", "System", "Type"),
951                                                                            ("mscorlib", "System", "String"),
952                                                                        },
953                                                                        isStatic: true));
954                 yield break;
955             }
956             yield return Create(Ldnull);
957             yield break;
958         }
959
960         public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILContext context, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference declaringTypeReference = null)
961         {
962             var module = context.Body.Method.Module;
963
964 #if NOSERVICEPROVIDER
965             yield return Instruction.Create (OpCodes.Ldnull);
966             yield break;
967 #endif
968
969             var addService = module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"),
970                                                           methodName: "Add",
971                                                           parameterTypes: new[] {
972                                                               ("mscorlib", "System", "Type"),
973                                                               ("mscorlib", "System", "Object"),
974                                                           });
975
976             yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlServiceProvider"), parameterTypes: null));
977
978             //Add a SimpleValueTargetProvider and register it as IProvideValueTarget and IReferenceProvider
979             var pushParentIl = node.PushParentObjectsArray(context).ToList();
980             if (pushParentIl[pushParentIl.Count - 1].OpCode != Ldnull) {
981                 yield return Create(Dup); //Keep the serviceProvider on the stack
982                 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IProvideValueTarget")));
983                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
984
985                 foreach (var instruction in pushParentIl)
986                     yield return instruction;
987
988                 foreach (var instruction in PushTargetProperty(bpRef, propertyRef, declaringTypeReference, module))
989                     yield return instruction;
990
991                 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "SimpleValueTargetProvider"), paramCount: 2));
992                 //store the provider so we can register it again with a different key
993                 yield return Create(Dup);
994                 var refProvider = new VariableDefinition(module.ImportReference(("mscorlib", "System", "Object")));
995                 context.Body.Variables.Add(refProvider);
996                 yield return Create(Stloc, refProvider);
997                 yield return Create(Callvirt, addService);
998
999                 yield return Create(Dup); //Keep the serviceProvider on the stack
1000                 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IReferenceProvider")));
1001                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1002                 yield return Create(Ldloc, refProvider);
1003                 yield return Create(Callvirt, addService);
1004             }
1005
1006             //Add a XamlTypeResolver
1007             if (node.NamespaceResolver != null) {
1008                 yield return Create(Dup); //Duplicate the serviceProvider
1009                 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXamlTypeResolver")));
1010                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1011                 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"), parameterTypes: null));
1012                 foreach (var kvp in node.NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) {
1013                     yield return Create(Dup); //dup the resolver
1014                     yield return Create(Ldstr, kvp.Key);
1015                     yield return Create(Ldstr, kvp.Value);
1016                     yield return Create(Callvirt, module.ImportMethodReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlNamespaceResolver"),
1017                                                                                methodName: "Add",
1018                                                                                parameterTypes: new[] {
1019                                                                                    ("mscorlib", "System", "String"),
1020                                                                                    ("mscorlib", "System", "String"),
1021                                                                                }));
1022                 }
1023                 yield return Create(Ldtoken, context.Body.Method.DeclaringType);
1024                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1025                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System.Reflection", "IntrospectionExtensions"), methodName: "GetTypeInfo", parameterTypes: new[] { ("mscorlib", "System", "Type") }, isStatic: true));
1026                 yield return Create(Callvirt, module.ImportPropertyGetterReference(("mscorlib", "System.Reflection", "TypeInfo"), propertyName: "Assembly", flatten: true));
1027                 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XamlTypeResolver"), paramCount: 2));
1028                 yield return Create(Callvirt, addService);
1029             }
1030
1031             if (node is IXmlLineInfo) {
1032                 yield return Create(Dup); //Duplicate the serviceProvider
1033                 yield return Create(Ldtoken, module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "IXmlLineInfoProvider")));
1034                 yield return Create(Call, module.ImportMethodReference(("mscorlib", "System", "Type"), methodName: "GetTypeFromHandle", parameterTypes: new[] { ("mscorlib", "System", "RuntimeTypeHandle") }, isStatic: true));
1035                 foreach (var instruction in node.PushXmlLineInfo(context))
1036                     yield return instruction;
1037                 yield return Create(Newobj, module.ImportCtorReference((XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "XmlLineInfoProvider"), parameterTypes: new[] { ("System.Xml.ReaderWriter", "System.Xml", "IXmlLineInfo") }));
1038                 yield return Create(Callvirt, addService);
1039             }
1040         }
1041     }
1042 }
1043