123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- using System.Linq;
- using Jint.Native.Object;
- using Jint.Runtime;
- using Jint.Runtime.Descriptors;
- namespace Jint.Native.Array
- {
- public class ArrayInstance : ObjectInstance
- {
- private readonly Engine _engine;
-
- public ArrayInstance(Engine engine) : base(engine)
- {
- _engine = engine;
- }
- public override string Class
- {
- get
- {
- return "Array";
- }
- }
- public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
- {
- var oldLenDesc = GetOwnProperty("length");
- var oldLen = TypeConverter.ToNumber(oldLenDesc.Value.Value);
- if (propertyName == "length")
- {
- if (desc.Value.IsAbsent)
- {
- return base.DefineOwnProperty("length", desc, throwOnError);
- }
- var newLenDesc = new PropertyDescriptor(desc);
- uint newLen = TypeConverter.ToUint32(desc.Value.Value);
- if (newLen != TypeConverter.ToNumber(desc.Value.Value))
- {
- throw new JavaScriptException(_engine.RangeError);
- }
- newLenDesc.Value = new Field<object>(newLen);
- if (newLen >= oldLen)
- {
- return base.DefineOwnProperty("length", newLenDesc, throwOnError);
- }
- if (!oldLenDesc.Writable.Value)
- {
- if (throwOnError)
- {
- throw new JavaScriptException(_engine.TypeError);
- }
- return false;
- }
- bool newWritable;
- if (newLenDesc.Writable.IsAbsent || newLenDesc.Writable.Value)
- {
- newWritable = true;
- }
- else
- {
- newWritable = false;
- newLenDesc.Writable = new Field<bool>(true);
- }
-
- var succeeded = base.DefineOwnProperty("length", newLenDesc, throwOnError);
- if (!succeeded)
- {
- return false;
- }
- // in the case of sparse arrays, treat each concrete element instead of
- // iterating over all indexes
- if (Properties.Count < oldLen - newLen)
- {
- var keys = Properties.Keys.ToArray();
- foreach (var key in keys)
- {
- uint index;
- // is it the index of the array
- if (uint.TryParse(key, out index) && index >= newLen && index < oldLen)
- {
- var deleteSucceeded = Delete(key, false);
- if (!deleteSucceeded)
- {
- newLenDesc.Value = new Field<object>(index + 1);
- if (!newWritable)
- {
- newLenDesc.Writable = new Field<bool>(false);
- }
- base.DefineOwnProperty("length", newLenDesc, false);
- if (throwOnError)
- {
- throw new JavaScriptException(_engine.TypeError);
- }
- return false;
- }
- }
- }
- }
- else
- {
- while (newLen < oldLen)
- {
- // algorithm as per the spec
- oldLen--;
- var deleteSucceeded = Delete(TypeConverter.ToString(oldLen), false);
- if (!deleteSucceeded)
- {
- newLenDesc.Value = new Field<object>(oldLen + 1);
- if (!newWritable)
- {
- newLenDesc.Writable = new Field<bool>(false);
- }
- base.DefineOwnProperty("length", newLenDesc, false);
- if (throwOnError)
- {
- throw new JavaScriptException(_engine.TypeError);
- }
- return false;
- }
- }
- }
- if (!newWritable)
- {
- DefineOwnProperty("length", new PropertyDescriptor(value: null, writable: false, enumerable: null, configurable: null), false);
- }
- return true;
- }
- else if (IsArrayIndex(propertyName))
- {
- var index = TypeConverter.ToUint32(propertyName);
- if (index >= oldLen && !oldLenDesc.Writable.Value)
- {
- if (throwOnError)
- {
- throw new JavaScriptException(_engine.TypeError);
- }
- return false;
- }
- var succeeded = base.DefineOwnProperty(propertyName, desc, false);
- if (!succeeded)
- {
- if (throwOnError)
- {
- throw new JavaScriptException(_engine.TypeError);
- }
- return false;
- }
- if (index >= oldLen)
- {
- oldLenDesc.Value = new Field<object>(index + 1);
- base.DefineOwnProperty("length", oldLenDesc, false);
- }
- return true;
- }
- return base.DefineOwnProperty(propertyName, desc, throwOnError);
- }
- public static bool IsArrayIndex(object p)
- {
- return TypeConverter.ToString(TypeConverter.ToUint32(p)) == TypeConverter.ToString(p) && TypeConverter.ToUint32(p) != uint.MaxValue;
- }
- }
- }
|