From 2f31eb60cb5f0cad3474df48cfc36088cce17769 Mon Sep 17 00:00:00 2001 From: Jim Deville Date: Tue, 14 Apr 2009 10:59:04 -0700 Subject: [PATCH] syncing to head of tfs --- .../IronPython/IronPython.Modules/thread.cs | 2 +- .../Ruby/Experimental/Interop/com.rb | 39 ++ .../IronRuby.Tests/Runtime/HostingTests.cs | 18 +- .../Builtins/KernelOps.cs | 13 +- .../Builtins/ModuleOps.cs | 22 +- .../Extensions/IronRubyOps.cs | 33 -- Merlin/Main/Languages/Ruby/Ruby.sln | 21 +- .../Languages/Ruby/Ruby/Builtins/Proc.Meta.cs | 2 +- .../Ruby/Ruby/Builtins/RubyEvent.Meta.cs | 4 +- .../Ruby/Ruby/Builtins/RubyMethod.Meta.cs | 4 +- .../Ruby/Ruby/Builtins/RubyModule.Meta.cs | 2 +- .../Ruby/Ruby/Builtins/RubyModule.cs | 20 +- .../Ruby/Ruby/Builtins/RubyObject.Meta.cs | 2 +- .../Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs | 16 +- .../Compiler/ReflectionCache.Generated.cs | 10 +- Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj | 38 +- .../Ruby/Ruby/Runtime/BlockParam.Meta.cs | 2 +- .../Calls/CompositeConversionAction.cs | 5 +- .../Ruby/Runtime/Calls/ConvertToSAction.cs | 21 +- .../Ruby/Ruby/Runtime/Calls/InteropBinder.cs | 338 +++++++++++++++++- .../Ruby/Runtime/Calls/MetaObjectBuilder.cs | 18 +- .../Runtime/Calls/ProtocolConversionAction.cs | 32 +- .../Ruby/Ruby/Runtime/Calls/RubyCallAction.cs | 81 +++-- .../Ruby/Ruby/Runtime/Calls/RubyMemberInfo.cs | 3 + .../Ruby/Ruby/Runtime/Calls/RubyMetaBinder.cs | 57 ++- .../Ruby/Ruby/Runtime/Calls/RubyMetaObject.cs | 3 + .../Ruby/Runtime/Calls/SuperCallAction.cs | 12 +- .../Ruby/Ruby/Runtime/RubyContext.cs | 29 ++ .../Languages/Ruby/Ruby/Runtime/RubyOps.cs | 11 +- .../Main/Languages/Ruby/Ruby/Runtime/Utils.cs | 22 +- Merlin/Main/Languages/Ruby/context.rb | 2 +- .../ComInterop/TypeLibMetaObject.cs | 21 +- .../Generation/CompilerHelpers.cs | 5 +- .../src/Dynamic/System.Dynamic.asmmeta_ignore | 3 + 34 files changed, 720 insertions(+), 191 deletions(-) create mode 100644 Merlin/Main/Languages/Ruby/Experimental/Interop/com.rb create mode 100644 ndp/fx/src/Dynamic/System.Dynamic.asmmeta_ignore diff --git a/Merlin/Main/Languages/IronPython/IronPython.Modules/thread.cs b/Merlin/Main/Languages/IronPython/IronPython.Modules/thread.cs index 8fa536147c..1cf1527b41 100644 --- a/Merlin/Main/Languages/IronPython/IronPython.Modules/thread.cs +++ b/Merlin/Main/Languages/IronPython/IronPython.Modules/thread.cs @@ -262,7 +262,7 @@ public class _local { /// the thread. /// private class ThreadLocalDictionaryStorage : DictionaryStorage { - private readonly ThreadLocal _storage = new ThreadLocal(); + private readonly Microsoft.Scripting.Utils.ThreadLocal _storage = new Microsoft.Scripting.Utils.ThreadLocal(); public override void Add(object key, object value) { GetStorage().Add(key, value); diff --git a/Merlin/Main/Languages/Ruby/Experimental/Interop/com.rb b/Merlin/Main/Languages/Ruby/Experimental/Interop/com.rb new file mode 100644 index 0000000000..1a2f28be05 --- /dev/null +++ b/Merlin/Main/Languages/Ruby/Experimental/Interop/com.rb @@ -0,0 +1,39 @@ +class WIN32OLE + def initialize progIdOrClsId + if progIdOrClsId.is_a? System::Guid + type = System::Type.GetTypeFromCLSID(progIdOrClsId) + raise "Unknown CLSID #{progIdOrClsId}" if type.nil? + elsif WIN32OLE.is_guid progIdOrClsId + type = System::Type.GetTypeFromCLSID(System::Guid.new(progIdOrClsId)) + raise "Unknown CLSID #{progIdOrClsId}" if type.nil? + else + type = System::Type.GetTypeFromProgID(progIdOrClsId) + raise "Unknown PROGID '#{progIdOrClsId}'" if type.nil? + end + @com_object = System::Activator.CreateInstance(type) + end + + def self.is_guid(str) + !!(/[{]?[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}[}]?|[0-9A-F]{32}/ =~ str) + end + + def method_missing name, *args + @com_object.send(name, *args) + end + + attr_reader :com_object +end + +ex = WIN32OLE.new("Excel.Application") +#ex = WIN32OLE.new("{00024500-0000-0000-C000-000000000046}") + +ex.Visible = true +nb = ex.Workbooks.Add +ws = nb.Worksheets[1] +p ws.Name + +10.times do |i| + 10.times do |j| + ws.Cells[i + 1, j + 1] = (i + 1) * (j + 1) + end +end diff --git a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/HostingTests.cs b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/HostingTests.cs index d8dc62c814..702d151dbf 100644 --- a/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/HostingTests.cs +++ b/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/HostingTests.cs @@ -358,17 +358,25 @@ print ruby() py.Execute(@" def get_python_class(): class C(object): + x = 123 def __str__(self): return 'this is C' + return C() ", scope); - AssertOutput(() => Engine.Execute(@" -p get_python_class.call -", scope), @" -this is C -"); + Engine.Execute(@"self.c = get_python_class.call", scope); + + var s = Engine.Execute(@"c.to_str", scope); + Assert(s.ToString() == @"this is C"); + + var i = Engine.Execute(@"c.x", scope); + Assert(i == 123); + + // TODO: test + // c.y, where y is a delegate + // c.p, where p is a Ruby Proc } public void PythonInterop5() { diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs index 165ae75129..7c888908fe 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/KernelOps.cs @@ -1380,12 +1380,21 @@ internal ThrowCatchUnwinder(string/*!*/ label, object returnValue) // thread-safe: [RubyMethod("methods")] public static RubyArray/*!*/ GetMethods(RubyContext/*!*/ context, object self, [DefaultParameterValue(true)]bool inherited) { + var foreignMembers = context.GetForeignDynamicMemberNames(self); + RubyClass immediateClass = context.GetImmediateClassOf(self); if (!inherited && !immediateClass.IsSingletonClass) { - return new RubyArray(); + var result = new RubyArray(); + if (foreignMembers.Count > 0) { + var symbolicNames = context.RubyOptions.Compatibility > RubyCompatibility.Ruby18; + foreach (var name in foreignMembers) { + result.Add(ModuleOps.CreateMethodName(name, symbolicNames)); + } + } + return result; } - return ModuleOps.GetMethods(immediateClass, inherited, RubyMethodAttributes.Public | RubyMethodAttributes.Protected); + return ModuleOps.GetMethods(immediateClass, inherited, RubyMethodAttributes.Public | RubyMethodAttributes.Protected, foreignMembers); } // thread-safe: diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs index 5ba0d1fdf6..1871555d9d 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs @@ -786,21 +786,31 @@ public static class ModuleOps { } internal static RubyArray/*!*/ GetMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes) { + return GetMethods(self, inherited, attributes, null); + } + + internal static RubyArray/*!*/ GetMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes, + IEnumerable foreignMembers) { + var result = new RubyArray(); var symbolicNames = self.Context.RubyOptions.Compatibility > RubyCompatibility.Ruby18; using (self.Context.ClassHierarchyLocker()) { - self.ForEachMember(inherited, attributes, delegate(string/*!*/ name, RubyMemberInfo member) { - if (symbolicNames) { - result.Add(SymbolTable.StringToId(name)); - } else { - result.Add(MutableString.Create(name)); - } + self.ForEachMember(inherited, attributes, foreignMembers, delegate(string/*!*/ name, RubyMemberInfo member) { + result.Add(CreateMethodName(name, symbolicNames)); }); } return result; } + internal static object CreateMethodName(string/*!*/ name, bool symbolicNames) { + if (symbolicNames) { + return SymbolTable.StringToId(name); + } else { + return MutableString.Create(name); + } + } + #endregion #region {private_|protected_|public_|}method_defined? (thread-safe) diff --git a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IronRubyOps.cs b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IronRubyOps.cs index abc71edcbc..445026e061 100644 --- a/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IronRubyOps.cs +++ b/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Extensions/IronRubyOps.cs @@ -31,39 +31,6 @@ public static class IronRubyOps { [RubyModule("Clr")] public static class ClrOps { - - //[RubyConstant("String")] - //public static RubyModule/*!*/ GetClrStringModule(RubyModule/*!*/ module) { - // return GetModule(module, typeof(ClrString)); - //} - - //[RubyConstant("Float")] - //public static RubyModule/*!*/ GetClrFloatModule(RubyModule/*!*/ module) { - // return GetModule(module, typeof(ClrFloat)); - //} - - //[RubyConstant("Integer")] - //public static RubyModule/*!*/ GetClrIntegerModule(RubyModule/*!*/ module) { - // return GetModule(module, typeof(ClrInteger)); - //} - - //[RubyConstant("BigInteger")] - //public static RubyModule/*!*/ GetClrBigIntegerModule(RubyModule/*!*/ module) { - // return GetModule(module, typeof(ClrBigInteger)); - //} - - //[RubyConstant("MultiDimensionalArray")] - //public static RubyModule/*!*/ GetMultiDimensionalArrayModule(RubyModule/*!*/ module) { - // return GetModule(module, typeof(MultiDimensionalArray)); - //} - - //private static RubyModule/*!*/ GetModule(RubyModule/*!*/ declaringModule, Type/*!*/ type) { - // RubyModule result; - // declaringModule.Context.TryGetModule(type, out result); - // Debug.Assert(result != null); - // return result; - //} - [RubyMethod("profile", RubyMethodAttributes.PublicSingleton)] public static Hash/*!*/ GetProfile(RubyContext/*!*/ context, object self) { if (!((RubyOptions)context.Options).Profile) { diff --git a/Merlin/Main/Languages/Ruby/Ruby.sln b/Merlin/Main/Languages/Ruby/Ruby.sln index f5c19cb692..7d6d3c333d 100644 --- a/Merlin/Main/Languages/Ruby/Ruby.sln +++ b/Merlin/Main/Languages/Ruby/Ruby.sln @@ -11,13 +11,15 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClassInitGenerator", "Class EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Scripting.Core", "..\..\..\..\ndp\fx\src\Core\Microsoft\Scripting\Microsoft.Scripting.Core.csproj", "{2AE75F5A-CD1F-4925-9647-AF4D1C282FB4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Dynamic", "..\..\..\..\ndp\fx\src\Dynamic\System\Dynamic\Microsoft.Dynamic.csproj", "{D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRuby.Libraries", "Libraries.LCA_RESTRICTED\IronRuby.Libraries.csproj", "{77323B06-15A2-4CF4-8A7A-86EAA2B66498}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRuby.Libraries.Scanner", "Utils\IronRuby.Libraries.Scanner\IronRuby.Libraries.Scanner.csproj", "{5F692D9C-968B-48BF-AC2F-6B4F54D9C1BB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Scripting", "..\..\Runtime\Microsoft.Scripting\Microsoft.Scripting.csproj", "{EB66B766-6354-4208-A3D4-AACBDCB5C3B3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRuby.Libraries.Yaml", "..\..\..\External.LCA_RESTRICTED\Languages\IronRuby\yaml\IronRuby.Libraries.Yaml\IronRuby.Libraries.Yaml.csproj", "{AA18A245-E342-4368-A474-83178311A742}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRuby.Libraries.Yaml", "..\..\..\External.LCA_RESTRICTED\Languages\IronRuby\Yaml\IronRuby.Libraries.Yaml\IronRuby.Libraries.Yaml.csproj", "{AA18A245-E342-4368-A474-83178311A742}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Scripting.ExtensionAttribute", "..\..\..\..\ndp\fx\src\Core\Microsoft\Scripting\Microsoft.Scripting.ExtensionAttribute.csproj", "{8B0F1074-750E-4D64-BF23-A1E0F54261E5}" EndProject @@ -34,7 +36,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClrAssembly", "..\..\Test\C EndProject Global GlobalSection(TeamFoundationVersionControl) = preSolution - SccNumberOfProjects = 13 + SccNumberOfProjects = 14 SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} SccTeamFoundationServer = http://vstfdevdiv:8080/ SccLocalPath0 = . @@ -62,7 +64,7 @@ Global SccProjectUniqueName8 = ..\\..\\..\\..\\ndp\\fx\\src\\Core\\Microsoft\\Scripting\\Microsoft.Scripting.Core.csproj SccProjectName8 = ../../../../ndp/fx/src/Core/Microsoft/Scripting SccLocalPath8 = ..\\..\\..\\..\\ndp\\fx\\src\\Core\\Microsoft\\Scripting - SccProjectUniqueName9 = ..\\..\\..\\External.LCA_RESTRICTED\\Languages\\IronRuby\\yaml\\IronRuby.Libraries.Yaml\\IronRuby.Libraries.Yaml.csproj + SccProjectUniqueName9 = ..\\..\\..\\External.LCA_RESTRICTED\\Languages\\IronRuby\\Yaml\\IronRuby.Libraries.Yaml\\IronRuby.Libraries.Yaml.csproj SccProjectName9 = ../../../External.LCA_RESTRICTED/Languages/IronRuby/yaml/IronRuby.Libraries.Yaml SccLocalPath9 = ..\\..\\..\\External.LCA_RESTRICTED\\Languages\\IronRuby\\yaml\\IronRuby.Libraries.Yaml SccProjectUniqueName10 = ..\\..\\..\\..\\ndp\\fx\\src\\Core\\Microsoft\\Scripting\\Microsoft.Scripting.ExtensionAttribute.csproj @@ -74,6 +76,9 @@ Global SccProjectUniqueName12 = ..\\..\\Test\\ClrAssembly\\ClrAssembly.csproj SccProjectName12 = ../../Test/ClrAssembly SccLocalPath12 = ..\\..\\Test\\ClrAssembly + SccProjectUniqueName13 = ..\\..\\..\\..\\ndp\\fx\\src\\Dynamic\\System\\Dynamic\\Microsoft.Dynamic.csproj + SccProjectName13 = ../../../../ndp/fx/src/Dynamic/System/Dynamic + SccLocalPath13 = ..\\..\\..\\..\\ndp\\fx\\src\\Dynamic\\System\\Dynamic EndGlobalSection GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = Ruby.vsmdi @@ -130,6 +135,16 @@ Global {2AE75F5A-CD1F-4925-9647-AF4D1C282FB4}.Silverlight Debug|Any CPU.Build.0 = Silverlight Debug|Any CPU {2AE75F5A-CD1F-4925-9647-AF4D1C282FB4}.Silverlight Release|Any CPU.ActiveCfg = Silverlight Release|Any CPU {2AE75F5A-CD1F-4925-9647-AF4D1C282FB4}.Silverlight Release|Any CPU.Build.0 = Silverlight Release|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.FxCop|Any CPU.ActiveCfg = FxCop|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.FxCop|Any CPU.Build.0 = FxCop|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Release|Any CPU.Build.0 = Release|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Silverlight Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Silverlight Debug|Any CPU.Build.0 = Debug|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Silverlight Release|Any CPU.ActiveCfg = Release|Any CPU + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D}.Silverlight Release|Any CPU.Build.0 = Release|Any CPU {77323B06-15A2-4CF4-8A7A-86EAA2B66498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {77323B06-15A2-4CF4-8A7A-86EAA2B66498}.Debug|Any CPU.Build.0 = Debug|Any CPU {77323B06-15A2-4CF4-8A7A-86EAA2B66498}.FxCop|Any CPU.ActiveCfg = Release|Any CPU diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.Meta.cs index 6af9504e30..fedbd06950 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/Proc.Meta.cs @@ -28,7 +28,7 @@ namespace IronRuby.Builtins { - public partial class Proc : IDynamicMetaObjectProvider { + public partial class Proc : IRubyDynamicMetaObjectProvider { public DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyEvent.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyEvent.Meta.cs index 6a56236593..5c170f7f30 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyEvent.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyEvent.Meta.cs @@ -28,8 +28,8 @@ namespace IronRuby.Builtins { using Ast = System.Linq.Expressions.Expression; - - public partial class RubyEvent : IDynamicMetaObjectProvider { + + public partial class RubyEvent : IRubyDynamicMetaObjectProvider { public DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyMethod.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyMethod.Meta.cs index 6dc983fd44..2e614e3fde 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyMethod.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyMethod.Meta.cs @@ -28,8 +28,8 @@ namespace IronRuby.Builtins { using Ast = System.Linq.Expressions.Expression; - - public partial class RubyMethod : IDynamicMetaObjectProvider { + + public partial class RubyMethod : IRubyDynamicMetaObjectProvider { public DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.Meta.cs index 6d049e9fff..606ebdcd30 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.Meta.cs @@ -23,7 +23,7 @@ namespace IronRuby.Builtins { - public partial class RubyModule : IDynamicMetaObjectProvider { + public partial class RubyModule : IRubyDynamicMetaObjectProvider { public virtual DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs index c9456a882e..fc85297b49 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyModule.cs @@ -158,6 +158,10 @@ private enum MemberTableState { get { return false; } } + public bool IsComClass { + get { return ReferenceEquals(this, Context.ComObjectClass); } + } + internal virtual RubyClass GetSuperClass() { return null; } @@ -1375,7 +1379,9 @@ private enum ConstantLookupResult { /// /// Not thread safe. /// - public void ForEachMember(bool inherited, RubyMethodAttributes attributes, Action/*!*/ action) { + public void ForEachMember(bool inherited, RubyMethodAttributes attributes, IEnumerable foreignMembers, + Action/*!*/ action) { + Context.RequiresClassHierarchyLock(); var visited = new Dictionary(); @@ -1385,6 +1391,14 @@ private enum ConstantLookupResult { bool instanceMethods = (attributes & RubyMethodAttributes.Instance) != 0; bool singletonMethods = (attributes & RubyMethodAttributes.Singleton) != 0; + // TODO: if we allow creating singletons for foreign objects we need to change this: + if (foreignMembers != null) { + foreach (var name in foreignMembers) { + action(name, RubyMethodInfo.ForeignMember); + visited.Add(name, true); + } + } + bool stop = false; ForEachInstanceMethod(true, delegate(RubyModule/*!*/ module, string name, RubyMemberInfo member) { @@ -1416,6 +1430,10 @@ private enum ConstantLookupResult { }); } + public void ForEachMember(bool inherited, RubyMethodAttributes attributes, Action/*!*/ action) { + ForEachMember(inherited, attributes, null, action); + } + #endregion #region Class variables (TODO: thread-safety) diff --git a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyObject.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyObject.Meta.cs index 8b2c3552a6..2f66a68b03 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyObject.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Builtins/RubyObject.Meta.cs @@ -24,7 +24,7 @@ namespace IronRuby.Builtins { - public partial class RubyObject : IDynamicMetaObjectProvider { + public partial class RubyObject : IRubyDynamicMetaObjectProvider { public virtual DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs index 51243a130b..f4191da119 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/SourceUnitTree.cs @@ -115,6 +115,10 @@ public partial class SourceUnitTree : Node { moduleVariable = null; } + if (_statements.Count == 0) { + return Ast.Lambda(AstUtils.Constant(null), parameters); + } + gen.EnterSourceUnit( scope, selfVariable, @@ -198,14 +202,14 @@ public partial class SourceUnitTree : Node { body = gen.AddReturnTarget(scope.CreateScope(body)); gen.LeaveSourceUnit(); - return Ast.Lambda( - body, - RubyExceptionData.EncodeMethodName(gen.SourceUnit, RubyExceptionData.TopLevelMethodName, SourceSpan.None), - parameters - ); + return Ast.Lambda(body, GetEncodedName(gen), parameters); + } + + private static string/*!*/ GetEncodedName(AstGenerator/*!*/ gen) { + return RubyExceptionData.EncodeMethodName(gen.SourceUnit, RubyExceptionData.TopLevelMethodName, SourceSpan.None); } - private static MSA.Expression GenerateCheckForAsyncException(ScopeBuilder scope, MSA.Expression runtimeScopeVariable, MSA.Expression body) { + private static MSA.Expression/*!*/ GenerateCheckForAsyncException(ScopeBuilder scope, MSA.Expression runtimeScopeVariable, MSA.Expression body) { MSA.ParameterExpression exception = scope.DefineHiddenVariable("#exception", typeof(System.Threading.ThreadAbortException)); MSA.CatchBlock handler = Ast.Catch(exception, Ast.Call( diff --git a/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs b/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs index 7f0706c212..26623acd4f 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Compiler/ReflectionCache.Generated.cs @@ -180,6 +180,8 @@ internal static partial class Methods { private static MethodInfo _EvalReturn; public static MethodInfo/*!*/ EvalYield { get { return _EvalYield ?? (_EvalYield = GetMethod(typeof(RubyOps), "EvalYield")); } } private static MethodInfo _EvalYield; + public static MethodInfo/*!*/ ExistsUnsplat { get { return _ExistsUnsplat ?? (_ExistsUnsplat = GetMethod(typeof(RubyOps), "ExistsUnsplat")); } } + private static MethodInfo _ExistsUnsplat; public static MethodInfo/*!*/ GetArrayItem { get { return _GetArrayItem ?? (_GetArrayItem = GetMethod(typeof(RubyOps), "GetArrayItem")); } } private static MethodInfo _GetArrayItem; public static MethodInfo/*!*/ GetArraySuffix { get { return _GetArraySuffix ?? (_GetArraySuffix = GetMethod(typeof(RubyOps), "GetArraySuffix")); } } @@ -320,6 +322,8 @@ internal static partial class Methods { private static MethodInfo _MethodRetry; public static MethodInfo/*!*/ MethodYield { get { return _MethodYield ?? (_MethodYield = GetMethod(typeof(RubyOps), "MethodYield")); } } private static MethodInfo _MethodYield; + public static MethodInfo/*!*/ ObjectToMutableString { get { return _ObjectToMutableString ?? (_ObjectToMutableString = GetMethod(typeof(RubyOps), "ObjectToMutableString")); } } + private static MethodInfo _ObjectToMutableString; public static MethodInfo/*!*/ PrintInteractiveResult { get { return _PrintInteractiveResult ?? (_PrintInteractiveResult = GetMethod(typeof(RubyOps), "PrintInteractiveResult")); } } private static MethodInfo _PrintInteractiveResult; public static MethodInfo/*!*/ PropagateRetrySingleton { get { return _PropagateRetrySingleton ?? (_PropagateRetrySingleton = GetMethod(typeof(RubyOps), "PropagateRetrySingleton")); } } @@ -352,6 +356,8 @@ internal static partial class Methods { private static MethodInfo _SplatAppend; public static MethodInfo/*!*/ SplatPair { get { return _SplatPair ?? (_SplatPair = GetMethod(typeof(RubyOps), "SplatPair")); } } private static MethodInfo _SplatPair; + public static MethodInfo/*!*/ StringToMutableString { get { return _StringToMutableString ?? (_StringToMutableString = GetMethod(typeof(RubyOps), "StringToMutableString")); } } + private static MethodInfo _StringToMutableString; public static MethodInfo/*!*/ ToArrayValidator { get { return _ToArrayValidator ?? (_ToArrayValidator = GetMethod(typeof(RubyOps), "ToArrayValidator")); } } private static MethodInfo _ToArrayValidator; public static MethodInfo/*!*/ ToFixnumValidator { get { return _ToFixnumValidator ?? (_ToFixnumValidator = GetMethod(typeof(RubyOps), "ToFixnumValidator")); } } @@ -362,8 +368,6 @@ internal static partial class Methods { private static MethodInfo _ToHashValidator; public static MethodInfo/*!*/ ToIntegerValidator { get { return _ToIntegerValidator ?? (_ToIntegerValidator = GetMethod(typeof(RubyOps), "ToIntegerValidator")); } } private static MethodInfo _ToIntegerValidator; - public static MethodInfo/*!*/ ToMutableString { get { return _ToMutableString ?? (_ToMutableString = GetMethod(typeof(RubyOps), "ToMutableString")); } } - private static MethodInfo _ToMutableString; public static MethodInfo/*!*/ ToProcValidator { get { return _ToProcValidator ?? (_ToProcValidator = GetMethod(typeof(RubyOps), "ToProcValidator")); } } private static MethodInfo _ToProcValidator; public static MethodInfo/*!*/ ToRegexValidator { get { return _ToRegexValidator ?? (_ToRegexValidator = GetMethod(typeof(RubyOps), "ToRegexValidator")); } } @@ -382,8 +386,6 @@ internal static partial class Methods { private static MethodInfo _TraceMethodCall; public static MethodInfo/*!*/ TraceMethodReturn { get { return _TraceMethodReturn ?? (_TraceMethodReturn = GetMethod(typeof(RubyOps), "TraceMethodReturn")); } } private static MethodInfo _TraceMethodReturn; - public static MethodInfo/*!*/ ExistsUnsplat { get { return _ExistsUnsplat ?? (_ExistsUnsplat = GetMethod(typeof(RubyOps), "ExistsUnsplat")); } } - private static MethodInfo _ExistsUnsplat; public static MethodInfo/*!*/ TryGetClassVariable { get { return _TryGetClassVariable ?? (_TryGetClassVariable = GetMethod(typeof(RubyOps), "TryGetClassVariable")); } } private static MethodInfo _TryGetClassVariable; public static MethodInfo/*!*/ TryGetObjectClassVariable { get { return _TryGetObjectClassVariable ?? (_TryGetObjectClassVariable = GetMethod(typeof(RubyOps), "TryGetObjectClassVariable")); } } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj b/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj index 1fd2d25692..48f1375ce2 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj +++ b/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj @@ -77,11 +77,13 @@ + + + False $(SilverlightSdkPath)\mscorlib.dll - False $(SilverlightSdkPath)\System.Net.dll @@ -90,8 +92,23 @@ False $(SilverlightSdkPath)\System.dll - - + + {D4AE44AD-07B9-41DC-BB3B-1FDCDE3C987D} + System.Dynamic + + + {2AE75F5A-CD1F-4925-9647-AF4D1C282FB4} + Microsoft.Scripting.Core + False + + + {8B0F1074-750E-4D64-BF23-A1E0F54261E5} + Microsoft.Scripting.ExtensionAttribute + + + {EB66B766-6354-4208-A3D4-AACBDCB5C3B3} + Microsoft.Scripting + @@ -344,21 +361,6 @@ - - - {2AE75F5A-CD1F-4925-9647-AF4D1C282FB4} - Microsoft.Scripting.Core - False - - - {8B0F1074-750E-4D64-BF23-A1E0F54261E5} - Microsoft.Scripting.ExtensionAttribute - - - {EB66B766-6354-4208-A3D4-AACBDCB5C3B3} - Microsoft.Scripting - - diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.Meta.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.Meta.cs index 5e5cde9b09..2b56048a19 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.Meta.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/BlockParam.Meta.cs @@ -29,7 +29,7 @@ using System.Reflection; namespace IronRuby.Runtime { - public sealed partial class BlockParam : IDynamicMetaObjectProvider { + public sealed partial class BlockParam : IRubyDynamicMetaObjectProvider { public DynamicMetaObject/*!*/ GetMetaObject(Expression/*!*/ parameter) { return new Meta(parameter, BindingRestrictions.Empty, this); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/CompositeConversionAction.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/CompositeConversionAction.cs index 2082760905..d22e136594 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/CompositeConversionAction.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/CompositeConversionAction.cs @@ -22,6 +22,7 @@ using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; using Ast = System.Linq.Expressions.Expression; +using System.Diagnostics; namespace IronRuby.Runtime.Calls { public enum CompositeConversion { @@ -86,8 +87,10 @@ private CompositeConversionAction(CompositeConversion conversion, Type/*!*/ resu return Methods.GetMethod(GetType(), "MakeShared").OpCall(Ast.Constant(_conversion)); } - protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { + protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { + Debug.Assert(defaultFallback, "custom fallback not supported"); ProtocolConversionAction.BuildConversion(metaBuilder, args, _resultType, _conversions); + return true; } public override string/*!*/ ToString() { diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ConvertToSAction.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ConvertToSAction.cs index 725ef4b12c..46bd193873 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ConvertToSAction.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ConvertToSAction.cs @@ -24,6 +24,8 @@ using AstUtils = Microsoft.Scripting.Ast.Utils; using System.Dynamic; using System.Reflection; +using System.Diagnostics; +using System.Collections.Generic; namespace IronRuby.Runtime.Calls { @@ -48,12 +50,19 @@ public sealed class ConvertToSAction : RubyConversionAction, IExpressionSerializ return Methods.GetMethod(GetType(), "MakeShared").OpCall(); } - protected override ConvertBinder/*!*/ GetInteropBinder(RubyContext/*!*/ context, out MethodInfo postConverter) { - postConverter = Methods.ToMutableString; - return new InteropBinder.Convert(context, typeof(string), false); + protected override DynamicMetaObjectBinder/*!*/ GetInteropBinder(RubyContext/*!*/ context, IList/*!*/ args, + out MethodInfo postConverter) { + postConverter = Methods.StringToMutableString; + return new InteropBinder.InvokeMember(context, "ToString", new CallInfo(0)); } - protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { + protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { + Debug.Assert(defaultFallback, "custom fallback not supported"); + BuildConversion(metaBuilder, args); + return true; + } + + internal static void BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { const string ToS = "to_s"; // no conversion for a subclass of string: @@ -89,8 +98,8 @@ public sealed class ConvertToSAction : RubyConversionAction, IExpressionSerializ } metaBuilder.Result = Methods.ToSDefaultConversion.OpCall( - AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), - AstFactory.Box(args.TargetExpression), + AstUtils.Convert(args.MetaContext.Expression, typeof(RubyContext)), + AstFactory.Box(args.TargetExpression), AstFactory.Box(metaBuilder.Result) ); } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/InteropBinder.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/InteropBinder.cs index 2faca475fb..75b259afb8 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/InteropBinder.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/InteropBinder.cs @@ -25,10 +25,16 @@ using AstUtils = Microsoft.Scripting.Ast.Utils; using Ast = System.Linq.Expressions.Expression; using IronRuby.Builtins; +using Microsoft.Scripting.Runtime; namespace IronRuby.Runtime.Calls { + internal interface IInteropBinder { + Type/*!*/ ResultType { get; } + RubyContext Context { get; } + } + internal static class InteropBinder { - internal sealed class CreateInstance : CreateInstanceBinder { + internal sealed class CreateInstance : CreateInstanceBinder, IInteropBinder { private readonly RubyContext/*!*/ _context; internal CreateInstance(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) @@ -37,26 +43,122 @@ internal CreateInstance(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) _context = context; } + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + public override DynamicMetaObject/*!*/ FallbackCreateInstance(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { - return CreateErrorMetaObject(target, args, errorSuggestion); + // target is not instantiable meta-object + + // TODO: + // if target.LimitType == System.Type + // new {target}(args) + // else + + // invoke "new" method: + return new DynamicMetaObject( + Ast.Dynamic(new InvokeMember(_context, "new", CallInfo), typeof(object), target.Expression), + target.Restrictions.Merge(BindingRestrictions.Combine(args)) + ); + } + + public override string/*!*/ ToString() { + return String.Format("Interop.CreateInstance({0}){1}", + CallInfo.ArgumentCount, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); } } - internal sealed class Invoke : InvokeBinder { + internal sealed class Return : InvokeBinder, IInteropBinder { private readonly RubyContext/*!*/ _context; - internal Invoke(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) + internal Return(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) : base(callInfo) { Assert.NotNull(context); _context = context; } + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + + public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, + DynamicMetaObject errorSuggestion) { + + // Used in combination with GetMember to compose InvokeMember operation. + // Gets here only if the target is not a callable meta-object. + + var metaBuilder = new MetaObjectBuilder(this, target, args); + var callArgs = new CallArguments(_context, target, args, CallInfo); + + metaBuilder.AddTypeRestriction(target.GetLimitType(), target.Expression); + + var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, callArgs, 0, 0); + if (!metaBuilder.Error) { + // no arguments => just return the target: + metaBuilder.Result = target.Expression; + } else { + // any arguments found (expected none): + metaBuilder.SetMetaResult(errorSuggestion, false); + } + + return metaBuilder.CreateMetaObject(this); + } + } + + /// + /// Attempts to invoke the member, falls back to InvokeMember("call") + /// + internal sealed class Invoke : InvokeBinder, IInteropBinder { + private readonly RubyContext/*!*/ _context; + private readonly string/*!*/ _fallbackMethod; + + internal Invoke(RubyContext/*!*/ context, string/*!*/ fallbackMethod, CallInfo/*!*/ callInfo) + : base(callInfo) { + Assert.NotNull(context, fallbackMethod); + _context = context; + _fallbackMethod = fallbackMethod; + } + + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + public override DynamicMetaObject/*!*/ FallbackInvoke(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindInvoke(this, target, args, out result)) { + return result; + } +#endif + // target is not a callable meta-object + + // TODO: target could be a delegate + // if (target.LimitType <: Delegate) then + // invoke delegate + // else: - return CreateErrorMetaObject(target, args, errorSuggestion); + // invoke the fallback method: + return new DynamicMetaObject( + Ast.Dynamic(new InvokeMember(_context, _fallbackMethod, CallInfo), typeof(object), target.Expression), + target.Restrictions.Merge(BindingRestrictions.Combine(args)) + ); } public static DynamicMetaObject/*!*/ Bind(InvokeBinder/*!*/ binder, @@ -73,9 +175,16 @@ internal Invoke(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) buildInvoke(metaBuilder, callArgs); return metaBuilder.CreateMetaObject(binder); } + + public override string/*!*/ ToString() { + return String.Format("Interop.Invoke({0}){1}", + CallInfo.ArgumentCount, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } } - internal sealed class InvokeMember : InvokeMemberBinder { + internal class InvokeMember : InvokeMemberBinder, IInteropBinder { private readonly RubyContext/*!*/ _context; internal InvokeMember(RubyContext/*!*/ context, string/*!*/ name, CallInfo/*!*/ callInfo) @@ -84,15 +193,29 @@ internal InvokeMember(RubyContext/*!*/ context, string/*!*/ name, CallInfo/*!*/ _context = context; } + public virtual Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + #region Ruby -> DLR public override DynamicMetaObject/*!*/ FallbackInvokeMember(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, DynamicMetaObject errorSuggestion) { +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindInvokeMember(this, target, args, out result)) { + return result; + } +#endif - var metaBuilder = new MetaObjectBuilder(target, args); + var metaBuilder = new MetaObjectBuilder(this, target, args); var callArgs = new CallArguments(_context, target, args, CallInfo); - if (!RubyCallAction.Build(metaBuilder, Name, callArgs, errorSuggestion == null)) { + if (!RubyCallAction.BuildCall(metaBuilder, Name, callArgs, errorSuggestion == null)) { Debug.Assert(errorSuggestion != null); // method wasn't found so we didn't do any operation with arguments that would require restrictions converted to conditions: metaBuilder.SetMetaResult(errorSuggestion, false); @@ -108,8 +231,10 @@ internal InvokeMember(RubyContext/*!*/ context, string/*!*/ name, CallInfo/*!*/ exprs[0] = target.Expression; return new DynamicMetaObject( - Expression.Dynamic(new Invoke(_context, CallInfo), typeof(object), exprs), - target.Restrictions.Merge(BindingRestrictions.Combine(args)) + Expression.Dynamic(new Return(_context, CallInfo), typeof(object), exprs), + target.Restrictions.Merge(BindingRestrictions.Combine(args)). + // TODO: ??? + Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.GetLimitType())) ); } @@ -136,16 +261,24 @@ internal InvokeMember(RubyContext/*!*/ context, string/*!*/ name, CallInfo/*!*/ var callArgs = new CallArguments(context, target, args, RubyCallSignature.Simple(callInfo.ArgumentCount)); var metaBuilder = new MetaObjectBuilder(target, args); - if (!RubyCallAction.Build(metaBuilder, methodName, callArgs, false)) { + if (!RubyCallAction.BuildCall(metaBuilder, methodName, callArgs, false)) { metaBuilder.SetMetaResult(fallback(target, args), false); } return metaBuilder.CreateMetaObject(binder); } #endregion + + public override string/*!*/ ToString() { + return String.Format("Interop.InvokeMember({0}, {1}){2}", + Name, + CallInfo.ArgumentCount, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } } - internal sealed class GetMember : GetMemberBinder { + internal sealed class GetMember : GetMemberBinder, IInteropBinder { private readonly RubyContext/*!*/ _context; internal GetMember(RubyContext/*!*/ context, string/*!*/ name) @@ -154,9 +287,23 @@ internal GetMember(RubyContext/*!*/ context, string/*!*/ name) _context = context; } + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + #region Ruby -> DLR public override DynamicMetaObject/*!*/ FallbackGetMember(DynamicMetaObject/*!*/ target, DynamicMetaObject errorSuggestion) { +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindGetMember(this, target, out result)) { + return result; + } +#endif throw new NotImplementedException("TODO"); } @@ -187,9 +334,152 @@ internal GetMember(RubyContext/*!*/ context, string/*!*/ name) } #endregion + + public override string/*!*/ ToString() { + return String.Format("Interop.GetMember({0}){1}", + Name, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } } - internal sealed class Convert : ConvertBinder { + internal sealed class SetMember : SetMemberBinder, IInteropBinder { + private readonly RubyContext/*!*/ _context; + + internal SetMember(RubyContext/*!*/ context, string/*!*/ name) + : base(name, false) { + Assert.NotNull(context); + _context = context; + } + + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + + #region Ruby -> DLR + + public override DynamicMetaObject/*!*/ FallbackSetMember(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/ value, + DynamicMetaObject errorSuggestion) { + +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindSetMember(this, target, value, out result)) { + return result; + } +#endif + throw new NotImplementedException("TODO"); + } + + #endregion + + #region DLR -> Ruby + + // TODO + + #endregion + + public override string/*!*/ ToString() { + return String.Format("Interop.SetMember({0}){1}", + Name, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } + } + + internal sealed class GetIndex : GetIndexBinder, IInteropBinder { + private readonly RubyContext/*!*/ _context; + + internal GetIndex(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) + : base(callInfo) { + Assert.NotNull(context); + _context = context; + } + + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + + #region Ruby -> DLR + + public override DynamicMetaObject/*!*/ FallbackGetIndex(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ indexes, + DynamicMetaObject errorSuggestion) { +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindGetIndex(this, target, indexes, out result)) { + return result; + } +#endif + // TODO: CLR get index + // TODO: invoke + throw new NotImplementedException("TODO"); + } + + #endregion + + public override string/*!*/ ToString() { + return String.Format("Interop.GetIndex({0}){1}", + CallInfo.ArgumentCount, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } + } + + internal sealed class SetIndex : SetIndexBinder, IInteropBinder { + private readonly RubyContext/*!*/ _context; + + internal SetIndex(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) + : base(callInfo) { + Assert.NotNull(context); + _context = context; + } + + public Type/*!*/ ResultType { + get { return typeof(object); } + } + + public RubyContext Context { + get { return _context; } + } + + #region Ruby -> DLR + + public override DynamicMetaObject/*!*/ FallbackSetIndex(DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ indexes, + DynamicMetaObject/*!*/ value, DynamicMetaObject errorSuggestion) { + +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryBindSetIndex(this, target, indexes, value, out result)) { + return result; + } +#endif + throw new NotImplementedException("TODO"); + } + + #endregion + + #region DLR -> Ruby + + // TODO + + #endregion + + public override string/*!*/ ToString() { + return String.Format("Interop.SetIndex({0}){1}", + CallInfo.ArgumentCount, + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } + } + + internal sealed class Convert : ConvertBinder, IInteropBinder { private readonly RubyContext/*!*/ _context; public Convert(RubyContext/*!*/ context, Type/*!*/ type, bool isExplicit) @@ -198,9 +488,31 @@ public Convert(RubyContext/*!*/ context, Type/*!*/ type, bool isExplicit) _context = context; } + public Type/*!*/ ResultType { + get { return Type; } + } + + public RubyContext Context { + get { return _context; } + } + public override DynamicMetaObject/*!*/ FallbackConvert(DynamicMetaObject/*!*/ target, DynamicMetaObject errorSuggestion) { +#if !SILVERLIGHT + DynamicMetaObject result; + if (System.Dynamic.ComBinder.TryConvert(this, target, out result)) { + return result; + } +#endif return CreateErrorMetaObject(target, DynamicMetaObject.EmptyMetaObjects, errorSuggestion); } + + public override string/*!*/ ToString() { + return String.Format("Interop.Convert({0}, {1}){2}", + Type.Name, + Explicit ? "explicit" : "implicit", + (_context != null ? " @" + Context.RuntimeId.ToString() : null) + ); + } } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/MetaObjectBuilder.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/MetaObjectBuilder.cs index 11a2a4268e..c2620cd4a7 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/MetaObjectBuilder.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/MetaObjectBuilder.cs @@ -40,18 +40,26 @@ public sealed class MetaObjectBuilder { private bool _error; private bool _treatRestrictionsAsConditions; - internal MetaObjectBuilder(RubyMetaBinder/*!*/ rubyBinder, DynamicMetaObject/*!*/[]/*!*/ arguments) - : this((DynamicMetaObject)null, arguments) { - _siteContext = rubyBinder.Context; + internal MetaObjectBuilder(RubyMetaBinder/*!*/ binder, DynamicMetaObject/*!*/[]/*!*/ arguments) + : this(binder.Context, (DynamicMetaObject)null, arguments) { } - internal MetaObjectBuilder(DynamicMetaObject target, params DynamicMetaObject/*!*/[]/*!*/ arguments) { + internal MetaObjectBuilder(IInteropBinder/*!*/ binder, DynamicMetaObject target, params DynamicMetaObject/*!*/[]/*!*/ arguments) + : this(binder.Context, target, arguments) { + } + + internal MetaObjectBuilder(DynamicMetaObject target, params DynamicMetaObject/*!*/[]/*!*/ arguments) + : this((RubyContext)null, target, arguments) { + } + + private MetaObjectBuilder(RubyContext siteContext, DynamicMetaObject target, DynamicMetaObject/*!*/[]/*!*/ arguments) { var restrictions = BindingRestrictions.Combine(arguments); if (target != null) { restrictions = target.Restrictions.Merge(restrictions); } _restrictions = restrictions; + _siteContext = siteContext; } public bool Error { @@ -92,7 +100,7 @@ internal MetaObjectBuilder(RubyMetaBinder/*!*/ rubyBinder, DynamicMetaObject/*!* return CreateMetaObject(action, typeof(object)); } - private DynamicMetaObject/*!*/ CreateMetaObject(DynamicMetaObjectBinder/*!*/ action, Type/*!*/ returnType) { + internal DynamicMetaObject/*!*/ CreateMetaObject(DynamicMetaObjectBinder/*!*/ action, Type/*!*/ returnType) { Debug.Assert(ControlFlowBuilder == null, "Control flow required but not built"); var expr = _error ? Ast.Throw(_result, returnType) : AstUtils.Convert(_result, returnType); diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs index eacb96da3c..4ab4c7449e 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/ProtocolConversionAction.cs @@ -53,29 +53,6 @@ protected RubyConversionAction(RubyContext context) return GetType().Name + (Context != null ? " @" + Context.RuntimeId.ToString() : null); } - protected virtual ConvertBinder/*!*/ GetInteropBinder(RubyContext/*!*/ context, out MethodInfo postConverter) { - throw new NotImplementedException("TODO"); - } - - protected override DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { - var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, 0); - if (!metaBuilder.Error) { - MethodInfo postConverter; - ConvertBinder interopBinder = GetInteropBinder(args.RubyContext, out postConverter); - - // TODO: the type of result.Expression (and LimitType) should be the type of the conversion. - var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs)); - metaBuilder.SetMetaResult(result, args); - - if (postConverter != null) { - metaBuilder.Result = postConverter.OpCall(AstUtils.Convert(metaBuilder.Result, interopBinder.Type)); - } - return metaBuilder.CreateMetaObject(this); - } - - return metaBuilder.CreateMetaObject(this); - } - public static RubyConversionAction TryGetDefaultConversionAction(RubyContext/*!*/ context, Type/*!*/ parameterType) { var factory = context.MetaBinderFactory; @@ -144,8 +121,10 @@ public abstract class ProtocolConversionAction : RubyConversionAction { } } - protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { + protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { + Debug.Assert(defaultFallback, "custom fallback not supported"); BuildConversion(metaBuilder, args, ResultType, this); + return true; } internal static void BuildConversion(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, Type/*!*/ resultType, @@ -370,8 +349,9 @@ public sealed class ConvertToStrAction : ConvertToReferenceTypeAction/*!*/ args, + out MethodInfo postConverter) { + postConverter = Methods.StringToMutableString; return new InteropBinder.Convert(context, typeof(string), true); } } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallAction.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallAction.cs index d9ffd21e01..d2d457501e 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallAction.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyCallAction.cs @@ -26,6 +26,8 @@ using Ast = System.Linq.Expressions.Expression; using AstUtils = Microsoft.Scripting.Ast.Utils; using IronRuby.Compiler.Generation; +using System.Collections.Generic; +using System.Reflection; namespace IronRuby.Runtime.Calls { @@ -93,11 +95,12 @@ internal protected RubyCallAction(RubyContext context, string/*!*/ methodName, R #endregion - protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { - Build(metaBuilder, _methodName, args, true); + protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { + return BuildCall(metaBuilder, _methodName, args, defaultFallback); } - internal static bool Build(MetaObjectBuilder/*!*/ metaBuilder, string/*!*/ methodName, CallArguments/*!*/ args, bool defaultFallback) { + // Returns true if the call was bound (with success or failure), false if fallback should be performed. + internal static bool BuildCall(MetaObjectBuilder/*!*/ metaBuilder, string/*!*/ methodName, CallArguments/*!*/ args, bool defaultFallback) { RubyMemberInfo methodMissing; var method = Resolve(metaBuilder, methodName, args, out methodMissing); @@ -178,46 +181,70 @@ internal protected RubyCallAction(RubyContext context, string/*!*/ methodName, R return true; } - private DynamicMetaObjectBinder/*!*/ GetInteropBinder(RubyContext/*!*/ context, CallInfo/*!*/ callInfo) { + protected override DynamicMetaObjectBinder GetInteropBinder(RubyContext/*!*/ context, IList/*!*/ args, + out MethodInfo postConverter) { + switch (_methodName) { case "new": - return new InteropBinder.CreateInstance(context, callInfo); + postConverter = null; + return new InteropBinder.CreateInstance(context, new CallInfo(args.Count)); case "call": - return new InteropBinder.Invoke(context, callInfo); + postConverter = null; + return new InteropBinder.Invoke(context, "call", new CallInfo(args.Count)); case "to_s": - return new InteropBinder.Convert(context, typeof(string), true); + postConverter = Methods.ObjectToMutableString; + return new InteropBinder.InvokeMember(context, "ToString", new CallInfo(args.Count)); case "to_str": + postConverter = Methods.StringToMutableString; return new InteropBinder.Convert(context, typeof(string), false); - // TODO: other ops + case "[]": + // TODO: or invoke? + postConverter = null; + return new InteropBinder.GetIndex(context, new CallInfo(args.Count)); + + case "[]=": + postConverter = null; + return new InteropBinder.SetIndex(context, new CallInfo(args.Count)); + + // BinaryOps: + case "+": // ExpressionType.Add + case "-": // ExpressionType.Subtract + case "/": // ExpressionType.Divide + case "*": // ExpressionType.Multiply + case "%": // ExpressionType.Modulo + case "==": // ExpressionType.Equal + case "!=": // ExpressionType.NotEqual + case ">": // ExpressionType.GreaterThan + case ">=": // ExpressionType.GreaterThanOrEqual + case "<": // ExpressionType.LessThan + case "<=": // ExpressionType.LessThanOrEqual + + case "**": // ExpressionType.Power + case "<<": // ExpressionType.LeftShift + case ">>": // ExpressionType.RightShift + case "&": // ExpressionType.And + case "|": // ExpressionType.Or + case "^": // ExpressionType.ExclusiveOr; + + // UnaryOp: + case "-@": + case "+@": + case "~": + postConverter = null; + return null; default: + postConverter = null; if (_methodName.EndsWith("=")) { - // TODO: SetMemberBinder - throw new NotSupportedException(); + return new InteropBinder.SetMember(context, _methodName.Substring(0, _methodName.Length - 1)); } else { - return new InteropBinder.InvokeMember(context, _methodName, callInfo); + return new InteropBinder.InvokeMember(context, _methodName, new CallInfo(args.Count)); } } } - - protected override DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { - // TODO: pass block as the last parameter (before RHS arg?): - var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue); - if (!metaBuilder.Error) { - var callInfo = new CallInfo(normalizedArgs.Count); - - var interopBinder = GetInteropBinder(args.RubyContext, callInfo); - var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs)); - metaBuilder.SetMetaResult(result, args); - return metaBuilder.CreateMetaObject(this); - } - return metaBuilder.CreateMetaObject(this); - } - - } } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMemberInfo.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMemberInfo.cs index 8ec0763298..171d688181 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMemberInfo.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMemberInfo.cs @@ -30,6 +30,9 @@ public class RubyMemberInfo { // Singleton used to hide CLR methods: method resolution skips all CLR methods since encountering a hidden method. internal static readonly RubyMemberInfo/*!*/ HiddenMethod = new RubyMemberInfo(); + // Singleton used to represent foreign members (these are not in method tables): + internal static readonly RubyMemberInfo/*!*/ ForeignMember = new RubyMemberInfo(); + private readonly RubyMemberFlags _flags; // Null for dummy methods. diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaBinder.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaBinder.cs index cb3023bcaa..4705884454 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaBinder.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaBinder.cs @@ -16,6 +16,11 @@ using System.Dynamic; using System.Diagnostics; using System; +using Microsoft.Scripting.Utils; +using System.Collections.Generic; +using Ast = System.Linq.Expressions.Expression; +using AstUtils = Microsoft.Scripting.Ast.Utils; +using System.Reflection; namespace IronRuby.Runtime.Calls { public abstract class RubyMetaBinder : DynamicMetaObjectBinder { @@ -37,25 +42,65 @@ public abstract class RubyMetaBinder : DynamicMetaObjectBinder { } public abstract RubyCallSignature Signature { get; } - protected abstract void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args); - protected abstract DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args); + protected abstract bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback); public abstract Type/*!*/ ResultType { get; } + protected virtual DynamicMetaObjectBinder GetInteropBinder(RubyContext/*!*/ context, IList/*!*/ args, + out MethodInfo postProcessor) { + + postProcessor = null; + return null; + } + public override DynamicMetaObject/*!*/ Bind(DynamicMetaObject/*!*/ scopeOrContextOrTarget, DynamicMetaObject/*!*/[]/*!*/ args) { var callArgs = new CallArguments(_context, scopeOrContextOrTarget, args, Signature); var metaBuilder = new MetaObjectBuilder(this, args); - // TODO: COM interop if (IsForeignMetaObject(callArgs.MetaTarget)) { return InteropBind(metaBuilder, callArgs); - } + } + + Build(metaBuilder, callArgs, true); + return metaBuilder.CreateMetaObject(this); + } - Build(metaBuilder, callArgs); + + private DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { + // TODO: argument count limit depends on the binder! + + // TODO: pass block as the last (before RHS arg?) parameter/ignore block if args not accepting block: + var normalizedArgs = RubyOverloadResolver.NormalizeArguments(metaBuilder, args, 0, Int32.MaxValue); + if (!metaBuilder.Error) { + MethodInfo postConverter; + var interopBinder = GetInteropBinder(args.RubyContext, normalizedArgs, out postConverter); + if (interopBinder != null) { + Type resultType; + var result = interopBinder.Bind(args.MetaTarget, ArrayUtils.MakeArray(normalizedArgs)); + + metaBuilder.SetMetaResult(result, args); + if (postConverter != null) { + // TODO: do better? + var paramType = postConverter.GetParameters()[0].ParameterType; + + metaBuilder.Result = Ast.Call(null, postConverter, AstUtils.Convert(metaBuilder.Result, paramType)); + resultType = postConverter.ReturnType; + } else { + resultType = ((IInteropBinder)interopBinder).ResultType; + } + + return metaBuilder.CreateMetaObject(interopBinder, resultType); + } else { + metaBuilder.SetError(Ast.New( + typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }), + Ast.Constant(String.Format("{0} not supported on foreign meta-objects", this)) + )); + } + } return metaBuilder.CreateMetaObject(this); } internal static bool IsForeignMetaObject(DynamicMetaObject/*!*/ metaObject) { - return metaObject.Value is IDynamicMetaObjectProvider && !(metaObject is RubyMetaObject); + return metaObject.Value is IDynamicMetaObjectProvider && !(metaObject is RubyMetaObject) || Utils.IsComObjectType(metaObject.LimitType); } } } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaObject.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaObject.cs index f4ff873735..c53dee556e 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaObject.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/RubyMetaObject.cs @@ -29,6 +29,9 @@ namespace IronRuby.Runtime.Calls { using Ast = System.Linq.Expressions.Expression; + interface IRubyDynamicMetaObjectProvider : IDynamicMetaObjectProvider { + } + public abstract class RubyMetaObject : DynamicMetaObject { public abstract RubyContext/*!*/ Context { get; } public abstract Expression/*!*/ ContextExpression { get; } diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs index c3bff871c7..e53054a442 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Calls/SuperCallAction.cs @@ -63,7 +63,7 @@ internal SuperCallAction(RubyContext context, RubyCallSignature signature, int l #region Rule Generation - protected override void Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { + protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; @@ -111,16 +111,10 @@ internal SuperCallAction(RubyContext context, RubyCallSignature signature, int l if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { - RubyCallAction.BindToMethodMissing(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, true); + return RubyCallAction.BindToMethodMissing(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback); } - } - protected override DynamicMetaObject/*!*/ InteropBind(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args) { - metaBuilder.SetError(Ast.New( - typeof(NotSupportedException).GetConstructor(new[] { typeof(string) }), - Ast.Constant("Super call not supported on foreign meta-objects") - )); - return metaBuilder.CreateMetaObject(this); + return true; } #endregion diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs index c1f04e47fa..6bb59c1631 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyContext.cs @@ -187,6 +187,7 @@ public sealed class RubyContext : LanguageContext { private RubyClass/*!*/ _falseClass; private RubyClass/*!*/ _exceptionClass; private RubyClass _standardErrorClass; + private RubyClass _comObjectClass; private Action/*!*/ _classSingletonTrait; private Action/*!*/ _singletonSingletonTrait; @@ -202,6 +203,17 @@ public sealed class RubyContext : LanguageContext { public RubyClass/*!*/ FalseClass { get { return _falseClass; } set { _falseClass = value; } } public RubyClass ExceptionClass { get { return _exceptionClass; } set { _exceptionClass = value; } } public RubyClass StandardErrorClass { get { return _standardErrorClass; } set { _standardErrorClass = value; } } + + internal RubyClass ComObjectClass { + get { +#if !SILVERLIGHT + if (_comObjectClass == null) { + GetOrCreateClass(Utils.ComObjectType); + } +#endif + return _comObjectClass; + } + } internal Action/*!*/ ClassSingletonTrait { get { return _classSingletonTrait; } } internal Action/*!*/ SingletonSingletonTrait { get { return _singletonSingletonTrait; } } @@ -704,6 +716,10 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary result = CreateClass(RubyUtils.GetQualifiedName(type), type, null, null, null, null, null, baseClass, expandedMixins, tracker, null, false, false); + if (Utils.IsComObjectType(type)) { + _comObjectClass = result; + } + _moduleCache[type] = result; return result; } @@ -2105,6 +2121,19 @@ public RubyContext(ScriptDomainManager/*!*/ manager, IDictionary return new InteropBinder.CreateInstance(this, callInfo); } + // TODO: override GetMemberNames? + public IList/*!*/ GetForeignDynamicMemberNames(object obj) { + if (obj is IRubyDynamicMetaObjectProvider) { + return ArrayUtils.EmptyStrings; + } +#if !SILVERLIGHT + if (Utils.IsComObject(obj)) { + return new List(System.Dynamic.ComBinder.GetDynamicMemberNames(obj)); + } +#endif + return GetMemberNames(obj); + } + #endregion #region Dynamic Sites (thread-safe) diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs index ff5dc8cceb..52e31ac767 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs @@ -1440,13 +1440,18 @@ public static partial class RubyOps { return result; } - // TODO: (interop conversion) - // Used for implicit conversions from System.String to MutableString. + // Used for implicit conversions from System.String to MutableString (to_str conversion like). [Emitted] - public static MutableString/*!*/ ToMutableString(string/*!*/ str) { + public static MutableString/*!*/ StringToMutableString(string/*!*/ str) { return MutableString.Create(str, RubyEncoding.UTF8); } + // Used for implicit conversions from System.Object to MutableString (to_s conversion like). + [Emitted] + public static MutableString/*!*/ ObjectToMutableString(object/*!*/ value) { + return (value != null) ? MutableString.Create(value.ToString(), RubyEncoding.UTF8) : MutableString.Empty; + } + [Emitted] // ProtocolConversionAction public static MutableString/*!*/ ToStringValidator(string/*!*/ className, object obj) { MutableString result = obj as MutableString; diff --git a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs index 2dd431ca37..3c5acecd6c 100644 --- a/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs +++ b/Merlin/Main/Languages/Ruby/Ruby/Runtime/Utils.cs @@ -34,7 +34,27 @@ public static class Utils { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] public static readonly Delegate[] EmptyDelegates = new Delegate[0]; - + +#if !SILVERLIGHT + internal static Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject"); +#endif + + public static bool IsComObjectType(Type/*!*/ type) { +#if SILVERLIGHT + return false; +#else + return ComObjectType.IsAssignableFrom(type); +#endif + } + + public static bool IsComObject(object obj) { +#if SILVERLIGHT + return false; +#else + return obj != null && IsComObjectType(obj.GetType()); +#endif + } + public static int IndexOf(this string[]/*!*/ array, string/*!*/ value, StringComparer/*!*/ comparer) { ContractUtils.RequiresNotNull(array, "array"); ContractUtils.RequiresNotNull(value, "value"); diff --git a/Merlin/Main/Languages/Ruby/context.rb b/Merlin/Main/Languages/Ruby/context.rb index ac646b7438..9114031191 100644 --- a/Merlin/Main/Languages/Ruby/context.rb +++ b/Merlin/Main/Languages/Ruby/context.rb @@ -410,7 +410,7 @@ def method_missing(name, *args) generator :references => ['Microsoft.Scripting.Core.dll', 'Microsoft.Scripting.dll','Microsoft.Scripting.ExtensionAttribute.dll', 'IronRuby.dll', '!System.dll'], :output => 'ClassInitGenerator.exe', :dir => './ClassInitGenerator' - ironruby :references => ['Microsoft.Scripting.Core.dll', 'Microsoft.Scripting.dll', 'Microsoft.Scripting.ExtensionAttribute.dll','!System.dll', '!System.Configuration.dll'], + ironruby :references => ['Microsoft.Scripting.Core.dll', 'Microsoft.Scripting.dll', 'Microsoft.Scripting.ExtensionAttribute.dll', 'Microsoft.Dynamic.dll', '!System.dll', '!System.Configuration.dll'], :switches => ['target:library'], :output => 'IronRuby.dll', :dir => './Ruby', diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/ComInterop/TypeLibMetaObject.cs b/Merlin/Main/Runtime/Microsoft.Scripting/ComInterop/TypeLibMetaObject.cs index 02fd16ec20..f533bae4b0 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/ComInterop/TypeLibMetaObject.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/ComInterop/TypeLibMetaObject.cs @@ -30,8 +30,8 @@ internal TypeLibMetaObject(Expression expression, ComTypeLibDesc lib) _lib = lib; } - public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { - if (_lib.HasMember(binder.Name)) { + private DynamicMetaObject TryBindGetMember(string name) { + if (_lib.HasMember(name)) { BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction( Expression, typeof(ComTypeLibDesc) @@ -51,13 +51,26 @@ internal TypeLibMetaObject(Expression expression, ComTypeLibDesc lib) return new DynamicMetaObject( AstUtils.Constant( - ((ComTypeLibDesc)Value).GetTypeLibObjectDesc(binder.Name) + ((ComTypeLibDesc)Value).GetTypeLibObjectDesc(name) ), restrictions ); } - return base.BindGetMember(binder); + return null; + } + + public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { + return TryBindGetMember(binder.Name) ?? base.BindGetMember(binder); + } + + public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) { + var result = TryBindGetMember(binder.Name); + if (result != null) { + return binder.FallbackInvoke(result, args, null); + } + + return base.BindInvokeMember(binder, args); } public override IEnumerable GetDynamicMemberNames() { diff --git a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs index 2d70ca2508..8b2cabf1b6 100644 --- a/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs +++ b/Merlin/Main/Runtime/Microsoft.Scripting/Generation/CompilerHelpers.cs @@ -796,12 +796,13 @@ public static class CompilerHelpers { /// the compiled delegate [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] public static T CompileToMethod(Expression lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) { - var type = Snippets.Shared.DefineType(lambda.Name, typeof(object), false, emitDebugSymbols).TypeBuilder; + string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name; + + var type = Snippets.Shared.DefineType(methodName, typeof(object), false, emitDebugSymbols).TypeBuilder; var rewriter = new BoundConstantsRewriter(type); lambda = (Expression)rewriter.Visit(lambda); //Create a unique method name when the lambda doesn't have a name or the name is empty. - string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name; var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic); lambda.CompileToMethod(method, debugInfoGenerator); diff --git a/ndp/fx/src/Dynamic/System.Dynamic.asmmeta_ignore b/ndp/fx/src/Dynamic/System.Dynamic.asmmeta_ignore new file mode 100644 index 0000000000..f4293894f0 --- /dev/null +++ b/ndp/fx/src/Dynamic/System.Dynamic.asmmeta_ignore @@ -0,0 +1,3 @@ +Type:AssemblyRef +Type:FXAssembly +Type:ThisAssembly