/// <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); }
/// <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 + "."); } } }