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
|
269
|
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 ".":
|
|
71 m_token = TokenType.Dot;
|
|
72 break;
|
|
73 case ",":
|
|
74 m_token = TokenType.Comma;
|
|
75 break;
|
|
76 }
|
|
77 }
|
|
78 return true;
|
|
79 }
|
|
80 throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
|
|
81 }
|
|
82
|
268
|
83 public TypeReference Parse() {
|
|
84 var result = ReadTypeReference();
|
|
85 if (ReadToken())
|
|
86 ThrowUnexpectedToken();
|
|
87 return result;
|
267
|
88 }
|
|
89
|
|
90 string[] ReadTypeName() {
|
|
91 var parts = new List<string>();
|
|
92
|
|
93 string current = null;
|
|
94 bool stop = false;
|
|
95 while ((!stop) && ReadToken()) {
|
|
96 switch (Token) {
|
|
97 case TokenType.Word:
|
|
98 if (current != null)
|
|
99 ThrowUnexpectedToken();
|
|
100 current = TokenValue;
|
|
101 break;
|
|
102 case TokenType.Dot:
|
|
103 if (current == null)
|
|
104 ThrowUnexpectedToken();
|
|
105 parts.Add(current);
|
|
106 current = null;
|
|
107 break;
|
|
108 default:
|
|
109 stop = true;
|
|
110 break;
|
|
111 }
|
|
112 }
|
|
113 if (current != null)
|
|
114 parts.Add(current);
|
|
115
|
|
116 if (parts.Count == 0)
|
|
117 return null;
|
|
118
|
|
119 return parts.ToArray();
|
|
120 }
|
|
121
|
|
122 TypeReference ReadTypeReference() {
|
|
123
|
|
124 var parts = ReadTypeName();
|
|
125 if (parts == null)
|
|
126 return null;
|
|
127
|
|
128 var typeReference = new TypeReference {
|
268
|
129 Namespace = string.Join(".", parts, 0, parts.Length - 1),
|
|
130 TypeName = parts[parts.Length - 1]
|
|
131 };
|
267
|
132
|
|
133 switch (Token) {
|
|
134 case TokenType.OpenList:
|
|
135 typeReference.GenericParameters = ReadTypeReferenceList();
|
268
|
136 if (Token != TokenType.CloseList)
|
267
|
137 ThrowUnexpectedToken();
|
268
|
138 ReadToken();
|
267
|
139 break;
|
|
140 }
|
|
141
|
|
142 return typeReference;
|
|
143 }
|
|
144
|
|
145 TypeReference[] ReadTypeReferenceList() {
|
268
|
146 var list = new List<TypeReference>();
|
267
|
147
|
268
|
148 do {
|
|
149 var typeReference = ReadTypeReference();
|
|
150 list.Add(typeReference);
|
|
151 } while (Token == TokenType.Comma);
|
|
152
|
|
153 return list.ToArray();
|
267
|
154 }
|
|
155
|
|
156 void ThrowUnexpectedToken() {
|
268
|
157 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
|
267
|
158 }
|
|
159
|
|
160 }
|
|
161 } |