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

github.com/mono/cecil.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjbevain <jbevain@gmail.com>2010-04-18 20:29:14 +0400
committerjbevain <jbevain@gmail.com>2010-04-18 20:29:14 +0400
commitd4e053e2d1d42b66c9815d13d0d699f25cc66f8e (patch)
treefca7a56b237a852c76e09bb039b7a9d460bb5b6f /Mono.Cecil/TypeParser.cs
parent37f952bbc8f53df9677d9a5b6edc7f8cc2d26f6f (diff)
add new type parser
Diffstat (limited to 'Mono.Cecil/TypeParser.cs')
-rw-r--r--Mono.Cecil/TypeParser.cs386
1 files changed, 386 insertions, 0 deletions
diff --git a/Mono.Cecil/TypeParser.cs b/Mono.Cecil/TypeParser.cs
new file mode 100644
index 0000000..e788174
--- /dev/null
+++ b/Mono.Cecil/TypeParser.cs
@@ -0,0 +1,386 @@
+//
+// TypeParser.cs
+//
+// Author:
+// Jb Evain (jbevain@gmail.com)
+//
+// Copyright (c) 2008 - 2010 Jb Evain
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Mono.Cecil {
+
+ class TypeParser {
+
+ class Type {
+ public const int Ptr = -1;
+ public const int ByRef = -2;
+ public const int SzArray = -3;
+
+ public string type_fullname;
+ public string [] nested_names;
+ public int arity;
+ public int [] specs;
+ public Type [] generic_arguments;
+ public string assembly;
+ }
+
+ readonly string fullname;
+ readonly int length;
+
+ int position;
+
+ TypeParser (string fullname)
+ {
+ this.fullname = fullname;
+ this.length = fullname.Length;
+ }
+
+ Type ParseType ()
+ {
+ var type = new Type ();
+ type.type_fullname = ParsePart ();
+
+ type.nested_names = ParseNestedNames ();
+
+ if (IsGeneric (type))
+ type.generic_arguments = ParseGenericArguments (type.arity);
+
+ type.specs = ParseSpecs ();
+
+ type.assembly = ParseAssemblyName ();
+
+ return type;
+ }
+
+ static bool IsGeneric (Type type)
+ {
+ int arity = 0;
+
+ TryAddArity (type.type_fullname, ref arity);
+
+ var nested_names = type.nested_names;
+ if (!nested_names.IsNullOrEmpty ()) {
+ for (int i = 0; i < nested_names.Length; i++)
+ TryAddArity (nested_names [i], ref arity);
+ }
+
+ type.arity = arity;
+ return arity > 0;
+ }
+
+ static void TryAddArity (string name, ref int arity)
+ {
+ var index = name.LastIndexOf ('`');
+ if (index == -1)
+ return;
+
+ int value;
+ if (!int.TryParse (name.Substring (index + 1), out value))
+ return;
+
+ arity += value;
+ }
+
+ string ParsePart ()
+ {
+ int start = position;
+ while (position < length) {
+ var chr = fullname [position];
+
+ if (TrySkipEscapeChar (chr))
+ continue;
+
+ if (IsDelimiter (chr))
+ break;
+
+ position++;
+ }
+
+ return fullname.Substring (start, position - start);
+ }
+
+ static bool IsDelimiter (char chr)
+ {
+ return "+,[]*&".IndexOf (chr) != -1;
+ }
+
+ bool TrySkipEscapeChar (char chr)
+ {
+ if (chr == '\\') {
+ position++;
+ return true;
+ }
+
+ return false;
+ }
+
+ void SkipWhiteSpaces ()
+ {
+ while (position < length && Char.IsWhiteSpace (fullname [position]))
+ position++;
+ }
+
+ string [] ParseNestedNames ()
+ {
+ string [] nested_names = null;
+ while (TryParse ('+'))
+ Add (ref nested_names, ParsePart ());
+
+ return nested_names;
+ }
+
+ bool TryParse (char chr)
+ {
+ if (position < length && fullname [position] == chr) {
+ position++;
+ return true;
+ }
+
+ return false;
+ }
+
+ static void Add<T> (ref T [] array, T item)
+ {
+ if (array == null) {
+ array = new [] { item };
+ return;
+ }
+
+#if !CF
+ Array.Resize (ref array, array.Length + 1);
+#else
+ var copy = new T [array.Length + 1];
+ Array.Copy (array, copy, array.Length);
+ array = copy;
+#endif
+ array [array.Length - 1] = item;
+ }
+
+ int [] ParseSpecs ()
+ {
+ int [] specs = null;
+
+ while (position < length) {
+ switch (fullname [position]) {
+ case '*':
+ position++;
+ Add (ref specs, Type.Ptr);
+ break;
+ case '&':
+ position++;
+ Add (ref specs, Type.ByRef);
+ break;
+ case '[':
+ position++;
+ switch (fullname [position]) {
+ case ']':
+ position++;
+ Add (ref specs, Type.SzArray);
+ break;
+ case '*':
+ position++;
+ Add (ref specs, 1);
+ break;
+ default:
+ var rank = 1;
+ while (TryParse (','))
+ rank++;
+
+ Add (ref specs, rank);
+ break;
+ }
+ break;
+ }
+ }
+
+ return specs;
+ }
+
+ Type [] ParseGenericArguments (int arity)
+ {
+ if (position < length || fullname [position] != '[')
+ return new Type [0];
+
+ throw new NotImplementedException ();
+ }
+
+ string ParseAssemblyName ()
+ {
+ int start = position;
+ while (position < length) {
+ var chr = fullname [position];
+
+ if (TrySkipEscapeChar (chr))
+ continue;
+
+ if (chr == '[')
+ break;
+
+ position++;
+ }
+
+ return fullname.Substring (start, position - start);
+ }
+
+
+ public static TypeReference ParseType (ModuleDefinition module, string fullname)
+ {
+ var parser = new TypeParser (fullname);
+ var type_info = parser.ParseType ();
+
+ var type = GetTypeReference (module, type_info);
+
+ return type;
+ }
+
+ static TypeReference GetTypeReference (ModuleDefinition module, Type type_info)
+ {
+ TypeReference type;
+ if (TryGetDefinition (module, type_info, out type))
+ return type;
+
+ var scope = GetMetadataScope (module, type_info);
+ type = CreateReference (type_info, module, scope);
+
+ return CreateSpecs (type, type_info);
+ }
+
+ static TypeReference CreateSpecs (TypeReference type, Type type_info)
+ {
+ type = TryCreateGenericInstanceType (type, type_info);
+
+ var specs = type_info.specs;
+ if (specs.IsNullOrEmpty ())
+ return type;
+
+ for (int i = 0; i < specs.Length; i++) {
+ switch (specs [i]) {
+ case Type.Ptr:
+ type = new PointerType (type);
+ break;
+ case Type.ByRef:
+ type = new ByReferenceType (type);
+ break;
+ case Type.SzArray:
+ type = new ArrayType (type);
+ break;
+ default:
+ var array = new ArrayType (type);
+ array.Dimensions.Clear ();
+
+ for (int j = 0; j < specs [i]; j++)
+ array.Dimensions.Add (new ArrayDimension ());
+
+ type = array;
+ break;
+ }
+ }
+
+ return type;
+ }
+
+ static TypeReference TryCreateGenericInstanceType (TypeReference type, Type type_info)
+ {
+ var generic_arguments = type_info.generic_arguments;
+ if (generic_arguments.IsNullOrEmpty ())
+ return type;
+
+ var instance = new GenericInstanceType (type);
+ for (int i = 0; i < generic_arguments.Length; i++)
+ instance.GenericArguments.Add (GetTypeReference (type.Module, generic_arguments [i]));
+
+ return instance;
+ }
+
+ static TypeReference CreateReference (Type type_info, ModuleDefinition module, IMetadataScope scope)
+ {
+ string @namespace, name, fullname = type_info.type_fullname;
+ var last_dot = fullname.LastIndexOf ('.');
+
+ if (last_dot == -1) {
+ @namespace = string.Empty;
+ name = fullname;
+ } else {
+ @namespace = fullname.Substring (0, last_dot);
+ name = fullname.Substring (last_dot + 1);
+ }
+
+ var type = new TypeReference (@namespace, name, scope) {
+ module = module,
+ };
+
+ var nested_names = type_info.nested_names;
+ if (nested_names.IsNullOrEmpty ())
+ return type;
+
+ for (int i = 0; i < nested_names.Length; i++) {
+ type = new TypeReference (string.Empty, nested_names [i], null) {
+ DeclaringType = type,
+ module = module,
+ };
+ }
+
+ return type;
+ }
+
+ static IMetadataScope GetMetadataScope (ModuleDefinition module, Type type_info)
+ {
+ if (string.IsNullOrEmpty (type_info.assembly))
+ return module.TypeSystem.Corlib;
+
+ return MatchReference (module, AssemblyNameReference.Parse (type_info.assembly));
+ }
+
+ static AssemblyNameReference MatchReference (ModuleDefinition module, AssemblyNameReference pattern)
+ {
+ var references = module.AssemblyReferences;
+
+ for (int i = 0; i < references.Count; i++) {
+ var reference = references [i];
+ if (reference.FullName == pattern.FullName)
+ return reference;
+ }
+
+ return pattern;
+ }
+
+ static bool TryGetDefinition (ModuleDefinition module, Type type_info, out TypeReference type)
+ {
+ type = null;
+ if (!string.IsNullOrEmpty (type_info.assembly))
+ return false;
+
+ var typedef = module.GetType (type_info.type_fullname);
+ if (typedef == null)
+ return false;
+
+ var nested_names = type_info.nested_names;
+ for (int i = 0; i < nested_names.Length; i++)
+ typedef = typedef.GetNestedType (nested_names [i]);
+
+ type = typedef;
+ return true;
+ }
+ }
+}