Skip to content

Commit

Permalink
.NET: Initial work on field facades
Browse files Browse the repository at this point in the history
  • Loading branch information
praydog committed May 13, 2024
1 parent 47e1674 commit 4d78afa
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 4 deletions.
16 changes: 13 additions & 3 deletions csharp-api/AssemblyGenerator/ClassGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,12 +342,22 @@ private TypeDeclarationSyntax GenerateFields(List<SimpleBaseTypeSyntax> baseType
// So this is actually going to be made a property with get/set instead of an actual field
// 1. Because interfaces can't have fields
// 2. Because we don't actually have a concrete reference to the field in our VM, so we'll be a facade for the field
var fieldFacadeGetter = SyntaxFactory.AttributeList().AddAttributes(SyntaxFactory.Attribute(
SyntaxFactory.ParseName("global::REFrameworkNET.Attributes.Method"),
SyntaxFactory.ParseAttributeArgumentList("(" + field.Index.ToString() + ", global::REFrameworkNET::FieldFacadeType.Getter)"))
);

var fieldFacadeSetter = SyntaxFactory.AttributeList().AddAttributes(SyntaxFactory.Attribute(
SyntaxFactory.ParseName("global::REFrameworkNET.Attributes.Method"),
SyntaxFactory.ParseAttributeArgumentList("(" + field.Index.ToString() + ", global::REFrameworkNET::FieldFacadeType.Setter)"))
);

var properyDeclaration = SyntaxFactory.PropertyDeclaration(fieldType, fieldName)
.AddModifiers(new SyntaxToken[]{SyntaxFactory.Token(SyntaxKind.PublicKeyword)})
.AddAccessorListAccessors(
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration).AddAttributeLists(fieldFacadeGetter)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration).AddAttributeLists(fieldFacadeSetter)
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
);

Expand Down Expand Up @@ -423,7 +433,7 @@ private TypeDeclarationSyntax GenerateMethods(List<SimpleBaseTypeSyntax> baseTyp
methodDeclaration = methodDeclaration.AddAttributeLists(
SyntaxFactory.AttributeList().AddAttributes(SyntaxFactory.Attribute(
SyntaxFactory.ParseName("global::REFrameworkNET.Attributes.Method"),
SyntaxFactory.ParseAttributeArgumentList("(" + method.GetIndex().ToString() + ")")))
SyntaxFactory.ParseAttributeArgumentList("(" + method.GetIndex().ToString() + ", global::REFrameworkNET::FieldFacadeType.None)")))
);

bool anyOutParams = false;
Expand Down
53 changes: 52 additions & 1 deletion csharp-api/REFrameworkNET/Attributes/Method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

#include "../TDB.hpp"

namespace REFrameworkNET {
public enum class FieldFacadeType : uint8_t {
None,
Getter,
Setter
};
}

namespace REFrameworkNET::Attributes {
/// <summary>Attribute to mark a reference assembly method for easier lookup.</summary>
[System::AttributeUsage(System::AttributeTargets::Method)]
Expand Down Expand Up @@ -34,16 +42,45 @@ namespace REFrameworkNET::Attributes {
}

public:
MethodAttribute(uint32_t methodIndex) {
MethodAttribute(uint32_t methodIndex, FieldFacadeType fieldFacadeType) {
if (fieldFacadeType != FieldFacadeType::None) {
field = REFrameworkNET::TDB::Get()->GetField(methodIndex);
fieldFacade = fieldFacadeType;

if (field != nullptr) {
signature = nullptr;
isVirtual = false;
}

return;
}

method = REFrameworkNET::TDB::Get()->GetMethod(methodIndex);
fieldFacade = FieldFacadeType::None;

if (method != nullptr && method->IsVirtual()) {
signature = method->GetMethodSignature();
isVirtual = method->IsVirtual();
}
}

property bool IsField {
bool get() {
return field != nullptr;
}
}

property FieldFacadeType FieldFacade {
FieldFacadeType get() {
return fieldFacade;
}
}

REFrameworkNET::Method^ GetMethod(REFrameworkNET::TypeDefinition^ td) {
if (method == nullptr) {
return nullptr;
}

// Signature is used for virtual methods
if (isVirtual && signature != nullptr && td != method->GetDeclaringType()) {
if (auto result = td->GetMethod(signature); result != nullptr) {
Expand All @@ -54,8 +91,22 @@ namespace REFrameworkNET::Attributes {
return method;
}

REFrameworkNET::Field^ GetField() {
return field;
}

System::Object^ GetUnderlyingObject(REFrameworkNET::TypeDefinition^ td) {
if (auto method = GetMethod(td); method != nullptr) {
return method;
}

return field;
}

private:
REFrameworkNET::Method^ method;
REFrameworkNET::Field^ field;
FieldFacadeType fieldFacade{ FieldFacadeType::None };
System::String^ signature;
bool isVirtual;
};
Expand Down

0 comments on commit 4d78afa

Please sign in to comment.