You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by cd...@apache.org on 2022/03/09 13:06:13 UTC
[plc4x] branch develop updated: fix(codegen): Ensured the codegen works when referencing subtypes
This is an automated email from the ASF dual-hosted git repository.
cdutz pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git
The following commit(s) were added to refs/heads/develop by this push:
new f64f02c fix(codegen): Ensured the codegen works when referencing subtypes
f64f02c is described below
commit f64f02c37f7cbb3041584fe3d974da748cea2a8b
Author: cdutz <ch...@c-ware.de>
AuthorDate: Wed Mar 9 14:05:27 2022 +0100
fix(codegen): Ensured the codegen works when referencing subtypes
---
.../BaseFreemarkerLanguageTemplateHelper.java | 82 ------------------
.../plc4x/language/c/CLanguageTemplateHelper.java | 99 +++++++++++++++++++++-
.../templates/c/complex-type-template.h.ftlh | 4 +-
.../resources/templates/c/data-io-template.h.ftlh | 4 +-
.../resources/templates/c/enum-template.c.ftlh | 4 +-
.../resources/templates/c/enum-template.h.ftlh | 4 +-
.../src/main/resources/protocols/test/test.mspec | 34 ++++----
7 files changed, 119 insertions(+), 112 deletions(-)
diff --git a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
index 5910c6b..f6052be 100644
--- a/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
+++ b/code-generation/language-base-freemarker/src/main/java/org/apache/plc4x/plugins/codegenerator/protocol/freemarker/BaseFreemarkerLanguageTemplateHelper.java
@@ -96,88 +96,6 @@ public abstract class BaseFreemarkerLanguageTemplateHelper implements Freemarker
* 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"));
diff --git a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
index 45eb9be..45e68fc 100644
--- a/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
+++ b/code-generation/language-c/src/main/java/org/apache/plc4x/language/c/CLanguageTemplateHelper.java
@@ -118,11 +118,20 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
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);
@@ -1209,4 +1218,86 @@ public class CLanguageTemplateHelper extends BaseFreemarkerLanguageTemplateHelpe
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;
+ }
+
}
diff --git a/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
index c1a65af..eb80a73 100644
--- a/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/complex-type-template.h.ftlh
@@ -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>
diff --git a/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
index 687a312..75ddd0b 100644
--- a/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/data-io-template.h.ftlh
@@ -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>
diff --git a/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh b/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
index 62ba4e2..ea2e347 100644
--- a/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/enum-template.c.ftlh
@@ -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>
diff --git a/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh b/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
index b3d6e66..da8f7a3 100644
--- a/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
+++ b/code-generation/language-c/src/main/resources/templates/c/enum-template.h.ftlh
@@ -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>
diff --git a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
index 010c02c..1f2c2c4 100644
--- a/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
+++ b/code-generation/protocol-test/src/main/resources/protocols/test/test.mspec
@@ -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