static DefaultBindingParserHandler()
 {
     ReplaceKeywords = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
     {
         {"&lt;", "<"},
         {"&gt;", ">"},
         {"&quot;", "\""},
         {"&amp;", "&"}
     };
     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;
        }