ArrayConstructor.cs 4.9 KB

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