123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- using System.Runtime.CompilerServices;
- using Jint.Native;
- using Jint.Native.Object;
- using Jint.Runtime.Descriptors.Specialized;
- namespace Jint.Runtime.Descriptors
- {
- public class PropertyDescriptor
- {
- public static readonly PropertyDescriptor Undefined = new PropertyDescriptor(PropertyFlag.None);
- internal PropertyFlag _flags;
- internal JsValue _value;
- protected PropertyDescriptor(PropertyFlag flags)
- {
- _flags = flags;
- }
-
- protected internal PropertyDescriptor(JsValue value, PropertyFlag flags) : this(flags)
- {
- if ((_flags & PropertyFlag.CustomJsValue) != 0)
- {
- CustomValue = value;
- }
- _value = value;
- }
- public PropertyDescriptor(JsValue value, bool? writable, bool? enumerable, bool? configurable)
- {
- if ((_flags & PropertyFlag.CustomJsValue) != 0)
- {
- CustomValue = value;
- }
- _value = value;
- if (writable != null)
- {
- Writable = writable.Value;
- WritableSet = true;
- }
- if (enumerable != null)
- {
- Enumerable = enumerable.Value;
- EnumerableSet = true;
- }
- if (configurable != null)
- {
- Configurable = configurable.Value;
- ConfigurableSet = true;
- }
- }
- public PropertyDescriptor(PropertyDescriptor descriptor)
- {
- Value = descriptor.Value;
- Enumerable = descriptor.Enumerable;
- EnumerableSet = descriptor.EnumerableSet;
-
- Configurable = descriptor.Configurable;
- ConfigurableSet = descriptor.ConfigurableSet;
- Writable = descriptor.Writable;
- WritableSet = descriptor.WritableSet;
- }
- public virtual JsValue Get => null;
- public virtual JsValue Set => null;
- public bool Enumerable
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & PropertyFlag.Enumerable) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- _flags |= PropertyFlag.EnumerableSet;
- if (value)
- {
- _flags |= PropertyFlag.Enumerable;
- }
- else
- {
- _flags &= ~(PropertyFlag.Enumerable);
- }
- }
- }
-
- public bool EnumerableSet
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & (PropertyFlag.EnumerableSet | PropertyFlag.Enumerable)) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private set
- {
- if (value)
- {
- _flags |= PropertyFlag.EnumerableSet;
- }
- else
- {
- _flags &= ~(PropertyFlag.EnumerableSet);
- }
- }
- }
- public bool Writable
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & PropertyFlag.Writable) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- _flags |= PropertyFlag.WritableSet;
- if (value)
- {
- _flags |= PropertyFlag.Writable;
- }
- else
- {
- _flags &= ~(PropertyFlag.Writable);
- }
- }
- }
- public bool WritableSet
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private set
- {
- if (value)
- {
- _flags |= PropertyFlag.WritableSet;
- }
- else
- {
- _flags &= ~(PropertyFlag.WritableSet);
- }
- }
- }
- public bool Configurable
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & PropertyFlag.Configurable) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- _flags |= PropertyFlag.ConfigurableSet;
- if (value)
- {
- _flags |= PropertyFlag.Configurable;
- }
- else
- {
- _flags &= ~(PropertyFlag.Configurable);
- }
- }
- }
-
- public bool ConfigurableSet
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => (_flags & (PropertyFlag.ConfigurableSet | PropertyFlag.Configurable)) != 0;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private set
- {
- if (value)
- {
- _flags |= PropertyFlag.ConfigurableSet;
- }
- else
- {
- _flags &= ~(PropertyFlag.ConfigurableSet);
- }
- }
- }
- public JsValue Value
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- if ((_flags & PropertyFlag.CustomJsValue) != 0)
- {
- return CustomValue;
- }
-
- return _value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- if ((_flags & PropertyFlag.CustomJsValue) != 0)
- {
- CustomValue = value;
- }
- _value = value;
- }
- }
- protected virtual JsValue CustomValue
- {
- get => null;
- set => ExceptionHelper.ThrowNotImplementedException();
- }
- internal PropertyFlag Flags
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get { return _flags; }
- }
- public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o)
- {
- var obj = o.TryCast<ObjectInstance>();
- if (ReferenceEquals(obj, null))
- {
- ExceptionHelper.ThrowTypeError(engine);
- }
- var getProperty = obj.GetProperty("get");
- var hasGetProperty = getProperty != Undefined;
- var setProperty = obj.GetProperty("set");
- var hasSetProperty = setProperty != Undefined;
-
- if ((obj.HasProperty("value") || obj.HasProperty("writable")) &&
- (hasGetProperty || hasSetProperty))
- {
- ExceptionHelper.ThrowTypeError(engine);
- }
- var desc = hasGetProperty || hasSetProperty
- ? new GetSetPropertyDescriptor(null, null, PropertyFlag.None)
- : new PropertyDescriptor(PropertyFlag.None);
- var enumerableProperty = obj.GetProperty("enumerable");
- if (enumerableProperty != Undefined)
- {
- desc.Enumerable = TypeConverter.ToBoolean(obj.UnwrapJsValue(enumerableProperty));
- desc.EnumerableSet = true;
- }
- var configurableProperty = obj.GetProperty("configurable");
- if (configurableProperty != Undefined)
- {
- desc.Configurable = TypeConverter.ToBoolean(obj.UnwrapJsValue(configurableProperty));
- desc.ConfigurableSet = true;
- }
- var valueProperty = obj.GetProperty("value");
- if (valueProperty != Undefined)
- {
- desc.Value = obj.UnwrapJsValue(valueProperty);
- }
- var writableProperty = obj.GetProperty("writable");
- if (writableProperty != Undefined)
- {
- desc.Writable = TypeConverter.ToBoolean(obj.UnwrapJsValue(writableProperty));
- desc.WritableSet = true;
- }
- if (hasGetProperty)
- {
- var getter = obj.UnwrapJsValue(getProperty);
- if (!getter.IsUndefined() && getter.TryCast<ICallable>() == null)
- {
- ExceptionHelper.ThrowTypeError(engine);
- }
- ((GetSetPropertyDescriptor) desc).SetGet(getter);
- }
- if (hasSetProperty)
- {
- var setter = obj.UnwrapJsValue(setProperty);
- if (!setter.IsUndefined() && setter.TryCast<ICallable>() == null)
- {
- ExceptionHelper.ThrowTypeError(engine);
- }
- ((GetSetPropertyDescriptor) desc).SetSet(setter);
- }
- if (!ReferenceEquals(desc.Get, null))
- {
- if (!ReferenceEquals(desc.Value, null) || desc.WritableSet)
- {
- ExceptionHelper.ThrowTypeError(engine);
- }
- }
- return desc;
- }
- public static JsValue FromPropertyDescriptor(Engine engine, PropertyDescriptor desc)
- {
- if (ReferenceEquals(desc, Undefined))
- {
- return Native.Undefined.Instance;
- }
-
- var obj = engine.Object.Construct(Arguments.Empty);
- if (desc.IsDataDescriptor())
- {
- obj.SetOwnProperty("value", new PropertyDescriptor(desc.Value ?? Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
- obj.SetOwnProperty("writable", new PropertyDescriptor(desc.Writable, PropertyFlag.ConfigurableEnumerableWritable));
- }
- else
- {
- obj.SetOwnProperty("get", new PropertyDescriptor(desc.Get ?? Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
- obj.SetOwnProperty("set", new PropertyDescriptor(desc.Set ?? Native.Undefined.Instance, PropertyFlag.ConfigurableEnumerableWritable));
- }
- obj.SetOwnProperty("enumerable", new PropertyDescriptor(desc.Enumerable, PropertyFlag.ConfigurableEnumerableWritable));
- obj.SetOwnProperty("configurable", new PropertyDescriptor(desc.Configurable, PropertyFlag.ConfigurableEnumerableWritable));
- return obj;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool IsAccessorDescriptor()
- {
- return !ReferenceEquals(Get, null) || !ReferenceEquals(Set, null);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool IsDataDescriptor()
- {
- return (_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0
- || (_flags & PropertyFlag.CustomJsValue) != 0 && !ReferenceEquals(CustomValue, null)
- || !ReferenceEquals(_value, null);
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.3
- /// </summary>
- /// <returns></returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool IsGenericDescriptor()
- {
- return !IsDataDescriptor() && !IsAccessorDescriptor();
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal bool TryGetValue(ObjectInstance thisArg, out JsValue value)
- {
- value = JsValue.Undefined;
- // IsDataDescriptor logic inlined
- if ((_flags & (PropertyFlag.WritableSet | PropertyFlag.Writable)) != 0)
- {
- var val = (_flags & PropertyFlag.CustomJsValue) != 0
- ? CustomValue
- : _value;
-
- if (!ReferenceEquals(val, null))
- {
- value = val;
- return true;
- }
- }
-
- if (this == Undefined)
- {
- return false;
- }
-
- var getter = Get;
- if (!ReferenceEquals(getter, null) && !getter.IsUndefined())
- {
- // if getter is not undefined it must be ICallable
- var callable = getter.TryCast<ICallable>();
- value = callable.Call(thisArg, Arguments.Empty);
- }
- return true;
- }
- }
- }
|