# HG changeset patch # User cin # Date 2018-04-22 12:29:10 # Node ID 0be8a6ae83078a558dfef2376da8854c927a2d54 # Parent 6b3e5c48131b1871dcbb966038b9e7b1d75b43c4 Implemented typereference parser diff --git a/Implab.Playground/Program.cs b/Implab.Playground/Program.cs --- a/Implab.Playground/Program.cs +++ b/Implab.Playground/Program.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using Implab.Diagnostics; using Implab.ServiceHost.Unity; using Implab.Xml; using Unity; @@ -30,9 +32,20 @@ namespace Implab.Playground { static void Main(string[] args) { var container = new UnityContainer(); - var containerConfig = SerializationHelpers.DeserializeFromFile("data/sample.xml"); + var listener = new SimpleTraceListener(Console.Out); + Trace.TraceSource.Switch.Level = SourceLevels.All; + Trace.TraceSource.Listeners.Add(listener); + + var c = new Container(); - Console.WriteLine($"container: {containerConfig.Registrations.Count}"); + var cts = new ConfigurationContext(); + cts.AddNamespace("System"); + cts.AddNamespace("System.Collections.Generic"); + cts.AddNamespace("Implab.Playground"); + + Console.WriteLine(c.GetType().FullName); + + cts.Resolve("Container{Int32}"); } diff --git a/Implab.ServiceHost/Unity/ConfigurationContext.cs b/Implab.ServiceHost/Unity/ConfigurationContext.cs new file mode 100644 --- /dev/null +++ b/Implab.ServiceHost/Unity/ConfigurationContext.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Implab.Diagnostics; + +namespace Implab.ServiceHost.Unity { + using System.Linq; + using System.Text; + using static Trace; + + public class ConfigurationContext { + Regex _nsRx = new Regex(@"^\w+(\.\w+)*$", RegexOptions.Compiled); + readonly LinkedList m_namespases = new LinkedList(); + + LinkedListNode m_insertAt; + + public ConfigurationContext() { + m_insertAt = new LinkedListNode(string.Empty); + m_namespases.AddFirst(m_insertAt); + } + + public void AddNamespace(string ns) { + Safe.ArgumentMatch(ns, nameof(ns), _nsRx); + if (m_insertAt != null) + m_namespases.AddAfter(m_insertAt, ns); + else + m_namespases.AddFirst(ns); + } + + public Type Resolve(TypeReference reference) { + Safe.ArgumentNotNull(reference, nameof(reference)); + + var args = reference.IsGeneric && !reference.IsOpenGeneric ? reference.GenericParameters?.Select(Resolve).ToArray() : null; + var argc = reference.IsGeneric ? reference.GenericParameters.Length : 0; + + foreach (var ns in m_namespases) { + var typeName = FormatName(new [] { ns, reference.Namespace, reference.TypeName}, argc, args, reference.IsArray); + + var resolved = Type.GetType(typeName, false); + if (resolved != null) { + Log("Probe succeed {0} in '{1}': {2} -> {3}", reference, ns, typeName, resolved.FullName); + return resolved; + } else { + Log("Probe failed {0} in '{1}': {2}", reference, ns, typeName); + } + } + + throw new Exception($"Failed to resolve: {reference}"); + } + + string FormatName(string[] parts, int argc, Type[] args, bool isArray) { + var builder = new StringBuilder(); + + builder.Append(String.Join(".", parts.Where(x => !string.IsNullOrEmpty(x)))); + if (argc > 0) { + builder.Append('`'); + builder.Append(argc); + } + + if (args!= null && args.Length > 0) { + builder.Append('['); + builder.Append(string.Join(",", args.Select(x => x.FullName))); + builder.Append(']'); + } + + if(isArray) + builder.Append("[]"); + + return builder.ToString(); + } + + public Type Resolve(string typeReference) { + return Resolve(TypeReference.Parse(typeReference)); + } + + public void Register(ServiceElement descriptor) { + + } + + } +} \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/TypeReference.cs b/Implab.ServiceHost/Unity/TypeReference.cs --- a/Implab.ServiceHost/Unity/TypeReference.cs +++ b/Implab.ServiceHost/Unity/TypeReference.cs @@ -1,3 +1,7 @@ +using System; +using System.Linq; +using System.Text; + namespace Implab.ServiceHost.Unity { public class TypeReference { public string TypeName { get; set; } @@ -5,5 +9,50 @@ namespace Implab.ServiceHost.Unity { public string Namespace { get; set; } public TypeReference[] GenericParameters { get; set; } + + public bool IsArray { get; set; } + + public bool IsOpenGeneric { + get { + return GenericParameters!=null && GenericParameters.Contains(null); + } + } + + public bool IsGeneric { + get { + return GenericParameters != null && GenericParameters.Length > 0; + } + } + + public override string ToString() { + var builder = new StringBuilder(); + + if (!string.IsNullOrEmpty(Namespace)) { + builder.Append(Namespace); + builder.Append('.'); + } + + if (!string.IsNullOrEmpty(TypeName)) { + builder.Append(TypeName); + } else { + builder.Append("__unnamed__"); + } + + if (GenericParameters != null && GenericParameters.Length > 0) { + builder.Append('{'); + for(var i = 0; i < GenericParameters.Length; i++) { + if (i > 0) + builder.Append(','); + builder.Append(GenericParameters[i]); + } + builder.Append('}'); + } + + return builder.ToString(); + } + public static TypeReference Parse(string text) { + var parser = new TypeReferenceParser(text); + return parser.Parse(); + } } } \ No newline at end of file diff --git a/Implab.ServiceHost/Unity/TypeReferenceParser.cs b/Implab.ServiceHost/Unity/TypeReferenceParser.cs --- a/Implab.ServiceHost/Unity/TypeReferenceParser.cs +++ b/Implab.ServiceHost/Unity/TypeReferenceParser.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; namespace Implab.ServiceHost.Unity { - public class TypeReferenceParser { + internal class TypeReferenceParser { enum TokenType { None, @@ -20,7 +20,7 @@ namespace Implab.ServiceHost.Unity { Eof } - readonly Regex _tokens = new Regex(@"(\w+)|\s*([\.{},])\s*"); + readonly Regex _tokens = new Regex(@"(\w+)|\s*([\.{},\+])\s*"); TokenType m_token; @@ -28,12 +28,16 @@ namespace Implab.ServiceHost.Unity { 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; @@ -49,6 +53,7 @@ namespace Implab.ServiceHost.Unity { 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; @@ -63,6 +68,7 @@ namespace Implab.ServiceHost.Unity { m_token = TokenType.CloseList; break; case ".": + case "+": m_token = TokenType.Dot; break; case ",": @@ -75,8 +81,11 @@ namespace Implab.ServiceHost.Unity { throw new FormatException($"Failed to parse '{m_text}' at pos {m_pos}"); } - public TypeRerefence Pase() { - + public TypeReference Parse() { + var result = ReadTypeReference(); + if (ReadToken()) + ThrowUnexpectedToken(); + return result; } string[] ReadTypeName() { @@ -118,20 +127,16 @@ namespace Implab.ServiceHost.Unity { return null; var typeReference = new TypeReference { - Namespace = string.Join(",", parts, 0, parts.Length - 1), - TypeName = parts[parts.Length - 1] - }; + Namespace = string.Join(".", parts, 0, parts.Length - 1), + TypeName = parts[parts.Length - 1] + }; switch (Token) { - case TokenType.Eof: - break; case TokenType.OpenList: typeReference.GenericParameters = ReadTypeReferenceList(); - if(Token != TokenType.CloseList) + if (Token != TokenType.CloseList) ThrowUnexpectedToken(); - break; - default: - ThrowUnexpectedToken(); + ReadToken(); break; } @@ -139,18 +144,19 @@ namespace Implab.ServiceHost.Unity { } TypeReference[] ReadTypeReferenceList() { - throw new NotImplementedException(); - } + var list = new List(); - void ReadDot() { - if (!ReadToken() || Token != TokenType.Dot) - ThrowUnexpectedToken(); + do { + var typeReference = ReadTypeReference(); + list.Add(typeReference); + } while (Token == TokenType.Comma); + + return list.ToArray(); } void ThrowUnexpectedToken() { - throw new FormatException($"Unexpected '{Token}' at {m_pos}"); + throw new FormatException($"Unexpected '{Token}' at pos {TokenPos}: -->{m_text.Substring(TokenPos, Math.Min(m_text.Length - TokenPos, 10))}"); } - } } \ No newline at end of file