2 // MarkupExpressionParser.cs
4 // This code is partly salvaged from moonlight. Following licence apply.
8 // Moonlight List (moonlight-list@lists.ximian.com)
9 // Stephane Delcroix (stephane@mi8.be)
11 // Copyright 2009 Novell, Inc.
12 // Copyright 2013 Xamarin, Inc.
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
37 namespace Tizen.NUI.Xaml
39 internal abstract class MarkupExpressionParser
41 public object ParseExpression(ref string expression, IServiceProvider serviceProvider)
43 if (serviceProvider == null)
44 throw new ArgumentNullException(nameof(serviceProvider));
45 if (expression.StartsWith("{}", StringComparison.Ordinal))
46 return expression.Substring(2);
48 if (expression[expression.Length - 1] != '}')
49 throw new Exception("Expression must end with '}'");
53 if (!MatchMarkup(out match, expression, out len))
55 expression = expression.Substring(len).TrimStart();
56 if (expression.Length == 0)
57 throw new Exception("Expression did not end in '}'");
59 var parser = Activator.CreateInstance(GetType()) as IExpressionParser;
60 return parser?.Parse(match, ref expression, serviceProvider);
63 internal static bool MatchMarkup(out string match, string expression, out int end)
65 if (expression.Length < 2)
72 if (expression[0] != '{')
81 for (i = 1; i < expression.Length; i++)
83 if (expression[i] == ' ')
97 for (c = 0; c + i < expression.Length; c++)
99 if (expression[i + c] == ' ' || expression[i + c] == '}')
103 if (i + c == expression.Length)
111 match = expression.Substring(i, c);
115 protected void HandleProperty(string prop, IServiceProvider serviceProvider, ref string remaining, bool isImplicit)
123 SetPropertyValue(null, prop, null, serviceProvider);
126 remaining = remaining.TrimStart();
127 if (remaining.StartsWith("{", StringComparison.Ordinal))
129 value = ParseExpression(ref remaining, serviceProvider);
130 remaining = remaining.TrimStart();
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);
137 str_value = value as string;
140 str_value = GetNextPiece(ref remaining, out next);
142 SetPropertyValue(prop, str_value, value, serviceProvider);
145 protected abstract void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider);
147 protected string GetNextPiece(ref string remaining, out char next)
149 bool inString = false;
151 char stringTerminator = '\0';
152 remaining = remaining.TrimStart();
153 if (remaining.Length == 0)
155 next = Char.MaxValue;
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] != '=')))
166 if (remaining[end] == stringTerminator)
175 if (remaining[end] == '\'' || remaining[end] == '"')
178 stringTerminator = remaining[end];
184 // If this is an escape char, consume it and append the next char to our piece.
185 if (remaining[end] == '\\')
188 if (end == remaining.Length)
191 piece.Append(remaining[end]);
195 if (inString && end == remaining.Length)
196 throw new Exception("Unterminated quoted string");
198 if (end == remaining.Length && !remaining.EndsWith("}", StringComparison.Ordinal))
199 throw new Exception("Expression did not end with '}'");
203 next = Char.MaxValue;
207 next = remaining[end];
208 remaining = remaining.Substring(end + 1);
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]))
215 if (piece.Length >= 2)
217 char first = piece[0];
218 char last = piece[piece.Length - 1];
219 if ((first == '\'' && last == '\'') || (first == '"' && last == '"'))
221 piece.Remove(piece.Length - 1, 1);
226 return piece.ToString();