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 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();