[Xaml] Support import other xaml as the source of resource dictionary
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / EXamlBuild / EXamlContext.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.Reflection;
20 using Mono.Cecil;
21 using Mono.Cecil.Cil;
22
23 using Tizen.NUI.Xaml;
24
25 namespace Tizen.NUI.EXaml.Build.Tasks
26 {
27     internal class EXamlContext
28     {
29         public EXamlContext(TypeDefinition type, ModuleDefinition module, string embeddedResourceNameSpace, FieldDefinition parentContextValues = null)
30         {
31             Values = new Dictionary<INode, object>();
32             Variables = new Dictionary<IElementNode, VariableDefinition>();
33             Scopes = new Dictionary<INode, Tuple<VariableDefinition, IList<string>>>();
34             TypeExtensions = new Dictionary<INode, TypeReference>();
35             ParentContextValues = parentContextValues;
36             Type = type;
37             Module = module;
38             EmbeddedResourceNameSpace = embeddedResourceNameSpace;
39         }
40
41         public Dictionary<INode, object> Values { get; private set; }
42
43         public Dictionary<IElementNode, VariableDefinition> Variables { get; private set; }
44
45         public Dictionary<INode, Tuple<VariableDefinition, IList<string>>> Scopes { get; private set; }
46
47         public Dictionary<INode, TypeReference> TypeExtensions { get; }
48
49         public FieldDefinition ParentContextValues { get; private set; }
50
51         public object Root { get; set; } //FieldDefinition or VariableDefinition
52
53         public INode RootNode { get; set; }
54
55         public TypeDefinition Type { get; set; }
56
57         public ModuleDefinition Module { get; private set; }
58
59         public string EmbeddedResourceNameSpace { get; }
60
61         public List<EXamlOperation> eXamlOperations = new List<EXamlOperation>();
62
63         private string GetAssemblyName(AssemblyDefinition assembly)
64         {
65             string assemblyName = "";
66             if (assembly.FullName.StartsWith("Tizen.NUI.XamlBuild"))
67             {
68                 assemblyName = "Tizen.NUI";
69             }
70             else
71             {
72                 assemblyName = assembly.FullName;
73
74                 if (assemblyName.EndsWith(".dll"))
75                 {
76                     assemblyName = assemblyName.Substring(0, assemblyName.Length - ".dll".Length);
77                 }
78                 else if (assemblyName.EndsWith(".exe"))
79                 {
80                     assemblyName = assemblyName.Substring(0, assemblyName.Length - ".exe".Length);
81                 }
82                 else
83                 {
84                     int firstIndex = assemblyName.IndexOf(',');
85                     assemblyName = assemblyName.Substring(0, firstIndex);
86                 }
87
88                 if ("Tizen.NUI.Xaml" == assemblyName)
89                 {
90                     assemblyName = "Tizen.NUI";
91                 }
92             }
93
94             return assemblyName + ", ";
95         }
96
97         private string GetAssemblyName(Assembly assembly)
98         {
99             string assemblyName = "";
100             if (assembly.FullName == typeof(EXamlOperation).Assembly.FullName)
101             {
102                 assemblyName = "Tizen.NUI";
103             }
104             else
105             {
106                 assemblyName = assembly.FullName;
107
108                 if (assemblyName.Substring(assemblyName.Length - ".dll".Length) == ".dll")
109                 {
110                     assemblyName = assemblyName.Substring(0, assemblyName.Length - ".dll".Length);
111                 }
112                 else if (assemblyName.Substring(assemblyName.Length - ".exe".Length) == ".exe")
113                 {
114                     assemblyName = assemblyName.Substring(0, assemblyName.Length - ".exe".Length);
115                 }
116
117                 if ("Tizen.NUI.Xaml" == assemblyName)
118                 {
119                     assemblyName = "Tizen.NUI";
120                 }
121             }
122
123             return assemblyName + ", ";
124         }
125
126         private List<string> definedAssemblies
127         {
128             get;
129         } = new List<string>();
130
131         private List<TypeData> definedTypes
132         {
133             get;
134         } = new List<TypeData>();
135
136         internal EXamlDefinitionList<PropertyDefinition> definedProperties
137         {
138             get;
139         } = new EXamlDefinitionList<PropertyDefinition>();
140
141         internal EXamlDefinitionList<EventDefinition> definedEvents
142         {
143             get;
144         } = new EXamlDefinitionList<EventDefinition>();
145
146         internal List<IMemberDefinition> definedBindableProperties
147         {
148             get;
149         } = new List<IMemberDefinition>();
150
151         internal EXamlDefinitionList<MethodDefinition> definedMethods
152         {
153             get;
154         } = new EXamlDefinitionList<MethodDefinition>();
155
156         #region Data of CreateObject
157         internal List<EXamlCreateObject> eXamlCreateObjects
158         {
159             get;
160         } = new List<EXamlCreateObject>();
161
162         internal Dictionary<(TypeReference, MemberReference), EXamlCreateObject> StaticInstances
163         {
164             get;
165         } = new Dictionary<(TypeReference, MemberReference), EXamlCreateObject>();
166         #endregion
167
168         #region Data of AddObject
169         internal List<EXamlAddObject> eXamlAddObjectList
170         {
171             get;
172         } = new List<EXamlAddObject>();
173         #endregion
174
175         #region ConvertValue
176         internal Dictionary<TypeDefinition, EXamlCreateObject> typeToInstance
177         {
178             get;
179         } = new Dictionary<TypeDefinition, EXamlCreateObject>();
180         #endregion
181
182         #region Data of AddEvent
183         internal List<EXamlAddEvent> eXamlAddEventList
184         {
185             get;
186         } = new List<EXamlAddEvent>();
187         #endregion
188
189         #region Data of Register XName
190         internal Dictionary<string, object> xNameToInstance
191         {
192             get;
193         } = new Dictionary<string, object>();
194
195         internal object GetObjectByXName(string xName)
196         {
197             object ret = null;
198             xNameToInstance.TryGetValue(xName, out ret);
199             return ret;
200         }
201         #endregion
202
203         #region Data of Add Resource to Dictionary
204         internal Dictionary<string, object> resourceDictionary
205         {
206             get;
207         } = new Dictionary<string, object>();
208         #endregion
209
210         #region Data of Get object by property
211         internal List<EXamlGetObjectByProperty> objectsAccordingToProperty = new List<EXamlGetObjectByProperty>();
212
213         private int GetIndex(EXamlGetObjectByProperty eXamlObjectFromProperty)
214         {
215             return objectsAccordingToProperty.IndexOf(eXamlObjectFromProperty);
216         }
217         #endregion
218
219         public string GenerateEXamlString()
220         {
221             string ret = "";
222
223             int objectIndex = 0;
224
225             foreach (var examlOp in eXamlCreateObjects)
226             {
227                 if (examlOp.IsValid)
228                 {
229                     examlOp.Index = objectIndex++;
230                 }
231             }
232
233             foreach (var examlOp in eXamlCreateObjects)
234             {
235                 if (examlOp.IsValid)
236                 {
237                     GatherType(examlOp.Type);
238
239                     foreach (var property in examlOp.PropertyList)
240                     {
241                         GatherType(property.Item1);
242
243                         definedProperties.Add(property.Item1, property.Item2);
244
245                         if (true == property.Item1.Resolve()?.IsEnum)
246                         {
247                             GatherType(property.Item1.Resolve());
248                         }
249                     }
250
251                     foreach (var eventDef in examlOp.EventList)
252                     {
253                         GatherType(eventDef.Item1);
254
255                         definedEvents.Add(eventDef.Item1, eventDef.Item2);
256                     }
257
258                     foreach (var property in examlOp.BindableProperties)
259                     {
260                         if (!definedBindableProperties.Contains(property))
261                         {
262                             definedBindableProperties.Add(property);
263                         }
264
265                         var typeDef = property.DeclaringType;
266                         if (-1 == GetTypeIndex(typeDef))
267                         {
268                             GatherType(property.DeclaringType);
269                         }
270                     }
271
272                     foreach (var param in examlOp.paramsList)
273                     {
274                         if (null != param && param.GetType().IsEnum)
275                         {
276                             GatherType(param.GetType());
277                         }
278                     }
279
280                     if (null != examlOp.XFactoryMethod)
281                     {
282                         GatherMethod((examlOp.XFactoryMethod.DeclaringType, examlOp.XFactoryMethod));
283                     }
284                 }
285             }
286
287             foreach (var op in eXamlAddObjectList)
288             {
289                 if (op.Parent.IsValid && (!(op.Child is EXamlCreateObject eXamlCreateObject) || eXamlCreateObject.IsValid))
290                 {
291                     GatherMethod((op.Method.DeclaringType, op.Method));
292                 }
293             }
294
295             foreach (var op in eXamlAddEventList)
296             {
297                 if (op.Instance.IsValid)
298                 {
299                     GatherMethod((op.Value.DeclaringType, op.Value));
300                 }
301             }
302
303             foreach (var ass in definedAssemblies)
304             {
305                 ret += String.Format("({0} ({1}))\n",
306                                 GetValueString((int)EXamlOperationType.GatherAssembly),
307                                 GetValueString(ass));
308             }
309
310             foreach (var type in definedTypes)
311             {
312                 ret += String.Format("({0} {1})\n",
313                                 GetValueString((int)EXamlOperationType.GatherType),
314                                 type.ConvertToString(definedAssemblies, definedTypes));
315             }
316
317             foreach (var property in definedProperties)
318             {
319                 var typeDef = property.Item1;
320                 int typeIndex = GetTypeIndex(typeDef);
321                 ret += String.Format("({0} ({1} {2}))\n",
322                                 GetValueString((int)EXamlOperationType.GatherProperty),
323                                 GetValueString(typeIndex),
324                                 GetValueString(property.Item2.Name));
325             }
326
327             foreach (var eventDef in definedEvents)
328             {
329                 var typeDef = eventDef.Item1;
330                 int typeIndex = GetTypeIndex(typeDef);
331                 ret += String.Format("({0} ({1} {2}))\n",
332                                 GetValueString((int)EXamlOperationType.GatherEvent),
333                                 GetValueString(typeIndex),
334                                 GetValueString(eventDef.Item2.Name));
335             }
336
337             foreach (var method in definedMethods)
338             {
339                 var typeDef = method.Item1;
340                 int typeIndex = GetTypeIndex(typeDef);
341
342                 string strForParam = "(";
343                 foreach (var param in method.Item2.Parameters)
344                 {
345                     int paramTypeIndex = GetTypeIndex(param.ParameterType);
346
347                     if (-1 == paramTypeIndex)
348                     {
349                         throw new Exception($"Can't find index of param type {param.ParameterType.FullName}");
350                     }
351
352                     strForParam += GetValueString(paramTypeIndex) + " ";
353                 }
354                 strForParam += ")";
355
356                 ret += String.Format("({0} ({1} {2} {3}))\n",
357                                 GetValueString((int)EXamlOperationType.GatherMethod),
358                                 GetValueString(typeIndex),
359                                 GetValueString(method.Item2.Name),
360                                 strForParam);
361             }
362
363             foreach (var property in definedBindableProperties)
364             {
365                 var typeDef = property.DeclaringType;
366                 int typeIndex = GetTypeIndex(typeDef);
367                 ret += String.Format("({0} ({1} {2}))\n",
368                                 GetValueString((int)EXamlOperationType.GatherBindableProperty),
369                                 GetValueString(typeIndex),
370                                 GetValueString(property.Name));
371             }
372
373             foreach (var op in eXamlOperations)
374             {
375                 ret += op.Write();
376             }
377
378             if (0 < longStrings.Length)
379             {
380                 ret += String.Format("/{0}\n", longStrings);
381             }
382
383             return ret;
384         }
385
386         private void GatherType(TypeReference typeRef)
387         {
388             if (-1 == GetTypeIndex(typeRef))
389             {
390                 var assemblyName = GetAssemblyName(typeRef.Resolve().Module.Assembly);
391                 if (!definedAssemblies.Contains(assemblyName))
392                 {
393                     definedAssemblies.Add(assemblyName);
394                 }
395
396                 var typeData = new TypeData(typeRef, GetAssemblyName(typeRef.Resolve().Module.Assembly));
397
398                 if (typeRef is GenericInstanceType genericType)
399                 {
400                     foreach (var type in genericType.GenericArguments)
401                     {
402                         GatherType(type);
403                     }
404                 }
405                 definedTypes.Add(typeData);
406             }
407         }
408
409         private void GatherType(Type type)
410         {
411             var assemblyName = GetAssemblyName(type.Assembly);
412             if (!definedAssemblies.Contains(assemblyName))
413             {
414                 definedAssemblies.Add(assemblyName);
415             }
416
417             if (-1 == GetTypeIndex(type))
418             {
419                 definedTypes.Add(new TypeData(type, GetAssemblyName(type.Assembly)));
420             }
421         }
422
423         private void GatherMethod((TypeReference, MethodDefinition) methodInfo)
424         {
425             GatherType(methodInfo.Item1);
426
427             foreach (var param in methodInfo.Item2.Parameters)
428             {
429                 GatherType(param.ParameterType);
430             }
431
432             definedMethods.Add(methodInfo.Item1, methodInfo.Item2);
433         }
434
435         private int GetTypeIndex(TypeData typeData)
436         {
437             if (null != typeData.TypeReference)
438             {
439                 return GetTypeIndex(typeData.TypeReference);
440             }
441
442             if (null != typeData.Type)
443             {
444                 return GetTypeIndex(typeData.Type);
445             }
446
447             return -1;
448         }
449
450         internal int GetTypeIndex(TypeReference typeReference)
451         {
452             for (int i = 0; i < definedTypes.Count; i++)
453             {
454                 if (EXamlUtility.IsSameTypeReference(typeReference, definedTypes[i].TypeReference))
455                 {
456                     return i;
457                 }
458             }
459
460             int ret = -1;
461             switch (typeReference.FullName)
462             {
463                 case "System.SByte":
464                     ret = -2;
465                     break;
466                 case "System.Int16":
467                     ret = -3;
468                     break;
469                 case "System.Int32":
470                     ret = -4;
471                     break;
472                 case "System.Int64":
473                     ret = -5;
474                     break;
475                 case "System.Byte":
476                     ret = -6;
477                     break;
478                 case "System.UInt16":
479                     ret = -7;
480                     break;
481                 case "System.UInt32":
482                     ret = -8;
483                     break;
484                 case "System.UInt64":
485                     ret = -9;
486                     break;
487                 case "System.Boolean":
488                     ret = -10;
489                     break;
490                 case "System.String":
491                     ret = -11;
492                     break;
493                 case "System.Object":
494                     ret = -12;
495                     break;
496                 case "System.Char":
497                     ret = -13;
498                     break;
499                 case "System.Decimal":
500                     ret = -14;
501                     break;
502                 case "System.Single":
503                     ret = -15;
504                     break;
505                 case "System.Double":
506                     ret = -16;
507                     break;
508                 case "System.TimeSpan":
509                     ret = -17;
510                     break;
511                 case "System.Uri":
512                     ret = -18;
513                     break;
514             }
515
516             return ret;
517         }
518
519         internal static int GetTypeIndex(TypeData type, List<TypeData> definedTypes)
520         {
521             for (int i = 0; i < definedTypes.Count; i++)
522             {
523                 if (EXamlUtility.IsSameTypeReference(type.TypeReference, definedTypes[i].TypeReference))
524                 {
525                     return i;
526                 }
527             }
528
529             int ret = -1;
530             switch (type.TypeReference.FullName)
531             {
532                 case "System.SByte":
533                     ret = -2;
534                     break;
535                 case "System.Int16":
536                     ret = -3;
537                     break;
538                 case "System.Int32":
539                     ret = -4;
540                     break;
541                 case "System.Int64":
542                     ret = -5;
543                     break;
544                 case "System.Byte":
545                     ret = -6;
546                     break;
547                 case "System.UInt16":
548                     ret = -7;
549                     break;
550                 case "System.UInt32":
551                     ret = -8;
552                     break;
553                 case "System.UInt64":
554                     ret = -9;
555                     break;
556                 case "System.Boolean":
557                     ret = -10;
558                     break;
559                 case "System.String":
560                     ret = -11;
561                     break;
562                 case "System.Object":
563                     ret = -12;
564                     break;
565                 case "System.Char":
566                     ret = -13;
567                     break;
568                 case "System.Decimal":
569                     ret = -14;
570                     break;
571                 case "System.Single":
572                     ret = -15;
573                     break;
574                 case "System.Double":
575                     ret = -16;
576                     break;
577                 case "System.TimeSpan":
578                     ret = -17;
579                     break;
580                 case "System.Uri":
581                     ret = -18;
582                     break;
583             }
584
585             return ret;
586         }
587
588         private int GetTypeIndex(Type type)
589         {
590             for (int i = 0; i < definedTypes.Count; i++)
591             {
592                 if (type == definedTypes[i].Type)
593                 {
594                     return i;
595                 }
596             }
597
598             return -1;
599         }
600
601         internal (int, int) GetLongStringIndexs(string longString)
602         {
603             if (longStringToIndexPair.ContainsKey(longString))
604             {
605                 return longStringToIndexPair[longString];
606             }
607             else
608             {
609                 var indexPair = (longStrings.Length, 0);
610                 longStrings += longString;
611                 indexPair.Item2 = longStrings.Length - 1;
612
613                 longStringToIndexPair.Add(longString, indexPair);
614                 return indexPair;
615             }
616         }
617
618         private string longStrings = "";
619         private Dictionary<string, (int, int)> longStringToIndexPair = new Dictionary<string, (int, int)>();
620
621         internal string GetValueString(object valueObject)
622         {
623             //Fang: How to deal the Enum
624             string ret = "";
625
626             if (System.Type.Missing == valueObject)
627             {
628                 ret += "yy ";
629             }
630             else if (null == valueObject)
631             {
632                 ret += "zz ";
633             }
634             else if (valueObject is List<object> listObjects)
635             {
636                 ret += "(";
637
638                 foreach (var obj in listObjects)
639                 {
640                     ret += GetValueString(obj);
641                     ret += " ";
642                 }
643
644                 ret += ")";
645             }
646             else
647             {
648                 //Fang
649                 var paramType = valueObject.GetType();
650
651                 string signBegin = "a", signEnd = "a";
652                 string value = "";
653
654                 if (valueObject is EXamlCreateObject)
655                 {
656                     signBegin = signEnd = "a";
657                     value = (valueObject as EXamlCreateObject).Index.ToString();
658                 }
659                 else if (valueObject is EXamlGetObjectByProperty)
660                 {
661                     return GetValueString(GetIndex(valueObject as EXamlGetObjectByProperty));
662                 }
663                 else if (paramType == typeof(string) || paramType == typeof(Uri))
664                 {
665                     signBegin = signEnd = "\"";
666                     value = valueObject.ToString();
667                 }
668                 else if (paramType == typeof(char))
669                 {
670                     signBegin = signEnd = "\'";
671                     value = valueObject.ToString();
672                 }
673                 else if (paramType == typeof(SByte))
674                 {
675                     signBegin = signEnd = "b";
676                     value = valueObject.ToString();
677                 }
678                 else if (paramType == typeof(Int16))
679                 {
680                     signBegin = signEnd = "c";
681                     value = valueObject.ToString();
682                 }
683                 else if (paramType == typeof(Int32))
684                 {
685                     signBegin = signEnd = "d";
686                     value = valueObject.ToString();
687                 }
688                 else if (paramType == typeof(Int64))
689                 {
690                     signBegin = signEnd = "e";
691                     value = valueObject.ToString();
692                 }
693                 else if (paramType == typeof(Byte))
694                 {
695                     signBegin = signEnd = "f";
696                     value = valueObject.ToString();
697                 }
698                 else if (paramType == typeof(UInt16))
699                 {
700                     signBegin = signEnd = "g";
701                     value = valueObject.ToString();
702                 }
703                 else if (paramType == typeof(UInt32))
704                 {
705                     signBegin = signEnd = "h";
706                     value = valueObject.ToString();
707                 }
708                 else if (paramType == typeof(UInt64))
709                 {
710                     signBegin = signEnd = "i";
711                     value = valueObject.ToString();
712                 }
713                 else if (paramType == typeof(Single))
714                 {
715                     signBegin = signEnd = "j";
716                     value = valueObject.ToString();
717                 }
718                 else if (paramType == typeof(Double))
719                 {
720                     signBegin = signEnd = "k";
721                     value = valueObject.ToString();
722                 }
723                 else if (paramType == typeof(TimeSpan))
724                 {
725                     signBegin = signEnd = "l";
726                     value = valueObject.ToString();
727                 }
728                 else if (paramType == typeof(Boolean))
729                 {
730                     signBegin = signEnd = "m";
731                     value = valueObject.ToString();
732                 }
733                 else if (paramType == typeof(decimal))
734                 {
735                     signBegin = signEnd = "n";
736                     value = valueObject.ToString();
737                 }
738                 else if (paramType.IsEnum)
739                 {
740                     signBegin = "o(";
741                     int typeIndex = GetTypeIndex(paramType);
742                     value = String.Format("d{0}d \"{1}\"", typeIndex, valueObject.ToString());
743                     signEnd = ")o";
744                 }
745                 else if (valueObject is EXamlValueConverterFromString)
746                 {
747                     signBegin = "q(";
748                     signEnd = ")q";
749                     value = (valueObject as EXamlValueConverterFromString).GetString();
750                 }
751
752                 ret += String.Format("{0}{1}{2} ", signBegin, value, signEnd);
753             }
754
755             return ret;
756         }
757     }
758
759     internal class TypeData
760     {
761         internal TypeData(Type type, string assemblyName)
762         {
763             Type = type;
764             AssemblyName = assemblyName;
765
766             if (type.IsNested)
767             {
768                 FullName = type.FullName.Replace('/', '+');
769             }
770             else
771             {
772                 FullName = type.FullName;
773             }
774         }
775
776         internal TypeData(TypeReference typeReference, string assemblyName)
777         {
778             TypeReference = typeReference;
779
780             AssemblyName = assemblyName;
781
782             if (typeReference is GenericInstanceType genericType)
783             {
784                 GenericArgumentTypes = new List<TypeData>();
785                 foreach (var type in genericType.GenericArguments)
786                 {
787                     GenericArgumentTypes.Add(new TypeData(type, AssemblyName));
788                 }
789                 FullName = typeReference.Resolve().FullName;
790             }
791             else
792             {
793                 FullName = typeReference.FullName;
794             }
795
796             if (typeReference.IsNested)
797             {
798                 FullName = FullName.Replace('/', '+');
799             }
800         }
801
802         public string ConvertToString(List<string> definedAssemblies, List<TypeData> typeDatas)
803         {
804             string ret = "";
805             int assemblyIndex = definedAssemblies.IndexOf(AssemblyName);
806
807             if (null == GenericArgumentTypes)
808             {
809                 ret += String.Format("(d{0}d \"{1}\")", assemblyIndex, FullName);
810             }
811             else
812             {
813                 string strForGenericTypes = "(";
814
815                 foreach (var type in GenericArgumentTypes)
816                 {
817                     strForGenericTypes += "d" + EXamlContext.GetTypeIndex(type, typeDatas) + "d ";
818                 }
819
820                 strForGenericTypes += ")";
821
822                 ret += String.Format("(d{0}d \"{1}\" {2})", assemblyIndex, FullName, strForGenericTypes);
823             }
824
825             return ret;
826         }
827
828         internal TypeReference TypeReference
829         {
830             get;
831         }
832
833         internal Type Type
834         {
835             get;
836         }
837
838         internal string AssemblyName
839         {
840             get;
841         }
842
843         internal string FullName
844         {
845             get;
846         }
847
848         internal List<TypeData> GenericArgumentTypes
849         {
850             get;
851         }
852     }
853 }
854