Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2010-01-25 08:29:31 +0300
committerjfrijters <jfrijters>2010-01-25 08:29:31 +0300
commit198c9d70eac5d6d88718bfedee19314edf77661b (patch)
treecf6e13cb042f93d214c145fd405fefc19cb21b59 /reflect/TypeNameParser.cs
parent2966abd1dcb1eaa8fe692094f657943a9f2d21be (diff)
New IKVM.Reflection implementation.
Diffstat (limited to 'reflect/TypeNameParser.cs')
-rw-r--r--reflect/TypeNameParser.cs439
1 files changed, 439 insertions, 0 deletions
diff --git a/reflect/TypeNameParser.cs b/reflect/TypeNameParser.cs
new file mode 100644
index 00000000..c5b0ba19
--- /dev/null
+++ b/reflect/TypeNameParser.cs
@@ -0,0 +1,439 @@
+/*
+ Copyright (C) 2009 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace IKVM.Reflection
+{
+ struct TypeNameParser
+ {
+ private const string SpecialChars = "\\+,[]*&";
+ private const short SZARRAY = -1;
+ private const short BYREF = -2;
+ private const short POINTER = -3;
+ private readonly string name;
+ private readonly string[] nested;
+ private readonly string assemblyName;
+ private readonly short[] modifiers;
+ private readonly TypeNameParser[] genericParameters;
+
+ internal static string Escape(string name)
+ {
+ if (name == null)
+ {
+ return null;
+ }
+ StringBuilder sb = null;
+ for (int pos = 0; pos < name.Length; pos++)
+ {
+ char c = name[pos];
+ if (SpecialChars.IndexOf(c) != -1)
+ {
+ if (sb == null)
+ {
+ sb = new StringBuilder(name, 0, pos, name.Length + 3);
+ }
+ sb.Append('\\').Append(c);
+ }
+ else if (sb != null)
+ {
+ sb.Append(c);
+ }
+ }
+ return sb != null ? sb.ToString() : name;
+ }
+
+ internal static string Unescape(string name)
+ {
+ int pos = name.IndexOf('\\');
+ if (pos == -1)
+ {
+ return name;
+ }
+ StringBuilder sb = new StringBuilder(name, 0, pos, name.Length - 1);
+ for (; pos < name.Length; pos++)
+ {
+ char c = name[pos];
+ if (c == '\\')
+ {
+ c = name[++pos];
+ }
+ sb.Append(c);
+ }
+ return sb.ToString();
+ }
+
+ internal static TypeNameParser Parse(string typeName, bool throwOnError)
+ {
+ if (throwOnError)
+ {
+ Parser parser = new Parser(typeName);
+ return new TypeNameParser(ref parser);
+ }
+ else
+ {
+ try
+ {
+ Parser parser = new Parser(typeName);
+ return new TypeNameParser(ref parser);
+ }
+ catch (ArgumentException)
+ {
+ return new TypeNameParser();
+ }
+ }
+ }
+
+ private TypeNameParser(ref Parser parser)
+ {
+ bool genericParameter = parser.pos != 0;
+ name = parser.NextNamePart();
+ nested = null;
+ parser.ParseNested(ref nested);
+ genericParameters = null;
+ parser.ParseGenericParameters(ref genericParameters);
+ modifiers = null;
+ parser.ParseModifiers(ref modifiers);
+ assemblyName = null;
+ parser.ParseAssemblyName(genericParameter, ref assemblyName);
+ }
+
+ internal bool Error
+ {
+ get { return name == null; }
+ }
+
+ internal string FirstNamePart
+ {
+ get { return name; }
+ }
+
+ internal string AssemblyName
+ {
+ get { return assemblyName; }
+ }
+
+ private struct Parser
+ {
+ private readonly string typeName;
+ internal int pos;
+
+ internal Parser(string typeName)
+ {
+ this.typeName = typeName;
+ this.pos = 0;
+ }
+
+ private void Check(bool condition)
+ {
+ if (!condition)
+ {
+ throw new ArgumentException("Invalid type name '" + typeName + "'");
+ }
+ }
+
+ private void Consume(char c)
+ {
+ Check(pos < typeName.Length && typeName[pos++] == c);
+ }
+
+ private bool TryConsume(char c)
+ {
+ if (pos < typeName.Length && typeName[pos] == c)
+ {
+ pos++;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ internal string NextNamePart()
+ {
+ SkipWhiteSpace();
+ int start = pos;
+ for (; pos < typeName.Length; pos++)
+ {
+ char c = typeName[pos];
+ if (c == '\\')
+ {
+ pos++;
+ Check(pos < typeName.Length && SpecialChars.IndexOf(typeName[pos]) != -1);
+ }
+ else if (SpecialChars.IndexOf(c) != -1)
+ {
+ break;
+ }
+ }
+ Check(pos - start != 0);
+ if (start == 0 && pos == typeName.Length)
+ {
+ return typeName;
+ }
+ else
+ {
+ return typeName.Substring(start, pos - start);
+ }
+ }
+
+ internal void ParseNested(ref string[] nested)
+ {
+ while (TryConsume('+'))
+ {
+ Add(ref nested, NextNamePart());
+ }
+ }
+
+ internal void ParseGenericParameters(ref TypeNameParser[] genericParameters)
+ {
+ int saved = pos;
+ if (TryConsume('['))
+ {
+ SkipWhiteSpace();
+ if (TryConsume('['))
+ {
+ do
+ {
+ Add(ref genericParameters, new TypeNameParser(ref this));
+ Consume(']');
+ SkipWhiteSpace();
+ }
+ while (TryConsume('['));
+ Consume(']');
+ SkipWhiteSpace();
+ }
+ else
+ {
+ pos = saved;
+ }
+ }
+ }
+
+ internal void ParseModifiers(ref short[] modifiers)
+ {
+ while (pos < typeName.Length)
+ {
+ switch (typeName[pos])
+ {
+ case '*':
+ pos++;
+ Add(ref modifiers, POINTER);
+ break;
+ case '&':
+ pos++;
+ Add(ref modifiers, BYREF);
+ break;
+ case '[':
+ pos++;
+ Add(ref modifiers, ParseArray());
+ Consume(']');
+ break;
+ default:
+ return;
+ }
+ SkipWhiteSpace();
+ }
+ }
+
+ internal void ParseAssemblyName(bool genericParameter, ref string assemblyName)
+ {
+ if (pos < typeName.Length)
+ {
+ if (typeName[pos] == ']' && genericParameter)
+ {
+ // ok
+ }
+ else
+ {
+ Consume(',');
+ SkipWhiteSpace();
+ if (genericParameter)
+ {
+ int start = pos;
+ while (pos < typeName.Length)
+ {
+ char c = typeName[pos];
+ if (c == '\\')
+ {
+ pos++;
+ // a backslash itself is not legal in an assembly name, so we don't need to check for an escaped backslash
+ Check(pos < typeName.Length && typeName[pos++] == ']');
+ }
+ else if (c == ']')
+ {
+ break;
+ }
+ else
+ {
+ pos++;
+ }
+ }
+ Check(pos < typeName.Length && typeName[pos] == ']');
+ assemblyName = typeName.Substring(start, pos - start).Replace("\\]", "]");
+ }
+ else
+ {
+ // only when an assembly name is used in a generic type parameter, will it be escaped
+ assemblyName = typeName.Substring(pos);
+ }
+ Check(assemblyName.Length != 0);
+ }
+ }
+ else
+ {
+ Check(!genericParameter);
+ }
+ }
+
+ private short ParseArray()
+ {
+ SkipWhiteSpace();
+ Check(pos < typeName.Length);
+ char c = typeName[pos];
+ if (c == ']')
+ {
+ return SZARRAY;
+ }
+ else if (c == '*')
+ {
+ pos++;
+ SkipWhiteSpace();
+ return 1;
+ }
+ else
+ {
+ short rank = 1;
+ while (TryConsume(','))
+ {
+ Check(rank < short.MaxValue);
+ rank++;
+ SkipWhiteSpace();
+ }
+ return rank;
+ }
+ }
+
+ private static void SkipWhiteSpace(string typeName, ref int pos)
+ {
+ while (pos < typeName.Length && Char.IsWhiteSpace(typeName[pos]))
+ {
+ pos++;
+ }
+ }
+
+ private void SkipWhiteSpace()
+ {
+ while (pos < typeName.Length && Char.IsWhiteSpace(typeName[pos]))
+ {
+ pos++;
+ }
+ }
+
+ private static void Add<T>(ref T[] array, T elem)
+ {
+ if (array == null)
+ {
+ array = new T[] { elem };
+ return;
+ }
+ Array.Resize(ref array, array.Length + 1);
+ array[array.Length - 1] = elem;
+ }
+ }
+
+ private Type GetType(Assembly assembly, bool throwOnError, string originalName)
+ {
+ if (assemblyName != null)
+ {
+ assembly = assembly.universe.Load(assemblyName, null, throwOnError);
+ if (assembly == null)
+ {
+ return null;
+ }
+ }
+ return Expand(assembly.GetTypeImpl(name), assembly, throwOnError, originalName);
+ }
+
+ internal Type Expand(Type type, Assembly assembly, bool throwOnError, string originalName)
+ {
+ if (type == null)
+ {
+ if (throwOnError)
+ {
+ throw new TypeLoadException(originalName);
+ }
+ return null;
+ }
+ if (nested != null)
+ {
+ foreach (string nest in nested)
+ {
+ type = type.GetNestedType(nest, BindingFlags.Public | BindingFlags.NonPublic);
+ if (type == null)
+ {
+ return null;
+ }
+ }
+ }
+ if (genericParameters != null)
+ {
+ Type[] typeArgs = new Type[genericParameters.Length];
+ for (int i = 0; i < typeArgs.Length; i++)
+ {
+ typeArgs[i] = genericParameters[i].GetType(assembly, throwOnError, originalName);
+ if (typeArgs[i] == null)
+ {
+ return null;
+ }
+ }
+ type = type.MakeGenericType(typeArgs);
+ }
+ if (modifiers != null)
+ {
+ foreach (short modifier in modifiers)
+ {
+ switch (modifier)
+ {
+ case SZARRAY:
+ type = type.MakeArrayType();
+ break;
+ case BYREF:
+ type = type.MakeByRefType();
+ break;
+ case POINTER:
+ type = type.MakePointerType();
+ break;
+ default:
+ type = type.MakeArrayType(modifier);
+ break;
+ }
+ }
+ }
+ return type;
+ }
+ }
+}