Ejemplo n.º 1
0
        //     INITIALIZATION
        //_________________________________________________________________________________________

        /// <summary>
        /// Creates a new instance of a user-defined class.
        /// </summary>
        /// <param name="prototype"> The next object in the prototype chain. </param>
        /// <param name="name"> The name of the class. Can be <c>null</c> if none were supplied. </param>
        /// <param name="instancePrototype"> The value of the 'prototype' property. </param>
        /// <param name="constructor"> A function that represents the constructor, if the class has
        /// one, or <c>null</c> otherwise. </param>
        /// <remarks>
        /// A class that doesn't extend looks like this:
        /// new ClassFunction(engine.Function.InstancePrototype, name, engine.Object.Construct(), constructor)
        ///
        /// A class that extends A looks like this:
        /// new ClassFunction(A, name, ObjectInstance.CreateRawObject(A.InstancePrototype), constructor)
        ///
        /// A class that extends null looks like this:
        /// new ClassFunction(engine.Function.InstancePrototype, name, ObjectInstance.CreateRawObject(null), constructor)
        /// </remarks>
        public ClassFunction(ObjectInstance prototype, string name, ObjectInstance instancePrototype, UserDefinedFunction constructor)
            : base(prototype)
        {
            if (instancePrototype == null)
            {
                throw new ArgumentNullException(nameof(instancePrototype));
            }
            this.constructor = constructor;

            // Initialize the instance prototype.
            instancePrototype.InitializeProperties(new List <PropertyNameAndValue>
            {
                new PropertyNameAndValue("constructor", this, PropertyAttributes.NonEnumerable)
            });

            // Now add properties to this object.
            int length = constructor == null ? 0 : constructor.Length;

            InitializeProperties(new List <PropertyNameAndValue>()
            {
                new PropertyNameAndValue("name", name ?? string.Empty, PropertyAttributes.Configurable),
                new PropertyNameAndValue("length", length, PropertyAttributes.Configurable),
                new PropertyNameAndValue("prototype", instancePrototype, PropertyAttributes.Writable),
            });
        }
 /// <summary>
 /// Costructor
 /// </summary>
 /// <param name="userDefinedFunction">The watched function</param>
 public UserDefinedFunctionDebugView(UserDefinedFunction userDefinedFunction)
 {
     this.userDefinedFunction = userDefinedFunction;
 }
Ejemplo n.º 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);
            }
        }
Ejemplo n.º 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);
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Sets the value of a object literal property to a setter.  If the value already has a
 /// getter then it will be retained.
 /// </summary>
 /// <param name="obj"> The object to set the property on. </param>
 /// <param name="key"> The property key (can be a string or a symbol).</param>
 /// <param name="setter"> The setter function. </param>
 public static void SetObjectLiteralSetter(ObjectInstance obj, object key, UserDefinedFunction setter)
 {
     var descriptor = obj.GetOwnPropertyDescriptor(key);
     if (descriptor.Exists == false || !descriptor.IsAccessor)
         obj.DefineProperty(key, new PropertyDescriptor(null, setter, Library.PropertyAttributes.FullAccess), throwOnError: false);
     else
         obj.DefineProperty(key, new PropertyDescriptor(descriptor.Getter, setter, Library.PropertyAttributes.FullAccess), throwOnError: false);
 }