/
Parser.Assert.cs
101 lines (93 loc) · 4.1 KB
/
Parser.Assert.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
using System;
namespace Pidgin
{
public abstract partial class Parser<TToken, T>
{
/// <summary>
/// Creates a parser that fails if the value returned by the current parser fails to satisfy a predicate.
/// </summary>
/// <param name="predicate">The predicate to apply to the value returned by the current parser</param>
/// <returns>A parser that fails if the value returned by the current parser fails to satisfy <paramref name="predicate"/></returns>
public Parser<TToken, T> Assert(Func<T, bool> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
return Assert(predicate, "Assertion failed");
}
/// <summary>
/// Creates a parser that fails if the value returned by the current parser fails to satisfy a predicate.
/// </summary>
/// <param name="predicate">The predicate to apply to the value returned by the current parser</param>
/// <param name="message">A custom error message to return when the value returned by the current parser fails to satisfy the predicate</param>
/// <returns>A parser that fails if the value returned by the current parser fails to satisfy <paramref name="predicate"/></returns>
public Parser<TToken, T> Assert(Func<T, bool> predicate, string message)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
return Assert(predicate, _ => message);
}
/// <summary>
/// Creates a parser that fails if the value returned by the current parser fails to satisfy a predicate.
/// </summary>
/// <param name="predicate">The predicate to apply to the value returned by the current parser</param>
/// <param name="message">A function to produce a custom error message to return when the value returned by the current parser fails to satisfy the predicate</param>
/// <returns>A parser that fails if the value returned by the current parser fails to satisfy <paramref name="predicate"/></returns>
public Parser<TToken, T> Assert(Func<T, bool> predicate, Func<T, string> message)
{
if (predicate == null)
{
throw new ArgumentNullException(nameof(predicate));
}
if (message == null)
{
throw new ArgumentNullException(nameof(message));
}
return new AssertParser<TToken, T>(this, predicate, message);
}
}
internal sealed class AssertParser<TToken, T> : Parser<TToken, T>
{
private static readonly Expected<TToken> _expected
= new Expected<TToken>("result satisfying assertion");
private readonly Parser<TToken, T> _parser;
private readonly Func<T, bool> _predicate;
private readonly Func<T, string> _message;
public AssertParser(Parser<TToken, T> parser, Func<T, bool> predicate, Func<T, string> message)
{
_parser = parser;
_predicate = predicate;
_message = message;
}
internal sealed override InternalResult<T> Parse(ref ParseState<TToken> state)
{
state.BeginExpectedTran();
var result = _parser.Parse(ref state);
state.EndExpectedTran(!result.Success);
if (!result.Success)
{
return result;
}
var val = result.Value;
if (!_predicate(val))
{
state.Error = new InternalError<TToken>(
Maybe.Nothing<TToken>(),
false,
state.Location,
_message(val)
);
state.AddExpected(_expected);
return InternalResult.Failure<T>(result.ConsumedInput);
}
return result;
}
}
}