Browse Source

Introduce more informative data about discarded recursion + test + changed logic of recognizng recursion

auz34 11 years ago
parent
commit
49f43a9f6d

+ 44 - 0
Jint.Tests/Runtime/EngineTests.cs

@@ -674,6 +674,50 @@ namespace Jint.Tests.Runtime
             );
         }
 
+        [Fact]
+        public void ShouldProvideCallChainWhenDiscardRecursion()
+        {
+            var script = @" var funcRoot, funcA, funcB, funcC, funcD;
+
+            var funcRoot = function() {
+                funcA();
+            };
+ 
+            var funcA = function() {
+                funcB();
+            };
+
+            var funcB = function() {
+                funcC();
+            };
+
+            var funcC = function() {
+                funcD();
+            };
+
+            var funcD = function() {
+                funcRoot();
+            };
+
+            funcRoot();
+            ";
+
+            RecursionDiscardedException exception = null;
+
+            try
+            {
+                new Engine(cfg => cfg.DiscardRecursion()).Execute(script);
+            }
+            catch (RecursionDiscardedException ex)
+            {
+                exception = ex;
+            }
+
+            Assert.NotNull(exception);
+            Assert.Equal("funcRoot->funcA->funcB->funcC->funcD", exception.CallChain);
+            Assert.Equal("funcRoot", exception.CallExpressionReference);
+        }
+
         [Fact]
         public void ShouldConvertDoubleToStringWithoutLosingPrecision()
         {

+ 1 - 1
Jint/Engine.cs

@@ -37,7 +37,7 @@ namespace Jint
         // cache of types used when resolving CLR type names
         internal Dictionary<string, Type> TypeCache = new Dictionary<string, Type>();
 
-        internal Stack<CallExpression> CallStack = new Stack<CallExpression>(); 
+        internal Stack<Tuple<CallExpression, JsValue, string>> CallStack = new Stack<Tuple<CallExpression, JsValue, string>>();
 
         public Engine() : this(null)
         {

+ 4 - 4
Jint/Runtime/ExpressionIntepreter.cs

@@ -797,19 +797,19 @@ namespace Jint.Runtime
             var func = _engine.GetValue(callee);
             
             var r = callee as Reference;
+            var stackItem = new Tuple<CallExpression, JsValue, string>(callExpression, func, r.GetReferencedName());
 
-            //var funcName = r.GetReferencedName();
-            var recursionDepth = _engine.CallStack.Count(ce => ce == callExpression);
+            var recursionDepth = _engine.CallStack.Count(ce => ce.Item1 == callExpression || ce.Item2 == func);
 
             if (recursionDepth > 0)
             {
                 if (!_engine.Options.IsRecursionAllowed())
                 {
-                    throw new RecursionDiscardedException();
+                    throw new RecursionDiscardedException(_engine.CallStack, stackItem);
                 }
             }
 
-            _engine.CallStack.Push(callExpression);
+            _engine.CallStack.Push(stackItem);
 
             if (func == Undefined.Instance)
             {

+ 12 - 1
Jint/Runtime/RecursionDiscardedException.cs

@@ -5,11 +5,22 @@ using System.Text;
 
 namespace Jint.Runtime
 {
+    using Jint.Native;
+    using Jint.Parser.Ast;
+    using Jint.Runtime.References;
+
     public class RecursionDiscardedException : Exception 
     {
-        public RecursionDiscardedException()
+        public string CallChain { get; private set; }
+
+        public string CallExpressionReference { get; private set; }
+
+        public RecursionDiscardedException(Stack<Tuple<CallExpression, JsValue, string>> currentStack, Tuple<CallExpression, JsValue, string> currentExpression)
             : base("The recursion is forbidden by script host.")
         {
+            CallExpressionReference = currentExpression.Item3;
+
+            CallChain = string.Join("->", currentStack.Select(t => t.Item3).ToArray().Reverse());
         }
     }
 }