Added IsClass and FilterFields methods to streamline types creation, added more documentation

This commit is contained in:
Samuele Lorefice
2025-02-27 20:57:12 +01:00
parent bdc9624d13
commit 7a0ad7e968

View File

@@ -69,10 +69,6 @@ namespace CodeGenerator {
_customTypes = new(); _customTypes = new();
foreach (var type in _blendfile.SdnaStructs) { foreach (var type in _blendfile.SdnaStructs) {
Log($"Generating struct {type.Type}");
bool referenceSelf = false;
bool referencePointer = false;
//Add the type to the custom types list //Add the type to the custom types list
_customTypes.Add(type.Type); _customTypes.Add(type.Type);
@@ -82,27 +78,27 @@ namespace CodeGenerator {
new CodeAttributeArgument(new CodePrimitiveExpression(type.IdxType)), new CodeAttributeArgument(new CodePrimitiveExpression(type.IdxType)),
new CodeAttributeArgument(new CodePrimitiveExpression(type.Type)) new CodeAttributeArgument(new CodePrimitiveExpression(type.Type))
)); ));
//TODO: when encountering a list, run trough the fields to find a count/lenght or similar data.
foreach (var field in type.Fields) {
if (field.Name.Contains("*")) {
referencePointer = true;
}
if (field.Type.Contains(type.Type)) {
referenceSelf = true;
}
}
if (referenceSelf || referencePointer) { Log($"Generating type from struct {type.Type}");
Log("Struct contains references");
if(IsClass(type)) {
Log($"Marking {type.Type} as class");
ctd.IsClass = true; ctd.IsClass = true;
} }
else { else {
ctd.IsStruct = true; Log($"Marking {type.Type} as struct");
ctd.IsStruct = !ctd.IsClass;
} }
//Add the class to the namespace //Add the class to the namespace
ns.Types.Add(ctd); ns.Types.Add(ctd);
//TODO: when encountering a list, run trough the fields to find a count/lenght or similar data.
List<BlendFile.DnaField> normalFields; //Fields that are not lists nor lenghts of lists
List<(BlendFile.DnaField, BlendFile.DnaField)> listFields; //Fields that are lists, and their corresponding length fields
//filter the fields we want to include in the class minus the lists
FilterFields(type.Fields, out normalFields, out listFields);
var totalSize = 0; var totalSize = 0;
//Add the fields to the class //Add the fields to the class
@@ -142,6 +138,76 @@ namespace CodeGenerator {
return ns; return ns;
} }
/// <summary>
/// Determines if the type has to be serialized as a class or a struct
/// </summary>
/// <param name="type"><see cref="BlendFile.DnaStruct"/> istance to analyze</param>
/// <returns> <see langword="true"/> if there is any pointer or self reference, otherwise <see langword="false"/></returns>
private static bool IsClass(BlendFile.DnaStruct type) {
foreach (var field in type.Fields) {
if (field.Name.Contains("*")) {
Log($"Pointer detected. {field.Type} {field.Name}");
return true;
}
if (field.Type.Contains(type.Type)) {
Log($"Self reference detected. {field.Type} {field.Name}");
return true;
}
}
Log($"No pointer or self reference detected in {type.Type}");
return false;
}
/// <summary>
/// Filters the fields into normal fields and list fields pairs
/// </summary>
/// <param name="fields"><see cref="IEnumerable{T}"/> of <see cref="BlendFile.DnaField"/>s from all parameters</param>
/// <param name="normalFields"><see cref="List{T}"/> of <see cref="BlendFile.DnaField"/> containing all fields not part of a List</param>
/// <param name="listFields"><see cref="List{T}"/> of (<see cref="BlendFile.DnaField"/>, <see cref="BlendFile.DnaField"/>) collection where Item1 is the ListPointer and Item2 is the list lenght</param>
private static void FilterFields(IEnumerable<BlendFile.DnaField> fields,
out List<BlendFile.DnaField> normalFields,
out List<(BlendFile.DnaField, BlendFile.DnaField)> listFields) {
normalFields = new(); //Fields that are not lists nor lengths of lists
listFields = new(); //Fields that are lists, and their corresponding length fields
//Cast to array the fields to avoid multiple enumerations
var dnaFields = fields as BlendFile.DnaField[] ?? fields.ToArray();
foreach (var field in dnaFields) {
if (ListMarkerStr.Any(s => field.Name.Contains(s))) {
Log($"Found list field {field.Name}");
Log($"Searching for list length field");
var listLengthField = dnaFields.FirstOrDefault(f =>
f.Name.Contains(field.Name) && ListLenghtStr.Any(s => f.Name.Contains(s)));
if (listLengthField == null)
Log($"No list length field found for {field.Name}");
else {
Log($"Found list length field {listLengthField.Name}");
listFields.Add((field, listLengthField));
//Remove the list length field from the normal fields (if present)
if(normalFields.Remove(listLengthField))
Log($"Removed list length field {listLengthField.Name}");
}
continue;
}
//Skip fields that are recognized as listLengths
if (listFields.Select(f => f.Item2).Contains(field)) {
Log($"Skipping known list length field {field.Name}");
continue;
}
Log($"Adding normal field {field.Name}");
normalFields.Add(field);
}
}
/// <summary>
/// Generates the following attribute types <c>DNAAttribute, DNAFieldAttribute, DNAClassAttribute, DNAListAttribute</c>
/// </summary>
/// <returns><see cref="CodeTypeDeclaration"/> array containing the generated attribute types</returns>
/// <remarks>This internally uses a single instance of <see cref="AttributeBuilder"/> and sequentially generates the various attributes.</remarks>
private static CodeTypeDeclaration[] GenerateTypeDeclarations() { private static CodeTypeDeclaration[] GenerateTypeDeclarations() {
var attributeBuilder = new AttributeBuilder(); var attributeBuilder = new AttributeBuilder();
@@ -190,6 +256,7 @@ namespace CodeGenerator {
return typeDeclarations; return typeDeclarations;
} }
//TODO: use AttributeBuilder inside here
private static CodeAttributeDeclaration GenerateDnaFieldAttribute(int index, BlendFile.DnaField field, private static CodeAttributeDeclaration GenerateDnaFieldAttribute(int index, BlendFile.DnaField field,
BlendFile.Dna1Body body, int offset, out int size) { BlendFile.Dna1Body body, int offset, out int size) {
string t; string t;