-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPatternParser.cs
99 lines (88 loc) · 3.62 KB
/
PatternParser.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
using Cecil.AspectN.Matchers;
using System;
using System.Collections.Concurrent;
namespace Cecil.AspectN
{
public class PatternParser : AbstractPatternParser<IMatcher>
{
private readonly static PatternParser _Instance = new();
private readonly static ConcurrentDictionary<string, IMatcher> _Cache = new();
private PatternParser() { }
public static IMatcher Parse(string pattern)
{
return _Cache.GetOrAdd(pattern, _Instance.ParsePattern);
}
protected override IMatcher NewNotMatcher(IMatcher matcher) => new NotMatcher(matcher);
protected override IMatcher NewAndMatcher(IMatcher matcher1, IMatcher matcher2) => new AndMatcher(matcher1, matcher2);
protected override IMatcher NewOrMatcher(IMatcher matcher1, IMatcher matcher2) => new OrMatcher(matcher1, matcher2);
protected override IMatcher ParseSingle(string pattern, ref int index)
{
var method = ParseMethod(pattern, ref index);
var startSymbol = pattern[index++];
if (startSymbol != '(') throw new ArgumentException($"Expect pattern body start with '(', but got '{startSymbol}'");
var matchPattern = ParseMatchPattern(pattern, ref index);
var endSymbol = pattern[index++];
if (endSymbol != ')') throw new ArgumentException($"Expect pattern body end with ')', but got '{endSymbol}'");
return MatcherFactory.Create(method, matchPattern);
}
private string ParseMethod(string pattern, ref int index)
{
var start = index;
while (index < pattern.Length)
{
var ch = pattern[index++];
if (ch.IsWhiteSpace()) continue;
if (ch < 'A' || ch > 'Z' && ch < 'a' || ch > 'z')
{
index--;
break;
}
}
if (start == index) throw new ArgumentException($"Unknow pattern method ({pattern[index]}) at index {index} of {pattern}");
return pattern.Substring(start, index - start);
}
private string ParseMatchPattern(string pattern, ref int index)
{
char ch;
var start = index;
var groups = 0;
var escape = false;
var inRange = false;
while (index < pattern.Length)
{
ch = pattern[index];
switch (ch)
{
case '\\':
escape ^= true;
break;
case '[':
inRange = !escape;
escape = false;
break;
case ']':
inRange = inRange && escape;
escape = false;
break;
case '(':
if (!escape && !inRange) groups++;
escape = false;
break;
case ')':
if (!escape && !inRange)
{
if (groups == 0) return pattern.Substring(start, index - start);
groups--;
}
escape = false;
break;
default:
escape = false;
break;
}
index++;
}
throw new ArgumentException($"Unable parse the token source from index {start} to the end of pattern({pattern})");
}
}
}