|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
namespace Implab.ServiceHost.Unity {
|
|
|
internal class TypeReferenceParser {
|
|
|
enum TokenType {
|
|
|
None,
|
|
|
|
|
|
Word,
|
|
|
|
|
|
Dot,
|
|
|
|
|
|
Comma,
|
|
|
|
|
|
OpenList,
|
|
|
|
|
|
CloseList,
|
|
|
|
|
|
Eof
|
|
|
}
|
|
|
|
|
|
readonly Regex _tokens = new Regex(@"([\w\+]+)|\s*([\.{},])\s*");
|
|
|
|
|
|
TokenType m_token;
|
|
|
|
|
|
string m_tokenValue;
|
|
|
|
|
|
int m_pos;
|
|
|
|
|
|
int m_tokenPos;
|
|
|
|
|
|
readonly string m_text;
|
|
|
|
|
|
TokenType Token { get { return m_token; } }
|
|
|
|
|
|
string TokenValue { get { return m_tokenValue; } }
|
|
|
|
|
|
int TokenPos { get { return m_tokenPos; } }
|
|
|
|
|
|
public TypeReferenceParser(string text) {
|
|
|
Safe.ArgumentNotEmpty(text, nameof(text));
|
|
|
m_text = text;
|
|
|
}
|
|
|
|
|
|
bool ReadToken() {
|
|
|
if (m_pos >= m_text.Length) {
|
|
|
m_token = TokenType.Eof;
|
|
|
m_tokenValue = null;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
var m = _tokens.Match(m_text, m_pos);
|
|
|
|
|
|
if (m.Success) {
|
|
|
m_tokenPos = m_pos;
|
|
|
m_pos += m.Length;
|
|
|
if (m.Groups[1].Success) {
|
|
|
m_token = TokenType.Word;
|
|
|
m_tokenValue = m.Groups[1].Value;
|
|
|
} else if (m.Groups[2].Success) {
|
|
|
m_tokenValue = null;
|
|
|
switch (m.Groups[2].Value) {
|
|
|
case "{":
|
|
|
m_token = TokenType.OpenList;
|
|
|
break;
|
|
|
case "}":
|
|
|
m_token = TokenType.CloseList;
|
|
|
break;
|
|
|
case ".":
|
|
|
m_token = TokenType.Dot;
|
|
|
break;
|
|
|
case ",":
|
|
|
m_token = TokenType.Comma;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
|
|
|
}
|
|
|
|
|
|
public TypeReference Parse() {
|
|
|
var result = ReadTypeReference();
|
|
|
if (ReadToken())
|
|
|
ThrowUnexpectedToken();
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
string[] ReadTypeName() {
|
|
|
var parts = new List<string>();
|
|
|
|
|
|
string current = null;
|
|
|
bool stop = false;
|
|
|
while ((!stop) && ReadToken()) {
|
|
|
switch (Token) {
|
|
|
case TokenType.Word:
|
|
|
if (current != null)
|
|
|
ThrowUnexpectedToken();
|
|
|
current = TokenValue;
|
|
|
break;
|
|
|
case TokenType.Dot:
|
|
|
if (current == null)
|
|
|
ThrowUnexpectedToken();
|
|
|
parts.Add(current);
|
|
|
current = null;
|
|
|
break;
|
|
|
default:
|
|
|
stop = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (current != null)
|
|
|
parts.Add(current);
|
|
|
|
|
|
if (parts.Count == 0)
|
|
|
return null;
|
|
|
|
|
|
return parts.ToArray();
|
|
|
}
|
|
|
|
|
|
TypeReference ReadTypeReference() {
|
|
|
|
|
|
var parts = ReadTypeName();
|
|
|
if (parts == null)
|
|
|
return null;
|
|
|
|
|
|
var typeReference = new TypeReference {
|
|
|
Namespace = string.Join(".", parts, 0, parts.Length - 1),
|
|
|
TypeName = parts[parts.Length - 1]
|
|
|
};
|
|
|
|
|
|
switch (Token) {
|
|
|
case TokenType.OpenList:
|
|
|
typeReference.GenericParameters = ReadTypeReferenceList();
|
|
|
if (Token != TokenType.CloseList)
|
|
|
ThrowUnexpectedToken();
|
|
|
ReadToken();
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return typeReference;
|
|
|
}
|
|
|
|
|
|
TypeReference[] ReadTypeReferenceList() {
|
|
|
var list = new List<TypeReference>();
|
|
|
|
|
|
do {
|
|
|
var typeReference = ReadTypeReference();
|
|
|
list.Add(typeReference);
|
|
|
} while (Token == TokenType.Comma);
|
|
|
|
|
|
return list.ToArray();
|
|
|
}
|
|
|
|
|
|
void ThrowUnexpectedToken() {
|
|
|
throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|