[NUI]Add xaml support for nui and nui xaml test sample (#230)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / MarkupExpressionParser.cs
1 //
2 // MarkupExpressionParser.cs
3 //
4 // This code is partly salvaged from moonlight. Following licence apply.
5 //
6 //
7 // Author(s):
8 //   Moonlight List (moonlight-list@lists.ximian.com)
9 //   Stephane Delcroix (stephane@mi8.be)
10 //
11 // Copyright 2009 Novell, Inc.
12 // Copyright 2013 Xamarin, Inc.
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Text;
36
37 namespace Tizen.NUI.Xaml
38 {
39         abstract class MarkupExpressionParser
40         {
41                 public object ParseExpression(ref string expression, IServiceProvider serviceProvider)
42                 {
43                         if (serviceProvider == null)
44                                 throw new ArgumentNullException(nameof(serviceProvider));
45                         if (expression.StartsWith("{}", StringComparison.Ordinal))
46                                 return expression.Substring(2);
47
48                         if (expression[expression.Length - 1] != '}')
49                                 throw new Exception("Expression must end with '}'");
50
51                         int len;
52                         string match;
53                         if (!MatchMarkup(out match, expression, out len))
54                                 return false;
55                         expression = expression.Substring(len).TrimStart();
56                         if (expression.Length == 0)
57                                 throw new Exception("Expression did not end in '}'");
58
59                         var parser = Activator.CreateInstance(GetType()) as IExpressionParser;
60                         return parser.Parse(match, ref expression, serviceProvider);
61                 }
62
63                 internal static bool MatchMarkup(out string match, string expression, out int end)
64                 {
65                         if (expression.Length < 2)
66                         {
67                                 end = 1;
68                                 match = null;
69                                 return false;
70                         }
71
72                         if (expression[0] != '{')
73                         {
74                                 end = 2;
75                                 match = null;
76                                 return false;
77                         }
78
79                         int i;
80                         bool found = false;
81                         for (i = 1; i < expression.Length; i++)
82                         {
83                                 if (expression[i] == ' ')
84                                         continue;
85                                 found = true;
86                                 break;
87                         }
88
89                         if (!found)
90                         {
91                                 end = 3;
92                                 match = null;
93                                 return false;
94                         }
95
96                         int c;
97                         for (c = 0; c + i < expression.Length; c++)
98                         {
99                                 if (expression[i + c] == ' ' || expression[i + c] == '}')
100                                         break;
101                         }
102
103                         if (i + c == expression.Length)
104                         {
105                                 end = 6;
106                                 match = null;
107                                 return false;
108                         }
109
110                         end = i + c;
111                         match = expression.Substring(i, c);
112                         return true;
113                 }
114
115                 protected void HandleProperty(string prop, IServiceProvider serviceProvider, ref string remaining, bool isImplicit)
116                 {
117                         char next;
118                         object value = null;
119                         string str_value;
120
121                         if (isImplicit)
122                         {
123                                 SetPropertyValue(null, prop, null, serviceProvider);
124                                 return;
125                         }
126                         remaining = remaining.TrimStart();
127                         if (remaining.StartsWith("{", StringComparison.Ordinal))
128                         {
129                                 value = ParseExpression(ref remaining, serviceProvider);
130                                 remaining = remaining.TrimStart();
131
132                                 if (remaining.Length > 0 && remaining[0] == ',')
133                                         remaining = remaining.Substring(1);
134                                 else if (remaining.Length > 0 && remaining[0] == '}')
135                                         remaining = remaining.Substring(1);
136
137                                 str_value = value as string;
138                         }
139                         else
140                                 str_value = GetNextPiece(ref remaining, out next);
141
142                         SetPropertyValue(prop, str_value, value, serviceProvider);
143                 }
144
145                 protected abstract void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider);
146
147                 protected string GetNextPiece(ref string remaining, out char next)
148                 {
149                         bool inString = false;
150                         int end = 0;
151                         char stringTerminator = '\0';
152                         remaining = remaining.TrimStart();
153                         if (remaining.Length == 0)
154                         {
155                                 next = Char.MaxValue;
156                                 return null;
157                         }
158
159                         var piece = new StringBuilder();
160                         // If we're inside a quoted string we append all chars to our piece until we hit the ending quote.
161                         while (end < remaining.Length &&
162                                (inString || (remaining[end] != '}' && remaining[end] != ',' && remaining[end] != '=')))
163                         {
164                                 if (inString)
165                                 {
166                                         if (remaining[end] == stringTerminator)
167                                         {
168                                                 inString = false;
169                                                 end ++;
170                                                 break;
171                                         }
172                                 }
173                                 else
174                                 {
175                                         if (remaining[end] == '\'' || remaining[end] == '"')
176                                         {
177                                                 inString = true;
178                                                 stringTerminator = remaining[end];
179                                                 end ++;
180                                                 continue;
181                                         }
182                                 }
183
184                                 // If this is an escape char, consume it and append the next char to our piece.
185                                 if (remaining[end] == '\\')
186                                 {
187                                         end ++;
188                                         if (end == remaining.Length)
189                                                 break;
190                                 }
191                                 piece.Append(remaining[end]);
192                                 end++;
193                         }
194
195                         if (inString && end == remaining.Length)
196                                 throw new Exception("Unterminated quoted string");
197
198                         if (end == remaining.Length && !remaining.EndsWith("}", StringComparison.Ordinal))
199                                 throw new Exception("Expression did not end with '}'");
200
201                         if (end == 0)
202                         {
203                                 next = Char.MaxValue;
204                                 return null;
205                         }
206
207                         next = remaining[end];
208                         remaining = remaining.Substring(end + 1);
209
210                         // Whitespace is trimmed from the end of the piece before stripping
211                         // quote chars from the start/end of the string. 
212                         while (piece.Length > 0 && char.IsWhiteSpace(piece[piece.Length - 1]))
213                                 piece.Length --;
214
215                         if (piece.Length >= 2)
216                         {
217                                 char first = piece[0];
218                                 char last = piece[piece.Length - 1];
219                                 if ((first == '\'' && last == '\'') || (first == '"' && last == '"'))
220                                 {
221                                         piece.Remove(piece.Length - 1, 1);
222                                         piece.Remove(0, 1);
223                                 }
224                         }
225
226                         return piece.ToString();
227                 }
228         }
229 }