Browse Source

Implementing Function.prototype.bind

Sebastien Ros 12 years ago
parent
commit
e7767e9b35

+ 1 - 0
Jint/Jint.csproj

@@ -45,6 +45,7 @@
     <Compile Include="Native\Boolean\BooleanPrototype.cs" />
     <Compile Include="Native\Boolean\BooleanConstructor.cs" />
     <Compile Include="Native\Boolean\BooleanInstance.cs" />
+    <Compile Include="Native\Function\BindFunctionInstance.cs" />
     <Compile Include="Native\RegExp\RegExpConstructor.cs" />
     <Compile Include="Native\RegExp\RegExpInstance.cs" />
     <Compile Include="Native\RegExp\RegExpPrototype.cs" />

+ 53 - 0
Jint/Native/Function/BindFunctionInstance.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Linq;
+using Jint.Native.Object;
+using Jint.Runtime;
+
+namespace Jint.Native.Function
+{
+    public class BindFunctionInstance : FunctionInstance, IConstructor
+    {
+        public BindFunctionInstance(Engine engine) : base(engine, new string[0], null, false)
+        {
+        }
+
+        public object TargetFunction { get; set; }
+
+        public object BoundThis { get; set; }
+
+        public object[] BoundArgs { get; set; }
+
+        public override object Call(object thisObject, object[] arguments)
+        {
+            var f = TargetFunction as FunctionInstance;
+            if (f == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            return f.Call(BoundThis, BoundArgs.Union(arguments).ToArray());
+        }
+
+        public ObjectInstance Construct(object[] arguments)
+        {
+            var target = TargetFunction as IConstructor;
+            if (target == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            return target.Construct(BoundArgs.Union(arguments).ToArray());
+        }
+
+        public override bool HasInstance(object v)
+        {
+            var f = TargetFunction as FunctionInstance;
+            if (f == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+
+            return f.HasInstance(v);
+        }
+    }
+}

+ 1 - 10
Jint/Native/Function/FunctionInstance.cs

@@ -29,21 +29,12 @@ namespace Jint.Native.Function
         public string[] FormalParameters { get; private set; }
         public bool Strict { get; private set; }
 
-        // todo: implement
-        public object TargetFunction { get; set; }
-
-        // todo: implement
-        public object BoundThis { get; set; }
-
-        // todo: implement
-        public object BoundArgs { get; set; }
-
         /// <summary>
         /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5.3
         /// </summary>
         /// <param name="instance"></param>
         /// <returns></returns>
-        public bool HasInstance(object v)
+        public virtual bool HasInstance(object v)
         {
             var vObj = v as ObjectInstance;
             if (vObj == null)

+ 35 - 3
Jint/Native/Function/FunctionPrototype.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using Jint.Native.Object;
 using Jint.Runtime;
+using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop;
 
 namespace Jint.Native.Function
@@ -35,12 +36,43 @@ namespace Jint.Native.Function
             FastAddProperty("toString", new ClrFunctionInstance<object, object>(Engine, ToString), true, false, true);
             FastAddProperty("apply", new ClrFunctionInstance<object, object>(Engine, Apply), true, false, true);
             FastAddProperty("call", new ClrFunctionInstance<object, object>(Engine, Call, 1), true, false, true);
-            FastAddProperty("bind", new ClrFunctionInstance<object, object>(Engine, Bind), true, false, true);
+            FastAddProperty("bind", new ClrFunctionInstance<object, object>(Engine, Bind, 1), true, false, true);
         }
 
         private object Bind(object thisObj, object[] arguments)
         {
-            throw new NotImplementedException();
+            var target = thisObj as ICallable;
+
+            if (target == null)
+            {
+                throw new JavaScriptException(Engine.TypeError);
+            }
+            
+            object thisArg = arguments.At(0);
+            var f = new BindFunctionInstance(Engine);
+            f.TargetFunction = target;
+            f.BoundThis = thisArg;
+            f.BoundArgs = arguments.Skip(1).ToArray();
+            f.Prototype = Engine.Function.PrototypeObject;
+
+            var o = target as FunctionInstance;
+            if (o != null)
+            {
+                var l = TypeConverter.ToNumber(o.Get("length")) - (arguments.Length - 1);
+                f.FastAddProperty("length", System.Math.Max(l, 0), false, false, false); 
+            }
+            else
+            {
+                f.FastAddProperty("length", 0, false, false, false); 
+            }
+            
+
+            var thrower = Engine.Function.ThrowTypeError;
+            f.DefineOwnProperty("caller", new AccessorDescriptor(thrower, thrower) { Enumerable = false, Configurable = false }, false);
+            f.DefineOwnProperty("callee", new AccessorDescriptor(thrower, thrower) { Enumerable = false, Configurable = false }, false);
+
+
+            return f;
         }
 
         private object ToString(object thisObj, object[] arguments)
@@ -97,7 +129,7 @@ namespace Jint.Native.Function
                 return new JavaScriptException(Engine.TypeError);
             }
 
-            return func.Call(arguments[0], arguments.Skip(1).ToArray());
+            return func.Call(arguments.At(0), arguments.Length == 0 ? arguments : arguments.Skip(1).ToArray());
         }
     }
 }