Skip to content

Commit

Permalink
# 36 - Further cons pattern matching features added and some refactor…
Browse files Browse the repository at this point in the history
…ing.

Empty, Single and Cons (latter two with Where support) are now supported and the code has been refactored to be a lot less "hacky"
  • Loading branch information
DavidArno committed Jun 1, 2017
1 parent 03fa602 commit a257e8e
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 27 deletions.
8 changes: 5 additions & 3 deletions src/SuccincT/Functional/ConsEnumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private ConsEnumerable(IEnumerable<T> enumeration, IEnumerable<T> head) =>
}
};

private ConsEnumerable(ConsNode<T> node) =>
internal ConsEnumerable(ConsNode<T> node) =>
_node = new ConsNode<T>
{
State = StartNode,
Expand All @@ -57,6 +57,8 @@ private ConsEnumerable() =>

private IEnumerator<T> GetEnumerator() => new ConsNodeEnumerator<T>(_node);

internal ConsNodeEnumerator<T> GetTypedEnumerator() => new ConsNodeEnumerator<T>(_node);

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
Expand All @@ -68,7 +70,7 @@ IConsEnumerable<T> IConsEnumerable<T>.Cons(IEnumerable<T> head) =>

ConsResult<T> IConsEnumerable<T>.Cons()
{
using (var enumerator = GetEnumerator() as ConsNodeEnumerator<T>)
using (var enumerator = GetTypedEnumerator())
{
return enumerator.MoveNext()
? new ConsResult<T>(enumerator.Current, new ConsEnumerable<T>(enumerator.Node.Next))
Expand All @@ -78,7 +80,7 @@ ConsResult<T> IConsEnumerable<T>.Cons()

internal (T head, IConsEnumerable<T> tail) TupleCons()
{
using (var enumerator = GetEnumerator() as ConsNodeEnumerator<T>)
using (var enumerator = GetTypedEnumerator())
{
return enumerator.MoveNext()
? (enumerator.Current, new ConsEnumerable<T>(enumerator.Node.Next))
Expand Down
110 changes: 91 additions & 19 deletions src/SuccincT/PatternMatchers/ConsFuncMatcher.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
using System;
using SuccincT.Functional;
using SuccincT.Options;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SuccincT.PatternMatchers
{
internal class ConsFuncMatcher<T, TResult> : IConsFuncMatcher<T, TResult>,
IConsFuncNoneHandler<T, TResult>,
IConsFuncSingleHandler<T, TResult>,
IConsFuncSingleWhereHandler<T, TResult>
IConsFuncSingleWhereHandler<T, TResult>,
IConsFuncConsHandler<T, TResult>,
IConsFuncConsWhereHandler<T, TResult>
{
private readonly IEnumerable<T> _collection;
private TResult _emptyValue;
private Func<T, bool> _whereFunc;
private List<(Func<T, bool> testFunc, TResult value)> _singleTests;
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,
Func<T, IEnumerable<T>, TResult> doFunc)> _simpleConsTests;
private readonly ConsNodeEnumerator<T> _enumerator;

internal ConsFuncMatcher(IEnumerable<T> collection)
{
_collection = collection;
_singleTests = new List<(Func<T, bool> testFunc, TResult value)>();
_enumerator = new ConsEnumerable<T>(collection).GetTypedEnumerator();
_singleTests = new List<(Func<T, bool>, Func<T, TResult>)>();
_simpleConsTests = new List<(Func<T, IEnumerable<T>, bool>, Func<T, IEnumerable<T>, TResult>)>();
}

IConsFuncNoneHandler<T, TResult> IConsFuncMatcher<T, TResult>.Empty() => this;
IConsFuncSingleHandler<T, TResult> IConsFuncMatcher<T, TResult>.Single() => this;
IConsFuncConsHandler<T, TResult> IConsFuncMatcher<T, TResult>.Cons() => this;

TResult IConsFuncMatcher<T, TResult>.Result() => _collection.Count() == 0 ? _emptyValue : SingleMatch();
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();

IConsFuncMatcher<T, TResult> IConsFuncNoneHandler<T, TResult>.Do(TResult value)
{
Expand All @@ -33,31 +46,90 @@ IConsFuncMatcher<T, TResult> IConsFuncNoneHandler<T, TResult>.Do(TResult value)

IConsFuncMatcher<T, TResult> IConsFuncSingleHandler<T, TResult>.Do(TResult value)
{
_singleTests.Add((x => true, value));
_singleTests.Add((_ => true, _ => value));
return this;
}

IConsFuncSingleWhereHandler<T, TResult> IConsFuncSingleHandler<T, TResult>.Where(Func<T, bool> testFunc)
IConsFuncMatcher<T, TResult> IConsFuncSingleHandler<T, TResult>.Do(Func<T,TResult> doFunc)
{
_whereFunc = testFunc;
_singleTests.Add((_ => true, doFunc));
return this;
}

IConsFuncMatcher<T, TResult> IConsFuncSingleWhereHandler<T, TResult>.Do(TResult value)
{
_singleTests.Add((_whereFunc, value));
_singleTests.Add((_singleWhereFunc, _ => value));
return this;
}

IConsFuncMatcher<T, TResult> IConsFuncSingleWhereHandler<T, TResult>.Do(Func<T, TResult> doFunc)
{
_singleTests.Add((_singleWhereFunc, doFunc));
return this;
}
private TResult SingleMatch()

IConsFuncMatcher<T, TResult> IConsFuncConsHandler<T, TResult>.Do(Func<T, IEnumerable<T>, TResult> doFunc)
{
foreach(var (testFunc, value) in _singleTests)
_simpleConsTests.Add(((x, y) => true, doFunc));
return this;
}

IConsFuncMatcher<T, TResult> IConsFuncConsHandler<T, TResult>.Do(TResult value)
{
_simpleConsTests.Add(((x, y) => true, (x, y) => value));
return this;
}

IConsFuncMatcher<T, TResult> IConsFuncConsWhereHandler<T, TResult>.Do(Func<T, IEnumerable<T>, TResult> doFunc)
{
_simpleConsTests.Add((_consWhereFunc, doFunc));
return this;
}

IConsFuncMatcher<T, TResult> IConsFuncConsWhereHandler<T, TResult>.Do(TResult value)
{
_simpleConsTests.Add((_consWhereFunc, (x, y) => value));
return this;
}

IConsFuncSingleWhereHandler<T, TResult> IConsFuncSingleHandler<T, TResult>.Where(Func<T, bool> testFunc)
{
_singleWhereFunc = testFunc;
return this;
}

IConsFuncConsWhereHandler<T, TResult> IConsFuncConsHandler<T, TResult>.Where(Func<T, IEnumerable<T>,
bool> testFunc)
{
_consWhereFunc = testFunc;
return this;
}

private TResult SingleMatch(T head)
{
foreach (var (testFunc, doFunc) in _singleTests)
{
if (testFunc(_collection.First()))
{
return value;
}
if (testFunc(head)) return doFunc(head);
}
return default(TResult);
}

private TResult ConsMatch(T head, IConsEnumerable<T> tail)
{
foreach (var (testFunc, doFunc) in _simpleConsTests)
{
if (testFunc(head, tail)) return doFunc(head, tail);
}
return default(TResult);
}

private static (Option<T> head, ConsEnumerable<T> tail) TryCons(ConsNodeEnumerator<T> enumerator)
{
if (!enumerator.MoveNext()) return (Option<T>.None(), null);

var head = enumerator.Current;
var tailNode = enumerator.Node.Next;
return enumerator.MoveNext() ? (head, new ConsEnumerable<T>(tailNode)) : (head, null);
}
}
}
12 changes: 12 additions & 0 deletions src/SuccincT/PatternMatchers/IConsFuncConsHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;

namespace SuccincT.PatternMatchers
{
public interface IConsFuncConsHandler<T, TResult>
{
IConsFuncConsWhereHandler<T, TResult> Where(Func<T, IEnumerable<T>, bool> testFunc);
IConsFuncMatcher<T, TResult> Do(TResult value);
IConsFuncMatcher<T, TResult> Do(Func<T, IEnumerable<T>, TResult> doFunc);
}
}
11 changes: 11 additions & 0 deletions src/SuccincT/PatternMatchers/IConsFuncConsWhereHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;

namespace SuccincT.PatternMatchers
{
public interface IConsFuncConsWhereHandler<T, TResult>
{
IConsFuncMatcher<T, TResult> Do(TResult value);
IConsFuncMatcher<T, TResult> Do(Func<T, IEnumerable<T>, TResult> doFunc);
}
}
2 changes: 2 additions & 0 deletions src/SuccincT/PatternMatchers/IConsFuncMatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public interface IConsFuncMatcher<T, TResult>

IConsFuncSingleHandler<T, TResult> Single();

IConsFuncConsHandler<T, TResult> Cons();

TResult Result();
}
}
5 changes: 4 additions & 1 deletion src/SuccincT/PatternMatchers/IConsFuncSingleWhereHandler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
namespace SuccincT.PatternMatchers
using System;

namespace SuccincT.PatternMatchers
{
public interface IConsFuncSingleWhereHandler<T, TResult>
{
IConsFuncMatcher<T, TResult> Do(TResult value);
IConsFuncMatcher<T, TResult> Do(Func<T, TResult> doFunc);
}
}
4 changes: 2 additions & 2 deletions src/SuccincT/PatternMatchers/IConsSingleHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ namespace SuccincT.PatternMatchers
{
public interface IConsFuncSingleHandler<T, TResult>
{
IConsFuncMatcher<T, TResult> Do(TResult value);

IConsFuncSingleWhereHandler<T, TResult> Where(Func<T, bool> testFunc);
IConsFuncMatcher<T, TResult> Do(TResult value);
IConsFuncMatcher<T, TResult> Do(Func<T, TResult> doFunc);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using NUnit.Framework;
using NUnit.Framework;
using SuccincT.PatternMatchers;
using System.Collections.Generic;
using System.Linq;
using static NUnit.Framework.Assert;

namespace SuccincTTests.SuccincT.PatternMatchers
Expand Down Expand Up @@ -30,6 +31,17 @@ public void SingleItemList_CanBeMatchedWithSingle()
IsTrue(result);
}

[Test]
public void SingleItemList_CanBeMatchedWithSingleWithResultViaLambda()
{
var list = new List<int> { 1 };
var result = list.Match().To<bool>()
.Empty().Do(false)
.Single().Do(x => x == 1)
.Result();
IsTrue(result);
}

[Test]
public void SingleItemList_CanBeMatchedWithWhere()
{
Expand All @@ -41,6 +53,17 @@ public void SingleItemList_CanBeMatchedWithWhere()
IsTrue(result);
}

[Test]
public void SingleItemList_CanBeMatchedWithWhereWithResultViaLambda()
{
var list = new List<int> { 1 };
var result = list.Match().To<bool>()
.Single().Where(x => x == 1).Do(x => x == 1)
.Single().Do(false)
.Result();
IsTrue(result);
}

[Test]
public void SingleItemList_CanBeMatchedWhenWhereDoesntMatch()
{
Expand All @@ -51,5 +74,49 @@ public void SingleItemList_CanBeMatchedWhenWhereDoesntMatch()
.Result();
IsFalse(result);
}

[Test]
public void TwoItemList_CanBeMatchedWithCons()
{
var list = new List<int> { 1, 2 };
var result = list.Match().To<int>()
.Cons().Do((h, t) => h + t.First())
.Result();
AreEqual(3, result);
}

[Test]
public void TwoItemList_CanBeMatchedWithConsUsingValue()
{
var list = new List<int> { 1, 2 };
var result = list.Match().To<bool>()
.Empty().Do(false)
.Single().Do(false)
.Cons().Do(true)
.Result();
IsTrue(result);
}

[Test]
public void MultiItemList_CanBeMatchedWithConsWithWhere()
{
var list = new List<int> { 1, 2, 3, 4 };
var result = list.Match().To<int>()
.Cons().Where((h, t) => t.Count() == 3).Do((x, y) => 1)
.Cons().Do(2)
.Result();
AreEqual(1, result);
}

[Test]
public void MultiItemList_CanBeMatchedWithConsWithWhereUsingValue()
{
var list = new List<int> { 1, 2, 3, 4 };
var result = list.Match().To<int>()
.Cons().Where((h, t) => t.Count() == 3).Do(1)
.Cons().Do(2)
.Result();
AreEqual(1, result);
}
}
}

0 comments on commit a257e8e

Please sign in to comment.