##// END OF EJS Templates
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete) Implab.ServiceHost: rewritten TypeReference (added support for nested types), stable API

File last commit:

r278:6691aff01de1 v3
r278:6691aff01de1 v3
Show More
TypeReferenceParser.cs
244 lines | 7.1 KiB | text/x-csharp | CSharpLexer
cin
Working on Unity xml configuration
r267 using System;
using System.Collections.Generic;
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 using System.Linq;
cin
Working on Unity xml configuration
r267 using System.Text.RegularExpressions;
namespace Implab.ServiceHost.Unity {
cin
Implemented typereference parser
r268 internal class TypeReferenceParser {
cin
Working on Unity xml configuration
r267 enum TokenType {
None,
Word,
Dot,
Comma,
OpenList,
CloseList,
cin
Refactoring...
r277 OpenArray,
CloseArray,
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 Plus,
cin
Working on Unity xml configuration
r267 Eof
}
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 readonly Regex _tokens = new Regex(@"\G(?:([\w]+)|\s*([\+\.{},\[\]])\s*)", RegexOptions.Compiled);
cin
Working on Unity xml configuration
r267
TokenType m_token;
string m_tokenValue;
int m_pos;
cin
Implemented typereference parser
r268 int m_tokenPos;
cin
Working on Unity xml configuration
r267 readonly string m_text;
TokenType Token { get { return m_token; } }
string TokenValue { get { return m_tokenValue; } }
cin
Implemented typereference parser
r268 int TokenPos { get { return m_tokenPos; } }
cin
Working on Unity xml configuration
r267 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) {
cin
Implemented typereference parser
r268 m_tokenPos = m_pos;
cin
Working on Unity xml configuration
r267 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;
cin
Refactoring...
r277 case "[":
m_token = TokenType.OpenArray;
break;
case "]":
m_token = TokenType.CloseArray;
break;
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 case "+":
m_token = TokenType.Plus;
break;
cin
Working on Unity xml configuration
r267 }
}
return true;
}
throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}");
}
cin
Implemented typereference parser
r268 public TypeReference Parse() {
var result = ReadTypeReference();
cin
Refactoring...
r277 if (Token != TokenType.Eof)
cin
Implemented typereference parser
r268 ThrowUnexpectedToken();
return result;
cin
Working on Unity xml configuration
r267 }
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 string[] ReadQTypeName() {
cin
Working on Unity xml configuration
r267 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();
}
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 string ReadNQTypeName() {
ReadToken();
if (Token != TokenType.Word)
ThrowUnexpectedToken();
return TokenValue;
}
cin
Working on Unity xml configuration
r267 TypeReference ReadTypeReference() {
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 var parts = ReadQTypeName();
cin
Working on Unity xml configuration
r267 if (parts == null)
return null;
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 var genericParameters = ReadGenericParams();
var typeReference = TypeReference.Create(
string.Join(".", parts, 0, parts.Length - 1),
parts[parts.Length - 1],
genericParameters.Length
);
if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
typeReference = typeReference.MakeGenericType(genericParameters);
typeReference = ReadArraySpec(typeReference);
if(Token == TokenType.Plus)
return ReadNestedType(typeReference);
return typeReference;
}
TypeReference ReadNestedType(TypeReference declaringType) {
var name = ReadNQTypeName();
if(string.IsNullOrEmpty(name))
throw new FormatException("Nested type name can't be empty");
ReadToken();
var genericParameters = ReadGenericParams();
var typeReference = declaringType.Create(
name,
genericParameters.Length
);
cin
Working on Unity xml configuration
r267
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 if (genericParameters.Length > 0 && genericParameters.All(x => x != null))
typeReference = typeReference.MakeGenericType(genericParameters);
typeReference = ReadArraySpec(typeReference);
if(Token == TokenType.Plus)
return ReadNestedType(typeReference);
return typeReference;
}
TypeReference[] ReadGenericParams() {
if (Token == TokenType.OpenList) {
var genericParameters = ReadTypeReferenceList();
if (Token != TokenType.CloseList)
ThrowUnexpectedToken();
ReadToken();
return genericParameters;
}
return Array.Empty<TypeReference>();
}
TypeReference ReadArraySpec(TypeReference typeReference) {
while (Token == TokenType.OpenArray) {
var rank = CountRank();
if (Token != TokenType.CloseArray)
ThrowUnexpectedToken();
typeReference = typeReference.MakeArrayType(rank);
ReadToken();
cin
Working on Unity xml configuration
r267 }
return typeReference;
}
cin
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)...
r278 int CountRank() {
int rank = 0;
do {
rank++;
} while(ReadToken() && Token == TokenType.Comma);
return rank;
cin
Refactoring...
r277 }
cin
Working on Unity xml configuration
r267 TypeReference[] ReadTypeReferenceList() {
cin
Implemented typereference parser
r268 var list = new List<TypeReference>();
cin
Working on Unity xml configuration
r267
cin
Implemented typereference parser
r268 do {
var typeReference = ReadTypeReference();
list.Add(typeReference);
} while (Token == TokenType.Comma);
return list.ToArray();
cin
Working on Unity xml configuration
r267 }
void ThrowUnexpectedToken() {
cin
Implemented typereference parser
r268 throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}");
cin
Working on Unity xml configuration
r267 }
}
}