PageRenderTime 20ms CodeModel.GetById 12ms app.highlight 6ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_Main/Languages/Ruby/Ruby/Compiler/Generation/RubyTypeDispenser.cs

#
C# | 153 lines | 116 code | 21 blank | 16 comment | 9 complexity | f6d2e256e588bab32103b243218e4427 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Apache License, Version 2.0, please send an email to 
  8 * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Apache License, Version 2.0.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16using System;
 17using System.Collections.Generic;
 18using System.Diagnostics;
 19using System.Reflection.Emit;
 20using System.Text;
 21using System.Threading;
 22using Microsoft.Scripting;
 23using Microsoft.Scripting.Generation;
 24using Microsoft.Scripting.Utils;
 25using IronRuby.Builtins;
 26using IronRuby.Runtime;
 27using System.Globalization;
 28
 29namespace IronRuby.Compiler.Generation {
 30    internal static class RubyTypeDispenser {
 31        private static readonly Publisher<TypeDescription/*!*/, Type/*!*/>/*!*/ _newTypes;
 32        private static readonly Dictionary<Type/*!*/, IList<ITypeFeature/*!*/>/*!*/>/*!*/ _typeFeatures;
 33        private static readonly ITypeFeature/*!*/[]/*!*/ _defaultFeatures = new ITypeFeature[2] {
 34            RubyTypeBuilder.Feature,
 35            InterfacesBuilder.MakeFeature(Type.EmptyTypes)
 36        };
 37
 38        static RubyTypeDispenser() {
 39            _newTypes = new Publisher<TypeDescription, Type>();
 40            _typeFeatures = new Dictionary<Type, IList<ITypeFeature>>();
 41
 42            AddBuiltinType(typeof(object), typeof(RubyObject), false);
 43            AddBuiltinType(typeof(MutableString), typeof(MutableString.Subclass), true);
 44            AddBuiltinType(typeof(Proc), typeof(Proc.Subclass), true);
 45            AddBuiltinType(typeof(RubyRegex), typeof(RubyRegex.Subclass), true);
 46            AddBuiltinType(typeof(Range), typeof(Range.Subclass), true);
 47            AddBuiltinType(typeof(Hash), typeof(Hash.Subclass), true);
 48            AddBuiltinType(typeof(RubyArray), typeof(RubyArray.Subclass), true);
 49            AddBuiltinType(typeof(MatchData), typeof(MatchData.Subclass), true);
 50            AddBuiltinType(typeof(RubyIO), typeof(RubyIO.Subclass), true);
 51        }
 52
 53        internal static Type/*!*/ GetOrCreateType(Type/*!*/ baseType, IList<Type/*!*/>/*!*/ interfaces, bool noOverrides) {
 54            Assert.NotNull(baseType);
 55            Assert.NotNull(interfaces);
 56
 57            ITypeFeature[] features;
 58            if (interfaces.Count == 0) {
 59                features = _defaultFeatures;
 60            } else {
 61                features = new ITypeFeature[2] {
 62                    RubyTypeBuilder.Feature,
 63                    InterfacesBuilder.MakeFeature(interfaces)
 64                };
 65            }
 66            noOverrides |= typeof(IRubyType).IsAssignableFrom(baseType);
 67
 68            TypeDescription typeInfo = new TypeDescription(baseType, features, noOverrides);
 69            Type type = _newTypes.GetOrCreateValue(typeInfo,
 70                delegate() {
 71                    if (TypeImplementsFeatures(baseType, features)) {
 72                        return baseType;
 73                    }
 74                    return CreateType(typeInfo);
 75                });
 76
 77            Debug.Assert(typeof(IRubyObject).IsAssignableFrom(type));
 78            return type;
 79        }
 80
 81        internal static bool TryGetFeatures(Type/*!*/ type, out IList<ITypeFeature/*!*/> features) {
 82            lock (_typeFeatures) {
 83                return _typeFeatures.TryGetValue(type, out features);
 84            }
 85        }
 86
 87        private static bool TypeImplementsFeatures(Type/*!*/ type, IList<ITypeFeature/*!*/>/*!*/ features) {
 88            IList<ITypeFeature> featuresFound;
 89            if (TryGetFeatures(type, out featuresFound)) {
 90                return TypeDescription.FeatureSetsMatch(features, featuresFound);
 91            }
 92
 93            foreach (ITypeFeature feature in features) {
 94                if (!feature.IsImplementedBy(type)) {
 95                    return false;
 96                }
 97            }
 98            return true;
 99        }
100
101        private static Type CreateType(TypeDescription/*!*/ typeInfo) {
102            Type baseType = typeInfo.BaseType;
103            if (baseType.IsSealed) {
104                throw new NotSupportedException(
105                    String.Format(CultureInfo.InvariantCulture, "Can't inherit from a sealed type {0}.",
106                    RubyContext.GetQualifiedNameNoLock(baseType, null, false))
107                );
108            }
109
110            string typeName = GetName(baseType);
111            TypeBuilder tb = Snippets.Shared.DefinePublicType(typeName, baseType);
112            Utils.Log(typeName, "TYPE_BUILDER");
113
114            IFeatureBuilder[] features = new IFeatureBuilder[typeInfo.Features.Count];
115            RubyTypeEmitter emitter = new RubyTypeEmitter(tb);
116
117            for (int i = 0; i < typeInfo.Features.Count; i++) {
118                features[i] = typeInfo.Features[i].MakeBuilder(tb);
119            }
120
121            foreach (IFeatureBuilder feature in features) {
122                feature.Implement(emitter);
123            }
124
125            if (!typeInfo.NoOverrides) {
126                emitter.OverrideMethods(baseType);
127            }
128
129            Type result = emitter.FinishType();
130            lock (_typeFeatures) {
131                _typeFeatures.Add(result, typeInfo.Features);
132            }
133            return result;
134        }
135
136        private static string GetName(Type/*!*/ baseType) {
137            // DLR appends a counter, so we don't need to
138            // TODO: Reflect feature set in the name?
139            StringBuilder name = new StringBuilder("IronRuby.Classes.");
140            name.Append(baseType.Name);
141            return name.ToString();
142        }
143
144        private static void AddBuiltinType(Type/*!*/ clsBaseType, Type/*!*/ rubyType, bool noOverrides) {
145            AddBuiltinType(clsBaseType, rubyType, _defaultFeatures, noOverrides);
146        }
147
148        private static void AddBuiltinType(Type/*!*/ clsBaseType, Type/*!*/ rubyType, ITypeFeature/*!*/[]/*!*/ features, bool noOverrides) {
149            _newTypes.GetOrCreateValue(new TypeDescription(clsBaseType, features, noOverrides), () => rubyType);
150            _typeFeatures[rubyType] = features;
151        }
152    }
153}