FunctionPrototype.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. using System;
  2. using Jint.Collections;
  3. using Jint.Native.Array;
  4. using Jint.Native.Object;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Descriptors;
  7. using Jint.Runtime.Interop;
  8. namespace Jint.Native.Function
  9. {
  10. /// <summary>
  11. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4
  12. /// </summary>
  13. public sealed class FunctionPrototype : FunctionInstance
  14. {
  15. private static readonly JsString _functionName = new JsString("Function");
  16. private FunctionPrototype(Engine engine)
  17. : base(engine, _functionName, strict: false)
  18. {
  19. }
  20. public static FunctionPrototype CreatePrototypeObject(Engine engine)
  21. {
  22. var obj = new FunctionPrototype(engine)
  23. {
  24. // The value of the [[Prototype]] internal property of the Function prototype object is the standard built-in Object prototype object
  25. _prototype = engine.Object.PrototypeObject,
  26. _length = PropertyDescriptor.AllForbiddenDescriptor.NumberZero
  27. };
  28. return obj;
  29. }
  30. protected override void Initialize()
  31. {
  32. _properties = new StringDictionarySlim<PropertyDescriptor>(5)
  33. {
  34. ["constructor"] = new PropertyDescriptor(Engine.Function, PropertyFlag.NonEnumerable),
  35. ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString), true, false, true),
  36. ["apply"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "apply", Apply, 2), true, false, true),
  37. ["call"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "call", CallImpl, 1), true, false, true),
  38. ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1), true, false, true)
  39. };
  40. }
  41. private JsValue Bind(JsValue thisObj, JsValue[] arguments)
  42. {
  43. var target = thisObj.TryCast<ICallable>(x =>
  44. {
  45. ExceptionHelper.ThrowTypeError(Engine);
  46. });
  47. var func = thisObj as IConstructor;
  48. var thisArg = arguments.At(0);
  49. var f = new BindFunctionInstance(Engine)
  50. {
  51. TargetFunction = thisObj,
  52. BoundThis = thisArg,
  53. BoundArgs = arguments.Skip(1),
  54. _prototype = Engine.Function.PrototypeObject
  55. };
  56. if (target is FunctionInstance functionInstance)
  57. {
  58. var l = TypeConverter.ToNumber(functionInstance.Get("length", functionInstance)) - (arguments.Length - 1);
  59. f.SetOwnProperty(KnownKeys.Length, new PropertyDescriptor(System.Math.Max(l, 0), PropertyFlag.AllForbidden));
  60. }
  61. else
  62. {
  63. f.SetOwnProperty(KnownKeys.Length, PropertyDescriptor.AllForbiddenDescriptor.NumberZero);
  64. }
  65. f.DefineOwnProperty(KnownKeys.Caller, _engine._getSetThrower);
  66. f.DefineOwnProperty(KnownKeys.Arguments, _engine._getSetThrower);
  67. return f;
  68. }
  69. private JsValue ToString(JsValue thisObj, JsValue[] arguments)
  70. {
  71. if (!(thisObj is FunctionInstance))
  72. {
  73. return ExceptionHelper.ThrowTypeError<FunctionInstance>(_engine, "Function object expected.");
  74. }
  75. return "function() {{ ... }}";
  76. }
  77. internal JsValue Apply(JsValue thisObject, JsValue[] arguments)
  78. {
  79. var func = thisObject as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(Engine);
  80. var thisArg = arguments.At(0);
  81. var argArray = arguments.At(1);
  82. if (argArray.IsNullOrUndefined())
  83. {
  84. return func.Call(thisArg, Arguments.Empty);
  85. }
  86. var argList = CreateListFromArrayLike(argArray);
  87. var result = func.Call(thisArg, argList);
  88. return result;
  89. }
  90. internal JsValue[] CreateListFromArrayLike(JsValue argArray, Types? elementTypes = null)
  91. {
  92. var argArrayObj = argArray as ObjectInstance ?? ExceptionHelper.ThrowTypeError<ObjectInstance>(_engine);
  93. var operations = ArrayOperations.For(argArrayObj);
  94. var allowedTypes = elementTypes ??
  95. Types.Undefined | Types.Null | Types.Boolean | Types.String | Types.Symbol | Types.Number | Types.Object;
  96. var argList = operations.GetAll(allowedTypes);
  97. return argList;
  98. }
  99. private JsValue CallImpl(JsValue thisObject, JsValue[] arguments)
  100. {
  101. var func = thisObject as ICallable ?? ExceptionHelper.ThrowTypeError<ICallable>(Engine);
  102. JsValue[] values = ArrayExt.Empty<JsValue>();
  103. if (arguments.Length > 1)
  104. {
  105. values = new JsValue[arguments.Length - 1];
  106. System.Array.Copy(arguments, 1, values, 0, arguments.Length - 1);
  107. }
  108. var result = func.Call(arguments.At(0), values);
  109. return result;
  110. }
  111. public override JsValue Call(JsValue thisObject, JsValue[] arguments)
  112. {
  113. return Undefined;
  114. }
  115. }
  116. }