[NUI] Add Tizen.NUI.XamlBuild module
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / public / EXamlBuild / EXamlSetNamescopesAndRegisterNamesVisitor.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 using System.Xml;
21 using Mono.Cecil.Cil;
22 using Tizen.NUI.Xaml;
23 using Tizen.NUI.Xaml.Build.Tasks;
24
25 namespace Tizen.NUI.EXaml.Build.Tasks
26 {
27     class EXamlSetNamescopesAndRegisterNamesVisitor : IXamlNodeVisitor
28     {
29         public EXamlSetNamescopesAndRegisterNamesVisitor(EXamlContext context)
30         {
31             Context = context;
32         }
33
34         EXamlContext Context { get; }
35
36         public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
37         public bool StopOnDataTemplate => true;
38         public bool StopOnResourceDictionary => false;
39         public bool VisitNodeOnDataTemplate => false;
40         public bool SkipChildren(INode node, INode parentNode) => false;
41
42         public bool IsResourceDictionary(ElementNode node)
43         {
44             var parentVar = Context.Variables[(IElementNode)node];
45             return parentVar.VariableType.FullName == "Tizen.NUI.Binding.ResourceDictionary"
46                 || parentVar.VariableType.Resolve().BaseType?.FullName == "Tizen.NUI.Binding.ResourceDictionary";
47         }
48
49         public void Visit(ValueNode node, INode parentNode)
50         {
51             Context.Scopes[node] = Context.Scopes[parentNode];
52             if (!IsXNameProperty(node, parentNode))
53                 return;
54             new EXaml.EXamlRegisterXName(Context, Context.Values[parentNode], node.Value as string);
55             //RegisterName((string)node.Value, Context.Scopes[node].Item1, Context.Scopes[node].Item2, Context.Variables[(IElementNode)parentNode], node);
56             //SetStyleId((string)node.Value, Context.Variables[(IElementNode)parentNode]);
57         }
58
59         public void Visit(MarkupNode node, INode parentNode)
60         {
61             Context.Scopes[node] = Context.Scopes[parentNode];
62         }
63
64         public void Visit(ElementNode node, INode parentNode)
65         {
66             VariableDefinition namescopeVarDef;
67             IList<string> namesInNamescope;
68             var setNameScope = false;
69             if (parentNode == null || IsDataTemplate(node, parentNode) || IsStyle(node, parentNode) || IsVisualStateGroupList(node)) {
70                 namescopeVarDef = CreateNamescope();
71                 namesInNamescope = new List<string>();
72                 setNameScope = true;
73             } else {
74                 namescopeVarDef = Context.Scopes[parentNode].Item1;
75                 namesInNamescope = Context.Scopes[parentNode].Item2;
76             }
77             if (setNameScope && Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
78                 SetNameScope(node, namescopeVarDef);
79             Context.Scopes[node] = new Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
80         }
81     
82         public void Visit(RootNode node, INode parentNode)
83         {
84             var namescopeVarDef = CreateNamescope();
85             IList<string> namesInNamescope = new List<string>();
86             if (Context.Variables[node].VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.xamlAssemblyName, XamlTask.bindingNameSpace, "BindableObject"))))
87                 SetNameScope(node, namescopeVarDef);
88             Context.Scopes[node] = new System.Tuple<VariableDefinition, IList<string>>(namescopeVarDef, namesInNamescope);
89         }
90
91         public void Visit(ListNode node, INode parentNode)
92         {
93             Context.Scopes[node] = Context.Scopes[parentNode];
94         }
95
96         static bool IsDataTemplate(INode node, INode parentNode)
97         {
98             var parentElement = parentNode as IElementNode;
99             INode createContent;
100             if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
101                 createContent == node)
102                 return true;
103             return false;
104         }
105
106         static bool IsStyle(INode node, INode parentNode)
107         {
108             var pnode = parentNode as ElementNode;
109             return pnode != null && pnode.XmlType.Name == "Style";
110         }
111
112         static bool IsVisualStateGroupList(ElementNode node)
113         {
114             return node != null  && node.XmlType.Name == "VisualStateGroup" && node.Parent is IListNode;
115         }
116
117         static bool IsXNameProperty(ValueNode node, INode parentNode)
118         {
119             var parentElement = parentNode as IElementNode;
120             INode xNameNode;
121             if (parentElement != null && parentElement.Properties.TryGetValue(XmlName.xName, out xNameNode) && xNameNode == node)
122                 return true;
123             return false;
124         }
125
126         VariableDefinition CreateNamescope()
127         {
128             var module = Context.Module;
129             var vardef = new VariableDefinition(module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope")));
130             //Context.IL.Emit(OpCodes.Newobj, module.ImportCtorReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope"), parameterTypes: null));
131             //Context.IL.Emit(OpCodes.Stloc, vardef);
132             return vardef;
133         }
134
135         void SetNameScope(ElementNode node, VariableDefinition ns)
136         {
137             var module = Context.Module;
138             //Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
139             //Context.IL.Emit(OpCodes.Ldloc, ns);
140             //Context.IL.Emit(OpCodes.Call, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "NameScope"),
141             //                                                           methodName: "SetNameScope",
142             //                                                           parameterTypes: new[] {
143             //                                                               (XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "BindableObject"),
144             //                                                               (XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "INameScope"),
145             //                                                           },
146             //                                                           isStatic: true));
147         }
148
149         void RegisterName(string str, VariableDefinition namescopeVarDef, IList<string> namesInNamescope, VariableDefinition element, INode node)
150         {
151             if (namesInNamescope.Contains(str))
152                 throw new XamlParseException($"An element with the name \"{str}\" already exists in this NameScope", node as IXmlLineInfo);
153             namesInNamescope.Add(str);
154
155             var module = Context.Module;
156             //Context.IL.Emit(OpCodes.Ldloc, namescopeVarDef);
157             //Context.IL.Emit(OpCodes.Ldstr, str);
158             //Context.IL.Emit(OpCodes.Ldloc, element);
159             //Context.IL.Emit(OpCodes.Callvirt, module.ImportMethodReference((XamlTask.bindingAssemblyName, XamlTask.bindingInternalNameSpace, "INameScope"),
160             //                                                               methodName: "RegisterName",
161             //                                                               parameterTypes: new[] {
162             //                                                                   ("mscorlib", "System", "String"),
163             //                                                                   ("mscorlib", "System", "Object"),
164             //                                                               }));
165         }
166
167         void SetStyleId(string str, VariableDefinition element)
168         {
169             if (!element.VariableType.InheritsFromOrImplements(Context.Module.ImportReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"))))
170                 return;
171
172             var module = Context.Module;
173
174             var nop = Instruction.Create(OpCodes.Nop);
175             //Context.IL.Emit(OpCodes.Ldloc, element);
176             //Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertyGetterReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
177             //Context.IL.Emit(OpCodes.Brtrue, nop);
178             //Context.IL.Emit(OpCodes.Ldloc, element);
179             //Context.IL.Emit(OpCodes.Ldstr, str);
180             //Context.IL.Emit(OpCodes.Callvirt, module.ImportPropertySetterReference((XamlTask.bindingAssemblyName, XamlTask.bindingNameSpace, "Element"), propertyName: "StyleId"));
181             //Context.IL.Append(nop);
182         }
183     }
184 }