Terraria v1.4.4.9
Terraria source code documentation
All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Events Macros
RegexPrefixAnalyzer.cs
Go to the documentation of this file.
3
5
6internal ref struct RegexPrefixAnalyzer
7{
8 private readonly List<RegexFC> _fcStack;
9
11
12 private bool _skipAllChildren;
13
14 private bool _skipchild;
15
16 private bool _failed;
17
19 {
20 _fcStack = new List<RegexFC>(32);
22 _failed = false;
23 _skipchild = false;
24 _skipAllChildren = false;
25 }
26
27 public static (string Prefix, bool CaseInsensitive) ComputeLeadingSubstring(RegexTree tree)
28 {
30 RegexNode regexNode2 = null;
31 int num = 0;
32 while (true)
33 {
34 switch (regexNode.Type)
35 {
36 case 25:
37 if (regexNode.ChildCount() > 0)
38 {
40 num = 0;
41 }
42 break;
43 case 28:
44 case 32:
45 regexNode = regexNode.Child(0);
46 regexNode2 = null;
47 continue;
48 case 3:
49 case 6:
50 case 43:
51 if (regexNode.M > 0 && regexNode.M < 50000)
52 {
53 return (Prefix: new string(regexNode.Ch, regexNode.M), CaseInsensitive: (regexNode.Options & RegexOptions.IgnoreCase) != 0);
54 }
55 return (Prefix: string.Empty, CaseInsensitive: false);
56 case 9:
57 return (Prefix: regexNode.Ch.ToString(), CaseInsensitive: (regexNode.Options & RegexOptions.IgnoreCase) != 0);
58 case 12:
59 return (Prefix: regexNode.Str, CaseInsensitive: (regexNode.Options & RegexOptions.IgnoreCase) != 0);
60 default:
61 return (Prefix: string.Empty, CaseInsensitive: false);
62 case 14:
63 case 15:
64 case 16:
65 case 18:
66 case 19:
67 case 20:
68 case 21:
69 case 23:
70 case 30:
71 case 31:
72 case 41:
73 break;
74 }
75 if (regexNode2 == null || num >= regexNode2.ChildCount())
76 {
77 break;
78 }
79 regexNode = regexNode2.Child(num++);
80 }
81 return (Prefix: string.Empty, CaseInsensitive: false);
82 }
83
84 public static (string CharClass, bool CaseInsensitive)[] ComputeFirstCharClass(RegexTree tree)
85 {
88 RegexFC regexFC = regexPrefixAnalyzer.RegexFCFromRegexTree(tree);
89 regexPrefixAnalyzer.Dispose();
90 if (regexFC == null || regexFC._nullable)
91 {
92 return null;
93 }
94 if (regexFC.CaseInsensitive)
95 {
96 regexFC.AddLowercase(((tree.Options & RegexOptions.CultureInvariant) != 0) ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture);
97 }
98 return new(string, bool)[1] { (regexFC.GetFirstChars(), regexFC.CaseInsensitive) };
99 }
100
101 public static (string CharClass, bool CaseInsensitive)[] ComputeMultipleCharClasses(RegexTree tree, int maxChars)
102 {
103 if ((tree.Options & RegexOptions.RightToLeft) != 0)
104 {
105 return null;
106 }
107 maxChars = Math.Min(tree.MinRequiredLength, maxChars);
108 if (maxChars <= 1)
109 {
110 return null;
111 }
112 RegexNode regexNode = tree.Root;
113 while (regexNode.Type != 24)
114 {
115 int type = regexNode.Type;
116 if (type == 25 || type == 28 || type == 32)
117 {
118 regexNode = regexNode.Child(0);
119 continue;
120 }
121 return null;
122 }
124 bool flag = false;
125 int num = regexNode.ChildCount();
126 for (int i = 0; i < num; i++)
127 {
129 flag |= (regexNode2.Options & RegexOptions.IgnoreCase) != 0;
130 switch (regexNode2.Type)
131 {
132 case 12:
133 {
134 maxChars = Math.Min(maxChars, regexNode2.Str.Length);
135 for (int l = 0; l < maxChars; l++)
136 {
138 (reference ?? (reference = new RegexCharClass())).AddChar(regexNode2.Str[l]);
139 }
140 break;
141 }
142 case 25:
143 {
144 int num2 = 0;
145 int num3 = regexNode2.ChildCount();
146 for (int j = 0; j < num3; j++)
147 {
148 if (num2 >= array.Length)
149 {
150 break;
151 }
153 flag |= (regexNode3.Options & RegexOptions.IgnoreCase) != 0;
154 switch (regexNode3.Type)
155 {
156 case 9:
157 {
159 (reference ?? (reference = new RegexCharClass())).AddChar(regexNode3.Ch);
160 break;
161 }
162 case 11:
163 {
165 if (!(reference ?? (reference = new RegexCharClass())).TryAddCharClass(RegexCharClass.Parse(regexNode3.Str)))
166 {
167 return null;
168 }
169 break;
170 }
171 case 12:
172 {
173 for (int k = 0; k < regexNode3.Str.Length; k++)
174 {
175 if (num2 >= array.Length)
176 {
177 break;
178 }
180 (reference ?? (reference = new RegexCharClass())).AddChar(regexNode3.Str[k]);
181 }
182 break;
183 }
184 default:
185 j = num3;
186 break;
187 }
188 }
190 break;
191 }
192 default:
193 return null;
194 }
195 }
196 for (int m = 0; m < maxChars; m++)
197 {
198 if (array[m] == null)
199 {
200 maxChars = m;
201 break;
202 }
203 }
204 if (maxChars == 0)
205 {
206 return null;
207 }
208 (string, bool)[] array2 = new(string, bool)[maxChars];
209 CultureInfo culture = null;
210 if (flag)
211 {
212 culture = (((tree.Options & RegexOptions.CultureInvariant) != 0) ? CultureInfo.InvariantCulture : CultureInfo.CurrentCulture);
213 }
214 for (int n = 0; n < array2.Length; n++)
215 {
216 if (flag)
217 {
218 array[n].AddLowercase(culture);
219 }
220 array2[n] = (array[n].ToStringClass(), flag);
221 }
222 return array2;
223 }
224
226 {
227 RegexNode regexNode = tree.Root;
228 RegexNode regexNode2 = null;
229 int num = 0;
230 while (true)
231 {
232 switch (regexNode.Type)
233 {
234 case 14:
235 return 2;
236 case 15:
237 return 8;
238 case 16:
239 return 64;
240 case 41:
241 return 128;
242 case 18:
243 return 1;
244 case 19:
245 return 4;
246 case 20:
247 return 16;
248 case 21:
249 return 32;
250 case 25:
251 if (regexNode.ChildCount() > 0)
252 {
254 num = 0;
255 }
256 break;
257 case 28:
258 case 32:
259 regexNode = regexNode.Child(0);
260 regexNode2 = null;
261 continue;
262 default:
263 return 0;
264 case 23:
265 case 30:
266 case 31:
267 break;
268 }
269 if (regexNode2 == null || num >= regexNode2.ChildCount())
270 {
271 break;
272 }
273 regexNode = regexNode2.Child(num++);
274 }
275 return 0;
276 }
277
278 private void PushInt(int i)
279 {
280 _intStack.Append(i);
281 }
282
283 private bool IntIsEmpty()
284 {
285 return _intStack.Length == 0;
286 }
287
288 private int PopInt()
289 {
290 return _intStack.Pop();
291 }
292
293 private void PushFC(RegexFC fc)
294 {
295 _fcStack.Add(fc);
296 }
297
298 private bool FCIsEmpty()
299 {
300 return _fcStack.Count == 0;
301 }
302
303 private RegexFC PopFC()
304 {
305 RegexFC result = TopFC();
306 _fcStack.RemoveAt(_fcStack.Count - 1);
307 return result;
308 }
309
310 private RegexFC TopFC()
311 {
312 return _fcStack[_fcStack.Count - 1];
313 }
314
315 public void Dispose()
316 {
317 _intStack.Dispose();
318 }
319
321 {
322 RegexNode regexNode = tree.Root;
323 int num = 0;
324 while (true)
325 {
326 int num2 = regexNode.ChildCount();
327 if (num2 == 0)
328 {
330 }
331 else if (num < num2 && !_skipAllChildren)
332 {
333 CalculateFC(regexNode.Type | 0x40, regexNode, num);
334 if (!_skipchild)
335 {
336 regexNode = regexNode.Child(num);
337 PushInt(num);
338 num = 0;
339 }
340 else
341 {
342 num++;
343 _skipchild = false;
344 }
345 continue;
346 }
347 _skipAllChildren = false;
348 if (IntIsEmpty())
349 {
350 break;
351 }
352 num = PopInt();
353 regexNode = regexNode.Next;
354 CalculateFC(regexNode.Type | 0x80, regexNode, num);
355 if (_failed)
356 {
357 return null;
358 }
359 num++;
360 }
361 if (FCIsEmpty())
362 {
363 return null;
364 }
365 return PopFC();
366 }
367
368 private void SkipChild()
369 {
370 _skipchild = true;
371 }
372
373 private void CalculateFC(int NodeType, RegexNode node, int CurIndex)
374 {
375 bool caseInsensitive = (node.Options & RegexOptions.IgnoreCase) != 0;
376 bool flag = (node.Options & RegexOptions.RightToLeft) != 0;
377 switch (NodeType)
378 {
379 case 98:
380 if (CurIndex == 0)
381 {
382 SkipChild();
383 }
384 break;
385 case 23:
386 PushFC(new RegexFC(nullable: true));
387 break;
388 case 153:
389 if (CurIndex != 0)
390 {
391 RegexFC fc3 = PopFC();
393 _failed = !regexFC3.AddFC(fc3, concatenate: true);
394 }
395 if (!TopFC()._nullable)
396 {
397 _skipAllChildren = true;
398 }
399 break;
400 case 162:
401 if (CurIndex > 1)
402 {
403 RegexFC fc2 = PopFC();
405 _failed = !regexFC2.AddFC(fc2, concatenate: false);
406 }
407 break;
408 case 152:
409 case 161:
410 if (CurIndex != 0)
411 {
412 RegexFC fc = PopFC();
414 _failed = !regexFC.AddFC(fc, concatenate: false);
415 }
416 break;
417 case 154:
418 case 155:
419 if (node.M == 0)
420 {
421 TopFC()._nullable = true;
422 }
423 break;
424 case 94:
425 case 95:
426 SkipChild();
427 PushFC(new RegexFC(nullable: true));
428 break;
429 case 9:
430 case 10:
431 PushFC(new RegexFC(node.Ch, NodeType == 10, nullable: false, caseInsensitive));
432 break;
433 case 3:
434 case 6:
435 case 43:
436 PushFC(new RegexFC(node.Ch, not: false, node.M == 0, caseInsensitive));
437 break;
438 case 4:
439 case 7:
440 case 44:
441 PushFC(new RegexFC(node.Ch, not: true, node.M == 0, caseInsensitive));
442 break;
443 case 12:
444 if (node.Str.Length == 0)
445 {
446 PushFC(new RegexFC(nullable: true));
447 }
448 else if (!flag)
449 {
450 PushFC(new RegexFC(node.Str[0], not: false, nullable: false, caseInsensitive));
451 }
452 else
453 {
454 PushFC(new RegexFC(node.Str[node.Str.Length - 1], not: false, nullable: false, caseInsensitive));
455 }
456 break;
457 case 11:
458 PushFC(new RegexFC(node.Str, nullable: false, caseInsensitive));
459 break;
460 case 5:
461 case 8:
462 case 45:
463 PushFC(new RegexFC(node.Str, node.M == 0, caseInsensitive));
464 break;
465 case 13:
466 PushFC(new RegexFC("\0\u0001\0\0", nullable: true, caseInsensitive: false));
467 break;
468 case 14:
469 case 15:
470 case 16:
471 case 17:
472 case 18:
473 case 19:
474 case 20:
475 case 21:
476 case 22:
477 case 41:
478 case 42:
479 case 46:
480 PushFC(new RegexFC(nullable: true));
481 break;
482 default:
484 case 88:
485 case 89:
486 case 90:
487 case 91:
488 case 92:
489 case 93:
490 case 96:
491 case 97:
492 case 156:
493 case 157:
494 case 158:
495 case 159:
496 case 160:
497 break;
498 }
499 }
500}
void Add(TKey key, TValue value)
static CultureInfo CurrentCulture
static CultureInfo InvariantCulture
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static string Format(string resourceFormat, object p1)
Definition SR.cs:118
static string UnexpectedOpcode
Definition SR.cs:94
Definition SR.cs:7
static RegexCharClass Parse(string charClass)
static string bool CaseInsensitive ComputeLeadingSubstring(RegexTree tree)
static string bool CaseInsensitive[] ComputeMultipleCharClasses(RegexTree tree, int maxChars)
void CalculateFC(int NodeType, RegexNode node, int CurIndex)
static string bool CaseInsensitive[] ComputeFirstCharClass(RegexTree tree)
System.Collections.Generic.ValueListBuilder< int > _intStack