private static int ParseArraySpecifier(ref BufferReader s) { s.ConsumeCharacter(ArrayStartIndicator); var dimensions = 1; while (s.TryPeek(out var c) && c != ArrayEndIndicator) { s.ConsumeCharacter(ArrayDimensionIndicator); ++dimensions; } s.ConsumeCharacter(ArrayEndIndicator); return(dimensions); }
private static ReadOnlySpan <char> ParseTypeName(ref BufferReader s) { var start = s.Index; var typeName = ParseSpan(ref s, TypeNameDelimiters); var genericArityStart = -1; while (s.TryPeek(out char c)) { if (genericArityStart < 0 && c == GenericTypeIndicator) { genericArityStart = s.Index + 1; } else if (genericArityStart < 0 || !char.IsDigit(c)) { break; } s.ConsumeCharacter(c); } if (genericArityStart >= 0) { // The generic arity is additive, so that a generic class nested in a generic class has an arity // equal to the sum of specified arity values. For example, "C`1+N`2" has an arity of 3. var aritySlice = s.Input.Slice(genericArityStart, s.Index - genericArityStart); #if NETCOREAPP var arity = int.Parse(aritySlice); #else var arity = int.Parse(aritySlice.ToString()); #endif s.TotalGenericArity += arity; if (s.TotalGenericArity > MaxAllowedGenericArity) { ThrowGenericArityTooLarge(s.TotalGenericArity); } // Include the generic arity in the type name. typeName = s.Input.Slice(start, s.Index - start); } return(typeName); }
private static TypeSpec ParseInternal(ref ReadOnlySpan <char> input) { TypeSpec result; char c; BufferReader s = default; s.Input = input; // Read namespace and class name, including generic arity, which is a part of the class name. NamedTypeSpec named = null; while (true) { var typeName = ParseTypeName(ref s); named = new NamedTypeSpec(named, typeName.ToString(), s.TotalGenericArity); if (s.TryPeek(out c) && c == NestedTypeIndicator) { // Consume the nested type indicator, then loop to parse the nested type. s.ConsumeCharacter(NestedTypeIndicator); continue; } break; } // Parse generic type parameters if (s.TotalGenericArity > 0 && s.TryPeek(out c) && c == ArrayStartIndicator) { s.ConsumeCharacter(ArrayStartIndicator); var arguments = new TypeSpec[s.TotalGenericArity]; for (var i = 0; i < s.TotalGenericArity; i++) { if (i > 0) { s.ConsumeCharacter(ParameterSeparator); } // Parse the argument type s.ConsumeCharacter(ArrayStartIndicator); var remaining = s.Remaining; arguments[i] = ParseInternal(ref remaining); var consumed = s.Remaining.Length - remaining.Length; s.Consume(consumed); s.ConsumeCharacter(ArrayEndIndicator); } s.ConsumeCharacter(ArrayEndIndicator); result = new ConstructedGenericTypeSpec(named, arguments); } else { // This is not a constructed generic type result = named; } // Parse modifiers bool hadModifier; do { hadModifier = false; if (!s.TryPeek(out c)) { break; } switch (c) { case ArrayStartIndicator: var dimensions = ParseArraySpecifier(ref s); result = new ArrayTypeSpec(result, dimensions); hadModifier = true; break; case PointerIndicator: result = new PointerTypeSpec(result); s.ConsumeCharacter(PointerIndicator); hadModifier = true; break; case ReferenceIndicator: result = new ReferenceTypeSpec(result); s.ConsumeCharacter(ReferenceIndicator); hadModifier = true; break; } } while (hadModifier); // Extract the assembly, if specified. if (s.TryPeek(out c) && c == AssemblyIndicator) { s.ConsumeCharacter(AssemblyIndicator); var assembly = ExtractAssemblySpec(ref s); result = new AssemblyQualifiedTypeSpec(result, assembly.ToString()); } input = s.Remaining; return(result); }