Esempio n. 1
0
        /// <summary>
        /// Calls the function with the given name.  The function must exist on this object or an
        /// exception will be thrown.
        /// </summary>
        /// <param name="functionName"> The name of the function to call. </param>
        /// <param name="parameters"> The parameters to pass to the function. </param>
        /// <returns> The result of calling the function. </returns>
        internal object CallMemberFunctionOn(object thisObj, string functionName, params object[] parameters)
        {
            PropertyVariable function = GetProperty(functionName);

            if (function == null)
            {
                throw new JavaScriptException(this.Engine, "TypeError", "Object " + ToString() + " has no method '" + functionName + "'");
            }

            MethodBase method = function.ConstantValue as MethodBase;

            if (method != null)
            {
                // Invoke it:
                return(method.Invoke(thisObj, parameters));
            }

            MethodGroup set = function.ConstantValue as MethodGroup;

            if (set != null)
            {
                // Invoke it:
                set.Invoke(thisObj, parameters);
            }

            throw new JavaScriptException(this.Engine, "TypeError", "Property '" + functionName + "' of object " + ToString() + " is not a function");
        }
Esempio n. 2
0
        /// <summary>Enumerates all properties and accounts for any custom ones if the object defines it.</summary>
        public IEnumerable <string> PropertyEnumerator(object obj)
        {
            // Got a custom one?
            PropertyVariable pv = GetProperty("Properties");

            if (pv == null)
            {
                foreach (KeyValuePair <string, PropertyVariable> kvp in Properties)
                {
                    if (kvp.Value.IsEnumerable)
                    {
                        yield return(kvp.Key);
                    }
                }
            }
            else
            {
                // Get the value:
                IEnumerable <string> set = pv.GetValue(obj) as IEnumerable <string>;

                // Iterate it:
                foreach (string str in set)
                {
                    yield return(str);
                }
            }
        }
Esempio n. 3
0
        /// <summary>Enumerates all the values in the given object.</summary>
        public IEnumerable <object> PropertyValues(object obj)
        {
            // Got a custom one?
            PropertyVariable pv = GetProperty("PropertyValues");

            if (pv == null)
            {
                foreach (KeyValuePair <string, PropertyVariable> kvp in Properties)
                {
                    if (kvp.Value.IsEnumerable)
                    {
                        // Read the value:
                        object value = kvp.Value.GetValue(obj);

                        yield return(value);
                    }
                }
            }
            else
            {
                // Get the value:
                IEnumerable <object> set = pv.GetValue(obj) as IEnumerable <object>;

                // Iterate it:
                foreach (object s in set)
                {
                    yield return(s);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Adds a property to this object, typically generating a field of the given type.
        /// </summary>
        /// <param name="name"> The name of the property to add. </param>
        /// <param name="attributes"> The property attributes. </param>
        internal PropertyVariable AddProperty(string name, Nitrassic.Library.PropertyAttributes attributes, Type valueType)
        {
            if (Properties == null)
            {
                Properties = new Dictionary <string, PropertyVariable>();
            }

            PropertyVariable sp = new PropertyVariable(this, name, attributes, valueType);

            Properties[name] = sp;

            return(sp);
        }
Esempio n. 5
0
        /// <summary>Sets a generic property on the given object at runtime. Note that this can't create a property.</summary>
        public static void SetPropertyValue(ScriptEngine engine, object thisObj, string property, object value)
        {
            // Exists?
            if (thisObj == null)
            {
                throw new NullReferenceException("Attempted to set property '" + property + "' on a null reference.");
            }

            // Get the prototype:
            Prototype proto = engine.Prototypes.Get(thisObj.GetType());

            // Get the property:
            PropertyVariable pv = proto.GetProperty(property);

            if (pv == null)
            {
                // Undefined:
                throw new JavaScriptException(engine, "TypeError", "Can't set dynamic properties on generic objects.");
            }

            // Set the value:
            pv.SetValue(thisObj, value);
        }
Esempio n. 6
0
        /// <summary>Pulls a generic property from the given object at runtime.</summary>
        public static object GetPropertyValue(ScriptEngine engine, object thisObj, string property)
        {
            // Exists?
            if (thisObj == null)
            {
                throw new NullReferenceException("Attempted to read property '" + property + "' from a null reference.");
            }

            // Get the prototype:
            Prototype proto = engine.Prototypes.Get(thisObj.GetType());

            // Get the property:
            PropertyVariable pv = proto.GetProperty(property);

            if (pv == null)
            {
                // Undefined:
                return(Nitrassic.Undefined.Value);
            }

            // Get the value:
            return(pv.GetValue(thisObj));
        }
Esempio n. 7
0
        /// <summary>
        /// Adds the given method to the prototype.
        /// </summary>
        private void AddMethod(MethodBase method, Type type, int staticMode)
        {
            // Get the properties attribute if it's got one:
            var attribute = (JSProperties)Attribute.GetCustomAttribute(method, typeof(JSProperties));

            if (attribute != null && attribute.Hidden)
            {
                return;
            }

            // Determine the name of the method.
            string name;

            if (attribute != null && attribute.Name != null)
            {
                name = attribute.Name;
            }
            else
            {
                name = method.Name;
            }

            // Reject properties (but not constructors):
            if (method.IsSpecialName && name != ".ctor")
            {
                return;
            }

            ParameterInfo[] mParams = null;

            if (method.IsStatic && staticMode != 0)
            {
                // If it's static and it does not have a 'thisObj' property
                // then it's a constructor level static function, IF the object has a constructor at all.
                mParams = method.GetParameters();

                if (mParams.Length > 0)
                {
                    if (mParams[0].Name == "thisObj" || (mParams.Length > 1 && mParams[1].Name == "thisObj"))
                    {
                        // Not actually static.
                        if (staticMode == 2)
                        {
                            return;
                        }
                    }
                    else if (staticMode == 1)
                    {
                        return;
                    }
                }
            }

            bool enumerable = true;

            if (name == "OnConstruct" || name == ".ctor")
            {
                name       = ".make";
                enumerable = false;
            }
            else if (name == "OnCall")
            {
                name       = ".call";
                enumerable = false;
            }

            // Special case for get_ or set_ methods - we want them to act like properties.
            // Chop off get_ or set_ here (so the actual name entering the proto is correct)
            // then when the user attempts to use it like a property, it checks then.
            int actLikeProperty = 0;

            if (name.StartsWith("get_"))
            {
                name            = name.Substring(4);
                actLikeProperty = 1;
            }
            else if (name.StartsWith("set_"))
            {
                name            = name.Substring(4);
                actLikeProperty = 2;
            }

            // For methods, auto == lowercase.
            if (attribute == null)
            {
                name = char.ToLower(name[0]) + name.Substring(1);
            }
            else
            {
                // For methods, auto == lowercase
                if (attribute.FirstCharacter == CaseMode.Upper)
                {
                    name = char.ToUpper(name[0]) + name.Substring(1);
                }
                else if (attribute.FirstCharacter == CaseMode.Lower || attribute.FirstCharacter == CaseMode.Auto)
                {
                    name = char.ToLower(name[0]) + name.Substring(1);
                }
            }

            if (actLikeProperty != 0)
            {
                if (name == "_Item")
                {
                    // Rename! Actually got an indexer here.
                    name = "___item";

                    if (mParams == null)
                    {
                        mParams = method.GetParameters();
                    }

                    // Skip thisObj and engine if they're set:
                    for (int i = 0; i < mParams.Length; i++)
                    {
                        ParameterInfo p = mParams[i];

                        if (i < 2)
                        {
                            // Skip special parameters.

                            if (p.Name == "thisObj" || (i == 0 && p.ParameterType == typeof(ScriptEngine)))
                            {
                                continue;
                            }
                        }

                        // Append the type name:
                        name += "_" + p.ParameterType.Name;
                    }
                }
                else if (name == "_Properties")
                {
                    // Rename! Got the property enumerator here.
                    name = "___properties";
                }
            }

            // Check property attributes.
            Nitrassic.Library.PropertyAttributes descriptorAttributes = Nitrassic.Library.PropertyAttributes.Sealed;
            if (attribute != null && attribute.IsEnumerable && enumerable)
            {
                descriptorAttributes |= Nitrassic.Library.PropertyAttributes.Enumerable;
            }
            if (attribute == null || attribute.IsConfigurable)
            {
                descriptorAttributes |= Nitrassic.Library.PropertyAttributes.Configurable;
            }
            if (attribute == null || attribute.IsWritable)
            {
                descriptorAttributes |= Nitrassic.Library.PropertyAttributes.Writable;
            }

            // Already defined this property?
            PropertyVariable property = GetProperty(name);

            if (property == null)
            {
                // Add as a single method, optionally as a virtual property:
                object propertyValue;

                if (actLikeProperty == 0)
                {
                    // Straight apply the method:
                    propertyValue = method;
                }
                else
                {
                    // Create a virtual property:
                    VirtualProperty vProperty = new VirtualProperty();

                    // Apply the method:
                    if (actLikeProperty == 1)
                    {
                        vProperty.GetMethod = method;
                        vProperty.LoadMeta();
                    }
                    else
                    {
                        vProperty.SetMethod = method;
                    }

                    // Apply virtual property as the value:
                    propertyValue = vProperty;
                }

                property = AddProperty(name, propertyValue, descriptorAttributes);
            }
            else if (actLikeProperty != 0)
            {
                // Got the other method in a property.
                VirtualProperty vProperty = property.ConstantValue as VirtualProperty;

                // Apply the method:
                if (actLikeProperty == 1)
                {
                    vProperty.GetMethod = method;
                    vProperty.LoadMeta();
                }
                else
                {
                    vProperty.SetMethod = method;
                }
            }
            else
            {
                // Already a method set?
                MethodGroup group = property.ConstantValue as MethodGroup;

                if (group == null)
                {
                    // Create a method group and add the current method to it:
                    group = new MethodGroup();

                    // Set the attributes:
                    group.PropertyAttributes = descriptorAttributes;

                    // Add the method:
                    group.Add(property.ConstantValue as MethodBase);

                    // Force the property to change type:
                    property.ForceChange(group);
                }

                // Add this method to the group:
                group.Add(method);

                if (group.PropertyAttributes != descriptorAttributes)
                {
                    throw new InvalidOperationException("Inconsistant property attributes detected on " + method + ".");
                }
            }
        }