static DefaultBindingParserHandler() { ReplaceKeywords = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase) { {"<", "<"}, {">", ">"}, {""", "\""}, {"&", "&"} }; QuoteSymbols = new HashSet<string> { "\"", "'" }; InterpolatedStringTokenizer = new Tokenizer(false); InterpolatedStringTokenizer.IgnoreChars.Add('\''); InterpolatedStringTokenizer.IgnoreChars.Add('"'); }
public BindingParser() { _cache = new Dictionary<string, KeyValuePair<KeyValuePair<string, int>, Action<IDataContext>[]>[]>(StringComparer.Ordinal); _defaultContext = new DataContext(); _handlers = new List<IBindingParserHandler> { new DefaultBindingParserHandler() }; _defaultTokenizer = new Tokenizer(true); _memberVisitor = new BindingMemberVisitor(); _counterVisitor = new ExpressionCounterVisitor(); _binaryOperationTokens = new Dictionary<TokenType, int> { {TokenType.QuestionDot, 101}, {TokenType.Asterisk, 100}, {TokenType.Slash, 100}, {TokenType.Percent, 100}, {TokenType.Plus, 99}, {TokenType.Minus, 99}, {TokenType.ExclamationEqual, 98}, {TokenType.GreaterThan, 98}, {TokenType.LessThan, 98}, {TokenType.GreaterThanEqual, 98}, {TokenType.LessThanEqual, 98}, {TokenType.Equal, 97}, {TokenType.DoubleEqual, 97}, {TokenType.Amphersand, 96}, {TokenType.Bar, 95}, {TokenType.DoubleAmphersand, 94}, {TokenType.DoubleBar, 93}, }; _unaryOperationTokens = new HashSet<TokenType> { TokenType.Minus, TokenType.Exclamation, TokenType.Tilde }; _bindingParameterToAction = new Dictionary<string, Func<BindingParser, IList<Action<IDataContext>>>>(StringComparer.OrdinalIgnoreCase) { {"Mode", parser => parser.GetBindingModeSetter()}, {"M", parser => parser.GetBindingModeSetter()}, {"ValidatesOnNotifyDataErrors", parser => parser.GetBehaviorSetter(ValidatesOnNotifyDataErrorsBehavior.Prototype)}, {"ValidatesOnErrors", parser => parser.GetBehaviorSetter(ValidatesOnNotifyDataErrorsBehavior.Prototype)}, {"ValidatesOnExceptions", parser => parser.GetBehaviorSetter(ValidatesOnExceptionsBehavior.Instance)}, {"Validate", parser => parser.GetBehaviorSetter(ValidatesOnNotifyDataErrorsBehavior.Prototype, ValidatesOnExceptionsBehavior.Instance)}, {"DefaultValueOnException", parser => parser.GetDefaultValueOnExceptionSetter()}, {"SetDefaultValue", parser => parser.GetDefaultValueOnExceptionSetter()}, {"Delay", parser => parser.GetDelaySetter(false)}, {"SourceDelay", parser => parser.GetDelaySetter(false)}, {"TargetDelay", parser => parser.GetDelaySetter(true)}, {"Converter", parser => parser.GetConverterSetter()}, {"Conv", parser => parser.GetConverterSetter()}, {"ConverterParameter", parser => parser.GetConverterParameterSetter()}, {"ConverterCulture", parser => parser.GetConverterCultureSetter()}, {"Fallback", parser => parser.GetFallbackSetter()}, {"TargetNullValue", parser => parser.GetTargetNullValueSetter()}, {AttachedMemberConstants.CommandParameter, parser => parser.GetCommandParameterSetter()}, {"Behavior", parser => parser.GetCustomBehaviorSetter()}, {nameof(BindingBuilderConstants.ToggleEnabledState), parser => parser.GetBoolValue(BindingBuilderConstants.ToggleEnabledState)}, {"ToggleEnabled", parser => parser.GetBoolValue(BindingBuilderConstants.ToggleEnabledState)}, {"DisableEqualityChecking", parser => parser.GetDisableEqualityChecking(null)}, {"TargetDisableEqualityChecking", parser => parser.GetDisableEqualityChecking(true)}, {"SourceDisableEqualityChecking", parser => parser.GetDisableEqualityChecking(false)}, {nameof(BindingBuilderConstants.HasStablePath), parser => parser.GetBoolValue(BindingBuilderConstants.HasStablePath) }, {nameof(BindingBuilderConstants.Observable), parser => parser.GetBoolValue(BindingBuilderConstants.Observable) }, {nameof(BindingBuilderConstants.Optional), parser => parser.GetBoolValue(BindingBuilderConstants.Optional) } }; _binaryOperationAliases = new Dictionary<string, TokenType>(StringComparer.OrdinalIgnoreCase) { {"and", TokenType.DoubleAmphersand}, {"or", TokenType.DoubleBar}, {"mod", TokenType.Percent} }; _unaryOperationAliases = new Dictionary<string, TokenType>(StringComparer.OrdinalIgnoreCase) { {"not", TokenType.Exclamation} }; _relativeSourceAliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { RelativeSourceExpressionNode.RelativeSourceType, "Relative", "Rel" }; _elementSourceAliases = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { RelativeSourceExpressionNode.ElementSourceType, "Element", "El" }; }
//https://msdn.microsoft.com/en-us/library/dn961160.aspx private static string ParseInterpolatedString(Tokenizer tokenizer, out int start, out int end, bool openQuote = false) { start = -1; end = -1; var resultBuilder = new StringBuilder(); var items = new List<string>(); while (tokenizer.Token != TokenType.Eof) { if (tokenizer.Token == TokenType.Dollar) { start = tokenizer.Position - 1; tokenizer.NextToken(false); if (QuoteSymbols.Contains(tokenizer.Value)) { if (openQuote) return null; openQuote = true; tokenizer.NextToken(false); } } if (QuoteSymbols.Contains(tokenizer.Value)) { if (openQuote) { end = tokenizer.Position; tokenizer.NextToken(false); return $"$string.Format(\"{resultBuilder}\", {string.Join(",", items)})"; } } if (!openQuote) { tokenizer.NextToken(false); continue; } if (tokenizer.Token == TokenType.OpenBrace) { resultBuilder.Append(tokenizer.Value); tokenizer.NextToken(false); //Ignoring two brace if (tokenizer.Token == TokenType.OpenBrace) { resultBuilder.Append(tokenizer.Value); tokenizer.NextToken(false); continue; } var item = new StringBuilder(); bool hasItem = false; bool hasFieldWidth = false; bool hasFormat = false; bool startFormat = false; int openParenCount = 0; while (true) { if (tokenizer.Token == TokenType.Eof) return null; if (tokenizer.Token == TokenType.Dollar) { tokenizer.NextToken(false); if (QuoteSymbols.Contains(tokenizer.Value)) { if (hasItem) return null; tokenizer.NextToken(false); int s, e; var nestedItem = ParseInterpolatedString(tokenizer, out s, out e, true); if (nestedItem == null) return null; item.Append(nestedItem); } else { if (hasItem) resultBuilder.Append(TokenType.Dollar.Value); else item.Append(TokenType.Dollar.Value); } } if (tokenizer.Token == TokenType.OpenParen) ++openParenCount; else if (tokenizer.Token == TokenType.CloseParen) --openParenCount; else if (openParenCount == 0) { if (tokenizer.Token == TokenType.CloseBrace) { AddInterpolatedItem(ref hasItem, resultBuilder, item, items); resultBuilder.Append(tokenizer.Value); tokenizer.NextToken(false); break; } if (tokenizer.Token == TokenType.Comma) { AddInterpolatedItem(ref hasItem, resultBuilder, item, items); resultBuilder.Append(tokenizer.Value); while (tokenizer.NextToken(false) == TokenType.Whitespace) resultBuilder.Append(tokenizer.Value); if (tokenizer.Token == TokenType.IntegerLiteral) { if (hasFieldWidth) return null; hasFieldWidth = true; if (startFormat) hasFormat = true; } else if (!startFormat) return null; } else if (tokenizer.Token == TokenType.Colon) { if (hasFormat) return null; AddInterpolatedItem(ref hasItem, resultBuilder, item, items); startFormat = true; } } if (hasItem) resultBuilder.Append(tokenizer.Value); else item.Append(tokenizer.Value); tokenizer.NextToken(false); } } else if (tokenizer.Token == TokenType.CloseBrace) { tokenizer.NextToken(false); if (tokenizer.Token != TokenType.CloseBrace) return null; tokenizer.NextToken(false); resultBuilder.Append("}}"); } else { resultBuilder.Append(tokenizer.Value); tokenizer.NextToken(false); } } return null; }