private static EcmaPropertyKey GetNameFromMember(IntrinsicMemberAttribute propAttr, MemberInfo member) { if (propAttr.Symbol != 0) { return(new EcmaPropertyKey(propAttr.Symbol)); } return(new EcmaPropertyKey(propAttr.Name ?? Regex.Replace(member.Name, "^[A-Z](?=[a-z])", v => v.Value.ToLower()))); }
private void DefineIntrinsicObjectFromType(Type type, IntrinsicObjectAttribute typeAttr) { int objectIndex = ToValidIndex((Enum)typeAttr.ObjectType); Dictionary <EcmaPropertyKey, EcmaPropertyDescriptor> ht = properties[objectIndex]; SharedObjectHandle handle = new SharedObjectHandle(this.Container.ID, objectIndex); if (IsValidReference(typeAttr.Prototype, out SharedObjectHandle protoHandle)) { RuntimeObject thisObj = EnsureObject(objectIndex); thisObj.SetPrototypeOf(this.Realm.GetRuntimeObject(protoHandle)); } if (typeAttr.Global) { globals[typeAttr.Name ?? type.Name] = CreateSharedObjectDescriptor(handle, EcmaPropertyAttributes.Configurable | EcmaPropertyAttributes.Writable); } foreach (MemberInfo member in type.GetMembers()) { // special handling if the type defines an instrinsic contructor // replace the default object created from EnsureWellKnownObject to InstrincFunction if (member.HasAttribute(out IntrinsicConstructorAttribute ctorAttr)) { string ctorName = ctorAttr.Name ?? member.Name; runtimeObjects[objectIndex] = CreateIntrinsicFunction(ctorName, (MethodInfo)member, ctorAttr.SuperClass as Enum, WellKnownObject.Global, ctorName); if (IsValidReference(ctorAttr.Prototype, out SharedObjectHandle p1)) { Dictionary <EcmaPropertyKey, EcmaPropertyDescriptor> hp = properties[ToValidIndex((Enum)ctorAttr.Prototype)]; ht[WellKnownProperty.Prototype] = CreateSharedObjectDescriptor(p1, EcmaPropertyAttributes.None); hp[WellKnownProperty.Constructor] = CreateSharedObjectDescriptor(handle, EcmaPropertyAttributes.Configurable | EcmaPropertyAttributes.Writable); } if (ctorAttr.Global) { globals[ctorName] = CreateSharedObjectDescriptor(handle, EcmaPropertyAttributes.DefaultMethodProperty); } continue; } object[] propAttrs = member.GetCustomAttributes(typeof(IntrinsicMemberAttribute), false); if (propAttrs.Length > 0) { EcmaValue sharedValue = default; if (member.HasAttribute(out AliasOfAttribute aliasOf) && aliasOf.ObjectType is Enum aliasOfType) { EcmaPropertyKey aliasOfKey = aliasOf.Name != null ? (EcmaPropertyKey)aliasOf.Name : aliasOf.Symbol; if (!properties[ToValidIndex(aliasOfType)].TryGetValue(aliasOfKey, out EcmaPropertyDescriptor descriptor)) { // for sake of simplicity the aliased target should be defined on intrinsic object with smaller WellKnownObject enum value // to avoid the need of topological sort throw new InvalidOperationException(); } sharedValue = descriptor.Value; } if (sharedValue == default) { switch (member.MemberType) { case MemberTypes.Method: IntrinsicMemberAttribute propAttr = (IntrinsicMemberAttribute)propAttrs[0]; EcmaPropertyKey name = GetNameFromMember(propAttr, member); string runtimeName = (propAttr.Getter ? "get " : propAttr.Setter ? "set " : "") + (name.IsSymbol ? "[" + name.Symbol.Description + "]" : name.Name); sharedValue = this.Container.Add(CreateIntrinsicFunction(runtimeName, (MethodInfo)member, null, typeAttr.ObjectType as Enum, name)).ToValue(); if (propAttr.Overridable) { overridables.Add(new SharedObjectKey(typeAttr.ObjectType, name), sharedValue.ToInt32() & 0xFFFF); } break; case MemberTypes.Field: object fieldValue = ((FieldInfo)member).GetValue(null); sharedValue = IsValidReference(fieldValue, out SharedObjectHandle p1) ? p1.ToValue() : new EcmaValue(fieldValue); break; case MemberTypes.Property: object propertyValue = ((PropertyInfo)member).GetValue(null, null); sharedValue = IsValidReference(propertyValue, out SharedObjectHandle p2) ? p2.ToValue() : new EcmaValue(propertyValue); break; } } foreach (IntrinsicMemberAttribute propAttr in propAttrs) { EcmaPropertyKey name = GetNameFromMember(propAttr, member); if (propAttr.Getter) { DefineIntrinsicAccessorProperty(ht, name, sharedValue, propAttr.Attributes, true); } else if (propAttr.Setter) { DefineIntrinsicAccessorProperty(ht, name, sharedValue, propAttr.Attributes, false); } else if (member.MemberType != MemberTypes.Method) { DefineIntrinsicDataProperty(ht, name, sharedValue, propAttr.Attributes); } else { DefineIntrinsicMethodProperty(ht, name, sharedValue, propAttr.Attributes); if (propAttr.Global) { DefineIntrinsicMethodProperty(globals, name, sharedValue, propAttr.Attributes); } } } } } }