-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFsa.Extensions.cs
179 lines (142 loc) · 4.98 KB
/
Fsa.Extensions.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
namespace SourceGenerator;
public partial class Fsa
{
protected void _EXT_ParsePLUS_Bounded(string word, ref int start, ref int end, ref List<Fsa> frontier, bool escaped = false)
{
frontier = [];
start -= escaped ? 1 : 0;
var expr = word[start..end];
int startNum, endNum;
var canHaveMore = false;
{
var (token, match) = CommonMatcher.Search(word, ++end);
if (token != (int)CommonMatch.Numbers)
{
goto expected_numeric;
}
startNum = int.Parse(match);
end += match.Length;
}
if (end >= word.Length)
{
goto expected_operator;
}
switch (word[end])
{
case ',':
{
var (token, match) = CommonMatcher.Search(word, ++end);
if (token != (int)CommonMatch.Numbers)
{
goto expected_numeric;
}
endNum = int.Parse(match);
end += match.Length;
}
if (endNum < startNum)
{
throw new ApplicationException("Loop upper bound must be greater than or equal to lower bound");
}
break;
case '+':
end++;
endNum = startNum;
canHaveMore = true;
break;
case '}':
endNum = startNum;
break;
default:
goto expected_operator;
}
for (var c = startNum; c <= endNum; c++)
{
var builtExpr = string.Join("", Enumerable.Range(0, c).Select((_) => expr));
_ParseSERIES(builtExpr, 0, out _, out var _frontier);
frontier.AddRange(_frontier);
}
// Combine possible set of states down to one with epsilon
frontier = frontier.MergeFrontier();
if (canHaveMore)
{
frontier.Single()._ParsePARENS($"({expr}+|)", 0, out _, out frontier);
}
if (end >= word.Length || word[end] != '}')
{
throw new ApplicationException($"Expected '}}' at offset {end}");
}
end++;
return;
expected_operator:
throw new ApplicationException($"Expected ',' or '+' at offset {end}");
expected_numeric:
throw new ApplicationException($"Expected numeric value at offset {end}");
}
protected void _EXT_ParsePLUS_Optional(string word, ref int start, ref int end, ref List<Fsa> frontier, bool escaped = false)
{
start -= escaped ? 1 : 0;
var expr = word[start..end];
_ParsePARENS($"({expr}|)", 0, out _, out frontier);
end++;
}
protected void _EXT_ParsePLUS_Star(string word, ref int start, ref int end, ref List<Fsa> frontier, bool escaped = false)
{
start -= escaped ? 1 : 0;
var expr = word[start..end];
_ParsePARENS($"({expr}+|)", 0, out _, out frontier);
end++;
}
protected void _EXT_ParseRANGE_Chars(string word, ref int end, ref List<Fsa> frontier)
{
var letter = word[end];
var newState = new Fsa(letter);
_AddTransition(letter, newState);
frontier.Add(newState);
if (end + 1 < word.Length && word[end + 1] == '-')
{
if (end + 2 >= word.Length || word[end + 2] == ']')
{
throw new ApplicationException($"Expected range end character at offset {end + 2}");
}
end += 2;
var endLetter = word[end];
if (endLetter <= letter)
{
throw new ApplicationException($"Range end (at offset {end}) must be greater than '{letter}'");
}
for (char c = (char)(letter + 1); c <= endLetter; c++)
{
var _newState = new Fsa(c);
_AddTransition(c, _newState);
frontier.Add(_newState);
}
}
}
protected void _EXT_ParseRANGE(string word, int start, out int end, out List<Fsa> frontier)
{
end = start + 1;
frontier = [];
for (var _escaped = false;
end < word.Length && (_escaped || word[end] != ']');
end++)
{
switch (word[end])
{
case '\\' when !_escaped:
_escaped = true;
continue;
case '-' when !_escaped:
throw new ApplicationException($"Unexpected '-' at offset {end}");
}
_EXT_ParseRANGE_Chars(word, ref end, ref frontier);
_escaped = false;
}
// Combine possible set of states down to one with epsilon
frontier = frontier.MergeFrontier();
if (end >= word.Length || word[end] != ']')
{
throw new ApplicationException($"Expected ']' at offset {end}");
}
end++;
}
}