/// <summary> /// Determines if this is a field or method. /// </summary> private void Resolve(Type type) { if (_Type == null) { _Type = type; } // Property=null; // Field=null; if (typeof(PropertyInfo).IsAssignableFrom(_Type)) { // It's a property! PropertyInfo pI = (PropertyInfo)ConstantValue; Property = new VirtualProperty(pI); _Type = pI.PropertyType; } else if (typeof(VirtualProperty).IsAssignableFrom(_Type)) { // It's a property! Property = (VirtualProperty)ConstantValue; _Type = Property.PropertyType; } else if (typeof(FieldInfo).IsAssignableFrom(_Type)) { // It's a field! Field = (FieldInfo)ConstantValue; _Type = Field.FieldType; } else if (typeof(MethodBase).IsAssignableFrom(_Type) || _Type == typeof(MethodGroup)) { // It's a method - do nothing here; the prototype will store the reference for us. } else if (Prototype.Builder != null && _Type != null) { FieldAttributes attribs = FieldAttributes.Public; // Is it static? if (Prototype.IsStatic) { attribs |= FieldAttributes.Static; } // Declare a new field to store it. Field = Prototype.Builder.DefineField(Name, _Type, attribs); } }
/// <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 + "."); } } }