Browse Source

Implementing Function.prototype.apply

Sebastien Ros 12 năm trước cách đây
mục cha
commit
c04a606e27

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

@@ -481,6 +481,16 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void FunctionPrototypeShouldHaveApplyMethod()
+        {
+            RunTest(@"
+                var numbers = [5, 6, 2, 3, 7];
+                var max = Math.max.apply(null, numbers);
+                assert(max == 7);
+            ");
+        }
+
         [Theory]
         [InlineData(double.NaN, "parseInt(NaN)")]
         [InlineData(double.NaN, "parseInt(null)")]

+ 54 - 7
Jint/Native/Function/FunctionConstructor.cs

@@ -1,8 +1,10 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using Jint.Native.Object;
 using Jint.Parser.Ast;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
+using Jint.Runtime.Descriptors.Specialized;
 using Jint.Runtime.Environments;
 
 namespace Jint.Native.Function
@@ -13,7 +15,6 @@ namespace Jint.Native.Function
     public sealed class FunctionConstructor : FunctionInstance, IConstructor
     {
         private readonly Engine _engine;
-        private readonly IEnumerable<Identifier> _parameters;
 
         public FunctionConstructor(Engine engine)
             : base(engine, engine.RootFunction, null, null, false)
@@ -22,6 +23,9 @@ namespace Jint.Native.Function
             // http://www.ecma-international.org/ecma-262/5.1/#sec-13.2
 
             Extensible = true;
+
+            // Function.prototype properties
+            engine.RootFunction.DefineOwnProperty("apply", new ClrDataDescriptor<object, object>(engine, Apply), false);
         }
 
         public override object Call(object thisObject, object[] arguments)
@@ -57,15 +61,58 @@ namespace Jint.Native.Function
         }
 
         private FunctionInstance _throwTypeError;
-        public FunctionInstance ThrowTypeError { get
+
+        public FunctionInstance ThrowTypeError
         {
-            if (_throwTypeError != null)
+            get
             {
+                if (_throwTypeError != null)
+                {
+                    return _throwTypeError;
+                }
+
+                _throwTypeError = new ThrowTypeError(_engine);
                 return _throwTypeError;
             }
+        }
 
-            _throwTypeError = new ThrowTypeError(_engine);
-            return _throwTypeError;
-        }}
+        public object Apply(object thisObject, object[] arguments)
+        {
+            if (arguments.Length != 2)
+            {
+                throw new ArgumentException("Apply has to be called with two arguments.");
+            }
+
+            var func = thisObject as ICallable;
+            var thisArg = arguments[0];
+            var argArray = arguments[1];
+
+            if (func == null)
+            {
+                throw new JavaScriptException(_engine.TypeError);
+            }
+
+            if (argArray == Null.Instance || argArray == Undefined.Instance)
+            {
+                return func.Call(thisArg, Arguments.Empty);
+            }
+
+            var argArrayObj = argArray as ObjectInstance;
+            if (argArrayObj == null)
+            {
+                throw new JavaScriptException(_engine.TypeError);
+            }
+
+            var len = argArrayObj.Get("length");
+            var n = TypeConverter.ToUint32(len);
+            var argList = new List<object>();
+            for (var index = 0; index < n; index++)
+            {
+                var indexName = index.ToString();
+                var nextArg = argArrayObj.Get(indexName);
+                argList.Add(nextArg);
+            }
+            return func.Call(thisArg, argList.ToArray());
+        }
     }
 }

+ 0 - 3
Jint/Native/Function/FunctionInstance.cs

@@ -1,5 +1,4 @@
 using Jint.Native.Object;
-using Jint.Parser.Ast;
 using Jint.Runtime;
 using Jint.Runtime.Environments;
 
@@ -60,8 +59,6 @@ namespace Jint.Native.Function
                     return true;
                 }
             }
-
-            return false;
         }
 
         public override string Class

+ 1 - 4
Jint/Runtime/Interop/ClrFunctionInstance.cs

@@ -1,5 +1,4 @@
 using System;
-using Jint.Native;
 using Jint.Native.Function;
 
 namespace Jint.Runtime.Interop
@@ -9,13 +8,11 @@ namespace Jint.Runtime.Interop
     /// </summary>
     public sealed class ClrFunctionInstance<TObject, TResult> : FunctionInstance
     {
-        private readonly Engine _engine;
         private readonly Func<TObject, object[], TResult> _func;
 
         public ClrFunctionInstance(Engine engine, Func<TObject, object[], TResult> func)
-            : base(engine, null, null, null, false)
+            : base(engine, engine.Function, null, null, false)
         {
-            _engine = engine;
             _func = func;
         }