<commit_before>namespace Faithlife.Parsing;

public static partial class Parser
{
	/// <summary>
	/// Parses a single character if the specified predicate returns true.
	/// </summary>
	public static IParser<char> Char(Func<char, bool> test) => new FuncCharParser(test);

	private abstract class CharParser : Parser<char>
	{
		public override char TryParse(bool skip, ref TextPosition position, out bool success)
		{
			if (!position.IsAtEnd())
			{
				var current = position.GetCurrentChar();
				if (IsMatch(current))
				{
					success = true;
					position = position.WithNextIndex();
					return current;
				}
			}

			success = false;
			return default;
		}

		protected abstract bool IsMatch(char ch);
	}

	private sealed class FuncCharParser : CharParser
	{
		public FuncCharParser(Func<char, bool> test) => m_test = test;
		protected override bool IsMatch(char ch) => m_test(ch);
		private readonly Func<char, bool> m_test;
	}

	/// <summary>
	/// Parses the specified character.
	/// </summary>
	public static IParser<char> Char(char ch) => new SpecificCharParser(ch);

	private sealed class SpecificCharParser : CharParser
	{
		public SpecificCharParser(char ch) => m_ch = ch;
		protected override bool IsMatch(char ch) => ch == m_ch;
		private readonly char m_ch;
	}

	/// <summary>
	/// Parses any character; i.e. only fails at the end of the text.
	/// </summary>
	public static readonly IParser<char> AnyChar = new AnyCharParser();

	private sealed class AnyCharParser : CharParser
	{
		protected override bool IsMatch(char ch) => true;
	}

	/// <summary>
	/// Parses any character except the specified character.
	/// </summary>
	public static IParser<char> AnyCharExcept(char ch) => new AnyCharExceptParser(ch);

	private sealed class AnyCharExceptParser : CharParser
	{
		public AnyCharExceptParser(char ch) => m_ch = ch;
		protected override bool IsMatch(char ch) => ch != m_ch;
		private readonly char m_ch;
	}

	/// <summary>
	/// Parses any digit (as determined by <see cref="char.IsDigit(char)" />).
	/// </summary>
	public static readonly IParser<char> Digit = new DigitParser();

	private sealed class DigitParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsDigit(ch);
	}

	/// <summary>
	/// Parses any letter (as determined by <see cref="char.IsLetter(char)" />).
	/// </summary>
	public static readonly IParser<char> Letter = new LetterParser();

	private sealed class LetterParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsLetter(ch);
	}

	/// <summary>
	/// Parses any letter or digit (as determined by <see cref="char.IsLetterOrDigit(char)" />).
	/// </summary>
	public static readonly IParser<char> LetterOrDigit = new LetterOrDigitParser();

	private sealed class LetterOrDigitParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsLetterOrDigit(ch);
	}

	/// <summary>
	/// Parses any whitespace character (as determined by <see cref="char.IsWhiteSpace(char)" />).
	/// </summary>
	public static readonly IParser<char> WhiteSpace = new WhiteSpaceParser();

	private sealed class WhiteSpaceParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsWhiteSpace(ch);
	}
}
<commit_msg>Work around XmlDocMarkdown bug.<commit_after>namespace Faithlife.Parsing;

public static partial class Parser
{
	/// <summary>
	/// Parses a single character if the specified predicate returns true.
	/// </summary>
	public static IParser<char> Char(Func<char, bool> test) => new FuncCharParser(test);

	private abstract class CharParser : Parser<char>
	{
		public override char TryParse(bool skip, ref TextPosition position, out bool success)
		{
			if (!position.IsAtEnd())
			{
				var current = position.GetCurrentChar();
				if (IsMatch(current))
				{
					success = true;
					position = position.WithNextIndex();
					return current;
				}
			}

			success = false;
			return default;
		}

		protected abstract bool IsMatch(char ch);
	}

	private sealed class FuncCharParser : CharParser
	{
		public FuncCharParser(Func<char, bool> test) => m_test = test;
		protected override bool IsMatch(char ch) => m_test(ch);
		private readonly Func<char, bool> m_test;
	}

	/// <summary>
	/// Parses the specified character.
	/// </summary>
	public static IParser<char> Char(char ch) => new SpecificCharParser(ch);

	private sealed class SpecificCharParser : CharParser
	{
		public SpecificCharParser(char ch) => m_ch = ch;
		protected override bool IsMatch(char ch) => ch == m_ch;
		private readonly char m_ch;
	}

	/// <summary>
	/// Parses any character; i.e. only fails at the end of the text.
	/// </summary>
	public static readonly IParser<char> AnyChar = new AnyCharParser();

	private sealed class AnyCharParser : CharParser
	{
		protected override bool IsMatch(char ch) => true;
	}

	/// <summary>
	/// Parses any character except the specified character.
	/// </summary>
	public static IParser<char> AnyCharExcept(char ch) => new AnyCharExceptParser(ch);

	private sealed class AnyCharExceptParser : CharParser
	{
		public AnyCharExceptParser(char ch) => m_ch = ch;
		protected override bool IsMatch(char ch) => ch != m_ch;
		private readonly char m_ch;
	}

	/// <summary>
	/// Parses any digit (as determined by <c>char.IsDigit</c>).
	/// </summary>
	public static readonly IParser<char> Digit = new DigitParser();

	private sealed class DigitParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsDigit(ch);
	}

	/// <summary>
	/// Parses any letter (as determined by <c>char.IsLetter</c>).
	/// </summary>
	public static readonly IParser<char> Letter = new LetterParser();

	private sealed class LetterParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsLetter(ch);
	}

	/// <summary>
	/// Parses any letter or digit (as determined by <c>char.IsLetterOrDigit</c>).
	/// </summary>
	public static readonly IParser<char> LetterOrDigit = new LetterOrDigitParser();

	private sealed class LetterOrDigitParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsLetterOrDigit(ch);
	}

	/// <summary>
	/// Parses any whitespace character (as determined by <c>char.IsWhiteSpace</c>).
	/// </summary>
	public static readonly IParser<char> WhiteSpace = new WhiteSpaceParser();

	private sealed class WhiteSpaceParser : CharParser
	{
		protected override bool IsMatch(char ch) => char.IsWhiteSpace(ch);
	}
}

{'fraction_non_alphanumeric': 0.11966750313676286, 'fraction_numerical': 0.0, 'mean_word_length': 3.8274034822104466, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 99, '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': '349631', 'n_tokens_mistral': 2082, 'n_tokens_neox': 1918, 'n_words': 609}