-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathParse.Sequence.cs
158 lines (140 loc) · 6.05 KB
/
Parse.Sequence.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
namespace Sprache
{
using System;
using System.Collections.Generic;
using System.Linq;
partial class Parse
{
/// <summary>
///
/// </summary>
/// <param name="parser"></param>
/// <param name="delimiter"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<IEnumerable<T>> DelimitedBy<T, U>(this Parser<T> parser, Parser<U> delimiter)
{
return DelimitedBy(parser, delimiter, null, null);
}
/// <summary>
///
/// </summary>
/// <param name="parser"></param>
/// <param name="delimiter"></param>
/// <param name="minimumCount"></param>
/// <param name="maximumCount"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<IEnumerable<T>> DelimitedBy<T, U>(this Parser<T> parser, Parser<U> 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);
}
/// <summary>
/// Fails on the first itemParser failure, if it reads at least one character.
/// </summary>
/// <param name="itemParser"></param>
/// <param name="delimiter"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<IEnumerable<T>> XDelimitedBy<T, U>(this Parser<T> itemParser, Parser<U> 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);
}
/// <summary>
///
/// </summary>
/// <param name="parser"></param>
/// <param name="count"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<IEnumerable<T>> Repeat<T>(this Parser<T> parser, int count)
{
return Repeat(parser, count, count);
}
/// <summary>
///
/// </summary>
/// <param name="parser"></param>
/// <param name="minimumCount"></param>
/// <param name="maximumCount"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<IEnumerable<T>> Repeat<T>(this Parser<T> parser, int? minimumCount, int? maximumCount)
{
if (parser == null) throw new ArgumentNullException(nameof(parser));
return i =>
{
var remainder = i;
var result = new List<T>();
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<IEnumerable<T>>(i, msg, new[] { exp });
}
return Result.Success<IEnumerable<T>>(result, remainder);
};
}
/// <summary>
///
/// </summary>
/// <param name="parser"></param>
/// <param name="open"></param>
/// <param name="close"></param>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <typeparam name="V"></typeparam>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static Parser<T> Contained<T, U, V>(this Parser<T> parser, Parser<U> open, Parser<V> 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;
}
}
}