private static TypeSpecifier ParseArraySpecifier(CharReader reader)
        {
            System.Diagnostics.Debug.Assert(reader.Peek() == '[');
            int rank = 1;

            // Consume the leading '['
            reader.Read();

            while (true)
            {
                int ch = reader.Read();
                switch (ch)
                {
                case ',':
                    rank++;
                    break;

                case ']':
                    return(TypeSpecifier.Array(rank));

                case '*':
                    int la1 = reader.Peek();
                    if (la1 != ',' && la1 != ']')
                    {
                        throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(la1 == -1 ? "EOS" : ((char)la1).ToString())}' at position {reader.Position}; expected one of ',', ']'.");
                    }
                    break;

                default:
                    throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)ch}' at position {reader.Position}; one of ',', ']', '*'.");
                }
            }
        }
        private static (string Namespace, List <string> NestedTypeName, IList <TypeIdentifier> GenericArguments, IList <TypeSpecifier> Specifiers) ParseFullName(CharReader reader, bool allowTrailingCharacters)
        {
            var namespaceTypeName = ParseNamespaceTypeName(reader, true);

            IList <TypeIdentifier> genericArguments;
            int la1 = reader.Peek(1);

            if (reader.Peek() == '[' && la1 != ',' && la1 != '*' && la1 != ']')
            {
                genericArguments = ParseGenericArguments(reader);
            }
            else
            {
                genericArguments = null;
            }

            IList <TypeSpecifier> spec = ParseRefPtrArrSpec(reader);

            if (!allowTrailingCharacters && reader.HasMore)
            {
                throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)reader.Peek()}' at position {reader.Position}; expected end-of-string.");
            }

            return(namespaceTypeName.Namespace, namespaceTypeName.NestedTypeName, genericArguments, spec);
        }
        private static IList <TypeSpecifier> ParseRefPtrArrSpec(CharReader reader)
        {
            List <TypeSpecifier> specifiers = null;
            int ch;

            while ((ch = reader.Peek()) != -1)
            {
                TypeSpecifier specifier;

                switch (ch)
                {
                case '[':
                    int la1 = reader.Peek(1);
                    if (la1 == '*' || la1 == ']' || la1 == ',')
                    {
                        specifier = ParseArraySpecifier(reader);
                    }
                    else
                    {
                        return(specifiers);
                    }
                    break;

                case '*':
                    specifier = TypeSpecifier.Pointer;
                    reader.Read();
                    break;

                case '&':
                    specifier = TypeSpecifier.Reference;
                    reader.Read();
                    break;

                case ',':
                case ']':
                    return(specifiers);

                default:
                    throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)ch}' at position {reader.Position}; one of '[', '*', '&', ',', ']'.");
                }

                if (specifiers == null)
                {
                    specifiers = new List <TypeSpecifier>();
                }

                specifiers.Add(specifier);
            }

            return(specifiers);
        }
        // ID ('.' ID)* ('+' ID)*
        private static (string Namespace, List <string> NestedTypeName) ParseNamespaceTypeName(CharReader reader, bool allowTrailingCharacters)
        {
            List <string> nestedTypeName   = new List <string>();
            StringBuilder namespaceBuilder = new StringBuilder();
            int           lastDelimiterPos = -1;

            // Parse namespace including root type name, stop at nested types.
            while (reader.HasMore && TryParseIdentifierInto(reader, namespaceBuilder))
            {
                if (reader.Peek() == '.')
                {
                    lastDelimiterPos = namespaceBuilder.Length;
                    namespaceBuilder.Append('.');
                    reader.Read();
                }
                else
                {
                    break;
                }
            }

            // Verify that we actually parsed something.
            if (namespaceBuilder.Length == 0)
            {
                throw new TypeNameParserException($"Failed to parse type name from \"{reader.Data}\"; Expected NamespaceTypeName, but none found.");
            }

            // The type name is the identifier following the last dot. Extract that from the namespaceBuilder.
            nestedTypeName.Add(namespaceBuilder.ToString(lastDelimiterPos + 1, namespaceBuilder.Length - lastDelimiterPos - 1));
            namespaceBuilder.Length = lastDelimiterPos == -1 ? 0 : lastDelimiterPos;


            // Now parse any NestedTypeNames
            while (reader.Peek() == '+')
            {
                // Consume the +
                reader.Read();

                nestedTypeName.Add(ParseIdentifier(reader));
            }

            if (!allowTrailingCharacters && reader.HasMore)
            {
                throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)reader.Peek()}' at position {reader.Position}; expected end-of-string.");
            }

            return((namespaceBuilder.Length == 0) ? null : namespaceBuilder.ToString(), nestedTypeName);
        }
        private static bool TryParseIdentifierInto(CharReader reader, StringBuilder target)
        {
            int startPos = reader.Position;
            int ch;

            while ((ch = reader.Peek()) != -1)
            {
                if (ch != '\\' && IsSpecialCharacter((char)ch))
                {
                    break;
                }

                reader.Read();

                if (ch == '\\' && reader.HasMore)
                {
                    target.Append('\\');
                    ch = reader.Read();
                }

                target.Append((char)ch);
            }

            return(reader.Position > startPos);
        }
        private static void ConsumeUnquotedValue(CharReader reader, StringBuilder target)
        {
            int ch;

            while ((ch = reader.Peek()) != -1 && ch != ',' && ch != ']' && !Char.IsWhiteSpace((char)ch))
            {
                target.Append((char)reader.Read());
            }
        }
        private static void SkipWhitespace(CharReader reader)
        {
            int ch;

            while ((ch = reader.Peek()) != -1 && Char.IsWhiteSpace((char)ch))
            {
                reader.Read();
            }
        }
        private static void ConsumeWhitespace(CharReader reader, StringBuilder target)
        {
            int ch;

            while ((ch = reader.Peek()) != -1 && Char.IsWhiteSpace((char)ch))
            {
                target.Append((char)reader.Read());
            }
        }
 private static void ConsumeAssemblyNamePropertyValue(CharReader reader, StringBuilder target)
 {
     if (reader.Peek() == '\"')
     {
         ConsumeQuotedValue(reader, target);
     }
     else
     {
         ConsumeUnquotedValue(reader, target);
     }
 }
        private static int ConsumeAssemblyName(CharReader reader, StringBuilder target)
        {
            int pos = reader.Position;
            int ch;

            while ((ch = reader.Peek()) != -1 && ch != ',' && ch != ']')
            {
                target.Append((char)reader.Read());
            }
            return(reader.Position - pos);
        }
 private void ReadCgTrivia(List <PretokenizedSyntaxTrivia> target, string endText, SyntaxKind triviaKind)
 {
     while (_charReader.Current != '\0')
     {
         var shouldBreak = true;
         for (var i = 0; i < endText.Length; i++)
         {
             if (_charReader.Peek(i) != endText[i])
             {
                 shouldBreak = false;
                 break;
             }
         }
         if (shouldBreak)
         {
             break;
         }
         NextChar();
     }
     AddTrivia(target, triviaKind);
 }
        private static IReadOnlyList <string> ParseNestedTypeName(CharReader reader)
        {
            List <string> result = new List <string>();

            result.Add(ParseIdentifier(reader));

            while (reader.Peek() == '+')
            {
                result.Add(ParseIdentifier(reader));
            }

            return(result);
        }
        private static void ConsumeAssemblyNameProperties(CharReader reader, StringBuilder assemblyName)
        {
            ConsumeWhitespace(reader, assemblyName);
            while (ConsumeAssemblyNamePropertyName(reader, assemblyName))
            {
                ConsumeWhitespace(reader, assemblyName);
                if (reader.Peek() != '=')
                {
                    throw new ArgumentException($"Invalid type name; Missing value for assembly name property.");
                }
                assemblyName.Append((char)reader.Read()); // Consume the equal sign.
                ConsumeAssemblyNamePropertyValue(reader, assemblyName);
                ConsumeWhitespace(reader, assemblyName);
                if (reader.Peek() != ',')
                {
                    break;
                }

                // Consume the comma.
                assemblyName.Append((char)reader.Read());
            }
        }
        private static bool ConsumeAssemblyNamePropertyName(CharReader reader, StringBuilder target)
        {
            int initialLength = target.Length;

            ConsumeWhitespace(reader, target);
            int ch;

            while ((ch = reader.Peek()) != -1 && ch != '=' && !Char.IsWhiteSpace((char)ch) && ch != ',')
            {
                target.Append((char)reader.Read());
            }

            return(target.Length > initialLength);
        }
        private static IList <TypeIdentifier> ParseGenericArguments(CharReader reader)
        {
            List <TypeIdentifier> args = new List <TypeIdentifier>();

            if (reader.Peek() == '[')
            {
                do
                {
                    reader.Read();
                    bool fullyQualified = false;
                    if (reader.Peek() == '[')
                    {
                        fullyQualified = true;
                        reader.Read();
                    }

                    args.Add(ParseTypeIdentifier(reader, fullyQualified));


                    if (fullyQualified == true)
                    {
                        if (reader.Peek() == ']')
                        {
                            reader.Read();
                        }
                        else
                        {
                            throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)reader.Peek()}' at position {reader.Position}; expected ']'.");
                        }
                    }
                }while (reader.Peek() == ',');

                reader.Read(); // Consume closing ']'
            }
            return(args);
        }
        private static AssemblyName ParseAssemblyName(CharReader reader)
        {
            StringBuilder assemblyName = new StringBuilder();

            if (ConsumeAssemblyName(reader, assemblyName) == 0)
            {
                throw new ArgumentException("Invalid type name; Expected assembly name.");
            }

            ConsumeWhitespace(reader, assemblyName);

            if (reader.Peek() == ',')
            {
                assemblyName.Append((char)reader.Read());
                ConsumeWhitespace(reader, assemblyName);
                ConsumeAssemblyNameProperties(reader, assemblyName);
            }

            return(new AssemblyName(assemblyName.ToString()));
        }
        private static void ConsumeQuotedValue(CharReader reader, StringBuilder target)
        {
            target.Append((char)reader.Read()); // Leading quote

            int ch;

            while ((ch = reader.Peek()) != -1)
            {
                target.Append((char)reader.Read());
                if (ch == '\"')
                {
                    break;
                }
            }

            if (ch != '\"')
            {
                throw new ArgumentException("Invalid type name; Missing closing quote in assembly name property value.");
            }
        }
        private static (string Namespace, List <string> NestedTypeName, IList <TypeIdentifier> GenericArguments, IList <TypeSpecifier> Specifiers, AssemblyName AssemblyName) ParseAssemblyQualifiedName(CharReader reader, bool allowTrailingCharacters)
        {
            var fullName = ParseFullName(reader, true);

            AssemblyName assemblyName = null;

            if (reader.Peek() == ',')
            {
                reader.Read();
                SkipWhitespace(reader);
                assemblyName = ParseAssemblyName(reader);
            }

            if (!allowTrailingCharacters && reader.HasMore)
            {
                throw new TypeNameParserException($"Invalid type name \"{reader.Data}\"; Unexpected character '{(char)reader.Peek()}' at position {reader.Position}; expected end-of-string.");
            }

            return(fullName.Namespace, fullName.NestedTypeName, fullName.GenericArguments, fullName.Specifiers, assemblyName);
        }
 private void ReadCgTrivia(List <PretokenizedSyntaxTrivia> target)
 {
     while (_charReader.Current != '\0')
     {
         if (_charReader.Peek(0) == 'E' &&
             _charReader.Peek(1) == 'N' &&
             _charReader.Peek(2) == 'D' &&
             _charReader.Peek(3) == 'C' &&
             _charReader.Peek(4) == 'G')
         {
             break;
         }
         NextChar();
     }
     AddTrivia(target, SyntaxKind.CgProgramTrivia);
 }
Example #20
0
        private void ReadTrivia(List <SyntaxNode> target, bool isTrailing)
        {
            var onlyWhitespaceOnLine = !isTrailing;

            while (true)
            {
                switch (_charReader.Current)
                {
                case '\n':
                case '\r':
                {
                    ReadEndOfLine();
                    AddTrivia(target, SyntaxKind.EndOfLineTrivia);
                    if (isTrailing)
                    {
                        return;
                    }
                    onlyWhitespaceOnLine = true;
                }
                break;

                case '/':
                    if (_charReader.Peek() == '/')
                    {
                        ReadSinglelineComment();
                        AddTrivia(target, SyntaxKind.SingleLineCommentTrivia);
                        onlyWhitespaceOnLine = false;
                    }
                    else if (_charReader.Peek() == '*')
                    {
                        ReadMultilineComment();
                        AddTrivia(target, SyntaxKind.MultiLineCommentTrivia);
                        onlyWhitespaceOnLine = false;
                    }
                    else
                    {
                        return;
                    }
                    break;

                case '#':
                    var shouldContinue = LexDirectiveAndExcludedTrivia(isTrailing || !onlyWhitespaceOnLine, target);
                    if (!shouldContinue)
                    {
                        return;
                    }
                    break;

                case '\\':
                    if (_charReader.Peek() != '\r' && _charReader.Peek() != '\n')
                    {
                        goto default;
                    }
                    _kind = SyntaxKind.BackslashNewlineTrivia;
                    NextChar();
                    ReadEndOfLine();
                    AddTrivia(target, SyntaxKind.BackslashNewlineTrivia);
                    break;

                default:
                    if (char.IsWhiteSpace(_charReader.Current))
                    {
                        ReadWhitespace();
                        AddTrivia(target, SyntaxKind.WhitespaceTrivia);
                    }
                    else
                    {
                        return;
                    }
                    break;
                }
            }
        }