/
Parser.MapWithInput.cs
67 lines (56 loc) · 2.65 KB
/
Parser.MapWithInput.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
using System;
namespace Pidgin
{
public abstract partial class Parser<TToken, T>
{
/// <summary>
/// Returns a parser which runs the current parser and applies a selector function.
/// The selector function receives a <see cref="ReadOnlySpan{TToken}"/> as its first argument, and the result of the current parser as its second argument.
/// The <see cref="ReadOnlySpan{TToken}"/> represents the sequence of input tokens which were consumed by the parser.
///
/// This allows you to write "pattern"-style parsers which match a sequence of tokens and return a view of the part of the input stream which they matched.
///
/// This function is an alternative name for <see cref="Slice"/>.
/// </summary>
/// <param name="selector">
/// A selector function which computes a result of type <typeparamref name="U"/>.
/// The arguments of the selector function are a <see cref="ReadOnlySpan{TToken}"/> containing the sequence of input tokens which were consumed by this parser,
/// and the result of this parser.
/// </param>
/// <typeparam name="U">The result type</typeparam>
/// <returns>A parser which runs the current parser and applies a selector function.</returns>
public Parser<TToken, U> MapWithInput<U>(ReadOnlySpanFunc<TToken, T, U> selector)
{
if (selector == null)
{
throw new ArgumentNullException(nameof(selector));
}
return new MapWithInputParser<TToken, T, U>(this, selector);
}
}
internal class MapWithInputParser<TToken, T, U> : Parser<TToken, U>
{
private Parser<TToken, T> _parser;
private ReadOnlySpanFunc<TToken, T, U> _selector;
public MapWithInputParser(Parser<TToken, T> parser, ReadOnlySpanFunc<TToken, T, U> selector)
{
_parser = parser;
_selector = selector;
}
internal override InternalResult<U> Parse(ref ParseState<TToken> state, ref ExpectedCollector<TToken> expecteds)
{
var start = state.Location;
state.PushBookmark(); // don't discard input buffer
var result = _parser.Parse(ref state, ref expecteds);
if (!result.Success)
{
state.PopBookmark();
return InternalResult.Failure<U>(result.ConsumedInput);
}
var delta = state.Location - start;
var val = _selector(state.LookBehind(delta), result.Value);
state.PopBookmark();
return InternalResult.Success<U>(val, result.ConsumedInput);
}
}
}