Represents a JavaScript function that throws a type error.
Наследование: FunctionInstance
Пример #1
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined function.
        /// </summary>
        /// <param name="targetFunction"> The function that was bound. </param>
        /// <param name="boundThis"> The value of the "this" parameter when the target function is called. </param>
        /// <param name="boundArguments"> Zero or more bound argument values. </param>
        internal BoundFunction(FunctionInstance targetFunction, object boundThis, object[] boundArguments)
            : base(targetFunction.Prototype)
        {
            if (targetFunction == null)
            {
                throw new ArgumentNullException(nameof(targetFunction));
            }
            if (boundArguments == null)
            {
                boundArguments = new object[0];
            }
            this.TargetFunction = targetFunction;
            this.BoundThis      = boundThis;
            this.BoundArguments = boundArguments;

            // Add function properties.
            this.FastSetProperty("name", targetFunction.Name, PropertyAttributes.Configurable);
            this.FastSetProperty("length", Math.Max(targetFunction.Length - boundArguments.Length, 0), PropertyAttributes.Configurable);
            this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
            this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);

            // Caller and arguments cannot be accessed.
            var thrower  = new ThrowTypeErrorFunction(this.Engine.Function, "The 'caller' or 'arguments' properties cannot be accessed on a bound function.");
            var accessor = new PropertyAccessorValue(thrower, thrower);

            this.FastSetProperty("caller", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
            this.FastSetProperty("arguments", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
        }
Пример #2
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined function.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="targetFunction"> The function that was bound. </param>
        /// <param name="boundThis"> The value of the "this" parameter when the target function is called. </param>
        /// <param name="boundArguments"> Zero or more bound argument values. </param>
        internal BoundFunction(FunctionInstance targetFunction, object boundThis, object[] boundArguments)
            : base(targetFunction.Prototype)
        {
            if (targetFunction == null)
                throw new ArgumentNullException("targetFunction");
            if (boundArguments == null)
                boundArguments = new object[0];
            this.TargetFunction = targetFunction;
            this.BoundThis = boundThis;
            this.BoundArguments = boundArguments;

            // Add function properties.
            this.FastSetProperty("name", targetFunction.Name);
            this.FastSetProperty("length", Math.Max(targetFunction.Length - boundArguments.Length, 0));
            this.FastSetProperty("prototype", this.Engine.Object.Construct(), PropertyAttributes.Writable);
            this.InstancePrototype.FastSetProperty("constructor", this, PropertyAttributes.NonEnumerable);
            
            // Caller and arguments cannot be accessed.
            var thrower = new ThrowTypeErrorFunction(this.Engine.Function, "The 'caller' or 'arguments' properties cannot be accessed on a bound function.");
            var accessor = new PropertyAccessorValue(thrower, thrower);
            this.FastSetProperty("caller", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
            this.FastSetProperty("arguments", accessor, PropertyAttributes.IsAccessorProperty, overwriteAttributes: true);
        }
Пример #3
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new Arguments instance.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="callee"> The function that was called. </param>
        /// <param name="bindings"> The bindings to allow modification. </param>
        /// <param name="argumentValues"> The argument values that were passed to the function. </param>
        internal ArgumentsInstance(ObjectInstance prototype, UserDefinedFunction callee, RuntimeScope bindings, object[] argumentValues)
            : base(prototype)
        {
            if (callee == null)
            {
                throw new ArgumentNullException(nameof(callee));
            }
            if (bindings == null)
            {
                throw new ArgumentNullException(nameof(bindings));
            }
            if (argumentValues == null)
            {
                throw new ArgumentNullException(nameof(argumentValues));
            }
            this.callee   = callee;
            this.bindings = bindings;
            InitializeProperties(GetDeclarativeProperties(Engine));
            this.FastSetProperty("length", argumentValues.Length, PropertyAttributes.NonEnumerable);

            if (this.callee.StrictMode == false)
            {
                this.FastSetProperty("callee", callee, PropertyAttributes.NonEnumerable);


                // Create an array mappedArguments where mappedArguments[i] = true means a mapping is
                // maintained between arguments[i] and the corresponding variable.
                this.mappedArguments = new bool[argumentValues.Length];
                var mappedNames = new Dictionary <string, int>();    // maps argument name -> index
                for (int i = 0; i < argumentValues.Length; i++)
                {
                    if (i < callee.ArgumentNames.Count)
                    {
                        // Check if the argument name appeared previously in the argument list.
                        int previousIndex;
                        if (mappedNames.TryGetValue(callee.ArgumentNames[i], out previousIndex) == true)
                        {
                            // The argument name has appeared before.  Remove the getter/setter.
                            this.DefineProperty(previousIndex.ToString(), new PropertyDescriptor(argumentValues[previousIndex], PropertyAttributes.FullAccess), false);

                            // The argument is no longer mapped.
                            this.mappedArguments[previousIndex] = false;
                        }

                        // Add the argument name and index to the hashtable.
                        mappedNames[callee.ArgumentNames[i]] = i;

                        // The argument is mapped by default.
                        this.mappedArguments[i] = true;

                        // Define a getter and setter so that the property value reflects that of the argument.
                        var getter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentGetter", new string[0], this.bindings, "return " + callee.ArgumentNames[i], ArgumentGetter, true);
                        getter["argumentIndex"] = i;
                        var setter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentSetter", new string[] { "value" }, this.bindings, callee.ArgumentNames[i] + " = value", ArgumentSetter, true);
                        setter["argumentIndex"] = i;
                        this.DefineProperty(i.ToString(), new PropertyDescriptor(getter, setter, PropertyAttributes.FullAccess), false);
                    }
                    else
                    {
                        // This argument is unnamed - no mapping needs to happen.
                        this[(uint)i] = argumentValues[i];
                    }
                }
            }
            else
            {
                // In strict mode, arguments items are not connected to the variables.
                for (int i = 0; i < argumentValues.Length; i++)
                {
                    this[(uint)i] = argumentValues[i];
                }

                // In strict mode, accessing caller or callee is illegal.
                var throwErrorFunction = new ThrowTypeErrorFunction(this.Engine.Function.InstancePrototype);
                this.DefineProperty("caller", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false);
                this.DefineProperty("callee", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false);
            }
        }
Пример #4
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new Arguments instance.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="callee"> The function that was called. </param>
        /// <param name="scope"> The function scope. </param>
        /// <param name="argumentValues"> The argument values that were passed to the function. </param>
        public ArgumentsInstance(ObjectInstance prototype, UserDefinedFunction callee, DeclarativeScope scope, object[] argumentValues)
            : base(prototype)
        {
            if (callee == null)
                throw new ArgumentNullException("callee");
            if (scope == null)
                throw new ArgumentNullException("scope");
            if (argumentValues == null)
                throw new ArgumentNullException("argumentValues");
            this.callee = callee;
            this.scope = scope;
            this.FastSetProperty("length", argumentValues.Length, PropertyAttributes.NonEnumerable);

            if (this.callee.StrictMode == false)
            {
                this.FastSetProperty("callee", callee, PropertyAttributes.NonEnumerable);


                // Create an array mappedArguments where mappedArguments[i] = true means a mapping is
                // maintained between arguments[i] and the corresponding variable.
                this.mappedArguments = new bool[argumentValues.Length];
                var mappedNames = new Dictionary<string, int>();    // maps argument name -> index
                for (int i = 0; i < argumentValues.Length; i++)
                {
                    if (i < callee.ArgumentNames.Count)
                    {
                        // Check if the argument name appeared previously in the argument list.
                        int previousIndex;
                        if (mappedNames.TryGetValue(callee.ArgumentNames[i], out previousIndex) == true)
                        {
                            // The argument name has appeared before.  Remove the getter/setter.
                            this.DefineProperty(previousIndex.ToString(), new PropertyDescriptor(argumentValues[previousIndex], PropertyAttributes.FullAccess), false);

                            // The argument is no longer mapped.
                            this.mappedArguments[previousIndex] = false;
                        }

                        // Add the argument name and index to the hashtable.
                        mappedNames[callee.ArgumentNames[i]] = i;

                        // The argument is mapped by default.
                        this.mappedArguments[i] = true;

                        // Define a getter and setter so that the property value reflects that of the argument.
                        var getter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentGetter", new string[0], this.scope, "return " + callee.ArgumentNames[i], ArgumentGetter, true);
                        getter.SetPropertyValue("argumentIndex", i, false);
                        var setter = new UserDefinedFunction(this.Engine.Function.InstancePrototype, "ArgumentSetter", new string[] { "value" }, this.scope, callee.ArgumentNames[i] + " = value", ArgumentSetter, true);
                        setter.SetPropertyValue("argumentIndex", i, false);
                        this.DefineProperty(i.ToString(), new PropertyDescriptor(getter, setter, PropertyAttributes.FullAccess), false);
                    }
                    else
                    {
                        // This argument is unnamed - no mapping needs to happen.
                        this[(uint)i] = argumentValues[i];
                    }
                }
            }
            else
            {
                // In strict mode, arguments items are not connected to the variables.
                for (int i = 0; i < argumentValues.Length; i++)
                    this[(uint)i] = argumentValues[i];

                // In strict mode, accessing caller or callee is illegal.
                var throwErrorFunction = new ThrowTypeErrorFunction(this.Engine.Function.InstancePrototype);
                this.DefineProperty("caller", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false);
                this.DefineProperty("callee", new PropertyDescriptor(throwErrorFunction, throwErrorFunction, PropertyAttributes.Sealed), false);
            }
        }