private TypeName(string s, ref int index) { try { var startIndex = index; var nameStartIndex = startIndex; var nameEndIndex = (int?)null; var assemblyDescriptionStartIndex = (int?)null; var assemblyDescriptionEndIndex = (int?)null; var hasGroupingBracket = false; var state = State.Name; for (; index < s.Length; ++index) { var currentCharacter = s[index]; var nextCharacter = index + 1 < s.Length ? s[index + 1] : (char?)null; if (state == State.Name) { if (currentCharacter == '[') { if (index == startIndex) { // Skip type grouping bracket hasGroupingBracket = true; nameStartIndex++; } else if (nextCharacter == ']' || nextCharacter == ',') { // Square bracket delimits an array state = State.Array; } else { // Square bracket delimits the generic argument list nameEndIndex = index; state = State.Generics; } } else if (currentCharacter == ']') { if (hasGroupingBracket) { // We finished the current grouping, break out break; } } else if (currentCharacter == ',') { // We're entering assembly description state = State.Assembly; assemblyDescriptionStartIndex = index + 1; if (nameEndIndex == null) { nameEndIndex = index; } } } else if (state == State.Array) { if (currentCharacter == ']') { state = State.Name; } } else if (state == State.Generics) { if (currentCharacter == ']') { state = State.Name; } else if (currentCharacter == ',' || currentCharacter == ' ') { // Generic delimiters } else { GenericParameters.Add(new TypeName(s, ref index)); } } else if (state == State.Assembly) { if (currentCharacter == ']') { if (hasGroupingBracket) { // We finished the current grouping, break out assemblyDescriptionEndIndex = index; break; } } } } if (nameEndIndex == null) { nameEndIndex = s.Length; } if (assemblyDescriptionEndIndex == null) { assemblyDescriptionEndIndex = s.Length; } Name = s.Substring(nameStartIndex, nameEndIndex.Value - nameStartIndex); if (Name.Contains('+')) { var nestedNames = Name.Split('+'); foreach (var nestedName in nestedNames) { nestedName.PartsAround('`', out var name, out var genericarity); names.Add(name); if (genericarity != null) { genericarities.Add(int.Parse(genericarity)); } else { genericarities.Add(0); } } } else { Name.PartsAround('`', out var name, out var genericarity); names.Add(name); if (genericarity != null) { genericarities.Add(int.Parse(genericarity)); } else { genericarities.Add(0); } } if (assemblyDescriptionStartIndex != null) { AssemblyDescription = s.Substring(assemblyDescriptionStartIndex.Value, assemblyDescriptionEndIndex.Value - assemblyDescriptionStartIndex.Value); var parts = AssemblyDescription.Split(',') .Select(x => x.Trim()) .ToList(); AssemblyVersion = LookForPairThenRemove(parts, "Version"); AssemblyCulture = LookForPairThenRemove(parts, "Culture"); AssemblyPublicKeyToken = LookForPairThenRemove(parts, "PublicKeyToken"); if (parts.Count > 0) { AssemblyName = parts[0]; } } } catch (Exception ex) { throw new FormatException($"Failed to parse type name: {s}", ex); } }
public ParsedAssemblyQualifiedName(string AssemblyQualifiedName) { var typeNameLength = AssemblyQualifiedName.Length; var hasAssemblyDescription = false; var rootBlock = new Block(); { var depth = 0; var currentBlock = rootBlock; for (var index = 0; index < AssemblyQualifiedName.Length; ++index) { var c = AssemblyQualifiedName[index]; if (c == '[') { if (AssemblyQualifiedName[index + 1] == ']') // Array type // TODO (LAZLO): This won't detect multidimensional array, but FS can't handle them anyway { index++; } else { if (depth == 0) { typeNameLength = index; } ++depth; var innerBlock = new Block { startIndex = index + 1, level = depth, parentBlock = currentBlock }; currentBlock.innerBlocks.Add(innerBlock); currentBlock = innerBlock; } } else if (c == ']') { currentBlock.endIndex = index - 1; if (AssemblyQualifiedName[currentBlock.startIndex] != '[') { currentBlock.parsedAssemblyQualifiedName = new ParsedAssemblyQualifiedName(AssemblyQualifiedName.Substring(currentBlock.startIndex, index - currentBlock.startIndex)); if (depth == 2) { GenericParameters.Add(currentBlock.parsedAssemblyQualifiedName); } } currentBlock = currentBlock.parentBlock; --depth; } else if (depth == 0 && c == ',') { typeNameLength = index; hasAssemblyDescription = true; break; } } } TypeName = AssemblyQualifiedName.Substring(0, typeNameLength); var tickIndex = TypeName.IndexOf('`'); if (tickIndex >= 0) { GenericParameterCount = int.Parse(TypeName.Substring(tickIndex + 1)); TypeName = TypeName.Substring(0, tickIndex); } if (hasAssemblyDescription) { AssemblyDescriptionString = AssemblyQualifiedName.Substring(typeNameLength + 2); var parts = AssemblyDescriptionString.Split(',') .Select(x => x.Trim()) .ToList(); Version = LookForPairThenRemove(parts, "Version"); Culture = LookForPairThenRemove(parts, "Culture"); PublicKeyToken = LookForPairThenRemove(parts, "PublicKeyToken"); if (parts.Count > 0) { ShortAssemblyName = parts[0]; } } }