Commits

Anonymous committed 0d35be8

30178 clr.CompileModules fails for in-line dictionary initialization that uses tuples as values
30165 cannot create weak reference to old class, generator, possibly others.
30153 set union of set union raises NullReferenceException
30130 IronPython doesn't deliver traceback frames with exception event when tracing is enabled
30129 sys.settrace throws an exception when called on non-top most frame
28223 ',' is now a valid float format specifier

Also fixing a broken test which isn't recognizing RC version number
And fixing regression on last checkin related to formatting hex numbers

Comments (0)

Files changed (17)

Languages/IronPython/IronPython/Compiler/Ast/ConstantExpression.cs

 
         internal override string CheckAssign() {
             if (_value == null) {
-                return "assignment to None";
+                return "cannot assign to None";
             }
 
             return "can't assign to literal";

Languages/IronPython/IronPython/Compiler/Ast/TupleExpression.cs

 using Microsoft.Scripting;
 using Microsoft.Scripting.Runtime;
 
+using IronPython.Runtime;
 using IronPython.Runtime.Binding;
+using IronPython.Runtime.Operations;
 
 #if !CLR2
 using MSAst = System.Linq.Expressions;
 
 namespace IronPython.Compiler.Ast {
     using Ast = MSAst.Expression;
-    using IronPython.Runtime.Operations;
 
     public class TupleExpression : SequenceExpression {
         private bool _expandable;
         }
 
         internal override object GetConstantValue() {
+            if (Items.Count == 0) {
+                return PythonTuple.EMPTY;
+            }
+
             object[] items = new object[Items.Count];
             for (int i = 0; i < items.Length; i++) {
                 items[i] = Items[i].GetConstantValue();

Languages/IronPython/IronPython/Runtime/Exceptions/TraceBack.cs

             }
         }
 
-        public object tb_frame {
+        public TraceBackFrame tb_frame {
             get {
                 return _frame;
             }
 
         private void SetLineNumber(int newLineNum) {
             var pyThread = PythonOps.GetFunctionStackNoCreate();
-            if (!TracingThisFrame(pyThread)) {
-                throw PythonOps.ValueError("f_lineno can only be set by a trace function");
+            if (!IsTopMostFrame(pyThread)) {
+                if (!TracingThisFrame(pyThread)) {
+                    throw PythonOps.ValueError("f_lineno can only be set by a trace function");
+                } else {
+                    return;
+                }
             }
 
             FunctionCode funcCode = _debugProperties.Code;
         }
 
         private bool TracingThisFrame(List<FunctionStack> pyThread) {
-            return pyThread != null &&  pyThread.Count != 0 && Type.ReferenceEquals(this, pyThread[pyThread.Count - 1].Frame);
+            return pyThread != null &&
+                pyThread.FindIndex(x => x.Frame == this) != -1;
+        }
+
+        private bool IsTopMostFrame(List<FunctionStack> pyThread) {
+            return pyThread != null && pyThread.Count != 0 && Type.ReferenceEquals(this, pyThread[pyThread.Count - 1].Frame);
         }
 
         private static Exception BadForOrFinallyJump(int newLineNum, Dictionary<int, bool> jumpIntoLoopIds) {

Languages/IronPython/IronPython/Runtime/Generator.cs

 namespace IronPython.Runtime {
     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix"), PythonType("generator")]
     [DontMapIDisposableToContextManager, DontMapIEnumerableToContains]
-    public sealed class PythonGenerator : IEnumerator, IEnumerator<object>, ICodeFormattable, IEnumerable {
+    public sealed class PythonGenerator : IEnumerator, IEnumerator<object>, ICodeFormattable, IEnumerable, IWeakReferenceable {
         private readonly Func<MutableTuple, object>/*!*/ _next;     // The delegate which contains the user code to perform the iteration.
         private readonly PythonFunction _function;                  // the function which created the generator
         private readonly MutableTuple _data;                        // the closure data we need to pass into each iteration.  Item000 is the index, Item001 is the current value
         /// Since send() could send an exception, we need to keep this different from throwable's value.
         /// </summary>
         private object _sendValue;
+        private WeakRefTracker _tracker;
 
         internal PythonGenerator(PythonFunction function, Func<MutableTuple, object>/*!*/ next, MutableTuple data) {
             _function = function;
         }
 
         #endregion
+
+        #region IWeakReferenceable Members
+
+        WeakRefTracker IWeakReferenceable.GetWeakRef() {
+            return _tracker;
+        }
+
+        bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
+            _tracker = value;
+            return true;
+        }
+
+        void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
+            _tracker = value;
+        }
+
+        #endregion
     }
 }

Languages/IronPython/IronPython/Runtime/Operations/FloatOps.cs

                 return spec.AlignNumericText(digits, false, Double.IsNaN(self) || Sign(self) > 0);
             } else {
                 // Always pass isZero=false so that -0.0 shows up
-                return spec.AlignNumericText(digits, false, Sign(self) > 0);
+                return spec.AlignNumericText(digits, false, Double.IsNaN(self) ?  true : Sign(self) > 0);
             }
         }
 

Languages/IronPython/IronPython/Runtime/Operations/ObjectOps.cs

                 throw PythonOps.ValueError("Sign not allowed in string format specifier");
             } else if (spec.Alignment == '=') {
                 throw PythonOps.ValueError("'=' alignment not allowed in string format specifier");
+            } else if (spec.ThousandsComma) {
+                throw PythonOps.ValueError("Cannot specify ',' with 's'.");
             }
 
             // apply precision to shorten the string first

Languages/IronPython/IronPython/Runtime/Operations/PythonOps.cs

                         context,
                         context.GlobalDict,
                         context.Dict,
-                        code);
+                        code,
+                        tb != null ? tb.tb_frame : null);
 
                     tb = new TraceBack(tb, tbf);
                     tb.SetLine(frame.GetFileLineNumber());
                 if (pyFrames == null) {
                     e.SetFrameList(pyFrames = new List<DynamicStackFrame>());
                 }
-
+                
                 var frame = new PythonDynamicStackFrame(context, funcCode, line);
                 funcCode.LightThrowCompile(context);
                 pyFrames.Add(frame);

Languages/IronPython/IronPython/Runtime/PythonTracebackListener.cs

                     traceEvent = "exception";
                     object pyException = PythonExceptions.ToPython((Exception)payload);
                     object pyType = ((IPythonObject)pyException).PythonType;
-                    args = PythonTuple.MakeTuple(pyType, pyException, null);
+                    args = PythonTuple.MakeTuple(pyType, pyException, new TraceBack(null, pyFrame));
                     break;
                 case Debugging.TraceEventKind.FrameExit:
                     traceEvent = "return";

Languages/IronPython/IronPython/Runtime/PythonTuple.cs

 using Microsoft.Scripting.Runtime;
 using Microsoft.Scripting.Utils;
 
+using IronPython.Compiler.Ast;
+
 using IronPython.Runtime.Exceptions;
 using IronPython.Runtime.Operations;
 using IronPython.Runtime.Types;
 
 #if CLR2
 using Microsoft.Scripting.Math;
+using MSAst = Microsoft.Scripting.Ast;
 #else
 using System.Numerics;
+using MSAst = System.Linq.Expressions;
 #endif
 
+using Utils = Microsoft.Scripting.Ast.Utils;
+
 namespace IronPython.Runtime {
+    using Ast = MSAst.Expression;
+
     [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
     [PythonType("tuple"), Serializable, DebuggerTypeProxy(typeof(CollectionDebugProxy)), DebuggerDisplay("tuple, {Count} items")]
-    public class PythonTuple : ICollection, IEnumerable, IEnumerable<object>, IList, IList<object>, ICodeFormattable,
+    public class PythonTuple : ICollection, IEnumerable, IEnumerable<object>, IList, IList<object>, ICodeFormattable, IExpressionSerializable,
 #if CLR2
         IValueEquality,
 #endif
         }
 
         #endregion
+
+        #region IExpressionSerializable Members
+
+        public System.Linq.Expressions.Expression CreateExpression() {
+            Ast[] items = new Ast[Count];
+            for (int i = 0; i < items.Length; i++) {
+                items[i] = Utils.Constant(this[i]);
+            }
+
+            return Ast.Call(
+                AstMethods.MakeTuple,
+                Ast.NewArrayInit(
+                    typeof(object),
+                    items
+                )
+            );
+
+        }
+
+        #endregion
     }
 
     /// <summary>

Languages/IronPython/IronPython/Runtime/SetStorage.cs

             }
 
             Bucket[] buckets = _buckets;
+            res._hashFunc = _hashFunc;
+            res._eqFunc = _eqFunc;
+            res._itemType = _itemType;
             if (_count < _buckets.Length * MinLoad) {
                 // If the set is sparsely populated, create a cleaner copy
                 res.Initialize(_count);
-                res.UpdateHelperFunctions(this);
 
                 for (int i = 0; i < buckets.Length; i++) {
                     Bucket bucket = buckets[i];
                 // Otherwise, perform a faster copy
                 res._maxCount = (int)(buckets.Length * Load);
                 res._buckets = new Bucket[buckets.Length];
-                res._hashFunc = _hashFunc;
-                res._eqFunc = _eqFunc;
-                res._itemType = _itemType;
 
                 for (int i = 0; i < buckets.Length; i++) {
                     Bucket bucket = buckets[i];

Languages/IronPython/IronPython/Runtime/StringFormatter.cs

             StringBuilder str = new StringBuilder();
             // use .NETs faster conversion if we can
             if (radix == 16) {
-                str.Append(Char.IsLower(format) ? val.ToString("x") : val.ToString("X"));
+                AppendNumberReversed(str, Char.IsLower(format) ? val.ToString("x") : val.ToString("X"));
             } else if (radix == 10) {
-                str.Append(val.ToString());
+                AppendNumberReversed(str, val.ToString());
             } else {
                 if (val == 0) str.Append('0');
                 while (val != 0) {
             }
         }
 
+        private static void AppendNumberReversed(StringBuilder str, string res) {
+            int start = 0;
+            while (start < (res.Length - 1) && res[start] == '0') {
+                start++;
+            }
+            for (int i = res.Length - 1; i >= start; i--) {
+                str.Append(res[i]);
+            }
+        }
+
         private void AppendHex(char format) {
             AppendBase(format, 16);
         }

Languages/IronPython/IronPython/Runtime/Types/OldClass.cs

  ICodeFormattable,
         IMembersList,
         IDynamicMetaObjectProvider, 
-        IPythonMembersList {
+        IPythonMembersList,
+        IWeakReferenceable {
 
         [NonSerialized]
         private List<OldClass> _bases;
 
         private int _optimizedInstanceNamesVersion;
         private string[] _optimizedInstanceNames;
+        private WeakRefTracker _tracker;
 
         public static string __doc__ = "classobj(name, bases, dict)";
 
                 }
             }
         }
+
+        #region IWeakReferenceable Members
+
+        WeakRefTracker IWeakReferenceable.GetWeakRef() {
+            return _tracker;
+        }
+
+        bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
+            _tracker = value;
+            return true;
+        }
+
+        void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
+            _tracker = value;
+        }
+
+        #endregion
     }
 }

Languages/IronPython/Tests/modules/system_related/sys_test.py

 def test_version():
     import re
     #E.g., 2.5.0 (IronPython 2.0 Alpha (2.0.0.800) on .NET 2.0.50727.1433)
-    regex = "^\d\.\d\.\d \(IronPython \d\.\d(\.\d)? ((Alpha \d+ )|(Beta \d+ )|())((DEBUG )|()|(\d?))\(\d\.\d\.\d{1,8}\.\d{1,8}\) on \.NET \d(\.\d{1,5}){3}\)$"
+    regex = "^\d\.\d\.\d \(IronPython \d\.\d(\.\d)? ((Alpha \d+ )|(Beta \d+ )|(RC \d+ )|())((DEBUG )|()|(\d?))\(\d\.\d\.\d{1,8}\.\d{1,8}\) on \.NET \d(\.\d{1,5}){3}\)$"
     Assert(re.match(regex, sys.version) != None)
 
 def test_winver():
               None, 'line', None, 'call', None, 'line', None, 'return', None, 
               'return', None])
 
+def test_cp30129():
+    frames = []
+    def f(*args):
+        if args[1] == 'call':
+            frames.append(args[0])
+            if len(frames) == 3:
+                res.append('setting' + str(frames[1].f_lineno))
+                frames[1].f_lineno = 447
+        return f
+    
+    
+    import sys
+    sys.settrace(f)
+    
+    res = []
+    def a():
+        res.append('foo')
+        res.append('bar')
+        res.append('baz')
+    
+    def b():
+        a()
+        res.append('x')
+        res.append('y')
+        res.append('z')
+    
+    def c():
+        b()
+        res.append('hello')
+        res.append('goodbye')
+        res.append('see ya')
+    
+    
+    c()
+    
+    AreEqual(res, ['setting447', 'foo', 'bar', 'baz', 'x', 'y', 'z', 'hello', 'goodbye', 'see ya'])
+    
+    sys.settrace(None)
+    
+
+def test_cp30130():
+    def f(frame, event, arg):
+        if event == 'exception':
+                global ex
+                ex = arg
+        return f
+    
+    sys.settrace(f)
+    
+    def g():
+        raise Exception()
+    
+    try:
+        g()
+    except:
+        pass
+    
+    exc_type = ex[0]
+    exc_value = ex[1]
+    tb_value = ex[2]
+    
+    print tb_value
+    import traceback
+    Assert(''.join(traceback.format_exception(exc_type, exc_value, tb_value)).find('line') != -1)
+    
+    sys.settrace(None)
+
 #--MAIN------------------------------------------------------------------------    
 
 testDelGetFrame = "Test_GetFrame" in sys.argv

Languages/IronPython/Tests/test_compiler.py

     AreEqual(cp20623.A, 35)
     #TODO: need to also generate a standalone exe from cp20623 and try running it
 
+def test_cp30178():
+    compileCode("cp30178", 'mydict = { "a": ("Fail", "tuple") }')
+    import cp30178
+    AreEqual(cp30178.mydict, {'a' : ('Fail', 'tuple')})
+
 #------------------------------------------------------------------------------        
 run_test(__name__)

Languages/IronPython/Tests/test_strformat.py

     # ensure only the s format type is recognized
     for char in allChars:
         if char != 's' and (char < '0' or char > '9'):
-            if char==',' and is_cpython: 
+            if char==',': 
                 errors.append(('10' + char, "Cannot specify ',' with 's'."))
-            elif char==',': #http://ironpython.codeplex.com/workitem/28377
-                temp = object.__format__(",")
             else:
                 errors.append(('10' + char, "Unknown format code '%s' for object of type 'str'" % char))
 
                     (999999999999.9,   '1.2',      '1.0e+12'),
                     (999999999999.0,   '',         '999999999999.0'),
                     (-999999999999.0,  '',         '-999999999999.0'),
-                    (10e667,           '+',        '+1.0#INF'),
-                    (-10e667,          '+',        '-1.0#INF'),
-                    (10e667/10e667,    '+',        '-1.0#IND'),
-                    (10e667,           '-',        '1.0#INF'),
-                    (-10e667,          '-',        '-1.0#INF'),
-                    (10e667/10e667,    '-',        '-1.0#IND'),
-                    (10e667,           ' ',        ' 1.0#INF'),
-                    (-10e667,          ' ',        '-1.0#INF'),
-                    (10e667/10e667,    ' ',        '-1.0#IND'),
+                    (10e667,           '+',        '+inf'),
+                    (-10e667,          '+',        '-inf'),
+                    (10e667/10e667,    '+',        '+nan'),
+                    (10e667,           '-',        'inf'),
+                    (-10e667,          '-',        '-inf'),
+                    (10e667/10e667,    '-',        'nan'),
+                    (10e667,           ' ',        ' inf'),
+                    (-10e667,          ' ',        '-inf'),
+                    (10e667/10e667,    ' ',        ' nan'),
                 ]
     
     tests+= [ (2.0,              '',         '2.0'),
 def test_float___format___errors():
     errors = []
     
-    okChars = set(['\0', '%', 'E', 'F', 'G', 'e', 'f', 'g', 'n'])
-    if is_cpython: #http://ironpython.codeplex.com/workitem/28223
-        okChars.add(',')
+    okChars = set(['\0', '%', 'E', 'F', 'G', 'e', 'f', 'g', 'n', ','])
     # verify the okChars are actually ok
     for char in okChars:
         2.0.__format__('10' + char)

Languages/IronPython/Tests/test_syntax.py

     #("'abc'.", "invalid syntax", 1),
 ]
 
-if is_ironpython or float(sys.winver) < 2.7: #http://ironpython.codeplex.com/workitem/28379
-    compile_tests.append(("None = 2", "assignment to None", 1, False))
-else:
-    compile_tests.append(("None = 2", "cannot assign to None", 1, False))
+compile_tests.append(("None = 2", "cannot assign to None", 1, False))
 
 # different error messages, ok
 for test in compile_tests:

Runtime/Microsoft.Dynamic/Generation/ToDiskRewriter.cs

                     }
 
                     // Add the consant pool variable to the top lambda
-                    body = AstUtils.AddScopedVariable(
-                        body,
+                    // We first create the array and then assign into it so that we can refer to the
+                    // array and read values out that have already been created.
+                    ReadOnlyCollectionBuilder<Expression> assigns = new ReadOnlyCollectionBuilder<Expression>(_constants.Count + 2);
+                    assigns.Add(Expression.Assign(
                         _constantPool,
-                        Expression.NewArrayInit(typeof(object), _constants)
-                    );
+                        Expression.NewArrayBounds(typeof(object), Expression.Constant(_constants.Count))
+                    ));
+
+                    // emit inner most constants first so they're available for outer most constants to consume
+                    for (int i = _constants.Count - 1; i >= 0 ; i--) {
+                        assigns.Add(
+                            Expression.Assign(
+                                Expression.ArrayAccess(_constantPool, Expression.Constant(i)),
+                                _constants[i]
+                            )
+                        );
+                    }
+                    assigns.Add(body);
+
+                    body = Expression.Block(new[] { _constantPool }, assigns);
                 }
 
                 // Rewrite the lambda