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