123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- using Jint.Native;
- using Jint.Native.Object;
- namespace Jint.Runtime.Descriptors
- {
- /// <summary>
- /// An element of a javascript object
- /// </summary>
- public abstract class PropertyDescriptor
- {
- public static PropertyDescriptor Undefined = new UndefinedPropertyDescriptor();
- /// <summary>
- /// If true, the property will be enumerated by a for-in
- /// enumeration (see 12.6.4). Otherwise, the property is said
- /// to be non-enumerable.
- /// </summary>
- public bool? Enumerable { get; set; }
- public bool EnumerableIsSet
- {
- get { return Enumerable.HasValue && Enumerable.Value; }
- }
- /// <summary>
- /// If false, attempts to delete the property, change the
- /// property to be a data property, or change its attributes will
- /// fail.
- /// </summary>
- public bool? Configurable { get; set; }
- public bool ConfigurableIsSet
- {
- get { return Configurable.HasValue && Configurable.Value; }
- }
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.1
- /// </summary>
- /// <returns></returns>
- public abstract bool IsAccessorDescriptor();
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.2
- /// </summary>
- /// <returns></returns>
- public abstract bool IsDataDescriptor();
- /// <summary>
- /// http://www.ecma-international.org/ecma-262/5.1/#sec-8.10.3
- /// </summary>
- /// <returns></returns>
- public bool IsGenericDescriptor()
- {
- return !IsDataDescriptor() && !IsAccessorDescriptor();
- }
- public T As<T>() where T : PropertyDescriptor
- {
- return (T)this;
- }
- public static PropertyDescriptor ToPropertyDescriptor(Engine engine, object o)
- {
- var obj = o as ObjectInstance;
- if (obj == null)
- {
- throw new JavaScriptException(engine.TypeError);
- }
- if ((obj.HasProperty("value") || obj.HasProperty("writable")) &&
- (obj.HasProperty("get") || obj.HasProperty("set")))
- {
- throw new JavaScriptException(engine.TypeError);
- }
- bool? writable = obj.HasProperty("writable") ? TypeConverter.ToBoolean(obj.Get("writable")) : default(bool?);
- bool? enumerable = obj.HasProperty("enumerable") ? TypeConverter.ToBoolean(obj.Get("enumerable")) : default(bool?);
- bool? configurable = obj.HasProperty("configurable") ? TypeConverter.ToBoolean(obj.Get("configurable")) : default(bool?);
- if (obj.HasProperty("value"))
- {
- var value = obj.Get("value");
- return new DataDescriptor(value) { Configurable = configurable, Enumerable = enumerable, Writable = writable};
- }
- else
- {
- object getter = null, setter = null;
- if (obj.HasProperty("get"))
- {
- getter = obj.Get("get");
- if (getter != Native.Undefined.Instance && !(getter is ICallable))
- {
- throw new JavaScriptException(engine.TypeError);
- }
- }
- if (obj.HasProperty("set"))
- {
- setter = obj.Get("set");
- if (setter != Native.Undefined.Instance && !(setter is ICallable))
- {
- throw new JavaScriptException(engine.TypeError);
- }
- }
- return new AccessorDescriptor(getter as ICallable, setter as ICallable) { Configurable = configurable, Enumerable = enumerable };
- }
- }
- public static object FromPropertyDescriptor(Engine engine, PropertyDescriptor desc)
- {
- if (desc == PropertyDescriptor.Undefined)
- {
- return Native.Undefined.Instance;
- }
- var obj = engine.Object.Construct(Arguments.Empty);
- if (desc.IsDataDescriptor())
- {
- var datadesc = desc.As<DataDescriptor>();
- obj.DefineOwnProperty("value", new DataDescriptor(datadesc.Value) { Writable = true, Enumerable = true, Configurable = true }, false);
- obj.DefineOwnProperty("writable", new DataDescriptor(datadesc.Writable) { Writable = true, Enumerable = true, Configurable = true }, false);
- }
- else
- {
- var accdesc = desc.As<AccessorDescriptor>();
- obj.DefineOwnProperty("get", new DataDescriptor(accdesc.Get ?? Native.Undefined.Instance) { Writable = true, Enumerable = true, Configurable = true }, false);
- obj.DefineOwnProperty("set", new DataDescriptor(accdesc.Set ?? Native.Undefined.Instance) { Writable = true, Enumerable = true, Configurable = true }, false);
- }
- obj.DefineOwnProperty("enumerable", new DataDescriptor(desc.Enumerable) { Writable = true, Enumerable = true, Configurable = true }, false);
- obj.DefineOwnProperty("configurable", new DataDescriptor(desc.Configurable) { Writable = true, Enumerable = true, Configurable = true }, false);
- return obj;
- }
- /// <summary>
- /// Local implementation used to create a singleton representing
- /// an undefined result of a PropertyDescriptor. This prevents the rest
- /// of the code to return 'object' in order to be able to return
- /// Undefined.Instance
- /// </summary>
- internal sealed class UndefinedPropertyDescriptor : PropertyDescriptor
- {
- public override bool IsAccessorDescriptor()
- {
- return false;
- }
- public override bool IsDataDescriptor()
- {
- return false;
- }
- }
- }
- }
|