public PropertyDescriptor(PropertyDescriptor descriptor)
 {
     Get = descriptor.Get;
     Set = descriptor.Set;
     Value = descriptor.Value;
     Enumerable = descriptor.Enumerable;
     Configurable = descriptor.Configurable;
     Writable = descriptor.Writable;
 }
        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
        {
            if (throwOnError)
            {
                throw new JavaScriptException(Engine.TypeError, "Can't define a property of a NamespaceReference");
            }

            return false;
        }
예제 #3
0
 /// <summary>
 /// Optimized version of [[Put]] when the property is known to be already declared 
 /// </summary>
 /// <param name="name"></param>
 /// <param name="value"></param>
 public void FastSetProperty(string name, PropertyDescriptor value)
 {
     Properties[name] = value;
 }
예제 #4
0
        /// <summary>
        /// Creates or alters the named own property to 
        /// have the state described by a Property 
        /// Descriptor. The flag controls failure handling.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="desc"></param>
        /// <param name="throwOnError"></param>
        /// <returns></returns>
        public virtual bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
        {
            var current = GetOwnProperty(propertyName);
            
            if (current == PropertyDescriptor.Undefined)
            {
                if (!Extensible)
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(Engine.TypeError);
                    }

                    return false;
                }
                else
                {
                    if (desc.IsGenericDescriptor() || desc.IsDataDescriptor())
                    {
                        Properties[propertyName] = new PropertyDescriptor(desc)
                        {
                            Value = desc.Value.HasValue ? desc.Value : JsValue.Undefined,
                            Writable = desc.Writable.HasValue ? desc.Writable : false
                        };
                    }
                    else
                    {
                        Properties[propertyName] = new PropertyDescriptor(desc)
                        {
                            Enumerable = desc.Enumerable.HasValue ? desc.Enumerable : false,
                            Configurable = desc.Configurable.HasValue ? desc.Configurable : false,
                        };
                    }
                }

                return true;
            }

            // Step 5
            if (!current.Configurable.HasValue && 
                !current.Enumerable.HasValue &&
                !current.Writable.HasValue &&
                !current.Get.HasValue &&
                !current.Set.HasValue &&
                !current.Value.HasValue)
            {
                return true;
            }

            // Step 6
            var configurableIsSame = current.Configurable.HasValue
                ? desc.Configurable.HasValue && (current.Configurable.Value == desc.Configurable.Value)
                : !desc.Configurable.HasValue;

            var enumerableIsSame = current.Enumerable.HasValue
                ? desc.Enumerable.HasValue && (current.Enumerable.Value == desc.Enumerable.Value)
                : !desc.Enumerable.HasValue;

            var writableIsSame = true;
            var valueIsSame = true;

            if (current.IsDataDescriptor() && desc.IsDataDescriptor())
            {
                var currentDataDescriptor = current;
                var descDataDescriptor = desc;
                writableIsSame = currentDataDescriptor.Writable.HasValue
                ? descDataDescriptor.Writable.HasValue && (currentDataDescriptor.Writable.Value == descDataDescriptor.Writable.Value)
                : !descDataDescriptor.Writable.HasValue;

                var valueA = currentDataDescriptor.Value.HasValue
                    ? currentDataDescriptor.Value.Value
                    : Undefined.Instance;

                var valueB = descDataDescriptor.Value.HasValue
                                    ? descDataDescriptor.Value.Value
                                    : Undefined.Instance;

                valueIsSame = ExpressionInterpreter.SameValue(valueA, valueB);
            }
            else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
            {
                var currentAccessorDescriptor = current;
                var descAccessorDescriptor = desc;

                var getValueA = currentAccessorDescriptor.Get.HasValue
                    ? currentAccessorDescriptor.Get.Value
                    : Undefined.Instance;

                var getValueB = descAccessorDescriptor.Get.HasValue
                                    ? descAccessorDescriptor.Get.Value
                                    : Undefined.Instance;

                var setValueA = currentAccessorDescriptor.Set.HasValue
                   ? currentAccessorDescriptor.Set.Value
                   : Undefined.Instance;

                var setValueB = descAccessorDescriptor.Set.HasValue
                                    ? descAccessorDescriptor.Set.Value
                                    : Undefined.Instance;

                valueIsSame = ExpressionInterpreter.SameValue(getValueA, getValueB)
                              && ExpressionInterpreter.SameValue(setValueA, setValueB);
            }
            else
            {
                valueIsSame = false;
            }

            if (configurableIsSame && enumerableIsSame && writableIsSame && valueIsSame)
            {
                return true;
            }

            if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
            {
                if (desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean())
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(Engine.TypeError);
                    }

                    return false;
                }

                if (desc.Enumerable.HasValue && (!current.Enumerable.HasValue || desc.Enumerable.Value != current.Enumerable.Value))
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(Engine.TypeError);
                    }

                    return false;
                }
            }

            if (!desc.IsGenericDescriptor())
            {

                if (current.IsDataDescriptor() != desc.IsDataDescriptor())
                {
                    if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
                    {
                        if (throwOnError)
                        {
                            throw new JavaScriptException(Engine.TypeError);
                        }

                        return false;
                    }

                    if (current.IsDataDescriptor())
                    {
                        Properties[propertyName] = current = new PropertyDescriptor(
                            get: Undefined.Instance,
                            set: Undefined.Instance,
                            enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(),
                            configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean()
                            );
                    }
                    else
                    {
                        Properties[propertyName] = current = new PropertyDescriptor(
                            value: Undefined.Instance, 
                            writable: null,
                            enumerable: current.Enumerable.HasValue && current.Enumerable.Value.AsBoolean(),
                            configurable: current.Configurable.HasValue && current.Configurable.Value.AsBoolean()
                            );
                    }
                }
                else if (current.IsDataDescriptor() && desc.IsDataDescriptor())
                {
                    if (!current.Configurable.HasValue || current.Configurable.Value.AsBoolean() == false)
                    {
                        if (!current.Writable.HasValue || !current.Writable.Value.AsBoolean() && desc.Writable.HasValue && desc.Writable.Value.AsBoolean())
                        {
                            if (throwOnError)
                            {
                                throw new JavaScriptException(Engine.TypeError);
                            }

                            return false;
                        }

                        if (!current.Writable.Value.AsBoolean())
                        {
                            if (desc.Value.HasValue && !valueIsSame)
                            {
                                if (throwOnError)
                                {
                                    throw new JavaScriptException(Engine.TypeError);
                                }

                                return false;
                            }
                        }
                    }
                }
                else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
                {
                    if (!current.Configurable.HasValue || !current.Configurable.Value.AsBoolean())
                    {
                        if ((desc.Set.HasValue && !ExpressionInterpreter.SameValue(desc.Set.Value, current.Set.HasValue ? current.Set.Value : Undefined.Instance))
                            ||
                            (desc.Get.HasValue && !ExpressionInterpreter.SameValue(desc.Get.Value, current.Get.HasValue ? current.Get.Value : Undefined.Instance)))
                        {
                            if (throwOnError)
                            {
                                throw new JavaScriptException(Engine.TypeError);
                            }

                            return false;
                        }
                    }
                }
            }

            if (desc.Value.HasValue)
            {
                current.Value = desc.Value;
            }

            if (desc.Writable.HasValue)
            {
                current.Writable = desc.Writable;
            }

            if (desc.Enumerable.HasValue)
            {
                current.Enumerable = desc.Enumerable;
            }

            if (desc.Configurable.HasValue)
            {
                current.Configurable = desc.Configurable;
            }

            if (desc.Get.HasValue)
            {
                current.Get = desc.Get;
            }

            if (desc.Set.HasValue)
            {
                current.Set = desc.Set;
            }

            return true;
        }
예제 #5
0
        /// <summary>
        /// Sets the specified named property to the value 
        /// of the second parameter. The flag controls 
        /// failure handling.
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        /// <param name="throwOnError"></param>
        public virtual void Put(string propertyName, JsValue value, bool throwOnError)
        {
            if (!CanPut(propertyName))
            {
                if (throwOnError)
                {
                    throw new JavaScriptException(Engine.TypeError);
                }

                return;
            }

            var ownDesc = GetOwnProperty(propertyName);

            if (ownDesc.IsDataDescriptor())
            {
                var valueDesc = new PropertyDescriptor(value: value, writable: null, enumerable:null, configurable:null);
                DefineOwnProperty(propertyName, valueDesc, throwOnError);
                return;
            }

            // property is an accessor or inherited
            var desc = GetProperty(propertyName);

            if (desc.IsAccessorDescriptor())
            {
                var setter = desc.Set.Value.TryCast<ICallable>();
                setter.Call(new JsValue(this), new [] {value});
            }
            else
            {
                var newDesc = new PropertyDescriptor(value, true, true, true);
                DefineOwnProperty(propertyName, newDesc, throwOnError);
            }
        }
        public static JsValue FromPropertyDescriptor(Engine engine, PropertyDescriptor desc)
        {
            if (desc == Undefined)
            {
                return Native.Undefined.Instance;
            }

            var obj = engine.Object.Construct(Arguments.Empty);

            if (desc.IsDataDescriptor())
            {
                obj.DefineOwnProperty("value", new PropertyDescriptor(value: desc.Value.HasValue ? desc.Value.Value : Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false);
                obj.DefineOwnProperty("writable", new PropertyDescriptor(value: desc.Writable.HasValue && desc.Writable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);
            }
            else
            {
                obj.DefineOwnProperty("get", new PropertyDescriptor(desc.Get ?? Native.Undefined.Instance, writable: true, enumerable: true, configurable: true ), false);
                obj.DefineOwnProperty("set", new PropertyDescriptor(desc.Set ?? Native.Undefined.Instance, writable: true, enumerable: true, configurable: true), false);
            }

            obj.DefineOwnProperty("enumerable", new PropertyDescriptor(value: desc.Enumerable.HasValue && desc.Enumerable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);
            obj.DefineOwnProperty("configurable", new PropertyDescriptor(value: desc.Configurable.HasValue && desc.Configurable.Value.AsBoolean(), writable: true, enumerable: true, configurable: true), false);

            return obj;
        }
        public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o)
        {
            var obj = o.TryCast<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);
            }

            var desc = new PropertyDescriptor();

            if (obj.HasProperty("enumerable"))
            {
                desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable"));
            }

            if (obj.HasProperty("configurable"))
            {
                desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable"));
            }

            if (obj.HasProperty("value"))
            {
                var value = obj.Get("value");
                desc.Value = value;
            }

            if (obj.HasProperty("writable"))
            {
                desc.Writable = TypeConverter.ToBoolean(obj.Get("writable"));
            }

            if (obj.HasProperty("get"))
            {
                var getter = obj.Get("get");
                if (getter != JsValue.Undefined && getter.TryCast<ICallable>() == null)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
                desc.Get = getter;
            }

            if (obj.HasProperty("set"))
            {
                var setter = obj.Get("set");
                if (setter != Native.Undefined.Instance && setter.TryCast<ICallable>() == null)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
                desc.Set = setter;
            }

            if (desc.Get.HasValue || desc.Get.HasValue)
            {
                if (desc.Value.HasValue || desc.Writable.HasValue)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
            }

            return desc;
        }
        public JsValue EvaluateObjectExpression(ObjectExpression objectExpression)
        {
            // http://www.ecma-international.org/ecma-262/5.1/#sec-11.1.5

            var obj = _engine.Object.Construct(Arguments.Empty);
            foreach (var property in objectExpression.Properties)
            {
                var propName = property.Key.GetKey();
                var previous = obj.GetOwnProperty(propName);
                PropertyDescriptor propDesc;

                switch (property.Kind)
                {
                    case PropertyKind.Data:
                        var exprValue = _engine.EvaluateExpression(property.Value);
                        var propValue = _engine.GetValue(exprValue);
                        propDesc = new PropertyDescriptor(propValue, true, true, true);
                        break;

                    case PropertyKind.Get:
                        var getter = property.Value as FunctionExpression;

                        if (getter == null)
                        {
                            throw new JavaScriptException(_engine.SyntaxError);
                        }

                        ScriptFunctionInstance get; 
                        using (new StrictModeScope(getter.Strict))
                        {
                            get = new ScriptFunctionInstance(
                                _engine,
                                getter,
                                _engine.ExecutionContext.LexicalEnvironment, 
                                StrictModeScope.IsStrictModeCode
                            );
                        }

                        propDesc = new PropertyDescriptor(get: get, set: null, enumerable: true, configurable:true);
                        break;
                    
                    case PropertyKind.Set:
                        var setter = property.Value as FunctionExpression;

                        if (setter == null)
                        {
                            throw new JavaScriptException(_engine.SyntaxError);
                        }

                        ScriptFunctionInstance set;
                        using (new StrictModeScope(setter.Strict))
                        {
                            
                            set = new ScriptFunctionInstance(
                                _engine,
                                setter,
                                _engine.ExecutionContext.LexicalEnvironment,
                                StrictModeScope.IsStrictModeCode
                                );
                        }
                        propDesc = new PropertyDescriptor(get:null, set: set, enumerable: true, configurable: true);
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                }

                if (previous != PropertyDescriptor.Undefined)
                {
                    if (StrictModeScope.IsStrictModeCode && previous.IsDataDescriptor() && propDesc.IsDataDescriptor())
                    {
                        throw new JavaScriptException(_engine.SyntaxError);
                    }

                    if (previous.IsDataDescriptor() && propDesc.IsAccessorDescriptor())
                    {
                        throw new JavaScriptException(_engine.SyntaxError);
                    }

                    if (previous.IsAccessorDescriptor() && propDesc.IsDataDescriptor())
                    {
                        throw new JavaScriptException(_engine.SyntaxError);
                    }

                    if (previous.IsAccessorDescriptor() && propDesc.IsAccessorDescriptor())
                    {
                        if (propDesc.Set.HasValue && previous.Set.HasValue)
                        {
                            throw new JavaScriptException(_engine.SyntaxError);
                        }

                        if (propDesc.Get.HasValue && previous.Get.HasValue)
                        {
                            throw new JavaScriptException(_engine.SyntaxError);
                        }
                    }
                }

                obj.DefineOwnProperty(propName, propDesc, false);
            }

            return obj;
        }
예제 #9
0
        public static PropertyDescriptor ToPropertyDescriptor(Engine engine, JsValue o)
        {
            var obj = o.TryCast <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);
            }

            var desc = new PropertyDescriptor();

            if (obj.HasProperty("enumerable"))
            {
                desc.Enumerable = TypeConverter.ToBoolean(obj.Get("enumerable"));
            }

            if (obj.HasProperty("configurable"))
            {
                desc.Configurable = TypeConverter.ToBoolean(obj.Get("configurable"));
            }

            if (obj.HasProperty("value"))
            {
                var value = obj.Get("value");
                desc.Value = value;
            }

            if (obj.HasProperty("writable"))
            {
                desc.Writable = TypeConverter.ToBoolean(obj.Get("writable"));
            }

            if (obj.HasProperty("get"))
            {
                var getter = obj.Get("get");
                if (getter != JsValue.Undefined && getter.TryCast <ICallable>() == null)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
                desc.Get = getter;
            }

            if (obj.HasProperty("set"))
            {
                var setter = obj.Get("set");
                if (setter != Native.Undefined.Instance && setter.TryCast <ICallable>() == null)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
                desc.Set = setter;
            }

            if (desc.Get.HasValue || desc.Get.HasValue)
            {
                if (desc.Value.HasValue || desc.Writable.HasValue)
                {
                    throw new JavaScriptException(engine.TypeError);
                }
            }

            return(desc);
        }
예제 #10
0
        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.HasValue)
                {
                    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 = newLen;
                if (newLen >= oldLen)
                {
                    return base.DefineOwnProperty("length", newLenDesc, throwOnError);
                }
                if (!oldLenDesc.Writable.Value.AsBoolean())
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(_engine.TypeError);
                    }

                    return false;
                }
                bool newWritable;
                if (!newLenDesc.Writable.HasValue || newLenDesc.Writable.Value.AsBoolean())
                {
                    newWritable = true;
                }
                else
                {
                    newWritable = false;
                    newLenDesc.Writable = 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 JsValue(index + 1);
                                if (!newWritable)
                                {
                                    newLenDesc.Writable = JsValue.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 = oldLen + 1;
                            if (!newWritable)
                            {
                                newLenDesc.Writable = 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.AsBoolean())
                {
                    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 = index + 1;
                    base.DefineOwnProperty("length", oldLenDesc, false);
                }
                return true;
            }

            return base.DefineOwnProperty(propertyName, desc, throwOnError);
        }
예제 #11
0
        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
        {
            if (!Strict && ParameterMap != null)
            {
                var map = ParameterMap;
                var isMapped = map.GetOwnProperty(propertyName);
                var allowed = base.DefineOwnProperty(propertyName, desc, false);
                if (!allowed)
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(Engine.TypeError);
                    }
                }
                if (isMapped != PropertyDescriptor.Undefined)
                {
                    if (desc.IsAccessorDescriptor())
                    {
                        map.Delete(propertyName, false);
                    }
                    else
                    {
                        if (desc.Value.HasValue && desc.Value.Value != Undefined.Instance)
                        {
                            map.Put(propertyName, desc.Value.Value, throwOnError);
                        }

                        if (desc.Writable.HasValue && desc.Writable.Value == false)
                        {
                            map.Delete(propertyName, false);
                        }
                    }
                }

                return true;
            }

            return base.DefineOwnProperty(propertyName, desc, throwOnError);
        }