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;
}
}
}