edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C438696 File: RubyTests.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;C438696 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/RubyTests.cs;RubyBugFixesII @@ -96,7 +96,10 @@ MethodUndefExpression, Scenario_Assignment1, SetterCallValue, + SimpleInplaceAsignmentToIndirectLeftValues1, MemberAssignmentExpression1, + MemberAssignmentExpression2, + MemberAssignmentExpression3, Scenario_ParallelAssignment1, Scenario_ParallelAssignment2, =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/AssignmentTests.cs;C437359 File: AssignmentTests.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/AssignmentTests.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/AssignmentTests.cs;RubyBugFixesII @@ -266,6 +266,47 @@ "); } + /// + /// ArrayItemAccess and AttributeAccess read target ones in an in-place assignment. + /// + public void SimpleInplaceAsignmentToIndirectLeftValues1() { + AssertOutput(delegate { + CompilerTest(@" +class Array + def x; 1; end + def x= value; puts 'x=' end +end + +def foo + puts 'foo' + [0] +end + +p foo[0] += 1 +p foo::x += 2 +p foo[0] &&= 3 +p foo::x &&= 4 +p foo[0] ||= 5 +p foo::x ||= 6 +"); + }, @" +foo +1 +foo +x= +3 +foo +3 +foo +x= +4 +foo +0 +foo +1 +"); + } + public void SetterCallValue() { AssertOutput(delegate { CompilerTest(@" @@ -296,5 +337,95 @@ nil"); } + + private const string/*!*/ MemberAssignmentDefs = @" +class String + def + other + puts ""#{self} + #{other}"" + ""#{self}#{other}"" + end +end + +class C + def x= value + puts ""write: #{value}"" + end + + def x + puts ""read"" + $result + end +end + +def target + puts 'target' + C.new +end + +def rhs + puts 'rhs' + '_rhs' +end +"; + + public void MemberAssignmentExpression1() { + AssertOutput(delegate { + CompilerTest(MemberAssignmentDefs + @" +$result = 'result' +puts(target.x += rhs) +"); + }, @" +target +read +rhs +result + _rhs +write: result_rhs +result_rhs +"); + } + + public void MemberAssignmentExpression2() { + AssertOutput(delegate { + CompilerTest(MemberAssignmentDefs + @" +$result = true +puts(target.x &&= rhs) +puts +$result = false +puts(target.x &&= rhs) +"); + }, @" +target +read +rhs +write: _rhs +_rhs + +target +read +false +"); + } + + public void MemberAssignmentExpression3() { + AssertOutput(delegate { + CompilerTest(MemberAssignmentDefs + @" +$result = true +puts(target.x ||= rhs) +puts +$result = false +puts(target.x ||= rhs) +"); + }, @" +target +read +true + +target +read +rhs +write: _rhs +_rhs +"); + } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;C438696 File: MethodTests.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;C438696 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/IronRuby.Tests/Runtime/MethodTests.cs;RubyBugFixesII @@ -85,38 +85,5 @@ }, @"123"); } - - public void MemberAssignmentExpression1() { - AssertOutput(delegate { - CompilerTest(@" -class String - def + other - puts ""#{self} + #{other}"" - ""#{self}#{other}"" - end -end - -class C - def x= value - puts ""write: #{value}"" - end - - def x - puts ""read"" - 'result' - end -end - -z = C.new - -puts(z.x += '_rhs') -"); - }, @" -read -result + _rhs -write: result_rhs -result_rhs -"); - } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializer.Generated.cs;C438696 File: Initializer.Generated.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializer.Generated.cs;C438696 (server) 5/15/2008 10:40 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Initializer.Generated.cs;RubyBugFixesII @@ -44,7 +44,7 @@ #endif // Skipped primitive: Object Ruby.Builtins.RubyModule def33 = DefineModule("System::Collections::Generic::IDictionary", typeof(System.Collections.Generic.IDictionary), new System.Action(LoadSystem__Collections__Generic__IDictionary_Instance), null, new Ruby.Builtins.RubyModule[] {def28, }); - DefineModule("System::Collections::IEnumerable", typeof(System.Collections.IEnumerable), new System.Action(LoadSystem__Collections__IEnumerable_Instance), null, new Ruby.Builtins.RubyModule[] {def28, }); + Ruby.Builtins.RubyModule def47 = DefineModule("System::Collections::IEnumerable", typeof(System.Collections.IEnumerable), new System.Action(LoadSystem__Collections__IEnumerable_Instance), null, new Ruby.Builtins.RubyModule[] {def28, }); Ruby.Builtins.RubyModule def40 = DefineModule("System::Collections::IList", typeof(System.Collections.IList), new System.Action(LoadSystem__Collections__IList_Instance), null, new Ruby.Builtins.RubyModule[] {def28, }); DefineModule("System::IComparable", typeof(System.IComparable), new System.Action(LoadSystem__IComparable_Instance), null, new Ruby.Builtins.RubyModule[] {def38, }); DefineGlobalClass("Time", typeof(System.DateTime), typeof(Ruby.Builtins.TimeOps), new System.Action(LoadTime_Instance), new System.Action(LoadTime_Class), classRef1, new Ruby.Builtins.RubyModule[] {def38, }, new System.Delegate[] { @@ -60,7 +60,7 @@ new Microsoft.Scripting.Utils.Function(Ruby.Builtins.ArrayOps.CreateArray), }); DefineGlobalClass("Binding", typeof(Ruby.Builtins.Binding), typeof(Ruby.Builtins.BindingOps), null, null, Context.ObjectClass, Ruby.Builtins.RubyModule.EmptyArray, null); - DefineGlobalClass("ClrString", typeof(System.String), typeof(Ruby.Builtins.StringOps), new System.Action(LoadClrString_Instance), null, Context.ObjectClass, Ruby.Builtins.RubyModule.EmptyArray, null); + DefineGlobalClass("ClrString", typeof(System.String), typeof(Ruby.Builtins.StringOps), new System.Action(LoadClrString_Instance), null, Context.ObjectClass, new Ruby.Builtins.RubyModule[] {def47, }, null); Ruby.Builtins.RubyClass def13 = DefineClass("Digest::Class", typeof(Ruby.StandardLibrary.Digest.Class), null, null, new System.Action(LoadDigest__Class_Class), Context.ObjectClass, new Ruby.Builtins.RubyModule[] {def14, }, null); DefineGlobalClass("Dir", typeof(Ruby.Builtins.RubyDir), null, new System.Action(LoadDir_Instance), new System.Action(LoadDir_Class), Context.ObjectClass, new Ruby.Builtins.RubyModule[] {def28, }, null); Ruby.Builtins.RubyClass def39 = Context.ExceptionClass = DefineGlobalClass("Exception", typeof(System.Exception), typeof(Ruby.Builtins.ExceptionOps), new System.Action(LoadException_Instance), new System.Action(LoadException_Class), Context.ObjectClass, Ruby.Builtins.RubyModule.EmptyArray, new System.Delegate[] { @@ -2049,6 +2049,10 @@ new Microsoft.Scripting.Utils.Function(Ruby.Builtins.Kernel.MethodMissing), }); + module.DefineMethod("methods", 0x9, new System.Delegate[] { + new Microsoft.Scripting.Utils.Function(Ruby.Builtins.Kernel.GetMethods), + }); + module.DefineMethod("nil?", 0x9, new System.Delegate[] { new Microsoft.Scripting.Utils.Function(Ruby.Builtins.Kernel.IsNil), }); @@ -2101,7 +2105,6 @@ }); module.DefineMethod("singleton_methods", 0x9, new System.Delegate[] { - new Microsoft.Scripting.Utils.Function(Ruby.Builtins.Kernel.GetSingletonMethods), new Microsoft.Scripting.Utils.Function(Ruby.Builtins.Kernel.GetSingletonMethods), }); @@ -3622,6 +3625,14 @@ new Microsoft.Scripting.Utils.Function(Ruby.Builtins.MutableStringOps.Replace), }); + module.DefineMethod("reverse", 0x9, new System.Delegate[] { + new Microsoft.Scripting.Utils.Function(Ruby.Builtins.MutableStringOps.GetReversed), + }); + + module.DefineMethod("reverse!", 0x9, new System.Delegate[] { + new Microsoft.Scripting.Utils.Function(Ruby.Builtins.MutableStringOps.Reverse), + }); + module.DefineMethod("rindex", 0x9, new System.Delegate[] { new Microsoft.Scripting.Utils.Function(Ruby.Builtins.MutableStringOps.ReverseIndex), new Microsoft.Scripting.Utils.Function(Ruby.Builtins.MutableStringOps.ReverseIndex), =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Enumerable.cs;C415805 File: Enumerable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Enumerable.cs;C415805 (server) 5/15/2008 1:17 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Enumerable.cs;RubyBugFixesII @@ -13,23 +13,16 @@ * * ***************************************************************************/ -using System; using System.Collections; using System.Collections.Generic; -using System.ComponentModel; using System.Reflection; using System.Runtime.InteropServices; -using System.Text; -using Microsoft.Scripting; using Microsoft.Scripting.Actions; using Microsoft.Scripting.Runtime; -using Microsoft.Scripting.Utils; -using Ruby.Extensions; using Ruby.Runtime; namespace Ruby.Builtins { - using MSA = Microsoft.Scripting.Ast; - + // TODO: All of these methods use RubySites.Each, which is not ideal (shared DynamicSite). // We could have one DynamicSite per method, but what we really want is for the // "each" site to be merged into the calling site (e.g. maybe use ActionOnCallable) =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Kernel.cs;C436555 File: Kernel.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Kernel.cs;C436555 (server) 5/15/2008 10:40 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/Kernel.cs;RubyBugFixesII @@ -14,20 +14,17 @@ * ***************************************************************************/ using System; +using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Threading; using Microsoft.Scripting; using Microsoft.Scripting.Actions; using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; using Ruby.Runtime; -using Microsoft.Scripting.Runtime; -using Ruby.Compiler; -using System.Threading; using Ruby.Runtime.Calls; -using System.Collections; -using System.Diagnostics; -using System.ComponentModel; namespace Ruby.Builtins { @@ -124,14 +121,14 @@ [RubyMethod("eval", RubyMethodAttributes.PrivateInstance)] [RubyMethod("eval", RubyMethodAttributes.PublicSingleton)] public static object Evaluate(CodeContext/*!*/ context, object self, [NotNull]MutableString/*!*/ code, - [Optional]Binding binding, [Optional, NotNull]MutableString file, [Optional, DefaultValue(1)]int line) { + [Optional]Binding binding, [Optional, NotNull]MutableString file, [DefaultParameterValue(1)]int line) { return RubyUtils.Evaluate(self, code, (binding != null) ? binding.LocalScope : RubyUtils.GetScope(context), file, line); } [RubyMethod("eval", RubyMethodAttributes.PrivateInstance)] [RubyMethod("eval", RubyMethodAttributes.PublicSingleton)] - public static object Evaluate(CodeContext/*!*/ context, object self, [NotNull]MutableString/*!*/ code, - [NotNull]Proc/*!*/ procBinding, [Optional, NotNull]MutableString file, [Optional, DefaultValue(1)]int line) { + public static object Evaluate(CodeContext/*!*/ context, object self, [NotNull]MutableString/*!*/ code, + [NotNull]Proc/*!*/ procBinding, [Optional, NotNull]MutableString file, [DefaultParameterValue(1)]int line) { return RubyUtils.Evaluate(self, code, procBinding.LocalScope, file, line); } @@ -767,13 +764,6 @@ return new RubyMethod(self, info, name); } - [RubyMethod("method")] - public static RubyMethod/*!*/ GetMethod(CodeContext/*!*/ context, object self, object name) { - return GetMethod(context, self, Protocols.CastToSymbol(context, name)); - } - - //methods - [RubyMethod("nil?")] public static bool IsNil(object self) { return self == null; @@ -824,19 +814,31 @@ } #endregion - [RubyMethod("singleton_methods")] - public static RubyArray/*!*/ GetSingletonMethods(CodeContext/*!*/ context, object self) { - return GetSingletonMethods(context, self, true); + #region method, methods, singleton_methods + + [RubyMethod("method")] + public static RubyMethod/*!*/ GetMethod(CodeContext/*!*/ context, object self, object name) { + return GetMethod(context, self, Protocols.CastToSymbol(context, name)); } + [RubyMethod("methods")] + public static RubyArray/*!*/ GetMethods(CodeContext/*!*/ context, object self, [DefaultParameterValue(true)]bool inherited) { + RubyClass immediateClass = RubyUtils.GetExecutionContext(context).GetImmediateClassOf(self); + return ModuleOps.GetMethods(immediateClass, inherited, + RubyMethodAttributes.Private | RubyMethodAttributes.Public | RubyMethodAttributes.Protected + ); + } + [RubyMethod("singleton_methods")] - public static RubyArray/*!*/ GetSingletonMethods(CodeContext/*!*/ context, object self, bool inherited) { + public static RubyArray/*!*/ GetSingletonMethods(CodeContext/*!*/ context, object self, [DefaultParameterValue(true)]bool inherited) { RubyClass immediateClass = RubyUtils.GetExecutionContext(context).GetImmediateClassOf(self); - return ModuleOps.GetInstanceMethods(immediateClass, inherited, + return ModuleOps.GetMethods(immediateClass, inherited, RubyMethodAttributes.Public | RubyMethodAttributes.Protected | RubyMethodAttributes.Singleton ); } + #endregion + /// /// Returns a string containing a human-readable representation of obj. /// If not overridden, uses the to_s method to generate the string. @@ -882,8 +884,7 @@ public static void RequiresNotFrozen(CodeContext/*!*/ context, object/*!*/ obj) { if (Kernel.Frozen(context, obj)) { - string typeName = RubyUtils.GetExecutionContext(context).GetClassOf(obj).Name.ToString().ToLower(); - throw RubyExceptions.CreateTypeError("can't modify frozen " + typeName); + throw RubyExceptions.CreateTypeError("can't modify frozen object"); } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;C438696 File: ModuleOps.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;C438696 (server) 5/15/2008 10:59 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/ModuleOps.cs;RubyBugFixesII @@ -15,18 +15,14 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using Microsoft.Scripting; using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Runtime; using Microsoft.Scripting.Utils; -using Microsoft.Scripting.Hosting; using Ruby.Runtime; using Ruby.Runtime.Calls; -using Microsoft.Scripting.Runtime; -using Ruby.Compiler; -using System.Runtime.InteropServices; -using System.ComponentModel; -using System.Diagnostics; -using Microsoft.Scripting.Ast; namespace Ruby.Builtins { @@ -521,8 +517,8 @@ [RubyMethod("module_eval")] [RubyMethod("class_eval")] - public static object Evaluate(CodeContext/*!*/ context, RubyModule/*!*/ self, BlockParam block, [NotNull]MutableString/*!*/ code, - [Optional, NotNull]MutableString file, [Optional, DefaultValue(1)]int line) { + public static object Evaluate(CodeContext/*!*/ context, RubyModule/*!*/ self, BlockParam block, [NotNull]MutableString/*!*/ code, + [Optional, NotNull]MutableString file, [DefaultParameterValue(1)]int line) { // TODO: binder should do this: if (block != null) { @@ -653,7 +649,7 @@ [RubyMethod("instance_methods")] public static RubyArray/*!*/ GetInstanceMethods(RubyModule/*!*/ self, bool inherited) { - return GetInstanceMethods(self, inherited, RubyMethodAttributes.PublicInstance); + return GetMethods(self, inherited, RubyMethodAttributes.PublicInstance); } [RubyMethod("private_instance_methods")] @@ -663,7 +659,7 @@ [RubyMethod("private_instance_methods")] public static RubyArray/*!*/ GetPrivateInstanceMethods(RubyModule/*!*/ self, bool inherited) { - return GetInstanceMethods(self, inherited, RubyMethodAttributes.PrivateInstance); + return GetMethods(self, inherited, RubyMethodAttributes.PrivateInstance); } [RubyMethod("protected_instance_methods")] @@ -673,7 +669,7 @@ [RubyMethod("protected_instance_methods")] public static RubyArray/*!*/ GetProtectedInstanceMethods(RubyModule/*!*/ self, bool inherited) { - return GetInstanceMethods(self, inherited, RubyMethodAttributes.ProtectedInstance); + return GetMethods(self, inherited, RubyMethodAttributes.ProtectedInstance); } [RubyMethod("public_instance_methods")] @@ -683,7 +679,7 @@ [RubyMethod("public_instance_methods")] public static RubyArray/*!*/ GetPublicInstanceMethods(RubyModule/*!*/ self, bool inherited) { - return GetInstanceMethods(self, inherited, RubyMethodAttributes.PublicInstance); + return GetMethods(self, inherited, RubyMethodAttributes.PublicInstance); } /// @@ -693,18 +689,23 @@ /// inherited == false, attributes & Singleton != 0: /// - get methods in the "self" module only /// - do not visit mixins nor super classes - /// inherited == true + /// inherited == true, attributes & Singleton != 0: /// - walk all ancestors until a non-singleton is reached (include "self" module anyways) + /// inherited == true, attributes & (Singleton | Instance) == 0 : + /// - walk all ancestors until a an Object is reached /// /// Methods are filtered by visibility specified in attributes (mutliple visibilities could be specified). /// A name undefined in a module is not visible in that module and its ancestors. /// Method names are not duplicated in the result. /// - internal static RubyArray/*!*/ GetInstanceMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes) { + internal static RubyArray/*!*/ GetMethods(RubyModule/*!*/ self, bool inherited, RubyMethodAttributes attributes) { Dictionary visited = new Dictionary(); RubyArray result = new RubyArray(); + // We can look for instance methods, singleton methods or all methods. + // The difference is when we stop searching. bool instanceMethods = (attributes & RubyMethodAttributes.Instance) != 0; + bool singletonMethods = (attributes & RubyMethodAttributes.Singleton) != 0; bool stop = false; self.ForEachInstanceMethod(true, delegate(RubyModule/*!*/ module, SymbolId name, RubyMemberInfo method) { @@ -718,8 +719,12 @@ if (instanceMethods) { stop = !inherited && !module.IsSingletonClass; - } else if ((!inherited || !module.IsSingletonClass) && module != self) { - return true; + } else if (singletonMethods) { + if ((!inherited || !module.IsSingletonClass) && module != self) { + return true; + } + } else { + stop = !inherited; } } else if (method.IsUndefined) { =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C438696 File: MutableStringOps.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;C438696 (server) 5/15/2008 10:40 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/MutableStringOps.cs;RubyBugFixesII @@ -3065,5 +3065,16 @@ } #endregion + + [RubyMethod("reverse")] + public static MutableString/*!*/ GetReversed(CodeContext/*!*/ context, MutableString/*!*/ self) { + return CreateSubClass(context, self, self).Reverse(); + } + + [RubyMethod("reverse!")] + public static MutableString/*!*/ Reverse(CodeContext/*!*/ context, MutableString/*!*/ self) { + Kernel.RequiresNotFrozen(context, self); + return self.Reverse(); + } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RangeOps.cs;C438696 File: RangeOps.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RangeOps.cs;C438696 (server) 5/15/2008 1:18 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Libraries.LCA_RESTRICTED/Builtins/RangeOps.cs;RubyBugFixesII @@ -14,15 +14,11 @@ * ***************************************************************************/ using System; -using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Text; using Microsoft.Scripting; -using Microsoft.Scripting.Math; using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Runtime; using Ruby.Runtime; -using Microsoft.Scripting.Runtime; -using System.ComponentModel; namespace Ruby.Builtins { /// =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C438696 File: Ruby.csproj =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;C438696 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj;RubyBugFixesII @@ -258,6 +258,7 @@ + @@ -288,4 +289,4 @@ mkdir "$(SolutionDir)..\..\Tools\Nessie\Nessie\bin\Debug" copy /y "$(TargetPath)" "$(SolutionDir)..\..\Tools\Nessie\Nessie\bin\Debug" - + \ No newline at end of file =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Ruby.csproj.vspscc;C390406 add: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Utils.cs File: Utils.cs =================================================================== --- [no source file] +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Utils.cs;RubyBugFixesII @@ -1,0 +1,40 @@ +?/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Microsoft Public License. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Microsoft Public License, please send an email to + * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Microsoft Public License. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Scripting.Utils; +using Ruby.Runtime; + +namespace Ruby { + public static class Utils { + public static class Array { + public static int IndexOf(/*this*/ string[]/*!*/ array, string/*!*/ value, StringComparer/*!*/ comparer) { + ContractUtils.RequiresNotNull(array, "array"); + ContractUtils.RequiresNotNull(value, "value"); + ContractUtils.RequiresNotNull(comparer, "comparer"); + + for (int i = 0; i < array.Length; i++) { + if (comparer.Equals(array[i], value)) { + return i; + } + } + + return -1; + } + } + } +} =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C438696 File: MutableString.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;C438696 (server) 5/15/2008 10:40 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Builtins/MutableString.cs;RubyBugFixesII @@ -662,7 +662,7 @@ #endregion - #region Remove, Clear + #region Remove, Clear, Reverse public MutableString/*!*/ Remove(int start, int count) { RequiresArrayRange(start, count); @@ -674,6 +674,29 @@ _content = _content.GetSlice(0, 0); } + public MutableString/*!*/ Reverse() { + // TODO: + if (IsBinary) { + int length = Length; + for (int i = 0; i < length / 2; i++) { + byte a = GetByte(i); + byte b = GetByte(length - i - 1); + SetByte(i, b); + SetByte(length - i - 1, a); + } + } else { + int length = Length; + for (int i = 0; i < length / 2; i++) { + char a = GetChar(i); + char b = GetChar(length - i - 1); + SetChar(i, b); + SetChar(length - i - 1, a); + } + } + + return this; + } + #endregion #region Misc =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/MemberAssignmentExpression.cs;C437359 File: MemberAssignmentExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/MemberAssignmentExpression.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/MemberAssignmentExpression.cs;RubyBugFixesII @@ -23,14 +23,14 @@ using MSA = Microsoft.Scripting.Ast; using Ast = Microsoft.Scripting.Ast.Expression; - // lhs.id op= rhs + // left.id op= rigth public partial class MemberAssignmentExpression : AssignmentExpression { - private readonly Expression/*!*/ _left; + private readonly Expression/*!*/ _leftTarget; private readonly Expression/*!*/ _right; private readonly SymbolId _memberName; - public Expression/*!*/ Left { - get { return _left; } + public Expression/*!*/ LeftTarget { + get { return _leftTarget; } } public Expression/*!*/ Right { @@ -41,29 +41,45 @@ get { return _memberName; } } - public MemberAssignmentExpression(Expression/*!*/ left, SymbolId memberName, SymbolId operation, Expression/*!*/ right, SourceSpan location) + public MemberAssignmentExpression(Expression/*!*/ leftTarget, SymbolId memberName, SymbolId operation, Expression/*!*/ right, SourceSpan location) : base(operation, location) { - ContractUtils.RequiresNotNull(left, "left"); + ContractUtils.RequiresNotNull(leftTarget, "leftTarget"); ContractUtils.RequiresNotNull(operation, "operation"); ContractUtils.RequiresNotNull(right, "right"); ContractUtils.Requires(!memberName.IsEmpty, "memberName"); ContractUtils.Requires(!operation.IsEmpty, "operation"); _memberName = memberName; - _left = left; + _leftTarget = leftTarget; _right = right; } internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { SymbolId setterName = SymbolTable.StringToId(SymbolTable.IdToString(_memberName) + "="); - // left.member= left.member().op(right) + MSA.Expression transformedLeftTarget = _leftTarget.TransformRead(gen); + MSA.Expression transformedRight = _right.TransformRead(gen); - MSA.Expression leftMemberRead = MethodCall.TransformRead(gen, _memberName, _left, null, null, null); - MSA.Expression operationCall = MethodCall.TransformRead(gen, Operation, leftMemberRead, null, _right.TransformRead(gen), null); - MSA.Expression assignment = MethodCall.TransformRead(gen, setterName, _left, null, null, operationCall); + MSA.Expression leftTemp = gen.CurrentCodeBlock.CreateTemporaryVariable(Symbols.None, transformedLeftTarget.Type); - return assignment; + // lhs &&= rhs --> left.member && (left.member = rhs) + // lhs ||= rhs --> left.member || (left.member = rhs) + if (Operation == Symbols.And || Operation == Symbols.Or) { + MSA.Expression leftMemberRead = MethodCall.TransformRead(gen, _memberName, Ast.Assign(leftTemp, transformedLeftTarget), null, null, null); + MSA.Expression transformedWrite = MethodCall.TransformRead(gen, setterName, leftTemp, null, null, transformedRight); + + if (Operation == Symbols.And) { + return AndExpression.TransformRead(gen, leftMemberRead, transformedWrite); + } else { + return OrExpression.TransformRead(gen, leftMemberRead, transformedWrite); + } + } else { + // left.member= left.member().op(right) + MSA.Expression leftMemberRead = MethodCall.TransformRead(gen, _memberName, leftTemp, null, null, null); + MSA.Expression operationCall = MethodCall.TransformRead(gen, Operation, leftMemberRead, null, transformedRight, null); + MSA.Expression transformedWrite = MethodCall.TransformRead(gen, setterName, Ast.Assign(leftTemp, transformedLeftTarget), null, null, operationCall); + return transformedWrite; + } } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/SimpleAssignmentExpression.cs;C437359 File: SimpleAssignmentExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/SimpleAssignmentExpression.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Assignments/SimpleAssignmentExpression.cs;RubyBugFixesII @@ -51,22 +51,47 @@ } internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - MSA.Expression transformedRhs; - if (_operation == Symbols.And) { - // lhs &&= rhs - transformedRhs = AndExpression.TransformRead(gen, _left, _right); - } else if (_operation == Symbols.Or) { - // lhs ||= rhs - transformedRhs = OrExpression.TransformRead(gen, _left, _right); - } else if (_operation != SymbolId.Empty) { - // lhs op= rhs - transformedRhs = MethodCall.TransformRead(gen, _operation, _left, null, _right.TransformRead(gen), null); + // first, read target into a temp: + MSA.Expression transformedLeftTarget = _left.TransformTargetRead(gen); + MSA.Expression leftTargetTemp; + + if (transformedLeftTarget != null) { + leftTargetTemp = gen.CurrentCodeBlock.CreateTemporaryVariable(Symbols.None, transformedLeftTarget.Type); } else { - transformedRhs = _right.TransformRead(gen); + leftTargetTemp = null; } - return _left.TransformWrite(gen, transformedRhs); + MSA.Expression transformedRight = _right.TransformRead(gen); + + // lhs &&= rhs --> lhs && (lhs = rhs) + // lhs ||= rhs --> lhs || (lhs = rhs) + if (_operation == Symbols.And || _operation == Symbols.Or) { + MSA.Expression transformedLeftRead = _left.TransformRead(gen, + (transformedLeftTarget != null) ? Ast.Assign(leftTargetTemp, transformedLeftTarget) : null, + true // tryRead + ); + + MSA.Expression transformedWrite = _left.TransformWrite(gen, leftTargetTemp, transformedRight); + + if (_operation == Symbols.And) { + return AndExpression.TransformRead(gen, transformedLeftRead, transformedWrite); + } else { + return OrExpression.TransformRead(gen, transformedLeftRead, transformedWrite); + } + } else { + // lhs op= rhs --> lhs = lhs op rhs + if (_operation != SymbolId.Empty) { + MSA.Expression transformedLeftRead = _left.TransformRead(gen, leftTargetTemp, false); + transformedRight = MethodCall.TransformRead(gen, _operation, transformedLeftRead, null, transformedRight, null); + } + + // transform lhs write assigning lhs-target temp: + return _left.TransformWrite(gen, + (transformedLeftTarget != null) ? Ast.Assign(leftTargetTemp, transformedLeftTarget) : null, + transformedRight + ); + } } internal override string GetNodeName(AstGenerator gen) { =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/AndExpression.cs;C402444 File: AndExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/AndExpression.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/AndExpression.cs;RubyBugFixesII @@ -49,14 +49,14 @@ } internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - return TransformRead(gen, _left, _right); + return TransformRead(gen, _left.TransformRead(gen), _right.TransformRead(gen)); } - internal static MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, Expression/*!*/ left, Expression/*!*/ right) { + internal static MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression/*!*/ left, MSA.Expression/*!*/ right) { return Ast.CoalesceTrue( gen.CurrentCodeBlock, - Ast.ConvertHelper(left.TransformRead(gen), typeof(object)), - Ast.ConvertHelper(right.TransformRead(gen), typeof(object)), + Ast.ConvertHelper(left, typeof(object)), + Ast.ConvertHelper(right, typeof(object)), RubyOps.GetMethod("IsTrue") ); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/MethodCall.cs;C437564 edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/OrExpression.cs;C402444 File: OrExpression.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/OrExpression.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Expressions/OrExpression.cs;RubyBugFixesII @@ -47,14 +47,14 @@ } internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - return TransformRead(gen, _left, _right); + return TransformRead(gen, _left.TransformRead(gen), _right.TransformRead(gen)); } - internal static MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, Expression/*!*/ left, Expression/*!*/ right) { + internal static MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression/*!*/ left, MSA.Expression/*!*/ right) { return Ast.CoalesceFalse( gen.CurrentCodeBlock, - Ast.ConvertHelper(left.TransformRead(gen), typeof(object)), - Ast.ConvertHelper(right.TransformRead(gen), typeof(object)), + Ast.ConvertHelper(left, typeof(object)), + Ast.ConvertHelper(right, typeof(object)), RubyOps.GetMethod("IsTrue") ); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ArrayItemAccess.cs;C437359 File: ArrayItemAccess.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ArrayItemAccess.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ArrayItemAccess.cs;RubyBugFixesII @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Text; +using System.Diagnostics; using Microsoft.Scripting; using Microsoft.Scripting.Utils; @@ -46,13 +47,19 @@ _array = array; _arguments = arguments; } + + internal override MSA.Expression TransformTargetRead(AstGenerator/*!*/ gen) { + return _array.TransformRead(gen); + } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - return MethodCall.TransformRead(gen, Symbols.ArrayItemRead, _array, _arguments, null, null); + internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression targetValue, bool tryRead) { + Assert.NotNull(gen, targetValue); + return MethodCall.TransformRead(gen, Symbols.ArrayItemRead, targetValue, _arguments, null, null); } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { - return MethodCall.TransformRead(gen, Symbols.ArrayItemWrite, _array, _arguments, null, rightValue); + internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression target, MSA.Expression/*!*/ rightValue) { + Assert.NotNull(target); + return MethodCall.TransformRead(gen, Symbols.ArrayItemWrite, target, _arguments, null, rightValue); } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/AttributeAccess.cs;C437359 File: AttributeAccess.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/AttributeAccess.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/AttributeAccess.cs;RubyBugFixesII @@ -47,10 +47,6 @@ _qualifier = qualifier; } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { - return MethodCall.TransformRead(gen, _name, _qualifier, null, null, rightValue); - } - internal override string/*!*/ GetNodeName(AstGenerator/*!*/ gen) { return "assignment"; } @@ -59,8 +55,17 @@ return null; } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - throw Assert.Unreachable; + internal override MSA.Expression TransformTargetRead(AstGenerator/*!*/ gen) { + return _qualifier.TransformRead(gen); } + + internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression targetValue, bool tryRead) { + throw Assert.Unreachable; + } + + internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ targetValue, MSA.Expression/*!*/ rightValue) { + Assert.NotNull(gen, targetValue, rightValue); + return MethodCall.TransformRead(gen, _name, targetValue, null, null, rightValue); + } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ClassVariable.cs;C402444 File: ClassVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ClassVariable.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ClassVariable.cs;RubyBugFixesII @@ -29,10 +29,6 @@ Debug.Assert(SymbolTable.IdToString(name).StartsWith("@@")); } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { - return TransformRead(gen, "Get"); - } - private MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, string/*!*/ opPrefix) { // eval or in a non-singleton module/class declaration // -> we find the right scope at runtime by walking the hierarchy @@ -46,7 +42,11 @@ } } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { + return TransformRead(gen, tryRead ? "TryGet" : "Get"); + } + + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { if (gen.CompilerOptions.IsEval || gen.GetCurrentNonSingletonModule() != null) { return AstFactory.OpCall("SetClassVariable", rightValue, Ast.CodeContext(), Ast.Constant(Name)); } else { =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/CompoundLeftValue.cs;C437359 File: CompoundLeftValue.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/CompoundLeftValue.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/CompoundLeftValue.cs;RubyBugFixesII @@ -57,11 +57,16 @@ _unsplattedValue = unsplattedValue; } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression targetValue, bool tryRead) { throw Assert.Unreachable; } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression TransformTargetRead(AstGenerator/*!*/ gen) { + return null; + } + + internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression targetValue, MSA.Expression/*!*/ rightValue) { + Debug.Assert(targetValue == null); return TransformWrite(gen, CollectionUtils.MakeList(rightValue), null); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ConstantVariable.cs;C429806 File: ConstantVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ConstantVariable.cs;C429806 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/ConstantVariable.cs;RubyBugFixesII @@ -93,7 +93,7 @@ } } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { return TransformRead(gen, "Get"); } @@ -115,7 +115,7 @@ throw Assert.Unreachable; } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { MSA.Expression transformedName = TransformSymbolName(gen); MSA.Expression transformedQualifier; =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/GlobalVariable.cs;C402444 File: GlobalVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/GlobalVariable.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/GlobalVariable.cs;RubyBugFixesII @@ -31,11 +31,11 @@ Debug.Assert(name.ToString() == "$" || !name.ToString().StartsWith("$")); } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { return AstFactory.OpCall("GetGlobalVariable", Ast.CodeContext(), TransformSymbolName(gen)); } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { return AstFactory.OpCall("SetGlobalVariable", rightValue, Ast.CodeContext(), TransformSymbolName(gen)); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/InstanceVariable.cs;C402444 File: InstanceVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/InstanceVariable.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/InstanceVariable.cs;RubyBugFixesII @@ -29,11 +29,11 @@ Debug.Assert(SymbolTable.IdToString(name).StartsWith("@")); } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { return AstFactory.OpCall("GetInstanceVariable", Ast.CodeContext(), gen.CurrentSelfVariable, Ast.Constant(Name)); } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { return AstFactory.OpCall("SetInstanceVariable", Ast.CodeContext(), gen.CurrentSelfVariable, Ast.Constant(Name), rightValue); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LeftValue.cs;C402444 File: LeftValue.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LeftValue.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LeftValue.cs;RubyBugFixesII @@ -29,8 +29,24 @@ : base(location) { } - internal abstract MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue); + // Gets an expression that evaluates to the part of the left value that represents a holder (target) of the left value; + // For example target.bar, target[key], ... + // This target is passed to the TransformWrite by assignment expressions. + // This is necessary to prevent redundant evaluation of the target expression in in-place assignment left op= right. + // Returns null if the left value doesn't have target expression. + internal abstract MSA.Expression TransformTargetRead(AstGenerator/*!*/ gen); + + internal sealed override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + return TransformRead(gen, TransformTargetRead(gen), false); + } + + internal MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + return TransformWrite(gen, TransformTargetRead(gen), rightValue); + } + internal abstract MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression targetValue, bool tryRead); + internal abstract MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression targetValue, MSA.Expression/*!*/ rightValue); + internal virtual List/*!*/ ToList() { List result = new List(); result.Add(this); =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LocalVariable.cs;C420856 File: LocalVariable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LocalVariable.cs;C420856 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/LocalVariable.cs;RubyBugFixesII @@ -34,7 +34,7 @@ _containingScope = containingScope; } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { VariableInfo var = _containingScope.ResolveVariable(Name); if (var.TransformedVariable != null) { // static lookup: @@ -45,7 +45,7 @@ } } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { VariableInfo var = _containingScope.ResolveVariable(Name); if (var.TransformedVariable != null) { // static lookup: =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Placeholder.cs;C437359 File: Placeholder.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Placeholder.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Placeholder.cs;RubyBugFixesII @@ -27,18 +27,18 @@ /// Used as a null LHS without backing storage. /// E.g. 'a, = 1' is represented as 'ParallelAssignment(CoumpoundLeftValue(Variable, Placeholder), CompoundRightValue(Constant)) /// - public partial class Placeholder : LeftValue { + public partial class Placeholder : Variable { public static readonly Placeholder/*!*/ Singleton = new Placeholder(); private Placeholder() - : base(SourceSpan.None) { + : base(SymbolId.Empty, SourceSpan.None) { } - internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen) { + internal override MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead) { throw Assert.Unreachable; } - internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { + internal override MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue) { Assert.NotNull(gen, rightValue); // no-op =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Variable.cs;C402444 File: Variable.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Variable.cs;C402444 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/LeftValues/Variable.cs;RubyBugFixesII @@ -40,5 +40,22 @@ internal MSA.Expression/*!*/ TransformSymbolName(AstGenerator/*!*/ gen) { return Ast.Constant(_name); } + + internal sealed override MSA.Expression TransformTargetRead(AstGenerator/*!*/ gen) { + return null; + } + + internal abstract MSA.Expression/*!*/ TransformReadVariable(AstGenerator/*!*/ gen, bool tryRead); + internal abstract MSA.Expression/*!*/ TransformWriteVariable(AstGenerator/*!*/ gen, MSA.Expression/*!*/ rightValue); + + internal override MSA.Expression/*!*/ TransformRead(AstGenerator/*!*/ gen, MSA.Expression targetValue, bool tryRead) { + Debug.Assert(targetValue == null); + return TransformReadVariable(gen, tryRead); + } + + internal override MSA.Expression/*!*/ TransformWrite(AstGenerator/*!*/ gen, MSA.Expression targetValue, MSA.Expression/*!*/ rightValue) { + Debug.Assert(targetValue == null); + return TransformWriteVariable(gen, rightValue); + } } } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Walkers/Walker.cs;C437359 File: Walker.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Walkers/Walker.cs;C437359 (server) 5/15/2008 10:00 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Ast/Walkers/Walker.cs;RubyBugFixesII @@ -137,7 +137,7 @@ internal protected virtual void Walk(MemberAssignmentExpression/*!*/ node) { if (Enter(node)) { - node.Left.Walk(this); + node.LeftTarget.Walk(this); node.Right.Walk(this); } Exit(node); =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;C438696 File: Parser.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;C438696 (server) 5/15/2008 11:36 AM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Compiler/Parser/Parser.cs;RubyBugFixesII @@ -293,10 +293,8 @@ } private ArrayConstructor/*!*/ MakeVerbatimWords(List/*!*/ words, SourceSpan wordsLocation, SourceSpan location) { -#if !SILVERLIGHT - Debug.Assert(words.TrueForAll(delegate(Expression/*!*/ word) { return word is Literal && ((Literal)word).Value is string; }), + Debug.Assert(CollectionUtils.TrueForAll(words, delegate(Expression/*!*/ word) { return word is Literal && ((Literal)word).Value is string; }), "all words are string literals"); -#endif return new ArrayConstructor(new Arguments(words, null, null, null, wordsLocation), location); } =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;C436555 File: Loader.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;C436555 (server) 5/14/2008 7:51 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs;RubyBugFixesII @@ -15,25 +15,19 @@ using System; using System.IO; -using System.Text; using System.Diagnostics; -using System.Collections; +using System.Reflection; +using System.Text.RegularExpressions; using System.Collections.Generic; -using Assembly = System.Reflection.Assembly; -using Microsoft.Scripting; -using Microsoft.Scripting.Hosting; - -using Ruby.Runtime; -using Ruby.Hosting; using Ruby.Compiler; using Ruby.Builtins; +using Ruby.Runtime.Calls; + +using Microsoft.Scripting; using Microsoft.Scripting.Utils; using Microsoft.Scripting.Runtime; -using System.Reflection; -using System.Text.RegularExpressions; using Microsoft.Scripting.Actions; -using Ruby.Runtime.Calls; namespace Ruby.Runtime { [Flags] @@ -62,6 +56,9 @@ // $" private readonly RubyArray/*!*/ _loadedFiles; + // files that were required but their execution haven't completed yet: + private readonly Stack/*!*/ _unfinishedFiles; + /// /// TODO: Thread safety: the user of this object is responsible for locking it. /// @@ -93,6 +90,7 @@ _loadPaths.Add(MutableString.Create(".")); _loadedFiles = new RubyArray(); + _unfinishedFiles = new Stack(); } /// @@ -117,7 +115,7 @@ } } - return LoadSourceFile(context, self, strPath, flags); + return LoadFromPath(context, self, strPath, flags); } public bool LoadAssembly(string/*!*/ assemblyName, string typeName, bool throwOnError) { @@ -185,39 +183,74 @@ return false; } - private bool LoadSourceFile(CodeContext/*!*/ context, object self, string/*!*/ path, LoadFlags flags) { + private class ResolvedFile { + public readonly SourceUnit SourceUnit; + public readonly string/*!*/ Path; + public readonly string AppendedExtension; + + public ResolvedFile(SourceUnit/*!*/ sourceUnit, string appendedExtension) { + SourceUnit = sourceUnit; + Path = sourceUnit.Path; + AppendedExtension = appendedExtension; + } + + public ResolvedFile(string/*!*/ libraryPath, string appendedExtension) { + Assert.NotNull(libraryPath); + Path = libraryPath; + AppendedExtension = appendedExtension; + } + } + + private bool LoadFromPath(CodeContext/*!*/ context, object self, string/*!*/ path, LoadFlags flags) { Assert.NotNull(context, path); - SourceUnit sourceUnit = FindSourceUnit(context, path, (flags & LoadFlags.AppendExtensions) != 0); - if (sourceUnit == null) { + ResolvedFile file = FindFile(context, path, (flags & LoadFlags.AppendExtensions) != 0); + if (file == null) { throw new LoadError(String.Format("no such file to load -- {0}", path)); } MutableString pathWithExtension = MutableString.Create(path); - if (Path.GetExtension(path).Length == 0) { - pathWithExtension.Append(Path.GetExtension(sourceUnit.Path)); + if (file.AppendedExtension != null) { + pathWithExtension.Append(file.AppendedExtension); } - if (AlreadyLoaded(context, pathWithExtension, flags)) { + if (AlreadyLoaded(context, pathWithExtension, flags) || _unfinishedFiles.Contains(pathWithExtension.ToString())) { return false; } - RubyContext rubySource = sourceUnit.LanguageContext as RubyContext; - if (rubySource != null) { - RubyCompilerOptions options = new RubyCompilerOptions(); - options.IsIncluded = true; - options.IsWrapped = (flags & LoadFlags.LoadIsolated) != 0; - sourceUnit.Compile(options, _executionContext.RuntimeErrorSink).Run(context, false); - } else { - // TODO: publish scope? - sourceUnit.Execute(); + try { + // save path as is, no canonicalization nor combination with an extension or directory: + _unfinishedFiles.Push(pathWithExtension.ToString()); + + if (file.SourceUnit != null) { + RubyContext rubySource = file.SourceUnit.LanguageContext as RubyContext; + if (rubySource != null) { + RubyCompilerOptions options = new RubyCompilerOptions(); + options.IsIncluded = true; + options.IsWrapped = (flags & LoadFlags.LoadIsolated) != 0; + file.SourceUnit.Compile(options, _executionContext.RuntimeErrorSink).Run(context, false); + } else { + // TODO: publish scope? + file.SourceUnit.Execute(); + } + } else { + Debug.Assert(file.Path != null); + try { + DomainManager.LoadAssembly(Platform.LoadAssemblyFromPath(Platform.GetFullPath(file.Path))); + } catch (Exception e) { + throw new LoadError(e.Message, e); + } + } + + AddLoadedFile(pathWithExtension); + } finally { + _unfinishedFiles.Pop(); } - AddLoadedFile(pathWithExtension); return true; } - private SourceUnit FindSourceUnit(CodeContext/*!*/ context, string/*!*/ path, bool appendExtensions) { + private ResolvedFile FindFile(CodeContext/*!*/ context, string/*!*/ path, bool appendExtensions) { Assert.NotNull(path); bool isAbsolutePath; string extension; @@ -229,9 +262,12 @@ throw new LoadError(e.Message, e); } + string[] knownExtensions = DomainManager.GetRegisteredFileExtensions(); + Array.Sort(knownExtensions, StringComparer.OrdinalIgnoreCase); + // absolute path -> LoadPaths not consulted: if (isAbsolutePath) { - return ResolveSourceUnit(path, extension, appendExtensions); + return ResolveFile(path, extension, appendExtensions, knownExtensions); } foreach (object dir in GetLoadPaths()) { @@ -242,7 +278,7 @@ string strDir = _toStrSite.Invoke(context, dir).ConvertToString(); try { - SourceUnit result = ResolveSourceUnit(Path.Combine(strDir, path), extension, appendExtensions); + ResolvedFile result = ResolveFile(Path.Combine(strDir, path), extension, appendExtensions, knownExtensions); if (result != null) { return result; } @@ -254,29 +290,43 @@ return null; } - private SourceUnit ResolveSourceUnit(string/*!*/ path, string/*!*/ extension, bool appendExtensions) { + private ResolvedFile ResolveFile(string/*!*/ path, string/*!*/ extension, bool appendExtensions, string[]/*!*/ knownExtensions) { Debug.Assert(Path.GetExtension(path) == extension); - // MRI doesn't load file w/o extension: - if (extension.Length > 0) { - if (Platform.FileExists(path)) { - return GetSourceUnit(path, extension); - } - } else if (appendExtensions) { - List matchingExtensions = GetExtensionsOfExistingFiles(path, DomainManager.GetRegisteredFileExtensions()); + // MRI doesn't load file w/o .rb extension: + if (IsKnownExtension(extension, knownExtensions)) { + return GetSourceUnit(path, extension, false); + } else if (Utils.Array.IndexOf(_LibraryExtensions, extension, StringComparer.OrdinalIgnoreCase) != -1 && Platform.FileExists(path)) { + return new ResolvedFile(path, null); + } + if (appendExtensions) { + List matchingExtensions = GetExtensionsOfExistingFiles(path, knownExtensions); + if (matchingExtensions.Count == 1) { - return GetSourceUnit(path + matchingExtensions[0], matchingExtensions[0]); + return GetSourceUnit(path + matchingExtensions[0], matchingExtensions[0], true); } else if (matchingExtensions.Count > 1) { Exception e = new AmbiguousFileNameException(path + matchingExtensions[0], path + matchingExtensions[1]); throw new LoadError(e.Message, e); } + + foreach (string libExtension in _LibraryExtensions) { + if (Platform.FileExists(path + libExtension)) { + return new ResolvedFile(path + libExtension, libExtension); + } + } } return null; } - private SourceUnit GetSourceUnit(string/*!*/ path, string/*!*/ extension) { + private static readonly string[] _LibraryExtensions = new string[] { ".dll", ".so" }; + + private static bool IsKnownExtension(string/*!*/ extension, string[]/*!*/ knownExtensions) { + return extension.Length > 0 && Array.BinarySearch(knownExtensions, extension, StringComparer.OrdinalIgnoreCase) > 0; + } + + private ResolvedFile GetSourceUnit(string/*!*/ path, string/*!*/ extension, bool extensionAppended) { Assert.NotNull(path, extension); LanguageContext language; @@ -286,7 +336,8 @@ } // TODO: default encoding: - return DomainManager.Host.TryGetSourceFileUnit(language, path, StringUtils.DefaultEncoding, SourceCodeKind.File); + SourceUnit sourceUnit = DomainManager.Host.TryGetSourceFileUnit(language, path, StringUtils.DefaultEncoding, SourceCodeKind.File); + return (sourceUnit != null) ? new ResolvedFile(sourceUnit, extensionAppended ? extension : null) : null; } private List/*!*/ GetExtensionsOfExistingFiles(string/*!*/ path, IEnumerable/*!*/ extensions) { =================================================================== edit: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C438696 File: RubyOps.cs =================================================================== --- $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;C438696 (server) 5/15/2008 1:35 PM +++ Shelved Change: $/Dev10/feature/vs_langs01/Merlin/Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs;RubyBugFixesII @@ -1135,6 +1135,21 @@ } // emitted: + public static object TryGetObjectClassVariable(CodeContext/*!*/ context, SymbolId name) { + object value; + RubyUtils.GetExecutionContext(context).ObjectClass.TryGetClassVariable(name, out value); + return value; + } + + // emitted: + public static object TryGetClassVariable(CodeContext/*!*/ context, SymbolId name) { + object value; + // owner is the first module in scope: + RubyUtils.GetExecutionContext(context).GetInnerMostModule(context, true).TryResolveClassVariable(name, out value); + return value; + } + + // emitted: public static bool IsDefinedObjectClassVariable(CodeContext/*!*/ context, SymbolId name) { object value; return RubyUtils.GetExecutionContext(context).ObjectClass.TryResolveClassVariable(name, out value) != null; ===================================================================