<commit_before>package org.minimallycorrect.javatransformer.internal.util;

import lombok.experimental.UtilityClass;
import lombok.val;
import org.minimallycorrect.javatransformer.api.TransformationException;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

@UtilityClass
public class TypeUtil {
	public static List<String> splitTypes(final String signature, boolean isSignature) {
		if (signature == null)
			return null;

		val types = new ArrayList<String>();
		int pos = 0;
		while (pos < signature.length()) {
			val type = readType(signature, pos, isSignature);
			pos += type.length();
			types.add(type);
		}

		return types;
	}

	public static Stream<String> readTypes(String in, boolean isSignature) {
		return CollectionUtil.stream(new Supplier<String>() {
			int pos = 0;

			@Override
			public String get() {
				if (pos < in.length()) {
					String next = readType(in, pos, isSignature);
					pos += next.length();
					return next;
				}
				return null;
			}
		});
	}

	public static String readType(String in, int pos, boolean isSignature) {
		int startPos = pos;
		char c;
		String current = "";
		String name;
		while (pos < in.length())
			switch (c = in.charAt(pos++)) {
				case 'Z':
				case 'C':
				case 'B':
				case 'S':
				case 'I':
				case 'F':
				case 'J':
				case 'D':
				case 'V':
					return current + c;

				case '[':
					current += '[';
					break;

				case 'T':
					int end = in.indexOf(';', pos);
					name = in.substring(pos, end);
					return current + 'T' + name + ';';
				case 'L':
					int start = pos;
					int genericCount = 0;
					while (pos < in.length())
						switch (in.charAt(pos++)) {
							case ';':
								if (genericCount > 0)
									break;
								name = in.substring(start, pos);
								return current + 'L' + name;
							case '<':
								if (!isSignature)
									throw new TransformationException("Illegal character '<' in descriptor: " + in);
								genericCount++;
								break;
							case '>':
								genericCount--;
								break;
						}
					break;
				default:
					throw new TransformationException("Unexpected character '" + c + "' in signature/descriptor '" + in + "' Searched section '" + in.substring(startPos, pos) + "'");
			}

		throw new StringIndexOutOfBoundsException(pos);
	}<commit_msg>TypeUtil.readTypes now gives more detailed error if the end of the input string is reached unexpectedly<commit_after>package org.minimallycorrect.javatransformer.internal.util;

import lombok.experimental.UtilityClass;
import lombok.val;
import org.minimallycorrect.javatransformer.api.TransformationException;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

@UtilityClass
public class TypeUtil {
	public static List<String> splitTypes(final String signature, boolean isSignature) {
		if (signature == null)
			return null;

		val types = new ArrayList<String>();
		int pos = 0;
		while (pos < signature.length()) {
			val type = readType(signature, pos, isSignature);
			pos += type.length();
			types.add(type);
		}

		return types;
	}

	public static Stream<String> readTypes(String in, boolean isSignature) {
		return CollectionUtil.stream(new Supplier<String>() {
			int pos = 0;

			@Override
			public String get() {
				if (pos < in.length()) {
					String next = readType(in, pos, isSignature);
					pos += next.length();
					return next;
				}
				return null;
			}
		});
	}

	public static String readType(String in, int pos, boolean isSignature) {
		int startPos = pos;
		char c;
		String current = "";
		String name;
		while (pos < in.length())
			switch (c = in.charAt(pos++)) {
				case 'Z':
				case 'C':
				case 'B':
				case 'S':
				case 'I':
				case 'F':
				case 'J':
				case 'D':
				case 'V':
					return current + c;

				case '[':
					current += '[';
					break;

				case 'T':
					int end = in.indexOf(';', pos);
					name = in.substring(pos, end);
					return current + 'T' + name + ';';
				case 'L':
					int start = pos;
					int genericCount = 0;
					while (pos < in.length())
						switch (in.charAt(pos++)) {
							case ';':
								if (genericCount > 0)
									break;
								name = in.substring(start, pos);
								return current + 'L' + name;
							case '<':
								if (!isSignature)
									throw new TransformationException("Illegal character '<' in descriptor: " + in);
								genericCount++;
								break;
							case '>':
								genericCount--;
								break;
						}
					break;
				default:
					throw new TransformationException("Unexpected character '" + c + "' in signature/descriptor '" + in + "' Searched section '" + in.substring(startPos, pos) + "'");
			}

		throw new StringIndexOutOfBoundsException("Reached " + pos + " in " + in);
	}
{'fraction_non_alphanumeric': 0.13849715849294886, 'fraction_numerical': 0.0016838560303094085, 'mean_word_length': 2.706708268330733, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7394724', 'n_tokens_mistral': 1963, 'n_tokens_neox': 1460, 'n_words': 418}