Created a builder for attributes in code generator

This commit is contained in:
Samuele Lorefice
2025-02-25 16:32:38 +01:00
parent 23cec0bd0f
commit 91b74a24dd
2 changed files with 126 additions and 255 deletions

View File

@@ -0,0 +1,106 @@
using System;
using System.CodeDom;
using System.Collections.Generic;
namespace CodeGenerator {
public class AttributeBuilder {
private static AttributeBuilder _instance;
public static AttributeBuilder Instance => _instance ??= new();
private CodeTypeDeclaration _attrDecl = new();
private List<(Type, string)> _fields = new();
private List<(Type, string, string)> _properties = new();
public AttributeBuilder New() {
_attrDecl.IsClass = true;
_attrDecl.Attributes = MemberAttributes.Public;
_attrDecl.BaseTypes.Add(typeof(Attribute));
return this;
}
public AttributeBuilder New(string name) {
New();
_attrDecl.Name = name;
return this;
}
public AttributeBuilder SetAttributeUsage(CodeAttributeArgument usageArgs) {
var attrUsage = new CodeAttributeDeclaration() {
Name = nameof(AttributeUsageAttribute),
Arguments = { usageArgs }
};
_attrDecl.CustomAttributes.Add(attrUsage);
return this;
}
// ReSharper disable always BitwiseOperatorOnEnumWithoutFlags
public AttributeBuilder AddField<T>(string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) =>
AddField(typeof(T), name, attributes);
public AttributeBuilder AddField(string type, string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) =>
AddField(Type.GetType(type), name, attributes);
public AttributeBuilder AddField(Type type, string name,
MemberAttributes attributes = MemberAttributes.Private | MemberAttributes.Final) {
var field = new CodeMemberField(type, name);
field.Attributes = attributes;
_attrDecl.Members.Add(field);
_fields.Add((type, name));
return this;
}
public AttributeBuilder AddAutoProperty(Type type, string name, MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) {
AddField(type, $"_{name}", MemberAttributes.Private);
return AddProperty(type, name, $"_{name}", attributes, get, set);
}
public AttributeBuilder AddProperty(Type type, string name, string backingPropertyName,
MemberAttributes attributes = MemberAttributes.Public, bool get = true, bool set = true) {
var prop = new CodeMemberProperty {
Name = name,
Type = new (type),
Attributes = attributes,
HasGet = get,
HasSet = set
};
if (get) {
prop.GetStatements.Add(
new CodeMethodReturnStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), backingPropertyName)));
}
if (set) {
prop.SetStatements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), backingPropertyName),
new CodePropertySetValueReferenceExpression()));
}
_properties.Add((type, name, backingPropertyName));
_attrDecl.Members.Add(prop);
return this;
}
public AttributeBuilder AddPropertiesConstructor() {
var ctor = new CodeConstructor { Attributes = MemberAttributes.Public };
_attrDecl.Members.Add(ctor);
_properties.ForEach(property => {
ctor.Parameters.Add(new (property.Item1, property.Item2));
ctor.Statements.Add(
new CodeAssignStatement(
new CodeFieldReferenceExpression(
new CodeThisReferenceExpression(), property.Item3), new CodeVariableReferenceExpression(property.Item2)));
});
return this;
}
public CodeTypeDeclaration Build() => _attrDecl;
}
}

View File

@@ -4,7 +4,6 @@ using System.CodeDom.Compiler;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices.ComTypes;
using System.Text; using System.Text;
using Kaitai; using Kaitai;
using Microsoft.CSharp; using Microsoft.CSharp;
@@ -139,265 +138,31 @@ namespace CodeGenerator {
} }
private static CodeTypeDeclaration GenerateDNAFieldAttributeType() { private static CodeTypeDeclaration GenerateDNAFieldAttributeType() {
var ctd = new CodeTypeDeclaration("DNAFieldAttribute") { var attributeBuilder = AttributeBuilder.Instance;
IsClass = true,
Attributes = MemberAttributes.Public
};
ctd.BaseTypes.Add(new CodeTypeReference(typeof(Attribute)));
ctd.CustomAttributes.Add(new("AttributeUsage",
new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Field"))));
var cmf = new CodeMemberField(typeof(int), "_size") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
var cmp = new CodeMemberProperty() {
Name = "Size",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_size"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_size"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalType") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalType",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalName") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalName",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(
new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_originalIndex") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalIndex",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
}
};
ctd.Members.Add(cmp);
cmp = new CodeMemberProperty() {
Name = "UnderlyingType",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_originalType"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalType"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(bool), "_isPointer") { return attributeBuilder.New("DNAFieldAttribute")
Attributes = MemberAttributes.Private .SetAttributeUsage(new (new CodeSnippetExpression("AttributeTargets.Field")))
}; .AddAutoProperty(typeof(int), "Size")
.AddAutoProperty(typeof(string), "OriginalType")
ctd.Members.Add(cmf); .AddAutoProperty(typeof(string), "OriginalName")
.AddAutoProperty(typeof(int), "OriginalIndex")
cmp = new CodeMemberProperty() { .AddAutoProperty(typeof(string), "UnderlyingType")
Name = "IsPointer", .AddAutoProperty(typeof(bool), "IsPointer")
Type = new CodeTypeReference(typeof(bool)), .AddAutoProperty(typeof(int), "MemoryOffset")
Attributes = MemberAttributes.Public, .AddPropertiesConstructor()
HasGet = true, .Build();
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_isPointer"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_isPointer"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_memoryOffset") {
Attributes = MemberAttributes.Private
};
cmp = new CodeMemberProperty() {
Name = "MemoryOffset",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("0"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_memoryOffset"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
cc.Parameters.AddRange(new CParamDeclExp[] {
new(typeof(int), "originalIndex"),
new(typeof(string), "originalType"),
new(typeof(string), "originalName"),
new(typeof(string), "underlyingType"),
new(typeof(int), "size"),
new(typeof(bool), "isPointer"),
new(typeof(int), "memoryOffset")
});
cc.Statements.AddRange(new CodeAssignStatement[] {
new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalType"), new CArgRefExp("originalType")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalType"), new CArgRefExp("underlyingType")),
new(new CFieldRefExp(new CThisRefExp(), "Size"), new CArgRefExp("size")),
new(new CFieldRefExp(new CThisRefExp(), "IsPointer"), new CArgRefExp("isPointer")),
new(new CFieldRefExp(new CThisRefExp(), "MemoryOffset"), new CArgRefExp("memoryOffset"))
});
ctd.Members.Add(cc);
return ctd;
} }
private static CodeTypeDeclaration GenerateDNAClassAttributeType() { private static CodeTypeDeclaration GenerateDNAClassAttributeType() {
var ctd = new CodeTypeDeclaration("DNAClassAttribute") { var attributeBuilder = AttributeBuilder.Instance;
IsClass = true,
Attributes = MemberAttributes.Public
};
ctd.BaseTypes.Add(new CodeTypeReference(typeof(Attribute)));
ctd.CustomAttributes.Add(new("AttributeUsage",
new CodeAttributeArgument(new CodeSnippetExpression("AttributeTargets.Class | AttributeTargets.Struct"))));
return attributeBuilder.New("DNAClassAttribute")
var cmf = new CodeMemberField(typeof(int), "_originalIndex") { .SetAttributeUsage(new (new CodeSnippetExpression("AttributeTargets.Class | AttributeTargets.Struct")))
Attributes = MemberAttributes.Private .AddAutoProperty(typeof(int), "OriginalIndex")
}; .AddAutoProperty(typeof(string), "OriginalName")
ctd.Members.Add(cmf); .AddAutoProperty(typeof(int), "Size")
.AddPropertiesConstructor()
var cmp = new CodeMemberProperty() { .Build();
Name = "OriginalIndex",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalIndex"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(string), "_originalName") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "OriginalName",
Type = new CodeTypeReference(typeof(string)),
Attributes = MemberAttributes.Public,
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"), new CArgRefExp("value"))
},
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CFieldRefExp(new CThisRefExp(), "_originalName"))
}
};
ctd.Members.Add(cmp);
cmf = new CodeMemberField(typeof(int), "_size") {
Attributes = MemberAttributes.Private
};
ctd.Members.Add(cmf);
cmp = new CodeMemberProperty() {
Name = "Size",
Type = new CodeTypeReference(typeof(int)),
Attributes = MemberAttributes.Public,
HasGet = true,
GetStatements = {
new CodeMethodReturnStatement(new CodeSnippetExpression("_size"))
},
HasSet = true,
SetStatements = {
new CodeAssignStatement(new CFieldRefExp(new CThisRefExp(), "_size"), new CArgRefExp("value"))
}
};
ctd.Members.Add(cmp);
var cc = new CodeConstructor() { Attributes = MemberAttributes.Public };
cc.Parameters.AddRange(new CParamDeclExp[] {
new(typeof(int), "originalIndex"),
new(typeof(string), "originalName"),
new(typeof(int), "size")
});
cc.Statements.AddRange(new CodeAssignStatement[] {
new(new CFieldRefExp(new CThisRefExp(), "OriginalIndex"), new CArgRefExp("originalIndex")),
new(new CFieldRefExp(new CThisRefExp(), "OriginalName"), new CArgRefExp("originalName")),
new(new CFieldRefExp(new CThisRefExp(), "Size"), new CArgRefExp("size"))
});
ctd.Members.Add(cc);
return ctd;
} }
private static CodeAttributeDeclaration GenerateDNAFieldAttribute(int index, BlendFile.DnaField field, private static CodeAttributeDeclaration GenerateDNAFieldAttribute(int index, BlendFile.DnaField field,