Skip to content

Commit

Permalink
#36 - Added support for NoMatchExceptions when IEnumerable matches ha…
Browse files Browse the repository at this point in the history
…ve no match
  • Loading branch information
DavidArno committed Jun 8, 2017
1 parent a257e8e commit cc402b6
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 12 deletions.
38 changes: 26 additions & 12 deletions src/SuccincT/PatternMatchers/ConsFuncMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ internal class ConsFuncMatcher<T, TResult> : IConsFuncMatcher<T, TResult>,
IConsFuncConsHandler<T, TResult>,
IConsFuncConsWhereHandler<T, TResult>
{
private TResult _emptyValue;
private (bool supplied, TResult value) _emptyValue;
private Func<T, bool> _singleWhereFunc;
private Func<T, IEnumerable<T>, bool> _consWhereFunc;
private readonly List<(Func<T, bool> testFunc, Func<T, TResult> doFunc)> _singleTests;
private readonly List<(Func<T, IEnumerable<T>, bool> testFunc,
private readonly List<(Func<T, IEnumerable<T>, bool> testFunc,
Func<T, IEnumerable<T>, TResult> doFunc)> _simpleConsTests;
private readonly ConsNodeEnumerator<T> _enumerator;

Expand All @@ -31,16 +31,24 @@ internal ConsFuncMatcher(IEnumerable<T> collection)
IConsFuncSingleHandler<T, TResult> IConsFuncMatcher<T, TResult>.Single() => this;
IConsFuncConsHandler<T, TResult> IConsFuncMatcher<T, TResult>.Cons() => this;

TResult IConsFuncMatcher<T, TResult>.Result() =>
TryCons(_enumerator).Match().To<TResult>()
.Where((h, _) => !h.HasValue).Do(_emptyValue)
.Where((_, t) => t == null).Do((h, _) => SingleMatch(h.Value))
.Else((h, t) => ConsMatch(h.Value, t))
.Result();
TResult IConsFuncMatcher<T, TResult>.Result()
{
var simpleMatchData = TryCons(_enumerator);
if (!simpleMatchData.head.HasValue)
{
return _emptyValue.supplied
? _emptyValue.value
: throw new NoMatchException("No empty clause supplied");
}

return simpleMatchData.tail == null
? SingleMatch(simpleMatchData.head.Value)
: ConsMatch(simpleMatchData.head.Value, simpleMatchData.tail);
}

IConsFuncMatcher<T, TResult> IConsFuncNoneHandler<T, TResult>.Do(TResult value)
{
_emptyValue = value;
_emptyValue = (true, value);
return this;
}

Expand Down Expand Up @@ -98,7 +106,7 @@ IConsFuncSingleWhereHandler<T, TResult> IConsFuncSingleHandler<T, TResult>.Where
return this;
}

IConsFuncConsWhereHandler<T, TResult> IConsFuncConsHandler<T, TResult>.Where(Func<T, IEnumerable<T>,
IConsFuncConsWhereHandler<T, TResult> IConsFuncConsHandler<T, TResult>.Where(Func<T, IEnumerable<T>,
bool> testFunc)
{
_consWhereFunc = testFunc;
Expand All @@ -107,20 +115,26 @@ IConsFuncConsWhereHandler<T, TResult> IConsFuncConsHandler<T, TResult>.Where(Fun

private TResult SingleMatch(T head)
{
if (_singleTests.Count == 0) throw new NoMatchException("No single clause supplied.");

foreach (var (testFunc, doFunc) in _singleTests)
{
if (testFunc(head)) return doFunc(head);
}
return default(TResult);

throw new NoMatchException("No single clause matches the supplied value.");
}

private TResult ConsMatch(T head, IConsEnumerable<T> tail)
{
if (_simpleConsTests.Count == 0) throw new NoMatchException("No cons clause supplied.");

foreach (var (testFunc, doFunc) in _simpleConsTests)
{
if (testFunc(head, tail)) return doFunc(head, tail);
}
return default(TResult);

throw new NoMatchException("No cons clause matches the supplied value.");
}

private static (Option<T> head, ConsEnumerable<T> tail) TryCons(ConsNodeEnumerator<T> enumerator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ public void EmptyList_CanBeMatchedWithEmpty()
AreEqual(0, result);
}

[Test]
public void EmptyList_ThrowsExceptionWhenNoEmptyClauseSupplied()
{
var list = new List<int>();
Throws<NoMatchException>(() => list.Match().To<int>()
.Single().Do(0)
.Cons().Do(1)
.Result());
}

[Test]
public void SingleItemList_CanBeMatchedWithSingle()
{
Expand Down Expand Up @@ -75,6 +85,25 @@ public void SingleItemList_CanBeMatchedWhenWhereDoesntMatch()
IsFalse(result);
}

[Test]
public void SingleItemList_ThrowsExceptionWhenNoSingleClauseSupplied()
{
var list = new List<int> { 1 };
Throws<NoMatchException>(() => list.Match().To<int>()
.Empty().Do(0)
.Cons().Do(1)
.Result());
}

[Test]
public void SingleItemList_ThrowsExceptionWhenNoSingleClauseMatches()
{
var list = new List<int> { 1 };
Throws<NoMatchException>(() => list.Match().To<int>()
.Single().Where(x => x == 0).Do(0)
.Result());
}

[Test]
public void TwoItemList_CanBeMatchedWithCons()
{
Expand Down Expand Up @@ -118,5 +147,24 @@ public void MultiItemList_CanBeMatchedWithConsWithWhereUsingValue()
.Result();
AreEqual(1, result);
}

[Test]
public void MultiItemList_ThrowsExceptionWhenNoConsClauseSupplied()
{
var list = new List<int> { 1, 2, 3 };
Throws<NoMatchException>(() => list.Match().To<int>()
.Empty().Do(0)
.Single().Do(1)
.Result());
}

[Test]
public void MultiItemList_ThrowsExceptionWhenNoConsClauseMatches()
{
var list = new List<int> { 1, 2, 3 };
Throws<NoMatchException>(() => list.Match().To<int>()
.Cons().Where((x, y) => x == 0).Do(0)
.Result());
}
}
}

0 comments on commit cc402b6

Please sign in to comment.