BindFunction.cs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using Jint.Native.Object;
  2. using Jint.Runtime;
  3. namespace Jint.Native.Function;
  4. /// <summary>
  5. /// https://tc39.es/ecma262/#sec-bound-function-exotic-objects
  6. /// </summary>
  7. public sealed class BindFunction : ObjectInstance, IConstructor, ICallable
  8. {
  9. private readonly Realm _realm;
  10. public BindFunction(Engine engine,
  11. Realm realm,
  12. ObjectInstance? proto,
  13. ObjectInstance targetFunction,
  14. JsValue boundThis,
  15. JsValue[] boundArgs)
  16. : base(engine, ObjectClass.Function)
  17. {
  18. _realm = realm;
  19. _prototype = proto;
  20. BoundTargetFunction = targetFunction;
  21. BoundThis = boundThis;
  22. BoundArguments = boundArgs;
  23. }
  24. /// <summary>
  25. /// The wrapped function object.
  26. /// </summary>
  27. public JsValue BoundTargetFunction { get; }
  28. /// <summary>
  29. /// The value that is always passed as the this value when calling the wrapped function.
  30. /// </summary>
  31. public JsValue BoundThis { get; }
  32. /// <summary>
  33. /// A list of values whose elements are used as the first arguments to any call to the wrapped function.
  34. /// </summary>
  35. public JsValue[] BoundArguments { get; }
  36. JsValue ICallable.Call(JsValue thisObject, params JsCallArguments arguments)
  37. {
  38. var f = BoundTargetFunction as Function;
  39. if (f is null)
  40. {
  41. Throw.TypeError(_realm);
  42. }
  43. var args = CreateArguments(arguments);
  44. var value = f.Call(BoundThis, args);
  45. _engine._jsValueArrayPool.ReturnArray(args);
  46. return value;
  47. }
  48. ObjectInstance IConstructor.Construct(JsCallArguments arguments, JsValue newTarget)
  49. {
  50. var target = BoundTargetFunction as IConstructor;
  51. if (target is null)
  52. {
  53. Throw.TypeError(_realm);
  54. }
  55. var args = CreateArguments(arguments);
  56. if (ReferenceEquals(this, newTarget))
  57. {
  58. newTarget = BoundTargetFunction;
  59. }
  60. var value = target.Construct(args, newTarget);
  61. _engine._jsValueArrayPool.ReturnArray(args);
  62. return value;
  63. }
  64. internal override bool OrdinaryHasInstance(JsValue v)
  65. {
  66. var f = BoundTargetFunction as Function;
  67. if (f is null)
  68. {
  69. Throw.TypeError(_realm);
  70. }
  71. return f.OrdinaryHasInstance(v);
  72. }
  73. private JsValue[] CreateArguments(JsCallArguments arguments)
  74. {
  75. var combined = _engine._jsValueArrayPool.RentArray(BoundArguments.Length + arguments.Length);
  76. System.Array.Copy(BoundArguments, combined, BoundArguments.Length);
  77. System.Array.Copy(arguments, 0, combined, BoundArguments.Length, arguments.Length);
  78. return combined;
  79. }
  80. internal override bool IsConstructor => BoundTargetFunction.IsConstructor;
  81. public override string ToString() => "function () { [native code] }";
  82. }