private VisualBasicAstToken ReadStringToken()
        {
            var startLocation = Location;
            var startCharacter = Read();

            TextRange range;

            bool escaped = false;

            string stringToken = startCharacter + ReadCharacters(x =>
            {
                return x == startCharacter;
                // TOOD: c suffix and double quotes inside string.
            }, out range);

            char character;
            if (Peek(out character) && character == startCharacter)
                stringToken += Read();
            var endLocation = Location;

            var astToken = new VisualBasicAstToken(LITERAL, stringToken, new TextRange(startLocation, endLocation));
            astToken.UserData["InterpretedValue"] = VisualBasicLanguage.Instance.StringFormatter.EvaluateFormattedString(stringToken);
            return astToken;
        }
        protected override AstToken ReadNextToken()
        {
            while (true)
            {
                if (!MoveToNextToken())
                    return new VisualBasicAstToken(EOF, string.Empty, new TextRange(Location, Location));

                char currentChar;
                Peek(out currentChar);

                VisualBasicAstToken token;

                if (currentChar == '\'')
                {
                    var node = ReadSingleLineComment();
                    token = node as VisualBasicAstToken;
                    if (token == null)
                    {
                        SpecialBag.SpecialNodes.Add(node);
                        continue; 
                    }
                }
                else if (char.IsDigit(currentChar))
                {
                    token = ReadNumberToken();
                }
                else if (IsWordElement(currentChar))
                {
                    token = ReadWordToken();
                    VisualBasicAstTokenCode keywordCode;
                    if (VisualBasicAstToken.KeywordMapping.TryGetValue(token.Value, out keywordCode))
                    {
                        token.Code = keywordCode;

                        switch (keywordCode)
                        {
                            case TRUE:
                                token.UserData["InterpretedValue"] = true;
                                break;
                            case FALSE:
                                token.UserData["InterpretedValue"] = false;
                                break;
                        }
                    }
                }
                else if (currentChar == '\'' || currentChar == '"')
                {
                    token = ReadStringToken();
                }
                else
                {
                    var start = Location;
                    StartReadBuffer();
                    var code = TokenizeCurrentSymbol();
                    var end = Location;

                    token = new VisualBasicAstToken(code, EndReadBuffer().ToString(), new TextRange(start, end));
                }

                return token;
            }
        }
        protected VisualBasicAstToken ReadNumberToken()
        {
            TextRange range;
            bool hasSuffix = false;
            bool hasDecimalSpecifier = false;

            string token = ReadCharacters(x =>
            {
                if (char.IsLetter(x))
                {
                    hasSuffix = true;
                    return true;
                }

                if (char.IsDigit(x))
                    return !hasSuffix;

                if (x == '.')
                {
                    if (hasDecimalSpecifier)
                        throw new Exception("Too many decimal specifiers in number.");
                    hasDecimalSpecifier = true;
                    return true;
                }

                return false;

            }, out range);
            
            var astToken = new VisualBasicAstToken(LITERAL, token, range);
            astToken.UserData["InterpretedValue"] = VisualBasicLanguage.Instance.NumberFormatter.EvaluateFormattedNumber(token);
            return astToken;
        }