Skip to content

Commit

Permalink
fix(codegen): Ensured the codegen works when referencing subtypes
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisdutz committed Mar 9, 2022
1 parent 5352166 commit f64f02c
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,88 +96,6 @@ public List<TypeDefinition> getComplexTypeRootDefinitions() {
* Methods related to type-references.
**********************************************************************************/

/**
* Helper for collecting referenced non simple types as these usually need to be
* imported in some way.
*
* @return Collection of all non simple type references used in fields or enum constants.
*/
public Collection<String> getNonSimpleTypeReferences() {
return getNonSimpleTypeReferences(thisType);
}

/**
* Helper for collecting referenced non simple types as these usually need to be
* imported in some way.
*
* @param baseType the base type we want to get the type references from
* @return collection of non simple type references used in the type.
*/
public Collection<String> getNonSimpleTypeReferences(TypeDefinition baseType) {
return getNonSimpleTypeReferences(baseType, new HashSet<>());
}

public Collection<String> getNonSimpleTypeReferences(TypeDefinition baseType, Set<String> nonSimpleTypeReferences) {
// We add ourselves to avoid a stackoverflow
nonSimpleTypeReferences.add(baseType.getName());
// If this is a subtype of a discriminated type, we have to add a reference to the parent type.
if (baseType.isDiscriminatedComplexTypeDefinition()) {
DiscriminatedComplexTypeDefinition discriminatedComplexTypeDefinition = baseType.asDiscriminatedComplexTypeDefinition().orElseThrow();
if (!discriminatedComplexTypeDefinition.isAbstract()) {
String typeReferenceName = discriminatedComplexTypeDefinition.getParentType().orElseThrow().getName();
nonSimpleTypeReferences.add(typeReferenceName);
}
}
// If it's a complex type definition, add all the types referenced by any property fields
// (Includes any types referenced by sub-types in case this is a discriminated type parent)
if (baseType.isComplexTypeDefinition()) {
ComplexTypeDefinition complexTypeDefinition = baseType.asComplexTypeDefinition().orElseThrow();
for (Field field : complexTypeDefinition.getFields()) {
if (field.isPropertyField()) {
PropertyField propertyField = field.asPropertyField().orElseThrow();
TypeReference typeReference = propertyField.getType();
if (typeReference.isArrayTypeReference()) {
typeReference = typeReference.asArrayTypeReference().orElseThrow().getElementTypeReference();
}
if (typeReference.isNonSimpleTypeReference()) {
NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow();
nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
}
} else if (field.isSwitchField()) {
SwitchField switchField = field.asSwitchField().orElseThrow();
for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
if (nonSimpleTypeReferences.contains(switchCase.getName())) {
continue;
}
nonSimpleTypeReferences.addAll(getNonSimpleTypeReferences(switchCase, nonSimpleTypeReferences));
}
}
}
} else if (baseType.isEnumTypeDefinition()) {// In case this is an enum type, we have to check all the constant types.
EnumTypeDefinition enumTypeDefinition = baseType.asEnumTypeDefinition().orElseThrow();
for (String constantName : enumTypeDefinition.getConstantNames()) {
final TypeReference constantType = enumTypeDefinition.getConstantType(constantName);
if (constantType.isNonSimpleTypeReference()) {
NonSimpleTypeReference nonSimpleTypeReference = constantType.asNonSimpleTypeReference().orElseThrow();
nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
}
}
}
// If the type has any parser arguments, these have to be checked too.
baseType.getParserArguments().ifPresent(arguments -> arguments.stream()
.map(Argument::getType)
.map(TypeReferenceConversions::asNonSimpleTypeReference)
.filter(Optional::isPresent)
.map(Optional::get)
.map(NonSimpleTypeReference::getName)
.forEach(nonSimpleTypeReferences::add)
);

// We remove ourselves to avoid a stackoverflow
nonSimpleTypeReferences.remove(baseType.getName());
return nonSimpleTypeReferences;
}

protected EnumTypeDefinition getEnumTypeDefinition(TypeReference typeReference) {
NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow(
() -> new FreemarkerException("type reference for enum types must be of type non simple type"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,20 @@ public String getLanguageTypeNameForField(Field field) {
if (field.asArrayField().map(ArrayField::getLoopExpression).map(Term::isFixedValueExpression).orElse(false)) {
return "plc4c_list";
}
TypedField typedField = field.asTypedField().orElseThrow(IllegalStateException::new);
TypedField typedField = field.asTypedField().orElseThrow();
TypeReference typeReference = typedField.getType();
if (typeReference.isNonSimpleTypeReference()) {
if (typeReference.asNonSimpleTypeReference().orElseThrow().getTypeDefinition() instanceof DataIoTypeDefinition) {
return "plc4c_data*";
if (typeReference.isDataIoTypeReference()) {
return "plc4c_data*";
}
// If we reference a complex type subtype, we need to return a reference
// to the parent as in C the subtypes don't actually exist.
if (typeReference.isComplexTypeReference()) {
final ComplexTypeReference complexTypeReference = typeReference.asComplexTypeReference().orElseThrow();
if (complexTypeReference.getTypeDefinition().isDiscriminatedChildTypeDefinition()) {
final DiscriminatedComplexTypeDefinition discriminatedComplexTypeDefinition = complexTypeReference.getTypeDefinition().asDiscriminatedComplexTypeDefinition().orElseThrow();
if(discriminatedComplexTypeDefinition.getParentType().isPresent()) {
return getCTypeName(discriminatedComplexTypeDefinition.getParentType().orElseThrow().asComplexTypeDefinition().orElseThrow().getName());
}
}
}
return getLanguageTypeNameForTypeReference(typeReference);
Expand Down Expand Up @@ -1209,4 +1218,86 @@ public String getEnumExpression(String expression) {
return getCTypeName(enumName) + "_" + enumConstant;
}

/**
* Helper for collecting referenced non simple types as these usually need to be
* imported in some way.
*
* @return Collection of all non simple type references used in fields or enum constants.
*/
public Collection<String> getTypeNamesForImportStatements() {
return getTypeNamesForImportStatements(thisType);
}

/**
* Helper for collecting referenced non simple types as these usually need to be
* imported in some way.
*
* @param baseType the base type we want to get the type references from
* @return collection of non simple type references used in the type.
*/
public Collection<String> getTypeNamesForImportStatements(TypeDefinition baseType) {
return getTypeNamesForImportStatements(baseType, new HashSet<>());
}

public Collection<String> getTypeNamesForImportStatements(TypeDefinition baseType, Set<String> nonSimpleTypeReferences) {
// We add ourselves to avoid a stackoverflow
nonSimpleTypeReferences.add(baseType.getName());
// If it's a complex type definition, add all the types referenced by any property fields
// (Includes any types referenced by subtypes in case this is a discriminated type parent)
if (baseType.isComplexTypeDefinition()) {
ComplexTypeDefinition complexTypeDefinition = baseType.asComplexTypeDefinition().orElseThrow();
for (Field field : complexTypeDefinition.getFields()) {
if (field.isPropertyField()) {
PropertyField propertyField = field.asPropertyField().orElseThrow();
TypeReference typeReference = propertyField.getType();
if (typeReference.isArrayTypeReference()) {
typeReference = typeReference.asArrayTypeReference().orElseThrow().getElementTypeReference();
}
if (typeReference.isNonSimpleTypeReference()) {
NonSimpleTypeReference nonSimpleTypeReference = typeReference.asNonSimpleTypeReference().orElseThrow();
if(nonSimpleTypeReference.getTypeDefinition().isDiscriminatedComplexTypeDefinition()) {
final Optional<DiscriminatedComplexTypeDefinition> discriminatedComplexTypeDefinition = nonSimpleTypeReference.getTypeDefinition().asDiscriminatedComplexTypeDefinition();
if(discriminatedComplexTypeDefinition.orElseThrow().isDiscriminatedChildTypeDefinition()) {
final ComplexTypeDefinition complexTypeDefinition1 = discriminatedComplexTypeDefinition.orElseThrow().getParentType().orElseThrow();
nonSimpleTypeReferences.add(complexTypeDefinition1.getName());
}
} else {
nonSimpleTypeReferences.add(nonSimpleTypeReference.getTypeDefinition().getName());
}
}
} else if (field.isSwitchField()) {
SwitchField switchField = field.asSwitchField().orElseThrow();
for (DiscriminatedComplexTypeDefinition switchCase : switchField.getCases()) {
if (nonSimpleTypeReferences.contains(switchCase.getName())) {
continue;
}
nonSimpleTypeReferences.addAll(getTypeNamesForImportStatements(switchCase, nonSimpleTypeReferences));
}
}
}
} else if (baseType.isEnumTypeDefinition()) {// In case this is an enum type, we have to check all the constant types.
EnumTypeDefinition enumTypeDefinition = baseType.asEnumTypeDefinition().orElseThrow();
for (String constantName : enumTypeDefinition.getConstantNames()) {
final TypeReference constantType = enumTypeDefinition.getConstantType(constantName);
if (constantType.isNonSimpleTypeReference()) {
NonSimpleTypeReference nonSimpleTypeReference = constantType.asNonSimpleTypeReference().orElseThrow();
nonSimpleTypeReferences.add(nonSimpleTypeReference.getName());
}
}
}
// If the type has any parser arguments, these have to be checked too.
baseType.getParserArguments().ifPresent(arguments -> arguments.stream()
.map(Argument::getType)
.map(TypeReferenceConversions::asNonSimpleTypeReference)
.filter(Optional::isPresent)
.map(Optional::get)
.map(NonSimpleTypeReference::getName)
.forEach(nonSimpleTypeReferences::add)
);

// We remove ourselves to avoid a stackoverflow
nonSimpleTypeReferences.remove(baseType.getName());
return nonSimpleTypeReferences;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
<#--
Add any import statements for partent-types, complex types used in properties or parser arguments.
-->
<#if helper.getNonSimpleTypeReferences()?has_content>
<#list helper.getNonSimpleTypeReferences() as typeReference>
<#if helper.getTypeNamesForImportStatements()?has_content>
<#list helper.getTypeNamesForImportStatements() as typeReference>
#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
</#list>
</#if>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ ${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase
<#--
Add any import statements for partent-types, complex types used in properties or parser arguments.
-->
<#if helper.getNonSimpleTypeReferences()?has_content>
<#list helper.getNonSimpleTypeReferences() as typeReference>
<#if helper.getTypeNamesForImportStatements()?has_content>
<#list helper.getTypeNamesForImportStatements() as typeReference>
#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
</#list>
</#if>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ ${helper.getSourceDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase(t
<#--
Add any import statements for partent-types, complex types used in properties or parser arguments.
-->
<#if helper.getNonSimpleTypeReferences()?has_content>
<#list helper.getNonSimpleTypeReferences() as typeReference>
<#if helper.getTypeNamesForImportStatements()?has_content>
<#list helper.getTypeNamesForImportStatements() as typeReference>
#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
</#list>
</#if>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ ${helper.getIncludesDirectory()?replace(".", "/")}/${helper.camelCaseToSnakeCase
<#--
Add any import statements for partent-types, complex types used in properties or parser arguments.
-->
<#if helper.getNonSimpleTypeReferences()?has_content>
<#list helper.getNonSimpleTypeReferences() as typeReference>
<#if helper.getTypeNamesForImportStatements()?has_content>
<#list helper.getTypeNamesForImportStatements() as typeReference>
#include "${helper.camelCaseToSnakeCase(typeReference)}.h"
</#list>
</#if>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,25 +336,23 @@
//Test to check if we can include concrete types as fields. Doesn't work in any language at the moment.
// TODO: Check why this is commented out
//[discriminatedType SimpleDiscriminatedType
// [discriminator uint 8 discr]
// [typeSwitch discr
// ['0x00' SimpleDiscriminatedTypeA
// [simple AnotherSimpleDiscriminatedTypeA simpA]
// ]
// ]
//]
[discriminatedType SimpleDiscriminatedType
[discriminator uint 8 discr]
[typeSwitch discr
['0x00' SimpleDiscriminatedTypeA
[simple AnotherSimpleDiscriminatedTypeA simpA]
]
]
]
// TODO: Check why this is commented out
//[discriminatedType AnotherSimpleDiscriminatedType
// [discriminator uint 8 discr]
// [typeSwitch discr
// ['0x00' AnotherSimpleDiscriminatedTypeA
// [simple uint 8 simpA]
// ]
// ]
//]
[discriminatedType AnotherSimpleDiscriminatedType
[discriminator uint 8 discr]
[typeSwitch discr
['0x00' AnotherSimpleDiscriminatedTypeA
[simple uint 8 simpA]
]
]
]
////////////////////////////////////////////////////////////////
// Enumerated Type Tests
Expand Down

0 comments on commit f64f02c

Please sign in to comment.