Example #1
0
        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;
        }
Example #2
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 == desc) {
                return true;
            }

            if (current == PropertyDescriptor.Undefined)
            {
                if (!Extensible)
                {
                    if (throwOnError)
                    {
                        throw new JavaScriptException(Engine.TypeError);
                    }

                    return false;
                }
                else
                {
                    if (desc.IsGenericDescriptor() || desc.IsDataDescriptor())
                    {
                        SetOwnProperty(propertyName, new PropertyDescriptor(desc)
                        {
                            Value = desc.Value.HasValue ? desc.Value : JsValue.Undefined,
                            Writable = desc.Writable.HasValue ? desc.Writable.Value : false,
                            Enumerable = desc.Enumerable.HasValue ? desc.Enumerable.Value : false,
                            Configurable = desc.Configurable.HasValue ? desc.Configurable.Value : false
                        });
                    }
                    else
                    {
                        SetOwnProperty(propertyName, new PropertyDescriptor(desc)
                        {
                            Get = desc.Get,
                            Set = desc.Set,
                            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
            if (
                current.Configurable == desc.Configurable &&
                current.Writable == desc.Writable &&
                current.Enumerable == desc.Enumerable &&

                ((!current.Get.HasValue && !desc.Get.HasValue) || (current.Get.HasValue && desc.Get.HasValue && ExpressionInterpreter.SameValue(current.Get.Value, desc.Get.Value))) &&
                ((!current.Set.HasValue && !desc.Set.HasValue) || (current.Set.HasValue && desc.Set.HasValue && ExpressionInterpreter.SameValue(current.Set.Value, desc.Set.Value))) &&
                ((!current.Value.HasValue && !desc.Value.HasValue) || (current.Value.HasValue && desc.Value.HasValue && ExpressionInterpreter.StrictlyEqual(current.Value.Value, desc.Value.Value)))
            ) {
                return true;
            }

            if (!current.Configurable.HasValue || !current.Configurable.Value)
            {
                if (desc.Configurable.HasValue && desc.Configurable.Value)
                {
                    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)
                    {
                        if (throwOnError)
                        {
                            throw new JavaScriptException(Engine.TypeError);
                        }

                        return false;
                    }

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

                            return false;
                        }

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

                                return false;
                            }
                        }
                    }
                }
                else if (current.IsAccessorDescriptor() && desc.IsAccessorDescriptor())
                {
                    if (!current.Configurable.HasValue || !current.Configurable.Value)
                    {
                        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;
        }
Example #3
0
        public override bool DefineOwnProperty(string propertyName, PropertyDescriptor desc, bool throwOnError)
        {
            EnsureInitialized();

            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);
        }
Example #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;
        }