267
|
1 using System;
|
|
2 using System.Collections.Generic;
|
|
3 using System.Text.RegularExpressions;
|
|
4
|
|
5 namespace Implab.ServiceHost.Unity {
|
268
|
6 internal class TypeReferenceParser {
|
267
|
7 enum TokenType {
|
|
8 None,
|
|
9
|
|
10 Word,
|
|
11
|
|
12 Dot,
|
|
13
|
|
14 Comma,
|
|
15
|
|
16 OpenList,
|
|
17
|
|
18 CloseList,
|
|
19
|
|
20 Eof
|
|
21 }
|
|
22
|
268
|
23 readonly Regex _tokens = new Regex(@"(\w+)|\s*([\.{},\+])\s*");
|
267
|
24
|
|
25 TokenType m_token;
|
|
26
|
|
27 string m_tokenValue;
|
|
28
|
|
29 int m_pos;
|
|
30
|
268
|
31 int m_tokenPos;
|
|
32
|
267
|
33 readonly string m_text;
|
|
34
|
|
35 TokenType Token { get { return m_token; } }
|
|
36
|
|
37 string TokenValue { get { return m_tokenValue; } }
|
|
38
|
268
|
39 int TokenPos { get { return m_tokenPos; } }
|
|
40
|
267
|
41 public TypeReferenceParser(string text) {
|
|
42 Safe.ArgumentNotEmpty(text, nameof(text));
|
|
43 m_text = text;
|
|
44 }
|
|
45
|
|
46 bool ReadToken() {
|
|
47 if (m_pos >= m_text.Length) {
|
|
48 m_token = TokenType.Eof;
|
|
49 m_tokenValue = null;
|
|
50 return false;
|
|
51 }
|
|
52
|
|
53 var m = _tokens.Match(m_text, m_pos);
|
|
54
|
|
55 if (m.Success) {
|
268
|
56 m_tokenPos = m_pos;
|
267
|
57 m_pos += m.Length;
|
|
58 if (m.Groups[1].Success) {
|
|
59 m_token = TokenType.Word;
|
|
60 m_tokenValue = m.Groups[1].Value;
|
|
61 } else if (m.Groups[2].Success) {
|
|
62 m_tokenValue = null;
|
|
63 switch (m.Groups[2].Value) {
|
|
64 case "{":
|
|
65 m_token = TokenType.OpenList;
|
|
66 break;
|
|
67 case "}":
|
|
68 m_token = TokenType.CloseList;
|
|
69 break;
|
|
70 case ".":
|
268
|
71 case "+":
|
267
|
72 m_token = TokenType.Dot;
|
|
73 break;
|
|
74 case ",":
|
|
75 m_token = TokenType.Comma;
|
|
76 break;
|
|
77 }
|
|
78 }
|
|
79 return true;
|
|
80 }
|
|
81 throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
|
|
82 }
|
|
83
|
268
|
84 public TypeReference Parse() {
|
|
85 var result = ReadTypeReference();
|
|
86 if (ReadToken())
|
|
87 ThrowUnexpectedToken();
|
|
88 return result;
|
267
|
89 }
|
|
90
|
|
91 string[] ReadTypeName() {
|
|
92 var parts = new List<string>();
|
|
93
|
|
94 string current = null;
|
|
95 bool stop = false;
|
|
96 while ((!stop) && ReadToken()) {
|
|
97 switch (Token) {
|
|
98 case TokenType.Word:
|
|
99 if (current != null)
|
|
100 ThrowUnexpectedToken();
|
|
101 current = TokenValue;
|
|
102 break;
|
|
103 case TokenType.Dot:
|
|
104 if (current == null)
|
|
105 ThrowUnexpectedToken();
|
|
106 parts.Add(current);
|
|
107 current = null;
|
|
108 break;
|
|
109 default:
|
|
110 stop = true;
|
|
111 break;
|
|
112 }
|
|
113 }
|
|
114 if (current != null)
|
|
115 parts.Add(current);
|
|
116
|
|
117 if (parts.Count == 0)
|
|
118 return null;
|
|
119
|
|
120 return parts.ToArray();
|
|
121 }
|
|
122
|
|
123 TypeReference ReadTypeReference() {
|
|
124
|
|
125 var parts = ReadTypeName();
|
|
126 if (parts == null)
|
|
127 return null;
|
|
128
|
|
129 var typeReference = new TypeReference {
|
268
|
130 Namespace = string.Join(".", parts, 0, parts.Length - 1),
|
|
131 TypeName = parts[parts.Length - 1]
|
|
132 };
|
267
|
133
|
|
134 switch (Token) {
|
|
135 case TokenType.OpenList:
|
|
136 typeReference.GenericParameters = ReadTypeReferenceList();
|
268
|
137 if (Token != TokenType.CloseList)
|
267
|
138 ThrowUnexpectedToken();
|
268
|
139 ReadToken();
|
267
|
140 break;
|
|
141 }
|
|
142
|
|
143 return typeReference;
|
|
144 }
|
|
145
|
|
146 TypeReference[] ReadTypeReferenceList() {
|
268
|
147 var list = new List<TypeReference>();
|
267
|
148
|
268
|
149 do {
|
|
150 var typeReference = ReadTypeReference();
|
|
151 list.Add(typeReference);
|
|
152 } while (Token == TokenType.Comma);
|
|
153
|
|
154 return list.ToArray();
|
267
|
155 }
|
|
156
|
|
157 void ThrowUnexpectedToken() {
|
268
|
158 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
|
267
|
159 }
|
|
160
|
|
161 }
|
|
162 } |