ArrayConstructor.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System.Collections;
  2. using Jint.Native.Function;
  3. using Jint.Native.Object;
  4. using Jint.Runtime;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Interop;
  7. namespace Jint.Native.Array
  8. {
  9. public sealed class ArrayConstructor : FunctionInstance, IConstructor
  10. {
  11. private ArrayConstructor(Engine engine) : base(engine, null, null, false)
  12. {
  13. }
  14. public ArrayPrototype PrototypeObject { get; private set; }
  15. public static ArrayConstructor CreateArrayConstructor(Engine engine)
  16. {
  17. var obj = new ArrayConstructor(engine);
  18. obj.Extensible = true;
  19. // The value of the [[Prototype]] internal property of the Array constructor is the Function prototype object
  20. obj.Prototype = engine.Function.PrototypeObject;
  21. obj.PrototypeObject = ArrayPrototype.CreatePrototypeObject(engine, obj);
  22. obj.SetOwnProperty("length", new PropertyDescriptor(1, PropertyFlag.AllForbidden));
  23. // The initial value of Array.prototype is the Array prototype object
  24. obj.SetOwnProperty("prototype", new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden));
  25. return obj;
  26. }
  27. public void Configure()
  28. {
  29. SetOwnProperty("isArray", new PropertyDescriptor(new ClrFunctionInstance(Engine, IsArray, 1), PropertyFlag.NonEnumerable));
  30. }
  31. private static JsValue IsArray(JsValue thisObj, JsValue[] arguments)
  32. {
  33. if (arguments.Length == 0)
  34. {
  35. return false;
  36. }
  37. var o = arguments.At(0);
  38. return o.IsObject() && o.AsObject().Class == "Array";
  39. }
  40. public override JsValue Call(JsValue thisObject, JsValue[] arguments)
  41. {
  42. return Construct(arguments);
  43. }
  44. public ObjectInstance Construct(JsValue[] arguments)
  45. {
  46. // check if we can figure out good size
  47. var capacity = arguments.Length > 0 ? (uint) arguments.Length : 0;
  48. if (arguments.Length == 1 && arguments[0].Type == Types.Number)
  49. {
  50. var number = ((JsNumber) arguments[0])._value;
  51. if (number > 0)
  52. {
  53. capacity = (uint) number;
  54. }
  55. }
  56. return Construct(arguments, capacity);
  57. }
  58. public ArrayInstance Construct(int capacity)
  59. {
  60. if (capacity < 0)
  61. {
  62. ExceptionHelper.ThrowArgumentException("invalid array length", nameof(capacity));
  63. }
  64. return Construct(System.Array.Empty<JsValue>(), (uint) capacity);
  65. }
  66. public ArrayInstance Construct(uint capacity)
  67. {
  68. return Construct(System.Array.Empty<JsValue>(), capacity);
  69. }
  70. public ArrayInstance Construct(JsValue[] arguments, uint capacity)
  71. {
  72. var instance = new ArrayInstance(Engine, capacity);
  73. instance.Prototype = PrototypeObject;
  74. instance.Extensible = true;
  75. if (arguments.Length == 1 && arguments.At(0).IsNumber())
  76. {
  77. var length = TypeConverter.ToUint32(arguments.At(0));
  78. if (!TypeConverter.ToNumber(arguments[0]).Equals(length))
  79. {
  80. ExceptionHelper.ThrowRangeError(_engine, "Invalid array length");
  81. }
  82. instance.SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.OnlyWritable));
  83. }
  84. else if (arguments.Length == 1 && arguments[0] is ObjectWrapper objectWrapper)
  85. {
  86. if (objectWrapper.Target is IEnumerable enumerable)
  87. {
  88. var jsArray = (ArrayInstance) Engine.Array.Construct(Arguments.Empty);
  89. var tempArray = Engine.JsValueArrayPool.RentArray(1);
  90. foreach (var item in enumerable)
  91. {
  92. var jsItem = FromObject(Engine, item);
  93. tempArray[0] = jsItem;
  94. Engine.Array.PrototypeObject.Push(jsArray, tempArray);
  95. }
  96. Engine.JsValueArrayPool.ReturnArray(tempArray);
  97. return jsArray;
  98. }
  99. }
  100. else
  101. {
  102. instance.SetOwnProperty("length", new PropertyDescriptor(0, PropertyFlag.OnlyWritable));
  103. if (arguments.Length > 0)
  104. {
  105. PrototypeObject.Push(instance, arguments);
  106. }
  107. }
  108. return instance;
  109. }
  110. internal ArrayInstance ConstructFast(uint length)
  111. {
  112. var instance = new ArrayInstance(Engine, length);
  113. instance.Prototype = PrototypeObject;
  114. instance.Extensible = true;
  115. instance.SetOwnProperty("length", new PropertyDescriptor(length, PropertyFlag.OnlyWritable));
  116. return instance;
  117. }
  118. }
  119. }