<commit_before>﻿using emd.cs.Expressions;
using emd.cs.Nodes;
using emd.cs.Utils;
using pegleg.cs;
using pegleg.cs.Unicode;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace emd.cs.Grammar {
	public partial class EmdGrammar {
		#region Inline Rules

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		BlockInlinesOptional =
			Sequence(
				Optional(Reference(() => BlockWhitespaceOrComments)),
				AtLeast(0, Reference(() => Inline)),
				Optional(Reference(() => BlockWhitespaceOrComments)),
				match => match.Product.Of2);

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		BlockInlinesRequired =
			Sequence(
				Optional(Reference(() => BlockWhitespaceOrComments)),
				AtLeast(1, Reference(() => Inline)),
				Optional(Reference(() => BlockWhitespaceOrComments)),
				match => match.Product.Of2);

		public static readonly IParsingExpression<IInlineNode>
		Inline =
			Named(() => Inline,
				ChoiceOrdered<IInlineNode>(
					ChoiceUnordered<IInlineNode>(
						Reference(() => Text),
						ChoiceOrdered<IInlineNode>(
							Reference(() => LineBreak),
							Reference(() => Space)),
						ChoiceOrdered<IInlineNode>(
							Reference(() => Strong),
							Reference(() => Emphasis)),
						Reference(() => Quoted),
						Reference(() => Link),
						Reference(() => AutoLink),
						Reference(() => Entity),
						Reference(() => Code),
						Reference(() => InlineExpression)),
					Reference(() => Symbol)));

		#region AutoLink

		public static readonly IParsingExpression<AutoLinkNode>
		AutoLink =
			Named(() => AutoLink,
				Sequence(
					Literal("<"),
					Reference(() => SpaceChars),
					Reference(() => IriLiteral),
					Reference(() => SpaceChars),
					Literal(">"),
					Optional(
						Reference(() => ArgumentList),
						match => match.Product,
						noMatch => new IExpression[0]),
					match => new AutoLinkNode(match.Product.Of3, match.Product.Of6.ToArray(), match.SourceRange)));

		#endregion

		#region Link

		public static readonly IParsingExpression<LinkNode>
		Link =
			Named(() => Link,
				Sequence(
					Reference(() => Label),
					Optional(Reference(() => ReferenceLabel)),
					Optional(Reference(() => ArgumentList, match => match.Product.ToArray())),
					match => new LinkNode(match.Product.Of1.ToArray(), match.Product.Of2, match.Product.Of3, match.SourceRange)));

		public static readonly IParsingExpression<ReferenceId>
		ReferenceLabel =
			Named(() => ReferenceLabel,
				Sequence(
					Literal("["),
					AtLeast(0, 
						Sequence(
							NotAhead(GraphemeIn(']', '\n', '\r')),
							Reference(() => UnicodeCharacter)),
						match => match.String),
					Literal("]"),
					match => ReferenceId.FromText(match.Product.Of2)));

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		Label =
			Named(() => Label,
				Sequence(
					Literal("["),
					AtLeast(0, Sequence(NotAhead(Literal("]")), Reference(() => Inline), match => match.Product.Of2)),
					Literal("]"),
					match => match.Product.Of2));

		#endregion

		public static readonly IParsingExpression<InlineExpressionNode>
		InlineExpression =
			Named(() => InlineExpression,
				Sequence(
					Ahead(Literal("@")),
					Reference(() => LeftHandSideExpression),
					Optional(Literal(";")),
					match => new InlineExpressionNode(match.Product.Of2, match.SourceRange)));

		public static readonly IParsingExpression<StrongNode>
		Strong =
			Named(() => Strong,
				Sequence(
					Reference(() => StrongDelimiter),
					AtLeast(1,
						Sequence(
							NotAhead(Reference(() => StrongDelimiter)),
							Reference(() => Inline),
							match => match.Product.Of2)),
					Reference(() => StrongDelimiter),
					match => new StrongNode(match.Product.Of2.ToArray(), match.SourceRange)));

		public static readonly IParsingExpression<Nil>
		StrongDelimiter = Literal("**");

		public static readonly IParsingExpression<EmphasisNode>
		Emphasis =
			Named(() => Emphasis,
				Sequence(
					Reference(() => EmphasisDelimiter),
					AtLeast(1,
						ChoiceOrdered(
							Sequence(
								NotAhead(Reference(() => EmphasisDelimiter)),
								Reference(() => Inline),
								match => match.Product.Of2),
							Reference(() => Strong))),
					Reference(() => EmphasisDelimiter),
					match => new EmphasisNode(match.Product.Of2.ToArray(), match.SourceRange)));

		public static readonly IParsingExpression<Nil>
		EmphasisDelimiter = Literal("*");

		#region Quoted

		private static readonly IParsingExpression<QuotedNode>
		singleQuoted =
			Sequence(
				Literal("'"),
				AtLeast(0, Sequence(NotAhead(Literal("'")), Reference(() => Inline), match => match.Product.Of2)),
				Literal("'"),
				match => new QuotedNode(QuoteType.Single, match.Product.Of2.ToArray(), match.SourceRange));<commit_msg>Refactor Emphasis grammar to template method<commit_after>﻿using emd.cs.Expressions;
using emd.cs.Nodes;
using emd.cs.Utils;
using pegleg.cs;
using pegleg.cs.Unicode;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace emd.cs.Grammar {
	public partial class EmdGrammar {
		#region Inline Rules

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		BlockInlinesOptional =
			Sequence(
				Optional(Reference(() => BlockWhitespaceOrComments)),
				AtLeast(0, Reference(() => Inline)),
				Optional(Reference(() => BlockWhitespaceOrComments)),
				match => match.Product.Of2);

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		BlockInlinesRequired =
			Sequence(
				Optional(Reference(() => BlockWhitespaceOrComments)),
				AtLeast(1, Reference(() => Inline)),
				Optional(Reference(() => BlockWhitespaceOrComments)),
				match => match.Product.Of2);

		public static readonly IParsingExpression<IInlineNode>
		Inline =
			Named(() => Inline,
				ChoiceOrdered<IInlineNode>(
					ChoiceUnordered<IInlineNode>(
						Reference(() => Text),
						ChoiceOrdered<IInlineNode>(
							Reference(() => LineBreak),
							Reference(() => Space)),
						ChoiceOrdered<IInlineNode>(
							Reference(() => Strong),
							Reference(() => Emphasis)),
						Reference(() => Quoted),
						Reference(() => Link),
						Reference(() => AutoLink),
						Reference(() => Entity),
						Reference(() => Code),
						Reference(() => InlineExpression)),
					Reference(() => Symbol)));

		#region AutoLink

		public static readonly IParsingExpression<AutoLinkNode>
		AutoLink =
			Named(() => AutoLink,
				Sequence(
					Literal("<"),
					Reference(() => SpaceChars),
					Reference(() => IriLiteral),
					Reference(() => SpaceChars),
					Literal(">"),
					Optional(
						Reference(() => ArgumentList),
						match => match.Product,
						noMatch => new IExpression[0]),
					match => new AutoLinkNode(match.Product.Of3, match.Product.Of6.ToArray(), match.SourceRange)));

		#endregion

		#region Link

		public static readonly IParsingExpression<LinkNode>
		Link =
			Named(() => Link,
				Sequence(
					Reference(() => Label),
					Optional(Reference(() => ReferenceLabel)),
					Optional(Reference(() => ArgumentList, match => match.Product.ToArray())),
					match => new LinkNode(match.Product.Of1.ToArray(), match.Product.Of2, match.Product.Of3, match.SourceRange)));

		public static readonly IParsingExpression<ReferenceId>
		ReferenceLabel =
			Named(() => ReferenceLabel,
				Sequence(
					Literal("["),
					AtLeast(0, 
						Sequence(
							NotAhead(GraphemeIn(']', '\n', '\r')),
							Reference(() => UnicodeCharacter)),
						match => match.String),
					Literal("]"),
					match => ReferenceId.FromText(match.Product.Of2)));

		public static readonly IParsingExpression<IEnumerable<IInlineNode>>
		Label =
			Named(() => Label,
				Sequence(
					Literal("["),
					AtLeast(0, Sequence(NotAhead(Literal("]")), Reference(() => Inline), match => match.Product.Of2)),
					Literal("]"),
					match => match.Product.Of2));

		#endregion

		public static readonly IParsingExpression<InlineExpressionNode>
		InlineExpression =
			Named(() => InlineExpression,
				Sequence(
					Ahead(Literal("@")),
					Reference(() => LeftHandSideExpression),
					Optional(Literal(";")),
					match => new InlineExpressionNode(match.Product.Of2, match.SourceRange)));

		public static readonly IParsingExpression<StrongNode>
		Strong =
			Named(() => Strong,
				Sequence(
					Reference(() => StrongDelimiter),
					AtLeast(1,
						Sequence(
							NotAhead(Reference(() => StrongDelimiter)),
							Reference(() => Inline),
							match => match.Product.Of2)),
					Reference(() => StrongDelimiter),
					match => new StrongNode(match.Product.Of2.ToArray(), match.SourceRange)));

		public static readonly IParsingExpression<Nil>
		StrongDelimiter = Literal("**");

		public static readonly IParsingExpression<EmphasisNode>
		Emphasis =
			Named(() => Emphasis,
				TEmphasis(
					Reference(() => Inline),
					Reference(() => Strong)));

		public static IParsingExpression<EmphasisNode> TEmphasis(IParsingExpression<IInlineNode> recurse, IParsingExpression<IInlineNode> recurseStrong) {
			return Sequence(
				Reference(() => EmphasisDelimiter),
				AtLeast(1,
					ChoiceOrdered(
						Sequence(
							NotAhead(Reference(() => EmphasisDelimiter)),
							recurse,
							match => match.Product.Of2),
						recurseStrong)),
				Reference(() => EmphasisDelimiter),
				match => new EmphasisNode(match.Product.Of2.ToArray(), match.SourceRange));
		}

		public static readonly IParsingExpression<Nil>
		EmphasisDelimiter = Literal("*");

		#region Quoted

		private static readonly IParsingExpression<QuotedNode>
		singleQuoted =
			Sequence(
				Literal("'"),
				AtLeast(0, Sequence(NotAhead(Literal("'")), Reference(() => Inline), match => match.Product.Of2)),
				Literal("'"),
				match => new QuotedNode(QuoteType.Single, match.Product.Of2.ToArray(), match.SourceRange));
{'fraction_non_alphanumeric': 0.151766730788701, 'fraction_numerical': 0.005062265870203503, 'mean_word_length': 3.9022332506203474, 'pattern_counts': {'":': 0, '<': 48, '<?xml version=': 0, '>': 176, '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': '2483175', 'n_tokens_mistral': 3698, 'n_tokens_neox': 2820, 'n_words': 591}