namespace Sprache { using System; using System.Collections.Generic; using UniLinq; partial class Parse { /// /// /// /// /// /// /// /// /// public static Parser> DelimitedBy(this Parser parser, Parser delimiter) { return DelimitedBy(parser, delimiter, null, null); } /// /// /// /// /// /// /// /// /// /// /// public static Parser> DelimitedBy(this Parser parser, Parser delimiter, int? minimumCount, int? maximumCount) { if (parser == null) throw new ArgumentNullException(nameof(parser)); if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); return from head in parser.Once() from tail in (from separator in delimiter from item in parser select item).Repeat(minimumCount - 1, maximumCount - 1) select head.Concat(tail); } /// /// Fails on the first itemParser failure, if it reads at least one character. /// /// /// /// /// /// /// public static Parser> XDelimitedBy(this Parser itemParser, Parser delimiter) { if (itemParser == null) throw new ArgumentNullException(nameof(itemParser)); if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); return from head in itemParser.Once() from tail in (from separator in delimiter from item in itemParser select item).XMany() select head.Concat(tail); } /// /// /// /// /// /// /// /// public static Parser> Repeat(this Parser parser, int count) { return Repeat(parser, count, count); } /// /// /// /// /// /// /// /// /// public static Parser> Repeat(this Parser parser, int? minimumCount, int? maximumCount) { if (parser == null) throw new ArgumentNullException(nameof(parser)); return i => { var remainder = i; var result = new List(); var count = 0; var r = parser(remainder); while (r.WasSuccessful && (maximumCount == null || count < maximumCount.Value)) { count++; result.Add(r.Value); remainder = r.Remainder; r = parser(remainder); } if (minimumCount.HasValue && count < minimumCount.Value) { var what = r.Remainder.AtEnd ? "end of input" : r.Remainder.Current.ToString(); var msg = $"Unexpected '{what}'"; string exp; if (minimumCount == maximumCount) exp = $"'{StringExtensions.Join(", ", r.Expectations)}' {minimumCount.Value} times, but found {count}"; else if (maximumCount == null) exp = $"'{StringExtensions.Join(", ", r.Expectations)}' minimum {minimumCount.Value} times, but found {count}"; else exp = $"'{StringExtensions.Join(", ", r.Expectations)}' between {minimumCount.Value} and {maximumCount.Value} times, but found {count}"; return Result.Failure>(i, msg, new[] { exp }); } return Result.Success>(result, remainder); }; } /// /// /// /// /// /// /// /// /// /// /// public static Parser Contained(this Parser parser, Parser open, Parser close) { if (parser == null) throw new ArgumentNullException(nameof(parser)); if (open == null) throw new ArgumentNullException(nameof(open)); if (close == null) throw new ArgumentNullException(nameof(close)); return from o in open from item in parser from c in close select item; } } }