[Xaml] Support import other xaml as the source of resource dictionary
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / EXamlBuild / EXamlCreateObjectVisitor.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.Globalization;
20 using System.Linq;
21 using Mono.Cecil;
22 using Mono.Cecil.Cil;
23 using Tizen.NUI.Xaml;
24 using System.Xml;
25
26 using static Mono.Cecil.Cil.Instruction;
27 using static Mono.Cecil.Cil.OpCodes;
28 using Tizen.NUI.Xaml.Build.Tasks;
29 using ArrayExtension = Tizen.NUI.Xaml.Build.Tasks.ArrayExtension;
30 using Tizen.NUI.Binding;
31
32 namespace Tizen.NUI.EXaml.Build.Tasks
33 {
34     class EXamlCreateObjectVisitor : IXamlNodeVisitor
35     {
36         public EXamlCreateObjectVisitor(EXamlContext context)
37         {
38             Context = context;
39             Module = context.Module;
40         }
41
42         public EXamlContext Context { get; }
43
44         ModuleDefinition Module { get; }
45
46         public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
47         public bool StopOnDataTemplate => true;
48         public bool StopOnResourceDictionary => false;
49         public bool VisitNodeOnDataTemplate => false;
50         public bool SkipChildren(INode node, INode parentNode) => false;
51
52         public bool IsResourceDictionary(ElementNode node)
53         {
54             var parentVar = Context.Variables[(IElementNode)node];
55             return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
56                 || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
57         }
58
59         public void Visit(ValueNode node, INode parentNode)
60         {
61             Context.Values[node] = node.Value;
62         }
63
64         public void Visit(MarkupNode node, INode parentNode)
65         {
66             //At this point, all MarkupNodes are expanded to ElementNodes
67         }
68
69         public void Visit(ElementNode node, INode parentNode)
70         {
71             var typeref = Module.ImportReference(node.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.Both, Module, node));
72
73             if (IsXaml2009LanguagePrimitive(node))
74             {
75                 var vardef = new VariableDefinition(typeref);
76                 Context.Variables[node] = vardef;
77
78                 var value = GetValueFromLanguagePrimitive(typeref, node);
79
80                 Context.Values[node] = value;
81                 return;
82             }
83
84             TypeDefinition typedef = typeref.ResolveCached();
85
86             //if this is a MarkupExtension that can be compiled directly, compile and returns the value
87             var compiledMarkupExtensionName = typeref
88                 .GetCustomAttribute(Module, (XamlTask.xamlAssemblyName, XamlTask.xamlNameSpace, "ProvideCompiledAttribute"))
89                 ?.ConstructorArguments?[0].Value as string;
90             Type compiledMarkupExtensionType;
91             ICompiledMarkupExtension markupProvider;
92             if (compiledMarkupExtensionName != null &&
93                 (compiledMarkupExtensionType = Type.GetType(compiledMarkupExtensionName)) != null &&
94                 (markupProvider = Activator.CreateInstance(compiledMarkupExtensionType) as ICompiledMarkupExtension) != null)
95             {
96
97                 Context.Values[node] = markupProvider.ProvideValue(node, Module, Context);
98
99                 VariableDefinition vardef = new VariableDefinition(typeref);
100                 Context.Variables[node] = vardef;
101
102                 //clean the node as it has been fully exhausted
103                 foreach (var prop in node.Properties)
104                     if (!node.SkipProperties.Contains(prop.Key))
105                         node.SkipProperties.Add(prop.Key);
106                 node.CollectionItems.Clear();
107                 return;
108             }
109
110             MethodDefinition factoryCtorInfo = null;
111             MethodDefinition factoryMethodInfo = null;
112             MethodDefinition parameterizedCtorInfo = null;
113             MethodDefinition ctorInfo = null;
114
115             if (node.Properties.ContainsKey(XmlName.xArguments) && !node.Properties.ContainsKey(XmlName.xFactoryMethod))
116             {
117                 factoryCtorInfo = typedef.AllMethods().FirstOrDefault(md => md.IsConstructor &&
118                                                                             !md.IsStatic &&
119                                                                             md.HasParameters &&
120                                                                             md.MatchXArguments(node, typeref, Module, Context));
121                 if (factoryCtorInfo == null)
122                 {
123                     throw new XamlParseException(
124                         string.Format("No constructors found for {0} with matching x:Arguments", typedef.FullName), node);
125                 }
126                 ctorInfo = factoryCtorInfo;
127                 if (!typedef.IsValueType) //for ctor'ing typedefs, we first have to ldloca before the params
128                 {
129                     VariableDefinition vardef = new VariableDefinition(typeref);
130                     Context.Variables[node] = vardef;
131
132                     var argumentList = GetCtorXArguments(node, factoryCtorInfo.Parameters.Count, true);
133                     Context.Values[node] = new EXamlCreateObject(Context, null, typedef, argumentList.ToArray());
134                     return;
135                 }
136             }
137             else if (node.Properties.ContainsKey(XmlName.xFactoryMethod))
138             {
139                 var factoryMethod = (string)(node.Properties[XmlName.xFactoryMethod] as ValueNode).Value;
140                 factoryMethodInfo = typedef.AllMethods().FirstOrDefault(md => !md.IsConstructor &&
141                                                                               md.Name == factoryMethod &&
142                                                                               md.IsStatic &&
143                                                                               md.MatchXArguments(node, typeref, Module, Context));
144
145                 if (factoryMethodInfo == null)
146                 {
147                     var typeExtensionRef = Module.ImportReference(node.XmlType.GetTypeReference(XmlTypeExtensions.ModeOfGetType.OnlyGetTypeExtension, Module, node));
148                     typeExtensionRef = typeExtensionRef?.ResolveCached();
149
150                     if (null != typeExtensionRef)
151                     {
152                         factoryMethodInfo = typeExtensionRef.ResolveCached().AllMethods().FirstOrDefault(md => !md.IsConstructor &&
153                                                                               md.Name == factoryMethod &&
154                                                                               md.IsStatic &&
155                                                                               md.MatchXArguments(node, typeExtensionRef, Module, Context));
156                     }
157                 }
158
159                 if (factoryMethodInfo == null)
160                 {
161                     throw new XamlParseException(
162                         String.Format("No static method found for {0}::{1} ({2})", typedef.FullName, factoryMethod, null), node);
163                 }
164
165                 VariableDefinition vardef = new VariableDefinition(typeref);
166                 Context.Variables[node] = vardef;
167
168                 var argumentList = GetCtorXArguments(node, factoryMethodInfo.Parameters.Count, false);
169                 Context.Values[node] = new EXamlCreateObject(Context, null, typedef, factoryMethodInfo, argumentList?.ToArray());
170                 return;
171             }
172
173             if (ctorInfo == null && factoryMethodInfo == null)
174             {
175                 parameterizedCtorInfo = typedef.Methods.FirstOrDefault(md => md.IsConstructor &&
176                                                                              !md.IsStatic &&
177                                                                              md.HasParameters &&
178                                                                              md.Parameters.All(
179                                                                                  pd =>
180                                                                                      pd.CustomAttributes.Any(
181                                                                                          ca =>
182                                                                                              ca.AttributeType.FullName ==
183                                                                                              "Tizen.NUI.Binding.ParameterAttribute")));
184             }
185             string missingCtorParameter = null;
186             List<object> parameterizedCtorParams = null;
187
188             if (parameterizedCtorInfo != null && ValidateCtorArguments(parameterizedCtorInfo, node, out missingCtorParameter))
189             {
190                 ctorInfo = parameterizedCtorInfo;
191                 parameterizedCtorParams = GetCtorArguments(parameterizedCtorInfo, node, Context);
192                 //Fang
193                 //IL_0000:  ldstr "foo"
194                 //Context.IL.Append(PushCtorArguments(parameterizedCtorInfo, node));
195             }
196
197             ctorInfo = ctorInfo ?? typedef.Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters && !md.IsStatic);
198
199             if (null == ctorInfo)
200             {
201                 foreach (var method in typedef.Methods)
202                 {
203                     if (method.IsConstructor && !method.IsStatic)
204                     {
205                         bool areAllParamsDefault = true;
206
207                         foreach (var param in method.Parameters)
208                         {
209                             if (!param.HasDefault)
210                             {
211                                 areAllParamsDefault = false;
212                                 break;
213                             }
214                         }
215
216                         if (areAllParamsDefault)
217                         {
218                             if (null == ctorInfo)
219                             {
220                                 ctorInfo = method;
221                             }
222                             else
223                             {
224                                 throw new XamlParseException($"{typedef.FullName} has more than one constructor which params are all default.", node);
225                             }
226                         }
227                     }
228                 }
229
230                 if (null == ctorInfo && !typedef.IsValueType)
231                 {
232                     throw new XamlParseException($"{typedef.FullName} has no constructor which params are all default.", node);
233                 }
234             }
235
236             if (parameterizedCtorInfo != null && ctorInfo == null)
237                 //there was a parameterized ctor, we didn't use it
238                 throw new XamlParseException($"The Property '{missingCtorParameter}' is required to create a '{typedef.FullName}' object.", node);
239             var ctorinforef = ctorInfo?.ResolveGenericParameters(typeref, Module);
240
241             var factorymethodinforef = factoryMethodInfo?.ResolveGenericParameters(typeref, Module);
242             var implicitOperatorref = typedef.Methods.FirstOrDefault(md =>
243                 md.IsPublic &&
244                 md.IsStatic &&
245                 md.IsSpecialName &&
246                 md.Name == "op_Implicit" && md.Parameters[0].ParameterType.FullName == "System.String");
247
248             if (ctorinforef != null || factorymethodinforef != null || typedef.IsValueType)
249             {
250                 VariableDefinition vardef = new VariableDefinition(typeref);
251                 Context.Variables[node] = vardef;
252
253                 ValueNode vnode = null;
254                 if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
255                     vardef.VariableType.IsValueType)
256                 {
257                     Context.Values[node] = vnode.GetBaseValue(Context, typeref);
258                 }
259                 else if (node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null &&
260                            implicitOperatorref != null)
261                 {
262                     var converterType = vnode.GetConverterType(new ICustomAttributeProvider[] { typeref.ResolveCached() });
263                     if (null == converterType)
264                     {
265                         var realValue = vnode.GetBaseValue(Context, typeref);
266                         Context.Values[node] = new EXamlCreateObject(Context, realValue, typeref);
267                     }
268                     else
269                     {
270                         var converterValue = new EXamlValueConverterFromString(Context, converterType.Resolve(), vnode.Value as string);
271                         Context.Values[node] = new EXamlCreateObject(Context, converterValue, typeref);
272                     }
273                 }
274                 else if (factorymethodinforef != null)
275                 {
276                     //Fang
277                     //Context.IL.Emit(OpCodes.Call, Module.ImportReference(factorymethodinforef));
278                     //Context.IL.Emit(OpCodes.Stloc, vardef);
279                 }
280                 else if (!typedef.IsValueType)
281                 {
282                     var ctor = Module.ImportReference(ctorinforef);
283                     //IL_0001:  newobj instance void class [Tizen.NUI.Xaml.UIComponents]Tizen.NUI.Xaml.UIComponents.Button::'.ctor'()
284                     //IL_0006:  stloc.0
285                     //Context.IL.Emit(OpCodes.Newobj, ctor);
286                     //Context.IL.Emit(OpCodes.Stloc, vardef);
287                     if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
288                     {
289                         typeref = Module.ImportReference(typeof(ArrayExtension));
290                     }
291
292                     var accordingType = this.GetType().Assembly.GetType(typeref.FullName);
293
294                     if (null != accordingType && accordingType != typeof(Binding.Setter) && accordingType != typeof(ResourceDictionary))
295                     {
296                         Context.Values[node] = new EXamlCreateObject(Context, Activator.CreateInstance(accordingType), typeref);
297                     }
298                     else if (null != parameterizedCtorParams)
299                     {
300                         Context.Values[node] = new EXamlCreateObject(Context, null, typeref, parameterizedCtorParams.ToArray());
301                     }
302                     else
303                     {
304                         bool canConvertCollectionItem = false;
305
306                         if (!typeref.InheritsFromOrImplements(Context.Module.ImportReference(typeof(List<string>)).Resolve())
307                             &&
308                             node.CollectionItems.Count == 1 && (vnode = node.CollectionItems.First() as ValueNode) != null)
309                         {
310                             var valueNode = node.CollectionItems.First() as ValueNode;
311
312                             if (valueNode.CanConvertValue(Context.Module, typeref, (TypeReference)null))
313                             {
314                                 var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { typeref.Resolve() });
315                                 if (null != converterType)
316                                 {
317                                     var converterValue = new EXamlValueConverterFromString(Context, converterType.Resolve(), valueNode.Value as string);
318                                     Context.Values[node] = new EXamlCreateObject(Context, converterValue, typeref);
319                                 }
320                                 else
321                                 {
322                                     var valueItem = valueNode.GetBaseValue(Context, typeref);
323                                     if (null == valueItem)
324                                     {
325                                         throw new XamlParseException($"Can't convert collection item \"{vnode.Value}\" to object", node);
326                                     }
327
328                                     Context.Values[node] = valueItem;
329                                 }
330
331                                 canConvertCollectionItem = true;
332                             }
333                         }
334
335                         if (false == canConvertCollectionItem)
336                         {
337                             if (!ctorInfo.HasParameters)
338                             {
339                                 Context.Values[node] = new EXamlCreateObject(Context, null, typeref);
340                             }
341                             else
342                             {
343                                 object[] @params = new object[ctorInfo.Parameters.Count];
344
345                                 for (int i = 0; i < ctorInfo.Parameters.Count; i++)
346                                 {
347                                     var param = ctorInfo.Parameters[i];
348
349                                     if (ctorInfo.Parameters[i].ParameterType.ResolveCached().IsEnum)
350                                     {
351                                         @params[i] = NodeILExtensions.GetParsedEnum(Context, param.ParameterType, param.Constant.ToString());
352                                     }
353                                     else
354                                     {
355                                         @params[i] = param.Constant;
356                                     }
357                                 }
358
359                                 Context.Values[node] = new EXamlCreateObject(Context, null, typeref, @params);
360                             }
361                         }
362                     }
363                 }
364                 else if (ctorInfo != null && node.Properties.ContainsKey(XmlName.xArguments) &&
365                          !node.Properties.ContainsKey(XmlName.xFactoryMethod) && ctorInfo.MatchXArguments(node, typeref, Module, Context))
366                 {
367                     var argumentList = GetCtorXArguments(node, factoryCtorInfo.Parameters.Count, true);
368                     Context.Values[node] = new EXamlCreateObject(Context, null, typedef, argumentList.ToArray());
369                     return;
370                 }
371                 else
372                 {
373                     Context.Values[node] = new EXamlCreateObject(Context, null, typedef, null);
374                     return;
375                 }
376
377                 if (typeref.FullName == "Tizen.NUI.Xaml.ArrayExtension")
378                 {
379                     //Fang
380                     //var visitor = new SetPropertiesVisitor(Context);
381                     //foreach (var cnode in node.Properties.Values.ToList())
382                     //    cnode.Accept(visitor, node);
383                     //foreach (var cnode in node.CollectionItems)
384                     //    cnode.Accept(visitor, node);
385
386                     //markupProvider = new ArrayExtension();
387
388                     //var il = markupProvider.ProvideValue(node, Module, Context, out typeref);
389
390                     //vardef = new VariableDefinition(typeref);
391                     //Context.Variables[node] = vardef;
392                     //Context.Body.Variables.Add(vardef);
393
394                     //Context.IL.Append(il);
395                     //Context.IL.Emit(OpCodes.Stloc, vardef);
396
397                     ////clean the node as it has been fully exhausted
398                     //foreach (var prop in node.Properties)
399                     //    if (!node.SkipProperties.Contains(prop.Key))
400                     //        node.SkipProperties.Add(prop.Key);
401                     //node.CollectionItems.Clear();
402
403                     return;
404                 }
405             }
406         }
407
408         public void Visit(RootNode node, INode parentNode)
409         {
410             //IL_0013:  ldarg.0 
411             //IL_0014:  stloc.3 
412
413             var ilnode = (ILRootNode)node;
414             var typeref = ilnode.TypeReference;
415             var vardef = new VariableDefinition(typeref);
416             Context.Variables[node] = vardef;
417             Context.Root = vardef;
418             Context.RootNode = node;
419             //Context.IL.Emit(OpCodes.Ldarg_0);
420             //Context.IL.Emit(OpCodes.Stloc, vardef);
421         }
422
423         public void Visit(ListNode node, INode parentNode)
424         {
425             XmlName name;
426             if (EXamlSetPropertiesVisitor.TryGetPropertyName(node, parentNode, out name))
427                 node.XmlName = name;
428         }
429
430         bool ValidateCtorArguments(MethodDefinition ctorinfo, ElementNode enode, out string firstMissingProperty)
431         {
432             firstMissingProperty = null;
433             foreach (var parameter in ctorinfo.Parameters)
434             {
435                 var propname =
436                     parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
437                         .ConstructorArguments.First()
438                         .Value as string;
439                 if (!enode.Properties.ContainsKey(new XmlName("", propname)))
440                 {
441                     firstMissingProperty = propname;
442                     return false;
443                 }
444             }
445             return true;
446         }
447
448         List<object> GetCtorXArguments(ElementNode enode, int paramsCount, bool isConstructor)
449         {
450             if (!enode.Properties.ContainsKey(XmlName.xArguments))
451             {
452                 return null;
453             }
454
455             List<object> argumentList = new List<object>();
456
457             var arguments = new List<INode>();
458             var node = enode.Properties[XmlName.xArguments] as ElementNode;
459             if (node != null)
460             {
461                 node.Accept(new EXamlSetPropertiesVisitor(Context, true), null);
462                 arguments.Add(node);
463             }
464
465             var list = enode.Properties[XmlName.xArguments] as ListNode;
466             if (list != null)
467             {
468                 foreach (var n in list.CollectionItems)
469                     arguments.Add(n);
470             }
471
472             for (int i = 0; i < arguments.Count; i++)
473             {
474                 argumentList.Add(Context.Values[arguments[i]]);
475             }
476
477             if (!isConstructor)
478             {
479                 for (int i = arguments.Count; i < paramsCount; i++)
480                 {
481                     argumentList.Add(Type.Missing);
482                 }
483             }
484
485             return argumentList;
486         }
487
488         static bool IsXaml2009LanguagePrimitive(IElementNode node)
489         {
490             if (node.NamespaceURI == XamlParser.X2009Uri)
491             {
492                 var n = node.XmlType.Name.Split(':')[1];
493                 return n != "Array" && n != "DateTime";
494             }
495             if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib")
496                 return false;
497             var name = node.XmlType.Name.Split(':')[1];
498             if (name == "SByte" ||
499                 name == "Int16" ||
500                 name == "Int32" ||
501                 name == "Int64" ||
502                 name == "Byte" ||
503                 name == "UInt16" ||
504                 name == "UInt32" ||
505                 name == "UInt64" ||
506                 name == "Single" ||
507                 name == "Double" ||
508                 name == "Boolean" ||
509                 name == "String" ||
510                 name == "Char" ||
511                 name == "Decimal" ||
512                 name == "TimeSpan" ||
513                 name == "Uri")
514                 return true;
515             return false;
516         }
517
518         object GetValueFromLanguagePrimitive(TypeReference typeRef, ElementNode node)
519         {
520             var module = Context.Module;
521             var hasValue = node.CollectionItems.Count == 1 && node.CollectionItems[0] is ValueNode &&
522                            ((ValueNode)node.CollectionItems[0]).Value is string;
523             var valueString = hasValue ? ((ValueNode)node.CollectionItems[0]).Value as string : string.Empty;
524             object ret = null;
525
526             TypeDefinition typedef = typeRef.ResolveCached();
527
528             switch (typedef.FullName)
529             {
530                 case "System.SByte":
531                     if (hasValue && sbyte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out sbyte outsbyte))
532                         ret = outsbyte;
533                     else
534                         ret = 0;
535                     break;
536                 case "System.Int16":
537                     if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outshort))
538                         ret = outshort;
539                     else
540                         ret = 0;
541                     break;
542                 case "System.Int32":
543                     if (hasValue && int.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out int outint))
544                         ret = outint;
545                     else
546                         ret = 0;
547                     break;
548                 case "System.Int64":
549                     if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outlong))
550                         ret = outlong;
551                     else
552                         ret = 0;
553                     break;
554                 case "System.Byte":
555                     if (hasValue && byte.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out byte outbyte))
556                         ret = outbyte;
557                     else
558                         ret = 0;
559                     break;
560                 case "System.UInt16":
561                     if (hasValue && short.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out short outushort))
562                         ret = outushort;
563                     else
564                         ret = 0;
565                     break;
566                 case "System.UInt32":
567                     if (hasValue && uint.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out uint outuint))
568                         ret = outuint;
569                     else
570                         ret = 0;
571                     break;
572                 case "System.UInt64":
573                     if (hasValue && long.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out long outulong))
574                         ret = outulong;
575                     else
576                         ret = 0;
577                     break;
578                 case "System.Boolean":
579                     if (hasValue && bool.TryParse(valueString, out bool outbool))
580                         ret = outbool;
581                     else
582                         ret = false;
583                     break;
584                 case "System.String":
585                     ret = valueString;
586                     break;
587                 case "System.Object":
588                     var ctorinfo =
589                         module.TypeSystem.Object.ResolveCached()
590                             .Methods.FirstOrDefault(md => md.IsConstructor && !md.HasParameters);
591                     var ctor = module.ImportReference(ctorinfo);
592                     ret = Create(Newobj, ctor);
593                     break;
594                 case "System.Char":
595                     if (hasValue && char.TryParse(valueString, out char outchar))
596                         ret = outchar;
597                     else
598                         ret = (char)0;
599                     break;
600                 case "System.Decimal":
601                     decimal outdecimal;
602                     if (hasValue && decimal.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out outdecimal))
603                     {
604                         ret = outdecimal;
605                     }
606                     else
607                     {
608                         ret = (decimal)0;
609                     }
610                     break;
611                 case "System.Single":
612                     if (hasValue && float.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out float outfloat))
613                         ret = outfloat;
614                     else
615                         ret = 0f;
616                     break;
617                 case "System.Double":
618                     if (hasValue && double.TryParse(valueString, NumberStyles.Number, CultureInfo.InvariantCulture, out double outdouble))
619                         ret = outdouble;
620                     else
621                         ret = 0d;
622                     break;
623                 case "System.TimeSpan":
624                     if (hasValue && TimeSpan.TryParse(valueString, CultureInfo.InvariantCulture, out TimeSpan outspan))
625                     {
626                         ret = outspan;
627                     }
628                     else
629                     {
630                         ret = null;
631                     }
632                     break;
633                 case "System.Uri":
634                     if (hasValue && Uri.TryCreate(valueString, UriKind.RelativeOrAbsolute, out Uri outuri))
635                     {
636                         ret = outuri;
637                     }
638                     else
639                     {
640                         ret = null;
641                     };
642                     break;
643                 default:
644                     ret = new EXamlCreateObject(Context, null, typeRef);
645                     break;
646             }
647
648             return ret;
649         }
650
651         List<object> GetCtorArguments(MethodDefinition ctorinfo, ElementNode enode, EXamlContext context)
652         {
653             List<object> ret = null;
654
655             foreach (var parameter in ctorinfo.Parameters)
656             {
657                 var propname =
658                     parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")
659                         .ConstructorArguments.First()
660                         .Value as string;
661                 var node = enode.Properties[new XmlName("", propname)];
662                 if (!enode.SkipProperties.Contains(new XmlName("", propname)))
663                     enode.SkipProperties.Add(new XmlName("", propname));
664
665                 if (node is ValueNode valueNode)
666                 {
667                     var valueType = parameter.ParameterType;
668
669                     if ("System.Type" == valueType.FullName)
670                     {
671                         var typeRef = XmlTypeExtensions.GetTypeReference(valueNode.Value as string, Module, node as BaseNode, XmlTypeExtensions.ModeOfGetType.Both);
672                         context.Values[node] = new EXamlCreateObject(context, typeRef);
673                     }
674                     else
675                     {
676                         var converterType = valueNode.GetConverterType(new ICustomAttributeProvider[] { parameter, parameter.ParameterType.ResolveCached() });
677
678                         if (null != converterType)
679                         {
680                             var converterValue = new EXamlValueConverterFromString(context, converterType.Resolve(), valueNode.Value as string);
681                             context.Values[node] = new EXamlCreateObject(context, converterValue, valueType);
682                         }
683                         else
684                         {
685                             context.Values[node] = valueNode.GetBaseValue(context, valueType);
686                         }
687                     }
688
689                     if (null == ret)
690                     {
691                         ret = new List<object>();
692                     }
693
694                     ret.Add(context.Values[node]);
695                 }
696             }
697
698             return ret;
699         }
700     }
701 }
702