ArrayInstance.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using Jint.Native.Object;
  2. using Jint.Runtime;
  3. using Jint.Runtime.Descriptors;
  4. namespace Jint.Native.Array
  5. {
  6. public sealed class ArrayInstance : ObjectInstance
  7. {
  8. private readonly Engine _engine;
  9. public ArrayInstance(Engine engine) : base(engine)
  10. {
  11. _engine = engine;
  12. }
  13. public override string Class
  14. {
  15. get
  16. {
  17. return "Array";
  18. }
  19. }
  20. public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
  21. {
  22. var oldLenDesc = GetOwnProperty("length").As<DataDescriptor>();
  23. var oldLen = TypeConverter.ToNumber(oldLenDesc.Value);
  24. if (propertyName == "length")
  25. {
  26. var descData = desc as DataDescriptor;
  27. if (descData == null)
  28. {
  29. return base.DefineOwnProperty("length", desc, throwOnError);
  30. }
  31. var newLenDesc = new DataDescriptor(desc);
  32. double newLen = TypeConverter.ToUint32(descData.Value);
  33. if (newLen != TypeConverter.ToNumber(descData.Value))
  34. {
  35. throw new JavaScriptException(_engine.RangeError);
  36. }
  37. newLenDesc.Value = newLen;
  38. if (newLen >= oldLen)
  39. {
  40. return base.DefineOwnProperty("length", newLenDesc, throwOnError);
  41. }
  42. if (!oldLenDesc.Writable)
  43. {
  44. if (throwOnError)
  45. {
  46. throw new JavaScriptException(_engine.TypeError);
  47. }
  48. return false;
  49. }
  50. var newWritable = true;
  51. if (!newLenDesc.Writable)
  52. {
  53. newWritable = false;
  54. newLenDesc.Writable = true;
  55. }
  56. var succeeded = base.DefineOwnProperty("length", newLenDesc, throwOnError);
  57. if (!succeeded)
  58. {
  59. return false;
  60. }
  61. while (newLen < oldLen)
  62. {
  63. oldLen--;
  64. var deleteSucceeded = Delete(TypeConverter.ToString(oldLen), false);
  65. if (!deleteSucceeded)
  66. {
  67. newLenDesc.Value = oldLen + 1;
  68. if (!newWritable)
  69. {
  70. newLenDesc.Writable = false;
  71. }
  72. base.DefineOwnProperty("length", newLenDesc, false);
  73. if (throwOnError)
  74. {
  75. throw new JavaScriptException(_engine.TypeError);
  76. }
  77. return false;
  78. }
  79. }
  80. if (!newWritable)
  81. {
  82. DefineOwnProperty("length", new DataDescriptor(null) {Writable = false}, false);
  83. }
  84. return true;
  85. }
  86. else if (IsArrayIndex(propertyName))
  87. {
  88. var index = TypeConverter.ToUint32(propertyName);
  89. if (index >= oldLen && !oldLenDesc.Writable)
  90. {
  91. if (throwOnError)
  92. {
  93. throw new JavaScriptException(_engine.TypeError);
  94. }
  95. return false;
  96. }
  97. var succeeded = base.DefineOwnProperty(propertyName, desc, false);
  98. if (!succeeded)
  99. {
  100. if (throwOnError)
  101. {
  102. throw new JavaScriptException(_engine.TypeError);
  103. }
  104. return false;
  105. }
  106. if (index >= oldLen)
  107. {
  108. oldLenDesc.Value = index + 1;
  109. base.DefineOwnProperty("length", oldLenDesc, false);
  110. }
  111. return true;
  112. }
  113. return base.DefineOwnProperty(propertyName, desc, false);
  114. }
  115. public static bool IsArrayIndex(object p)
  116. {
  117. return TypeConverter.ToString(TypeConverter.ToUint32(p)) == TypeConverter.ToString(p) && TypeConverter.ToUint32(p) != uint.MaxValue;
  118. }
  119. }
  120. }