using Jint.Native.Object; using Jint.Runtime; namespace Jint.Native.Function; /// /// https://tc39.es/ecma262/#sec-bound-function-exotic-objects /// public sealed class BindFunction : ObjectInstance, IConstructor, ICallable { private readonly Realm _realm; public BindFunction(Engine engine, Realm realm, ObjectInstance? proto, ObjectInstance targetFunction, JsValue boundThis, JsValue[] boundArgs) : base(engine, ObjectClass.Function) { _realm = realm; _prototype = proto; BoundTargetFunction = targetFunction; BoundThis = boundThis; BoundArguments = boundArgs; } /// /// The wrapped function object. /// public JsValue BoundTargetFunction { get; } /// /// The value that is always passed as the this value when calling the wrapped function. /// public JsValue BoundThis { get; } /// /// A list of values whose elements are used as the first arguments to any call to the wrapped function. /// public JsValue[] BoundArguments { get; } JsValue ICallable.Call(JsValue thisObject, params JsCallArguments arguments) { var f = BoundTargetFunction as Function; if (f is null) { Throw.TypeError(_realm); } var args = CreateArguments(arguments); var value = f.Call(BoundThis, args); _engine._jsValueArrayPool.ReturnArray(args); return value; } ObjectInstance IConstructor.Construct(JsCallArguments arguments, JsValue newTarget) { var target = BoundTargetFunction as IConstructor; if (target is null) { Throw.TypeError(_realm); } var args = CreateArguments(arguments); if (ReferenceEquals(this, newTarget)) { newTarget = BoundTargetFunction; } var value = target.Construct(args, newTarget); _engine._jsValueArrayPool.ReturnArray(args); return value; } internal override bool OrdinaryHasInstance(JsValue v) { var f = BoundTargetFunction as Function; if (f is null) { Throw.TypeError(_realm); } return f.OrdinaryHasInstance(v); } private JsValue[] CreateArguments(JsCallArguments arguments) { var combined = _engine._jsValueArrayPool.RentArray(BoundArguments.Length + arguments.Length); System.Array.Copy(BoundArguments, combined, BoundArguments.Length); System.Array.Copy(arguments, 0, combined, BoundArguments.Length, arguments.Length); return combined; } internal override bool IsConstructor => BoundTargetFunction.IsConstructor; public override string ToString() => "function () { [native code] }"; }